2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
15 #define SECURITY_WIN32
26 #include <WINNT\afsreg.h>
30 extern osi_hyper_t hzero;
32 smb_packet_t *smb_Directory_Watches = NULL;
33 osi_mutex_t smb_Dir_Watch_Lock;
35 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
37 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
39 /* protected by the smb_globalLock */
40 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
42 /* retrieve a held reference to a user structure corresponding to an incoming
44 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
49 uidp = smb_FindUID(vcp, inp->uid, 0);
53 up = smb_GetUserFromUID(uidp);
61 * Return extended attributes.
62 * Right now, we aren't using any of the "new" bits, so this looks exactly
63 * like smb_Attributes() (see smb.c).
65 unsigned long smb_ExtAttributes(cm_scache_t *scp)
69 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
70 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
71 scp->fileType == CM_SCACHETYPE_INVALID)
73 attrs = SMB_ATTR_DIRECTORY;
74 #ifdef SPECIAL_FOLDERS
75 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
76 #endif /* SPECIAL_FOLDERS */
77 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
78 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
82 * We used to mark a file RO if it was in an RO volume, but that
83 * turns out to be impolitic in NT. See defect 10007.
86 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
87 attrs |= SMB_ATTR_READONLY; /* Read-only */
89 if ((scp->unixModeBits & 0222) == 0)
90 attrs |= SMB_ATTR_READONLY; /* Read-only */
94 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
99 int smb_V3IsStarMask(char *maskp)
103 while (tc = *maskp++)
104 if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
109 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
112 /* skip over null-terminated string */
113 *chainpp = inp + strlen(inp) + 1;
118 void OutputDebugF(char * format, ...) {
123 va_start( args, format );
124 len = _vscprintf( format, args ) // _vscprintf doesn't count
125 + 3; // terminating '\0' + '\n'
126 buffer = malloc( len * sizeof(char) );
127 vsprintf( buffer, format, args );
128 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buffer));
129 strcat(buffer, "\n");
130 OutputDebugString(buffer);
134 void OutputDebugHexDump(unsigned char * buffer, int len) {
137 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
139 OutputDebugF("Hexdump length [%d]",len);
141 for (i=0;i<len;i++) {
144 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
146 OutputDebugString(buf);
148 sprintf(buf,"%5x",i);
149 memset(buf+5,' ',80);
154 j = j*3 + 7 + ((j>7)?1:0);
157 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
160 j = j + 56 + ((j>7)?1:0) + pcts;
162 buf[j] = (k>32 && k<127)?k:'.';
169 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
171 OutputDebugString(buf);
175 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
177 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
178 SECURITY_STATUS status, istatus;
179 CredHandle creds = {0,0};
181 SecBufferDesc secOut;
189 OutputDebugF("Negotiating Extended Security");
191 status = AcquireCredentialsHandle( NULL,
192 SMB_EXT_SEC_PACKAGE_NAME,
201 if (status != SEC_E_OK) {
202 /* Really bad. We return an empty security blob */
203 OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
208 secOut.pBuffers = &secTok;
209 secOut.ulVersion = SECBUFFER_VERSION;
211 secTok.BufferType = SECBUFFER_TOKEN;
213 secTok.pvBuffer = NULL;
215 ctx.dwLower = ctx.dwUpper = 0;
217 status = AcceptSecurityContext( &creds,
220 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
221 SECURITY_NETWORK_DREP,
228 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
229 OutputDebugF("Completing token...");
230 istatus = CompleteAuthToken(&ctx, &secOut);
231 if ( istatus != SEC_E_OK )
232 OutputDebugF("Token completion failed: %x", istatus);
235 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
236 if (secTok.pvBuffer) {
237 *secBlobLength = secTok.cbBuffer;
238 *secBlob = malloc( secTok.cbBuffer );
239 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
242 if ( status != SEC_E_OK )
243 OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
246 /* Discard partial security context */
247 DeleteSecurityContext(&ctx);
249 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
251 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
252 FreeCredentialsHandle(&creds);
258 struct smb_ext_context {
265 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
266 SECURITY_STATUS status, istatus;
270 SecBufferDesc secBufIn;
272 SecBufferDesc secBufOut;
275 struct smb_ext_context * secCtx = NULL;
276 struct smb_ext_context * newSecCtx = NULL;
277 void * assembledBlob = NULL;
278 int assembledBlobLength = 0;
281 OutputDebugF("In smb_AuthenticateUserExt");
284 *secBlobOutLength = 0;
286 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
287 secCtx = vcp->secCtx;
288 lock_ObtainMutex(&vcp->mx);
289 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
291 lock_ReleaseMutex(&vcp->mx);
295 OutputDebugF("Received incoming token:");
296 OutputDebugHexDump(secBlobIn,secBlobInLength);
300 OutputDebugF("Continuing with existing context.");
301 creds = secCtx->creds;
304 if (secCtx->partialToken) {
305 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
306 assembledBlob = malloc(assembledBlobLength);
307 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
308 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
311 status = AcquireCredentialsHandle( NULL,
312 SMB_EXT_SEC_PACKAGE_NAME,
321 if (status != SEC_E_OK) {
322 OutputDebugF("Can't acquire Credentials handle [%lX]", status);
323 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
331 secBufIn.cBuffers = 1;
332 secBufIn.pBuffers = &secTokIn;
333 secBufIn.ulVersion = SECBUFFER_VERSION;
335 secTokIn.BufferType = SECBUFFER_TOKEN;
337 secTokIn.cbBuffer = assembledBlobLength;
338 secTokIn.pvBuffer = assembledBlob;
340 secTokIn.cbBuffer = secBlobInLength;
341 secTokIn.pvBuffer = secBlobIn;
344 secBufOut.cBuffers = 1;
345 secBufOut.pBuffers = &secTokOut;
346 secBufOut.ulVersion = SECBUFFER_VERSION;
348 secTokOut.BufferType = SECBUFFER_TOKEN;
349 secTokOut.cbBuffer = 0;
350 secTokOut.pvBuffer = NULL;
352 status = AcceptSecurityContext( &creds,
353 ((secCtx)?&ctx:NULL),
355 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
356 SECURITY_NETWORK_DREP,
363 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
364 OutputDebugF("Completing token...");
365 istatus = CompleteAuthToken(&ctx, &secBufOut);
366 if ( istatus != SEC_E_OK )
367 OutputDebugF("Token completion failed: %lX", istatus);
370 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
371 OutputDebugF("Continue needed");
373 newSecCtx = malloc(sizeof(*newSecCtx));
375 newSecCtx->creds = creds;
376 newSecCtx->ctx = ctx;
377 newSecCtx->partialToken = NULL;
378 newSecCtx->partialTokenLen = 0;
380 lock_ObtainMutex( &vcp->mx );
381 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
382 vcp->secCtx = newSecCtx;
383 lock_ReleaseMutex( &vcp->mx );
385 code = CM_ERROR_GSSCONTINUE;
388 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
389 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
390 secTokOut.pvBuffer) {
391 OutputDebugF("Need to send token back to client");
393 *secBlobOutLength = secTokOut.cbBuffer;
394 *secBlobOut = malloc(secTokOut.cbBuffer);
395 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
397 OutputDebugF("Outgoing token:");
398 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
399 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
400 OutputDebugF("Incomplete message");
402 newSecCtx = malloc(sizeof(*newSecCtx));
404 newSecCtx->creds = creds;
405 newSecCtx->ctx = ctx;
406 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
407 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
408 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
410 lock_ObtainMutex( &vcp->mx );
411 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
412 vcp->secCtx = newSecCtx;
413 lock_ReleaseMutex( &vcp->mx );
415 code = CM_ERROR_GSSCONTINUE;
418 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
420 SecPkgContext_Names names;
422 OutputDebugF("Authentication completed");
423 OutputDebugF("Returned flags : [%lX]", flags);
425 if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
426 OutputDebugF("Received name [%s]", names.sUserName);
427 strcpy(usern, names.sUserName);
428 strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
429 FreeContextBuffer(names.sUserName);
431 /* Force the user to retry if the context is invalid */
432 OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
433 code = CM_ERROR_BADPASSWORD;
437 case SEC_E_INVALID_TOKEN:
438 OutputDebugF("Returning bad password :: INVALID_TOKEN");
440 case SEC_E_INVALID_HANDLE:
441 OutputDebugF("Returning bad password :: INVALID_HANDLE");
443 case SEC_E_LOGON_DENIED:
444 OutputDebugF("Returning bad password :: LOGON_DENIED");
446 case SEC_E_UNKNOWN_CREDENTIALS:
447 OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
449 case SEC_E_NO_CREDENTIALS:
450 OutputDebugF("Returning bad password :: NO_CREDENTIALS");
452 case SEC_E_CONTEXT_EXPIRED:
453 OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
455 case SEC_E_INCOMPLETE_CREDENTIALS:
456 OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
458 case SEC_E_WRONG_PRINCIPAL:
459 OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
461 case SEC_E_TIME_SKEW:
462 OutputDebugF("Returning bad password :: TIME_SKEW");
465 OutputDebugF("Returning bad password :: Status == %lX", status);
467 code = CM_ERROR_BADPASSWORD;
471 if (secCtx->partialToken) free(secCtx->partialToken);
479 if (secTokOut.pvBuffer)
480 FreeContextBuffer(secTokOut.pvBuffer);
482 if (code != CM_ERROR_GSSCONTINUE) {
483 DeleteSecurityContext(&ctx);
484 FreeCredentialsHandle(&creds);
492 #define P_RESP_LEN 128
494 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
495 So put stuff in a struct. */
496 struct Lm20AuthBlob {
497 MSV1_0_LM20_LOGON lmlogon;
498 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
499 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
500 WCHAR accountNameW[P_LEN];
501 WCHAR primaryDomainW[P_LEN];
502 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
503 TOKEN_GROUPS tgroups;
504 TOKEN_SOURCE tsource;
507 long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
510 struct Lm20AuthBlob lmAuth;
511 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
512 QUOTA_LIMITS quotaLimits;
514 ULONG lmprofilepSize;
518 OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
519 OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
521 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
522 OutputDebugF("ciPwdLength or csPwdLength is too long");
523 return CM_ERROR_BADPASSWORD;
526 memset(&lmAuth,0,sizeof(lmAuth));
528 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
530 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
531 mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
532 lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
533 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
535 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
536 mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
537 lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
538 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
540 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
541 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
542 size = MAX_COMPUTERNAME_LENGTH + 1;
543 GetComputerNameW(lmAuth.workstationW, &size);
544 lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
546 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
548 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
549 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
550 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
551 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
553 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
554 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
555 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
556 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
558 lmAuth.lmlogon.ParameterControl = 0;
560 lmAuth.tgroups.GroupCount = 0;
561 lmAuth.tgroups.Groups[0].Sid = NULL;
562 lmAuth.tgroups.Groups[0].Attributes = 0;
564 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
565 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
566 strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
568 nts = LsaLogonUser( smb_lsaHandle,
583 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
584 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
587 OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
588 OutputDebugF("Extended status is 0x%lX", ntsEx);
590 if (nts == ERROR_SUCCESS) {
592 LsaFreeReturnBuffer(lmprofilep);
593 CloseHandle(lmToken);
597 if (nts == 0xC000015BL)
598 return CM_ERROR_BADLOGONTYPE;
599 else /* our catchall is a bad password though we could be more specific */
600 return CM_ERROR_BADPASSWORD;
604 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
605 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName)
610 /* check if we have sane input */
611 if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
614 /* we could get : [accountName][domainName]
620 atsign = strchr(accountName, '@');
622 if (atsign) /* [user@domain][] -> [user@domain][domain] */
627 /* if for some reason the client doesn't know what domain to use,
628 it will either return an empty string or a '?' */
629 if (!domain[0] || domain[0] == '?')
630 /* Empty domains and empty usernames are usually sent from tokenless contexts.
631 This way such logins will get an empty username (easy to check). I don't know
632 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
633 strcpy(usern,accountName);
635 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
636 strcpy(usern,domain);
639 strncat(usern,accountName,atsign - accountName);
641 strcat(usern,accountName);
649 /* When using SMB auth, all SMB sessions have to pass through here
650 * first to authenticate the user.
652 * Caveat: If not using SMB auth, the protocol does not require
653 * sending a session setup packet, which means that we can't rely on a
654 * UID in subsequent packets. Though in practice we get one anyway.
656 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
660 unsigned short newUid;
661 unsigned long caps = 0;
665 char usern[SMB_MAX_USERNAME_LENGTH];
666 char *secBlobOut = NULL;
667 int secBlobOutLength = 0;
669 /* Check for bad conns */
670 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
671 return CM_ERROR_REMOTECONN;
673 if (vcp->flags & SMB_VCFLAG_USENT) {
674 if (smb_authType == SMB_AUTH_EXTENDED) {
675 /* extended authentication */
679 OutputDebugF("NT Session Setup: Extended");
681 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
682 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
685 secBlobInLength = smb_GetSMBParm(inp, 7);
686 secBlobIn = smb_GetSMBData(inp, NULL);
688 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
690 if (code == CM_ERROR_GSSCONTINUE) {
691 smb_SetSMBParm(outp, 2, 0);
692 smb_SetSMBParm(outp, 3, secBlobOutLength);
693 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
694 tp = smb_GetSMBData(outp, NULL);
695 if (secBlobOutLength) {
696 memcpy(tp, secBlobOut, secBlobOutLength);
698 tp += secBlobOutLength;
700 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
701 tp += smb_ServerOSLength;
702 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
703 tp += smb_ServerLanManagerLength;
704 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
705 tp += smb_ServerDomainNameLength;
708 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
710 unsigned ciPwdLength, csPwdLength;
716 if (smb_authType == SMB_AUTH_NTLM)
717 OutputDebugF("NT Session Setup: NTLM");
719 OutputDebugF("NT Session Setup: None");
721 /* TODO: parse for extended auth as well */
722 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
723 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
725 tp = smb_GetSMBData(inp, &datalen);
727 OutputDebugF("Session packet data size [%d]",datalen);
734 accountName = smb_ParseString(tp, &tp);
735 primaryDomain = smb_ParseString(tp, NULL);
737 OutputDebugF("Account Name: %s",accountName);
738 OutputDebugF("Primary Domain: %s", primaryDomain);
739 OutputDebugF("Case Sensitive Password: %s", csPwd && csPwd[0] ? "yes" : "no");
740 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
742 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
743 /* shouldn't happen */
744 code = CM_ERROR_BADSMB;
745 goto after_read_packet;
748 /* capabilities are only valid for first session packet */
749 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
750 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
753 if (smb_authType == SMB_AUTH_NTLM) {
754 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
756 OutputDebugF("LM authentication failed [%d]", code);
758 OutputDebugF("LM authentication succeeded");
762 unsigned ciPwdLength;
767 switch ( smb_authType ) {
768 case SMB_AUTH_EXTENDED:
769 OutputDebugF("V3 Session Setup: Extended");
772 OutputDebugF("V3 Session Setup: NTLM");
775 OutputDebugF("V3 Session Setup: None");
777 ciPwdLength = smb_GetSMBParm(inp, 7);
778 tp = smb_GetSMBData(inp, NULL);
782 accountName = smb_ParseString(tp, &tp);
783 primaryDomain = smb_ParseString(tp, NULL);
785 OutputDebugF("Account Name: %s",accountName);
786 OutputDebugF("Primary Domain: %s", primaryDomain);
787 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
789 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
790 /* shouldn't happen */
791 code = CM_ERROR_BADSMB;
792 goto after_read_packet;
795 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
798 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
799 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
801 OutputDebugF("LM authentication failed [%d]", code);
803 OutputDebugF("LM authentication succeeded");
808 /* note down that we received a session setup X and set the capabilities flag */
809 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
810 lock_ObtainMutex(&vcp->mx);
811 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
812 /* for the moment we can only deal with NTSTATUS */
813 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
814 vcp->flags |= SMB_VCFLAG_STATUS32;
816 lock_ReleaseMutex(&vcp->mx);
819 /* code would be non-zero if there was an authentication failure.
820 Ideally we would like to invalidate the uid for this session or break
821 early to avoid accidently stealing someone else's tokens. */
827 OutputDebugF("Received username=[%s]", usern);
829 /* On Windows 2000, this function appears to be called more often than
830 it is expected to be called. This resulted in multiple smb_user_t
831 records existing all for the same user session which results in all
832 of the users tokens disappearing.
834 To avoid this problem, we look for an existing smb_user_t record
835 based on the users name, and use that one if we find it.
838 uidp = smb_FindUserByNameThisSession(vcp, usern);
839 if (uidp) { /* already there, so don't create a new one */
841 newUid = uidp->userID;
842 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
843 vcp->lana,vcp->lsn,newUid);
844 smb_ReleaseUID(uidp);
849 /* do a global search for the username/machine name pair */
850 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
851 lock_ObtainMutex(&unp->mx);
852 if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
853 /* clear the afslogon flag so that the tickets can now
854 * be freed when the refCount returns to zero.
856 unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
858 lock_ReleaseMutex(&unp->mx);
860 /* Create a new UID and cm_user_t structure */
863 userp = cm_NewUser();
864 cm_HoldUserVCRef(userp);
865 lock_ObtainMutex(&vcp->mx);
866 if (!vcp->uidCounter)
867 vcp->uidCounter++; /* handle unlikely wraparounds */
868 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
869 lock_ReleaseMutex(&vcp->mx);
871 /* Create a new smb_user_t structure and connect them up */
872 lock_ObtainMutex(&unp->mx);
874 lock_ReleaseMutex(&unp->mx);
876 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
878 lock_ObtainMutex(&uidp->mx);
880 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
881 lock_ReleaseMutex(&uidp->mx);
882 smb_ReleaseUID(uidp);
886 /* Return UID to the client */
887 ((smb_t *)outp)->uid = newUid;
888 /* Also to the next chained message */
889 ((smb_t *)inp)->uid = newUid;
891 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
892 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
894 smb_SetSMBParm(outp, 2, 0);
896 if (vcp->flags & SMB_VCFLAG_USENT) {
897 if (smb_authType == SMB_AUTH_EXTENDED) {
898 smb_SetSMBParm(outp, 3, secBlobOutLength);
899 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
900 tp = smb_GetSMBData(outp, NULL);
901 if (secBlobOutLength) {
902 memcpy(tp, secBlobOut, secBlobOutLength);
904 tp += secBlobOutLength;
906 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
907 tp += smb_ServerOSLength;
908 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
909 tp += smb_ServerLanManagerLength;
910 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
911 tp += smb_ServerDomainNameLength;
913 smb_SetSMBDataLength(outp, 0);
916 if (smb_authType == SMB_AUTH_EXTENDED) {
917 smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
918 tp = smb_GetSMBData(outp, NULL);
919 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
920 tp += smb_ServerOSLength;
921 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
922 tp += smb_ServerLanManagerLength;
923 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
924 tp += smb_ServerDomainNameLength;
926 smb_SetSMBDataLength(outp, 0);
933 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
937 /* find the tree and free it */
938 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
940 smb_username_t * unp;
942 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %s", uidp->userID,
943 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "));
945 lock_ObtainMutex(&uidp->mx);
946 uidp->flags |= SMB_USERFLAG_DELETE;
948 * it doesn't get deleted right away
949 * because the vcp points to it
952 lock_ReleaseMutex(&uidp->mx);
955 /* we can't do this. we get logoff messages prior to a session
956 * disconnect even though it doesn't mean the user is logging out.
957 * we need to create a new pioctl and EventLogoff handler to set
958 * SMB_USERNAMEFLAG_LOGOFF.
960 if (unp && smb_LogoffTokenTransfer) {
961 lock_ObtainMutex(&unp->mx);
962 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
963 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
964 lock_ReleaseMutex(&unp->mx);
968 smb_ReleaseUID(uidp);
971 osi_Log0(smb_logp, "SMB3 user logoffX");
973 smb_SetSMBDataLength(outp, 0);
977 #define SMB_SUPPORT_SEARCH_BITS 0x0001
978 #define SMB_SHARE_IS_IN_DFS 0x0002
980 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
983 smb_user_t *uidp = NULL;
984 unsigned short newTid;
992 cm_user_t *userp = NULL;
995 osi_Log0(smb_logp, "SMB3 receive tree connect");
997 /* parse input parameters */
998 tp = smb_GetSMBData(inp, NULL);
999 passwordp = smb_ParseString(tp, &tp);
1000 pathp = smb_ParseString(tp, &tp);
1001 if (smb_StoreAnsiFilenames)
1002 OemToChar(pathp,pathp);
1003 servicep = smb_ParseString(tp, &tp);
1005 tp = strrchr(pathp, '\\');
1007 return CM_ERROR_BADSMB;
1009 strcpy(shareName, tp+1);
1011 osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
1012 osi_LogSaveString(smb_logp, pathp),
1013 osi_LogSaveString(smb_logp, shareName));
1015 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
1017 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1020 return CM_ERROR_NOIPC;
1024 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1026 userp = smb_GetUserFromUID(uidp);
1028 lock_ObtainMutex(&vcp->mx);
1029 newTid = vcp->tidCounter++;
1030 lock_ReleaseMutex(&vcp->mx);
1032 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1035 if (!strcmp(shareName, "*."))
1036 strcpy(shareName, "all");
1037 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1040 smb_ReleaseUID(uidp);
1041 smb_ReleaseTID(tidp);
1042 return CM_ERROR_BADSHARENAME;
1045 if (vcp->flags & SMB_VCFLAG_USENT)
1047 int policy = smb_FindShareCSCPolicy(shareName);
1048 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1050 SMB_SHARE_IS_IN_DFS |
1055 smb_SetSMBParm(outp, 2, 0);
1059 smb_ReleaseUID(uidp);
1061 lock_ObtainMutex(&tidp->mx);
1062 tidp->userp = userp;
1063 tidp->pathname = sharePath;
1065 tidp->flags |= SMB_TIDFLAG_IPC;
1066 lock_ReleaseMutex(&tidp->mx);
1067 smb_ReleaseTID(tidp);
1069 ((smb_t *)outp)->tid = newTid;
1070 ((smb_t *)inp)->tid = newTid;
1071 tp = smb_GetSMBData(outp, NULL);
1073 /* XXX - why is this a drive letter? */
1081 smb_SetSMBDataLength(outp, 7);
1084 smb_SetSMBDataLength(outp, 4);
1087 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1091 /* must be called with global tran lock held */
1092 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1094 smb_tran2Packet_t *tp;
1097 smbp = (smb_t *) inp->data;
1098 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1099 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1105 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1106 int totalParms, int totalData)
1108 smb_tran2Packet_t *tp;
1111 smbp = (smb_t *) inp->data;
1112 tp = malloc(sizeof(*tp));
1113 memset(tp, 0, sizeof(*tp));
1116 tp->curData = tp->curParms = 0;
1117 tp->totalData = totalData;
1118 tp->totalParms = totalParms;
1119 tp->tid = smbp->tid;
1120 tp->mid = smbp->mid;
1121 tp->uid = smbp->uid;
1122 tp->pid = smbp->pid;
1123 tp->res[0] = smbp->res[0];
1124 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1125 if (totalParms != 0)
1126 tp->parmsp = malloc(totalParms);
1128 tp->datap = malloc(totalData);
1129 if (smbp->com == 0x25 || smbp->com == 0x26)
1132 tp->opcode = smb_GetSMBParm(inp, 14);
1135 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1139 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1140 smb_tran2Packet_t *inp, smb_packet_t *outp,
1141 int totalParms, int totalData)
1143 smb_tran2Packet_t *tp;
1144 unsigned short parmOffset;
1145 unsigned short dataOffset;
1146 unsigned short dataAlign;
1148 tp = malloc(sizeof(*tp));
1149 memset(tp, 0, sizeof(*tp));
1152 tp->curData = tp->curParms = 0;
1153 tp->totalData = totalData;
1154 tp->totalParms = totalParms;
1155 tp->oldTotalParms = totalParms;
1160 tp->res[0] = inp->res[0];
1161 tp->opcode = inp->opcode;
1165 * We calculate where the parameters and data will start.
1166 * This calculation must parallel the calculation in
1167 * smb_SendTran2Packet.
1170 parmOffset = 10*2 + 35;
1171 parmOffset++; /* round to even */
1172 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1174 dataOffset = parmOffset + totalParms;
1175 dataAlign = dataOffset & 2; /* quad-align */
1176 dataOffset += dataAlign;
1177 tp->datap = outp->data + dataOffset;
1182 /* free a tran2 packet */
1183 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1186 smb_ReleaseVC(t2p->vcp);
1189 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1198 /* called with a VC, an input packet to respond to, and an error code.
1199 * sends an error response.
1201 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1202 smb_packet_t *tp, long code)
1205 unsigned short errCode;
1206 unsigned char errClass;
1207 unsigned long NTStatus;
1209 if (vcp->flags & SMB_VCFLAG_STATUS32)
1210 smb_MapNTError(code, &NTStatus);
1212 smb_MapCoreError(code, vcp, &errCode, &errClass);
1214 smb_FormatResponsePacket(vcp, NULL, tp);
1215 smbp = (smb_t *) tp;
1217 /* We can handle long names */
1218 if (vcp->flags & SMB_VCFLAG_USENT)
1219 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1221 /* now copy important fields from the tran 2 packet */
1222 smbp->com = t2p->com;
1223 smbp->tid = t2p->tid;
1224 smbp->mid = t2p->mid;
1225 smbp->pid = t2p->pid;
1226 smbp->uid = t2p->uid;
1227 smbp->res[0] = t2p->res[0];
1228 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1229 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1230 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1231 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1232 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1233 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1236 smbp->rcls = errClass;
1237 smbp->errLow = (unsigned char) (errCode & 0xff);
1238 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1242 smb_SendPacket(vcp, tp);
1245 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1248 unsigned short parmOffset;
1249 unsigned short dataOffset;
1250 unsigned short totalLength;
1251 unsigned short dataAlign;
1254 smb_FormatResponsePacket(vcp, NULL, tp);
1255 smbp = (smb_t *) tp;
1257 /* We can handle long names */
1258 if (vcp->flags & SMB_VCFLAG_USENT)
1259 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1261 /* now copy important fields from the tran 2 packet */
1262 smbp->com = t2p->com;
1263 smbp->tid = t2p->tid;
1264 smbp->mid = t2p->mid;
1265 smbp->pid = t2p->pid;
1266 smbp->uid = t2p->uid;
1267 smbp->res[0] = t2p->res[0];
1269 totalLength = 1 + t2p->totalData + t2p->totalParms;
1271 /* now add the core parameters (tran2 info) to the packet */
1272 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1273 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1274 smb_SetSMBParm(tp, 2, 0); /* reserved */
1275 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1276 parmOffset = 10*2 + 35; /* parm offset in packet */
1277 parmOffset++; /* round to even */
1278 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1279 * hdr, bcc and wct */
1280 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1281 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1282 dataOffset = parmOffset + t2p->oldTotalParms;
1283 dataAlign = dataOffset & 2; /* quad-align */
1284 dataOffset += dataAlign;
1285 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1286 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1287 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1290 datap = smb_GetSMBData(tp, NULL);
1291 *datap++ = 0; /* we rounded to even */
1293 totalLength += dataAlign;
1294 smb_SetSMBDataLength(tp, totalLength);
1296 /* next, send the datagram */
1297 smb_SendPacket(vcp, tp);
1300 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1302 smb_tran2Packet_t *asp;
1315 /* We sometimes see 0 word count. What to do? */
1316 if (*inp->wctp == 0) {
1317 osi_Log0(smb_logp, "Transaction2 word count = 0");
1318 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1320 smb_SetSMBDataLength(outp, 0);
1321 smb_SendPacket(vcp, outp);
1325 totalParms = smb_GetSMBParm(inp, 0);
1326 totalData = smb_GetSMBParm(inp, 1);
1328 firstPacket = (inp->inCom == 0x25);
1330 /* find the packet we're reassembling */
1331 lock_ObtainWrite(&smb_globalLock);
1332 asp = smb_FindTran2Packet(vcp, inp);
1334 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1336 lock_ReleaseWrite(&smb_globalLock);
1338 /* now merge in this latest packet; start by looking up offsets */
1340 parmDisp = dataDisp = 0;
1341 parmOffset = smb_GetSMBParm(inp, 10);
1342 dataOffset = smb_GetSMBParm(inp, 12);
1343 parmCount = smb_GetSMBParm(inp, 9);
1344 dataCount = smb_GetSMBParm(inp, 11);
1345 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1346 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1348 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1349 totalData, dataCount, asp->maxReturnData);
1352 parmDisp = smb_GetSMBParm(inp, 4);
1353 parmOffset = smb_GetSMBParm(inp, 3);
1354 dataDisp = smb_GetSMBParm(inp, 7);
1355 dataOffset = smb_GetSMBParm(inp, 6);
1356 parmCount = smb_GetSMBParm(inp, 2);
1357 dataCount = smb_GetSMBParm(inp, 5);
1359 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1360 parmCount, dataCount);
1363 /* now copy the parms and data */
1364 if ( asp->totalParms > 0 && parmCount != 0 )
1366 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1368 if ( asp->totalData > 0 && dataCount != 0 ) {
1369 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1372 /* account for new bytes */
1373 asp->curData += dataCount;
1374 asp->curParms += parmCount;
1376 /* finally, if we're done, remove the packet from the queue and dispatch it */
1377 if (asp->totalParms > 0 &&
1378 asp->curParms > 0 &&
1379 asp->totalData <= asp->curData &&
1380 asp->totalParms <= asp->curParms) {
1381 /* we've received it all */
1382 lock_ObtainWrite(&smb_globalLock);
1383 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1384 lock_ReleaseWrite(&smb_globalLock);
1386 /* now dispatch it */
1387 rapOp = asp->parmsp[0];
1389 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1390 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1391 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1392 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
1395 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1396 code = CM_ERROR_BADOP;
1399 /* if an error is returned, we're supposed to send an error packet,
1400 * otherwise the dispatched function already did the data sending.
1401 * We give dispatched proc the responsibility since it knows how much
1402 * space to allocate.
1405 smb_SendTran2Error(vcp, asp, outp, code);
1408 /* free the input tran 2 packet */
1409 smb_FreeTran2Packet(asp);
1411 else if (firstPacket) {
1412 /* the first packet in a multi-packet request, we need to send an
1413 * ack to get more data.
1415 smb_SetSMBDataLength(outp, 0);
1416 smb_SendPacket(vcp, outp);
1422 /* ANSI versions. The unicode versions support arbitrary length
1423 share names, but we don't support unicode yet. */
1425 typedef struct smb_rap_share_info_0 {
1426 char shi0_netname[13];
1427 } smb_rap_share_info_0_t;
1429 typedef struct smb_rap_share_info_1 {
1430 char shi1_netname[13];
1433 DWORD shi1_remark; /* char *shi1_remark; data offset */
1434 } smb_rap_share_info_1_t;
1436 typedef struct smb_rap_share_info_2 {
1437 char shi2_netname[13];
1439 unsigned short shi2_type;
1440 DWORD shi2_remark; /* char *shi2_remark; data offset */
1441 unsigned short shi2_permissions;
1442 unsigned short shi2_max_uses;
1443 unsigned short shi2_current_uses;
1444 DWORD shi2_path; /* char *shi2_path; data offset */
1445 unsigned short shi2_passwd[9];
1446 unsigned short shi2_pad2;
1447 } smb_rap_share_info_2_t;
1449 #define SMB_RAP_MAX_SHARES 512
1451 typedef struct smb_rap_share_list {
1454 smb_rap_share_info_0_t * shares;
1455 } smb_rap_share_list_t;
1457 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1458 smb_rap_share_list_t * sp;
1463 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1464 return 0; /* skip over '.' and '..' */
1466 sp = (smb_rap_share_list_t *) vrockp;
1468 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1469 sp->shares[sp->cShare].shi0_netname[12] = 0;
1473 if (sp->cShare >= sp->maxShares)
1474 return CM_ERROR_STOPNOW;
1479 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1481 smb_tran2Packet_t *outp;
1482 unsigned short * tp;
1486 int outParmsTotal; /* total parameter bytes */
1487 int outDataTotal; /* total data bytes */
1490 DWORD allSubmount = 0;
1492 DWORD nRegShares = 0;
1493 DWORD nSharesRet = 0;
1495 HKEY hkSubmount = NULL;
1496 smb_rap_share_info_1_t * shares;
1499 char thisShare[256];
1502 smb_rap_share_list_t rootShares;
1507 tp = p->parmsp + 1; /* skip over function number (always 0) */
1508 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1509 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1513 if (infoLevel != 1) {
1514 return CM_ERROR_INVAL;
1517 /* first figure out how many shares there are */
1518 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1519 KEY_QUERY_VALUE, &hkParam);
1520 if (rv == ERROR_SUCCESS) {
1521 len = sizeof(allSubmount);
1522 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1523 (BYTE *) &allSubmount, &len);
1524 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1527 RegCloseKey (hkParam);
1530 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1531 0, KEY_QUERY_VALUE, &hkSubmount);
1532 if (rv == ERROR_SUCCESS) {
1533 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1534 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1535 if (rv != ERROR_SUCCESS)
1541 /* fetch the root shares */
1542 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1543 rootShares.cShare = 0;
1544 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1548 userp = smb_GetTran2User(vcp,p);
1550 thyper.HighPart = 0;
1553 cm_HoldSCache(cm_data.rootSCachep);
1554 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1555 cm_ReleaseSCache(cm_data.rootSCachep);
1557 cm_ReleaseUser(userp);
1559 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1561 #define REMARK_LEN 1
1562 outParmsTotal = 8; /* 4 dwords */
1563 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1564 if(outDataTotal > bufsize) {
1565 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1566 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1569 nSharesRet = nShares;
1572 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1574 /* now for the submounts */
1575 shares = (smb_rap_share_info_1_t *) outp->datap;
1576 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1578 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1581 strcpy( shares[cshare].shi1_netname, "all" );
1582 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1583 /* type and pad are zero already */
1589 for (i=0; i < nRegShares && cshare < nSharesRet; i++) {
1590 len = sizeof(thisShare);
1591 rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1592 if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1593 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1594 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1595 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1600 nShares--; /* uncount key */
1603 RegCloseKey(hkSubmount);
1606 nonrootShares = cshare;
1608 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1609 /* in case there are collisions with submounts, submounts have higher priority */
1610 for (j=0; j < nonrootShares; j++)
1611 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1614 if (j < nonrootShares) {
1615 nShares--; /* uncount */
1619 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1620 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1625 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1626 outp->parmsp[1] = 0;
1627 outp->parmsp[2] = cshare;
1628 outp->parmsp[3] = nShares;
1630 outp->totalData = (int)(cstrp - outp->datap);
1631 outp->totalParms = outParmsTotal;
1633 smb_SendTran2Packet(vcp, outp, op);
1634 smb_FreeTran2Packet(outp);
1636 free(rootShares.shares);
1641 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1643 smb_tran2Packet_t *outp;
1644 unsigned short * tp;
1646 BOOL shareFound = FALSE;
1647 unsigned short infoLevel;
1648 unsigned short bufsize;
1658 tp = p->parmsp + 1; /* skip over function number (always 1) */
1659 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1660 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1661 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1668 totalData = sizeof(smb_rap_share_info_0_t);
1669 else if(infoLevel == SMB_INFO_STANDARD)
1670 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1671 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1672 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1674 return CM_ERROR_INVAL;
1676 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1678 if(!stricmp(shareName,"all") || !strcmp(shareName,"*.")) {
1679 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1680 KEY_QUERY_VALUE, &hkParam);
1681 if (rv == ERROR_SUCCESS) {
1682 len = sizeof(allSubmount);
1683 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1684 (BYTE *) &allSubmount, &len);
1685 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1688 RegCloseKey (hkParam);
1695 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1696 KEY_QUERY_VALUE, &hkSubmount);
1697 if (rv == ERROR_SUCCESS) {
1698 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1699 if (rv == ERROR_SUCCESS) {
1702 RegCloseKey(hkSubmount);
1707 smb_FreeTran2Packet(outp);
1708 return CM_ERROR_BADSHARENAME;
1711 memset(outp->datap, 0, totalData);
1713 outp->parmsp[0] = 0;
1714 outp->parmsp[1] = 0;
1715 outp->parmsp[2] = totalData;
1717 if (infoLevel == 0) {
1718 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1719 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1720 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1721 } else if(infoLevel == SMB_INFO_STANDARD) {
1722 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1723 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1724 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1725 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1726 /* type and pad are already zero */
1727 } else { /* infoLevel==2 */
1728 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1729 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1730 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1731 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1732 info->shi2_permissions = ACCESS_ALL;
1733 info->shi2_max_uses = (unsigned short) -1;
1734 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
1737 outp->totalData = totalData;
1738 outp->totalParms = totalParam;
1740 smb_SendTran2Packet(vcp, outp, op);
1741 smb_FreeTran2Packet(outp);
1746 typedef struct smb_rap_wksta_info_10 {
1747 DWORD wki10_computername; /*char *wki10_computername;*/
1748 DWORD wki10_username; /* char *wki10_username; */
1749 DWORD wki10_langroup; /* char *wki10_langroup;*/
1750 unsigned char wki10_ver_major;
1751 unsigned char wki10_ver_minor;
1752 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1753 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1754 } smb_rap_wksta_info_10_t;
1757 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1759 smb_tran2Packet_t *outp;
1763 unsigned short * tp;
1766 smb_rap_wksta_info_10_t * info;
1770 tp = p->parmsp + 1; /* Skip over function number */
1771 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1772 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1776 if (infoLevel != 10) {
1777 return CM_ERROR_INVAL;
1783 totalData = sizeof(*info) + /* info */
1784 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1785 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1786 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1787 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1788 1; /* wki10_oth_domains (null)*/
1790 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1792 memset(outp->parmsp,0,totalParams);
1793 memset(outp->datap,0,totalData);
1795 info = (smb_rap_wksta_info_10_t *) outp->datap;
1796 cstrp = (char *) (info + 1);
1798 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1799 strcpy(cstrp, smb_localNamep);
1800 cstrp += strlen(cstrp) + 1;
1802 info->wki10_username = (DWORD) (cstrp - outp->datap);
1803 uidp = smb_FindUID(vcp, p->uid, 0);
1805 lock_ObtainMutex(&uidp->mx);
1806 if(uidp->unp && uidp->unp->name)
1807 strcpy(cstrp, uidp->unp->name);
1808 lock_ReleaseMutex(&uidp->mx);
1809 smb_ReleaseUID(uidp);
1811 cstrp += strlen(cstrp) + 1;
1813 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1814 strcpy(cstrp, "WORKGROUP");
1815 cstrp += strlen(cstrp) + 1;
1817 /* TODO: Not sure what values these should take, but these work */
1818 info->wki10_ver_major = 5;
1819 info->wki10_ver_minor = 1;
1821 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1822 strcpy(cstrp, smb_ServerDomainName);
1823 cstrp += strlen(cstrp) + 1;
1825 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1826 cstrp ++; /* no other domains */
1828 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1829 outp->parmsp[2] = outp->totalData;
1830 outp->totalParms = totalParams;
1832 smb_SendTran2Packet(vcp,outp,op);
1833 smb_FreeTran2Packet(outp);
1838 typedef struct smb_rap_server_info_0 {
1840 } smb_rap_server_info_0_t;
1842 typedef struct smb_rap_server_info_1 {
1844 char sv1_version_major;
1845 char sv1_version_minor;
1846 unsigned long sv1_type;
1847 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1848 } smb_rap_server_info_1_t;
1850 char smb_ServerComment[] = "OpenAFS Client";
1851 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1853 #define SMB_SV_TYPE_SERVER 0x00000002L
1854 #define SMB_SV_TYPE_NT 0x00001000L
1855 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1857 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1859 smb_tran2Packet_t *outp;
1863 unsigned short * tp;
1866 smb_rap_server_info_0_t * info0;
1867 smb_rap_server_info_1_t * info1;
1870 tp = p->parmsp + 1; /* Skip over function number */
1871 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1872 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1876 if (infoLevel != 0 && infoLevel != 1) {
1877 return CM_ERROR_INVAL;
1883 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1884 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1886 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1888 memset(outp->parmsp,0,totalParams);
1889 memset(outp->datap,0,totalData);
1891 if (infoLevel == 0) {
1892 info0 = (smb_rap_server_info_0_t *) outp->datap;
1893 cstrp = (char *) (info0 + 1);
1894 strcpy(info0->sv0_name, "AFS");
1895 } else { /* infoLevel == SMB_INFO_STANDARD */
1896 info1 = (smb_rap_server_info_1_t *) outp->datap;
1897 cstrp = (char *) (info1 + 1);
1898 strcpy(info1->sv1_name, "AFS");
1901 SMB_SV_TYPE_SERVER |
1903 SMB_SV_TYPE_SERVER_NT;
1905 info1->sv1_version_major = 5;
1906 info1->sv1_version_minor = 1;
1907 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1909 strcpy(cstrp, smb_ServerComment);
1911 cstrp += smb_ServerCommentLen;
1914 totalData = (DWORD)(cstrp - outp->datap);
1915 outp->totalData = min(bufsize,totalData); /* actual data size */
1916 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1917 outp->parmsp[2] = totalData;
1918 outp->totalParms = totalParams;
1920 smb_SendTran2Packet(vcp,outp,op);
1921 smb_FreeTran2Packet(outp);
1926 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1928 smb_tran2Packet_t *asp;
1940 /* We sometimes see 0 word count. What to do? */
1941 if (*inp->wctp == 0) {
1942 osi_Log0(smb_logp, "Transaction2 word count = 0");
1943 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1945 smb_SetSMBDataLength(outp, 0);
1946 smb_SendPacket(vcp, outp);
1950 totalParms = smb_GetSMBParm(inp, 0);
1951 totalData = smb_GetSMBParm(inp, 1);
1953 firstPacket = (inp->inCom == 0x32);
1955 /* find the packet we're reassembling */
1956 lock_ObtainWrite(&smb_globalLock);
1957 asp = smb_FindTran2Packet(vcp, inp);
1959 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1961 lock_ReleaseWrite(&smb_globalLock);
1963 /* now merge in this latest packet; start by looking up offsets */
1965 parmDisp = dataDisp = 0;
1966 parmOffset = smb_GetSMBParm(inp, 10);
1967 dataOffset = smb_GetSMBParm(inp, 12);
1968 parmCount = smb_GetSMBParm(inp, 9);
1969 dataCount = smb_GetSMBParm(inp, 11);
1970 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1971 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1973 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1974 totalData, dataCount, asp->maxReturnData);
1977 parmDisp = smb_GetSMBParm(inp, 4);
1978 parmOffset = smb_GetSMBParm(inp, 3);
1979 dataDisp = smb_GetSMBParm(inp, 7);
1980 dataOffset = smb_GetSMBParm(inp, 6);
1981 parmCount = smb_GetSMBParm(inp, 2);
1982 dataCount = smb_GetSMBParm(inp, 5);
1984 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1985 parmCount, dataCount);
1988 /* now copy the parms and data */
1989 if ( asp->totalParms > 0 && parmCount != 0 )
1991 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1993 if ( asp->totalData > 0 && dataCount != 0 ) {
1994 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1997 /* account for new bytes */
1998 asp->curData += dataCount;
1999 asp->curParms += parmCount;
2001 /* finally, if we're done, remove the packet from the queue and dispatch it */
2002 if (asp->totalParms > 0 &&
2003 asp->curParms > 0 &&
2004 asp->totalData <= asp->curData &&
2005 asp->totalParms <= asp->curParms) {
2006 /* we've received it all */
2007 lock_ObtainWrite(&smb_globalLock);
2008 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2009 lock_ReleaseWrite(&smb_globalLock);
2011 /* now dispatch it */
2012 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2013 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2014 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2017 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2018 code = CM_ERROR_BADOP;
2021 /* if an error is returned, we're supposed to send an error packet,
2022 * otherwise the dispatched function already did the data sending.
2023 * We give dispatched proc the responsibility since it knows how much
2024 * space to allocate.
2027 smb_SendTran2Error(vcp, asp, outp, code);
2030 /* free the input tran 2 packet */
2031 smb_FreeTran2Packet(asp);
2033 else if (firstPacket) {
2034 /* the first packet in a multi-packet request, we need to send an
2035 * ack to get more data.
2037 smb_SetSMBDataLength(outp, 0);
2038 smb_SendPacket(vcp, outp);
2044 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2047 smb_tran2Packet_t *outp;
2052 cm_scache_t *dscp; /* dir we're dealing with */
2053 cm_scache_t *scp; /* file we're creating */
2055 int initialModeBits;
2065 int parmSlot; /* which parm we're dealing with */
2066 long returnEALength;
2075 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2076 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2078 openFun = p->parmsp[6]; /* open function */
2079 excl = ((openFun & 3) == 0);
2080 trunc = ((openFun & 3) == 2); /* truncate it */
2081 openMode = (p->parmsp[1] & 0x7);
2082 openAction = 0; /* tracks what we did */
2084 attributes = p->parmsp[3];
2085 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2087 /* compute initial mode bits based on read-only flag in attributes */
2088 initialModeBits = 0666;
2089 if (attributes & SMB_ATTR_READONLY)
2090 initialModeBits &= ~0222;
2092 pathp = (char *) (&p->parmsp[14]);
2093 if (smb_StoreAnsiFilenames)
2094 OemToChar(pathp,pathp);
2096 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2098 spacep = cm_GetSpace();
2099 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2101 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2102 /* special case magic file name for receiving IOCTL requests
2103 * (since IOCTL calls themselves aren't getting through).
2105 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2106 smb_SetupIoctlFid(fidp, spacep);
2108 /* copy out remainder of the parms */
2110 outp->parmsp[parmSlot++] = fidp->fid;
2112 outp->parmsp[parmSlot++] = 0; /* attrs */
2113 outp->parmsp[parmSlot++] = 0; /* mod time */
2114 outp->parmsp[parmSlot++] = 0;
2115 outp->parmsp[parmSlot++] = 0; /* len */
2116 outp->parmsp[parmSlot++] = 0x7fff;
2117 outp->parmsp[parmSlot++] = openMode;
2118 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2119 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2121 /* and the final "always present" stuff */
2122 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2123 /* next write out the "unique" ID */
2124 outp->parmsp[parmSlot++] = 0x1234;
2125 outp->parmsp[parmSlot++] = 0x5678;
2126 outp->parmsp[parmSlot++] = 0;
2127 if (returnEALength) {
2128 outp->parmsp[parmSlot++] = 0;
2129 outp->parmsp[parmSlot++] = 0;
2132 outp->totalData = 0;
2133 outp->totalParms = parmSlot * 2;
2135 smb_SendTran2Packet(vcp, outp, op);
2137 smb_FreeTran2Packet(outp);
2139 /* and clean up fid reference */
2140 smb_ReleaseFID(fidp);
2144 #ifdef DEBUG_VERBOSE
2146 char *hexp, *asciip;
2147 asciip = (lastNamep ? lastNamep : pathp);
2148 hexp = osi_HexifyString( asciip );
2149 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2154 userp = smb_GetTran2User(vcp, p);
2155 /* In the off chance that userp is NULL, we log and abandon */
2157 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2158 smb_FreeTran2Packet(outp);
2159 return CM_ERROR_BADSMB;
2162 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2163 if (code == CM_ERROR_TIDIPC) {
2164 /* Attempt to use a TID allocated for IPC. The client
2165 * is probably looking for DCE RPC end points which we
2166 * don't support OR it could be looking to make a DFS
2169 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2171 cm_ReleaseUser(userp);
2172 smb_FreeTran2Packet(outp);
2173 return CM_ERROR_NOSUCHPATH;
2178 code = cm_NameI(cm_data.rootSCachep, pathp,
2179 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2180 userp, tidPathp, &req, &scp);
2182 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2183 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2184 userp, tidPathp, &req, &dscp);
2185 cm_FreeSpace(spacep);
2188 cm_ReleaseUser(userp);
2189 smb_FreeTran2Packet(outp);
2194 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2195 cm_ReleaseSCache(dscp);
2196 cm_ReleaseUser(userp);
2197 smb_FreeTran2Packet(outp);
2198 if ( WANTS_DFS_PATHNAMES(p) )
2199 return CM_ERROR_PATH_NOT_COVERED;
2201 return CM_ERROR_BADSHARENAME;
2203 #endif /* DFS_SUPPORT */
2205 /* otherwise, scp points to the parent directory. Do a lookup,
2206 * and truncate the file if we find it, otherwise we create the
2213 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2215 if (code && code != CM_ERROR_NOSUCHFILE) {
2216 cm_ReleaseSCache(dscp);
2217 cm_ReleaseUser(userp);
2218 smb_FreeTran2Packet(outp);
2223 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2224 cm_ReleaseSCache(scp);
2225 cm_ReleaseUser(userp);
2226 smb_FreeTran2Packet(outp);
2227 if ( WANTS_DFS_PATHNAMES(p) )
2228 return CM_ERROR_PATH_NOT_COVERED;
2230 return CM_ERROR_BADSHARENAME;
2232 #endif /* DFS_SUPPORT */
2234 /* macintosh is expensive to program for it */
2235 cm_FreeSpace(spacep);
2238 /* if we get here, if code is 0, the file exists and is represented by
2239 * scp. Otherwise, we have to create it.
2242 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2245 cm_ReleaseSCache(dscp);
2246 cm_ReleaseSCache(scp);
2247 cm_ReleaseUser(userp);
2248 smb_FreeTran2Packet(outp);
2253 /* oops, file shouldn't be there */
2255 cm_ReleaseSCache(dscp);
2256 cm_ReleaseSCache(scp);
2257 cm_ReleaseUser(userp);
2258 smb_FreeTran2Packet(outp);
2259 return CM_ERROR_EXISTS;
2263 setAttr.mask = CM_ATTRMASK_LENGTH;
2264 setAttr.length.LowPart = 0;
2265 setAttr.length.HighPart = 0;
2266 code = cm_SetAttr(scp, &setAttr, userp, &req);
2267 openAction = 3; /* truncated existing file */
2270 openAction = 1; /* found existing file */
2272 else if (!(openFun & 0x10)) {
2273 /* don't create if not found */
2275 cm_ReleaseSCache(dscp);
2276 osi_assert(scp == NULL);
2277 cm_ReleaseUser(userp);
2278 smb_FreeTran2Packet(outp);
2279 return CM_ERROR_NOSUCHFILE;
2282 osi_assert(dscp != NULL && scp == NULL);
2283 openAction = 2; /* created file */
2284 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2285 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2286 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2290 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2291 smb_NotifyChange(FILE_ACTION_ADDED,
2292 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2293 dscp, lastNamep, NULL, TRUE);
2294 } else if (!excl && code == CM_ERROR_EXISTS) {
2295 /* not an exclusive create, and someone else tried
2296 * creating it already, then we open it anyway. We
2297 * don't bother retrying after this, since if this next
2298 * fails, that means that the file was deleted after we
2299 * started this call.
2301 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2305 setAttr.mask = CM_ATTRMASK_LENGTH;
2306 setAttr.length.LowPart = 0;
2307 setAttr.length.HighPart = 0;
2308 code = cm_SetAttr(scp, &setAttr, userp,
2311 } /* lookup succeeded */
2315 /* we don't need this any longer */
2317 cm_ReleaseSCache(dscp);
2320 /* something went wrong creating or truncating the file */
2322 cm_ReleaseSCache(scp);
2323 cm_ReleaseUser(userp);
2324 smb_FreeTran2Packet(outp);
2328 /* make sure we're about to open a file */
2329 if (scp->fileType != CM_SCACHETYPE_FILE) {
2331 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2332 cm_scache_t * targetScp = 0;
2333 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2335 /* we have a more accurate file to use (the
2336 * target of the symbolic link). Otherwise,
2337 * we'll just use the symlink anyway.
2339 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2341 cm_ReleaseSCache(scp);
2345 if (scp->fileType != CM_SCACHETYPE_FILE) {
2346 cm_ReleaseSCache(scp);
2347 cm_ReleaseUser(userp);
2348 smb_FreeTran2Packet(outp);
2349 return CM_ERROR_ISDIR;
2353 /* now all we have to do is open the file itself */
2354 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2358 lock_ObtainMutex(&fidp->mx);
2359 /* save a pointer to the vnode */
2360 osi_Log2(afsd_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2362 lock_ObtainMutex(&scp->mx);
2363 scp->flags |= CM_SCACHEFLAG_SMB_FID;
2364 lock_ReleaseMutex(&scp->mx);
2367 fidp->userp = userp;
2369 /* compute open mode */
2371 fidp->flags |= SMB_FID_OPENREAD;
2372 if (openMode == 1 || openMode == 2)
2373 fidp->flags |= SMB_FID_OPENWRITE;
2375 /* remember that the file was newly created */
2377 fidp->flags |= SMB_FID_CREATED;
2379 lock_ReleaseMutex(&fidp->mx);
2381 smb_ReleaseFID(fidp);
2383 cm_Open(scp, 0, userp);
2385 /* copy out remainder of the parms */
2387 outp->parmsp[parmSlot++] = fidp->fid;
2388 lock_ObtainMutex(&scp->mx);
2390 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2391 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2392 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2393 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2394 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2395 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2396 outp->parmsp[parmSlot++] = openMode;
2397 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2398 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2400 /* and the final "always present" stuff */
2401 outp->parmsp[parmSlot++] = openAction;
2402 /* next write out the "unique" ID */
2403 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2404 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2405 outp->parmsp[parmSlot++] = 0;
2406 if (returnEALength) {
2407 outp->parmsp[parmSlot++] = 0;
2408 outp->parmsp[parmSlot++] = 0;
2410 lock_ReleaseMutex(&scp->mx);
2411 outp->totalData = 0; /* total # of data bytes */
2412 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2414 smb_SendTran2Packet(vcp, outp, op);
2416 smb_FreeTran2Packet(outp);
2418 cm_ReleaseUser(userp);
2419 /* leave scp held since we put it in fidp->scp */
2423 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2426 unsigned short infolevel;
2428 infolevel = p->parmsp[0];
2430 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2432 return CM_ERROR_BADOP;
2435 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2437 smb_tran2Packet_t *outp;
2438 smb_tran2QFSInfo_t qi;
2440 static char FSname[8] = {'A', 0, 'F', 0, 'S', 0, 0, 0};
2442 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2444 switch (p->parmsp[0]) {
2445 case SMB_INFO_ALLOCATION:
2446 responseSize = sizeof(qi.u.allocInfo);
2448 case SMB_INFO_VOLUME:
2449 responseSize = sizeof(qi.u.volumeInfo);
2451 case SMB_QUERY_FS_VOLUME_INFO:
2452 responseSize = sizeof(qi.u.FSvolumeInfo);
2454 case SMB_QUERY_FS_SIZE_INFO:
2455 responseSize = sizeof(qi.u.FSsizeInfo);
2457 case SMB_QUERY_FS_DEVICE_INFO:
2458 responseSize = sizeof(qi.u.FSdeviceInfo);
2460 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2461 responseSize = sizeof(qi.u.FSattributeInfo);
2463 case SMB_INFO_UNIX: /* CIFS Unix Info */
2464 case SMB_INFO_MACOS: /* Mac FS Info */
2466 return CM_ERROR_BADOP;
2469 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2470 switch (p->parmsp[0]) {
2471 case SMB_INFO_ALLOCATION:
2473 qi.u.allocInfo.FSID = 0;
2474 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2475 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2476 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2477 qi.u.allocInfo.bytesPerSector = 1024;
2480 case SMB_INFO_VOLUME:
2482 qi.u.volumeInfo.vsn = 1234;
2483 qi.u.volumeInfo.vnCount = 4;
2484 /* we're supposed to pad it out with zeroes to the end */
2485 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2486 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2489 case SMB_QUERY_FS_VOLUME_INFO:
2490 /* FS volume info */
2491 memset((char *)&qi.u.FSvolumeInfo.vct, 0, 4);
2492 qi.u.FSvolumeInfo.vsn = 1234;
2493 qi.u.FSvolumeInfo.vnCount = 8;
2494 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0\0", 8);
2497 case SMB_QUERY_FS_SIZE_INFO:
2499 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2500 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2501 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2502 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2503 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2504 qi.u.FSsizeInfo.bytesPerSector = 1024;
2507 case SMB_QUERY_FS_DEVICE_INFO:
2508 /* FS device info */
2509 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2510 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2513 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2514 /* FS attribute info */
2515 /* attributes, defined in WINNT.H:
2516 * FILE_CASE_SENSITIVE_SEARCH 0x1
2517 * FILE_CASE_PRESERVED_NAMES 0x2
2518 * FILE_VOLUME_QUOTAS 0x10
2519 * <no name defined> 0x4000
2520 * If bit 0x4000 is not set, Windows 95 thinks
2521 * we can't handle long (non-8.3) names,
2522 * despite our protestations to the contrary.
2524 qi.u.FSattributeInfo.attributes = 0x4003;
2525 qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
2526 qi.u.FSattributeInfo.FSnameLength = sizeof(FSname);
2527 memcpy(qi.u.FSattributeInfo.FSname, FSname, sizeof(FSname));
2531 /* copy out return data, and set corresponding sizes */
2532 outp->totalParms = 0;
2533 outp->totalData = responseSize;
2534 memcpy(outp->datap, &qi, responseSize);
2536 /* send and free the packets */
2537 smb_SendTran2Packet(vcp, outp, op);
2538 smb_FreeTran2Packet(outp);
2543 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2545 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2546 return CM_ERROR_BADOP;
2549 struct smb_ShortNameRock {
2553 size_t shortNameLen;
2556 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2559 struct smb_ShortNameRock *rockp;
2563 /* compare both names and vnodes, though probably just comparing vnodes
2564 * would be safe enough.
2566 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2568 if (ntohl(dep->fid.vnode) != rockp->vnode)
2570 /* This is the entry */
2571 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2572 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2573 return CM_ERROR_STOPNOW;
2576 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2577 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2579 struct smb_ShortNameRock rock;
2583 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2587 spacep = cm_GetSpace();
2588 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2590 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2592 cm_FreeSpace(spacep);
2597 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2598 cm_ReleaseSCache(dscp);
2599 cm_ReleaseUser(userp);
2600 return CM_ERROR_PATH_NOT_COVERED;
2602 #endif /* DFS_SUPPORT */
2604 if (!lastNamep) lastNamep = pathp;
2607 thyper.HighPart = 0;
2608 rock.shortName = shortName;
2610 rock.maskp = lastNamep;
2611 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2613 cm_ReleaseSCache(dscp);
2616 return CM_ERROR_NOSUCHFILE;
2617 if (code == CM_ERROR_STOPNOW) {
2618 *shortNameLenp = rock.shortNameLen;
2624 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2626 smb_tran2Packet_t *outp;
2629 unsigned short infoLevel;
2630 smb_tran2QPathInfo_t qpi;
2632 unsigned short attributes;
2633 unsigned long extAttributes;
2638 cm_scache_t *scp, *dscp;
2639 int scp_mx_held = 0;
2649 infoLevel = p->parmsp[0];
2650 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2652 else if (infoLevel == SMB_INFO_STANDARD)
2653 responseSize = sizeof(qpi.u.QPstandardInfo);
2654 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2655 responseSize = sizeof(qpi.u.QPeaSizeInfo);
2656 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2657 responseSize = sizeof(qpi.u.QPfileBasicInfo);
2658 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2659 responseSize = sizeof(qpi.u.QPfileStandardInfo);
2660 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2661 responseSize = sizeof(qpi.u.QPfileEaInfo);
2662 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2663 responseSize = sizeof(qpi.u.QPfileNameInfo);
2664 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
2665 responseSize = sizeof(qpi.u.QPfileAllInfo);
2666 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2667 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2669 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2670 p->opcode, infoLevel);
2671 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
2675 pathp = (char *)(&p->parmsp[3]);
2676 if (smb_StoreAnsiFilenames)
2677 OemToChar(pathp,pathp);
2678 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2679 osi_LogSaveString(smb_logp, pathp));
2681 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2683 if (infoLevel > 0x100)
2684 outp->totalParms = 2;
2686 outp->totalParms = 0;
2687 outp->totalData = responseSize;
2689 /* now, if we're at infoLevel 6, we're only being asked to check
2690 * the syntax, so we just OK things now. In particular, we're *not*
2691 * being asked to verify anything about the state of any parent dirs.
2693 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2694 smb_SendTran2Packet(vcp, outp, opx);
2695 smb_FreeTran2Packet(outp);
2699 userp = smb_GetTran2User(vcp, p);
2701 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2702 smb_FreeTran2Packet(outp);
2703 return CM_ERROR_BADSMB;
2706 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2708 cm_ReleaseUser(userp);
2709 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2710 smb_FreeTran2Packet(outp);
2715 * XXX Strange hack XXX
2717 * As of Patch 7 (13 January 98), we are having the following problem:
2718 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2719 * requests to look up "desktop.ini" in all the subdirectories.
2720 * This can cause zillions of timeouts looking up non-existent cells
2721 * and volumes, especially in the top-level directory.
2723 * We have not found any way to avoid this or work around it except
2724 * to explicitly ignore the requests for mount points that haven't
2725 * yet been evaluated and for directories that haven't yet been
2728 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2729 spacep = cm_GetSpace();
2730 smb_StripLastComponent(spacep->data, &lastComp, pathp);
2731 #ifndef SPECIAL_FOLDERS
2732 /* Make sure that lastComp is not NULL */
2734 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2735 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2739 userp, tidPathp, &req, &dscp);
2742 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2743 if ( WANTS_DFS_PATHNAMES(p) )
2744 code = CM_ERROR_PATH_NOT_COVERED;
2746 code = CM_ERROR_BADSHARENAME;
2748 #endif /* DFS_SUPPORT */
2749 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2750 code = CM_ERROR_NOSUCHFILE;
2751 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2752 cm_buf_t *bp = buf_Find(dscp, &hzero);
2756 code = CM_ERROR_NOSUCHFILE;
2758 cm_ReleaseSCache(dscp);
2760 cm_FreeSpace(spacep);
2761 cm_ReleaseUser(userp);
2762 smb_SendTran2Error(vcp, p, opx, code);
2763 smb_FreeTran2Packet(outp);
2769 #endif /* SPECIAL_FOLDERS */
2771 cm_FreeSpace(spacep);
2774 /* now do namei and stat, and copy out the info */
2775 code = cm_NameI(cm_data.rootSCachep, pathp,
2776 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2779 cm_ReleaseUser(userp);
2780 smb_SendTran2Error(vcp, p, opx, code);
2781 smb_FreeTran2Packet(outp);
2786 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2787 cm_ReleaseSCache(scp);
2788 cm_ReleaseUser(userp);
2789 if ( WANTS_DFS_PATHNAMES(p) )
2790 code = CM_ERROR_PATH_NOT_COVERED;
2792 code = CM_ERROR_BADSHARENAME;
2793 smb_SendTran2Error(vcp, p, opx, code);
2794 smb_FreeTran2Packet(outp);
2797 #endif /* DFS_SUPPORT */
2799 lock_ObtainMutex(&scp->mx);
2801 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2802 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2803 if (code) goto done;
2805 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2807 /* now we have the status in the cache entry, and everything is locked.
2808 * Marshall the output data.
2810 /* for info level 108, figure out short name */
2811 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
2812 code = cm_GetShortName(pathp, userp, &req,
2813 tidPathp, scp->fid.vnode, shortName,
2819 qpi.u.QPfileAltNameInfo.fileNameLength = (len + 1) * 2;
2820 mbstowcs((unsigned short *)qpi.u.QPfileAltNameInfo.fileName, shortName, len + 1);
2824 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2825 len = strlen(lastComp);
2826 qpi.u.QPfileNameInfo.fileNameLength = (len + 1) * 2;
2827 mbstowcs((unsigned short *)qpi.u.QPfileNameInfo.fileName, lastComp, len + 1);
2831 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2832 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2833 qpi.u.QPstandardInfo.creationDateTime = dosTime;
2834 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
2835 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
2836 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
2837 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
2838 attributes = smb_Attributes(scp);
2839 qpi.u.QPstandardInfo.attributes = attributes;
2840 qpi.u.QPstandardInfo.eaSize = 0;
2842 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2843 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2844 qpi.u.QPfileBasicInfo.creationTime = ft;
2845 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
2846 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
2847 qpi.u.QPfileBasicInfo.changeTime = ft;
2848 extAttributes = smb_ExtAttributes(scp);
2849 qpi.u.QPfileBasicInfo.attributes = extAttributes;
2850 qpi.u.QPfileBasicInfo.reserved = 0;
2852 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2853 smb_fid_t *fidp = smb_FindFIDByScache(vcp, scp);
2855 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
2856 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
2857 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
2858 qpi.u.QPfileStandardInfo.directory =
2859 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2860 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2861 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2862 qpi.u.QPfileStandardInfo.reserved = 0;
2865 lock_ReleaseMutex(&scp->mx);
2867 lock_ObtainMutex(&fidp->mx);
2868 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
2869 lock_ReleaseMutex(&fidp->mx);
2870 smb_ReleaseFID(fidp);
2872 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
2874 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2875 qpi.u.QPfileEaInfo.eaSize = 0;
2877 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
2878 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2879 qpi.u.QPfileAllInfo.creationTime = ft;
2880 qpi.u.QPfileAllInfo.lastAccessTime = ft;
2881 qpi.u.QPfileAllInfo.lastWriteTime = ft;
2882 qpi.u.QPfileAllInfo.changeTime = ft;
2883 extAttributes = smb_ExtAttributes(scp);
2884 qpi.u.QPfileAllInfo.attributes = extAttributes;
2885 qpi.u.QPfileAllInfo.allocationSize = scp->length;
2886 qpi.u.QPfileAllInfo.endOfFile = scp->length;
2887 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
2888 qpi.u.QPfileAllInfo.deletePending = 0;
2889 qpi.u.QPfileAllInfo.directory =
2890 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2891 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2892 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2893 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
2894 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
2895 qpi.u.QPfileAllInfo.eaSize = 0;
2896 qpi.u.QPfileAllInfo.accessFlags = 0;
2897 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
2898 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
2899 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
2900 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
2901 qpi.u.QPfileAllInfo.mode = 0;
2902 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
2903 len = strlen(lastComp);
2904 qpi.u.QPfileAllInfo.fileNameLength = (len + 1) * 2;
2905 mbstowcs((unsigned short *)qpi.u.QPfileAllInfo.fileName, lastComp, len + 1);
2908 /* send and free the packets */
2911 lock_ReleaseMutex(&scp->mx);
2912 cm_ReleaseSCache(scp);
2913 cm_ReleaseUser(userp);
2915 memcpy(outp->datap, &qpi, responseSize);
2916 smb_SendTran2Packet(vcp, outp, opx);
2918 smb_SendTran2Error(vcp, p, opx, code);
2920 smb_FreeTran2Packet(outp);
2925 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2928 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2929 return CM_ERROR_BADOP;
2933 unsigned short infoLevel;
2935 smb_tran2Packet_t *outp;
2936 smb_tran2QPathInfo_t *spi;
2938 cm_scache_t *scp, *dscp;
2946 infoLevel = p->parmsp[0];
2947 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
2948 if (infoLevel != SMB_INFO_STANDARD &&
2949 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
2950 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
2951 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2952 p->opcode, infoLevel);
2953 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2957 pathp = (char *)(&p->parmsp[3]);
2958 if (smb_StoreAnsiFilenames)
2959 OemToChar(pathp,pathp);
2960 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %s", infoLevel,
2961 osi_LogSaveString(smb_logp, pathp));
2963 userp = smb_GetTran2User(vcp, p);
2965 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
2966 code = CM_ERROR_BADSMB;
2970 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2971 if (code == CM_ERROR_TIDIPC) {
2972 /* Attempt to use a TID allocated for IPC. The client
2973 * is probably looking for DCE RPC end points which we
2974 * don't support OR it could be looking to make a DFS
2977 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2978 cm_ReleaseUser(userp);
2979 return CM_ERROR_NOSUCHPATH;
2983 * XXX Strange hack XXX
2985 * As of Patch 7 (13 January 98), we are having the following problem:
2986 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2987 * requests to look up "desktop.ini" in all the subdirectories.
2988 * This can cause zillions of timeouts looking up non-existent cells
2989 * and volumes, especially in the top-level directory.
2991 * We have not found any way to avoid this or work around it except
2992 * to explicitly ignore the requests for mount points that haven't
2993 * yet been evaluated and for directories that haven't yet been
2996 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2997 spacep = cm_GetSpace();
2998 smb_StripLastComponent(spacep->data, &lastComp, pathp);
2999 #ifndef SPECIAL_FOLDERS
3000 /* Make sure that lastComp is not NULL */
3002 if (stricmp(lastComp, "\\desktop.ini") == 0) {
3003 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3007 userp, tidPathp, &req, &dscp);
3010 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3011 if ( WANTS_DFS_PATHNAMES(p) )
3012 code = CM_ERROR_PATH_NOT_COVERED;
3014 code = CM_ERROR_BADSHARENAME;
3016 #endif /* DFS_SUPPORT */
3017 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3018 code = CM_ERROR_NOSUCHFILE;
3019 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3020 cm_buf_t *bp = buf_Find(dscp, &hzero);
3024 code = CM_ERROR_NOSUCHFILE;
3026 cm_ReleaseSCache(dscp);
3028 cm_FreeSpace(spacep);
3029 cm_ReleaseUser(userp);
3030 smb_SendTran2Error(vcp, p, opx, code);
3036 #endif /* SPECIAL_FOLDERS */
3038 cm_FreeSpace(spacep);
3041 /* now do namei and stat, and copy out the info */
3042 code = cm_NameI(cm_data.rootSCachep, pathp,
3043 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3045 cm_ReleaseUser(userp);
3046 smb_SendTran2Error(vcp, p, opx, code);
3050 fidp = smb_FindFIDByScache(vcp, scp);
3052 cm_ReleaseSCache(scp);
3053 cm_ReleaseUser(userp);
3054 smb_SendTran2Error(vcp, p, opx, code);
3058 lock_ObtainMutex(&fidp->mx);
3059 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
3060 lock_ReleaseMutex(&fidp->mx);
3061 cm_ReleaseSCache(scp);
3062 smb_ReleaseFID(fidp);
3063 cm_ReleaseUser(userp);
3064 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3067 lock_ReleaseMutex(&fidp->mx);
3069 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3071 outp->totalParms = 2;
3072 outp->totalData = 0;
3074 spi = (smb_tran2QPathInfo_t *)p->datap;
3075 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3078 /* lock the vnode with a callback; we need the current status
3079 * to determine what the new status is, in some cases.
3081 lock_ObtainMutex(&scp->mx);
3082 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3083 CM_SCACHESYNC_GETSTATUS
3084 | CM_SCACHESYNC_NEEDCALLBACK);
3086 lock_ReleaseMutex(&scp->mx);
3089 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3091 lock_ReleaseMutex(&scp->mx);
3092 lock_ObtainMutex(&fidp->mx);
3093 lock_ObtainMutex(&scp->mx);
3095 /* prepare for setattr call */
3096 attr.mask = CM_ATTRMASK_LENGTH;
3097 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3098 attr.length.HighPart = 0;
3100 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3101 smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3102 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3103 fidp->flags |= SMB_FID_MTIMESETDONE;
3106 if (spi->u.QPstandardInfo.attributes != 0) {
3107 if ((scp->unixModeBits & 0222)
3108 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3109 /* make a writable file read-only */
3110 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3111 attr.unixModeBits = scp->unixModeBits & ~0222;
3113 else if ((scp->unixModeBits & 0222) == 0
3114 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3115 /* make a read-only file writable */
3116 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3117 attr.unixModeBits = scp->unixModeBits | 0222;
3120 lock_ReleaseMutex(&scp->mx);
3121 lock_ReleaseMutex(&fidp->mx);
3125 code = cm_SetAttr(scp, &attr, userp, &req);
3129 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3130 /* we don't support EAs */
3131 code = CM_ERROR_INVAL;
3135 cm_ReleaseSCache(scp);
3136 cm_ReleaseUser(userp);
3137 smb_ReleaseFID(fidp);
3139 smb_SendTran2Packet(vcp, outp, opx);
3141 smb_SendTran2Error(vcp, p, opx, code);
3142 smb_FreeTran2Packet(outp);
3148 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3150 smb_tran2Packet_t *outp;
3152 unsigned long attributes;
3153 unsigned short infoLevel;
3160 smb_tran2QFileInfo_t qfi;
3167 fidp = smb_FindFID(vcp, fid, 0);
3170 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3174 infoLevel = p->parmsp[1];
3175 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3176 responseSize = sizeof(qfi.u.QFbasicInfo);
3177 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3178 responseSize = sizeof(qfi.u.QFstandardInfo);
3179 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3180 responseSize = sizeof(qfi.u.QFeaInfo);
3181 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3182 responseSize = sizeof(qfi.u.QFfileNameInfo);
3184 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3185 p->opcode, infoLevel);
3186 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
3187 smb_ReleaseFID(fidp);
3190 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3192 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3194 if (infoLevel > 0x100)
3195 outp->totalParms = 2;
3197 outp->totalParms = 0;
3198 outp->totalData = responseSize;
3200 userp = smb_GetTran2User(vcp, p);
3202 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3203 code = CM_ERROR_BADSMB;
3207 lock_ObtainMutex(&fidp->mx);
3208 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3210 osi_Log2(afsd_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3212 lock_ReleaseMutex(&fidp->mx);
3213 lock_ObtainMutex(&scp->mx);
3214 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3215 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3219 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3221 /* now we have the status in the cache entry, and everything is locked.
3222 * Marshall the output data.
3224 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3225 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3226 qfi.u.QFbasicInfo.creationTime = ft;
3227 qfi.u.QFbasicInfo.lastAccessTime = ft;
3228 qfi.u.QFbasicInfo.lastWriteTime = ft;
3229 qfi.u.QFbasicInfo.lastChangeTime = ft;
3230 attributes = smb_ExtAttributes(scp);
3231 qfi.u.QFbasicInfo.attributes = attributes;
3233 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3234 qfi.u.QFstandardInfo.allocationSize = scp->length;
3235 qfi.u.QFstandardInfo.endOfFile = scp->length;
3236 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3237 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3238 qfi.u.QFstandardInfo.directory =
3239 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3240 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3241 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3243 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3244 qfi.u.QFeaInfo.eaSize = 0;
3246 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3250 lock_ReleaseMutex(&scp->mx);
3251 lock_ObtainMutex(&fidp->mx);
3252 lock_ObtainMutex(&scp->mx);
3253 if (fidp->NTopen_wholepathp)
3254 name = fidp->NTopen_wholepathp;
3256 name = "\\"; /* probably can't happen */
3257 lock_ReleaseMutex(&fidp->mx);
3258 len = (unsigned long)strlen(name);
3259 outp->totalData = ((len+1)*2) + 4; /* this is actually what we want to return */
3260 qfi.u.QFfileNameInfo.fileNameLength = (len + 1) * 2;
3261 mbstowcs((unsigned short *)qfi.u.QFfileNameInfo.fileName, name, len + 1);
3264 /* send and free the packets */
3266 lock_ReleaseMutex(&scp->mx);
3267 cm_ReleaseSCache(scp);
3268 cm_ReleaseUser(userp);
3269 smb_ReleaseFID(fidp);
3271 memcpy(outp->datap, &qfi, responseSize);
3272 smb_SendTran2Packet(vcp, outp, opx);
3274 smb_SendTran2Error(vcp, p, opx, code);
3276 smb_FreeTran2Packet(outp);
3281 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3286 unsigned short infoLevel;
3287 smb_tran2Packet_t *outp;
3295 fidp = smb_FindFID(vcp, fid, 0);
3298 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3302 infoLevel = p->parmsp[1];
3303 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3304 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3305 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3306 p->opcode, infoLevel);
3307 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
3308 smb_ReleaseFID(fidp);
3312 lock_ObtainMutex(&fidp->mx);
3313 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) {
3314 lock_ReleaseMutex(&fidp->mx);
3315 smb_ReleaseFID(fidp);
3316 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3319 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3320 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3321 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3322 lock_ReleaseMutex(&fidp->mx);
3323 smb_ReleaseFID(fidp);
3324 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3329 osi_Log2(afsd_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3331 lock_ReleaseMutex(&fidp->mx);
3333 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3335 outp->totalParms = 2;
3336 outp->totalData = 0;
3338 userp = smb_GetTran2User(vcp, p);
3340 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3341 code = CM_ERROR_BADSMB;
3345 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3347 unsigned int attribute;
3349 smb_tran2QFileInfo_t *sfi;
3351 sfi = (smb_tran2QFileInfo_t *)p->datap;
3353 /* lock the vnode with a callback; we need the current status
3354 * to determine what the new status is, in some cases.
3356 lock_ObtainMutex(&scp->mx);
3357 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3358 CM_SCACHESYNC_GETSTATUS
3359 | CM_SCACHESYNC_NEEDCALLBACK);
3361 lock_ReleaseMutex(&scp->mx);
3365 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3367 lock_ReleaseMutex(&scp->mx);
3368 lock_ObtainMutex(&fidp->mx);
3369 lock_ObtainMutex(&scp->mx);
3371 /* prepare for setattr call */
3374 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3375 /* when called as result of move a b, lastMod is (-1, -1).
3376 * If the check for -1 is not present, timestamp
3377 * of the resulting file will be 1969 (-1)
3379 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3380 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3381 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3382 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3383 fidp->flags |= SMB_FID_MTIMESETDONE;
3386 attribute = sfi->u.QFbasicInfo.attributes;
3387 if (attribute != 0) {
3388 if ((scp->unixModeBits & 0222)
3389 && (attribute & SMB_ATTR_READONLY) != 0) {
3390 /* make a writable file read-only */
3391 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3392 attr.unixModeBits = scp->unixModeBits & ~0222;
3394 else if ((scp->unixModeBits & 0222) == 0
3395 && (attribute & SMB_ATTR_READONLY) == 0) {
3396 /* make a read-only file writable */
3397 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3398 attr.unixModeBits = scp->unixModeBits | 0222;
3401 lock_ReleaseMutex(&scp->mx);
3402 lock_ReleaseMutex(&fidp->mx);
3406 code = cm_SetAttr(scp, &attr, userp, &req);
3410 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3411 if (*((char *)(p->datap))) { /* File is Deleted */
3412 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3415 lock_ObtainMutex(&fidp->mx);
3416 fidp->flags |= SMB_FID_DELONCLOSE;
3417 lock_ReleaseMutex(&fidp->mx);
3422 lock_ObtainMutex(&fidp->mx);
3423 fidp->flags &= ~SMB_FID_DELONCLOSE;
3424 lock_ReleaseMutex(&fidp->mx);
3427 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3428 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3429 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3432 attr.mask = CM_ATTRMASK_LENGTH;
3433 attr.length.LowPart = size.LowPart;
3434 attr.length.HighPart = size.HighPart;
3435 code = cm_SetAttr(scp, &attr, userp, &req);
3439 cm_ReleaseSCache(scp);
3440 cm_ReleaseUser(userp);
3441 smb_ReleaseFID(fidp);
3443 smb_SendTran2Packet(vcp, outp, opx);
3445 smb_SendTran2Error(vcp, p, opx, code);
3446 smb_FreeTran2Packet(outp);
3452 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3454 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3455 return CM_ERROR_BADOP;
3459 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3461 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3462 return CM_ERROR_BADOP;
3466 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3468 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3469 return CM_ERROR_BADOP;
3473 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3475 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3476 return CM_ERROR_BADOP;
3480 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3482 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3483 return CM_ERROR_BADOP;
3487 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3489 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3490 return CM_ERROR_BADOP;
3493 struct smb_v2_referral {
3495 USHORT ReferralFlags;
3498 USHORT DfsPathOffset;
3499 USHORT DfsAlternativePathOffset;
3500 USHORT NetworkAddressOffset;
3504 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3506 /* This is a UNICODE only request (bit15 of Flags2) */
3507 /* The TID must be IPC$ */
3509 /* The documentation for the Flags response field is contradictory */
3511 /* Use Version 1 Referral Element Format */
3512 /* ServerType = 0; indicates the next server should be queried for the file */
3513 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3514 /* Node = UnicodeString of UNC path of the next share name */
3517 int maxReferralLevel = 0;
3518 char requestFileName[1024] = "";
3519 smb_tran2Packet_t *outp = 0;
3520 cm_user_t *userp = 0;
3522 CPINFO CodePageInfo;
3523 int i, nbnLen, reqLen;
3528 maxReferralLevel = p->parmsp[0];
3530 GetCPInfo(CP_ACP, &CodePageInfo);
3531 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
3532 requestFileName, 1024, NULL, NULL);
3534 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
3535 maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3537 nbnLen = strlen(cm_NetbiosName);
3538 reqLen = strlen(requestFileName);
3540 if (reqLen == nbnLen + 5 &&
3541 requestFileName[0] == '\\' &&
3542 !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3543 requestFileName[nbnLen+1] == '\\' &&
3544 (!_strnicmp("all",&requestFileName[nbnLen+2],3) ||
3545 !_strnicmp("*.",&requestFileName[nbnLen+2],2)))
3548 struct smb_v2_referral * v2ref;
3549 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
3551 sp = (USHORT *)outp->datap;
3553 sp[idx++] = reqLen; /* path consumed */
3554 sp[idx++] = 1; /* number of referrals */
3555 sp[idx++] = 0x03; /* flags */
3556 #ifdef DFS_VERSION_1
3557 sp[idx++] = 1; /* Version Number */
3558 sp[idx++] = reqLen + 4; /* Referral Size */
3559 sp[idx++] = 1; /* Type = SMB Server */
3560 sp[idx++] = 0; /* Do not strip path consumed */
3561 for ( i=0;i<=reqLen; i++ )
3562 sp[i+idx] = requestFileName[i];
3563 #else /* DFS_VERSION_2 */
3564 sp[idx++] = 2; /* Version Number */
3565 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3566 idx += (sizeof(struct smb_v2_referral) / 2);
3567 v2ref = (struct smb_v2_referral *) &sp[5];
3568 v2ref->ServerType = 1; /* SMB Server */
3569 v2ref->ReferralFlags = 0x03;
3570 v2ref->Proximity = 0; /* closest */
3571 v2ref->TimeToLive = 3600; /* seconds */
3572 v2ref->DfsPathOffset = idx * 2;
3573 v2ref->DfsAlternativePathOffset = idx * 2;
3574 v2ref->NetworkAddressOffset = 0;
3575 for ( i=0;i<=reqLen; i++ )
3576 sp[i+idx] = requestFileName[i];
3579 userp = smb_GetTran2User(vcp, p);
3581 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3582 code = CM_ERROR_BADSMB;
3587 code = CM_ERROR_NOSUCHPATH;
3592 cm_ReleaseUser(userp);
3594 smb_SendTran2Packet(vcp, outp, op);
3596 smb_SendTran2Error(vcp, p, op, code);
3598 smb_FreeTran2Packet(outp);
3601 #else /* DFS_SUPPORT */
3602 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3603 return CM_ERROR_BADOP;
3604 #endif /* DFS_SUPPORT */
3608 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3610 /* This is a UNICODE only request (bit15 of Flags2) */
3612 /* There is nothing we can do about this operation. The client is going to
3613 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3614 * Unfortunately, there is really nothing we can do about it other then log it
3615 * somewhere. Even then I don't think there is anything for us to do.
3616 * So let's return an error value.
3619 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3620 return CM_ERROR_BADOP;
3624 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3625 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3630 cm_scache_t *targetScp; /* target if scp is a symlink */
3635 unsigned short attr;
3636 unsigned long lattr;
3637 smb_dirListPatch_t *patchp;
3638 smb_dirListPatch_t *npatchp;
3640 for(patchp = *dirPatchespp; patchp; patchp =
3641 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3642 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3644 lock_ObtainMutex(&scp->mx);
3645 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3646 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3648 lock_ReleaseMutex(&scp->mx);
3649 cm_ReleaseSCache(scp);
3651 dptr = patchp->dptr;
3653 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3654 errors in the client. */
3655 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3656 /* 1969-12-31 23:59:59 +00 */
3657 ft.dwHighDateTime = 0x19DB200;
3658 ft.dwLowDateTime = 0x5BB78980;
3660 /* copy to Creation Time */
3661 *((FILETIME *)dptr) = ft;
3664 /* copy to Last Access Time */
3665 *((FILETIME *)dptr) = ft;
3668 /* copy to Last Write Time */
3669 *((FILETIME *)dptr) = ft;
3672 /* copy to Change Time */
3673 *((FILETIME *)dptr) = ft;
3676 /* merge in hidden attribute */
3677 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3678 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3682 /* 1969-12-31 23:59:58 +00*/
3683 dosTime = 0xEBBFBF7D;
3685 /* and copy out date */
3686 shortTemp = (dosTime>>16) & 0xffff;
3687 *((u_short *)dptr) = shortTemp;
3690 /* copy out creation time */
3691 shortTemp = dosTime & 0xffff;
3692 *((u_short *)dptr) = shortTemp;
3695 /* and copy out date */
3696 shortTemp = (dosTime>>16) & 0xffff;
3697 *((u_short *)dptr) = shortTemp;
3700 /* copy out access time */
3701 shortTemp = dosTime & 0xffff;
3702 *((u_short *)dptr) = shortTemp;
3705 /* and copy out date */
3706 shortTemp = (dosTime>>16) & 0xffff;
3707 *((u_short *)dptr) = shortTemp;
3710 /* copy out mod time */
3711 shortTemp = dosTime & 0xffff;
3712 *((u_short *)dptr) = shortTemp;
3715 /* merge in hidden (dot file) attribute */
3716 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3717 attr = SMB_ATTR_HIDDEN;
3718 *dptr++ = attr & 0xff;
3719 *dptr++ = (attr >> 8) & 0xff;
3725 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3727 /* now watch for a symlink */
3729 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3730 lock_ReleaseMutex(&scp->mx);
3731 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3733 /* we have a more accurate file to use (the
3734 * target of the symbolic link). Otherwise,
3735 * we'll just use the symlink anyway.
3737 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3739 cm_ReleaseSCache(scp);
3742 lock_ObtainMutex(&scp->mx);
3745 dptr = patchp->dptr;
3747 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3749 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3751 /* copy to Creation Time */
3752 *((FILETIME *)dptr) = ft;
3755 /* copy to Last Access Time */
3756 *((FILETIME *)dptr) = ft;
3759 /* copy to Last Write Time */
3760 *((FILETIME *)dptr) = ft;
3763 /* copy to Change Time */
3764 *((FILETIME *)dptr) = ft;
3767 /* Use length for both file length and alloc length */
3768 *((LARGE_INTEGER *)dptr) = scp->length;
3770 *((LARGE_INTEGER *)dptr) = scp->length;
3773 /* Copy attributes */
3774 lattr = smb_ExtAttributes(scp);
3775 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3776 if (lattr == SMB_ATTR_NORMAL)
3777 lattr = SMB_ATTR_DIRECTORY;
3779 lattr |= SMB_ATTR_DIRECTORY;
3781 /* merge in hidden (dot file) attribute */
3782 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3783 if (lattr == SMB_ATTR_NORMAL)
3784 lattr = SMB_ATTR_HIDDEN;
3786 lattr |= SMB_ATTR_HIDDEN;
3788 *((u_long *)dptr) = lattr;
3792 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3794 /* and copy out date */
3795 shortTemp = (dosTime>>16) & 0xffff;
3796 *((u_short *)dptr) = shortTemp;
3799 /* copy out creation time */
3800 shortTemp = dosTime & 0xffff;
3801 *((u_short *)dptr) = shortTemp;
3804 /* and copy out date */
3805 shortTemp = (dosTime>>16) & 0xffff;
3806 *((u_short *)dptr) = shortTemp;
3809 /* copy out access time */
3810 shortTemp = dosTime & 0xffff;
3811 *((u_short *)dptr) = shortTemp;
3814 /* and copy out date */
3815 shortTemp = (dosTime>>16) & 0xffff;
3816 *((u_short *)dptr) = shortTemp;
3819 /* copy out mod time */
3820 shortTemp = dosTime & 0xffff;
3821 *((u_short *)dptr) = shortTemp;
3824 /* copy out file length and alloc length,
3825 * using the same for both
3827 *((u_long *)dptr) = scp->length.LowPart;
3829 *((u_long *)dptr) = scp->length.LowPart;
3832 /* finally copy out attributes as short */
3833 attr = smb_Attributes(scp);
3834 /* merge in hidden (dot file) attribute */
3835 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3836 if (lattr == SMB_ATTR_NORMAL)
3837 lattr = SMB_ATTR_HIDDEN;
3839 lattr |= SMB_ATTR_HIDDEN;
3841 *dptr++ = attr & 0xff;
3842 *dptr++ = (attr >> 8) & 0xff;
3845 lock_ReleaseMutex(&scp->mx);
3846 cm_ReleaseSCache(scp);
3849 /* now free the patches */
3850 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3851 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3855 /* and mark the list as empty */
3856 *dirPatchespp = NULL;
3861 #ifndef USE_OLD_MATCHING
3862 // char table for case insensitive comparison
3863 char mapCaseTable[256];
3865 VOID initUpperCaseTable(VOID)
3868 for (i = 0; i < 256; ++i)
3869 mapCaseTable[i] = toupper(i);
3870 // make '"' match '.'
3871 mapCaseTable[(int)'"'] = toupper('.');
3872 // make '<' match '*'
3873 mapCaseTable[(int)'<'] = toupper('*');
3874 // make '>' match '?'
3875 mapCaseTable[(int)'>'] = toupper('?');
3878 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3880 // Note : this procedure works recursively calling itself.
3882 // PSZ pattern : string containing metacharacters.
3883 // PSZ name : file name to be compared with 'pattern'.
3885 // BOOL : TRUE/FALSE (match/mistmatch)
3888 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
3890 PSZ pename; // points to the last 'name' character
3892 pename = name + strlen(name) - 1;
3903 if (*pattern == '\0')
3905 for (p = pename; p >= name; --p) {
3906 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
3907 !casefold && (*p == *pattern)) &&
3908 szWildCardMatchFileName(pattern + 1, p + 1, casefold))
3913 if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
3914 (!casefold && *name != *pattern))
3921 /* if all we have left are wildcards, then we match */
3922 for (;*pattern; pattern++) {
3923 if (*pattern != '*' && *pattern != '?')
3929 /* do a case-folding search of the star name mask with the name in namep.
3930 * Return 1 if we match, otherwise 0.
3932 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3935 int i, j, star, qmark, casefold, retval;
3937 /* make sure we only match 8.3 names, if requested */
3938 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3941 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
3943 /* optimize the pattern:
3944 * if there is a mixture of '?' and '*',
3945 * for example the sequence "*?*?*?*"
3946 * must be turned into the form "*"
3948 newmask = (char *)malloc(strlen(maskp)+1);
3949 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3950 switch ( maskp[i] ) {
3962 } else if ( qmark ) {
3966 newmask[j++] = maskp[i];
3973 } else if ( qmark ) {
3977 newmask[j++] = '\0';
3979 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
3985 #else /* USE_OLD_MATCHING */
3986 /* do a case-folding search of the star name mask with the name in namep.
3987 * Return 1 if we match, otherwise 0.
3989 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3991 unsigned char tcp1, tcp2; /* Pattern characters */
3992 unsigned char tcn1; /* Name characters */
3993 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3994 char *starNamep, *starMaskp;
3995 static char nullCharp[] = {0};
3996 int casefold = flags & CM_FLAG_CASEFOLD;
3998 /* make sure we only match 8.3 names, if requested */
3999 req8dot3 = (flags & CM_FLAG_8DOT3);
4000 if (req8dot3 && !cm_Is8Dot3(namep))
4005 /* Next pattern character */
4008 /* Next name character */
4012 /* 0 - end of pattern */
4018 else if (tcp1 == '.' || tcp1 == '"') {
4028 * first dot in pattern;
4029 * must match dot or end of name
4034 else if (tcn1 == '.') {
4043 else if (tcp1 == '?') {
4044 if (tcn1 == 0 || tcn1 == '.')
4049 else if (tcp1 == '>') {
4050 if (tcn1 != 0 && tcn1 != '.')
4054 else if (tcp1 == '*' || tcp1 == '<') {
4058 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
4059 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
4074 * pattern character after '*' is not null or
4075 * period. If it is '?' or '>', we are not
4076 * going to understand it. If it is '*' or
4077 * '<', we are going to skip over it. None of
4078 * these are likely, I hope.
4080 /* skip over '*' and '<' */
4081 while (tcp2 == '*' || tcp2 == '<')
4084 /* skip over characters that don't match tcp2 */
4085 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
4086 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
4087 (!casefold && tcn1 != tcp2)))
4091 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
4094 /* Remember where we are */
4104 /* tcp1 is not a wildcard */
4105 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
4106 (!casefold && tcn1 == tcp1)) {
4111 /* if trying to match a star pattern, go back */
4113 maskp = starMaskp - 2;
4114 namep = starNamep + 1;
4123 #endif /* USE_OLD_MATCHING */
4125 /* smb_ReceiveTran2SearchDir implements both
4126 * Tran2_Find_First and Tran2_Find_Next
4128 #define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
4129 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
4130 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
4131 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
4132 #define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
4134 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4139 long code = 0, code2 = 0;
4143 smb_dirListPatch_t *dirListPatchesp;
4144 smb_dirListPatch_t *curPatchp;
4147 long orbytes; /* # of bytes in this output record */
4148 long ohbytes; /* # of bytes, except file name */
4149 long onbytes; /* # of bytes in name, incl. term. null */
4150 osi_hyper_t dirLength;
4151 osi_hyper_t bufferOffset;
4152 osi_hyper_t curOffset;
4154 smb_dirSearch_t *dsp;
4158 cm_pageHeader_t *pageHeaderp;
4159 cm_user_t *userp = NULL;
4162 long nextEntryCookie;
4163 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4164 char *op; /* output data ptr */
4165 char *origOp; /* original value of op */
4166 cm_space_t *spacep; /* for pathname buffer */
4167 long maxReturnData; /* max # of return data */
4168 long maxReturnParms; /* max # of return parms */
4169 long bytesInBuffer; /* # data bytes in the output buffer */
4171 char *maskp; /* mask part of path */
4175 smb_tran2Packet_t *outp; /* response packet */
4178 char shortName[13]; /* 8.3 name if needed */
4190 if (p->opcode == 1) {
4191 /* find first; obtain basic parameters from request */
4192 attribute = p->parmsp[0];
4193 maxCount = p->parmsp[1];
4194 infoLevel = p->parmsp[3];
4195 searchFlags = p->parmsp[2];
4196 dsp = smb_NewDirSearch(1);
4197 dsp->attribute = attribute;
4198 pathp = ((char *) p->parmsp) + 12; /* points to path */
4199 if (smb_StoreAnsiFilenames)
4200 OemToChar(pathp,pathp);
4202 maskp = strrchr(pathp, '\\');
4206 maskp++; /* skip over backslash */
4207 strcpy(dsp->mask, maskp); /* and save mask */
4208 /* track if this is likely to match a lot of entries */
4209 starPattern = smb_V3IsStarMask(maskp);
4212 osi_assert(p->opcode == 2);
4213 /* find next; obtain basic parameters from request or open dir file */
4214 dsp = smb_FindDirSearch(p->parmsp[0]);
4215 maxCount = p->parmsp[1];
4216 infoLevel = p->parmsp[2];
4217 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4218 searchFlags = p->parmsp[5];
4220 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4221 p->parmsp[0], nextCookie);
4222 return CM_ERROR_BADFD;
4224 attribute = dsp->attribute;
4227 starPattern = 1; /* assume, since required a Find Next */
4230 switch ( infoLevel ) {
4231 case SMB_INFO_STANDARD:
4234 case SMB_INFO_QUERY_EA_SIZE:
4235 s = "InfoQueryEaSize";
4237 case SMB_INFO_QUERY_EAS_FROM_LIST:
4238 s = "InfoQueryEasFromList";
4240 case SMB_FIND_FILE_DIRECTORY_INFO:
4241 s = "FindFileDirectoryInfo";
4243 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4244 s = "FindFileFullDirectoryInfo";
4246 case SMB_FIND_FILE_NAMES_INFO:
4247 s = "FindFileNamesInfo";
4249 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4250 s = "FindFileBothDirectoryInfo";
4253 s = "unknownInfoLevel";
4256 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
4259 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4260 attribute, infoLevel, maxCount, searchFlags);
4262 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
4263 p->opcode, dsp->cookie, nextCookie);
4265 if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4266 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4267 smb_ReleaseDirSearch(dsp);
4268 return CM_ERROR_INVAL;
4271 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4272 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4274 dirListPatchesp = NULL;
4276 maxReturnData = p->maxReturnData;
4277 if (p->opcode == 1) /* find first */
4278 maxReturnParms = 10; /* bytes */
4280 maxReturnParms = 8; /* bytes */
4282 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4283 if (maxReturnData > 6000)
4284 maxReturnData = 6000;
4285 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4287 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4290 osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
4291 maxCount, osi_LogSaveString(smb_logp, pathp));
4293 /* bail out if request looks bad */
4294 if (p->opcode == 1 && !pathp) {
4295 smb_ReleaseDirSearch(dsp);
4296 smb_FreeTran2Packet(outp);
4297 return CM_ERROR_BADSMB;
4300 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
4301 dsp->cookie, nextCookie, attribute);
4303 userp = smb_GetTran2User(vcp, p);
4305 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
4306 smb_ReleaseDirSearch(dsp);
4307 smb_FreeTran2Packet(outp);
4308 return CM_ERROR_BADSMB;
4311 /* try to get the vnode for the path name next */
4312 lock_ObtainMutex(&dsp->mx);
4315 osi_Log2(afsd_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4319 spacep = cm_GetSpace();
4320 smb_StripLastComponent(spacep->data, NULL, pathp);
4321 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4323 cm_ReleaseUser(userp);
4324 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4325 smb_FreeTran2Packet(outp);
4326 lock_ReleaseMutex(&dsp->mx);
4327 smb_DeleteDirSearch(dsp);
4328 smb_ReleaseDirSearch(dsp);
4331 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4332 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4333 userp, tidPathp, &req, &scp);
4334 cm_FreeSpace(spacep);
4337 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4338 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4339 cm_ReleaseSCache(scp);
4340 cm_ReleaseUser(userp);
4341 if ( WANTS_DFS_PATHNAMES(p) )
4342 code = CM_ERROR_PATH_NOT_COVERED;
4344 code = CM_ERROR_BADSHARENAME;
4345 smb_SendTran2Error(vcp, p, opx, code);
4346 smb_FreeTran2Packet(outp);
4347 lock_ReleaseMutex(&dsp->mx);
4348 smb_DeleteDirSearch(dsp);
4349 smb_ReleaseDirSearch(dsp);
4352 #endif /* DFS_SUPPORT */
4354 osi_Log2(afsd_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4355 /* we need one hold for the entry we just stored into,
4356 * and one for our own processing. When we're done
4357 * with this function, we'll drop the one for our own
4358 * processing. We held it once from the namei call,
4359 * and so we do another hold now.
4362 lock_ObtainMutex(&scp->mx);
4363 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
4364 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4365 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4366 dsp->flags |= SMB_DIRSEARCH_BULKST;
4368 lock_ReleaseMutex(&scp->mx);
4371 lock_ReleaseMutex(&dsp->mx);
4373 cm_ReleaseUser(userp);
4374 smb_FreeTran2Packet(outp);
4375 smb_DeleteDirSearch(dsp);
4376 smb_ReleaseDirSearch(dsp);
4380 /* get the directory size */
4381 lock_ObtainMutex(&scp->mx);
4382 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4383 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4385 lock_ReleaseMutex(&scp->mx);
4386 cm_ReleaseSCache(scp);
4387 cm_ReleaseUser(userp);
4388 smb_FreeTran2Packet(outp);
4389 smb_DeleteDirSearch(dsp);
4390 smb_ReleaseDirSearch(dsp);
4394 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4397 dirLength = scp->length;
4399 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4400 curOffset.HighPart = 0;
4401 curOffset.LowPart = nextCookie;
4402 origOp = outp->datap;
4410 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4411 /* skip over resume key */
4414 /* make sure that curOffset.LowPart doesn't point to the first
4415 * 32 bytes in the 2nd through last dir page, and that it doesn't
4416 * point at the first 13 32-byte chunks in the first dir page,
4417 * since those are dir and page headers, and don't contain useful
4420 temp = curOffset.LowPart & (2048-1);
4421 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4422 /* we're in the first page */
4423 if (temp < 13*32) temp = 13*32;
4426 /* we're in a later dir page */
4427 if (temp < 32) temp = 32;
4430 /* make sure the low order 5 bits are zero */
4433 /* now put temp bits back ito curOffset.LowPart */
4434 curOffset.LowPart &= ~(2048-1);
4435 curOffset.LowPart |= temp;
4437 /* check if we've passed the dir's EOF */
4438 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4439 osi_Log0(smb_logp, "T2 search dir passed eof");
4444 /* check if we've returned all the names that will fit in the
4445 * response packet; we check return count as well as the number
4446 * of bytes requested. We check the # of bytes after we find
4447 * the dir entry, since we'll need to check its size.
4449 if (returnedNames >= maxCount) {
4450 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4451 returnedNames, maxCount);
4455 /* see if we can use the bufferp we have now; compute in which
4456 * page the current offset would be, and check whether that's
4457 * the offset of the buffer we have. If not, get the buffer.
4459 thyper.HighPart = curOffset.HighPart;
4460 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4461 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4464 buf_Release(bufferp);
4467 lock_ReleaseMutex(&scp->mx);
4468 lock_ObtainRead(&scp->bufCreateLock);
4469 code = buf_Get(scp, &thyper, &bufferp);
4470 lock_ReleaseRead(&scp->bufCreateLock);
4471 lock_ObtainMutex(&dsp->mx);
4473 /* now, if we're doing a star match, do bulk fetching
4474 * of all of the status info for files in the dir.
4477 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
4480 lock_ObtainMutex(&scp->mx);
4481 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4482 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
4483 /* Don't bulk stat if risking timeout */
4484 int now = GetTickCount();
4485 if (now - req.startTime > RDRtimeout) {
4486 scp->bulkStatProgress = thyper;
4487 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4488 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4490 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4493 lock_ObtainMutex(&scp->mx);
4495 lock_ReleaseMutex(&dsp->mx);
4497 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
4501 bufferOffset = thyper;
4503 /* now get the data in the cache */
4505 code = cm_SyncOp(scp, bufferp, userp, &req,
4507 CM_SCACHESYNC_NEEDCALLBACK
4508 | CM_SCACHESYNC_READ);
4510 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
4514 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4516 if (cm_HaveBuffer(scp, bufferp, 0)) {
4517 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4521 /* otherwise, load the buffer and try again */
4522 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4525 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4526 scp, bufferp, code);
4531 buf_Release(bufferp);
4535 } /* if (wrong buffer) ... */
4537 /* now we have the buffer containing the entry we're interested
4538 * in; copy it out if it represents a non-deleted entry.
4540 entryInDir = curOffset.LowPart & (2048-1);
4541 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4543 /* page header will help tell us which entries are free. Page
4544 * header can change more often than once per buffer, since
4545 * AFS 3 dir page size may be less than (but not more than)
4546 * a buffer package buffer.
4548 /* only look intra-buffer */
4549 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4550 temp &= ~(2048 - 1); /* turn off intra-page bits */
4551 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4553 /* now determine which entry we're looking at in the page.
4554 * If it is free (there's a free bitmap at the start of the
4555 * dir), we should skip these 32 bytes.
4557 slotInPage = (entryInDir & 0x7e0) >> 5;
4558 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
4559 (1 << (slotInPage & 0x7)))) {
4560 /* this entry is free */
4561 numDirChunks = 1; /* only skip this guy */
4565 tp = bufferp->datap + entryInBuffer;
4566 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4568 /* while we're here, compute the next entry's location, too,
4569 * since we'll need it when writing out the cookie into the dir
4572 * XXXX Probably should do more sanity checking.
4574 numDirChunks = cm_NameEntries(dep->name, &onbytes);
4576 /* compute offset of cookie representing next entry */
4577 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4579 /* Need 8.3 name? */
4581 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4582 && dep->fid.vnode != 0
4583 && !cm_Is8Dot3(dep->name)) {
4584 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4588 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %s (%s)",
4589 dep->fid.vnode, dep->fid.unique,
4590 osi_LogSaveString(smb_logp, dep->name),
4591 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4593 /* When matching, we are using doing a case fold if we have a wildcard mask.
4594 * If we get a non-wildcard match, it's a lookup for a specific file.
4596 if (dep->fid.vnode != 0 &&
4597 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
4599 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
4601 /* Eliminate entries that don't match requested attributes */
4602 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
4603 smb_IsDotFile(dep->name)) {
4604 osi_Log0(smb_logp, "T2 search dir skipping hidden");
4605 goto nextEntry; /* no hidden files */
4607 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4609 /* We have already done the cm_TryBulkStat above */
4610 fid.cell = scp->fid.cell;
4611 fid.volume = scp->fid.volume;
4612 fid.vnode = ntohl(dep->fid.vnode);
4613 fid.unique = ntohl(dep->fid.unique);
4614 fileType = cm_FindFileType(&fid);
4615 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
4616 "has filetype %d", dep->name,
4618 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4619 fileType == CM_SCACHETYPE_DFSLINK ||
4620 fileType == CM_SCACHETYPE_INVALID)
4621 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
4625 /* finally check if this name will fit */
4627 /* standard dir entry stuff */
4628 if (infoLevel < 0x101)
4629 ohbytes = 23; /* pre-NT */
4630 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4631 ohbytes = 12; /* NT names only */
4633 ohbytes = 64; /* NT */
4635 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
4636 ohbytes += 26; /* Short name & length */
4638 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4639 ohbytes += 4; /* if resume key required */
4642 if (infoLevel != SMB_INFO_STANDARD
4643 && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
4644 && infoLevel != SMB_FIND_FILE_NAMES_INFO)
4645 ohbytes += 4; /* EASIZE */
4647 /* add header to name & term. null */
4648 orbytes = onbytes + ohbytes + 1;
4650 /* now, we round up the record to a 4 byte alignment,
4651 * and we make sure that we have enough room here for
4652 * even the aligned version (so we don't have to worry
4653 * about an * overflow when we pad things out below).
4654 * That's the reason for the alignment arithmetic below.
4656 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4657 align = (4 - (orbytes & 3)) & 3;
4660 if (orbytes + bytesInBuffer + align > maxReturnData) {
4661 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4666 /* this is one of the entries to use: it is not deleted
4667 * and it matches the star pattern we're looking for.
4668 * Put out the name, preceded by its length.
4670 /* First zero everything else */
4671 memset(origOp, 0, ohbytes);
4673 if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
4674 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4675 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4676 *((u_long *)(op + 8)) = onbytes;
4678 *((u_long *)(op + 60)) = onbytes;
4679 strcpy(origOp+ohbytes, dep->name);
4680 if (smb_StoreAnsiFilenames)
4681 CharToOem(origOp+ohbytes, origOp+ohbytes);
4683 /* Short name if requested and needed */
4684 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4685 if (NeedShortName) {
4686 strcpy(op + 70, shortName);
4687 if (smb_StoreAnsiFilenames)
4688 CharToOem(op + 70, op + 70);
4689 *(op + 68) = (char)(shortNameEnd - shortName);
4693 /* now, adjust the # of entries copied */
4696 /* NextEntryOffset and FileIndex */
4697 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4698 int entryOffset = orbytes + align;
4699 *((u_long *)op) = entryOffset;
4700 *((u_long *)(op+4)) = nextEntryCookie;
4703 /* now we emit the attribute. This is tricky, since
4704 * we need to really stat the file to find out what
4705 * type of entry we've got. Right now, we're copying
4706 * out data from a buffer, while holding the scp
4707 * locked, so it isn't really convenient to stat
4708 * something now. We'll put in a place holder
4709 * now, and make a second pass before returning this
4710 * to get the real attributes. So, we just skip the
4711 * data for now, and adjust it later. We allocate a
4712 * patch record to make it easy to find this point
4713 * later. The replay will happen at a time when it is
4714 * safe to unlock the directory.
4716 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4717 curPatchp = malloc(sizeof(*curPatchp));
4718 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4720 curPatchp->dptr = op;
4721 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4722 curPatchp->dptr += 8;
4724 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4725 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4728 curPatchp->flags = 0;
4730 curPatchp->fid.cell = scp->fid.cell;
4731 curPatchp->fid.volume = scp->fid.volume;
4732 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4733 curPatchp->fid.unique = ntohl(dep->fid.unique);
4736 curPatchp->dep = dep;
4739 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4740 /* put out resume key */
4741 *((u_long *)origOp) = nextEntryCookie;
4743 /* Adjust byte ptr and count */
4744 origOp += orbytes; /* skip entire record */
4745 bytesInBuffer += orbytes;
4747 /* and pad the record out */
4748 while (--align >= 0) {
4752 } /* if we're including this name */
4753 else if (!starPattern &&
4755 dep->fid.vnode != 0 &&
4756 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4757 /* We were looking for exact matches, but here's an inexact one*/
4762 /* and adjust curOffset to be where the new cookie is */
4763 thyper.HighPart = 0;
4764 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4765 curOffset = LargeIntegerAdd(thyper, curOffset);
4766 } /* while copying data for dir listing */
4768 /* If we didn't get a star pattern, we did an exact match during the first pass.
4769 * If there were no exact matches found, we fail over to inexact matches by
4770 * marking the query as a star pattern (matches all case permutations), and
4771 * re-running the query.
4773 if (returnedNames == 0 && !starPattern && foundInexact) {
4774 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4779 /* release the mutex */
4780 lock_ReleaseMutex(&scp->mx);
4782 buf_Release(bufferp);
4786 /* apply and free last set of patches; if not doing a star match, this
4787 * will be empty, but better safe (and freeing everything) than sorry.
4789 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4792 /* now put out the final parameters */
4793 if (returnedNames == 0)
4795 if (p->opcode == 1) {
4797 outp->parmsp[0] = (unsigned short) dsp->cookie;
4798 outp->parmsp[1] = returnedNames;
4799 outp->parmsp[2] = eos;
4800 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4801 outp->parmsp[4] = 0;
4802 /* don't need last name to continue
4803 * search, cookie is enough. Normally,
4804 * this is the offset of the file name
4805 * of the last entry returned.
4807 outp->totalParms = 10; /* in bytes */
4811 outp->parmsp[0] = returnedNames;
4812 outp->parmsp[1] = eos;
4813 outp->parmsp[2] = 0; /* EAS error */
4814 outp->parmsp[3] = 0; /* last name, as above */
4815 outp->totalParms = 8; /* in bytes */
4818 /* return # of bytes in the buffer */
4819 outp->totalData = bytesInBuffer;
4821 /* Return error code if unsuccessful on first request */
4822 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4823 code = CM_ERROR_NOSUCHFILE;
4825 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
4826 p->opcode, dsp->cookie, returnedNames, code);
4828 /* if we're supposed to close the search after this request, or if
4829 * we're supposed to close the search if we're done, and we're done,
4830 * or if something went wrong, close the search.
4832 if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
4833 (returnedNames == 0) ||
4834 ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
4836 smb_DeleteDirSearch(dsp);
4839 smb_SendTran2Error(vcp, p, opx, code);
4841 smb_SendTran2Packet(vcp, outp, opx);
4843 smb_FreeTran2Packet(outp);
4844 smb_ReleaseDirSearch(dsp);
4845 cm_ReleaseSCache(scp);
4846 cm_ReleaseUser(userp);
4850 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4853 smb_dirSearch_t *dsp;
4855 dirHandle = smb_GetSMBParm(inp, 0);
4857 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4859 dsp = smb_FindDirSearch(dirHandle);
4862 return CM_ERROR_BADFD;
4864 /* otherwise, we have an FD to destroy */
4865 smb_DeleteDirSearch(dsp);
4866 smb_ReleaseDirSearch(dsp);
4868 /* and return results */
4869 smb_SetSMBDataLength(outp, 0);
4874 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4876 smb_SetSMBDataLength(outp, 0);
4880 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4887 cm_scache_t *dscp; /* dir we're dealing with */
4888 cm_scache_t *scp; /* file we're creating */
4890 int initialModeBits;
4900 int parmSlot; /* which parm we're dealing with */
4909 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4910 openFun = smb_GetSMBParm(inp, 8); /* open function */
4911 excl = ((openFun & 3) == 0);
4912 trunc = ((openFun & 3) == 2); /* truncate it */
4913 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4914 openAction = 0; /* tracks what we did */
4916 attributes = smb_GetSMBParm(inp, 5);
4917 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4919 /* compute initial mode bits based on read-only flag in attributes */
4920 initialModeBits = 0666;
4921 if (attributes & SMB_ATTR_READONLY)
4922 initialModeBits &= ~0222;
4924 pathp = smb_GetSMBData(inp, NULL);
4925 if (smb_StoreAnsiFilenames)
4926 OemToChar(pathp,pathp);
4928 spacep = inp->spacep;
4929 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4931 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4932 /* special case magic file name for receiving IOCTL requests
4933 * (since IOCTL calls themselves aren't getting through).
4936 osi_Log0(smb_logp, "IOCTL Open");
4939 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4940 smb_SetupIoctlFid(fidp, spacep);
4942 /* set inp->fid so that later read calls in same msg can find fid */
4943 inp->fid = fidp->fid;
4945 /* copy out remainder of the parms */
4947 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4949 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4950 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4951 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4952 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4953 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4954 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4955 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4956 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4958 /* and the final "always present" stuff */
4959 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4960 /* next write out the "unique" ID */
4961 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4962 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4963 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4964 smb_SetSMBDataLength(outp, 0);
4966 /* and clean up fid reference */
4967 smb_ReleaseFID(fidp);
4971 #ifdef DEBUG_VERBOSE
4973 char *hexp, *asciip;
4974 asciip = (lastNamep ? lastNamep : pathp );
4975 hexp = osi_HexifyString(asciip);
4976 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4980 userp = smb_GetUserFromVCP(vcp, inp);
4983 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4985 cm_ReleaseUser(userp);
4986 return CM_ERROR_NOSUCHPATH;
4988 code = cm_NameI(cm_data.rootSCachep, pathp,
4989 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4990 userp, tidPathp, &req, &scp);
4993 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4994 cm_ReleaseSCache(scp);
4995 cm_ReleaseUser(userp);
4996 if ( WANTS_DFS_PATHNAMES(inp) )
4997 return CM_ERROR_PATH_NOT_COVERED;
4999 return CM_ERROR_BADSHARENAME;
5001 #endif /* DFS_SUPPORT */
5004 code = cm_NameI(cm_data.rootSCachep, spacep->data,
5005 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5006 userp, tidPathp, &req, &dscp);
5008 cm_ReleaseUser(userp);
5013 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5014 cm_ReleaseSCache(dscp);
5015 cm_ReleaseUser(userp);
5016 if ( WANTS_DFS_PATHNAMES(inp) )
5017 return CM_ERROR_PATH_NOT_COVERED;
5019 return CM_ERROR_BADSHARENAME;
5021 #endif /* DFS_SUPPORT */
5022 /* otherwise, scp points to the parent directory. Do a lookup,
5023 * and truncate the file if we find it, otherwise we create the
5030 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
5032 if (code && code != CM_ERROR_NOSUCHFILE) {
5033 cm_ReleaseSCache(dscp);
5034 cm_ReleaseUser(userp);
5039 /* if we get here, if code is 0, the file exists and is represented by
5040 * scp. Otherwise, we have to create it. The dir may be represented
5041 * by dscp, or we may have found the file directly. If code is non-zero,
5045 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
5047 if (dscp) cm_ReleaseSCache(dscp);
5048 cm_ReleaseSCache(scp);
5049 cm_ReleaseUser(userp);
5054 /* oops, file shouldn't be there */
5056 cm_ReleaseSCache(dscp);
5057 cm_ReleaseSCache(scp);
5058 cm_ReleaseUser(userp);
5059 return CM_ERROR_EXISTS;
5063 setAttr.mask = CM_ATTRMASK_LENGTH;
5064 setAttr.length.LowPart = 0;
5065 setAttr.length.HighPart = 0;
5066 code = cm_SetAttr(scp, &setAttr, userp, &req);
5067 openAction = 3; /* truncated existing file */
5069 else openAction = 1; /* found existing file */
5071 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
5072 /* don't create if not found */
5073 if (dscp) cm_ReleaseSCache(dscp);
5074 cm_ReleaseUser(userp);
5075 return CM_ERROR_NOSUCHFILE;
5078 osi_assert(dscp != NULL);
5079 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
5080 osi_LogSaveString(smb_logp, lastNamep));
5081 openAction = 2; /* created file */
5082 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5083 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5084 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5088 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5089 smb_NotifyChange(FILE_ACTION_ADDED,
5090 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5091 dscp, lastNamep, NULL, TRUE);
5092 } else if (!excl && code == CM_ERROR_EXISTS) {
5093 /* not an exclusive create, and someone else tried
5094 * creating it already, then we open it anyway. We
5095 * don't bother retrying after this, since if this next
5096 * fails, that means that the file was deleted after we
5097 * started this call.
5099 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5103 setAttr.mask = CM_ATTRMASK_LENGTH;
5104 setAttr.length.LowPart = 0;
5105 setAttr.length.HighPart = 0;
5106 code = cm_SetAttr(scp, &setAttr, userp, &req);
5108 } /* lookup succeeded */
5112 /* we don't need this any longer */
5114 cm_ReleaseSCache(dscp);
5117 /* something went wrong creating or truncating the file */
5119 cm_ReleaseSCache(scp);
5120 cm_ReleaseUser(userp);
5124 /* make sure we're about to open a file */
5125 if (scp->fileType != CM_SCACHETYPE_FILE) {
5126 cm_ReleaseSCache(scp);
5127 cm_ReleaseUser(userp);
5128 return CM_ERROR_ISDIR;
5131 /* now all we have to do is open the file itself */
5132 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5136 lock_ObtainMutex(&fidp->mx);
5137 /* save a pointer to the vnode */
5139 lock_ObtainMutex(&scp->mx);
5140 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5141 lock_ReleaseMutex(&scp->mx);
5142 osi_Log2(afsd_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
5144 fidp->userp = userp;
5146 /* compute open mode */
5148 fidp->flags |= SMB_FID_OPENREAD;
5149 if (openMode == 1 || openMode == 2)
5150 fidp->flags |= SMB_FID_OPENWRITE;
5152 /* remember if the file was newly created */
5154 fidp->flags |= SMB_FID_CREATED;
5156 lock_ReleaseMutex(&fidp->mx);
5157 smb_ReleaseFID(fidp);
5159 cm_Open(scp, 0, userp);
5161 /* set inp->fid so that later read calls in same msg can find fid */
5162 inp->fid = fidp->fid;
5164 /* copy out remainder of the parms */
5166 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5167 lock_ObtainMutex(&scp->mx);
5169 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5170 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5171 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5172 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5173 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5174 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5175 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5176 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5177 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5179 /* and the final "always present" stuff */
5180 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5181 /* next write out the "unique" ID */
5182 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5183 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5184 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5185 lock_ReleaseMutex(&scp->mx);
5186 smb_SetSMBDataLength(outp, 0);
5188 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5190 cm_ReleaseUser(userp);
5191 /* leave scp held since we put it in fidp->scp */
5195 static void smb_GetLockParams(unsigned char LockType,
5197 unsigned int * ppid,
5198 LARGE_INTEGER * pOffset,
5199 LARGE_INTEGER * pLength)
5201 if (LockType & LOCKING_ANDX_LARGE_FILES) {
5203 *ppid = *((USHORT *) *buf);
5204 pOffset->HighPart = *((LONG *)(*buf + 4));
5205 pOffset->LowPart = *((DWORD *)(*buf + 8));
5206 pLength->HighPart = *((LONG *)(*buf + 12));
5207 pLength->LowPart = *((DWORD *)(*buf + 16));
5211 /* Not Large Files */
5212 *ppid = *((USHORT *) *buf);
5213 pOffset->HighPart = 0;
5214 pOffset->LowPart = *((DWORD *)(*buf + 2));
5215 pLength->HighPart = 0;
5216 pLength->LowPart = *((DWORD *)(*buf + 6));
5221 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5228 unsigned char LockType;
5229 unsigned short NumberOfUnlocks, NumberOfLocks;
5233 LARGE_INTEGER LOffset, LLength;
5234 smb_waitingLockRequest_t *wlRequest = NULL;
5235 cm_file_lock_t *lockp;
5243 fid = smb_GetSMBParm(inp, 2);
5244 fid = smb_ChainFID(fid, inp);
5246 fidp = smb_FindFID(vcp, fid, 0);
5248 return CM_ERROR_BADFD;
5250 lock_ObtainMutex(&fidp->mx);
5251 if (fidp->flags & SMB_FID_IOCTL) {
5252 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
5253 lock_ReleaseMutex(&fidp->mx);
5254 smb_ReleaseFID(fidp);
5255 return CM_ERROR_BADFD;
5258 osi_Log2(afsd_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
5260 lock_ReleaseMutex(&fidp->mx);
5262 /* set inp->fid so that later read calls in same msg can find fid */
5265 userp = smb_GetUserFromVCP(vcp, inp);
5268 lock_ObtainMutex(&scp->mx);
5269 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5270 CM_SCACHESYNC_NEEDCALLBACK
5271 | CM_SCACHESYNC_GETSTATUS
5272 | CM_SCACHESYNC_LOCK);
5274 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
5278 LockType = smb_GetSMBParm(inp, 3) & 0xff;
5279 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
5280 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
5281 NumberOfLocks = smb_GetSMBParm(inp, 7);
5283 if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
5284 (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
5286 /* We don't support these requests. Apparently, we can safely
5287 not deal with them too. */
5288 osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
5289 ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
5290 "LOCKING_ANDX_CANCEL_LOCK":
5291 "LOCKING_ANDX_CHANGE_LOCKTYPE"));
5292 /* No need to call osi_LogSaveString since these are string
5295 code = CM_ERROR_BADOP;
5300 op = smb_GetSMBData(inp, NULL);
5302 for (i=0; i<NumberOfUnlocks; i++) {
5303 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5305 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5307 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
5315 for (i=0; i<NumberOfLocks; i++) {
5316 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5318 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5320 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
5321 userp, &req, &lockp);
5323 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
5324 smb_waitingLock_t * wLock;
5326 /* Put on waiting list */
5327 if(wlRequest == NULL) {
5331 LARGE_INTEGER tOffset, tLength;
5333 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
5335 osi_assert(wlRequest != NULL);
5337 wlRequest->vcp = vcp;
5339 wlRequest->scp = scp;
5340 osi_Log2(afsd_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
5342 wlRequest->inp = smb_CopyPacket(inp);
5343 wlRequest->outp = smb_CopyPacket(outp);
5344 wlRequest->lockType = LockType;
5345 wlRequest->timeRemaining = Timeout;
5346 wlRequest->locks = NULL;
5348 /* The waiting lock request needs to have enough
5349 information to undo all the locks in the request.
5350 We do the following to store info about locks that
5351 have already been granted. Sure, we can get most
5352 of the info from the packet, but the packet doesn't
5353 hold the result of cm_Lock call. In practice we
5354 only receive packets with one or two locks, so we
5355 are only wasting a few bytes here and there and
5356 only for a limited period of time until the waiting
5357 lock times out or is freed. */
5359 for(opt = op_locks, j=i; j > 0; j--) {
5360 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
5362 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5364 wLock = malloc(sizeof(smb_waitingLock_t));
5366 osi_assert(wLock != NULL);
5369 wLock->LOffset = tOffset;
5370 wLock->LLength = tLength;
5371 wLock->lockp = NULL;
5372 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
5373 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5378 wLock = malloc(sizeof(smb_waitingLock_t));
5380 osi_assert(wLock != NULL);
5383 wLock->LOffset = LOffset;
5384 wLock->LLength = LLength;
5385 wLock->lockp = lockp;
5386 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
5387 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5390 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
5398 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
5405 /* Since something went wrong with the lock number i, we now
5406 have to go ahead and release any locks acquired before the
5407 failure. All locks before lock number i (of which there
5408 are i of them) have either been successful or are waiting.
5409 Either case requires calling cm_Unlock(). */
5411 /* And purge the waiting lock */
5412 if(wlRequest != NULL) {
5413 smb_waitingLock_t * wl;
5414 smb_waitingLock_t * wlNext;
5417 for(wl = wlRequest->locks; wl; wl = wlNext) {
5419 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
5421 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
5424 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
5426 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
5429 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
5434 smb_ReleaseVC(wlRequest->vcp);
5435 cm_ReleaseSCache(wlRequest->scp);
5436 smb_FreePacket(wlRequest->inp);
5437 smb_FreePacket(wlRequest->outp);
5446 if (wlRequest != NULL) {
5448 lock_ObtainWrite(&smb_globalLock);
5449 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
5451 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
5452 lock_ReleaseWrite(&smb_globalLock);
5454 /* don't send reply immediately */
5455 outp->flags |= SMB_PACKETFLAG_NOSEND;
5458 smb_SetSMBDataLength(outp, 0);
5462 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5465 lock_ReleaseMutex(&scp->mx);
5466 cm_ReleaseSCache(scp);
5467 cm_ReleaseUser(userp);
5468 smb_ReleaseFID(fidp);
5473 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5479 afs_uint32 searchTime;
5485 fid = smb_GetSMBParm(inp, 0);
5486 fid = smb_ChainFID(fid, inp);
5488 fidp = smb_FindFID(vcp, fid, 0);
5490 return CM_ERROR_BADFD;
5492 lock_ObtainMutex(&fidp->mx);
5493 if (fidp->flags & SMB_FID_IOCTL) {
5494 lock_ReleaseMutex(&fidp->mx);
5495 smb_ReleaseFID(fidp);
5496 return CM_ERROR_BADFD;
5499 osi_Log2(afsd_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
5501 lock_ReleaseMutex(&fidp->mx);
5503 userp = smb_GetUserFromVCP(vcp, inp);
5506 /* otherwise, stat the file */
5507 lock_ObtainMutex(&scp->mx);
5508 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5509 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5513 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5515 /* decode times. We need a search time, but the response to this
5516 * call provides the date first, not the time, as returned in the
5517 * searchTime variable. So we take the high-order bits first.
5519 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
5520 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
5521 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
5522 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
5523 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
5524 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
5525 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
5527 /* now handle file size and allocation size */
5528 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
5529 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
5530 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
5531 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
5533 /* file attribute */
5534 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
5536 /* and finalize stuff */
5537 smb_SetSMBDataLength(outp, 0);
5541 lock_ReleaseMutex(&scp->mx);
5542 cm_ReleaseSCache(scp);
5543 cm_ReleaseUser(userp);
5544 smb_ReleaseFID(fidp);
5548 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5554 afs_uint32 searchTime;
5562 fid = smb_GetSMBParm(inp, 0);
5563 fid = smb_ChainFID(fid, inp);
5565 fidp = smb_FindFID(vcp, fid, 0);
5567 return CM_ERROR_BADFD;
5569 lock_ObtainMutex(&fidp->mx);
5570 if (fidp->flags & SMB_FID_IOCTL) {
5571 lock_ReleaseMutex(&fidp->mx);
5572 smb_ReleaseFID(fidp);
5573 return CM_ERROR_BADFD;
5576 osi_Log2(afsd_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
5578 lock_ReleaseMutex(&fidp->mx);
5580 userp = smb_GetUserFromVCP(vcp, inp);
5583 /* now prepare to call cm_setattr. This message only sets various times,
5584 * and AFS only implements mtime, and we'll set the mtime if that's
5585 * requested. The others we'll ignore.
5587 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
5589 if (searchTime != 0) {
5590 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
5592 if ( unixTime != -1 ) {
5593 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
5594 attrs.clientModTime = unixTime;
5595 code = cm_SetAttr(scp, &attrs, userp, &req);
5597 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
5599 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
5605 cm_ReleaseSCache(scp);
5606 cm_ReleaseUser(userp);
5607 smb_ReleaseFID(fidp);
5611 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5614 long count, written = 0, total_written = 0;
5621 int inDataBlockCount;
5623 fd = smb_GetSMBParm(inp, 2);
5624 count = smb_GetSMBParm(inp, 10);
5626 offset.HighPart = 0;
5627 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5629 if (*inp->wctp == 14) {
5630 /* we have a request with 64-bit file offsets */
5631 #ifdef AFS_LARGEFILES
5632 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
5634 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
5636 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
5637 /* we shouldn't have received this op if we didn't specify
5638 largefile support */
5639 return CM_ERROR_BADOP;
5644 op = inp->data + smb_GetSMBParm(inp, 11);
5645 inDataBlockCount = count;
5647 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
5648 fd, offset.HighPart, offset.LowPart, count);
5650 fd = smb_ChainFID(fd, inp);
5651 fidp = smb_FindFID(vcp, fd, 0);
5653 return CM_ERROR_BADFD;
5655 lock_ObtainMutex(&fidp->mx);
5656 if (fidp->flags & SMB_FID_IOCTL) {
5657 lock_ReleaseMutex(&fidp->mx);
5658 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
5659 smb_ReleaseFID(fidp);
5662 lock_ReleaseMutex(&fidp->mx);
5663 userp = smb_GetUserFromVCP(vcp, inp);
5665 /* special case: 0 bytes transferred means there is no data
5666 transferred. A slight departure from SMB_COM_WRITE where this
5667 means that we are supposed to truncate the file at this
5672 LARGE_INTEGER LOffset;
5673 LARGE_INTEGER LLength;
5675 pid = ((smb_t *) inp)->pid;
5676 key = cm_GenerateKey(vcp->vcID, pid, fd);
5678 LOffset.HighPart = offset.HighPart;
5679 LOffset.LowPart = offset.LowPart;
5680 LLength.HighPart = 0;
5681 LLength.LowPart = count;
5683 lock_ObtainMutex(&fidp->scp->mx);
5684 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
5685 lock_ReleaseMutex(&fidp->scp->mx);
5692 * Work around bug in NT client
5694 * When copying a file, the NT client should first copy the data,
5695 * then copy the last write time. But sometimes the NT client does
5696 * these in the wrong order, so the data copies would inadvertently
5697 * cause the last write time to be overwritten. We try to detect this,
5698 * and don't set client mod time if we think that would go against the
5701 lock_ObtainMutex(&fidp->mx);
5702 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5703 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5704 fidp->scp->clientModTime = time(NULL);
5706 lock_ReleaseMutex(&fidp->mx);
5709 while ( code == 0 && count > 0 ) {
5710 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5711 if (code == 0 && written == 0)
5712 code = CM_ERROR_PARTIALWRITE;
5714 offset = LargeIntegerAdd(offset,
5715 ConvertLongToLargeInteger(written));
5717 total_written += written;
5723 /* slots 0 and 1 are reserved for request chaining and will be
5724 filled in when we return. */
5725 smb_SetSMBParm(outp, 2, total_written);
5726 smb_SetSMBParm(outp, 3, 0); /* reserved */
5727 smb_SetSMBParm(outp, 4, 0); /* reserved */
5728 smb_SetSMBParm(outp, 5, 0); /* reserved */
5729 smb_SetSMBDataLength(outp, 0);
5732 cm_ReleaseUser(userp);
5733 smb_ReleaseFID(fidp);
5738 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5742 long finalCount = 0;
5751 fd = smb_GetSMBParm(inp, 2);
5752 count = smb_GetSMBParm(inp, 5);
5753 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5755 if (*inp->wctp == 12) {
5756 /* a request with 64-bit offsets */
5757 #ifdef AFS_LARGEFILES
5758 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
5760 if (LargeIntegerLessThanZero(offset)) {
5761 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
5762 offset.HighPart, offset.LowPart);
5763 return CM_ERROR_BADSMB;
5766 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
5767 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
5768 return CM_ERROR_BADSMB;
5770 offset.HighPart = 0;
5774 offset.HighPart = 0;
5777 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
5778 fd, offset.HighPart, offset.LowPart, count);
5780 fd = smb_ChainFID(fd, inp);
5781 fidp = smb_FindFID(vcp, fd, 0);
5783 return CM_ERROR_BADFD;
5786 pid = ((smb_t *) inp)->pid;
5787 key = cm_GenerateKey(vcp->vcID, pid, fd);
5789 LARGE_INTEGER LOffset, LLength;
5791 LOffset.HighPart = offset.HighPart;
5792 LOffset.LowPart = offset.LowPart;
5793 LLength.HighPart = 0;
5794 LLength.LowPart = count;
5796 lock_ObtainMutex(&fidp->scp->mx);
5797 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
5798 lock_ReleaseMutex(&fidp->scp->mx);
5802 smb_ReleaseFID(fidp);
5806 /* set inp->fid so that later read calls in same msg can find fid */
5809 lock_ObtainMutex(&fidp->mx);
5810 if (fidp->flags & SMB_FID_IOCTL) {
5811 lock_ReleaseMutex(&fidp->mx);
5812 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
5813 smb_ReleaseFID(fidp);
5816 lock_ReleaseMutex(&fidp->mx);
5818 userp = smb_GetUserFromVCP(vcp, inp);
5820 /* 0 and 1 are reserved for request chaining, were setup by our caller,
5821 * and will be further filled in after we return.
5823 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
5824 smb_SetSMBParm(outp, 3, 0); /* resvd */
5825 smb_SetSMBParm(outp, 4, 0); /* resvd */
5826 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
5827 /* fill in #6 when we have all the parameters' space reserved */
5828 smb_SetSMBParm(outp, 7, 0); /* resv'd */
5829 smb_SetSMBParm(outp, 8, 0); /* resv'd */
5830 smb_SetSMBParm(outp, 9, 0); /* resv'd */
5831 smb_SetSMBParm(outp, 10, 0); /* resv'd */
5832 smb_SetSMBParm(outp, 11, 0); /* reserved */
5834 /* get op ptr after putting in the parms, since otherwise we don't
5835 * know where the data really is.
5837 op = smb_GetSMBData(outp, NULL);
5839 /* now fill in offset from start of SMB header to first data byte (to op) */
5840 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
5842 /* set the packet data length the count of the # of bytes */
5843 smb_SetSMBDataLength(outp, count);
5845 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5847 /* fix some things up */
5848 smb_SetSMBParm(outp, 5, finalCount);
5849 smb_SetSMBDataLength(outp, finalCount);
5851 cm_ReleaseUser(userp);
5852 smb_ReleaseFID(fidp);
5857 * Values for createDisp, copied from NTDDK.H
5859 #define FILE_SUPERSEDE 0 // (???)
5860 #define FILE_OPEN 1 // (open)
5861 #define FILE_CREATE 2 // (exclusive)
5862 #define FILE_OPEN_IF 3 // (non-exclusive)
5863 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
5864 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
5867 #define REQUEST_OPLOCK 2
5868 #define REQUEST_BATCH_OPLOCK 4
5869 #define OPEN_DIRECTORY 8
5870 #define EXTENDED_RESPONSE_REQUIRED 0x10
5872 /* CreateOptions field. */
5873 #define FILE_DIRECTORY_FILE 0x0001
5874 #define FILE_WRITE_THROUGH 0x0002
5875 #define FILE_SEQUENTIAL_ONLY 0x0004
5876 #define FILE_NON_DIRECTORY_FILE 0x0040
5877 #define FILE_NO_EA_KNOWLEDGE 0x0200
5878 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
5879 #define FILE_RANDOM_ACCESS 0x0800
5880 #define FILE_DELETE_ON_CLOSE 0x1000
5881 #define FILE_OPEN_BY_FILE_ID 0x2000
5883 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5885 char *pathp, *realPathp;
5889 cm_scache_t *dscp; /* parent dir */
5890 cm_scache_t *scp; /* file to create or open */
5891 cm_scache_t *targetScp; /* if scp is a symlink */
5895 unsigned short nameLength;
5897 unsigned int requestOpLock;
5898 unsigned int requestBatchOpLock;
5899 unsigned int mustBeDir;
5900 unsigned int extendedRespRequired;
5901 unsigned int treeCreate;
5903 unsigned int desiredAccess;
5904 unsigned int extAttributes;
5905 unsigned int createDisp;
5906 unsigned int createOptions;
5907 unsigned int shareAccess;
5908 int initialModeBits;
5909 unsigned short baseFid;
5910 smb_fid_t *baseFidp;
5912 cm_scache_t *baseDirp;
5913 unsigned short openAction;
5922 cm_lock_data_t *ldp = NULL;
5926 /* This code is very long and has a lot of if-then-else clauses
5927 * scp and dscp get reused frequently and we need to ensure that
5928 * we don't lose a reference. Start by ensuring that they are NULL.
5935 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
5936 flags = smb_GetSMBOffsetParm(inp, 3, 1)
5937 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
5938 requestOpLock = flags & REQUEST_OPLOCK;
5939 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
5940 mustBeDir = flags & OPEN_DIRECTORY;
5941 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
5944 * Why all of a sudden 32-bit FID?
5945 * We will reject all bits higher than 16.
5947 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
5948 return CM_ERROR_INVAL;
5949 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
5950 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
5951 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
5952 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
5953 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
5954 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
5955 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
5956 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
5957 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
5958 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
5959 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
5961 /* mustBeDir is never set; createOptions directory bit seems to be
5964 if (createOptions & FILE_DIRECTORY_FILE)
5966 else if (createOptions & FILE_NON_DIRECTORY_FILE)
5972 * compute initial mode bits based on read-only flag in
5973 * extended attributes
5975 initialModeBits = 0666;
5976 if (extAttributes & SMB_ATTR_READONLY)
5977 initialModeBits &= ~0222;
5979 pathp = smb_GetSMBData(inp, NULL);
5980 /* Sometimes path is not null-terminated, so we make a copy. */
5981 realPathp = malloc(nameLength+1);
5982 memcpy(realPathp, pathp, nameLength);
5983 realPathp[nameLength] = 0;
5984 if (smb_StoreAnsiFilenames)
5985 OemToChar(realPathp,realPathp);
5987 spacep = inp->spacep;
5988 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5990 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
5991 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
5992 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
5994 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5995 /* special case magic file name for receiving IOCTL requests
5996 * (since IOCTL calls themselves aren't getting through).
5998 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5999 smb_SetupIoctlFid(fidp, spacep);
6000 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
6002 /* set inp->fid so that later read calls in same msg can find fid */
6003 inp->fid = fidp->fid;
6007 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6008 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6009 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
6011 memset(&ft, 0, sizeof(ft));
6012 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6013 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6014 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6015 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6016 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
6017 sz.HighPart = 0x7fff; sz.LowPart = 0;
6018 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
6019 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
6020 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6021 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6022 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
6023 smb_SetSMBDataLength(outp, 0);
6025 /* clean up fid reference */
6026 smb_ReleaseFID(fidp);
6031 #ifdef DEBUG_VERBOSE
6033 char *hexp, *asciip;
6034 asciip = (lastNamep? lastNamep : realPathp);
6035 hexp = osi_HexifyString( asciip );
6036 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
6041 userp = smb_GetUserFromVCP(vcp, inp);
6043 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
6045 return CM_ERROR_INVAL;
6050 baseDirp = cm_data.rootSCachep;
6051 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6052 if (code == CM_ERROR_TIDIPC) {
6053 /* Attempt to use a TID allocated for IPC. The client
6054 * is probably looking for DCE RPC end points which we
6055 * don't support OR it could be looking to make a DFS
6058 osi_Log0(smb_logp, "NTCreateX received IPC TID");
6061 cm_ReleaseUser(userp);
6062 return CM_ERROR_NOSUCHFILE;
6063 #endif /* DFS_SUPPORT */
6066 baseFidp = smb_FindFID(vcp, baseFid, 0);
6068 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
6070 cm_ReleaseUser(userp);
6071 return CM_ERROR_INVAL;
6073 baseDirp = baseFidp->scp;
6077 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
6079 /* compute open mode */
6081 if (desiredAccess & DELETE)
6082 fidflags |= SMB_FID_OPENDELETE;
6083 if (desiredAccess & AFS_ACCESS_READ)
6084 fidflags |= SMB_FID_OPENREAD;
6085 if (desiredAccess & AFS_ACCESS_WRITE)
6086 fidflags |= SMB_FID_OPENWRITE;
6087 if (createOptions & FILE_DELETE_ON_CLOSE)
6088 fidflags |= SMB_FID_DELONCLOSE;
6089 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6090 fidflags |= SMB_FID_SEQUENTIAL;
6091 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6092 fidflags |= SMB_FID_RANDOM;
6094 /* and the share mode */
6095 if (shareAccess & FILE_SHARE_READ)
6096 fidflags |= SMB_FID_SHARE_READ;
6097 if (shareAccess & FILE_SHARE_WRITE)
6098 fidflags |= SMB_FID_SHARE_WRITE;
6100 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
6103 /* For an exclusive create, we want to do a case sensitive match for the last component. */
6104 if ( createDisp == FILE_CREATE ||
6105 createDisp == FILE_OVERWRITE ||
6106 createDisp == FILE_OVERWRITE_IF) {
6107 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6108 userp, tidPathp, &req, &dscp);
6111 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6112 cm_ReleaseSCache(dscp);
6113 cm_ReleaseUser(userp);
6116 smb_ReleaseFID(baseFidp);
6117 if ( WANTS_DFS_PATHNAMES(inp) )
6118 return CM_ERROR_PATH_NOT_COVERED;
6120 return CM_ERROR_BADSHARENAME;
6122 #endif /* DFS_SUPPORT */
6123 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6125 if (code == CM_ERROR_NOSUCHFILE) {
6126 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6127 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6128 if (code == 0 && realDirFlag == 1) {
6129 cm_ReleaseSCache(scp);
6130 cm_ReleaseSCache(dscp);
6131 cm_ReleaseUser(userp);
6134 smb_ReleaseFID(baseFidp);
6135 return CM_ERROR_EXISTS;
6139 /* we have both scp and dscp */
6141 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6142 userp, tidPathp, &req, &scp);
6144 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6145 cm_ReleaseSCache(scp);
6146 cm_ReleaseUser(userp);
6149 smb_ReleaseFID(baseFidp);
6150 if ( WANTS_DFS_PATHNAMES(inp) )
6151 return CM_ERROR_PATH_NOT_COVERED;
6153 return CM_ERROR_BADSHARENAME;
6155 #endif /* DFS_SUPPORT */
6156 /* we might have scp but not dscp */
6162 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6163 /* look up parent directory */
6164 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
6165 * the immediate parent. We have to work our way up realPathp until we hit something that we
6169 /* we might or might not have scp */
6175 code = cm_NameI(baseDirp, spacep->data,
6176 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6177 userp, tidPathp, &req, &dscp);
6180 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6182 cm_ReleaseSCache(scp);
6183 cm_ReleaseSCache(dscp);
6184 cm_ReleaseUser(userp);
6187 smb_ReleaseFID(baseFidp);
6188 if ( WANTS_DFS_PATHNAMES(inp) )
6189 return CM_ERROR_PATH_NOT_COVERED;
6191 return CM_ERROR_BADSHARENAME;
6193 #endif /* DFS_SUPPORT */
6196 (tp = strrchr(spacep->data,'\\')) &&
6197 (createDisp == FILE_CREATE) &&
6198 (realDirFlag == 1)) {
6201 treeStartp = realPathp + (tp - spacep->data);
6203 if (*tp && !smb_IsLegalFilename(tp)) {
6204 cm_ReleaseUser(userp);
6206 smb_ReleaseFID(baseFidp);
6209 cm_ReleaseSCache(scp);
6210 return CM_ERROR_BADNTFILENAME;
6214 } while (dscp == NULL && code == 0);
6218 /* we might have scp and we might have dscp */
6221 smb_ReleaseFID(baseFidp);
6224 osi_Log0(smb_logp,"NTCreateX parent not found");
6226 cm_ReleaseSCache(scp);
6228 cm_ReleaseSCache(dscp);
6229 cm_ReleaseUser(userp);
6234 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
6235 /* A file exists where we want a directory. */
6237 cm_ReleaseSCache(scp);
6238 cm_ReleaseSCache(dscp);
6239 cm_ReleaseUser(userp);
6241 return CM_ERROR_EXISTS;
6245 lastNamep = realPathp;
6249 if (!smb_IsLegalFilename(lastNamep)) {
6251 cm_ReleaseSCache(scp);
6253 cm_ReleaseSCache(dscp);
6254 cm_ReleaseUser(userp);
6256 return CM_ERROR_BADNTFILENAME;
6259 if (!foundscp && !treeCreate) {
6260 if ( createDisp == FILE_CREATE ||
6261 createDisp == FILE_OVERWRITE ||
6262 createDisp == FILE_OVERWRITE_IF)
6264 code = cm_Lookup(dscp, lastNamep,
6265 CM_FLAG_FOLLOW, userp, &req, &scp);
6267 code = cm_Lookup(dscp, lastNamep,
6268 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6271 if (code && code != CM_ERROR_NOSUCHFILE) {
6273 cm_ReleaseSCache(dscp);
6274 cm_ReleaseUser(userp);
6279 /* we have scp and dscp */
6281 /* we have scp but not dscp */
6283 smb_ReleaseFID(baseFidp);
6286 /* if we get here, if code is 0, the file exists and is represented by
6287 * scp. Otherwise, we have to create it. The dir may be represented
6288 * by dscp, or we may have found the file directly. If code is non-zero,
6291 if (code == 0 && !treeCreate) {
6292 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
6295 cm_ReleaseSCache(dscp);
6297 cm_ReleaseSCache(scp);
6298 cm_ReleaseUser(userp);
6303 if (createDisp == FILE_CREATE) {
6304 /* oops, file shouldn't be there */
6305 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6307 cm_ReleaseSCache(dscp);
6309 cm_ReleaseSCache(scp);
6310 cm_ReleaseUser(userp);
6312 return CM_ERROR_EXISTS;
6315 if ( createDisp == FILE_OVERWRITE ||
6316 createDisp == FILE_OVERWRITE_IF) {
6318 setAttr.mask = CM_ATTRMASK_LENGTH;
6319 setAttr.length.LowPart = 0;
6320 setAttr.length.HighPart = 0;
6321 /* now watch for a symlink */
6323 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6325 osi_assert(dscp != NULL);
6326 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6328 /* we have a more accurate file to use (the
6329 * target of the symbolic link). Otherwise,
6330 * we'll just use the symlink anyway.
6332 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6334 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6335 cm_ReleaseSCache(scp);
6337 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
6340 cm_ReleaseSCache(dscp);
6342 cm_ReleaseSCache(scp);
6343 cm_ReleaseUser(userp);
6349 code = cm_SetAttr(scp, &setAttr, userp, &req);
6350 openAction = 3; /* truncated existing file */
6353 openAction = 1; /* found existing file */
6355 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6356 /* don't create if not found */
6358 cm_ReleaseSCache(dscp);
6360 cm_ReleaseSCache(scp);
6361 cm_ReleaseUser(userp);
6363 return CM_ERROR_NOSUCHFILE;
6364 } else if (realDirFlag == 0 || realDirFlag == -1) {
6365 osi_assert(dscp != NULL);
6366 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
6367 osi_LogSaveString(smb_logp, lastNamep));
6368 openAction = 2; /* created file */
6369 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6370 setAttr.clientModTime = time(NULL);
6371 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
6374 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6375 smb_NotifyChange(FILE_ACTION_ADDED,
6376 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6377 dscp, lastNamep, NULL, TRUE);
6378 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6379 /* Not an exclusive create, and someone else tried
6380 * creating it already, then we open it anyway. We
6381 * don't bother retrying after this, since if this next
6382 * fails, that means that the file was deleted after we
6383 * started this call.
6385 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6388 if (createDisp == FILE_OVERWRITE_IF) {
6389 setAttr.mask = CM_ATTRMASK_LENGTH;
6390 setAttr.length.LowPart = 0;
6391 setAttr.length.HighPart = 0;
6393 /* now watch for a symlink */
6395 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6397 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6399 /* we have a more accurate file to use (the
6400 * target of the symbolic link). Otherwise,
6401 * we'll just use the symlink anyway.
6403 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6405 cm_ReleaseSCache(scp);
6409 code = cm_SetAttr(scp, &setAttr, userp, &req);
6411 } /* lookup succeeded */
6415 char *cp; /* This component */
6416 int clen = 0; /* length of component */
6417 cm_scache_t *tscp1, *tscp2;
6420 /* create directory */
6422 treeStartp = lastNamep;
6423 osi_assert(dscp != NULL);
6424 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
6425 osi_LogSaveString(smb_logp, treeStartp));
6426 openAction = 2; /* created directory */
6428 /* if the request is to create the root directory
6429 * it will appear as a directory name of the nul-string
6430 * and a code of CM_ERROR_NOSUCHFILE
6432 if ( !*treeStartp && code == CM_ERROR_NOSUCHFILE)
6433 code = CM_ERROR_EXISTS;
6435 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6436 setAttr.clientModTime = time(NULL);
6441 cm_HoldSCache(tscp1);
6445 tp = strchr(pp, '\\');
6448 clen = (int)strlen(cp);
6449 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
6451 clen = (int)(tp - pp);
6452 strncpy(cp,pp,clen);
6459 continue; /* the supplied path can't have consecutive slashes either , but */
6461 /* cp is the next component to be created. */
6462 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
6463 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
6464 smb_NotifyChange(FILE_ACTION_ADDED,
6465 FILE_NOTIFY_CHANGE_DIR_NAME,
6466 tscp1, cp, NULL, TRUE);
6468 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6469 /* Not an exclusive create, and someone else tried
6470 * creating it already, then we open it anyway. We
6471 * don't bother retrying after this, since if this next
6472 * fails, that means that the file was deleted after we
6473 * started this call.
6475 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
6476 userp, &req, &tscp2);
6481 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
6482 cm_ReleaseSCache(tscp1);
6483 tscp1 = tscp2; /* Newly created directory will be next parent */
6484 /* the hold is transfered to tscp1 from tscp2 */
6489 cm_ReleaseSCache(dscp);
6492 cm_ReleaseSCache(scp);
6495 * if we get here and code == 0, then scp is the last directory created, and dscp is the
6501 /* something went wrong creating or truncating the file */
6503 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6505 cm_ReleaseSCache(scp);
6507 cm_ReleaseSCache(dscp);
6508 cm_ReleaseUser(userp);
6513 /* make sure we have file vs. dir right (only applies for single component case) */
6514 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
6515 /* now watch for a symlink */
6517 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6518 cm_scache_t * targetScp = 0;
6519 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6521 /* we have a more accurate file to use (the
6522 * target of the symbolic link). Otherwise,
6523 * we'll just use the symlink anyway.
6525 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
6527 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6528 cm_ReleaseSCache(scp);
6533 if (scp->fileType != CM_SCACHETYPE_FILE) {
6535 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6537 cm_ReleaseSCache(dscp);
6538 cm_ReleaseSCache(scp);
6539 cm_ReleaseUser(userp);
6541 return CM_ERROR_ISDIR;
6545 /* (only applies to single component case) */
6546 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
6548 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6549 cm_ReleaseSCache(scp);
6551 cm_ReleaseSCache(dscp);
6552 cm_ReleaseUser(userp);
6554 return CM_ERROR_NOTDIR;
6557 /* open the file itself */
6558 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6561 /* save a reference to the user */
6563 fidp->userp = userp;
6565 /* If we are restricting sharing, we should do so with a suitable
6567 if (scp->fileType == CM_SCACHETYPE_FILE &&
6568 !(fidflags & SMB_FID_SHARE_WRITE)) {
6570 LARGE_INTEGER LOffset, LLength;
6573 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
6574 LOffset.LowPart = SMB_FID_QLOCK_LOW;
6575 LLength.HighPart = 0;
6576 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
6578 if (fidflags & SMB_FID_SHARE_READ) {
6579 sLockType = LOCKING_ANDX_SHARED_LOCK;
6584 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
6586 lock_ObtainMutex(&scp->mx);
6587 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
6588 lock_ReleaseMutex(&scp->mx);
6592 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6593 cm_ReleaseSCache(scp);
6595 cm_ReleaseSCache(dscp);
6596 cm_ReleaseUser(userp);
6597 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
6598 smb_CloseFID(vcp, fidp, NULL, 0);
6599 smb_ReleaseFID(fidp);
6605 /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
6607 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6609 lock_ObtainMutex(&fidp->mx);
6610 /* save a pointer to the vnode */
6611 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
6612 lock_ObtainMutex(&scp->mx);
6613 scp->flags |= CM_SCACHEFLAG_SMB_FID;
6614 lock_ReleaseMutex(&scp->mx);
6615 osi_Log2(afsd_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
6617 fidp->flags = fidflags;
6619 /* remember if the file was newly created */
6621 fidp->flags |= SMB_FID_CREATED;
6623 /* save parent dir and pathname for delete or change notification */
6624 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
6625 osi_Log2(afsd_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
6626 fidp->flags |= SMB_FID_NTOPEN;
6627 fidp->NTopen_dscp = dscp;
6629 fidp->NTopen_pathp = strdup(lastNamep);
6631 fidp->NTopen_wholepathp = realPathp;
6632 lock_ReleaseMutex(&fidp->mx);
6634 /* we don't need this any longer */
6636 cm_ReleaseSCache(dscp);
6640 cm_Open(scp, 0, userp);
6642 /* set inp->fid so that later read calls in same msg can find fid */
6643 inp->fid = fidp->fid;
6647 lock_ObtainMutex(&scp->mx);
6648 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6649 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6650 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
6651 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6652 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6653 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6654 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6655 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6656 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
6658 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6659 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6660 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6661 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6662 smb_SetSMBParmByte(outp, parmSlot,
6663 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
6664 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
6665 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
6666 lock_ReleaseMutex(&scp->mx);
6667 smb_SetSMBDataLength(outp, 0);
6669 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
6670 osi_LogSaveString(smb_logp, realPathp));
6672 cm_ReleaseUser(userp);
6673 smb_ReleaseFID(fidp);
6675 /* Can't free realPathp if we get here since
6676 fidp->NTopen_wholepathp is pointing there */
6678 /* leave scp held since we put it in fidp->scp */
6683 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
6684 * Instead, ultimately, would like to use a subroutine for common code.
6686 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6688 char *pathp, *realPathp;
6692 cm_scache_t *dscp; /* parent dir */
6693 cm_scache_t *scp; /* file to create or open */
6694 cm_scache_t *targetScp; /* if scp is a symlink */
6697 unsigned long nameLength;
6699 unsigned int requestOpLock;
6700 unsigned int requestBatchOpLock;
6701 unsigned int mustBeDir;
6702 unsigned int extendedRespRequired;
6704 unsigned int desiredAccess;
6705 #ifdef DEBUG_VERBOSE
6706 unsigned int allocSize;
6708 unsigned int shareAccess;
6709 unsigned int extAttributes;
6710 unsigned int createDisp;
6711 #ifdef DEBUG_VERBOSE
6714 unsigned int createOptions;
6715 int initialModeBits;
6716 unsigned short baseFid;
6717 smb_fid_t *baseFidp;
6719 cm_scache_t *baseDirp;
6720 unsigned short openAction;
6726 int parmOffset, dataOffset;
6732 cm_lock_data_t *ldp = NULL;
6739 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6740 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6741 parmp = inp->data + parmOffset;
6742 lparmp = (ULONG *) parmp;
6745 requestOpLock = flags & REQUEST_OPLOCK;
6746 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6747 mustBeDir = flags & OPEN_DIRECTORY;
6748 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6751 * Why all of a sudden 32-bit FID?
6752 * We will reject all bits higher than 16.
6754 if (lparmp[1] & 0xFFFF0000)
6755 return CM_ERROR_INVAL;
6756 baseFid = (unsigned short)lparmp[1];
6757 desiredAccess = lparmp[2];
6758 #ifdef DEBUG_VERBOSE
6759 allocSize = lparmp[3];
6760 #endif /* DEBUG_VERSOSE */
6761 extAttributes = lparmp[5];
6762 shareAccess = lparmp[6];
6763 createDisp = lparmp[7];
6764 createOptions = lparmp[8];
6765 #ifdef DEBUG_VERBOSE
6768 nameLength = lparmp[11];
6770 #ifdef DEBUG_VERBOSE
6771 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
6772 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
6773 osi_Log1(smb_logp,"... flags[%x]",flags);
6776 /* mustBeDir is never set; createOptions directory bit seems to be
6779 if (createOptions & FILE_DIRECTORY_FILE)
6781 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6787 * compute initial mode bits based on read-only flag in
6788 * extended attributes
6790 initialModeBits = 0666;
6791 if (extAttributes & SMB_ATTR_READONLY)
6792 initialModeBits &= ~0222;
6794 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
6795 /* Sometimes path is not null-terminated, so we make a copy. */
6796 realPathp = malloc(nameLength+1);
6797 memcpy(realPathp, pathp, nameLength);
6798 realPathp[nameLength] = 0;
6799 if (smb_StoreAnsiFilenames)
6800 OemToChar(realPathp,realPathp);
6802 spacep = cm_GetSpace();
6803 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6806 * Nothing here to handle SMB_IOCTL_FILENAME.
6807 * Will add it if necessary.
6810 #ifdef DEBUG_VERBOSE
6812 char *hexp, *asciip;
6813 asciip = (lastNamep? lastNamep : realPathp);
6814 hexp = osi_HexifyString( asciip );
6815 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
6820 userp = smb_GetUserFromVCP(vcp, inp);
6822 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
6824 return CM_ERROR_INVAL;
6829 baseDirp = cm_data.rootSCachep;
6830 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6831 if (code == CM_ERROR_TIDIPC) {
6832 /* Attempt to use a TID allocated for IPC. The client
6833 * is probably looking for DCE RPC end points which we
6834 * don't support OR it could be looking to make a DFS
6837 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
6840 cm_ReleaseUser(userp);
6841 return CM_ERROR_NOSUCHPATH;
6845 baseFidp = smb_FindFID(vcp, baseFid, 0);
6847 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
6849 cm_ReleaseUser(userp);
6850 return CM_ERROR_INVAL;
6852 baseDirp = baseFidp->scp;
6856 /* compute open mode */
6858 if (desiredAccess & DELETE)
6859 fidflags |= SMB_FID_OPENDELETE;
6860 if (desiredAccess & AFS_ACCESS_READ)
6861 fidflags |= SMB_FID_OPENREAD;
6862 if (desiredAccess & AFS_ACCESS_WRITE)
6863 fidflags |= SMB_FID_OPENWRITE;
6864 if (createOptions & FILE_DELETE_ON_CLOSE)
6865 fidflags |= SMB_FID_DELONCLOSE;
6866 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6867 fidflags |= SMB_FID_SEQUENTIAL;
6868 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6869 fidflags |= SMB_FID_RANDOM;
6871 /* And the share mode */
6872 if (shareAccess & FILE_SHARE_READ)
6873 fidflags |= SMB_FID_SHARE_READ;
6874 if (shareAccess & FILE_SHARE_WRITE)
6875 fidflags |= SMB_FID_SHARE_WRITE;
6879 if ( createDisp == FILE_OPEN ||
6880 createDisp == FILE_OVERWRITE ||
6881 createDisp == FILE_OVERWRITE_IF) {
6882 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6883 userp, tidPathp, &req, &dscp);
6886 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6887 cm_ReleaseSCache(dscp);
6888 cm_ReleaseUser(userp);
6891 smb_ReleaseFID(baseFidp);
6892 if ( WANTS_DFS_PATHNAMES(inp) )
6893 return CM_ERROR_PATH_NOT_COVERED;
6895 return CM_ERROR_BADSHARENAME;
6897 #endif /* DFS_SUPPORT */
6898 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6900 if (code == CM_ERROR_NOSUCHFILE) {
6901 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6902 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6903 if (code == 0 && realDirFlag == 1) {
6904 cm_ReleaseSCache(scp);
6905 cm_ReleaseSCache(dscp);
6906 cm_ReleaseUser(userp);
6909 smb_ReleaseFID(baseFidp);
6910 return CM_ERROR_EXISTS;
6916 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6917 userp, tidPathp, &req, &scp);
6919 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6920 cm_ReleaseSCache(scp);
6921 cm_ReleaseUser(userp);
6924 smb_ReleaseFID(baseFidp);
6925 if ( WANTS_DFS_PATHNAMES(inp) )
6926 return CM_ERROR_PATH_NOT_COVERED;
6928 return CM_ERROR_BADSHARENAME;
6930 #endif /* DFS_SUPPORT */
6936 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6937 /* look up parent directory */
6939 code = cm_NameI(baseDirp, spacep->data,
6940 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6941 userp, tidPathp, &req, &dscp);
6943 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6944 cm_ReleaseSCache(dscp);
6945 cm_ReleaseUser(userp);
6948 smb_ReleaseFID(baseFidp);
6949 if ( WANTS_DFS_PATHNAMES(inp) )
6950 return CM_ERROR_PATH_NOT_COVERED;
6952 return CM_ERROR_BADSHARENAME;
6954 #endif /* DFS_SUPPORT */
6958 cm_FreeSpace(spacep);
6961 smb_ReleaseFID(baseFidp);
6964 cm_ReleaseUser(userp);
6970 lastNamep = realPathp;
6974 if (!smb_IsLegalFilename(lastNamep))
6975 return CM_ERROR_BADNTFILENAME;
6978 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
6979 code = cm_Lookup(dscp, lastNamep,
6980 CM_FLAG_FOLLOW, userp, &req, &scp);
6982 code = cm_Lookup(dscp, lastNamep,
6983 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6986 if (code && code != CM_ERROR_NOSUCHFILE) {
6987 cm_ReleaseSCache(dscp);
6988 cm_ReleaseUser(userp);
6995 smb_ReleaseFID(baseFidp);
6996 cm_FreeSpace(spacep);
6999 /* if we get here, if code is 0, the file exists and is represented by
7000 * scp. Otherwise, we have to create it. The dir may be represented
7001 * by dscp, or we may have found the file directly. If code is non-zero,
7005 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7008 cm_ReleaseSCache(dscp);
7009 cm_ReleaseSCache(scp);
7010 cm_ReleaseUser(userp);
7015 if (createDisp == FILE_CREATE) {
7016 /* oops, file shouldn't be there */
7017 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7019 cm_ReleaseSCache(dscp);
7020 cm_ReleaseSCache(scp);
7021 cm_ReleaseUser(userp);
7023 return CM_ERROR_EXISTS;
7026 if (createDisp == FILE_OVERWRITE ||
7027 createDisp == FILE_OVERWRITE_IF) {
7028 setAttr.mask = CM_ATTRMASK_LENGTH;
7029 setAttr.length.LowPart = 0;
7030 setAttr.length.HighPart = 0;
7032 /* now watch for a symlink */
7034 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7036 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7038 /* we have a more accurate file to use (the
7039 * target of the symbolic link). Otherwise,
7040 * we'll just use the symlink anyway.
7042 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7044 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7045 cm_ReleaseSCache(scp);
7047 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7050 cm_ReleaseSCache(dscp);
7052 cm_ReleaseSCache(scp);
7053 cm_ReleaseUser(userp);
7059 code = cm_SetAttr(scp, &setAttr, userp, &req);
7060 openAction = 3; /* truncated existing file */
7062 else openAction = 1; /* found existing file */
7064 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7065 /* don't create if not found */
7067 cm_ReleaseSCache(dscp);
7068 cm_ReleaseUser(userp);
7070 return CM_ERROR_NOSUCHFILE;
7072 else if (realDirFlag == 0 || realDirFlag == -1) {
7073 osi_assert(dscp != NULL);
7074 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
7075 osi_LogSaveString(smb_logp, lastNamep));
7076 openAction = 2; /* created file */
7077 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7078 setAttr.clientModTime = time(NULL);
7079 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7083 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7084 smb_NotifyChange(FILE_ACTION_ADDED,
7085 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7086 dscp, lastNamep, NULL, TRUE);
7087 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7088 /* Not an exclusive create, and someone else tried
7089 * creating it already, then we open it anyway. We
7090 * don't bother retrying after this, since if this next
7091 * fails, that means that the file was deleted after we
7092 * started this call.
7094 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7097 if (createDisp == FILE_OVERWRITE_IF) {
7098 setAttr.mask = CM_ATTRMASK_LENGTH;
7099 setAttr.length.LowPart = 0;
7100 setAttr.length.HighPart = 0;
7102 /* now watch for a symlink */
7104 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7106 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7108 /* we have a more accurate file to use (the
7109 * target of the symbolic link). Otherwise,
7110 * we'll just use the symlink anyway.
7112 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7114 cm_ReleaseSCache(scp);
7118 code = cm_SetAttr(scp, &setAttr, userp, &req);
7120 } /* lookup succeeded */
7123 /* create directory */
7124 osi_assert(dscp != NULL);
7126 "smb_ReceiveNTTranCreate creating directory %s",
7127 osi_LogSaveString(smb_logp, lastNamep));
7128 openAction = 2; /* created directory */
7129 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7130 setAttr.clientModTime = time(NULL);
7131 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
7132 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7133 smb_NotifyChange(FILE_ACTION_ADDED,
7134 FILE_NOTIFY_CHANGE_DIR_NAME,
7135 dscp, lastNamep, NULL, TRUE);
7137 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7138 /* Not an exclusive create, and someone else tried
7139 * creating it already, then we open it anyway. We
7140 * don't bother retrying after this, since if this next
7141 * fails, that means that the file was deleted after we
7142 * started this call.
7144 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7150 /* something went wrong creating or truncating the file */
7152 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7154 cm_ReleaseSCache(scp);
7155 cm_ReleaseUser(userp);
7160 /* make sure we have file vs. dir right */
7161 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7162 /* now watch for a symlink */
7164 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7166 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7168 /* we have a more accurate file to use (the
7169 * target of the symbolic link). Otherwise,
7170 * we'll just use the symlink anyway.
7172 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7175 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7176 cm_ReleaseSCache(scp);
7181 if (scp->fileType != CM_SCACHETYPE_FILE) {
7183 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7184 cm_ReleaseSCache(scp);
7185 cm_ReleaseUser(userp);
7187 return CM_ERROR_ISDIR;
7191 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7193 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7194 cm_ReleaseSCache(scp);
7195 cm_ReleaseUser(userp);
7197 return CM_ERROR_NOTDIR;
7200 /* open the file itself */
7201 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7204 /* save a reference to the user */
7206 fidp->userp = userp;
7208 /* If we are restricting sharing, we should do so with a suitable
7210 if (scp->fileType == CM_SCACHETYPE_FILE &&
7211 !(fidflags & SMB_FID_SHARE_WRITE)) {
7213 LARGE_INTEGER LOffset, LLength;
7216 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7217 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7218 LLength.HighPart = 0;
7219 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7221 if (fidflags & SMB_FID_SHARE_READ) {
7222 sLockType = LOCKING_ANDX_SHARED_LOCK;
7227 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7229 lock_ObtainMutex(&scp->mx);
7230 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7231 lock_ReleaseMutex(&scp->mx);
7235 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7236 cm_ReleaseSCache(scp);
7237 cm_ReleaseUser(userp);
7238 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7239 smb_CloseFID(vcp, fidp, NULL, 0);
7240 smb_ReleaseFID(fidp);
7242 return CM_ERROR_SHARING_VIOLATION;
7246 /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
7248 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7250 lock_ObtainMutex(&fidp->mx);
7251 /* save a pointer to the vnode */
7253 lock_ObtainMutex(&scp->mx);
7254 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7255 lock_ReleaseMutex(&scp->mx);
7256 osi_Log2(afsd_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
7258 fidp->flags = fidflags;
7260 /* remember if the file was newly created */
7262 fidp->flags |= SMB_FID_CREATED;
7264 /* save parent dir and pathname for deletion or change notification */
7265 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7266 fidp->flags |= SMB_FID_NTOPEN;
7267 fidp->NTopen_dscp = dscp;
7268 osi_Log2(afsd_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
7270 fidp->NTopen_pathp = strdup(lastNamep);
7272 fidp->NTopen_wholepathp = realPathp;
7273 lock_ReleaseMutex(&fidp->mx);
7275 /* we don't need this any longer */
7277 cm_ReleaseSCache(dscp);
7279 cm_Open(scp, 0, userp);
7281 /* set inp->fid so that later read calls in same msg can find fid */
7282 inp->fid = fidp->fid;
7284 /* check whether we are required to send an extended response */
7285 if (!extendedRespRequired) {
7287 parmOffset = 8*4 + 39;
7288 parmOffset += 1; /* pad to 4 */
7289 dataOffset = parmOffset + 70;
7293 /* Total Parameter Count */
7294 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7295 /* Total Data Count */
7296 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7297 /* Parameter Count */
7298 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7299 /* Parameter Offset */
7300 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7301 /* Parameter Displacement */
7302 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7304 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7306 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7307 /* Data Displacement */
7308 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7309 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7310 smb_SetSMBDataLength(outp, 70);
7312 lock_ObtainMutex(&scp->mx);
7313 outData = smb_GetSMBData(outp, NULL);
7314 outData++; /* round to get to parmOffset */
7315 *outData = 0; outData++; /* oplock */
7316 *outData = 0; outData++; /* reserved */
7317 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7318 *((ULONG *)outData) = openAction; outData += 4;
7319 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
7320 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7321 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
7322 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
7323 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
7324 *((FILETIME *)outData) = ft; outData += 8; /* change time */
7325 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7326 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7327 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7328 *((USHORT *)outData) = 0; outData += 2; /* filetype */
7329 *((USHORT *)outData) = 0; outData += 2; /* dev state */
7330 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7331 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7332 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7333 outData += 2; /* is a dir? */
7334 lock_ReleaseMutex(&scp->mx);
7337 parmOffset = 8*4 + 39;
7338 parmOffset += 1; /* pad to 4 */
7339 dataOffset = parmOffset + 104;
7343 /* Total Parameter Count */
7344 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7345 /* Total Data Count */
7346 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7347 /* Parameter Count */
7348 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7349 /* Parameter Offset */
7350 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7351 /* Parameter Displacement */
7352 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7354 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7356 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7357 /* Data Displacement */
7358 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7359 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7360 smb_SetSMBDataLength(outp, 105);
7362 lock_ObtainMutex(&scp->mx);
7363 outData = smb_GetSMBData(outp, NULL);
7364 outData++; /* round to get to parmOffset */
7365 *outData = 0; outData++; /* oplock */
7366 *outData = 1; outData++; /* response type */
7367 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7368 *((ULONG *)outData) = openAction; outData += 4;
7369 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
7370 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7371 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
7372 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
7373 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
7374 *((FILETIME *)outData) = ft; outData += 8; /* change time */
7375 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7376 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7377 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7378 *((USHORT *)outData) = 0; outData += 2; /* filetype */
7379 *((USHORT *)outData) = 0; outData += 2; /* dev state */
7380 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7381 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7382 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7383 outData += 1; /* is a dir? */
7384 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
7385 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
7386 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
7387 lock_ReleaseMutex(&scp->mx);
7390 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
7392 cm_ReleaseUser(userp);
7393 smb_ReleaseFID(fidp);
7395 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
7396 /* leave scp held since we put it in fidp->scp */
7400 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
7403 smb_packet_t *savedPacketp;
7405 USHORT fid, watchtree;
7409 filter = smb_GetSMBParm(inp, 19) |
7410 (smb_GetSMBParm(inp, 20) << 16);
7411 fid = smb_GetSMBParm(inp, 21);
7412 watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
7414 fidp = smb_FindFID(vcp, fid, 0);
7416 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
7417 return CM_ERROR_BADFD;
7420 /* Create a copy of the Directory Watch Packet to use when sending the
7421 * notification if in the future a matching change is detected.
7423 savedPacketp = smb_CopyPacket(inp);
7425 if (savedPacketp->vcp)
7426 smb_ReleaseVC(savedPacketp->vcp);
7427 savedPacketp->vcp = vcp;
7429 /* Add the watch to the list of events to send notifications for */
7430 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7431 savedPacketp->nextp = smb_Directory_Watches;
7432 smb_Directory_Watches = savedPacketp;
7433 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7436 osi_Log3(afsd_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%s\"",
7437 fidp, scp, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
7438 osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
7439 filter, fid, watchtree);
7440 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
7441 osi_Log0(smb_logp, " Notify Change File Name");
7442 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
7443 osi_Log0(smb_logp, " Notify Change Directory Name");
7444 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
7445 osi_Log0(smb_logp, " Notify Change Attributes");
7446 if (filter & FILE_NOTIFY_CHANGE_SIZE)
7447 osi_Log0(smb_logp, " Notify Change Size");
7448 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
7449 osi_Log0(smb_logp, " Notify Change Last Write");
7450 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
7451 osi_Log0(smb_logp, " Notify Change Last Access");
7452 if (filter & FILE_NOTIFY_CHANGE_CREATION)
7453 osi_Log0(smb_logp, " Notify Change Creation");
7454 if (filter & FILE_NOTIFY_CHANGE_EA)
7455 osi_Log0(smb_logp, " Notify Change Extended Attributes");
7456 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
7457 osi_Log0(smb_logp, " Notify Change Security");
7458 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
7459 osi_Log0(smb_logp, " Notify Change Stream Name");
7460 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
7461 osi_Log0(smb_logp, " Notify Change Stream Size");
7462 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
7463 osi_Log0(smb_logp, " Notify Change Stream Write");
7465 lock_ObtainMutex(&scp->mx);
7467 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
7469 scp->flags |= CM_SCACHEFLAG_WATCHED;
7470 lock_ReleaseMutex(&scp->mx);
7471 smb_ReleaseFID(fidp);
7473 outp->flags |= SMB_PACKETFLAG_NOSEND;
7477 unsigned char nullSecurityDesc[36] = {
7478 0x01, /* security descriptor revision */
7479 0x00, /* reserved, should be zero */
7480 0x00, 0x80, /* security descriptor control;
7481 * 0x8000 : self-relative format */
7482 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
7483 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
7484 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
7485 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
7486 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7487 /* "null SID" owner SID */
7488 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
7489 /* "null SID" group SID */
7492 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7494 int parmOffset, parmCount, dataOffset, dataCount;
7502 ULONG securityInformation;
7504 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7505 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7506 parmp = inp->data + parmOffset;
7507 sparmp = (USHORT *) parmp;
7508 lparmp = (ULONG *) parmp;
7511 securityInformation = lparmp[1];
7513 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
7514 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
7522 parmOffset = 8*4 + 39;
7523 parmOffset += 1; /* pad to 4 */
7525 dataOffset = parmOffset + parmCount;
7529 /* Total Parameter Count */
7530 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
7531 /* Total Data Count */
7532 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
7533 /* Parameter Count */
7534 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
7535 /* Parameter Offset */
7536 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7537 /* Parameter Displacement */
7538 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7540 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
7542 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7543 /* Data Displacement */
7544 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7545 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7546 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
7548 outData = smb_GetSMBData(outp, NULL);
7549 outData++; /* round to get to parmOffset */
7550 *((ULONG *)outData) = 36; outData += 4; /* length */
7552 if (maxData >= 36) {
7553 memcpy(outData, nullSecurityDesc, 36);
7557 return CM_ERROR_BUFFERTOOSMALL;
7560 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7562 unsigned short function;
7564 function = smb_GetSMBParm(inp, 18);
7566 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
7568 /* We can handle long names */
7569 if (vcp->flags & SMB_VCFLAG_USENT)
7570 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
7574 return smb_ReceiveNTTranCreate(vcp, inp, outp);
7576 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
7579 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
7582 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
7584 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
7587 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
7589 return CM_ERROR_INVAL;
7593 * smb_NotifyChange -- find relevant change notification messages and
7596 * If we don't know the file name (i.e. a callback break), filename is
7597 * NULL, and we return a zero-length list.
7599 * At present there is not a single call to smb_NotifyChange that
7600 * has the isDirectParent parameter set to FALSE.
7602 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
7603 cm_scache_t *dscp, char *filename, char *otherFilename,
7604 BOOL isDirectParent)
7606 smb_packet_t *watch, *lastWatch, *nextWatch;
7607 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
7608 char *outData, *oldOutData;
7612 BOOL twoEntries = FALSE;
7613 ULONG otherNameLen, oldParmCount = 0;
7617 /* Get ready for rename within directory */
7618 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
7620 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
7623 osi_Log4(smb_logp,"in smb_NotifyChange for file [%s] dscp [%p] notification 0x%x parent %d",
7624 osi_LogSaveString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
7626 osi_Log0(smb_logp," FILE_ACTION_NONE");
7627 if (action == FILE_ACTION_ADDED)
7628 osi_Log0(smb_logp," FILE_ACTION_ADDED");
7629 if (action == FILE_ACTION_REMOVED)
7630 osi_Log0(smb_logp," FILE_ACTION_REMOVED");
7631 if (action == FILE_ACTION_MODIFIED)
7632 osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
7633 if (action == FILE_ACTION_RENAMED_OLD_NAME)
7634 osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
7635 if (action == FILE_ACTION_RENAMED_NEW_NAME)
7636 osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
7638 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7639 watch = smb_Directory_Watches;
7641 filter = smb_GetSMBParm(watch, 19)
7642 | (smb_GetSMBParm(watch, 20) << 16);
7643 fid = smb_GetSMBParm(watch, 21);
7644 wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
7646 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
7647 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
7650 * Strange hack - bug in NT Client and NT Server that we must emulate?
7652 if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
7653 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
7655 fidp = smb_FindFID(watch->vcp, fid, 0);
7657 osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
7659 watch = watch->nextp;
7662 if (fidp->scp != dscp
7663 || (filter & notifyFilter) == 0
7664 || (!isDirectParent && !wtree)) {
7665 osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
7666 smb_ReleaseFID(fidp);
7668 watch = watch->nextp;
7671 smb_ReleaseFID(fidp);
7674 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
7675 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
7676 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
7677 osi_Log0(smb_logp, " Notify Change File Name");
7678 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
7679 osi_Log0(smb_logp, " Notify Change Directory Name");
7680 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
7681 osi_Log0(smb_logp, " Notify Change Attributes");
7682 if (filter & FILE_NOTIFY_CHANGE_SIZE)
7683 osi_Log0(smb_logp, " Notify Change Size");
7684 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
7685 osi_Log0(smb_logp, " Notify Change Last Write");
7686 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
7687 osi_Log0(smb_logp, " Notify Change Last Access");
7688 if (filter & FILE_NOTIFY_CHANGE_CREATION)
7689 osi_Log0(smb_logp, " Notify Change Creation");
7690 if (filter & FILE_NOTIFY_CHANGE_EA)
7691 osi_Log0(smb_logp, " Notify Change Extended Attributes");
7692 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
7693 osi_Log0(smb_logp, " Notify Change Security");
7694 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
7695 osi_Log0(smb_logp, " Notify Change Stream Name");
7696 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
7697 osi_Log0(smb_logp, " Notify Change Stream Size");
7698 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
7699 osi_Log0(smb_logp, " Notify Change Stream Write");
7701 /* A watch can only be notified once. Remove it from the list */
7702 nextWatch = watch->nextp;
7703 if (watch == smb_Directory_Watches)
7704 smb_Directory_Watches = nextWatch;
7706 lastWatch->nextp = nextWatch;
7708 /* Turn off WATCHED flag in dscp */
7709 lock_ObtainMutex(&dscp->mx);
7711 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
7713 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
7714 lock_ReleaseMutex(&dscp->mx);
7716 /* Convert to response packet */
7717 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
7718 ((smb_t *) watch)->wct = 0;
7721 if (filename == NULL)
7724 nameLen = (ULONG)strlen(filename);
7725 parmCount = 3*4 + nameLen*2;
7726 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
7728 otherNameLen = (ULONG)strlen(otherFilename);
7729 oldParmCount = parmCount;
7730 parmCount += 3*4 + otherNameLen*2;
7731 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
7733 if (maxLen < parmCount)
7734 parmCount = 0; /* not enough room */
7736 parmOffset = 8*4 + 39;
7737 parmOffset += 1; /* pad to 4 */
7738 dataOffset = parmOffset + parmCount;
7742 /* Total Parameter Count */
7743 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
7744 /* Total Data Count */
7745 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7746 /* Parameter Count */
7747 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
7748 /* Parameter Offset */
7749 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
7750 /* Parameter Displacement */
7751 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7753 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7755 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
7756 /* Data Displacement */
7757 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7758 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
7759 smb_SetSMBDataLength(watch, parmCount + 1);
7761 if (parmCount != 0) {
7763 outData = smb_GetSMBData(watch, NULL);
7764 outData++; /* round to get to parmOffset */
7765 oldOutData = outData;
7766 *((DWORD *)outData) = oldParmCount; outData += 4;
7767 /* Next Entry Offset */
7768 *((DWORD *)outData) = action; outData += 4;
7770 *((DWORD *)outData) = nameLen*2; outData += 4;
7771 /* File Name Length */
7772 p = strdup(filename);
7773 if (smb_StoreAnsiFilenames)
7775 mbstowcs((WCHAR *)outData, p, nameLen);
7779 outData = oldOutData + oldParmCount;
7780 *((DWORD *)outData) = 0; outData += 4;
7781 /* Next Entry Offset */
7782 *((DWORD *)outData) = otherAction; outData += 4;
7784 *((DWORD *)outData) = otherNameLen*2;
7785 outData += 4; /* File Name Length */
7786 p = strdup(otherFilename);
7787 if (smb_StoreAnsiFilenames)
7789 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
7795 * If filename is null, we don't know the cause of the
7796 * change notification. We return zero data (see above),
7797 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
7798 * (= 0x010C). We set the error code here by hand, without
7799 * modifying wct and bcc.
7801 if (filename == NULL) {
7802 ((smb_t *) watch)->rcls = 0x0C;
7803 ((smb_t *) watch)->reh = 0x01;
7804 ((smb_t *) watch)->errLow = 0;
7805 ((smb_t *) watch)->errHigh = 0;
7806 /* Set NT Status codes flag */
7807 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7810 smb_SendPacket(watch->vcp, watch);
7811 smb_FreePacket(watch);
7814 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7817 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7819 unsigned char *replyWctp;
7820 smb_packet_t *watch, *lastWatch;
7821 USHORT fid, watchtree;
7825 osi_Log0(smb_logp, "SMB3 receive NT cancel");
7827 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7828 watch = smb_Directory_Watches;
7830 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
7831 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
7832 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
7833 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
7834 if (watch == smb_Directory_Watches)
7835 smb_Directory_Watches = watch->nextp;
7837 lastWatch->nextp = watch->nextp;
7838 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7840 /* Turn off WATCHED flag in scp */
7841 fid = smb_GetSMBParm(watch, 21);
7842 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
7844 if (vcp != watch->vcp)
7845 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
7848 fidp = smb_FindFID(vcp, fid, 0);
7850 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
7852 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
7855 osi_Log2(afsd_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
7856 lock_ObtainMutex(&scp->mx);
7858 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
7860 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
7861 lock_ReleaseMutex(&scp->mx);
7862 smb_ReleaseFID(fidp);
7864 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
7867 /* assume STATUS32; return 0xC0000120 (CANCELED) */
7868 replyWctp = watch->wctp;
7872 ((smb_t *)watch)->rcls = 0x20;
7873 ((smb_t *)watch)->reh = 0x1;
7874 ((smb_t *)watch)->errLow = 0;
7875 ((smb_t *)watch)->errHigh = 0xC0;
7876 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7877 smb_SendPacket(vcp, watch);
7878 smb_FreePacket(watch);
7882 watch = watch->nextp;
7884 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7890 * NT rename also does hard links.
7893 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
7894 #define RENAME_FLAG_HARD_LINK 0x103
7895 #define RENAME_FLAG_RENAME 0x104
7896 #define RENAME_FLAG_COPY 0x105
7898 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7900 char *oldPathp, *newPathp;
7906 attrs = smb_GetSMBParm(inp, 0);
7907 rename_type = smb_GetSMBParm(inp, 1);
7909 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
7910 osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
7911 return CM_ERROR_NOACCESS;
7914 tp = smb_GetSMBData(inp, NULL);
7915 oldPathp = smb_ParseASCIIBlock(tp, &tp);
7916 if (smb_StoreAnsiFilenames)
7917 OemToChar(oldPathp,oldPathp);
7918 newPathp = smb_ParseASCIIBlock(tp, &tp);
7919 if (smb_StoreAnsiFilenames)
7920 OemToChar(newPathp,newPathp);
7922 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
7923 osi_LogSaveString(smb_logp, oldPathp),
7924 osi_LogSaveString(smb_logp, newPathp),
7925 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
7927 if (rename_type == RENAME_FLAG_RENAME) {
7928 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
7929 } else { /* RENAME_FLAG_HARD_LINK */
7930 code = smb_Link(vcp,inp,oldPathp,newPathp);
7937 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
7940 cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
7942 smb_username_t *unp;
7945 unp = smb_FindUserByName(usern, machine, flags);
7947 lock_ObtainMutex(&unp->mx);
7948 unp->userp = cm_NewUser();
7949 lock_ReleaseMutex(&unp->mx);
7950 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7952 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7956 smb_ReleaseUsername(unp);