3 * Copyright 2000, International Business Machines Corporation and others.
6 * This software has been released under the terms of the IBM Public
7 * License. For details, see the LICENSE file in the top-level source
8 * directory or online at http://www.openafs.org/dl/license10.html
11 #include <afsconfig.h>
12 #include <afs/param.h>
19 #pragma warning(disable: 4005)
21 #define SECURITY_WIN32
34 #include <WINNT\afsreg.h>
40 extern osi_hyper_t hzero;
42 smb_packet_t *smb_Directory_Watches = NULL;
43 osi_mutex_t smb_Dir_Watch_Lock;
45 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
47 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
49 /* protected by the smb_globalLock */
50 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
52 const clientchar_t **smb_ExecutableExtensions = NULL;
54 /* retrieve a held reference to a user structure corresponding to an incoming
56 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
61 uidp = smb_FindUID(vcp, inp->uid, 0);
65 up = smb_GetUserFromUID(uidp);
73 * Return boolean specifying if the path name is thought to be an
74 * executable file. For now .exe or .dll.
76 afs_uint32 smb_IsExecutableFileName(const clientchar_t *name)
80 if ( smb_ExecutableExtensions == NULL || name == NULL)
83 len = (int)cm_ClientStrLen(name);
85 for ( i=0; smb_ExecutableExtensions[i]; i++) {
86 j = len - (int)cm_ClientStrLen(smb_ExecutableExtensions[i]);
87 if (cm_ClientStrCmpI(smb_ExecutableExtensions[i], &name[j]) == 0)
95 * Return extended attributes.
96 * Right now, we aren't using any of the "new" bits, so this looks exactly
97 * like smb_Attributes() (see smb.c).
99 unsigned long smb_ExtAttributes(cm_scache_t *scp)
103 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
104 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
105 scp->fileType == CM_SCACHETYPE_INVALID)
107 attrs = SMB_ATTR_DIRECTORY;
108 #ifdef SPECIAL_FOLDERS
109 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
110 #endif /* SPECIAL_FOLDERS */
111 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
112 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
113 } else if (scp->fid.vnode & 0x1)
114 attrs = SMB_ATTR_DIRECTORY;
119 * We used to mark a file RO if it was in an RO volume, but that
120 * turns out to be impolitic in NT. See defect 10007.
123 if ((scp->unixModeBits & 0200) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
124 attrs |= SMB_ATTR_READONLY; /* Read-only */
126 if ((scp->unixModeBits & 0200) == 0)
127 attrs |= SMB_ATTR_READONLY; /* Read-only */
131 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
136 int smb_V3IsStarMask(clientchar_t *maskp)
140 while (tc = *maskp++)
141 if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
146 void OutputDebugF(clientchar_t * format, ...) {
148 clientchar_t vbuffer[1024];
150 va_start( args, format );
151 cm_ClientStrPrintfV(vbuffer, lengthof(vbuffer), format, args);
152 osi_Log1(smb_logp, "%S", osi_LogSaveClientString(smb_logp, vbuffer));
155 void OutputDebugHexDump(unsigned char * buffer, int len) {
158 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
160 OutputDebugF(_C("Hexdump length [%d]"),len);
162 for (i=0;i<len;i++) {
165 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
167 StringCchPrintfA(buf, lengthof(buf), "%5x", i);
168 memset(buf+5,' ',80);
173 j = j*3 + 7 + ((j>7)?1:0);
176 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
179 j = j + 56 + ((j>7)?1:0);
181 buf[j] = (k>32 && k<127)?k:'.';
184 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
188 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
190 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
191 SECURITY_STATUS status, istatus;
192 CredHandle creds = {0,0};
194 SecBufferDesc secOut;
202 OutputDebugF(_C("Negotiating Extended Security"));
204 status = AcquireCredentialsHandle( NULL,
205 SMB_EXT_SEC_PACKAGE_NAME,
214 if (status != SEC_E_OK) {
215 /* Really bad. We return an empty security blob */
216 OutputDebugF(_C("AcquireCredentialsHandle failed with %lX"), status);
221 secOut.pBuffers = &secTok;
222 secOut.ulVersion = SECBUFFER_VERSION;
224 secTok.BufferType = SECBUFFER_TOKEN;
226 secTok.pvBuffer = NULL;
228 ctx.dwLower = ctx.dwUpper = 0;
230 status = AcceptSecurityContext( &creds,
233 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
234 SECURITY_NETWORK_DREP,
241 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
242 OutputDebugF(_C("Completing token..."));
243 istatus = CompleteAuthToken(&ctx, &secOut);
244 if ( istatus != SEC_E_OK )
245 OutputDebugF(_C("Token completion failed: %x"), istatus);
248 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
249 if (secTok.pvBuffer) {
250 *secBlobLength = secTok.cbBuffer;
251 *secBlob = malloc( secTok.cbBuffer );
252 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
255 if ( status != SEC_E_OK )
256 OutputDebugF(_C("AcceptSecurityContext status != CONTINUE %lX"), status);
259 /* Discard partial security context */
260 DeleteSecurityContext(&ctx);
262 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
264 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
265 FreeCredentialsHandle(&creds);
272 smb_GetLogonSID(HANDLE hToken, PSID *ppsid)
274 BOOL bSuccess = FALSE;
277 PTOKEN_GROUPS ptg = NULL;
279 // Verify the parameter passed in is not NULL.
283 // Get required buffer size and allocate the TOKEN_GROUPS buffer.
285 if (!GetTokenInformation( hToken, // handle to the access token
286 TokenGroups, // get information about the token's groups
287 (LPVOID) ptg, // pointer to TOKEN_GROUPS buffer
289 &dwLength // receives required buffer size
292 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
295 ptg = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(),
296 HEAP_ZERO_MEMORY, dwLength);
302 // Get the token group information from the access token.
304 if (!GetTokenInformation( hToken, // handle to the access token
305 TokenGroups, // get information about the token's groups
306 (LPVOID) ptg, // pointer to TOKEN_GROUPS buffer
307 dwLength, // size of buffer
308 &dwLength // receives required buffer size
314 // Loop through the groups to find the logon SID.
315 for (dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++) {
316 if ((ptg->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID)
318 // Found the logon SID; make a copy of it.
320 dwLength = GetLengthSid(ptg->Groups[dwIndex].Sid);
321 *ppsid = (PSID) HeapAlloc(GetProcessHeap(),
322 HEAP_ZERO_MEMORY, dwLength);
325 if (!CopySid(dwLength, *ppsid, ptg->Groups[dwIndex].Sid))
327 HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
337 // Free the buffer for the token groups.
339 HeapFree(GetProcessHeap(), 0, (LPVOID)ptg);
345 smb_GetUserSID(HANDLE hToken, PSID *ppsid)
347 BOOL bSuccess = FALSE;
349 PTOKEN_USER ptu = NULL;
351 // Verify the parameter passed in is not NULL.
355 // Get required buffer size and allocate the TOKEN_USER buffer.
357 if (!GetTokenInformation( hToken, // handle to the access token
358 TokenUser, // get information about the token's user
359 (LPVOID) ptu, // pointer to TOKEN_USER buffer
361 &dwLength // receives required buffer size
364 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
367 ptu = (PTOKEN_USER)HeapAlloc(GetProcessHeap(),
368 HEAP_ZERO_MEMORY, dwLength);
374 // Get the token group information from the access token.
376 if (!GetTokenInformation( hToken, // handle to the access token
377 TokenUser, // get information about the token's user
378 (LPVOID) ptu, // pointer to TOKEN_USER buffer
379 dwLength, // size of buffer
380 &dwLength // receives required buffer size
386 // Found the user SID; make a copy of it.
387 dwLength = GetLengthSid(ptu->User.Sid);
388 *ppsid = (PSID) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
391 if (!CopySid(dwLength, *ppsid, ptu->User.Sid))
393 HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
400 // Free the buffer for the token groups.
402 HeapFree(GetProcessHeap(), 0, (LPVOID)ptu);
408 smb_FreeSID (PSID psid)
410 HeapFree(GetProcessHeap(), 0, (LPVOID)psid);
414 struct smb_ext_context {
421 long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern,
422 char * secBlobIn, int secBlobInLength,
423 char ** secBlobOut, int * secBlobOutLength,
424 wchar_t **secSidString) {
425 SECURITY_STATUS status, istatus;
429 SecBufferDesc secBufIn;
431 SecBufferDesc secBufOut;
434 struct smb_ext_context * secCtx = NULL;
435 struct smb_ext_context * newSecCtx = NULL;
436 void * assembledBlob = NULL;
437 int assembledBlobLength = 0;
440 OutputDebugF(_C("In smb_AuthenticateUserExt"));
443 *secBlobOutLength = 0;
444 *secSidString = NULL;
446 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
447 secCtx = vcp->secCtx;
448 lock_ObtainMutex(&vcp->mx);
449 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
451 lock_ReleaseMutex(&vcp->mx);
455 OutputDebugF(_C("Received incoming token:"));
456 OutputDebugHexDump(secBlobIn,secBlobInLength);
460 OutputDebugF(_C("Continuing with existing context."));
461 creds = secCtx->creds;
464 if (secCtx->partialToken) {
465 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
466 assembledBlob = malloc(assembledBlobLength);
467 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
468 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
471 status = AcquireCredentialsHandle( NULL,
472 SMB_EXT_SEC_PACKAGE_NAME,
481 if (status != SEC_E_OK) {
482 OutputDebugF(_C("Can't acquire Credentials handle [%lX]"), status);
483 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
491 secBufIn.cBuffers = 1;
492 secBufIn.pBuffers = &secTokIn;
493 secBufIn.ulVersion = SECBUFFER_VERSION;
495 secTokIn.BufferType = SECBUFFER_TOKEN;
497 secTokIn.cbBuffer = assembledBlobLength;
498 secTokIn.pvBuffer = assembledBlob;
500 secTokIn.cbBuffer = secBlobInLength;
501 secTokIn.pvBuffer = secBlobIn;
504 secBufOut.cBuffers = 1;
505 secBufOut.pBuffers = &secTokOut;
506 secBufOut.ulVersion = SECBUFFER_VERSION;
508 secTokOut.BufferType = SECBUFFER_TOKEN;
509 secTokOut.cbBuffer = 0;
510 secTokOut.pvBuffer = NULL;
512 status = AcceptSecurityContext( &creds,
513 ((secCtx)?&ctx:NULL),
515 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
516 SECURITY_NETWORK_DREP,
523 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
524 OutputDebugF(_C("Completing token..."));
525 istatus = CompleteAuthToken(&ctx, &secBufOut);
526 if ( istatus != SEC_E_OK )
527 OutputDebugF(_C("Token completion failed: %lX"), istatus);
530 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
531 OutputDebugF(_C("Continue needed"));
533 newSecCtx = malloc(sizeof(*newSecCtx));
535 newSecCtx->creds = creds;
536 newSecCtx->ctx = ctx;
537 newSecCtx->partialToken = NULL;
538 newSecCtx->partialTokenLen = 0;
540 lock_ObtainMutex( &vcp->mx );
541 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
542 vcp->secCtx = newSecCtx;
543 lock_ReleaseMutex( &vcp->mx );
545 code = CM_ERROR_GSSCONTINUE;
548 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
549 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
550 secTokOut.pvBuffer) {
551 OutputDebugF(_C("Need to send token back to client"));
553 *secBlobOutLength = secTokOut.cbBuffer;
554 *secBlobOut = malloc(secTokOut.cbBuffer);
555 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
557 OutputDebugF(_C("Outgoing token:"));
558 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
559 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
560 OutputDebugF(_C("Incomplete message"));
562 newSecCtx = malloc(sizeof(*newSecCtx));
564 newSecCtx->creds = creds;
565 newSecCtx->ctx = ctx;
566 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
567 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
568 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
570 lock_ObtainMutex( &vcp->mx );
571 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
572 vcp->secCtx = newSecCtx;
573 lock_ReleaseMutex( &vcp->mx );
575 code = CM_ERROR_GSSCONTINUE;
578 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
581 SecPkgContext_NamesW names;
583 OutputDebugF(_C("Authentication completed"));
584 OutputDebugF(_C("Returned flags : [%lX]"), flags);
586 if (!QueryContextAttributesW(&ctx, SECPKG_ATTR_NAMES, &names)) {
587 OutputDebugF(_C("Received name [%s]"), names.sUserName);
588 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, names.sUserName);
589 cm_ClientStrLwr(usern); /* in tandem with smb_GetNormalizedUsername */
590 FreeContextBuffer(names.sUserName);
592 /* Force the user to retry if the context is invalid */
593 OutputDebugF(_C("QueryContextAttributes Names failed [%x]"), GetLastError());
594 code = CM_ERROR_BADPASSWORD;
597 /* Obtain the user's SID */
598 if (code == 0 && !QuerySecurityContextToken(((secCtx)?&ctx:NULL), &hToken)) {
600 OutputDebugF(_C("Received hToken"));
602 if (smb_GetUserSID(hToken, &pSid))
603 ConvertSidToStringSidW(pSid, secSidString);
609 OutputDebugF(_C("QueryContextToken failed [%x]"), GetLastError());
613 case SEC_E_INVALID_TOKEN:
614 OutputDebugF(_C("Returning bad password :: INVALID_TOKEN"));
616 case SEC_E_INVALID_HANDLE:
617 OutputDebugF(_C("Returning bad password :: INVALID_HANDLE"));
619 case SEC_E_LOGON_DENIED:
620 OutputDebugF(_C("Returning bad password :: LOGON_DENIED"));
622 case SEC_E_UNKNOWN_CREDENTIALS:
623 OutputDebugF(_C("Returning bad password :: UNKNOWN_CREDENTIALS"));
625 case SEC_E_NO_CREDENTIALS:
626 OutputDebugF(_C("Returning bad password :: NO_CREDENTIALS"));
628 case SEC_E_CONTEXT_EXPIRED:
629 OutputDebugF(_C("Returning bad password :: CONTEXT_EXPIRED"));
631 case SEC_E_INCOMPLETE_CREDENTIALS:
632 OutputDebugF(_C("Returning bad password :: INCOMPLETE_CREDENTIALS"));
634 case SEC_E_WRONG_PRINCIPAL:
635 OutputDebugF(_C("Returning bad password :: WRONG_PRINCIPAL"));
637 case SEC_E_TIME_SKEW:
638 OutputDebugF(_C("Returning bad password :: TIME_SKEW"));
641 OutputDebugF(_C("Returning bad password :: Status == %lX"), status);
643 code = CM_ERROR_BADPASSWORD;
647 if (secCtx->partialToken) free(secCtx->partialToken);
655 if (secTokOut.pvBuffer)
656 FreeContextBuffer(secTokOut.pvBuffer);
658 if (code != CM_ERROR_GSSCONTINUE) {
659 DeleteSecurityContext(&ctx);
660 FreeCredentialsHandle(&creds);
668 #define P_RESP_LEN 128
670 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
671 So put stuff in a struct. */
672 struct Lm20AuthBlob {
673 MSV1_0_LM20_LOGON lmlogon;
674 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
675 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
676 WCHAR accountNameW[P_LEN];
677 WCHAR primaryDomainW[P_LEN];
678 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
679 TOKEN_GROUPS tgroups;
680 TOKEN_SOURCE tsource;
683 long smb_AuthenticateUserLM(smb_vc_t *vcp, clientchar_t * accountName, clientchar_t * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
686 struct Lm20AuthBlob lmAuth;
687 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
688 QUOTA_LIMITS quotaLimits;
690 ULONG lmprofilepSize;
694 OutputDebugF(_C("In smb_AuthenticateUser for user [%s] domain [%s]"), accountName, primaryDomain);
695 OutputDebugF(_C("ciPwdLength is %d and csPwdLength is %d"), ciPwdLength, csPwdLength);
697 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
698 OutputDebugF(_C("ciPwdLength or csPwdLength is too long"));
699 return CM_ERROR_BADPASSWORD;
702 memset(&lmAuth,0,sizeof(lmAuth));
704 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
706 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
707 cm_ClientStringToUtf16(primaryDomain, -1, lmAuth.primaryDomainW, P_LEN);
708 lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
709 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
711 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
712 cm_ClientStringToUtf16(accountName, -1, lmAuth.accountNameW, P_LEN);
713 lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
714 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
716 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
717 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
718 size = MAX_COMPUTERNAME_LENGTH + 1;
719 GetComputerNameW(lmAuth.workstationW, &size);
720 lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
722 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
724 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
725 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
726 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
727 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
729 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
730 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
731 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
732 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
734 lmAuth.lmlogon.ParameterControl = 0;
736 lmAuth.tgroups.GroupCount = 0;
737 lmAuth.tgroups.Groups[0].Sid = NULL;
738 lmAuth.tgroups.Groups[0].Attributes = 0;
741 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
743 lmAuth.tsource.SourceIdentifier.HighPart = 0;
745 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
746 StringCchCopyA(lmAuth.tsource.SourceName, lengthof(lmAuth.tsource.SourceName),
747 "OpenAFS"); /* 8 char limit */
749 nts = LsaLogonUser( smb_lsaHandle,
764 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
765 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
768 OutputDebugF(_C("Return from LsaLogonUser is 0x%lX"), nts);
769 OutputDebugF(_C("Extended status is 0x%lX"), ntsEx);
771 if (nts == ERROR_SUCCESS) {
773 LsaFreeReturnBuffer(lmprofilep);
774 CloseHandle(lmToken);
778 if (nts == 0xC000015BL)
779 return CM_ERROR_BADLOGONTYPE;
780 else /* our catchall is a bad password though we could be more specific */
781 return CM_ERROR_BADPASSWORD;
785 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
786 long smb_GetNormalizedUsername(clientchar_t * usern, const clientchar_t * accountName, const clientchar_t * domainName)
788 clientchar_t * atsign;
789 const clientchar_t * domain;
791 /* check if we have sane input */
792 if ((cm_ClientStrLen(accountName) + cm_ClientStrLen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
795 /* we could get : [accountName][domainName]
801 atsign = cm_ClientStrChr(accountName, '@');
803 if (atsign) /* [user@domain][] -> [user@domain][domain] */
808 /* if for some reason the client doesn't know what domain to use,
809 it will either return an empty string or a '?' */
810 if (!domain[0] || domain[0] == '?')
811 /* Empty domains and empty usernames are usually sent from tokenless contexts.
812 This way such logins will get an empty username (easy to check). I don't know
813 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
814 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, accountName);
816 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
817 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, domain);
818 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, _C("\\"));
820 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
822 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
825 cm_ClientStrLwr(usern);
830 /* When using SMB auth, all SMB sessions have to pass through here
831 * first to authenticate the user.
833 * Caveat: If not using SMB auth, the protocol does not require
834 * sending a session setup packet, which means that we can't rely on a
835 * UID in subsequent packets. Though in practice we get one anyway.
837 /* SMB_COM_SESSION_SETUP_ANDX */
838 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
842 unsigned short newUid;
843 unsigned long caps = 0;
845 clientchar_t *s1 = _C(" ");
847 clientchar_t usern[SMB_MAX_USERNAME_LENGTH];
849 char *secBlobOut = NULL;
850 int secBlobOutLength = 0;
851 wchar_t *secSidString = 0;
852 int maxBufferSize = 0;
856 /* Check for bad conns */
857 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
858 return CM_ERROR_REMOTECONN;
861 maxBufferSize = smb_GetSMBParm(inp, 2);
862 maxMpxCount = smb_GetSMBParm(inp, 3);
863 vcNumber = smb_GetSMBParm(inp, 4);
865 osi_Log3(smb_logp, "SESSION_SETUP_ANDX with MaxBufferSize=%d, MaxMpxCount=%d, VCNumber=%d",
866 maxBufferSize, maxMpxCount, vcNumber);
868 if (maxMpxCount > smb_maxMpxRequests) {
869 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_MPX_COUNT, maxMpxCount, smb_maxMpxRequests);
870 osi_Log2(smb_logp, "MaxMpxCount for client is too large (Client=%d, Server=%d)",
871 maxMpxCount, smb_maxMpxRequests);
874 if (maxBufferSize < SMB_PACKETSIZE) {
875 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_BUFFER_SIZE, maxBufferSize, SMB_PACKETSIZE);
876 osi_Log2(smb_logp, "MaxBufferSize for client is too small (Client=%d, Server=%d)",
877 maxBufferSize, SMB_PACKETSIZE);
881 osi_Log0(smb_logp, "Resetting all VCs");
882 smb_MarkAllVCsDead(vcp);
885 if (vcp->flags & SMB_VCFLAG_USENT) {
886 if (smb_authType == SMB_AUTH_EXTENDED) {
887 /* extended authentication */
891 OutputDebugF(_C("NT Session Setup: Extended"));
893 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
894 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
897 secBlobInLength = smb_GetSMBParm(inp, 7);
898 secBlobIn = smb_GetSMBData(inp, NULL);
900 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength, &secSidString);
902 if (code == CM_ERROR_GSSCONTINUE) {
905 smb_SetSMBParm(outp, 2, 0);
906 smb_SetSMBParm(outp, 3, secBlobOutLength);
908 tp = smb_GetSMBData(outp, NULL);
909 if (secBlobOutLength) {
910 memcpy(tp, secBlobOut, secBlobOutLength);
912 tp += secBlobOutLength;
913 cb_data += secBlobOutLength;
915 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
916 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
917 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
919 smb_SetSMBDataLength(outp, cb_data);
922 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
924 unsigned ciPwdLength, csPwdLength;
926 clientchar_t *accountName;
927 clientchar_t *primaryDomain;
930 if (smb_authType == SMB_AUTH_NTLM)
931 OutputDebugF(_C("NT Session Setup: NTLM"));
933 OutputDebugF(_C("NT Session Setup: None"));
935 /* TODO: parse for extended auth as well */
936 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
937 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
939 tp = smb_GetSMBData(inp, &datalen);
941 OutputDebugF(_C("Session packet data size [%d]"),datalen);
948 accountName = smb_ParseString(inp, tp, &tp, 0);
949 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
951 OutputDebugF(_C("Account Name: %s"),accountName);
952 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
953 OutputDebugF(_C("Case Sensitive Password: %s"),
954 csPwd && csPwd[0] ? _C("yes") : _C("no"));
955 OutputDebugF(_C("Case Insensitive Password: %s"),
956 ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
958 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
959 /* shouldn't happen */
960 code = CM_ERROR_BADSMB;
961 goto after_read_packet;
964 /* capabilities are only valid for first session packet */
965 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
966 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
969 if (smb_authType == SMB_AUTH_NTLM) {
970 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
972 OutputDebugF(_C("LM authentication failed [%d]"), code);
974 OutputDebugF(_C("LM authentication succeeded"));
978 unsigned ciPwdLength;
980 clientchar_t *accountName;
981 clientchar_t *primaryDomain;
983 switch ( smb_authType ) {
984 case SMB_AUTH_EXTENDED:
985 OutputDebugF(_C("V3 Session Setup: Extended"));
988 OutputDebugF(_C("V3 Session Setup: NTLM"));
991 OutputDebugF(_C("V3 Session Setup: None"));
993 ciPwdLength = smb_GetSMBParm(inp, 7);
994 tp = smb_GetSMBData(inp, NULL);
998 accountName = smb_ParseString(inp, tp, &tp, 0);
999 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
1001 OutputDebugF(_C("Account Name: %s"),accountName);
1002 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
1003 OutputDebugF(_C("Case Insensitive Password: %s"), ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
1005 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
1006 /* shouldn't happen */
1007 code = CM_ERROR_BADSMB;
1008 goto after_read_packet;
1011 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
1014 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
1015 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
1017 OutputDebugF(_C("LM authentication failed [%d]"), code);
1019 OutputDebugF(_C("LM authentication succeeded"));
1024 /* note down that we received a session setup X and set the capabilities flag */
1025 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
1026 lock_ObtainMutex(&vcp->mx);
1027 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
1028 /* for the moment we can only deal with NTSTATUS */
1029 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
1030 vcp->flags |= SMB_VCFLAG_STATUS32;
1034 if ((caps & NTNEGOTIATE_CAPABILITY_UNICODE) && smb_UseUnicode) {
1035 vcp->flags |= SMB_VCFLAG_USEUNICODE;
1038 lock_ReleaseMutex(&vcp->mx);
1041 /* code would be non-zero if there was an authentication failure.
1042 Ideally we would like to invalidate the uid for this session or break
1043 early to avoid accidently stealing someone else's tokens. */
1047 LocalFree(secSidString);
1052 * If the SidString for the user could be obtained, use that
1056 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, secSidString);
1060 OutputDebugF(_C("Received username=[%s]"), usern);
1062 /* On Windows 2000, this function appears to be called more often than
1063 it is expected to be called. This resulted in multiple smb_user_t
1064 records existing all for the same user session which results in all
1065 of the users tokens disappearing.
1067 To avoid this problem, we look for an existing smb_user_t record
1068 based on the users name, and use that one if we find it.
1071 uidp = smb_FindUserByNameThisSession(vcp, usern);
1072 if (uidp) { /* already there, so don't create a new one */
1074 newUid = uidp->userID;
1075 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
1076 vcp->lana,vcp->lsn,newUid);
1077 smb_ReleaseUID(uidp);
1082 /* do a global search for the username/machine name pair */
1083 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
1084 lock_ObtainMutex(&unp->mx);
1085 if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
1086 /* clear the afslogon flag so that the tickets can now
1087 * be freed when the refCount returns to zero.
1089 unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
1091 unp->flags |= SMB_USERNAMEFLAG_SID;
1094 unp->flags |= SMB_USERNAMEFLAG_SID;
1095 lock_ReleaseMutex(&unp->mx);
1097 /* Create a new UID and cm_user_t structure */
1100 userp = cm_NewUser();
1101 cm_HoldUserVCRef(userp);
1102 lock_ObtainMutex(&vcp->mx);
1103 if (!vcp->uidCounter)
1104 vcp->uidCounter++; /* handle unlikely wraparounds */
1105 newUid = (cm_ClientStrLen(usern)==0)?0:vcp->uidCounter++;
1106 lock_ReleaseMutex(&vcp->mx);
1108 /* Create a new smb_user_t structure and connect them up */
1109 lock_ObtainMutex(&unp->mx);
1111 lock_ReleaseMutex(&unp->mx);
1113 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
1115 lock_ObtainMutex(&uidp->mx);
1117 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
1118 lock_ReleaseMutex(&uidp->mx);
1119 smb_ReleaseUID(uidp);
1123 /* Return UID to the client */
1124 ((smb_t *)outp)->uid = newUid;
1125 /* Also to the next chained message */
1126 ((smb_t *)inp)->uid = newUid;
1128 osi_Log3(smb_logp, "SMB3 session setup name %S creating ID %d%S",
1129 osi_LogSaveClientString(smb_logp, usern), newUid,
1130 osi_LogSaveClientString(smb_logp, s1));
1132 smb_SetSMBParm(outp, 2, 0);
1134 if (vcp->flags & SMB_VCFLAG_USENT) {
1135 if (smb_authType == SMB_AUTH_EXTENDED) {
1138 smb_SetSMBParm(outp, 3, secBlobOutLength);
1140 tp = smb_GetSMBData(outp, NULL);
1141 if (secBlobOutLength) {
1142 memcpy(tp, secBlobOut, secBlobOutLength);
1144 tp += secBlobOutLength;
1145 cb_data += secBlobOutLength;
1148 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
1149 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
1150 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
1152 smb_SetSMBDataLength(outp, cb_data);
1154 smb_SetSMBDataLength(outp, 0);
1157 if (smb_authType == SMB_AUTH_EXTENDED) {
1160 tp = smb_GetSMBData(outp, NULL);
1162 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
1163 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
1164 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
1166 smb_SetSMBDataLength(outp, cb_data);
1168 smb_SetSMBDataLength(outp, 0);
1173 LocalFree(secSidString);
1177 /* SMB_COM_LOGOFF_ANDX */
1178 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1182 /* find the tree and free it */
1183 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1185 smb_username_t * unp;
1187 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %S", uidp->userID,
1188 osi_LogSaveClientString(smb_logp, (uidp->unp) ? uidp->unp->name: _C(" ")));
1190 lock_ObtainMutex(&uidp->mx);
1191 uidp->flags |= SMB_USERFLAG_DELETE;
1193 * it doesn't get deleted right away
1194 * because the vcp points to it
1197 lock_ReleaseMutex(&uidp->mx);
1200 /* we can't do this. we get logoff messages prior to a session
1201 * disconnect even though it doesn't mean the user is logging out.
1202 * we need to create a new pioctl and EventLogoff handler to set
1203 * SMB_USERNAMEFLAG_LOGOFF.
1205 if (unp && smb_LogoffTokenTransfer) {
1206 lock_ObtainMutex(&unp->mx);
1207 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
1208 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
1209 lock_ReleaseMutex(&unp->mx);
1213 smb_ReleaseUID(uidp);
1216 osi_Log0(smb_logp, "SMB3 user logoffX");
1218 smb_SetSMBDataLength(outp, 0);
1222 #define SMB_SUPPORT_SEARCH_BITS 0x0001
1223 #define SMB_SHARE_IS_IN_DFS 0x0002
1225 /* SMB_COM_TREE_CONNECT_ANDX */
1226 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1229 smb_user_t *uidp = NULL;
1230 unsigned short newTid;
1231 clientchar_t shareName[AFSPATHMAX];
1232 clientchar_t *sharePath;
1235 clientchar_t *slashp;
1236 clientchar_t *pathp;
1237 clientchar_t *passwordp;
1238 clientchar_t *servicep;
1239 cm_user_t *userp = NULL;
1242 osi_Log0(smb_logp, "SMB3 receive tree connect");
1244 /* parse input parameters */
1245 tp = smb_GetSMBData(inp, NULL);
1246 passwordp = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1247 pathp = smb_ParseString(inp, tp, &tp, SMB_STRF_ANSIPATH);
1248 servicep = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1250 slashp = cm_ClientStrRChr(pathp, '\\');
1252 return CM_ERROR_BADSMB;
1254 cm_ClientStrCpy(shareName, lengthof(shareName), slashp+1);
1256 osi_Log3(smb_logp, "Tree connect pathp[%S] shareName[%S] service[%S]",
1257 osi_LogSaveClientString(smb_logp, pathp),
1258 osi_LogSaveClientString(smb_logp, shareName),
1259 osi_LogSaveClientString(smb_logp, servicep));
1261 if (cm_ClientStrCmp(servicep, _C("IPC")) == 0 ||
1262 cm_ClientStrCmp(shareName, _C("IPC$")) == 0) {
1264 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1267 return CM_ERROR_NOIPC;
1271 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1273 userp = smb_GetUserFromUID(uidp);
1275 lock_ObtainMutex(&vcp->mx);
1276 newTid = vcp->tidCounter++;
1277 lock_ReleaseMutex(&vcp->mx);
1279 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1282 if (!cm_ClientStrCmp(shareName, _C("*.")))
1283 cm_ClientStrCpy(shareName, lengthof(shareName), _C("all"));
1284 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1287 smb_ReleaseUID(uidp);
1288 smb_ReleaseTID(tidp, FALSE);
1289 return CM_ERROR_BADSHARENAME;
1292 if (vcp->flags & SMB_VCFLAG_USENT)
1294 int policy = smb_FindShareCSCPolicy(shareName);
1297 DWORD dwAdvertiseDFS = 0, dwSize = sizeof(DWORD);
1299 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1300 0, KEY_QUERY_VALUE, &parmKey);
1301 if (code == ERROR_SUCCESS) {
1302 code = RegQueryValueEx(parmKey, "AdvertiseDFS", NULL, NULL,
1303 (BYTE *)&dwAdvertiseDFS, &dwSize);
1304 if (code != ERROR_SUCCESS)
1306 RegCloseKey (parmKey);
1308 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1309 (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
1313 smb_SetSMBParm(outp, 2, 0);
1317 smb_ReleaseUID(uidp);
1319 lock_ObtainMutex(&tidp->mx);
1320 tidp->userp = userp;
1321 tidp->pathname = sharePath;
1323 tidp->flags |= SMB_TIDFLAG_IPC;
1324 lock_ReleaseMutex(&tidp->mx);
1325 smb_ReleaseTID(tidp, FALSE);
1327 ((smb_t *)outp)->tid = newTid;
1328 ((smb_t *)inp)->tid = newTid;
1329 tp = smb_GetSMBData(outp, NULL);
1333 tp = smb_UnparseString(outp, tp, _C("A:"), &cb_data, SMB_STRF_FORCEASCII);
1334 tp = smb_UnparseString(outp, tp, _C("AFS"), &cb_data, 0);
1335 smb_SetSMBDataLength(outp, cb_data);
1339 tp = smb_UnparseString(outp, tp, _C("IPC"), &cb_data, SMB_STRF_FORCEASCII);
1340 smb_SetSMBDataLength(outp, cb_data);
1343 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1347 /* must be called with global tran lock held */
1348 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1350 smb_tran2Packet_t *tp;
1353 smbp = (smb_t *) inp->data;
1354 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1355 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1361 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1362 int totalParms, int totalData)
1364 smb_tran2Packet_t *tp;
1367 smbp = (smb_t *) inp->data;
1368 tp = malloc(sizeof(*tp));
1369 memset(tp, 0, sizeof(*tp));
1372 tp->curData = tp->curParms = 0;
1373 tp->totalData = totalData;
1374 tp->totalParms = totalParms;
1375 tp->tid = smbp->tid;
1376 tp->mid = smbp->mid;
1377 tp->uid = smbp->uid;
1378 tp->pid = smbp->pid;
1379 tp->res[0] = smbp->res[0];
1380 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1381 if (totalParms != 0)
1382 tp->parmsp = malloc(totalParms);
1384 tp->datap = malloc(totalData);
1385 if (smbp->com == 0x25 || smbp->com == 0x26)
1388 tp->opcode = smb_GetSMBParm(inp, 14);
1391 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1393 if (WANTS_UNICODE(inp) && (vcp->flags & SMB_VCFLAG_USEUNICODE))
1394 tp->flags |= SMB_TRAN2PFLAG_USEUNICODE;
1399 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1400 smb_tran2Packet_t *inp, smb_packet_t *outp,
1401 int totalParms, int totalData)
1403 smb_tran2Packet_t *tp;
1404 unsigned short parmOffset;
1405 unsigned short dataOffset;
1406 unsigned short dataAlign;
1408 tp = malloc(sizeof(*tp));
1409 memset(tp, 0, sizeof(*tp));
1412 tp->curData = tp->curParms = 0;
1413 tp->totalData = totalData;
1414 tp->totalParms = totalParms;
1415 tp->oldTotalParms = totalParms;
1420 tp->res[0] = inp->res[0];
1421 tp->opcode = inp->opcode;
1425 * We calculate where the parameters and data will start.
1426 * This calculation must parallel the calculation in
1427 * smb_SendTran2Packet.
1430 parmOffset = 10*2 + 35;
1431 parmOffset++; /* round to even */
1432 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1434 dataOffset = parmOffset + totalParms;
1435 dataAlign = dataOffset & 2; /* quad-align */
1436 dataOffset += dataAlign;
1437 tp->datap = outp->data + dataOffset;
1442 /* free a tran2 packet */
1443 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1446 smb_ReleaseVC(t2p->vcp);
1449 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1459 while (t2p->stringsp) {
1463 t2p->stringsp = ns->nextp;
1469 clientchar_t *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
1470 char ** chainpp, int flags)
1475 if (!(p->flags & SMB_TRAN2PFLAG_USEUNICODE))
1476 flags |= SMB_STRF_FORCEASCII;
1479 cb = p->totalParms - (inp - (char *)p->parmsp);
1480 if (inp < (char *) p->parmsp ||
1481 inp >= ((char *) p->parmsp) + p->totalParms) {
1482 #ifdef DEBUG_UNICODE
1488 return smb_ParseStringBuf((unsigned char *) p->parmsp, &p->stringsp,
1489 inp, &cb, chainpp, flags);
1492 /* called with a VC, an input packet to respond to, and an error code.
1493 * sends an error response.
1495 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1496 smb_packet_t *tp, long code)
1499 unsigned short errCode;
1500 unsigned char errClass;
1501 unsigned long NTStatus;
1503 if (vcp->flags & SMB_VCFLAG_STATUS32)
1504 smb_MapNTError(code, &NTStatus, FALSE);
1506 smb_MapCoreError(code, vcp, &errCode, &errClass);
1508 smb_FormatResponsePacket(vcp, NULL, tp);
1509 smbp = (smb_t *) tp;
1511 /* We can handle long names */
1512 if (vcp->flags & SMB_VCFLAG_USENT)
1513 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1515 /* now copy important fields from the tran 2 packet */
1516 smbp->com = t2p->com;
1517 smbp->tid = t2p->tid;
1518 smbp->mid = t2p->mid;
1519 smbp->pid = t2p->pid;
1520 smbp->uid = t2p->uid;
1521 smbp->res[0] = t2p->res[0];
1522 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1523 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1524 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1525 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1526 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1527 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1530 smbp->rcls = errClass;
1531 smbp->errLow = (unsigned char) (errCode & 0xff);
1532 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1536 smb_SendPacket(vcp, tp);
1539 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1542 unsigned short parmOffset;
1543 unsigned short dataOffset;
1544 unsigned short totalLength;
1545 unsigned short dataAlign;
1548 smb_FormatResponsePacket(vcp, NULL, tp);
1549 smbp = (smb_t *) tp;
1551 /* We can handle long names */
1552 if (vcp->flags & SMB_VCFLAG_USENT)
1553 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1555 /* now copy important fields from the tran 2 packet */
1556 smbp->com = t2p->com;
1557 smbp->tid = t2p->tid;
1558 smbp->mid = t2p->mid;
1559 smbp->pid = t2p->pid;
1560 smbp->uid = t2p->uid;
1561 smbp->res[0] = t2p->res[0];
1563 if (t2p->error_code) {
1564 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1565 unsigned long NTStatus;
1567 smb_MapNTError(t2p->error_code, &NTStatus, FALSE);
1569 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1570 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1571 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1572 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1573 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1576 unsigned short errCode;
1577 unsigned char errClass;
1579 smb_MapCoreError(t2p->error_code, vcp, &errCode, &errClass);
1581 smbp->rcls = errClass;
1582 smbp->errLow = (unsigned char) (errCode & 0xff);
1583 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1587 totalLength = 1 + t2p->totalData + t2p->totalParms;
1589 /* now add the core parameters (tran2 info) to the packet */
1590 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1591 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1592 smb_SetSMBParm(tp, 2, 0); /* reserved */
1593 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1594 parmOffset = 10*2 + 35; /* parm offset in packet */
1595 parmOffset++; /* round to even */
1596 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1597 * hdr, bcc and wct */
1598 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1599 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1600 dataOffset = parmOffset + t2p->oldTotalParms;
1601 dataAlign = dataOffset & 2; /* quad-align */
1602 dataOffset += dataAlign;
1603 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1604 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1605 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1608 datap = smb_GetSMBData(tp, NULL);
1609 *datap++ = 0; /* we rounded to even */
1611 totalLength += dataAlign;
1612 smb_SetSMBDataLength(tp, totalLength);
1614 /* next, send the datagram */
1615 smb_SendPacket(vcp, tp);
1618 /* TRANS_SET_NMPIPE_STATE */
1619 long smb_nmpipeSetState(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1623 int pipeState = 0x0100; /* default */
1624 smb_tran2Packet_t *outp = NULL;
1627 if (p->totalParms > 0)
1628 pipeState = p->parmsp[0];
1630 osi_Log2(smb_logp, "smb_nmpipeSetState for fd[%d] with state[0x%x]", fd, pipeState);
1632 fidp = smb_FindFID(vcp, fd, 0);
1634 osi_Log2(smb_logp, "smb_nmpipeSetState Unknown SMB Fid vcp 0x%p fid %d",
1636 return CM_ERROR_BADFD;
1638 lock_ObtainMutex(&fidp->mx);
1639 if (pipeState & 0x8000)
1640 fidp->flags |= SMB_FID_BLOCKINGPIPE;
1641 if (pipeState & 0x0100)
1642 fidp->flags |= SMB_FID_MESSAGEMODEPIPE;
1643 lock_ReleaseMutex(&fidp->mx);
1645 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 0);
1646 smb_SendTran2Packet(vcp, outp, op);
1647 smb_FreeTran2Packet(outp);
1649 smb_ReleaseFID(fidp);
1654 long smb_nmpipeTransact(smb_vc_t * vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1664 osi_Log3(smb_logp, "smb_nmpipeTransact for fd[%d] %d bytes in, %d max bytes out",
1665 fd, p->totalData, p->maxReturnData);
1667 fidp = smb_FindFID(vcp, fd, 0);
1669 osi_Log2(smb_logp, "smb_nmpipeTransact Unknown SMB Fid vcp 0x%p fid %d",
1671 return CM_ERROR_BADFD;
1673 lock_ObtainMutex(&fidp->mx);
1674 if (fidp->flags & SMB_FID_RPC) {
1677 lock_ReleaseMutex(&fidp->mx);
1680 code = smb_RPCNmpipeTransact(fidp, vcp, p, op);
1681 smb_ReleaseFID(fidp);
1683 /* We only deal with RPC pipes */
1684 osi_Log2(smb_logp, "smb_nmpipeTransact Not a RPC vcp 0x%p fid %d",
1686 code = CM_ERROR_BADFD;
1693 /* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
1694 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1696 smb_tran2Packet_t *asp;
1709 /* We sometimes see 0 word count. What to do? */
1710 if (*inp->wctp == 0) {
1711 osi_Log0(smb_logp, "Transaction2 word count = 0");
1712 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1714 smb_SetSMBDataLength(outp, 0);
1715 smb_SendPacket(vcp, outp);
1719 totalParms = smb_GetSMBParm(inp, 0);
1720 totalData = smb_GetSMBParm(inp, 1);
1722 firstPacket = (inp->inCom == 0x25);
1724 /* find the packet we're reassembling */
1725 lock_ObtainWrite(&smb_globalLock);
1726 asp = smb_FindTran2Packet(vcp, inp);
1728 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1730 lock_ReleaseWrite(&smb_globalLock);
1732 /* now merge in this latest packet; start by looking up offsets */
1734 parmDisp = dataDisp = 0;
1735 parmOffset = smb_GetSMBParm(inp, 10);
1736 dataOffset = smb_GetSMBParm(inp, 12);
1737 parmCount = smb_GetSMBParm(inp, 9);
1738 dataCount = smb_GetSMBParm(inp, 11);
1739 asp->setupCount = smb_GetSMBParmByte(inp, 13);
1740 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1741 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1743 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1744 totalData, dataCount, asp->maxReturnData);
1746 if (asp->setupCount == 2) {
1747 clientchar_t * pname;
1749 asp->pipeCommand = smb_GetSMBParm(inp, 14);
1750 asp->pipeParam = smb_GetSMBParm(inp, 15);
1751 pname = smb_ParseString(inp, inp->wctp + 35, NULL, 0);
1753 asp->name = cm_ClientStrDup(pname);
1756 osi_Log2(smb_logp, " Named Pipe command id [%d] with name [%S]",
1757 asp->pipeCommand, osi_LogSaveClientString(smb_logp, asp->name));
1761 parmDisp = smb_GetSMBParm(inp, 4);
1762 parmOffset = smb_GetSMBParm(inp, 3);
1763 dataDisp = smb_GetSMBParm(inp, 7);
1764 dataOffset = smb_GetSMBParm(inp, 6);
1765 parmCount = smb_GetSMBParm(inp, 2);
1766 dataCount = smb_GetSMBParm(inp, 5);
1768 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1769 parmCount, dataCount);
1772 /* now copy the parms and data */
1773 if ( asp->totalParms > 0 && parmCount != 0 )
1775 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1777 if ( asp->totalData > 0 && dataCount != 0 ) {
1778 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1781 /* account for new bytes */
1782 asp->curData += dataCount;
1783 asp->curParms += parmCount;
1785 /* finally, if we're done, remove the packet from the queue and dispatch it */
1786 if (((asp->totalParms > 0 && asp->curParms > 0)
1787 || asp->setupCount == 2) &&
1788 asp->totalData <= asp->curData &&
1789 asp->totalParms <= asp->curParms) {
1791 /* we've received it all */
1792 lock_ObtainWrite(&smb_globalLock);
1793 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1794 lock_ReleaseWrite(&smb_globalLock);
1796 switch(asp->setupCount) {
1799 rapOp = asp->parmsp[0];
1801 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES &&
1802 smb_rapDispatchTable[rapOp].procp) {
1804 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",
1805 myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1807 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1809 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",
1810 code,vcp,vcp->lana,vcp->lsn);
1813 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]",
1814 rapOp, vcp, vcp->lana, vcp->lsn);
1816 code = CM_ERROR_BADOP;
1822 { /* Named pipe operation */
1823 osi_Log2(smb_logp, "Named Pipe: %s with name [%S]",
1824 myCrt_NmpipeDispatch(asp->pipeCommand),
1825 osi_LogSaveClientString(smb_logp, asp->name));
1827 code = CM_ERROR_BADOP;
1829 switch (asp->pipeCommand) {
1830 case SMB_TRANS_SET_NMPIPE_STATE:
1831 code = smb_nmpipeSetState(vcp, asp, outp);
1834 case SMB_TRANS_RAW_READ_NMPIPE:
1837 case SMB_TRANS_QUERY_NMPIPE_STATE:
1840 case SMB_TRANS_QUERY_NMPIPE_INFO:
1843 case SMB_TRANS_PEEK_NMPIPE:
1846 case SMB_TRANS_TRANSACT_NMPIPE:
1847 code = smb_nmpipeTransact(vcp, asp, outp);
1850 case SMB_TRANS_RAW_WRITE_NMPIPE:
1853 case SMB_TRANS_READ_NMPIPE:
1856 case SMB_TRANS_WRITE_NMPIPE:
1859 case SMB_TRANS_WAIT_NMPIPE:
1862 case SMB_TRANS_CALL_NMPIPE:
1869 code = CM_ERROR_BADOP;
1872 /* if an error is returned, we're supposed to send an error packet,
1873 * otherwise the dispatched function already did the data sending.
1874 * We give dispatched proc the responsibility since it knows how much
1875 * space to allocate.
1878 smb_SendTran2Error(vcp, asp, outp, code);
1881 /* free the input tran 2 packet */
1882 smb_FreeTran2Packet(asp);
1884 else if (firstPacket) {
1885 /* the first packet in a multi-packet request, we need to send an
1886 * ack to get more data.
1888 smb_SetSMBDataLength(outp, 0);
1889 smb_SendPacket(vcp, outp);
1895 /* ANSI versions. */
1897 #pragma pack(push, 1)
1899 typedef struct smb_rap_share_info_0 {
1900 BYTE shi0_netname[13];
1901 } smb_rap_share_info_0_t;
1903 typedef struct smb_rap_share_info_1 {
1904 BYTE shi1_netname[13];
1907 DWORD shi1_remark; /* char *shi1_remark; data offset */
1908 } smb_rap_share_info_1_t;
1910 typedef struct smb_rap_share_info_2 {
1911 BYTE shi2_netname[13];
1914 DWORD shi2_remark; /* char *shi2_remark; data offset */
1915 WORD shi2_permissions;
1917 WORD shi2_current_uses;
1918 DWORD shi2_path; /* char *shi2_path; data offset */
1919 WORD shi2_passwd[9];
1921 } smb_rap_share_info_2_t;
1923 #define SMB_RAP_MAX_SHARES 512
1925 typedef struct smb_rap_share_list {
1928 smb_rap_share_info_0_t * shares;
1929 } smb_rap_share_list_t;
1933 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1934 smb_rap_share_list_t * sp;
1936 if (dep->name[0] == '.' && (!dep->name[1] || (dep->name[1] == '.' && !dep->name[2])))
1937 return 0; /* skip over '.' and '..' */
1939 sp = (smb_rap_share_list_t *) vrockp;
1941 strncpy(sp->shares[sp->cShare].shi0_netname, dep->name, 12);
1942 sp->shares[sp->cShare].shi0_netname[12] = 0;
1946 if (sp->cShare >= sp->maxShares)
1947 return CM_ERROR_STOPNOW;
1952 /* RAP NetShareEnumRequest */
1953 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1955 smb_tran2Packet_t *outp;
1956 unsigned short * tp;
1960 int outParmsTotal; /* total parameter bytes */
1961 int outDataTotal; /* total data bytes */
1964 DWORD allSubmount = 0;
1966 DWORD nRegShares = 0;
1967 DWORD nSharesRet = 0;
1969 HKEY hkSubmount = NULL;
1970 smb_rap_share_info_1_t * shares;
1973 clientchar_t thisShare[AFSPATHMAX];
1977 smb_rap_share_list_t rootShares;
1981 cm_scache_t *rootScp;
1983 tp = p->parmsp + 1; /* skip over function number (always 0) */
1986 clientchar_t * cdescp;
1988 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1989 if (cm_ClientStrCmp(cdescp, _C("WrLeh")))
1990 return CM_ERROR_INVAL;
1991 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1992 if (cm_ClientStrCmp(cdescp, _C("B13BWz")))
1993 return CM_ERROR_INVAL;
1999 if (infoLevel != 1) {
2000 return CM_ERROR_INVAL;
2003 /* We are supposed to use the same ASCII data structure even if
2004 Unicode is negotiated, which ultimately means that the share
2005 names that we return must be at most 13 characters in length,
2006 including the NULL terminator.
2008 The RAP specification states that shares with names longer than
2009 12 characters should not be included in the enumeration.
2010 However, since we support prefix cell references and since many
2011 cell names are going to exceed 12 characters, we lie and send
2012 the first 12 characters.
2015 /* first figure out how many shares there are */
2016 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
2017 KEY_QUERY_VALUE, &hkParam);
2018 if (rv == ERROR_SUCCESS) {
2019 len = sizeof(allSubmount);
2020 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
2021 (BYTE *) &allSubmount, &len);
2022 if (rv != ERROR_SUCCESS || allSubmount != 0) {
2025 RegCloseKey (hkParam);
2028 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
2029 0, KEY_QUERY_VALUE, &hkSubmount);
2030 if (rv == ERROR_SUCCESS) {
2031 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
2032 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
2033 if (rv != ERROR_SUCCESS)
2039 /* fetch the root shares */
2040 rootShares.maxShares = SMB_RAP_MAX_SHARES;
2041 rootShares.cShare = 0;
2042 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
2046 userp = smb_GetTran2User(vcp,p);
2048 thyper.HighPart = 0;
2051 rootScp = cm_RootSCachep(userp, &req);
2052 cm_HoldSCache(rootScp);
2053 cm_ApplyDir(rootScp, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
2054 cm_ReleaseSCache(rootScp);
2056 cm_ReleaseUser(userp);
2058 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
2060 #define REMARK_LEN 1
2061 outParmsTotal = 8; /* 4 dwords */
2062 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
2063 if(outDataTotal > bufsize) {
2064 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
2065 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
2068 nSharesRet = nShares;
2071 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
2073 /* now for the submounts */
2074 shares = (smb_rap_share_info_1_t *) outp->datap;
2075 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
2077 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
2080 StringCchCopyA(shares[cshare].shi1_netname,
2081 lengthof(shares[cshare].shi1_netname), "all" );
2082 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
2083 /* type and pad are zero already */
2089 for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
2090 len = sizeof(thisShare);
2091 rv = RegEnumValueW(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
2092 if (rv == ERROR_SUCCESS &&
2093 cm_ClientStrLen(thisShare) &&
2094 (!allSubmount || cm_ClientStrCmpI(thisShare,_C("all")))) {
2095 cm_ClientStringToUtf8(thisShare, -1, shares[cshare].shi1_netname,
2096 lengthof( shares[cshare].shi1_netname ));
2097 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
2098 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
2103 nShares--; /* uncount key */
2106 RegCloseKey(hkSubmount);
2109 nonrootShares = cshare;
2111 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
2112 /* in case there are collisions with submounts, submounts have
2114 for (j=0; j < nonrootShares; j++)
2115 if (!cm_stricmp_utf8(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
2118 if (j < nonrootShares) {
2119 nShares--; /* uncount */
2123 StringCchCopyA(shares[cshare].shi1_netname, lengthof(shares[cshare].shi1_netname),
2124 rootShares.shares[i].shi0_netname);
2125 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
2130 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
2131 outp->parmsp[1] = 0;
2132 outp->parmsp[2] = cshare;
2133 outp->parmsp[3] = nShares;
2135 outp->totalData = (int)(cstrp - outp->datap);
2136 outp->totalParms = outParmsTotal;
2138 smb_SendTran2Packet(vcp, outp, op);
2139 smb_FreeTran2Packet(outp);
2141 free(rootShares.shares);
2146 /* RAP NetShareGetInfo */
2147 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2149 smb_tran2Packet_t *outp;
2150 unsigned short * tp;
2151 clientchar_t * shareName;
2152 BOOL shareFound = FALSE;
2153 unsigned short infoLevel;
2154 unsigned short bufsize;
2163 cm_scache_t *scp = NULL;
2169 tp = p->parmsp + 1; /* skip over function number (always 1) */
2172 clientchar_t * cdescp;
2174 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2175 if (cm_ClientStrCmp(cdescp, _C("zWrLh")))
2177 return CM_ERROR_INVAL;
2179 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2180 if (cm_ClientStrCmp(cdescp, _C("B13")) &&
2181 cm_ClientStrCmp(cdescp, _C("B13BWz")) &&
2182 cm_ClientStrCmp(cdescp, _C("B13BWzWWWzB9B")))
2184 return CM_ERROR_INVAL;
2186 shareName = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2194 totalData = sizeof(smb_rap_share_info_0_t);
2195 else if(infoLevel == SMB_INFO_STANDARD)
2196 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
2197 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
2198 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
2200 return CM_ERROR_INVAL;
2202 if(!cm_ClientStrCmpI(shareName, _C("all")) || !cm_ClientStrCmp(shareName,_C("*."))) {
2203 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
2204 KEY_QUERY_VALUE, &hkParam);
2205 if (rv == ERROR_SUCCESS) {
2206 len = sizeof(allSubmount);
2207 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
2208 (BYTE *) &allSubmount, &len);
2209 if (rv != ERROR_SUCCESS || allSubmount != 0) {
2212 RegCloseKey (hkParam);
2219 userp = smb_GetTran2User(vcp, p);
2221 osi_Log1(smb_logp,"ReceiveRAPNetShareGetInfo unable to resolve user [%d]", p->uid);
2222 return CM_ERROR_BADSMB;
2224 code = cm_NameI(cm_RootSCachep(userp, &req), shareName,
2225 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
2226 userp, NULL, &req, &scp);
2228 cm_ReleaseSCache(scp);
2231 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
2232 KEY_QUERY_VALUE, &hkSubmount);
2233 if (rv == ERROR_SUCCESS) {
2234 rv = RegQueryValueExW(hkSubmount, shareName, NULL, NULL, NULL, NULL);
2235 if (rv == ERROR_SUCCESS) {
2238 RegCloseKey(hkSubmount);
2244 return CM_ERROR_BADSHARENAME;
2246 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
2247 memset(outp->datap, 0, totalData);
2249 outp->parmsp[0] = 0;
2250 outp->parmsp[1] = 0;
2251 outp->parmsp[2] = totalData;
2253 if (infoLevel == 0) {
2254 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
2255 cm_ClientStringToUtf8(shareName, -1, info->shi0_netname,
2256 lengthof(info->shi0_netname));
2257 } else if(infoLevel == SMB_INFO_STANDARD) {
2258 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
2259 cm_ClientStringToUtf8(shareName, -1, info->shi1_netname, lengthof(info->shi1_netname));
2260 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
2261 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
2262 /* type and pad are already zero */
2263 } else { /* infoLevel==2 */
2264 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
2265 cm_ClientStringToUtf8(shareName, -1, info->shi2_netname, lengthof(info->shi2_netname));
2266 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
2267 info->shi2_permissions = ACCESS_ALL;
2268 info->shi2_max_uses = (unsigned short) -1;
2269 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
2272 outp->totalData = totalData;
2273 outp->totalParms = totalParam;
2275 smb_SendTran2Packet(vcp, outp, op);
2276 smb_FreeTran2Packet(outp);
2281 #pragma pack(push, 1)
2283 typedef struct smb_rap_wksta_info_10 {
2284 DWORD wki10_computername; /*char *wki10_computername;*/
2285 DWORD wki10_username; /* char *wki10_username; */
2286 DWORD wki10_langroup; /* char *wki10_langroup;*/
2287 BYTE wki10_ver_major;
2288 BYTE wki10_ver_minor;
2289 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
2290 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
2291 } smb_rap_wksta_info_10_t;
2295 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2297 smb_tran2Packet_t *outp;
2301 unsigned short * tp;
2304 smb_rap_wksta_info_10_t * info;
2308 tp = p->parmsp + 1; /* Skip over function number */
2311 clientchar_t * cdescp;
2313 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2314 SMB_STRF_FORCEASCII);
2315 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2316 return CM_ERROR_INVAL;
2318 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2319 SMB_STRF_FORCEASCII);
2320 if (cm_ClientStrCmp(cdescp, _C("zzzBBzz")))
2321 return CM_ERROR_INVAL;
2327 if (infoLevel != 10) {
2328 return CM_ERROR_INVAL;
2334 totalData = sizeof(*info) + /* info */
2335 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
2336 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
2337 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
2338 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
2339 1; /* wki10_oth_domains (null)*/
2341 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2343 memset(outp->parmsp,0,totalParams);
2344 memset(outp->datap,0,totalData);
2346 info = (smb_rap_wksta_info_10_t *) outp->datap;
2347 cstrp = (char *) (info + 1);
2349 info->wki10_computername = (DWORD) (cstrp - outp->datap);
2350 StringCbCopyA(cstrp, totalData, smb_localNamep);
2351 cstrp += strlen(cstrp) + 1;
2353 info->wki10_username = (DWORD) (cstrp - outp->datap);
2354 uidp = smb_FindUID(vcp, p->uid, 0);
2356 lock_ObtainMutex(&uidp->mx);
2357 if(uidp->unp && uidp->unp->name)
2358 cm_ClientStringToUtf8(uidp->unp->name, -1,
2359 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2360 lock_ReleaseMutex(&uidp->mx);
2361 smb_ReleaseUID(uidp);
2363 cstrp += strlen(cstrp) + 1;
2365 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
2366 StringCbCopyA(cstrp, totalData - (cstrp - outp->datap)*sizeof(char), "WORKGROUP");
2367 cstrp += strlen(cstrp) + 1;
2369 /* TODO: Not sure what values these should take, but these work */
2370 info->wki10_ver_major = 5;
2371 info->wki10_ver_minor = 1;
2373 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
2374 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
2375 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2376 cstrp += strlen(cstrp) + 1;
2378 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
2379 cstrp ++; /* no other domains */
2381 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
2382 outp->parmsp[2] = outp->totalData;
2383 outp->totalParms = totalParams;
2385 smb_SendTran2Packet(vcp,outp,op);
2386 smb_FreeTran2Packet(outp);
2391 #pragma pack(push, 1)
2393 typedef struct smb_rap_server_info_0 {
2395 } smb_rap_server_info_0_t;
2397 typedef struct smb_rap_server_info_1 {
2399 BYTE sv1_version_major;
2400 BYTE sv1_version_minor;
2402 DWORD sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
2403 } smb_rap_server_info_1_t;
2407 char smb_ServerComment[] = "OpenAFS Client";
2408 int smb_ServerCommentLen = sizeof(smb_ServerComment);
2410 #define SMB_SV_TYPE_SERVER 0x00000002L
2411 #define SMB_SV_TYPE_NT 0x00001000L
2412 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
2414 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2416 smb_tran2Packet_t *outp;
2420 unsigned short * tp;
2423 smb_rap_server_info_0_t * info0;
2424 smb_rap_server_info_1_t * info1;
2427 tp = p->parmsp + 1; /* Skip over function number */
2430 clientchar_t * cdescp;
2432 cdescp = smb_ParseStringT2Parm(p, (unsigned char *) tp, (char **) &tp,
2433 SMB_STRF_FORCEASCII);
2434 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2435 return CM_ERROR_INVAL;
2436 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2437 SMB_STRF_FORCEASCII);
2438 if (cm_ClientStrCmp(cdescp, _C("B16")) ||
2439 cm_ClientStrCmp(cdescp, _C("B16BBDz")))
2440 return CM_ERROR_INVAL;
2446 if (infoLevel != 0 && infoLevel != 1) {
2447 return CM_ERROR_INVAL;
2453 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
2454 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
2456 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2458 memset(outp->parmsp,0,totalParams);
2459 memset(outp->datap,0,totalData);
2461 if (infoLevel == 0) {
2462 info0 = (smb_rap_server_info_0_t *) outp->datap;
2463 cstrp = (char *) (info0 + 1);
2464 StringCchCopyA(info0->sv0_name, lengthof(info0->sv0_name), "AFS");
2465 } else { /* infoLevel == SMB_INFO_STANDARD */
2466 info1 = (smb_rap_server_info_1_t *) outp->datap;
2467 cstrp = (char *) (info1 + 1);
2468 StringCchCopyA(info1->sv1_name, lengthof(info1->sv1_name), "AFS");
2471 SMB_SV_TYPE_SERVER |
2473 SMB_SV_TYPE_SERVER_NT;
2475 info1->sv1_version_major = 5;
2476 info1->sv1_version_minor = 1;
2477 info1->sv1_comment_or_master_browser = (DWORD) (cstrp - outp->datap);
2479 StringCbCopyA(cstrp, smb_ServerCommentLen, smb_ServerComment);
2481 cstrp += smb_ServerCommentLen / sizeof(char);
2484 totalData = (DWORD)(cstrp - outp->datap);
2485 outp->totalData = min(bufsize,totalData); /* actual data size */
2486 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
2487 outp->parmsp[2] = totalData;
2488 outp->totalParms = totalParams;
2490 smb_SendTran2Packet(vcp,outp,op);
2491 smb_FreeTran2Packet(outp);
2496 /* SMB_COM_TRANSACTION2 and SMB_COM_TRANSACTION2_SECONDARY */
2497 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2499 smb_tran2Packet_t *asp;
2510 DWORD oldTime, newTime;
2512 /* We sometimes see 0 word count. What to do? */
2513 if (*inp->wctp == 0) {
2514 osi_Log0(smb_logp, "Transaction2 word count = 0");
2515 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
2517 smb_SetSMBDataLength(outp, 0);
2518 smb_SendPacket(vcp, outp);
2522 totalParms = smb_GetSMBParm(inp, 0);
2523 totalData = smb_GetSMBParm(inp, 1);
2525 firstPacket = (inp->inCom == 0x32);
2527 /* find the packet we're reassembling */
2528 lock_ObtainWrite(&smb_globalLock);
2529 asp = smb_FindTran2Packet(vcp, inp);
2531 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
2533 lock_ReleaseWrite(&smb_globalLock);
2535 /* now merge in this latest packet; start by looking up offsets */
2537 parmDisp = dataDisp = 0;
2538 parmOffset = smb_GetSMBParm(inp, 10);
2539 dataOffset = smb_GetSMBParm(inp, 12);
2540 parmCount = smb_GetSMBParm(inp, 9);
2541 dataCount = smb_GetSMBParm(inp, 11);
2542 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2543 asp->maxReturnData = smb_GetSMBParm(inp, 3);
2545 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2546 totalData, dataCount, asp->maxReturnData);
2549 parmDisp = smb_GetSMBParm(inp, 4);
2550 parmOffset = smb_GetSMBParm(inp, 3);
2551 dataDisp = smb_GetSMBParm(inp, 7);
2552 dataOffset = smb_GetSMBParm(inp, 6);
2553 parmCount = smb_GetSMBParm(inp, 2);
2554 dataCount = smb_GetSMBParm(inp, 5);
2556 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2557 parmCount, dataCount);
2560 /* now copy the parms and data */
2561 if ( asp->totalParms > 0 && parmCount != 0 )
2563 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2565 if ( asp->totalData > 0 && dataCount != 0 ) {
2566 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2569 /* account for new bytes */
2570 asp->curData += dataCount;
2571 asp->curParms += parmCount;
2573 /* finally, if we're done, remove the packet from the queue and dispatch it */
2574 if (asp->totalParms > 0 &&
2575 asp->curParms > 0 &&
2576 asp->totalData <= asp->curData &&
2577 asp->totalParms <= asp->curParms) {
2578 /* we've received it all */
2579 lock_ObtainWrite(&smb_globalLock);
2580 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2581 lock_ReleaseWrite(&smb_globalLock);
2583 oldTime = GetTickCount();
2585 /* now dispatch it */
2586 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2587 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2588 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2591 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2592 code = CM_ERROR_BADOP;
2595 /* if an error is returned, we're supposed to send an error packet,
2596 * otherwise the dispatched function already did the data sending.
2597 * We give dispatched proc the responsibility since it knows how much
2598 * space to allocate.
2601 smb_SendTran2Error(vcp, asp, outp, code);
2604 newTime = GetTickCount();
2605 if (newTime - oldTime > 45000) {
2608 clientchar_t *treepath = NULL; /* do not free */
2609 clientchar_t *pathname = NULL;
2610 cm_fid_t afid = {0,0,0,0,0};
2612 uidp = smb_FindUID(vcp, asp->uid, 0);
2613 smb_LookupTIDPath(vcp, asp->tid, &treepath);
2614 fidp = smb_FindFID(vcp, inp->fid, 0);
2617 lock_ObtainMutex(&fidp->mx);
2618 if (fidp->NTopen_pathp)
2619 pathname = fidp->NTopen_pathp;
2621 afid = fidp->scp->fid;
2623 if (inp->stringsp->wdata)
2624 pathname = inp->stringsp->wdata;
2627 afsi_log("Request %s duration %d ms user 0x%x \"%S\" pid 0x%x mid 0x%x tid 0x%x \"%S\" path? \"%S\" afid (%d.%d.%d.%d)",
2628 myCrt_2Dispatch(asp->opcode), newTime - oldTime,
2629 asp->uid, uidp ? uidp->unp->name : NULL,
2630 asp->pid, asp->mid, asp->tid,
2633 afid.cell, afid.volume, afid.vnode, afid.unique);
2636 lock_ReleaseMutex(&fidp->mx);
2639 smb_ReleaseUID(uidp);
2641 smb_ReleaseFID(fidp);
2644 /* free the input tran 2 packet */
2645 smb_FreeTran2Packet(asp);
2647 else if (firstPacket) {
2648 /* the first packet in a multi-packet request, we need to send an
2649 * ack to get more data.
2651 smb_SetSMBDataLength(outp, 0);
2652 smb_SendPacket(vcp, outp);
2659 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2661 clientchar_t *pathp;
2662 smb_tran2Packet_t *outp;
2667 cm_scache_t *dscp; /* dir we're dealing with */
2668 cm_scache_t *scp; /* file we're creating */
2672 clientchar_t *lastNamep;
2679 int parmSlot; /* which parm we're dealing with */
2680 long returnEALength;
2681 clientchar_t *tidPathp;
2684 BOOL is_rpc = FALSE;
2685 BOOL is_ipc = FALSE;
2691 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2692 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2694 openFun = p->parmsp[6]; /* open function */
2695 excl = ((openFun & 3) == 0);
2696 trunc = ((openFun & 3) == 2); /* truncate it */
2697 openMode = (p->parmsp[1] & 0x7);
2698 openAction = 0; /* tracks what we did */
2700 attributes = p->parmsp[3];
2701 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2703 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
2706 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2708 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2709 if (code == CM_ERROR_TIDIPC) {
2711 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2714 spacep = cm_GetSpace();
2715 /* smb_StripLastComponent will strip "::$DATA" if present */
2716 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2720 /* special case magic file name for receiving IOCTL requests
2721 * (since IOCTL calls themselves aren't getting through).
2723 (cm_ClientStrCmpI(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
2725 /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional)*/
2726 (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
2728 unsigned short file_type = 0;
2729 unsigned short device_state = 0;
2731 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2734 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
2735 osi_Log2(smb_logp, "smb_ReceiveTran2Open Creating RPC Fid [%d] code [%d]",
2738 smb_ReleaseFID(fidp);
2739 smb_FreeTran2Packet(outp);
2740 osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
2744 smb_SetupIoctlFid(fidp, spacep);
2745 osi_Log1(smb_logp, "smb_ReceiveTran2Open Creating IOCTL Fid [%d]", fidp->fid);
2748 /* copy out remainder of the parms */
2750 outp->parmsp[parmSlot++] = fidp->fid;
2752 outp->parmsp[parmSlot++] = 0; /* attrs */
2753 outp->parmsp[parmSlot++] = 0; /* mod time */
2754 outp->parmsp[parmSlot++] = 0;
2755 outp->parmsp[parmSlot++] = 0; /* len */
2756 outp->parmsp[parmSlot++] = 0x7fff;
2757 outp->parmsp[parmSlot++] = openMode;
2758 outp->parmsp[parmSlot++] = file_type;
2759 outp->parmsp[parmSlot++] = device_state;
2761 /* and the final "always present" stuff */
2762 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2763 /* next write out the "unique" ID */
2764 outp->parmsp[parmSlot++] = 0x1234;
2765 outp->parmsp[parmSlot++] = 0x5678;
2766 outp->parmsp[parmSlot++] = 0;
2767 if (returnEALength) {
2768 outp->parmsp[parmSlot++] = 0;
2769 outp->parmsp[parmSlot++] = 0;
2772 outp->totalData = 0;
2773 outp->totalParms = parmSlot * 2;
2775 smb_SendTran2Packet(vcp, outp, op);
2777 smb_FreeTran2Packet(outp);
2779 /* and clean up fid reference */
2780 smb_ReleaseFID(fidp);
2786 osi_Log1(smb_logp, "Tran2Open rejecting IPC TID vcp %p", vcp);
2787 smb_FreeTran2Packet(outp);
2788 return CM_ERROR_BADFD;
2792 if (!cm_IsValidClientString(pathp)) {
2794 clientchar_t * hexp;
2796 hexp = cm_GetRawCharsAlloc(pathp, -1);
2797 osi_Log1(smb_logp, "Tran2Open rejecting invalid name. [%S]",
2798 osi_LogSaveClientString(smb_logp, hexp));
2802 osi_Log0(smb_logp, "Tran2Open rejecting invalid name");
2804 smb_FreeTran2Packet(outp);
2805 return CM_ERROR_BADNTFILENAME;
2808 #ifdef DEBUG_VERBOSE
2810 char *hexp, *asciip;
2811 asciip = (lastNamep ? lastNamep : pathp);
2812 hexp = osi_HexifyString( asciip );
2813 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2818 userp = smb_GetTran2User(vcp, p);
2819 /* In the off chance that userp is NULL, we log and abandon */
2821 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2822 smb_FreeTran2Packet(outp);
2823 return CM_ERROR_BADSMB;
2827 code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
2828 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2829 userp, tidPathp, &req, &scp);
2831 if (code == CM_ERROR_NOSUCHFILE ||
2832 code == CM_ERROR_NOSUCHPATH ||
2833 code == CM_ERROR_BPLUS_NOMATCH)
2834 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
2835 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2836 userp, tidPathp, &req, &dscp);
2837 cm_FreeSpace(spacep);
2840 cm_ReleaseUser(userp);
2841 smb_FreeTran2Packet(outp);
2846 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2847 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2848 (clientchar_t*) spacep->data);
2849 cm_ReleaseSCache(dscp);
2850 cm_ReleaseUser(userp);
2851 smb_FreeTran2Packet(outp);
2852 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2853 return CM_ERROR_PATH_NOT_COVERED;
2855 return CM_ERROR_NOSUCHPATH;
2857 #endif /* DFS_SUPPORT */
2859 /* otherwise, scp points to the parent directory. Do a lookup,
2860 * and truncate the file if we find it, otherwise we create the
2867 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2869 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2870 cm_ReleaseSCache(dscp);
2871 cm_ReleaseUser(userp);
2872 smb_FreeTran2Packet(outp);
2876 /* macintosh is expensive to program for it */
2877 cm_FreeSpace(spacep);
2880 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2881 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2882 cm_ReleaseSCache(scp);
2883 cm_ReleaseUser(userp);
2884 smb_FreeTran2Packet(outp);
2885 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2886 return CM_ERROR_PATH_NOT_COVERED;
2888 return CM_ERROR_NOSUCHPATH;
2890 #endif /* DFS_SUPPORT */
2893 /* if we get here, if code is 0, the file exists and is represented by
2894 * scp. Otherwise, we have to create it.
2897 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2900 cm_ReleaseSCache(dscp);
2901 cm_ReleaseSCache(scp);
2902 cm_ReleaseUser(userp);
2903 smb_FreeTran2Packet(outp);
2908 /* oops, file shouldn't be there */
2910 cm_ReleaseSCache(dscp);
2911 cm_ReleaseSCache(scp);
2912 cm_ReleaseUser(userp);
2913 smb_FreeTran2Packet(outp);
2914 return CM_ERROR_EXISTS;
2918 setAttr.mask = CM_ATTRMASK_LENGTH;
2919 setAttr.length.LowPart = 0;
2920 setAttr.length.HighPart = 0;
2921 code = cm_SetAttr(scp, &setAttr, userp, &req);
2922 openAction = 3; /* truncated existing file */
2925 openAction = 1; /* found existing file */
2927 else if (!(openFun & 0x10)) {
2928 /* don't create if not found */
2930 cm_ReleaseSCache(dscp);
2931 osi_assertx(scp == NULL, "null cm_scache_t");
2932 cm_ReleaseUser(userp);
2933 smb_FreeTran2Packet(outp);
2934 return CM_ERROR_NOSUCHFILE;
2937 osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2938 openAction = 2; /* created file */
2939 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2940 cm_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2941 smb_SetInitialModeBitsForFile(attributes, &setAttr);
2943 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2947 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2948 smb_NotifyChange(FILE_ACTION_ADDED,
2949 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2950 dscp, lastNamep, NULL, TRUE);
2951 } else if (!excl && code == CM_ERROR_EXISTS) {
2952 /* not an exclusive create, and someone else tried
2953 * creating it already, then we open it anyway. We
2954 * don't bother retrying after this, since if this next
2955 * fails, that means that the file was deleted after we
2956 * started this call.
2958 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2962 setAttr.mask = CM_ATTRMASK_LENGTH;
2963 setAttr.length.LowPart = 0;
2964 setAttr.length.HighPart = 0;
2965 code = cm_SetAttr(scp, &setAttr, userp,
2968 } /* lookup succeeded */
2972 /* we don't need this any longer */
2974 cm_ReleaseSCache(dscp);
2977 /* something went wrong creating or truncating the file */
2979 cm_ReleaseSCache(scp);
2980 cm_ReleaseUser(userp);
2981 smb_FreeTran2Packet(outp);
2985 /* make sure we're about to open a file */
2986 if (scp->fileType != CM_SCACHETYPE_FILE) {
2988 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2989 cm_scache_t * targetScp = 0;
2990 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2992 /* we have a more accurate file to use (the
2993 * target of the symbolic link). Otherwise,
2994 * we'll just use the symlink anyway.
2996 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2998 cm_ReleaseSCache(scp);
3002 if (scp->fileType != CM_SCACHETYPE_FILE) {
3003 cm_ReleaseSCache(scp);
3004 cm_ReleaseUser(userp);
3005 smb_FreeTran2Packet(outp);
3006 return CM_ERROR_ISDIR;
3010 /* now all we have to do is open the file itself */
3011 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3012 osi_assertx(fidp, "null smb_fid_t");
3015 lock_ObtainMutex(&fidp->mx);
3016 /* save a pointer to the vnode */
3017 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
3019 lock_ObtainWrite(&scp->rw);
3020 scp->flags |= CM_SCACHEFLAG_SMB_FID;
3021 lock_ReleaseWrite(&scp->rw);
3024 fidp->userp = userp;
3026 /* compute open mode */
3028 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
3029 if (openMode == 1 || openMode == 2)
3030 fidp->flags |= SMB_FID_OPENWRITE;
3032 /* remember that the file was newly created */
3034 fidp->flags |= SMB_FID_CREATED;
3036 lock_ReleaseMutex(&fidp->mx);
3038 smb_ReleaseFID(fidp);
3040 cm_Open(scp, 0, userp);
3042 /* copy out remainder of the parms */
3044 outp->parmsp[parmSlot++] = fidp->fid;
3045 lock_ObtainRead(&scp->rw);
3047 outp->parmsp[parmSlot++] = smb_Attributes(scp);
3048 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3049 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
3050 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
3051 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
3052 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
3053 outp->parmsp[parmSlot++] = openMode;
3054 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
3055 outp->parmsp[parmSlot++] = 0; /* IPC junk */
3057 /* and the final "always present" stuff */
3058 outp->parmsp[parmSlot++] = openAction;
3059 /* next write out the "unique" ID */
3060 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
3061 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
3062 outp->parmsp[parmSlot++] = 0;
3063 if (returnEALength) {
3064 outp->parmsp[parmSlot++] = 0;
3065 outp->parmsp[parmSlot++] = 0;
3067 lock_ReleaseRead(&scp->rw);
3068 outp->totalData = 0; /* total # of data bytes */
3069 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
3071 smb_SendTran2Packet(vcp, outp, op);
3073 smb_FreeTran2Packet(outp);
3075 cm_ReleaseUser(userp);
3076 /* leave scp held since we put it in fidp->scp */
3080 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3083 unsigned short infolevel;
3085 infolevel = p->parmsp[0];
3087 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
3089 return CM_ERROR_BAD_LEVEL;
3092 /* TRANS2_QUERY_FS_INFORMATION */
3093 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3095 smb_tran2Packet_t *outp;
3096 smb_tran2QFSInfo_t qi;
3100 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
3102 switch (p->parmsp[0]) {
3103 case SMB_INFO_ALLOCATION:
3105 responseSize = sizeof(qi.u.allocInfo);
3107 qi.u.allocInfo.FSID = 0;
3108 qi.u.allocInfo.sectorsPerAllocUnit = 1;
3109 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
3110 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
3111 qi.u.allocInfo.bytesPerSector = 1024;
3114 case SMB_INFO_VOLUME:
3116 qi.u.volumeInfo.vsn = 1234; /* Volume serial number */
3117 qi.u.volumeInfo.vnCount = 3; /* Number of characters in label (AFS\0)*/
3119 /* we're supposed to pad it out with zeroes to the end */
3120 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
3121 smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
3123 responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
3126 case SMB_QUERY_FS_VOLUME_INFO:
3127 /* FS volume info */
3128 responseSize = sizeof(qi.u.FSvolumeInfo);
3131 FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
3132 memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
3135 qi.u.FSvolumeInfo.vsn = 1234;
3136 qi.u.FSvolumeInfo.vnCount = 6; /* This is always in Unicode */
3137 memset(&qi.u.FSvolumeInfo.label, 0, sizeof(qi.u.FSvolumeInfo.label));
3138 memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
3141 case SMB_QUERY_FS_SIZE_INFO:
3143 responseSize = sizeof(qi.u.FSsizeInfo);
3145 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
3146 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
3147 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
3148 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
3149 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
3150 qi.u.FSsizeInfo.bytesPerSector = 1024;
3153 case SMB_QUERY_FS_DEVICE_INFO:
3154 /* FS device info */
3155 responseSize = sizeof(qi.u.FSdeviceInfo);
3157 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
3158 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
3161 case SMB_QUERY_FS_ATTRIBUTE_INFO:
3162 /* FS attribute info */
3164 /* attributes, defined in WINNT.H:
3165 * FILE_CASE_SENSITIVE_SEARCH 0x1
3166 * FILE_CASE_PRESERVED_NAMES 0x2
3167 * FILE_UNICODE_ON_DISK 0x4
3168 * FILE_VOLUME_QUOTAS 0x10
3169 * <no name defined> 0x4000
3170 * If bit 0x4000 is not set, Windows 95 thinks
3171 * we can't handle long (non-8.3) names,
3172 * despite our protestations to the contrary.
3174 qi.u.FSattributeInfo.attributes = 0x4003;
3175 /* The maxCompLength is supposed to be in bytes */
3177 qi.u.FSattributeInfo.attributes |= 0x04;
3179 qi.u.FSattributeInfo.maxCompLength = 255;
3180 smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
3181 qi.u.FSattributeInfo.FSnameLength = sz;
3184 sizeof(qi.u.FSattributeInfo.attributes) +
3185 sizeof(qi.u.FSattributeInfo.maxCompLength) +
3186 sizeof(qi.u.FSattributeInfo.FSnameLength) +
3191 case SMB_INFO_UNIX: /* CIFS Unix Info */
3192 case SMB_INFO_MACOS: /* Mac FS Info */
3194 return CM_ERROR_BADOP;
3197 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
3199 /* copy out return data, and set corresponding sizes */
3200 outp->totalParms = 0;
3201 outp->totalData = responseSize;
3202 memcpy(outp->datap, &qi, responseSize);
3204 /* send and free the packets */
3205 smb_SendTran2Packet(vcp, outp, op);
3206 smb_FreeTran2Packet(outp);
3211 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3213 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
3214 return CM_ERROR_BADOP;
3217 struct smb_ShortNameRock {
3218 clientchar_t *maskp;
3220 clientchar_t *shortName;
3221 size_t shortNameLen;
3224 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
3227 struct smb_ShortNameRock *rockp;
3228 normchar_t normName[MAX_PATH];
3229 clientchar_t *shortNameEnd;
3233 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t)) == 0) {
3234 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
3235 osi_LogSaveString(smb_logp, dep->name));
3239 /* compare both names and vnodes, though probably just comparing vnodes
3240 * would be safe enough.
3242 if (cm_NormStrCmpI(normName, rockp->maskp) != 0)
3244 if (ntohl(dep->fid.vnode) != rockp->vnode)
3247 /* This is the entry */
3248 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
3249 rockp->shortNameLen = shortNameEnd - rockp->shortName;
3251 return CM_ERROR_STOPNOW;
3254 long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
3255 clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
3257 struct smb_ShortNameRock rock;
3258 clientchar_t *lastNamep;
3261 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
3265 spacep = cm_GetSpace();
3266 /* smb_StripLastComponent will strip "::$DATA" if present */
3267 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
3269 code = cm_NameI(cm_RootSCachep(userp, reqp), spacep->wdata,
3270 caseFold, userp, tidPathp,
3272 cm_FreeSpace(spacep);
3277 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3278 cm_ReleaseSCache(dscp);
3279 cm_ReleaseUser(userp);
3283 return CM_ERROR_PATH_NOT_COVERED;
3285 #endif /* DFS_SUPPORT */
3287 if (!lastNamep) lastNamep = pathp;
3290 thyper.HighPart = 0;
3291 rock.shortName = shortName;
3293 rock.maskp = lastNamep;
3294 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
3296 cm_ReleaseSCache(dscp);
3299 return CM_ERROR_NOSUCHFILE;
3300 if (code == CM_ERROR_STOPNOW) {
3301 *shortNameLenp = rock.shortNameLen;
3307 /* TRANS2_QUERY_PATH_INFORMATION */
3308 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3310 smb_tran2Packet_t *outp;
3313 unsigned short infoLevel;
3314 smb_tran2QPathInfo_t qpi;
3316 unsigned short attributes;
3317 unsigned long extAttributes;
3318 clientchar_t shortName[13];
3322 cm_scache_t *scp, *dscp;
3323 int scp_rw_held = 0;
3326 clientchar_t *pathp;
3327 clientchar_t *tidPathp;
3328 clientchar_t *lastComp;
3333 infoLevel = p->parmsp[0];
3334 if (infoLevel == SMB_INFO_IS_NAME_VALID)
3336 else if (infoLevel == SMB_INFO_STANDARD)
3337 responseSize = sizeof(qpi.u.QPstandardInfo);
3338 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
3339 responseSize = sizeof(qpi.u.QPeaSizeInfo);
3340 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3341 responseSize = sizeof(qpi.u.QPfileBasicInfo);
3342 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3343 responseSize = sizeof(qpi.u.QPfileStandardInfo);
3344 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3345 responseSize = sizeof(qpi.u.QPfileEaInfo);
3346 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3347 responseSize = sizeof(qpi.u.QPfileNameInfo);
3348 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
3349 responseSize = sizeof(qpi.u.QPfileAllInfo);
3350 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
3351 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
3352 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO)
3353 responseSize = sizeof(qpi.u.QPfileStreamInfo);
3355 osi_Log2(smb_logp, "Bad Tran2QPathInfo op 0x%x infolevel 0x%x",
3356 p->opcode, infoLevel);
3357 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3360 memset(&qpi, 0, sizeof(qpi));
3362 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3363 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path \"%S\"", infoLevel,
3364 osi_LogSaveClientString(smb_logp, pathp));
3366 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3368 if (infoLevel > 0x100)
3369 outp->totalParms = 2;
3371 outp->totalParms = 0;
3373 /* now, if we're at infoLevel 6, we're only being asked to check
3374 * the syntax, so we just OK things now. In particular, we're *not*
3375 * being asked to verify anything about the state of any parent dirs.
3377 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
3378 smb_SendTran2Packet(vcp, outp, opx);
3379 smb_FreeTran2Packet(outp);
3383 userp = smb_GetTran2User(vcp, p);
3385 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
3386 smb_FreeTran2Packet(outp);
3387 return CM_ERROR_BADSMB;
3390 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3392 osi_Log1(smb_logp, "ReceiveTran2QPathInfo tid path lookup failure 0x%x", code);
3393 cm_ReleaseUser(userp);
3394 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
3395 smb_FreeTran2Packet(outp);
3399 osi_Log1(smb_logp, "T2 QPathInfo tidPathp \"%S\"",
3400 osi_LogSaveClientString(smb_logp, tidPathp));
3403 * XXX Strange hack XXX
3405 * As of Patch 7 (13 January 98), we are having the following problem:
3406 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3407 * requests to look up "desktop.ini" in all the subdirectories.
3408 * This can cause zillions of timeouts looking up non-existent cells
3409 * and volumes, especially in the top-level directory.
3411 * We have not found any way to avoid this or work around it except
3412 * to explicitly ignore the requests for mount points that haven't
3413 * yet been evaluated and for directories that haven't yet been
3416 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3417 spacep = cm_GetSpace();
3418 /* smb_StripLastComponent will strip "::$DATA" if present */
3419 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3420 #ifndef SPECIAL_FOLDERS
3421 /* Make sure that lastComp is not NULL */
3423 if (cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
3424 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
3428 userp, tidPathp, &req, &dscp);
3431 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3432 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3434 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3435 code = CM_ERROR_PATH_NOT_COVERED;
3437 code = CM_ERROR_NOSUCHPATH;
3439 #endif /* DFS_SUPPORT */
3440 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3441 code = CM_ERROR_NOSUCHFILE;
3442 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3443 cm_buf_t *bp = buf_Find(&dscp->fid, &hzero);
3449 code = CM_ERROR_NOSUCHFILE;
3451 cm_ReleaseSCache(dscp);
3453 cm_FreeSpace(spacep);
3454 cm_ReleaseUser(userp);
3455 smb_SendTran2Error(vcp, p, opx, code);
3456 smb_FreeTran2Packet(outp);
3462 #endif /* SPECIAL_FOLDERS */
3464 cm_FreeSpace(spacep);
3468 code == CM_ERROR_NOSUCHFILE ||
3469 code == CM_ERROR_NOSUCHPATH ||
3470 code == CM_ERROR_BPLUS_NOMATCH) {
3471 /* now do namei and stat, and copy out the info */
3472 code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
3473 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3477 cm_ReleaseUser(userp);
3478 smb_SendTran2Error(vcp, p, opx, code);
3479 smb_FreeTran2Packet(outp);
3484 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3485 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3486 cm_ReleaseSCache(scp);
3487 cm_ReleaseUser(userp);
3488 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3489 code = CM_ERROR_PATH_NOT_COVERED;
3491 code = CM_ERROR_NOSUCHPATH;
3492 smb_SendTran2Error(vcp, p, opx, code);
3493 smb_FreeTran2Packet(outp);
3496 #endif /* DFS_SUPPORT */
3498 lock_ObtainWrite(&scp->rw);
3500 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3501 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3505 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3507 lock_ConvertWToR(&scp->rw);
3512 /* now we have the status in the cache entry, and everything is locked.
3513 * Marshall the output data.
3515 /* for info level 108, figure out short name */
3516 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3517 code = cm_GetShortName(pathp, userp, &req,
3518 tidPathp, scp->fid.vnode, shortName,
3524 smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
3525 qpi.u.QPfileAltNameInfo.fileNameLength = len;
3526 responseSize = sizeof(unsigned long) + len;
3528 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3529 smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3530 qpi.u.QPfileNameInfo.fileNameLength = len;
3531 responseSize = sizeof(unsigned long) + len;
3533 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3534 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3535 qpi.u.QPstandardInfo.creationDateTime = dosTime;
3536 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3537 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3538 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3539 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3540 attributes = smb_Attributes(scp);
3541 qpi.u.QPstandardInfo.attributes = attributes;
3542 qpi.u.QPstandardInfo.eaSize = 0;
3544 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3545 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3546 qpi.u.QPfileBasicInfo.creationTime = ft;
3547 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3548 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3549 qpi.u.QPfileBasicInfo.changeTime = ft;
3550 extAttributes = smb_ExtAttributes(scp);
3551 qpi.u.QPfileBasicInfo.attributes = extAttributes;
3552 qpi.u.QPfileBasicInfo.reserved = 0;
3554 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3557 lock_ReleaseRead(&scp->rw);
3559 fidp = smb_FindFIDByScache(vcp, scp);
3561 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3562 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3563 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3564 qpi.u.QPfileStandardInfo.directory =
3565 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3566 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3567 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3568 qpi.u.QPfileStandardInfo.reserved = 0;
3571 lock_ObtainMutex(&fidp->mx);
3572 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3573 lock_ReleaseMutex(&fidp->mx);
3574 smb_ReleaseFID(fidp);
3576 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3578 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3579 qpi.u.QPfileEaInfo.eaSize = 0;
3581 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3584 lock_ReleaseRead(&scp->rw);
3586 fidp = smb_FindFIDByScache(vcp, scp);
3588 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3589 qpi.u.QPfileAllInfo.creationTime = ft;
3590 qpi.u.QPfileAllInfo.lastAccessTime = ft;
3591 qpi.u.QPfileAllInfo.lastWriteTime = ft;
3592 qpi.u.QPfileAllInfo.changeTime = ft;
3593 extAttributes = smb_ExtAttributes(scp);
3594 qpi.u.QPfileAllInfo.attributes = extAttributes;
3595 qpi.u.QPfileAllInfo.allocationSize = scp->length;
3596 qpi.u.QPfileAllInfo.endOfFile = scp->length;
3597 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3598 qpi.u.QPfileAllInfo.deletePending = 0;
3599 qpi.u.QPfileAllInfo.directory =
3600 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3601 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3602 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3603 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.vnode;
3604 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.unique;
3605 qpi.u.QPfileAllInfo.eaSize = 0;
3606 qpi.u.QPfileAllInfo.accessFlags = 0;
3608 lock_ObtainMutex(&fidp->mx);
3609 if (fidp->flags & SMB_FID_OPENDELETE)
3610 qpi.u.QPfileAllInfo.accessFlags |= DELETE;
3611 if (fidp->flags & SMB_FID_OPENREAD_LISTDIR)
3612 qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_READ|AFS_ACCESS_EXECUTE;
3613 if (fidp->flags & SMB_FID_OPENWRITE)
3614 qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_WRITE;
3615 if (fidp->flags & SMB_FID_DELONCLOSE)
3616 qpi.u.QPfileAllInfo.deletePending = 1;
3617 lock_ReleaseMutex(&fidp->mx);
3618 smb_ReleaseFID(fidp);
3620 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.cell;
3621 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.volume;
3622 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3623 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3624 qpi.u.QPfileAllInfo.mode = 0;
3625 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3627 smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3628 qpi.u.QPfileAllInfo.fileNameLength = len;
3629 responseSize -= (sizeof(qpi.u.QPfileAllInfo.fileName) - len);
3631 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO) {
3633 /* For now we have no streams */
3634 qpi.u.QPfileStreamInfo.nextEntryOffset = 0;
3635 if (scp->fileType == CM_SCACHETYPE_FILE) {
3636 qpi.u.QPfileStreamInfo.streamSize = scp->length;
3637 qpi.u.QPfileStreamInfo.streamAllocationSize = scp->length;
3638 smb_UnparseString(opx, qpi.u.QPfileStreamInfo.fileName, L"::$DATA", &len, SMB_STRF_IGNORENUL);
3639 qpi.u.QPfileStreamInfo.streamNameLength = len;
3640 responseSize -= (sizeof(qpi.u.QPfileStreamInfo.fileName) - len);
3642 qpi.u.QPfileStreamInfo.streamSize.QuadPart = 0;
3643 qpi.u.QPfileStreamInfo.streamAllocationSize.QuadPart = 0;
3644 smb_UnparseString(opx, qpi.u.QPfileStreamInfo.fileName, L"", &len, SMB_STRF_IGNORENUL);
3645 qpi.u.QPfileStreamInfo.streamNameLength = 0;
3649 outp->totalData = responseSize;
3651 /* send and free the packets */
3653 switch (scp_rw_held) {
3655 lock_ReleaseRead(&scp->rw);
3658 lock_ReleaseWrite(&scp->rw);
3662 cm_ReleaseSCache(scp);
3663 cm_ReleaseUser(userp);
3665 memcpy(outp->datap, &qpi, responseSize);
3666 smb_SendTran2Packet(vcp, outp, opx);
3668 smb_SendTran2Error(vcp, p, opx, code);
3670 smb_FreeTran2Packet(outp);
3675 /* TRANS2_SET_PATH_INFORMATION */
3676 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3679 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
3680 return CM_ERROR_BADOP;
3683 unsigned short infoLevel;
3684 clientchar_t * pathp;
3685 smb_tran2Packet_t *outp;
3686 smb_tran2QPathInfo_t *spi;
3688 cm_scache_t *scp, *dscp;
3691 clientchar_t *tidPathp;
3692 clientchar_t *lastComp;
3696 infoLevel = p->parmsp[0];
3697 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
3698 if (infoLevel != SMB_INFO_STANDARD &&
3699 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
3700 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
3701 osi_Log2(smb_logp, "Bad Tran2SetPathInfo op 0x%x infolevel 0x%x",
3702 p->opcode, infoLevel);
3703 smb_SendTran2Error(vcp, p, opx,
3704 infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3708 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3710 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
3711 osi_LogSaveClientString(smb_logp, pathp));
3713 userp = smb_GetTran2User(vcp, p);
3715 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3716 code = CM_ERROR_BADSMB;
3720 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3721 if (code == CM_ERROR_TIDIPC) {
3722 /* Attempt to use a TID allocated for IPC. The client
3723 * is probably looking for DCE RPC end points which we
3724 * don't support OR it could be looking to make a DFS
3727 osi_Log0(smb_logp, "Tran2Open received IPC TID");
3728 cm_ReleaseUser(userp);
3729 return CM_ERROR_NOSUCHPATH;
3733 * XXX Strange hack XXX
3735 * As of Patch 7 (13 January 98), we are having the following problem:
3736 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3737 * requests to look up "desktop.ini" in all the subdirectories.
3738 * This can cause zillions of timeouts looking up non-existent cells
3739 * and volumes, especially in the top-level directory.
3741 * We have not found any way to avoid this or work around it except
3742 * to explicitly ignore the requests for mount points that haven't
3743 * yet been evaluated and for directories that haven't yet been
3746 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3747 spacep = cm_GetSpace();
3748 /* smb_StripLastComponent will strip "::$DATA" if present */
3749 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3750 #ifndef SPECIAL_FOLDERS
3751 /* Make sure that lastComp is not NULL */
3753 if (cm_ClientStrCmpI(lastComp, _C("\\desktop.ini")) == 0) {
3754 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
3758 userp, tidPathp, &req, &dscp);
3761 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3762 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3764 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3765 code = CM_ERROR_PATH_NOT_COVERED;
3767 code = CM_ERROR_NOSUCHPATH;
3769 #endif /* DFS_SUPPORT */
3770 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3771 code = CM_ERROR_NOSUCHFILE;
3772 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3773 cm_buf_t *bp = buf_Find(&dscp->fid, &hzero);
3779 code = CM_ERROR_NOSUCHFILE;
3781 cm_ReleaseSCache(dscp);
3783 cm_FreeSpace(spacep);
3784 cm_ReleaseUser(userp);
3785 smb_SendTran2Error(vcp, p, opx, code);
3791 #endif /* SPECIAL_FOLDERS */
3793 cm_FreeSpace(spacep);
3797 code == CM_ERROR_NOSUCHFILE ||
3798 code == CM_ERROR_NOSUCHPATH ||
3799 code == CM_ERROR_BPLUS_NOMATCH) {
3800 /* now do namei and stat, and copy out the info */
3801 code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
3802 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3806 cm_ReleaseUser(userp);
3807 smb_SendTran2Error(vcp, p, opx, code);
3811 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3813 outp->totalParms = 2;
3814 outp->totalData = 0;
3816 spi = (smb_tran2QPathInfo_t *)p->datap;
3817 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3820 /* lock the vnode with a callback; we need the current status
3821 * to determine what the new status is, in some cases.
3823 lock_ObtainWrite(&scp->rw);
3824 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3825 CM_SCACHESYNC_GETSTATUS
3826 | CM_SCACHESYNC_NEEDCALLBACK);
3828 lock_ReleaseWrite(&scp->rw);
3831 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3833 /* prepare for setattr call */
3834 attr.mask = CM_ATTRMASK_LENGTH;
3835 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3836 attr.length.HighPart = 0;
3838 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3839 cm_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3840 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3843 if (spi->u.QPstandardInfo.attributes != 0) {
3844 if ((scp->unixModeBits & 0200)
3845 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3846 /* make a writable file read-only */
3847 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3848 attr.unixModeBits = scp->unixModeBits & ~0222;
3850 else if ((scp->unixModeBits & 0200) == 0
3851 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3852 /* make a read-only file writable */
3853 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3854 attr.unixModeBits = scp->unixModeBits | 0222;
3857 lock_ReleaseRead(&scp->rw);
3861 code = cm_SetAttr(scp, &attr, userp, &req);
3865 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3866 /* we don't support EAs */
3867 code = CM_ERROR_EAS_NOT_SUPPORTED;
3871 cm_ReleaseSCache(scp);
3872 cm_ReleaseUser(userp);
3874 smb_SendTran2Packet(vcp, outp, opx);
3876 smb_SendTran2Error(vcp, p, opx, code);
3877 smb_FreeTran2Packet(outp);
3883 /* TRANS2_QUERY_FILE_INFORMATION */
3884 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3886 smb_tran2Packet_t *outp;
3888 unsigned long attributes;
3889 unsigned short infoLevel;
3896 smb_tran2QFileInfo_t qfi;
3904 fidp = smb_FindFID(vcp, fid, 0);
3907 osi_Log2(smb_logp, "Tran2QFileInfo Unknown SMB Fid vcp 0x%p fid %d",
3909 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3913 lock_ObtainMutex(&fidp->mx);
3914 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3915 lock_ReleaseMutex(&fidp->mx);
3916 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3917 smb_CloseFID(vcp, fidp, NULL, 0);
3918 smb_ReleaseFID(fidp);
3921 lock_ReleaseMutex(&fidp->mx);
3923 infoLevel = p->parmsp[1];
3924 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3925 responseSize = sizeof(qfi.u.QFbasicInfo);
3926 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3927 responseSize = sizeof(qfi.u.QFstandardInfo);
3928 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3929 responseSize = sizeof(qfi.u.QFeaInfo);
3930 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3931 responseSize = sizeof(qfi.u.QFfileNameInfo);
3932 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO)
3933 responseSize = sizeof(qfi.u.QFfileStreamInfo);
3935 osi_Log2(smb_logp, "Bad Tran2QFileInfo op 0x%x infolevel 0x%x",
3936 p->opcode, infoLevel);
3937 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3938 smb_ReleaseFID(fidp);
3941 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3942 memset(&qfi, 0, sizeof(qfi));
3944 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3946 if (infoLevel > 0x100)
3947 outp->totalParms = 2;
3949 outp->totalParms = 0;
3951 userp = smb_GetTran2User(vcp, p);
3953 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3954 code = CM_ERROR_BADSMB;
3958 lock_ObtainMutex(&fidp->mx);
3959 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3961 osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3963 lock_ReleaseMutex(&fidp->mx);
3964 lock_ObtainWrite(&scp->rw);
3965 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3966 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3970 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3972 lock_ConvertWToR(&scp->rw);
3975 /* now we have the status in the cache entry, and everything is locked.
3976 * Marshall the output data.
3978 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3979 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3980 qfi.u.QFbasicInfo.creationTime = ft;
3981 qfi.u.QFbasicInfo.lastAccessTime = ft;
3982 qfi.u.QFbasicInfo.lastWriteTime = ft;
3983 qfi.u.QFbasicInfo.lastChangeTime = ft;
3984 attributes = smb_ExtAttributes(scp);
3985 qfi.u.QFbasicInfo.attributes = attributes;
3987 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3988 qfi.u.QFstandardInfo.allocationSize = scp->length;
3989 qfi.u.QFstandardInfo.endOfFile = scp->length;
3990 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3991 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3992 qfi.u.QFstandardInfo.directory =
3993 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3994 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3995 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3997 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3998 qfi.u.QFeaInfo.eaSize = 0;
4000 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
4004 lock_ReleaseRead(&scp->rw);
4005 lock_ObtainMutex(&fidp->mx);
4006 lock_ObtainRead(&scp->rw);
4007 if (fidp->NTopen_wholepathp)
4008 name = fidp->NTopen_wholepathp;
4010 name = _C("\\"); /* probably can't happen */
4011 lock_ReleaseMutex(&fidp->mx);
4013 smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, SMB_STRF_IGNORENUL);
4014 responseSize = len + 4; /* this is actually what we want to return */
4015 qfi.u.QFfileNameInfo.fileNameLength = len;
4017 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO) {
4020 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
4021 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4022 scp->fileType == CM_SCACHETYPE_INVALID) {
4023 /* Do not return the alternate streams for directories */
4026 /* For now we have no alternate streams */
4027 qfi.u.QFfileStreamInfo.nextEntryOffset = 0;
4028 qfi.u.QFfileStreamInfo.streamSize = scp->length;
4029 qfi.u.QFfileStreamInfo.streamAllocationSize = scp->length;
4030 smb_UnparseString(opx, qfi.u.QFfileStreamInfo.fileName, L"::$DATA", &len, SMB_STRF_IGNORENUL);
4031 qfi.u.QFfileStreamInfo.streamNameLength = len;
4032 responseSize -= (sizeof(qfi.u.QFfileStreamInfo.fileName) - len);
4035 outp->totalData = responseSize;
4037 /* send and free the packets */
4040 lock_ReleaseRead(&scp->rw);
4042 lock_ReleaseWrite(&scp->rw);
4043 cm_ReleaseSCache(scp);
4044 cm_ReleaseUser(userp);
4045 smb_ReleaseFID(fidp);
4047 memcpy(outp->datap, &qfi, responseSize);
4048 smb_SendTran2Packet(vcp, outp, opx);
4050 smb_SendTran2Error(vcp, p, opx, code);
4052 smb_FreeTran2Packet(outp);
4058 /* TRANS2_SET_FILE_INFORMATION */
4059 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4064 unsigned short infoLevel;
4065 smb_tran2Packet_t *outp;
4066 cm_user_t *userp = NULL;
4067 cm_scache_t *scp = NULL;
4073 fidp = smb_FindFID(vcp, fid, 0);
4076 osi_Log2(smb_logp, "Tran2SetFileInfo Unknown SMB Fid vcp 0x%p fid %d",
4078 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
4082 infoLevel = p->parmsp[1];
4083 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
4084 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
4085 osi_Log2(smb_logp, "Bad Tran2SetFileInfo op 0x%x infolevel 0x%x",
4086 p->opcode, infoLevel);
4087 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
4088 smb_ReleaseFID(fidp);
4092 lock_ObtainMutex(&fidp->mx);
4093 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
4094 lock_ReleaseMutex(&fidp->mx);
4095 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
4096 smb_CloseFID(vcp, fidp, NULL, 0);
4097 smb_ReleaseFID(fidp);
4101 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
4102 !(fidp->flags & SMB_FID_OPENDELETE)) {
4103 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
4104 fidp, fidp->scp, fidp->flags);
4105 lock_ReleaseMutex(&fidp->mx);
4106 smb_ReleaseFID(fidp);
4107 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
4110 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
4111 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
4112 && !(fidp->flags & SMB_FID_OPENWRITE)) {
4113 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
4114 fidp, fidp->scp, fidp->flags);
4115 lock_ReleaseMutex(&fidp->mx);
4116 smb_ReleaseFID(fidp);
4117 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
4122 osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
4124 lock_ReleaseMutex(&fidp->mx);
4126 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
4128 outp->totalParms = 2;
4129 outp->totalData = 0;
4131 userp = smb_GetTran2User(vcp, p);
4133 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
4134 code = CM_ERROR_BADSMB;
4138 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
4140 unsigned int attribute;
4142 smb_tran2QFileInfo_t *sfi;
4144 sfi = (smb_tran2QFileInfo_t *)p->datap;
4146 /* lock the vnode with a callback; we need the current status
4147 * to determine what the new status is, in some cases.
4149 lock_ObtainWrite(&scp->rw);
4150 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4151 CM_SCACHESYNC_GETSTATUS
4152 | CM_SCACHESYNC_NEEDCALLBACK);
4154 lock_ReleaseWrite(&scp->rw);
4158 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4160 lock_ReleaseWrite(&scp->rw);
4161 lock_ObtainMutex(&fidp->mx);
4162 lock_ObtainRead(&scp->rw);
4164 /* prepare for setattr call */
4167 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
4168 /* when called as result of move a b, lastMod is (-1, -1).
4169 * If the check for -1 is not present, timestamp
4170 * of the resulting file will be 1969 (-1)
4172 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
4173 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
4174 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4175 cm_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
4176 fidp->flags |= SMB_FID_MTIMESETDONE;
4179 attribute = sfi->u.QFbasicInfo.attributes;
4180 if (attribute != 0) {
4181 if ((scp->unixModeBits & 0200)
4182 && (attribute & SMB_ATTR_READONLY) != 0) {
4183 /* make a writable file read-only */
4184 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4185 attr.unixModeBits = scp->unixModeBits & ~0222;
4187 else if ((scp->unixModeBits & 0200) == 0
4188 && (attribute & SMB_ATTR_READONLY) == 0) {
4189 /* make a read-only file writable */
4190 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4191 attr.unixModeBits = scp->unixModeBits | 0222;
4194 lock_ReleaseRead(&scp->rw);
4195 lock_ReleaseMutex(&fidp->mx);
4199 code = cm_SetAttr(scp, &attr, userp, &req);
4203 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
4204 int delflag = *((char *)(p->datap));
4205 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
4206 delflag, fidp, scp);
4207 if (*((char *)(p->datap))) { /* File is Deleted */
4208 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
4211 lock_ObtainMutex(&fidp->mx);
4212 fidp->flags |= SMB_FID_DELONCLOSE;
4213 lock_ReleaseMutex(&fidp->mx);
4215 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
4221 lock_ObtainMutex(&fidp->mx);
4222 fidp->flags &= ~SMB_FID_DELONCLOSE;
4223 lock_ReleaseMutex(&fidp->mx);
4226 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
4227 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
4228 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
4231 attr.mask = CM_ATTRMASK_LENGTH;
4232 attr.length.LowPart = size.LowPart;
4233 attr.length.HighPart = size.HighPart;
4234 code = cm_SetAttr(scp, &attr, userp, &req);
4238 cm_ReleaseSCache(scp);
4239 cm_ReleaseUser(userp);
4240 smb_ReleaseFID(fidp);
4242 smb_SendTran2Packet(vcp, outp, opx);
4244 smb_SendTran2Error(vcp, p, opx, code);
4245 smb_FreeTran2Packet(outp);
4252 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4254 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
4255 return CM_ERROR_BADOP;
4260 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4262 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
4263 return CM_ERROR_BADOP;
4266 /* TRANS2_FIND_NOTIFY_FIRST */
4268 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4270 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
4271 return CM_ERROR_BADOP;
4274 /* TRANS2_FIND_NOTIFY_NEXT */
4276 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4278 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
4279 return CM_ERROR_BADOP;
4282 /* TRANS2_CREATE_DIRECTORY */
4284 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4286 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
4287 return CM_ERROR_BADOP;
4290 /* TRANS2_SESSION_SETUP */
4292 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4294 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
4295 return CM_ERROR_BADOP;
4298 struct smb_v2_referral {
4300 USHORT ReferralFlags;
4303 USHORT DfsPathOffset;
4304 USHORT DfsAlternativePathOffset;
4305 USHORT NetworkAddressOffset;
4308 /* TRANS2_GET_DFS_REFERRAL */
4310 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
4312 /* This is a UNICODE only request (bit15 of Flags2) */
4313 /* The TID must be IPC$ */
4315 /* The documentation for the Flags response field is contradictory */
4317 /* Use Version 1 Referral Element Format */
4318 /* ServerType = 0; indicates the next server should be queried for the file */
4319 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
4320 /* Node = UnicodeString of UNC path of the next share name */
4323 int maxReferralLevel = 0;
4324 clientchar_t requestFileName[1024] = _C("");
4325 clientchar_t referralPath[1024] = _C("");
4326 smb_tran2Packet_t *outp = 0;
4327 cm_user_t *userp = 0;
4328 cm_scache_t *scp = 0;
4329 cm_scache_t *dscp = 0;
4331 CPINFO CodePageInfo;
4332 int i, nbnLen, reqLen, refLen;
4337 maxReferralLevel = p->parmsp[0];
4339 GetCPInfo(CP_ACP, &CodePageInfo);
4340 cm_Utf16ToClientString(&p->parmsp[1], -1, requestFileName, lengthof(requestFileName));
4342 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%S]",
4343 maxReferralLevel, osi_LogSaveClientString(smb_logp, requestFileName));
4345 nbnLen = (int)cm_ClientStrLen(cm_NetbiosNameC);
4346 reqLen = (int)cm_ClientStrLen(requestFileName);
4348 if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
4349 !cm_ClientStrCmpNI(cm_NetbiosNameC, &requestFileName[1], nbnLen) &&
4350 requestFileName[nbnLen+1] == '\\')
4354 if (!cm_ClientStrCmpNI(_C("all"), &requestFileName[nbnLen+2], 3) ||
4355 !cm_ClientStrCmpNI(_C("*."), &requestFileName[nbnLen+2], 2)) {
4357 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4360 userp = smb_GetTran2User(vcp, p);
4362 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
4363 code = CM_ERROR_BADSMB;
4368 * We have a requested path. Check to see if it is something
4371 * But be careful because the name that we might be searching
4372 * for might be a known name with the final character stripped
4375 code = cm_NameI(cm_RootSCachep(userp, &req), &requestFileName[nbnLen+2],
4376 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
4377 userp, NULL, &req, &scp);
4379 code == CM_ERROR_ALLDOWN ||
4380 code == CM_ERROR_ALLBUSY ||
4381 code == CM_ERROR_ALLOFFLINE ||
4382 code == CM_ERROR_NOSUCHCELL ||
4383 code == CM_ERROR_NOSUCHVOLUME ||
4384 code == CM_ERROR_NOACCESS) {
4387 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4389 } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
4390 clientchar_t temp[1024];
4391 clientchar_t pathName[1024];
4392 clientchar_t *lastComponent;
4394 * we have a msdfs link somewhere in the path
4395 * we should figure out where in the path the link is.
4398 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%S]", requestFileName);
4400 cm_ClientStrCpy(temp, lengthof(temp), &requestFileName[nbnLen+2]);
4404 cm_ReleaseSCache(dscp);
4408 cm_ReleaseSCache(scp);
4411 /* smb_StripLastComponent will strip "::$DATA" if present */
4412 smb_StripLastComponent(pathName, &lastComponent, temp);
4414 code = cm_NameI(cm_RootSCachep(userp, &req), pathName,
4415 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4416 userp, NULL, &req, &dscp);
4418 code = cm_NameI(dscp, ++lastComponent,
4420 userp, NULL, &req, &scp);
4421 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK)
4424 } while (code == CM_ERROR_PATH_NOT_COVERED);
4426 /* scp should now be the DfsLink we are looking for */
4428 /* figure out how much of the input path was used */
4429 reqLen = (int)(nbnLen+2 + cm_ClientStrLen(pathName) + 1 + cm_ClientStrLen(lastComponent));
4431 cm_FsStringToClientString(&scp->mountPointStringp[strlen("msdfs:")], -1,
4432 referralPath, lengthof(referralPath));
4433 refLen = (int)cm_ClientStrLen(referralPath);
4437 clientchar_t shareName[MAX_PATH + 1];
4438 clientchar_t *p, *q;
4439 /* we may have a sharename that is a volume reference */
4441 for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
4447 if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
4448 code = cm_NameI(cm_RootSCachep(userp, &req), _C(""),
4449 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
4450 userp, p, &req, &scp);
4455 cm_ClientStrCpy(referralPath, lengthof(referralPath),
4466 struct smb_v2_referral * v2ref;
4467 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (refLen + 8));
4469 sp = (USHORT *)outp->datap;
4471 sp[idx++] = reqLen; /* path consumed */
4472 sp[idx++] = 1; /* number of referrals */
4473 sp[idx++] = 0x03; /* flags */
4474 #ifdef DFS_VERSION_1
4475 sp[idx++] = 1; /* Version Number */
4476 sp[idx++] = refLen + 4; /* Referral Size */
4477 sp[idx++] = 1; /* Type = SMB Server */
4478 sp[idx++] = 0; /* Do not strip path consumed */
4479 for ( i=0;i<=refLen; i++ )
4480 sp[i+idx] = referralPath[i];
4481 #else /* DFS_VERSION_2 */
4482 sp[idx++] = 2; /* Version Number */
4483 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
4484 idx += (sizeof(struct smb_v2_referral) / 2);
4485 v2ref = (struct smb_v2_referral *) &sp[5];
4486 v2ref->ServerType = 1; /* SMB Server */
4487 v2ref->ReferralFlags = 0x03;
4488 v2ref->Proximity = 0; /* closest */
4489 v2ref->TimeToLive = 3600; /* seconds */
4490 v2ref->DfsPathOffset = idx * 2;
4491 v2ref->DfsAlternativePathOffset = idx * 2;
4492 v2ref->NetworkAddressOffset = 0;
4493 for ( i=0;i<=refLen; i++ )
4494 sp[i+idx] = referralPath[i];
4497 code = CM_ERROR_NOSUCHPATH;
4500 code = CM_ERROR_NOSUCHPATH;
4505 cm_ReleaseSCache(dscp);
4507 cm_ReleaseSCache(scp);
4509 cm_ReleaseUser(userp);
4511 smb_SendTran2Packet(vcp, outp, op);
4513 smb_SendTran2Error(vcp, p, op, code);
4515 smb_FreeTran2Packet(outp);
4518 #else /* DFS_SUPPORT */
4519 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
4520 return CM_ERROR_NOSUCHDEVICE;
4521 #endif /* DFS_SUPPORT */
4524 /* TRANS2_REPORT_DFS_INCONSISTENCY */
4526 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4528 /* This is a UNICODE only request (bit15 of Flags2) */
4530 /* There is nothing we can do about this operation. The client is going to
4531 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
4532 * Unfortunately, there is really nothing we can do about it other then log it
4533 * somewhere. Even then I don't think there is anything for us to do.
4534 * So let's return an error value.
4537 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
4538 return CM_ERROR_BADOP;
4542 smb_ApplyV3DirListPatches(cm_scache_t *dscp, smb_dirListPatch_t **dirPatchespp,
4543 clientchar_t * tidPathp, clientchar_t * relPathp,
4544 int infoLevel, cm_user_t *userp, cm_req_t *reqp)
4548 cm_scache_t *targetScp; /* target if scp is a symlink */
4551 unsigned short attr;
4552 unsigned long lattr;
4553 smb_dirListPatch_t *patchp;
4554 smb_dirListPatch_t *npatchp;
4556 afs_int32 mustFake = 0;
4557 clientchar_t path[AFSPATHMAX];
4559 lock_ObtainWrite(&dscp->rw);
4560 code = cm_FindACLCache(dscp, userp, &rights);
4562 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4563 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4565 cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4566 if (code == CM_ERROR_NOACCESS) {
4571 lock_ReleaseWrite(&dscp->rw);
4575 if (!mustFake) { /* Bulk Stat */
4577 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4579 memset(bsp, 0, sizeof(cm_bulkStat_t));
4581 for (patchp = *dirPatchespp, count=0;
4583 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4584 cm_scache_t *tscp = NULL;
4587 /* Do not look for a cm_scache_t or bulkstat an ioctl entry */
4588 if (patchp->flags & SMB_DIRLISTPATCH_IOCTL)
4591 code = cm_GetSCache(&patchp->fid, &dscp->fid, &tscp, userp, reqp);
4593 if (lock_TryWrite(&tscp->rw)) {
4594 /* we have an entry that we can look at */
4595 #ifdef AFS_FREELANCE_CLIENT
4596 if (dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID && dscp->fid.volume == AFS_FAKE_ROOT_VOL_ID) {
4597 code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
4598 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4600 cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4602 lock_ReleaseWrite(&tscp->rw);
4603 cm_ReleaseSCache(tscp);
4606 #endif /* AFS_FREELANCE_CLIENT */
4607 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4608 /* we have a callback on it. Don't bother
4609 * fetching this stat entry, since we're happy
4610 * with the info we have.
4612 lock_ReleaseWrite(&tscp->rw);
4613 cm_ReleaseSCache(tscp);
4616 lock_ReleaseWrite(&tscp->rw);
4618 cm_ReleaseSCache(tscp);
4622 bsp->fids[i].Volume = patchp->fid.volume;
4623 bsp->fids[i].Vnode = patchp->fid.vnode;
4624 bsp->fids[i].Unique = patchp->fid.unique;
4626 if (bsp->counter == AFSCBMAX) {
4627 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4628 memset(bsp, 0, sizeof(cm_bulkStat_t));
4632 if (bsp->counter > 0)
4633 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4638 for( patchp = *dirPatchespp;
4640 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4641 cm_ClientStrPrintfN(path, lengthof(path),_C("%s\\%S"),
4642 relPathp ? relPathp : _C(""), patchp->dep->name);
4643 reqp->relPathp = path;
4644 reqp->tidPathp = tidPathp;
4646 if (patchp->flags & SMB_DIRLISTPATCH_IOCTL) {
4647 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4648 errors in the client. */
4649 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4650 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4652 /* 1969-12-31 23:59:59 +00 */
4653 ft.dwHighDateTime = 0x19DB200;
4654 ft.dwLowDateTime = 0x5BB78980;
4656 /* copy to Creation Time */
4657 fa->creationTime = ft;
4658 fa->lastAccessTime = ft;
4659 fa->lastWriteTime = ft;
4660 fa->lastChangeTime = ft;
4661 fa->extFileAttributes = SMB_ATTR_SYSTEM | SMB_ATTR_HIDDEN;
4663 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4665 /* 1969-12-31 23:59:58 +00*/
4666 dosTime = 0xEBBFBF7D;
4668 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4669 fa->lastAccessDateTime = fa->creationDateTime;
4670 fa->lastWriteDateTime = fa->creationDateTime;
4671 fa->attributes = SMB_ATTR_SYSTEM|SMB_ATTR_HIDDEN;
4676 code = cm_GetSCache(&patchp->fid, &dscp->fid, &scp, userp, reqp);
4677 reqp->relPathp = reqp->tidPathp = NULL;
4681 lock_ObtainWrite(&scp->rw);
4682 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4683 lock_ReleaseWrite(&scp->rw);
4685 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4686 errors in the client. */
4687 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4688 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4690 /* 1969-12-31 23:59:59 +00 */
4691 ft.dwHighDateTime = 0x19DB200;
4692 ft.dwLowDateTime = 0x5BB78980;
4694 /* copy to Creation Time */
4695 fa->creationTime = ft;
4696 fa->lastAccessTime = ft;
4697 fa->lastWriteTime = ft;
4698 fa->lastChangeTime = ft;
4700 switch (scp->fileType) {
4701 case CM_SCACHETYPE_DIRECTORY:
4702 case CM_SCACHETYPE_MOUNTPOINT:
4703 case CM_SCACHETYPE_INVALID:
4704 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4706 case CM_SCACHETYPE_SYMLINK:
4707 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4708 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4710 fa->extFileAttributes = SMB_ATTR_NORMAL;
4713 /* if we get here we either have a normal file
4714 * or we have a file for which we have never
4715 * received status info. In this case, we can
4716 * check the even/odd value of the entry's vnode.
4717 * odd means it is to be treated as a directory
4718 * and even means it is to be treated as a file.
4720 if (mustFake && (scp->fid.vnode & 0x1))
4721 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4723 fa->extFileAttributes = SMB_ATTR_NORMAL;
4725 /* merge in hidden attribute */
4726 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4727 fa->extFileAttributes |= SMB_ATTR_HIDDEN;
4730 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4732 /* 1969-12-31 23:59:58 +00*/
4733 dosTime = 0xEBBFBF7D;
4735 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4736 fa->lastAccessDateTime = fa->creationDateTime;
4737 fa->lastWriteDateTime = fa->creationDateTime;
4739 /* set the attribute */
4740 switch (scp->fileType) {
4741 case CM_SCACHETYPE_DIRECTORY:
4742 case CM_SCACHETYPE_MOUNTPOINT:
4743 case CM_SCACHETYPE_INVALID:
4744 fa->attributes = SMB_ATTR_DIRECTORY;
4746 case CM_SCACHETYPE_SYMLINK:
4747 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4748 fa->attributes = SMB_ATTR_DIRECTORY;
4750 fa->attributes = SMB_ATTR_NORMAL;
4753 /* if we get here we either have a normal file
4754 * or we have a file for which we have never
4755 * received status info. In this case, we can
4756 * check the even/odd value of the entry's vnode.
4757 * even means it is to be treated as a directory
4758 * and odd means it is to be treated as a file.
4760 if (mustFake && (scp->fid.vnode & 0x1))
4761 fa->attributes = SMB_ATTR_DIRECTORY;
4763 fa->attributes = SMB_ATTR_NORMAL;
4766 /* merge in hidden (dot file) attribute */
4767 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4768 fa->attributes |= SMB_ATTR_HIDDEN;
4772 cm_ReleaseSCache(scp);
4776 /* now watch for a symlink */
4778 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
4779 lock_ReleaseWrite(&scp->rw);
4780 cm_ClientStrPrintfN(path, lengthof(path), _C("%s\\%S"),
4781 relPathp ? relPathp : _C(""), patchp->dep->name);
4782 reqp->relPathp = path;
4783 reqp->tidPathp = tidPathp;
4784 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
4785 reqp->relPathp = reqp->tidPathp = NULL;
4787 /* we have a more accurate file to use (the
4788 * target of the symbolic link). Otherwise,
4789 * we'll just use the symlink anyway.
4791 osi_Log2(smb_logp, "symlink vp %x to vp %x",
4793 cm_ReleaseSCache(scp);
4796 lock_ObtainWrite(&scp->rw);
4799 lock_ConvertWToR(&scp->rw);
4801 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4802 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4805 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4807 fa->creationTime = ft;
4808 fa->lastAccessTime = ft;
4809 fa->lastWriteTime = ft;
4810 fa->lastChangeTime = ft;
4812 /* Use length for both file length and alloc length */
4813 fa->endOfFile = scp->length;
4814 fa->allocationSize = scp->length;
4816 /* Copy attributes */
4817 lattr = smb_ExtAttributes(scp);
4818 if ((code == CM_ERROR_NOSUCHPATH &&
4819 (scp->fileType == CM_SCACHETYPE_SYMLINK &&
4820 cm_TargetPerceivedAsDirectory(scp->mountPointStringp))) ||
4821 code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4822 if (lattr == SMB_ATTR_NORMAL)
4823 lattr = SMB_ATTR_DIRECTORY;
4825 lattr |= SMB_ATTR_DIRECTORY;
4827 /* merge in hidden (dot file) attribute */
4828 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4829 if (lattr == SMB_ATTR_NORMAL)
4830 lattr = SMB_ATTR_HIDDEN;
4832 lattr |= SMB_ATTR_HIDDEN;
4835 fa->extFileAttributes = lattr;
4837 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4840 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4842 fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
4843 fa->lastAccessDateTime = fa->creationDateTime;
4844 fa->lastWriteDateTime = fa->creationDateTime;
4846 /* copy out file length and alloc length,
4847 * using the same for both
4849 fa->dataSize = scp->length.LowPart;
4850 fa->allocationSize = scp->length.LowPart;
4852 /* finally copy out attributes as short */
4853 attr = smb_Attributes(scp);
4854 /* merge in hidden (dot file) attribute */
4855 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4856 if (lattr == SMB_ATTR_NORMAL)
4857 lattr = SMB_ATTR_HIDDEN;
4859 lattr |= SMB_ATTR_HIDDEN;
4861 fa->attributes = attr;
4864 lock_ReleaseRead(&scp->rw);
4865 cm_ReleaseSCache(scp);
4868 /* now free the patches */
4869 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4870 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4874 /* and mark the list as empty */
4875 *dirPatchespp = NULL;
4881 /* smb_ReceiveTran2SearchDir implements both
4882 * Tran2_Find_First and Tran2_Find_Next
4884 #define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
4885 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
4886 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
4887 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
4888 #define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
4890 /* this is an optimized handler for T2SearchDir that handles the case
4891 where there are no wildcards in the search path. I.e. an
4892 application is using FindFirst(Ex) to get information about a
4893 single file or directory. It will attempt to do a single lookup.
4894 If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4895 the usual mechanism.
4897 This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4899 TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
4901 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4905 long code = 0, code2 = 0;
4906 clientchar_t *pathp = 0;
4908 smb_dirListPatch_t *dirListPatchesp;
4909 smb_dirListPatch_t *curPatchp;
4910 size_t orbytes; /* # of bytes in this output record */
4911 size_t ohbytes; /* # of bytes, except file name */
4912 size_t onbytes; /* # of bytes in name, incl. term. null */
4913 cm_scache_t *scp = NULL;
4914 cm_scache_t *targetScp = NULL;
4915 cm_user_t *userp = NULL;
4916 char *op; /* output data ptr */
4917 char *origOp; /* original value of op */
4918 cm_space_t *spacep; /* for pathname buffer */
4919 unsigned long maxReturnData; /* max # of return data */
4920 long maxReturnParms; /* max # of return parms */
4921 long bytesInBuffer; /* # data bytes in the output buffer */
4922 clientchar_t *maskp; /* mask part of path */
4926 smb_tran2Packet_t *outp; /* response packet */
4927 clientchar_t *tidPathp = 0;
4929 clientchar_t shortName[13]; /* 8.3 name if needed */
4931 clientchar_t *shortNameEnd;
4932 cm_dirEntry_t * dep = NULL;
4935 void * attrp = NULL;
4936 smb_tran2Find_t * fp;
4937 int afs_ioctl = 0; /* is this query for _._AFS_IOCTL_._? */
4943 osi_assertx(p->opcode == 1, "invalid opcode");
4945 /* find first; obtain basic parameters from request */
4947 /* note that since we are going to failover to regular
4948 * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4949 * modify any of the input parameters here. */
4950 attribute = p->parmsp[0];
4951 maxCount = p->parmsp[1];
4952 infoLevel = p->parmsp[3];
4953 searchFlags = p->parmsp[2];
4954 pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4956 maskp = cm_ClientStrRChr(pathp, '\\');
4960 maskp++; /* skip over backslash */
4961 /* track if this is likely to match a lot of entries */
4963 osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%S], mask[%S]",
4964 osi_LogSaveClientString(smb_logp, pathp),
4965 osi_LogSaveClientString(smb_logp, maskp));
4967 switch ( infoLevel ) {
4968 case SMB_INFO_STANDARD:
4970 ohbytes = sizeof(fp->u.FstandardInfo);
4973 case SMB_INFO_QUERY_EA_SIZE:
4974 ohbytes = sizeof(fp->u.FeaSizeInfo);
4975 s = "InfoQueryEaSize";
4978 case SMB_INFO_QUERY_EAS_FROM_LIST:
4979 ohbytes = sizeof(fp->u.FeasFromListInfo);
4980 s = "InfoQueryEasFromList";
4983 case SMB_FIND_FILE_DIRECTORY_INFO:
4984 s = "FindFileDirectoryInfo";
4985 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4988 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4989 s = "FindFileFullDirectoryInfo";
4990 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4993 case SMB_FIND_FILE_NAMES_INFO:
4994 s = "FindFileNamesInfo";
4995 ohbytes = sizeof(fp->u.FfileNamesInfo);
4998 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4999 s = "FindFileBothDirectoryInfo";
5000 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
5004 s = "unknownInfoLevel";
5008 osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
5011 "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
5012 attribute, infoLevel, maxCount, searchFlags);
5015 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
5016 return CM_ERROR_INVAL;
5019 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5020 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
5022 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5025 dirListPatchesp = NULL;
5027 maxReturnData = p->maxReturnData;
5028 maxReturnParms = 10; /* return params for findfirst, which
5029 is the only one we handle.*/
5031 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
5034 osi_Log2(smb_logp, "T2SDSingle search dir count %d [%S]",
5035 maxCount, osi_LogSaveClientString(smb_logp, pathp));
5037 /* bail out if request looks bad */
5039 smb_FreeTran2Packet(outp);
5040 return CM_ERROR_BADSMB;
5043 userp = smb_GetTran2User(vcp, p);
5045 osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
5046 smb_FreeTran2Packet(outp);
5047 return CM_ERROR_BADSMB;
5050 /* try to get the vnode for the path name next */
5051 spacep = cm_GetSpace();
5052 /* smb_StripLastComponent will strip "::$DATA" if present */
5053 smb_StripLastComponent(spacep->wdata, NULL, pathp);
5054 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
5056 cm_ReleaseUser(userp);
5057 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
5058 smb_FreeTran2Packet(outp);
5062 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
5063 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5064 userp, tidPathp, &req, &scp);
5065 cm_FreeSpace(spacep);
5068 cm_ReleaseUser(userp);
5069 smb_SendTran2Error(vcp, p, opx, code);
5070 smb_FreeTran2Packet(outp);
5074 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
5075 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5076 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
5077 cm_ReleaseSCache(scp);
5078 cm_ReleaseUser(userp);
5079 if ( WANTS_DFS_PATHNAMES(p) || pnc )
5080 code = CM_ERROR_PATH_NOT_COVERED;
5082 code = CM_ERROR_NOSUCHPATH;
5083 smb_SendTran2Error(vcp, p, opx, code);
5084 smb_FreeTran2Packet(outp);
5087 #endif /* DFS_SUPPORT */
5088 osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
5090 afs_ioctl = (cm_ClientStrCmpI(maskp, CM_IOCTL_FILENAME_NOSLASH_W) == 0);
5093 * If we are not searching for _._AFS_IOCTL_._, then we need to obtain
5097 /* now do a single case sensitive lookup for the file in question */
5098 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetScp);
5101 * if a case sensitive match failed, we try a case insensitive
5104 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH)
5105 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetScp);
5107 if (code == 0 && targetScp->fid.vnode == 0) {
5108 cm_ReleaseSCache(targetScp);
5109 code = CM_ERROR_NOSUCHFILE;
5114 * if we can't find the directory entry, this block will
5115 * return CM_ERROR_NOSUCHFILE, which we will pass on to
5116 * smb_ReceiveTran2SearchDir().
5118 cm_ReleaseSCache(scp);
5119 cm_ReleaseUser(userp);
5120 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5121 smb_SendTran2Error(vcp, p, opx, code);
5124 smb_FreeTran2Packet(outp);
5129 /* now that we have the target in sight, we proceed with filling
5130 up the return data. */
5132 op = origOp = outp->datap;
5135 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
5136 /* skip over resume key */
5140 fp = (smb_tran2Find_t *) op;
5142 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
5143 && !cm_Is8Dot3(maskp)) {
5146 * Since the _._AFS_IOCTL_._ file does not actually exist
5147 * we will make up a per directory FID equivalent to the
5148 * directory vnode and the uniqifier 0.
5151 dfid.vnode = htonl(scp->fid.vnode);
5152 dfid.unique = htonl(0);
5154 dfid.vnode = htonl(targetScp->fid.vnode);
5155 dfid.unique = htonl(targetScp->fid.unique);
5158 cm_Gen8Dot3NameIntW(maskp, &dfid, shortName, &shortNameEnd);
5164 osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %S (%S)",
5167 osi_LogSaveClientString(smb_logp, pathp),
5168 (NeedShortName)? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
5170 /* Eliminate entries that don't match requested attributes */
5171 if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
5172 smb_IsDotFile(maskp)) {
5174 code = CM_ERROR_NOSUCHFILE;
5175 osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
5180 if (!(attribute & SMB_ATTR_DIRECTORY) &&
5182 (targetScp->fileType == CM_SCACHETYPE_DIRECTORY ||
5183 targetScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
5184 targetScp->fileType == CM_SCACHETYPE_DFSLINK ||
5185 targetScp->fileType == CM_SCACHETYPE_INVALID)) {
5187 code = CM_ERROR_NOSUCHFILE;
5188 osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
5193 /* add header to name & term. null */
5195 smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5196 orbytes = ohbytes + onbytes;
5198 /* now, we round up the record to a 4 byte alignment, and we make
5199 * sure that we have enough room here for even the aligned version
5200 * (so we don't have to worry about an * overflow when we pad
5201 * things out below). That's the reason for the alignment
5204 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5205 align = (4 - (orbytes & 3)) & 3;
5209 if (orbytes + align > maxReturnData) {
5211 /* even though this request is unlikely to succeed with a
5212 failover, we do it anyway. */
5213 code = CM_ERROR_NOSUCHFILE;
5214 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5219 /* this is one of the entries to use: it is not deleted and it
5220 * matches the star pattern we're looking for. Put out the name,
5221 * preceded by its length.
5223 /* First zero everything else */
5224 memset(origOp, 0, orbytes);
5227 smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5229 switch (infoLevel) {
5230 case SMB_INFO_STANDARD:
5231 fp->u.FstandardInfo.fileNameLength = onbytes;
5232 attrp = &fp->u.FstandardInfo.fileAttrs;
5235 case SMB_INFO_QUERY_EA_SIZE:
5236 fp->u.FeaSizeInfo.fileNameLength = onbytes;
5237 attrp = &fp->u.FeaSizeInfo.fileAttrs;
5238 fp->u.FeaSizeInfo.eaSize = 0;
5241 case SMB_INFO_QUERY_EAS_FROM_LIST:
5242 fp->u.FeasFromListInfo.fileNameLength = onbytes;
5243 attrp = &fp->u.FeasFromListInfo.fileAttrs;
5244 fp->u.FeasFromListInfo.eaSize = 0;
5247 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5248 if (NeedShortName) {
5252 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
5253 fp->u.FfileBothDirectoryInfo.shortName,
5254 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
5256 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
5258 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5259 fp->u.FfileBothDirectoryInfo.reserved = 0;
5261 strcpy(fp->u.FfileBothDirectoryInfo.shortName,
5263 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
5268 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5269 fp->u.FfileFullDirectoryInfo.eaSize = 0;
5272 case SMB_FIND_FILE_DIRECTORY_INFO:
5273 fp->u.FfileDirectoryInfo.nextEntryOffset = 0;
5274 fp->u.FfileDirectoryInfo.fileIndex = 0;
5275 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5276 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5279 case SMB_FIND_FILE_NAMES_INFO:
5280 fp->u.FfileNamesInfo.nextEntryOffset = 0;
5281 fp->u.FfileNamesInfo.fileIndex = 0;
5282 fp->u.FfileNamesInfo.fileNameLength = onbytes;
5286 /* we shouldn't hit this case */
5287 osi_assertx(FALSE, "Unknown query type");
5290 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5291 osi_assert(attrp != NULL);
5293 curPatchp = malloc(sizeof(*curPatchp));
5294 osi_QAdd((osi_queue_t **) &dirListPatchesp,
5296 curPatchp->dptr = attrp;
5298 if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
5299 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5301 curPatchp->flags = 0;
5306 int namelen = cm_ClientStringToFsString(maskp, -1, NULL, 0);
5307 dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+namelen);
5308 cm_ClientStringToFsString(maskp, -1, dep->name, namelen);
5312 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, scp->fid.vnode, 0);
5313 dep->fid.vnode = scp->fid.vnode;
5314 dep->fid.unique = 0;
5315 curPatchp->flags |= SMB_DIRLISTPATCH_IOCTL;
5317 cm_SetFid(&curPatchp->fid, targetScp->fid.cell, targetScp->fid.volume, targetScp->fid.vnode, targetScp->fid.unique);
5318 dep->fid.vnode = targetScp->fid.vnode;
5319 dep->fid.unique = targetScp->fid.unique;
5322 curPatchp->dep = dep;
5325 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
5326 /* put out resume key */
5327 *((u_long *)origOp) = 0;
5330 /* Adjust byte ptr and count */
5331 origOp += orbytes; /* skip entire record */
5332 bytesInBuffer += orbytes;
5334 /* and pad the record out */
5335 while (--align >= 0) {
5340 /* apply the patches */
5341 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->wdata, infoLevel, userp, &req);
5343 outp->parmsp[0] = 0;
5344 outp->parmsp[1] = 1; /* number of names returned */
5345 outp->parmsp[2] = 1; /* end of search */
5346 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5347 outp->parmsp[4] = 0;
5349 outp->totalParms = 10; /* in bytes */
5351 outp->totalData = bytesInBuffer;
5353 osi_Log0(smb_logp, "T2SDSingle done.");
5355 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5357 smb_SendTran2Error(vcp, p, opx, code);
5359 smb_SendTran2Packet(vcp, outp, opx);
5364 smb_FreeTran2Packet(outp);
5368 cm_ReleaseSCache(scp);
5370 cm_ReleaseSCache(targetScp);
5371 cm_ReleaseUser(userp);
5377 /* TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2 */
5378 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
5383 long code = 0, code2 = 0;
5384 clientchar_t *pathp;
5385 cm_dirEntry_t *dep = 0;
5387 smb_dirListPatch_t *dirListPatchesp = 0;
5388 smb_dirListPatch_t *curPatchp = 0;
5391 size_t orbytes; /* # of bytes in this output record */
5392 size_t ohbytes; /* # of bytes, except file name */
5393 size_t onbytes; /* # of bytes in name, incl. term. null */
5394 osi_hyper_t dirLength;
5395 osi_hyper_t bufferOffset;
5396 osi_hyper_t curOffset;
5398 smb_dirSearch_t *dsp;
5402 cm_pageHeader_t *pageHeaderp;
5403 cm_user_t *userp = NULL;
5406 long nextEntryCookie;
5407 int numDirChunks; /* # of 32 byte dir chunks in this entry */
5408 char *op; /* output data ptr */
5409 char *origOp; /* original value of op */
5410 cm_space_t *spacep; /* for pathname buffer */
5411 unsigned long maxReturnData; /* max # of return data */
5412 unsigned long maxReturnParms; /* max # of return parms */
5413 long bytesInBuffer; /* # data bytes in the output buffer */
5415 clientchar_t *maskp; /* mask part of path */
5419 smb_tran2Packet_t *outp; /* response packet */
5420 clientchar_t *tidPathp;
5422 clientchar_t shortName[13]; /* 8.3 name if needed */
5425 clientchar_t *shortNameEnd;
5431 smb_tran2Find_t * fp;
5436 if (p->opcode == 1) {
5437 /* find first; obtain basic parameters from request */
5438 attribute = p->parmsp[0];
5439 maxCount = p->parmsp[1];
5440 infoLevel = p->parmsp[3];
5441 searchFlags = p->parmsp[2];
5442 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
5444 maskp = cm_ClientStrRChr(pathp, '\\');
5448 maskp++; /* skip over backslash */
5450 /* track if this is likely to match a lot of entries */
5451 starPattern = smb_V3IsStarMask(maskp);
5453 #ifndef NOFINDFIRSTOPTIMIZE
5455 /* if this is for a single directory or file, we let the
5456 optimized routine handle it. The only error it
5457 returns is CM_ERROR_NOSUCHFILE. The */
5458 code = smb_T2SearchDirSingle(vcp, p, opx);
5460 /* we only failover if we see a CM_ERROR_NOSUCHFILE */
5461 if (code != CM_ERROR_NOSUCHFILE) {
5463 /* unless we are using the BPlusTree */
5464 if (code == CM_ERROR_BPLUS_NOMATCH)
5465 code = CM_ERROR_NOSUCHFILE;
5466 #endif /* USE_BPLUS */
5470 #endif /* NOFINDFIRSTOPTIMIZE */
5473 dsp = smb_NewDirSearch(1);
5474 dsp->attribute = attribute;
5475 cm_ClientStrCpy(dsp->mask, lengthof(dsp->mask), maskp); /* and save mask */
5478 osi_assertx(p->opcode == 2, "invalid opcode");
5479 /* find next; obtain basic parameters from request or open dir file */
5480 dsp = smb_FindDirSearch(p->parmsp[0]);
5481 maxCount = p->parmsp[1];
5482 infoLevel = p->parmsp[2];
5483 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
5484 searchFlags = p->parmsp[5];
5486 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
5487 p->parmsp[0], nextCookie);
5488 return CM_ERROR_BADFD;
5490 attribute = dsp->attribute;
5493 starPattern = 1; /* assume, since required a Find Next */
5496 switch ( infoLevel ) {
5497 case SMB_INFO_STANDARD:
5499 ohbytes = sizeof(fp->u.FstandardInfo);
5502 case SMB_INFO_QUERY_EA_SIZE:
5503 ohbytes = sizeof(fp->u.FeaSizeInfo);
5504 s = "InfoQueryEaSize";
5507 case SMB_INFO_QUERY_EAS_FROM_LIST:
5508 ohbytes = sizeof(fp->u.FeasFromListInfo);
5509 s = "InfoQueryEasFromList";
5512 case SMB_FIND_FILE_DIRECTORY_INFO:
5513 s = "FindFileDirectoryInfo";
5514 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
5517 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5518 s = "FindFileFullDirectoryInfo";
5519 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
5522 case SMB_FIND_FILE_NAMES_INFO:
5523 s = "FindFileNamesInfo";
5524 ohbytes = sizeof(fp->u.FfileNamesInfo);
5527 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5528 s = "FindFileBothDirectoryInfo";
5529 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
5533 s = "unknownInfoLevel";
5537 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
5540 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
5541 attribute, infoLevel, maxCount, searchFlags);
5543 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
5544 p->opcode, dsp->cookie, nextCookie);
5547 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
5548 smb_ReleaseDirSearch(dsp);
5549 return CM_ERROR_INVAL;
5552 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5553 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
5555 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5558 dirListPatchesp = NULL;
5560 maxReturnData = p->maxReturnData;
5561 if (p->opcode == 1) /* find first */
5562 maxReturnParms = 10; /* bytes */
5564 maxReturnParms = 8; /* bytes */
5566 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
5572 osi_Log2(smb_logp, "T2 receive search dir count %d [%S]",
5573 maxCount, osi_LogSaveClientString(smb_logp, pathp));
5575 /* bail out if request looks bad */
5576 if (p->opcode == 1 && !pathp) {
5577 smb_ReleaseDirSearch(dsp);
5578 smb_FreeTran2Packet(outp);
5579 return CM_ERROR_BADSMB;
5582 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
5583 dsp->cookie, nextCookie, attribute);
5585 userp = smb_GetTran2User(vcp, p);
5587 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
5588 smb_ReleaseDirSearch(dsp);
5589 smb_FreeTran2Packet(outp);
5590 return CM_ERROR_BADSMB;
5593 /* try to get the vnode for the path name next */
5594 lock_ObtainMutex(&dsp->mx);
5597 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5601 spacep = cm_GetSpace();
5602 /* smb_StripLastComponent will strip "::$DATA" if present */
5603 smb_StripLastComponent(spacep->wdata, NULL, pathp);
5604 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
5606 cm_ReleaseUser(userp);
5607 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
5608 smb_FreeTran2Packet(outp);
5609 lock_ReleaseMutex(&dsp->mx);
5610 smb_DeleteDirSearch(dsp);
5611 smb_ReleaseDirSearch(dsp);
5615 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
5616 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
5618 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
5619 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5620 userp, tidPathp, &req, &scp);
5621 cm_FreeSpace(spacep);
5624 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
5625 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5626 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
5627 cm_ReleaseSCache(scp);
5628 cm_ReleaseUser(userp);
5629 if ( WANTS_DFS_PATHNAMES(p) || pnc )
5630 code = CM_ERROR_PATH_NOT_COVERED;
5632 code = CM_ERROR_NOSUCHPATH;
5633 smb_SendTran2Error(vcp, p, opx, code);
5634 smb_FreeTran2Packet(outp);
5635 lock_ReleaseMutex(&dsp->mx);
5636 smb_DeleteDirSearch(dsp);
5637 smb_ReleaseDirSearch(dsp);
5640 #endif /* DFS_SUPPORT */
5642 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5643 /* we need one hold for the entry we just stored into,
5644 * and one for our own processing. When we're done
5645 * with this function, we'll drop the one for our own
5646 * processing. We held it once from the namei call,
5647 * and so we do another hold now.
5650 dsp->flags |= SMB_DIRSEARCH_BULKST;
5653 lock_ReleaseMutex(&dsp->mx);
5655 cm_ReleaseUser(userp);
5656 smb_FreeTran2Packet(outp);
5657 smb_DeleteDirSearch(dsp);
5658 smb_ReleaseDirSearch(dsp);
5662 /* get the directory size */
5663 lock_ObtainWrite(&scp->rw);
5664 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5665 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5667 lock_ReleaseWrite(&scp->rw);
5668 cm_ReleaseSCache(scp);
5669 cm_ReleaseUser(userp);
5670 smb_FreeTran2Packet(outp);
5671 smb_DeleteDirSearch(dsp);
5672 smb_ReleaseDirSearch(dsp);
5676 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5679 dirLength = scp->length;
5681 bufferOffset.LowPart = bufferOffset.HighPart = 0;
5682 curOffset.HighPart = 0;
5683 curOffset.LowPart = nextCookie;
5684 origOp = outp->datap;
5691 normchar_t normName[MAX_PATH]; /* Normalized name */
5692 clientchar_t cfileName[MAX_PATH]; /* Non-normalized name */
5695 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5696 /* skip over resume key */
5699 fp = (smb_tran2Find_t *) op;
5701 /* make sure that curOffset.LowPart doesn't point to the first
5702 * 32 bytes in the 2nd through last dir page, and that it doesn't
5703 * point at the first 13 32-byte chunks in the first dir page,
5704 * since those are dir and page headers, and don't contain useful
5707 temp = curOffset.LowPart & (2048-1);
5708 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5709 /* we're in the first page */
5710 if (temp < 13*32) temp = 13*32;
5713 /* we're in a later dir page */
5714 if (temp < 32) temp = 32;
5717 /* make sure the low order 5 bits are zero */
5720 /* now put temp bits back ito curOffset.LowPart */
5721 curOffset.LowPart &= ~(2048-1);
5722 curOffset.LowPart |= temp;
5724 /* check if we've passed the dir's EOF */
5725 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
5726 osi_Log0(smb_logp, "T2 search dir passed eof");
5731 /* check if we've returned all the names that will fit in the
5732 * response packet; we check return count as well as the number
5733 * of bytes requested. We check the # of bytes after we find
5734 * the dir entry, since we'll need to check its size.
5736 if (returnedNames >= maxCount) {
5737 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
5738 returnedNames, maxCount);
5742 /* when we have obtained as many entries as can be processed in
5743 * a single Bulk Status call to the file server, apply the dir listing
5746 if (returnedNames > 0 && returnedNames % AFSCBMAX == 0) {
5747 lock_ReleaseWrite(&scp->rw);
5748 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5749 dsp->relPath, infoLevel, userp, &req);
5750 lock_ObtainWrite(&scp->rw);
5752 /* Then check to see if we have time left to process more entries */
5753 if (GetTickCount() - req.startTime > (RDRtimeout - 15) * 1000) {
5754 osi_Log0(smb_logp, "T2 search dir RDRtimeout exceeded");
5758 /* see if we can use the bufferp we have now; compute in which
5759 * page the current offset would be, and check whether that's
5760 * the offset of the buffer we have. If not, get the buffer.
5762 thyper.HighPart = curOffset.HighPart;
5763 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5764 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5767 buf_Release(bufferp);
5770 lock_ReleaseWrite(&scp->rw);
5771 code = buf_Get(scp, &thyper, &req, &bufferp);
5772 lock_ObtainWrite(&scp->rw);
5774 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
5778 bufferOffset = thyper;
5780 /* now get the data in the cache */
5782 code = cm_SyncOp(scp, bufferp, userp, &req,
5784 CM_SCACHESYNC_NEEDCALLBACK
5785 | CM_SCACHESYNC_READ);
5787 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5791 if (cm_HaveBuffer(scp, bufferp, 0)) {
5792 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5793 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5797 /* otherwise, load the buffer and try again */
5798 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5800 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5802 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5803 scp, bufferp, code);
5808 buf_Release(bufferp);
5812 } /* if (wrong buffer) ... */
5814 /* now we have the buffer containing the entry we're interested
5815 * in; copy it out if it represents a non-deleted entry.
5817 entryInDir = curOffset.LowPart & (2048-1);
5818 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5820 /* page header will help tell us which entries are free. Page
5821 * header can change more often than once per buffer, since
5822 * AFS 3 dir page size may be less than (but not more than)
5823 * a buffer package buffer.
5825 /* only look intra-buffer */
5826 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5827 temp &= ~(2048 - 1); /* turn off intra-page bits */
5828 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5830 /* now determine which entry we're looking at in the page.
5831 * If it is free (there's a free bitmap at the start of the
5832 * dir), we should skip these 32 bytes.
5834 slotInPage = (entryInDir & 0x7e0) >> 5;
5835 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5836 (1 << (slotInPage & 0x7)))) {
5837 /* this entry is free */
5838 numDirChunks = 1; /* only skip this guy */
5842 tp = bufferp->datap + entryInBuffer;
5843 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5845 /* while we're here, compute the next entry's location, too,
5846 * since we'll need it when writing out the cookie into the dir
5849 * XXXX Probably should do more sanity checking.
5851 numDirChunks = cm_NameEntries(dep->name, &onbytes);
5853 /* compute offset of cookie representing next entry */
5854 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5856 if (dep->fid.vnode == 0)
5857 goto nextEntry; /* This entry is not in use */
5859 if (cm_FsStringToClientString(dep->name, -1, cfileName, lengthof(cfileName)) == 0 ||
5860 cm_ClientStringToNormString(cfileName, -1, normName, lengthof(normName)) == 0) {
5862 osi_Log1(smb_logp, "Skipping entry [%s]. Can't convert or normalize FS String",
5863 osi_LogSaveString(smb_logp, dep->name));
5867 /* Need 8.3 name? */
5869 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
5870 !cm_Is8Dot3(cfileName)) {
5871 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5875 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %S (%S)",
5876 dep->fid.vnode, dep->fid.unique,
5877 osi_LogSaveClientString(smb_logp, cfileName),
5878 NeedShortName ? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
5880 /* When matching, we are using doing a case fold if we have a wildcard mask.
5881 * If we get a non-wildcard match, it's a lookup for a specific file.
5883 if (cm_MatchMask(normName, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5884 (NeedShortName && cm_MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))
5886 /* Eliminate entries that don't match requested attributes */
5887 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5888 smb_IsDotFile(cfileName)) {
5889 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5890 goto nextEntry; /* no hidden files */
5893 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5895 /* We have already done the cm_TryBulkStat above */
5896 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume,
5897 ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5898 fileType = cm_FindFileType(&fid);
5899 /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5900 * "has filetype %d", dep->name, fileType);
5902 if ( fileType == CM_SCACHETYPE_DIRECTORY ||
5903 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5904 fileType == CM_SCACHETYPE_DFSLINK ||
5905 fileType == CM_SCACHETYPE_INVALID)
5906 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5910 /* finally check if this name will fit */
5912 smb_UnparseString(opx, NULL, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5913 orbytes = ohbytes + onbytes;
5915 /* now, we round up the record to a 4 byte alignment,
5916 * and we make sure that we have enough room here for
5917 * even the aligned version (so we don't have to worry
5918 * about an overflow when we pad things out below).
5919 * That's the reason for the alignment arithmetic below.
5921 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5922 align = (4 - (orbytes & 3)) & 3;
5926 if (orbytes + bytesInBuffer + align > maxReturnData) {
5927 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5932 /* this is one of the entries to use: it is not deleted
5933 * and it matches the star pattern we're looking for.
5934 * Put out the name, preceded by its length.
5936 /* First zero everything else */
5937 memset(origOp, 0, orbytes);
5940 smb_UnparseString(opx, origOp + ohbytes, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5942 switch (infoLevel) {
5943 case SMB_INFO_STANDARD:
5944 fp->u.FstandardInfo.fileNameLength = onbytes;
5945 attrp = &fp->u.FstandardInfo.fileAttrs;
5948 case SMB_INFO_QUERY_EA_SIZE:
5949 fp->u.FeaSizeInfo.fileNameLength = onbytes;
5950 attrp = &fp->u.FeaSizeInfo.fileAttrs;
5951 fp->u.FeaSizeInfo.eaSize = 0;
5954 case SMB_INFO_QUERY_EAS_FROM_LIST:
5955 fp->u.FeasFromListInfo.fileNameLength = onbytes;
5956 attrp = &fp->u.FeasFromListInfo.fileAttrs;
5957 fp->u.FeasFromListInfo.eaSize = 0;
5960 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5961 if (NeedShortName) {
5965 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
5966 fp->u.FfileBothDirectoryInfo.shortName,
5967 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
5969 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
5971 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5972 fp->u.FfileBothDirectoryInfo.reserved = 0;
5974 cm_ClientStrCpy(fp->u.FfileBothDirectoryInfo.shortName,
5975 lengthof(fp->u.FfileBothDirectoryInfo.shortName),
5977 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
5982 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5983 fp->u.FfileFullDirectoryInfo.eaSize = 0;
5986 case SMB_FIND_FILE_DIRECTORY_INFO:
5987 fp->u.FfileDirectoryInfo.nextEntryOffset = orbytes + align;
5988 fp->u.FfileDirectoryInfo.fileIndex = nextEntryCookie;
5989 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5990 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5993 case SMB_FIND_FILE_NAMES_INFO:
5994 fp->u.FfileNamesInfo.nextEntryOffset = orbytes + align;
5995 fp->u.FfileNamesInfo.fileIndex = nextEntryCookie;
5996 fp->u.FfileNamesInfo.fileNameLength = onbytes;
6001 /* we shouldn't hit this case */
6002 osi_assertx(FALSE, "Unknown query type");
6005 /* now, adjust the # of entries copied */
6008 /* now we emit the attribute. This is tricky, since
6009 * we need to really stat the file to find out what
6010 * type of entry we've got. Right now, we're copying
6011 * out data from a buffer, while holding the scp
6012 * locked, so it isn't really convenient to stat
6013 * something now. We'll put in a place holder
6014 * now, and make a second pass before returning this
6015 * to get the real attributes. So, we just skip the
6016 * data for now, and adjust it later. We allocate a
6017 * patch record to make it easy to find this point
6018 * later. The replay will happen at a time when it is
6019 * safe to unlock the directory.
6021 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
6022 osi_assert(attrp != NULL);
6023 curPatchp = malloc(sizeof(*curPatchp));
6024 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
6025 curPatchp->dptr = attrp;
6027 if (smb_hideDotFiles && smb_IsDotFile(cfileName)) {
6028 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
6030 curPatchp->flags = 0;
6033 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
6036 curPatchp->dep = dep;
6039 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
6040 /* put out resume key */
6041 *((u_long *)origOp) = nextEntryCookie;
6043 /* Adjust byte ptr and count */
6044 origOp += orbytes; /* skip entire record */
6045 bytesInBuffer += orbytes;
6047 /* and pad the record out */
6048 while (align-- > 0) {
6052 } /* if we're including this name */
6053 else if (!starPattern &&
6055 cm_MatchMask(normName, maskp, CM_FLAG_CASEFOLD)) {
6056 /* We were looking for exact matches, but here's an inexact one*/
6061 /* and adjust curOffset to be where the new cookie is */
6062 thyper.HighPart = 0;
6063 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
6064 curOffset = LargeIntegerAdd(thyper, curOffset);
6065 } /* while copying data for dir listing */
6067 /* If we didn't get a star pattern, we did an exact match during the first pass.
6068 * If there were no exact matches found, we fail over to inexact matches by
6069 * marking the query as a star pattern (matches all case permutations), and
6070 * re-running the query.
6072 if (returnedNames == 0 && !starPattern && foundInexact) {
6073 osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
6078 /* release the mutex */
6079 lock_ReleaseWrite(&scp->rw);
6081 buf_Release(bufferp);
6086 * Finally, process whatever entries we have left.
6088 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
6089 dsp->relPath, infoLevel, userp, &req);
6091 /* now put out the final parameters */
6092 if (returnedNames == 0)
6094 if (p->opcode == 1) {
6096 outp->parmsp[0] = (unsigned short) dsp->cookie;
6097 outp->parmsp[1] = returnedNames;
6098 outp->parmsp[2] = eos;
6099 outp->parmsp[3] = 0; /* nothing wrong with EAS */
6100 outp->parmsp[4] = 0;
6101 /* don't need last name to continue
6102 * search, cookie is enough. Normally,
6103 * this is the offset of the file name
6104 * of the last entry returned.
6106 outp->totalParms = 10; /* in bytes */
6110 outp->parmsp[0] = returnedNames;
6111 outp->parmsp[1] = eos;
6112 outp->parmsp[2] = 0; /* EAS error */
6113 outp->parmsp[3] = 0; /* last name, as above */
6114 outp->totalParms = 8; /* in bytes */
6117 /* return # of bytes in the buffer */
6118 outp->totalData = bytesInBuffer;
6120 /* Return error code if unsuccessful on first request */
6121 if (code == 0 && p->opcode == 1 && returnedNames == 0)
6122 code = CM_ERROR_NOSUCHFILE;
6124 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
6125 p->opcode, dsp->cookie, returnedNames, code);
6127 /* if we're supposed to close the search after this request, or if
6128 * we're supposed to close the search if we're done, and we're done,
6129 * or if something went wrong, close the search.
6131 if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
6132 (returnedNames == 0) ||
6133 ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
6135 smb_DeleteDirSearch(dsp);
6138 smb_SendTran2Error(vcp, p, opx, code);
6140 smb_SendTran2Packet(vcp, outp, opx);
6142 smb_FreeTran2Packet(outp);
6143 smb_ReleaseDirSearch(dsp);
6144 cm_ReleaseSCache(scp);
6145 cm_ReleaseUser(userp);
6149 /* SMB_COM_FIND_CLOSE2 */
6150 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6153 smb_dirSearch_t *dsp;
6155 dirHandle = smb_GetSMBParm(inp, 0);
6157 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
6159 dsp = smb_FindDirSearch(dirHandle);
6162 return CM_ERROR_BADFD;
6164 /* otherwise, we have an FD to destroy */
6165 smb_DeleteDirSearch(dsp);
6166 smb_ReleaseDirSearch(dsp);
6168 /* and return results */
6169 smb_SetSMBDataLength(outp, 0);
6175 /* SMB_COM_FIND_NOTIFY_CLOSE */
6176 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6178 smb_SetSMBDataLength(outp, 0);
6182 /* SMB_COM_OPEN_ANDX */
6183 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6185 clientchar_t *pathp;
6190 cm_scache_t *dscp; /* dir we're dealing with */
6191 cm_scache_t *scp; /* file we're creating */
6195 clientchar_t *lastNamep;
6196 unsigned long dosTime;
6202 int parmSlot; /* which parm we're dealing with */
6203 clientchar_t *tidPathp;
6206 BOOL is_rpc = FALSE;
6207 BOOL is_ipc = FALSE;
6213 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
6214 openFun = smb_GetSMBParm(inp, 8); /* open function */
6215 excl = ((openFun & 3) == 0);
6216 trunc = ((openFun & 3) == 2); /* truncate it */
6217 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
6218 openAction = 0; /* tracks what we did */
6220 attributes = smb_GetSMBParm(inp, 5);
6221 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
6223 pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
6226 return CM_ERROR_BADSMB;
6228 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6230 if (code == CM_ERROR_TIDIPC) {
6233 return CM_ERROR_NOSUCHPATH;
6237 spacep = inp->spacep;
6238 /* smb_StripLastComponent will strip "::$DATA" if present */
6239 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6243 /* special case magic file name for receiving IOCTL requests
6244 * (since IOCTL calls themselves aren't getting through).
6246 (cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
6248 /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional) */
6249 (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
6251 unsigned short file_type = 0;
6252 unsigned short device_state = 0;
6254 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6256 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
6257 osi_Log1(smb_logp, "OpenAndX Setting up RPC on fid[%d]", fidp->fid);
6259 osi_Log1(smb_logp, "smb_SetupRPCFid failure code [%d]", code);
6260 smb_ReleaseFID(fidp);
6264 smb_SetupIoctlFid(fidp, spacep);
6265 osi_Log1(smb_logp, "OpenAndX Setting up IOCTL on fid[%d]", fidp->fid);
6268 /* set inp->fid so that later read calls in same msg can find fid */
6269 inp->fid = fidp->fid;
6271 /* copy out remainder of the parms */
6273 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6275 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
6276 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
6277 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6278 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
6279 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
6280 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
6281 smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++;
6282 smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++;
6284 /* and the final "always present" stuff */
6285 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
6286 /* next write out the "unique" ID */
6287 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
6288 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
6289 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6290 smb_SetSMBDataLength(outp, 0);
6292 /* and clean up fid reference */
6293 smb_ReleaseFID(fidp);
6299 osi_Log0(smb_logp, "NTOpenX rejecting IPC TID");
6300 return CM_ERROR_BADFD;
6304 if (!cm_IsValidClientString(pathp)) {
6306 clientchar_t * hexp;
6308 hexp = cm_GetRawCharsAlloc(pathp, -1);
6309 osi_Log1(smb_logp, "NTOpenX rejecting invalid name. [%S]",
6310 osi_LogSaveClientString(smb_logp, hexp));
6314 osi_Log0(smb_logp, "NTOpenX rejecting invalid name");
6316 return CM_ERROR_BADNTFILENAME;
6319 #ifdef DEBUG_VERBOSE
6321 char *hexp, *asciip;
6322 asciip = (lastNamep ? lastNamep : pathp );
6323 hexp = osi_HexifyString(asciip);
6324 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
6328 userp = smb_GetUserFromVCP(vcp, inp);
6331 code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
6332 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6333 userp, tidPathp, &req, &scp);
6336 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6337 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
6338 cm_ReleaseSCache(scp);
6339 cm_ReleaseUser(userp);
6340 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6341 return CM_ERROR_PATH_NOT_COVERED;
6343 return CM_ERROR_NOSUCHPATH;
6345 #endif /* DFS_SUPPORT */
6348 if (code == CM_ERROR_NOSUCHFILE ||
6349 code == CM_ERROR_NOSUCHPATH ||
6350 code == CM_ERROR_BPLUS_NOMATCH)
6351 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
6352 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6353 userp, tidPathp, &req, &dscp);
6355 cm_ReleaseUser(userp);
6360 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6361 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
6363 cm_ReleaseSCache(dscp);
6364 cm_ReleaseUser(userp);
6365 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6366 return CM_ERROR_PATH_NOT_COVERED;
6368 return CM_ERROR_NOSUCHPATH;
6370 #endif /* DFS_SUPPORT */
6371 /* otherwise, scp points to the parent directory. Do a lookup,
6372 * and truncate the file if we find it, otherwise we create the
6379 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
6381 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
6382 cm_ReleaseSCache(dscp);
6383 cm_ReleaseUser(userp);
6388 /* if we get here, if code is 0, the file exists and is represented by
6389 * scp. Otherwise, we have to create it. The dir may be represented
6390 * by dscp, or we may have found the file directly. If code is non-zero,
6394 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
6396 if (dscp) cm_ReleaseSCache(dscp);
6397 cm_ReleaseSCache(scp);
6398 cm_ReleaseUser(userp);
6403 /* oops, file shouldn't be there */
6405 cm_ReleaseSCache(dscp);
6406 cm_ReleaseSCache(scp);
6407 cm_ReleaseUser(userp);
6408 return CM_ERROR_EXISTS;
6412 setAttr.mask = CM_ATTRMASK_LENGTH;
6413 setAttr.length.LowPart = 0;
6414 setAttr.length.HighPart = 0;
6415 code = cm_SetAttr(scp, &setAttr, userp, &req);
6416 openAction = 3; /* truncated existing file */
6418 else openAction = 1; /* found existing file */
6420 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
6421 /* don't create if not found */
6422 if (dscp) cm_ReleaseSCache(dscp);
6423 cm_ReleaseUser(userp);
6424 return CM_ERROR_NOSUCHFILE;
6427 osi_assertx(dscp != NULL, "null cm_scache_t");
6428 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %S",
6429 osi_LogSaveClientString(smb_logp, lastNamep));
6430 openAction = 2; /* created file */
6431 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6432 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6433 smb_SetInitialModeBitsForFile(attributes, &setAttr);
6435 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6439 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6440 smb_NotifyChange(FILE_ACTION_ADDED,
6441 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6442 dscp, lastNamep, NULL, TRUE);
6443 } else if (!excl && code == CM_ERROR_EXISTS) {
6444 /* not an exclusive create, and someone else tried
6445 * creating it already, then we open it anyway. We
6446 * don't bother retrying after this, since if this next
6447 * fails, that means that the file was deleted after we
6448 * started this call.
6450 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6454 setAttr.mask = CM_ATTRMASK_LENGTH;
6455 setAttr.length.LowPart = 0;
6456 setAttr.length.HighPart = 0;
6457 code = cm_SetAttr(scp, &setAttr, userp, &req);
6459 } /* lookup succeeded */
6463 /* we don't need this any longer */
6465 cm_ReleaseSCache(dscp);
6468 /* something went wrong creating or truncating the file */
6470 cm_ReleaseSCache(scp);
6471 cm_ReleaseUser(userp);
6475 /* make sure we're about to open a file */
6476 if (scp->fileType != CM_SCACHETYPE_FILE) {
6477 cm_ReleaseSCache(scp);
6478 cm_ReleaseUser(userp);
6479 return CM_ERROR_ISDIR;
6482 /* now all we have to do is open the file itself */
6483 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6484 osi_assertx(fidp, "null smb_fid_t");
6487 lock_ObtainMutex(&fidp->mx);
6488 /* save a pointer to the vnode */
6490 lock_ObtainWrite(&scp->rw);
6491 scp->flags |= CM_SCACHEFLAG_SMB_FID;
6492 lock_ReleaseWrite(&scp->rw);
6493 osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
6495 fidp->userp = userp;
6497 /* compute open mode */
6499 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
6500 if (openMode == 1 || openMode == 2)
6501 fidp->flags |= SMB_FID_OPENWRITE;
6503 /* remember if the file was newly created */
6505 fidp->flags |= SMB_FID_CREATED;
6507 lock_ReleaseMutex(&fidp->mx);
6508 smb_ReleaseFID(fidp);
6510 cm_Open(scp, 0, userp);
6512 /* set inp->fid so that later read calls in same msg can find fid */
6513 inp->fid = fidp->fid;
6515 /* copy out remainder of the parms */
6517 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6518 lock_ObtainRead(&scp->rw);
6520 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
6521 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
6522 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
6523 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
6524 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
6525 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
6526 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
6527 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
6528 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
6530 /* and the final "always present" stuff */
6531 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
6532 /* next write out the "unique" ID */
6533 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
6534 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
6535 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6536 lock_ReleaseRead(&scp->rw);
6537 smb_SetSMBDataLength(outp, 0);
6539 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
6541 cm_ReleaseUser(userp);
6542 /* leave scp held since we put it in fidp->scp */
6546 static void smb_GetLockParams(unsigned char LockType,
6548 unsigned int * ppid,
6549 LARGE_INTEGER * pOffset,
6550 LARGE_INTEGER * pLength)
6552 if (LockType & LOCKING_ANDX_LARGE_FILES) {
6554 *ppid = *((USHORT *) *buf);
6555 pOffset->HighPart = *((LONG *)(*buf + 4));
6556 pOffset->LowPart = *((DWORD *)(*buf + 8));
6557 pLength->HighPart = *((LONG *)(*buf + 12));
6558 pLength->LowPart = *((DWORD *)(*buf + 16));
6562 /* Not Large Files */
6563 *ppid = *((USHORT *) *buf);
6564 pOffset->HighPart = 0;
6565 pOffset->LowPart = *((DWORD *)(*buf + 2));
6566 pLength->HighPart = 0;
6567 pLength->LowPart = *((DWORD *)(*buf + 6));
6572 /* SMB_COM_LOCKING_ANDX */
6573 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6580 unsigned char LockType;
6581 unsigned short NumberOfUnlocks, NumberOfLocks;
6585 LARGE_INTEGER LOffset, LLength;
6586 smb_waitingLockRequest_t *wlRequest = NULL;
6587 cm_file_lock_t *lockp;
6592 afs_uint32 smb_vc_hold_required = 0;
6596 fid = smb_GetSMBParm(inp, 2);
6597 fid = smb_ChainFID(fid, inp);
6599 fidp = smb_FindFID(vcp, fid, 0);
6601 osi_Log2(smb_logp, "V3LockingX Unknown SMB Fid vcp 0x%p fid %d",
6603 return CM_ERROR_BADFD;
6605 lock_ObtainMutex(&fidp->mx);
6606 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6607 lock_ReleaseMutex(&fidp->mx);
6608 smb_CloseFID(vcp, fidp, NULL, 0);
6609 smb_ReleaseFID(fidp);
6610 return CM_ERROR_NOSUCHFILE;
6613 if (fidp->flags & SMB_FID_IOCTL) {
6614 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
6615 lock_ReleaseMutex(&fidp->mx);
6616 smb_ReleaseFID(fidp);
6617 return CM_ERROR_BADFD;
6620 osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
6622 lock_ReleaseMutex(&fidp->mx);
6624 /* set inp->fid so that later read calls in same msg can find fid */
6627 userp = smb_GetUserFromVCP(vcp, inp);
6630 lock_ObtainWrite(&scp->rw);
6631 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6632 CM_SCACHESYNC_NEEDCALLBACK
6633 | CM_SCACHESYNC_GETSTATUS
6634 | CM_SCACHESYNC_LOCK);
6636 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
6640 LockType = smb_GetSMBParm(inp, 3) & 0xff;
6641 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
6642 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
6643 NumberOfLocks = smb_GetSMBParm(inp, 7);
6645 if (!(fidp->flags & SMB_FID_OPENWRITE) &&
6646 !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
6647 /* somebody wants exclusive locks on a file that they only
6648 opened for reading. We downgrade this to a shared lock. */
6649 osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
6650 LockType |= LOCKING_ANDX_SHARED_LOCK;
6653 if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
6654 /* AFS does not support atomic changes of lock types from read or write and vice-versa */
6655 osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]");
6656 code = CM_ERROR_BADOP;
6661 op = smb_GetSMBData(inp, NULL);
6663 if (LockType & LOCKING_ANDX_CANCEL_LOCK) {
6664 /* Cancel outstanding lock requests */
6665 smb_waitingLock_t * wl;
6667 for (i=0; i<NumberOfLocks; i++) {
6668 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6670 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6672 lock_ObtainWrite(&smb_globalLock);
6673 for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
6675 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
6676 if (cm_KeyEquals(&wl->key, &key, 0) && LargeIntegerEqualTo(wl->LOffset, LOffset) &&
6677 LargeIntegerEqualTo(wl->LLength, LLength)) {
6678 wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
6679 goto found_lock_request;
6684 lock_ReleaseWrite(&smb_globalLock);
6687 smb_SetSMBDataLength(outp, 0);
6692 for (i=0; i<NumberOfUnlocks; i++) {
6693 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6695 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6697 code = cm_Unlock(scp, LockType, LOffset, LLength, key, 0, userp, &req);
6705 for (i=0; i<NumberOfLocks; i++) {
6706 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6708 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6710 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
6711 userp, &req, &lockp);
6713 if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
6714 (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
6716 code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
6717 userp, &req, &lockp);
6720 if (code == CM_ERROR_LOCK_NOT_GRANTED && Timeout != 0) {
6721 smb_waitingLock_t * wLock;
6723 /* Put on waiting list */
6724 if(wlRequest == NULL) {
6728 LARGE_INTEGER tOffset, tLength;
6730 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
6732 osi_assertx(wlRequest != NULL, "null wlRequest");
6734 wlRequest->vcp = vcp;
6735 smb_vc_hold_required = 1;
6736 wlRequest->scp = scp;
6737 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
6739 wlRequest->inp = smb_CopyPacket(inp);
6740 wlRequest->outp = smb_CopyPacket(outp);
6741 wlRequest->lockType = LockType;
6742 wlRequest->msTimeout = Timeout;
6743 wlRequest->start_t = osi_Time();
6744 wlRequest->locks = NULL;
6746 /* The waiting lock request needs to have enough
6747 information to undo all the locks in the request.
6748 We do the following to store info about locks that
6749 have already been granted. Sure, we can get most
6750 of the info from the packet, but the packet doesn't
6751 hold the result of cm_Lock call. In practice we
6752 only receive packets with one or two locks, so we
6753 are only wasting a few bytes here and there and
6754 only for a limited period of time until the waiting
6755 lock times out or is freed. */
6757 for(opt = op_locks, j=i; j > 0; j--) {
6758 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
6760 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6762 wLock = malloc(sizeof(smb_waitingLock_t));
6764 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6767 wLock->LOffset = tOffset;
6768 wLock->LLength = tLength;
6769 wLock->lockp = NULL;
6770 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
6771 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6776 wLock = malloc(sizeof(smb_waitingLock_t));
6778 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6781 wLock->LOffset = LOffset;
6782 wLock->LLength = LLength;
6783 wLock->lockp = lockp;
6784 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
6785 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6788 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
6796 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
6803 /* Since something went wrong with the lock number i, we now
6804 have to go ahead and release any locks acquired before the
6805 failure. All locks before lock number i (of which there
6806 are i of them) have either been successful or are waiting.
6807 Either case requires calling cm_Unlock(). */
6809 /* And purge the waiting lock */
6810 if(wlRequest != NULL) {
6811 smb_waitingLock_t * wl;
6812 smb_waitingLock_t * wlNext;
6815 for(wl = wlRequest->locks; wl; wl = wlNext) {
6817 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
6819 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, 0, userp, &req);
6822 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
6824 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
6827 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
6832 smb_ReleaseVC(wlRequest->vcp);
6833 cm_ReleaseSCache(wlRequest->scp);
6834 smb_FreePacket(wlRequest->inp);
6835 smb_FreePacket(wlRequest->outp);
6844 if (wlRequest != NULL) {
6846 lock_ObtainWrite(&smb_globalLock);
6847 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
6849 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
6850 lock_ReleaseWrite(&smb_globalLock);
6852 /* don't send reply immediately */
6853 outp->flags |= SMB_PACKETFLAG_NOSEND;
6856 smb_SetSMBDataLength(outp, 0);
6860 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
6863 lock_ReleaseWrite(&scp->rw);
6864 cm_ReleaseSCache(scp);
6865 cm_ReleaseUser(userp);
6866 smb_ReleaseFID(fidp);
6867 if (!smb_vc_hold_required)
6873 /* SMB_COM_QUERY_INFORMATION2 */
6874 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6880 afs_uint32 searchTime;
6887 fid = smb_GetSMBParm(inp, 0);
6888 fid = smb_ChainFID(fid, inp);
6890 fidp = smb_FindFID(vcp, fid, 0);
6892 osi_Log2(smb_logp, "V3GetAttributes Unknown SMB Fid vcp 0x%p fid %d",
6894 return CM_ERROR_BADFD;
6896 lock_ObtainMutex(&fidp->mx);
6897 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6898 lock_ReleaseMutex(&fidp->mx);
6899 smb_CloseFID(vcp, fidp, NULL, 0);
6900 smb_ReleaseFID(fidp);
6901 return CM_ERROR_NOSUCHFILE;
6904 if (fidp->flags & SMB_FID_IOCTL) {
6905 lock_ReleaseMutex(&fidp->mx);
6906 smb_ReleaseFID(fidp);
6907 return CM_ERROR_BADFD;
6910 osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6912 lock_ReleaseMutex(&fidp->mx);
6914 userp = smb_GetUserFromVCP(vcp, inp);
6917 /* otherwise, stat the file */
6918 lock_ObtainWrite(&scp->rw);
6919 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6920 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6924 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6926 lock_ConvertWToR(&scp->rw);
6929 /* decode times. We need a search time, but the response to this
6930 * call provides the date first, not the time, as returned in the
6931 * searchTime variable. So we take the high-order bits first.
6933 cm_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
6934 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
6935 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
6936 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
6937 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
6938 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
6939 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
6941 /* now handle file size and allocation size */
6942 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
6943 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
6944 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
6945 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
6947 /* file attribute */
6948 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
6950 /* and finalize stuff */
6951 smb_SetSMBDataLength(outp, 0);
6956 lock_ReleaseRead(&scp->rw);
6958 lock_ReleaseWrite(&scp->rw);
6959 cm_ReleaseSCache(scp);
6960 cm_ReleaseUser(userp);
6961 smb_ReleaseFID(fidp);
6965 /* SMB_COM_SET_INFORMATION2 */
6966 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6972 afs_uint32 searchTime;
6980 fid = smb_GetSMBParm(inp, 0);
6981 fid = smb_ChainFID(fid, inp);
6983 fidp = smb_FindFID(vcp, fid, 0);
6985 osi_Log2(smb_logp, "V3SetAttributes Unknown SMB Fid vcp 0x%p fid %d",
6987 return CM_ERROR_BADFD;
6989 lock_ObtainMutex(&fidp->mx);
6990 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6991 lock_ReleaseMutex(&fidp->mx);
6992 smb_CloseFID(vcp, fidp, NULL, 0);
6993 smb_ReleaseFID(fidp);
6994 return CM_ERROR_NOSUCHFILE;
6997 if (fidp->flags & SMB_FID_IOCTL) {
6998 lock_ReleaseMutex(&fidp->mx);
6999 smb_ReleaseFID(fidp);
7000 return CM_ERROR_BADFD;
7003 osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
7005 lock_ReleaseMutex(&fidp->mx);
7007 userp = smb_GetUserFromVCP(vcp, inp);
7009 /* now prepare to call cm_setattr. This message only sets various times,
7010 * and AFS only implements mtime, and we'll set the mtime if that's
7011 * requested. The others we'll ignore.
7013 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
7015 if (searchTime != 0) {
7016 cm_UnixTimeFromSearchTime(&unixTime, searchTime);
7018 if ( unixTime != -1 ) {
7019 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
7020 attrs.clientModTime = unixTime;
7021 code = cm_SetAttr(scp, &attrs, userp, &req);
7023 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
7025 osi_Log1(smb_logp, "**cm_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
7031 cm_ReleaseSCache(scp);
7032 cm_ReleaseUser(userp);
7033 smb_ReleaseFID(fidp);
7037 /* SMB_COM_WRITE_ANDX */
7038 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7041 long count, written = 0, total_written = 0;
7045 smb_t *smbp = (smb_t*) inp;
7050 int inDataBlockCount;
7052 fd = smb_GetSMBParm(inp, 2);
7053 count = smb_GetSMBParm(inp, 10);
7055 offset.HighPart = 0;
7056 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7058 if (*inp->wctp == 14) {
7059 /* we have a request with 64-bit file offsets */
7060 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7063 op = inp->data + smb_GetSMBParm(inp, 11);
7064 inDataBlockCount = count;
7066 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
7067 fd, offset.HighPart, offset.LowPart, count);
7069 fd = smb_ChainFID(fd, inp);
7070 fidp = smb_FindFID(vcp, fd, 0);
7072 osi_Log2(smb_logp, "smb_ReceiveV3WriteX Unknown SMB Fid vcp 0x%p fid %d",
7074 return CM_ERROR_BADFD;
7076 lock_ObtainMutex(&fidp->mx);
7077 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7078 lock_ReleaseMutex(&fidp->mx);
7079 smb_CloseFID(vcp, fidp, NULL, 0);
7080 smb_ReleaseFID(fidp);
7081 return CM_ERROR_NOSUCHFILE;
7084 if (fidp->flags & SMB_FID_IOCTL) {
7085 lock_ReleaseMutex(&fidp->mx);
7086 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
7087 smb_ReleaseFID(fidp);
7091 if (fidp->flags & SMB_FID_RPC) {
7092 lock_ReleaseMutex(&fidp->mx);
7093 code = smb_RPCV3Write(fidp, vcp, inp, outp);
7094 smb_ReleaseFID(fidp);
7099 lock_ReleaseMutex(&fidp->mx);
7100 smb_ReleaseFID(fidp);
7101 return CM_ERROR_BADFDOP;
7106 lock_ReleaseMutex(&fidp->mx);
7108 userp = smb_GetUserFromVCP(vcp, inp);
7110 /* special case: 0 bytes transferred means there is no data
7111 transferred. A slight departure from SMB_COM_WRITE where this
7112 means that we are supposed to truncate the file at this
7117 LARGE_INTEGER LOffset;
7118 LARGE_INTEGER LLength;
7121 key = cm_GenerateKey(vcp->vcID, pid, fd);
7123 LOffset.HighPart = offset.HighPart;
7124 LOffset.LowPart = offset.LowPart;
7125 LLength.HighPart = 0;
7126 LLength.LowPart = count;
7128 lock_ObtainWrite(&scp->rw);
7129 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7130 lock_ReleaseWrite(&scp->rw);
7137 * Work around bug in NT client
7139 * When copying a file, the NT client should first copy the data,
7140 * then copy the last write time. But sometimes the NT client does
7141 * these in the wrong order, so the data copies would inadvertently
7142 * cause the last write time to be overwritten. We try to detect this,
7143 * and don't set client mod time if we think that would go against the
7146 lock_ObtainMutex(&fidp->mx);
7147 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7148 lock_ObtainWrite(&fidp->scp->rw);
7149 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7150 scp->clientModTime = time(NULL);
7151 lock_ReleaseWrite(&fidp->scp->rw);
7153 lock_ReleaseMutex(&fidp->mx);
7156 while ( code == 0 && count > 0 ) {
7157 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7158 if (code == 0 && written == 0)
7159 code = CM_ERROR_PARTIALWRITE;
7161 offset = LargeIntegerAdd(offset,
7162 ConvertLongToLargeInteger(written));
7164 total_written += written;
7168 /* slots 0 and 1 are reserved for request chaining and will be
7169 filled in when we return. */
7170 smb_SetSMBParm(outp, 2, total_written);
7171 smb_SetSMBParm(outp, 3, 0); /* reserved */
7172 smb_SetSMBParm(outp, 4, 0); /* reserved */
7173 smb_SetSMBParm(outp, 5, 0); /* reserved */
7174 smb_SetSMBDataLength(outp, 0);
7178 cm_ReleaseSCache(scp);
7179 cm_ReleaseUser(userp);
7180 smb_ReleaseFID(fidp);
7185 /* SMB_COM_READ_ANDX */
7186 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7190 long finalCount = 0;
7194 smb_t *smbp = (smb_t*) inp;
7201 fd = smb_GetSMBParm(inp, 2); /* File ID */
7202 count = smb_GetSMBParm(inp, 5); /* MaxCount */
7203 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7205 if (*inp->wctp == 12) {
7206 /* a request with 64-bit offsets */
7207 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
7209 if (LargeIntegerLessThanZero(offset)) {
7210 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
7211 offset.HighPart, offset.LowPart);
7212 return CM_ERROR_BADSMB;
7215 offset.HighPart = 0;
7218 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
7219 fd, offset.HighPart, offset.LowPart, count);
7221 fd = smb_ChainFID(fd, inp);
7222 fidp = smb_FindFID(vcp, fd, 0);
7224 osi_Log2(smb_logp, "smb_ReceiveV3Read Unknown SMB Fid vcp 0x%p fid %d",
7226 return CM_ERROR_BADFD;
7229 lock_ObtainMutex(&fidp->mx);
7231 if (fidp->flags & SMB_FID_IOCTL) {
7232 lock_ReleaseMutex(&fidp->mx);
7234 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
7235 smb_ReleaseFID(fidp);
7239 if (fidp->flags & SMB_FID_RPC) {
7240 lock_ReleaseMutex(&fidp->mx);
7242 code = smb_RPCV3Read(fidp, vcp, inp, outp);
7243 smb_ReleaseFID(fidp);
7247 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7248 lock_ReleaseMutex(&fidp->mx);
7249 smb_CloseFID(vcp, fidp, NULL, 0);
7250 smb_ReleaseFID(fidp);
7251 return CM_ERROR_NOSUCHFILE;
7255 lock_ReleaseMutex(&fidp->mx);
7256 smb_ReleaseFID(fidp);
7257 return CM_ERROR_BADFDOP;
7263 lock_ReleaseMutex(&fidp->mx);
7266 key = cm_GenerateKey(vcp->vcID, pid, fd);
7268 LARGE_INTEGER LOffset, LLength;
7270 LOffset.HighPart = offset.HighPart;
7271 LOffset.LowPart = offset.LowPart;
7272 LLength.HighPart = 0;
7273 LLength.LowPart = count;
7275 lock_ObtainWrite(&scp->rw);
7276 code = cm_LockCheckRead(scp, LOffset, LLength, key);
7277 lock_ReleaseWrite(&scp->rw);
7279 cm_ReleaseSCache(scp);
7282 smb_ReleaseFID(fidp);
7286 /* set inp->fid so that later read calls in same msg can find fid */
7289 userp = smb_GetUserFromVCP(vcp, inp);
7291 /* 0 and 1 are reserved for request chaining, were setup by our caller,
7292 * and will be further filled in after we return.
7294 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
7295 smb_SetSMBParm(outp, 3, 0); /* resvd */
7296 smb_SetSMBParm(outp, 4, 0); /* resvd */
7297 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
7298 /* fill in #6 when we have all the parameters' space reserved */
7299 smb_SetSMBParm(outp, 7, 0); /* resv'd */
7300 smb_SetSMBParm(outp, 8, 0); /* resv'd */
7301 smb_SetSMBParm(outp, 9, 0); /* resv'd */
7302 smb_SetSMBParm(outp, 10, 0); /* resv'd */
7303 smb_SetSMBParm(outp, 11, 0); /* reserved */
7305 /* get op ptr after putting in the parms, since otherwise we don't
7306 * know where the data really is.
7308 op = smb_GetSMBData(outp, NULL);
7310 /* now fill in offset from start of SMB header to first data byte (to op) */
7311 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
7313 /* set the packet data length the count of the # of bytes */
7314 smb_SetSMBDataLength(outp, count);
7316 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7318 /* fix some things up */
7319 smb_SetSMBParm(outp, 5, finalCount);
7320 smb_SetSMBDataLength(outp, finalCount);
7322 cm_ReleaseUser(userp);
7323 smb_ReleaseFID(fidp);
7328 * Values for createDisp, copied from NTDDK.H
7330 #define FILE_SUPERSEDE 0 // (???)
7331 #define FILE_OPEN 1 // (open)
7332 #define FILE_CREATE 2 // (exclusive)
7333 #define FILE_OPEN_IF 3 // (non-exclusive)
7334 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
7335 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
7338 #define REQUEST_OPLOCK 2
7339 #define REQUEST_BATCH_OPLOCK 4
7340 #define OPEN_DIRECTORY 8
7341 #define EXTENDED_RESPONSE_REQUIRED 0x10
7343 /* CreateOptions field. */
7344 #define FILE_DIRECTORY_FILE 0x0001
7345 #define FILE_WRITE_THROUGH 0x0002
7346 #define FILE_SEQUENTIAL_ONLY 0x0004
7347 #define FILE_NON_DIRECTORY_FILE 0x0040
7348 #define FILE_NO_EA_KNOWLEDGE 0x0200
7349 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
7350 #define FILE_RANDOM_ACCESS 0x0800
7351 #define FILE_DELETE_ON_CLOSE 0x1000
7352 #define FILE_OPEN_BY_FILE_ID 0x2000
7353 #define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000
7354 #define FILE_NO_COMPRESSION 0x00008000
7355 #define FILE_RESERVE_OPFILTER 0x00100000
7356 #define FILE_OPEN_REPARSE_POINT 0x00200000
7357 #define FILE_OPEN_NO_RECALL 0x00400000
7358 #define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000
7360 /* SMB_COM_NT_CREATE_ANDX */
7361 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7363 clientchar_t *pathp, *realPathp;
7367 cm_scache_t *dscp; /* parent dir */
7368 cm_scache_t *scp; /* file to create or open */
7369 cm_scache_t *targetScp; /* if scp is a symlink */
7371 clientchar_t *lastNamep;
7372 clientchar_t *treeStartp;
7373 unsigned short nameLength;
7375 unsigned int requestOpLock;
7376 unsigned int requestBatchOpLock;
7377 unsigned int mustBeDir;
7378 unsigned int extendedRespRequired;
7379 unsigned int treeCreate;
7381 unsigned int desiredAccess;
7382 unsigned int extAttributes;
7383 unsigned int createDisp;
7384 unsigned int createOptions;
7385 unsigned int shareAccess;
7386 unsigned short baseFid;
7387 smb_fid_t *baseFidp;
7389 cm_scache_t *baseDirp;
7390 unsigned short openAction;
7395 clientchar_t *tidPathp;
7400 int checkDoneRequired = 0;
7401 cm_lock_data_t *ldp = NULL;
7402 BOOL is_rpc = FALSE;
7403 BOOL is_ipc = FALSE;
7407 /* This code is very long and has a lot of if-then-else clauses
7408 * scp and dscp get reused frequently and we need to ensure that
7409 * we don't lose a reference. Start by ensuring that they are NULL.
7416 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
7417 flags = smb_GetSMBOffsetParm(inp, 3, 1)
7418 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
7419 requestOpLock = flags & REQUEST_OPLOCK;
7420 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7421 mustBeDir = flags & OPEN_DIRECTORY;
7422 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7425 * Why all of a sudden 32-bit FID?
7426 * We will reject all bits higher than 16.
7428 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
7429 return CM_ERROR_INVAL;
7430 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
7431 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
7432 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
7433 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
7434 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
7435 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
7436 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
7437 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
7438 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
7439 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
7440 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
7442 /* mustBeDir is never set; createOptions directory bit seems to be
7445 if (createOptions & FILE_DIRECTORY_FILE)
7447 else if (createOptions & FILE_NON_DIRECTORY_FILE)
7452 pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
7453 NULL, SMB_STRF_ANSIPATH);
7455 /* Sometimes path is not null-terminated, so we make a copy. */
7456 realPathp = malloc(nameLength+sizeof(clientchar_t));
7457 memcpy(realPathp, pathp, nameLength+sizeof(clientchar_t));
7458 realPathp[nameLength/sizeof(clientchar_t)] = 0;
7460 spacep = inp->spacep;
7461 /* smb_StripLastComponent will strip "::$DATA" if present */
7462 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
7464 osi_Log1(smb_logp,"NTCreateX for [%S]",osi_LogSaveClientString(smb_logp,realPathp));
7465 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
7466 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%S]", shareAccess, flags, osi_LogSaveClientString(smb_logp,(lastNamep?lastNamep:_C("null"))));
7470 baseDirp = cm_RootSCachep(cm_rootUserp, &req);
7471 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7472 if (code == CM_ERROR_TIDIPC) {
7473 /* Attempt to use a TID allocated for IPC. The client
7474 * is probably looking for DCE RPC end points which we
7475 * don't support OR it could be looking to make a DFS
7478 osi_Log0(smb_logp, "NTCreateX received IPC TID");
7483 osi_Log1(smb_logp, "NTCreateX tidPathp=[%S]", (tidPathp==NULL)?_C("null"): osi_LogSaveClientString(smb_logp,tidPathp));
7487 ((is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)) ||
7489 /* special case magic file name for receiving IOCTL requests
7490 * (since IOCTL calls themselves aren't getting through).
7492 cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0)) {
7494 unsigned short file_type = 0;
7495 unsigned short device_state = 0;
7497 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7500 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
7501 osi_Log1(smb_logp, "NTCreateX Setting up RPC on fid[%d]", fidp->fid);
7503 osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
7504 smb_ReleaseFID(fidp);
7509 smb_SetupIoctlFid(fidp, spacep);
7510 osi_Log1(smb_logp, "NTCreateX Setting up IOCTL on fid[%d]", fidp->fid);
7513 /* set inp->fid so that later read calls in same msg can find fid */
7514 inp->fid = fidp->fid;
7518 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7519 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7520 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
7522 memset(&ft, 0, sizeof(ft));
7523 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7524 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7525 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7526 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7527 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
7528 sz.HighPart = 0x7fff; sz.LowPart = 0;
7529 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
7530 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
7531 smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++; /* filetype */
7532 smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++; /* dev state */
7533 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
7534 smb_SetSMBDataLength(outp, 0);
7536 /* clean up fid reference */
7537 smb_ReleaseFID(fidp);
7544 osi_Log0(smb_logp, "NTCreateX rejecting IPC TID");
7546 return CM_ERROR_BADFD;
7550 if (!cm_IsValidClientString(realPathp)) {
7552 clientchar_t * hexp;
7554 hexp = cm_GetRawCharsAlloc(realPathp, -1);
7555 osi_Log1(smb_logp, "NTCreateX rejecting invalid name. [%S]",
7556 osi_LogSaveClientString(smb_logp, hexp));
7560 osi_Log0(smb_logp, "NTCreateX rejecting invalid name");
7563 return CM_ERROR_BADNTFILENAME;
7566 userp = smb_GetUserFromVCP(vcp, inp);
7568 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
7570 return CM_ERROR_INVAL;
7573 if (baseFidp != 0) {
7574 baseFidp = smb_FindFID(vcp, baseFid, 0);
7576 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
7577 cm_ReleaseUser(userp);
7579 return CM_ERROR_INVAL;
7582 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7584 smb_CloseFID(vcp, baseFidp, NULL, 0);
7585 smb_ReleaseFID(baseFidp);
7586 cm_ReleaseUser(userp);
7587 return CM_ERROR_NOSUCHPATH;
7590 baseDirp = baseFidp->scp;
7594 /* compute open mode */
7596 if (desiredAccess & DELETE)
7597 fidflags |= SMB_FID_OPENDELETE;
7598 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
7599 fidflags |= SMB_FID_OPENREAD_LISTDIR;
7600 if (desiredAccess & AFS_ACCESS_WRITE)
7601 fidflags |= SMB_FID_OPENWRITE;
7602 if (createOptions & FILE_DELETE_ON_CLOSE)
7603 fidflags |= SMB_FID_DELONCLOSE;
7604 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7605 fidflags |= SMB_FID_SEQUENTIAL;
7606 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7607 fidflags |= SMB_FID_RANDOM;
7608 if (createOptions & FILE_OPEN_REPARSE_POINT)
7609 osi_Log0(smb_logp, "NTCreateX Open Reparse Point");
7610 if (smb_IsExecutableFileName(lastNamep))
7611 fidflags |= SMB_FID_EXECUTABLE;
7613 /* and the share mode */
7614 if (shareAccess & FILE_SHARE_READ)
7615 fidflags |= SMB_FID_SHARE_READ;
7616 if (shareAccess & FILE_SHARE_WRITE)
7617 fidflags |= SMB_FID_SHARE_WRITE;
7619 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
7622 /* For an exclusive create, we want to do a case sensitive match for the last component. */
7623 if ( createDisp == FILE_CREATE ||
7624 createDisp == FILE_OVERWRITE ||
7625 createDisp == FILE_OVERWRITE_IF) {
7626 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7627 userp, tidPathp, &req, &dscp);
7630 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7631 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7633 cm_ReleaseSCache(dscp);
7634 cm_ReleaseUser(userp);
7637 smb_ReleaseFID(baseFidp);
7638 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7639 return CM_ERROR_PATH_NOT_COVERED;
7641 return CM_ERROR_NOSUCHPATH;
7643 #endif /* DFS_SUPPORT */
7644 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7646 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7647 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7648 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7649 if (code == 0 && realDirFlag == 1) {
7650 cm_ReleaseSCache(scp);
7651 cm_ReleaseSCache(dscp);
7652 cm_ReleaseUser(userp);
7655 smb_ReleaseFID(baseFidp);
7656 return CM_ERROR_EXISTS;
7659 /* we have both scp and dscp */
7662 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7663 userp, tidPathp, &req, &scp);
7665 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7666 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7667 cm_ReleaseSCache(scp);
7668 cm_ReleaseUser(userp);
7671 smb_ReleaseFID(baseFidp);
7672 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7673 return CM_ERROR_PATH_NOT_COVERED;
7675 return CM_ERROR_NOSUCHPATH;
7677 #endif /* DFS_SUPPORT */
7678 /* we might have scp but not dscp */
7682 code != CM_ERROR_NOSUCHFILE &&
7683 code != CM_ERROR_NOSUCHPATH &&
7684 code != CM_ERROR_BPLUS_NOMATCH) {
7685 cm_ReleaseUser(userp);
7688 smb_ReleaseFID(baseFidp);
7695 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7696 /* look up parent directory */
7697 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
7698 * the immediate parent. We have to work our way up realPathp until we hit something that we
7702 /* we might or might not have scp */
7708 code = cm_NameI(baseDirp, spacep->wdata,
7709 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7710 userp, tidPathp, &req, &dscp);
7713 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7714 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7717 cm_ReleaseSCache(scp);
7718 cm_ReleaseSCache(dscp);
7719 cm_ReleaseUser(userp);
7722 smb_ReleaseFID(baseFidp);
7723 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7724 return CM_ERROR_PATH_NOT_COVERED;
7726 return CM_ERROR_NOSUCHPATH;
7728 #endif /* DFS_SUPPORT */
7731 (code == CM_ERROR_NOSUCHFILE ||
7732 code == CM_ERROR_NOSUCHPATH ||
7733 code == CM_ERROR_BPLUS_NOMATCH) &&
7734 (tp = cm_ClientStrRChr(spacep->wdata, '\\')) &&
7735 (createDisp == FILE_CREATE) &&
7736 (realDirFlag == 1)) {
7739 treeStartp = realPathp + (tp - spacep->wdata);
7741 if (*tp && !smb_IsLegalFilename(tp)) {
7742 cm_ReleaseUser(userp);
7744 smb_ReleaseFID(baseFidp);
7747 cm_ReleaseSCache(scp);
7748 return CM_ERROR_BADNTFILENAME;
7752 } while (dscp == NULL && code == 0);
7756 /* we might have scp and we might have dscp */
7759 smb_ReleaseFID(baseFidp);
7762 osi_Log0(smb_logp,"NTCreateX parent not found");
7764 cm_ReleaseSCache(scp);
7766 cm_ReleaseSCache(dscp);
7767 cm_ReleaseUser(userp);
7772 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
7773 /* A file exists where we want a directory. */
7775 cm_ReleaseSCache(scp);
7776 cm_ReleaseSCache(dscp);
7777 cm_ReleaseUser(userp);
7779 return CM_ERROR_EXISTS;
7783 lastNamep = realPathp;
7787 if (!smb_IsLegalFilename(lastNamep)) {
7789 cm_ReleaseSCache(scp);
7791 cm_ReleaseSCache(dscp);
7792 cm_ReleaseUser(userp);
7794 return CM_ERROR_BADNTFILENAME;
7797 if (!foundscp && !treeCreate) {
7798 if ( createDisp == FILE_CREATE ||
7799 createDisp == FILE_OVERWRITE ||
7800 createDisp == FILE_OVERWRITE_IF)
7802 code = cm_Lookup(dscp, lastNamep,
7803 CM_FLAG_FOLLOW, userp, &req, &scp);
7805 code = cm_Lookup(dscp, lastNamep,
7806 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7809 if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
7811 cm_ReleaseSCache(dscp);
7812 cm_ReleaseUser(userp);
7817 /* we have scp and dscp */
7819 /* we have scp but not dscp */
7821 smb_ReleaseFID(baseFidp);
7824 /* if we get here, if code is 0, the file exists and is represented by
7825 * scp. Otherwise, we have to create it. The dir may be represented
7826 * by dscp, or we may have found the file directly. If code is non-zero,
7831 * open the file itself
7832 * allocate the fidp early so the smb fid can be used by cm_CheckNTOpen()
7834 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7835 osi_assertx(fidp, "null smb_fid_t");
7837 /* save a reference to the user */
7839 fidp->userp = userp;
7841 if (code == 0 && !treeCreate) {
7842 code = cm_CheckNTOpen(scp, desiredAccess, shareAccess, createDisp, 0, fidp->fid, userp, &req, &ldp);
7844 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7846 cm_ReleaseSCache(dscp);
7848 cm_ReleaseSCache(scp);
7849 cm_ReleaseUser(userp);
7850 smb_CloseFID(vcp, fidp, NULL, 0);
7851 smb_ReleaseFID(fidp);
7855 checkDoneRequired = 1;
7857 if (createDisp == FILE_CREATE) {
7858 /* oops, file shouldn't be there */
7859 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7861 cm_ReleaseSCache(dscp);
7863 cm_ReleaseSCache(scp);
7864 cm_ReleaseUser(userp);
7865 smb_CloseFID(vcp, fidp, NULL, 0);
7866 smb_ReleaseFID(fidp);
7868 return CM_ERROR_EXISTS;
7871 if ( createDisp == FILE_OVERWRITE ||
7872 createDisp == FILE_OVERWRITE_IF) {
7874 setAttr.mask = CM_ATTRMASK_LENGTH;
7875 setAttr.length.LowPart = 0;
7876 setAttr.length.HighPart = 0;
7877 /* now watch for a symlink */
7879 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7881 osi_assertx(dscp != NULL, "null cm_scache_t");
7882 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7884 /* we have a more accurate file to use (the
7885 * target of the symbolic link). Otherwise,
7886 * we'll just use the symlink anyway.
7888 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7890 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7891 cm_ReleaseSCache(scp);
7893 code = cm_CheckNTOpen(scp, desiredAccess, shareAccess, createDisp, 0, fidp->fid, userp, &req, &ldp);
7895 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7897 cm_ReleaseSCache(dscp);
7899 cm_ReleaseSCache(scp);
7900 cm_ReleaseUser(userp);
7901 smb_CloseFID(vcp, fidp, NULL, 0);
7902 smb_ReleaseFID(fidp);
7908 code = cm_SetAttr(scp, &setAttr, userp, &req);
7909 openAction = 3; /* truncated existing file */
7912 openAction = 1; /* found existing file */
7914 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7915 /* don't create if not found */
7917 cm_ReleaseSCache(dscp);
7919 cm_ReleaseSCache(scp);
7920 cm_ReleaseUser(userp);
7921 smb_CloseFID(vcp, fidp, NULL, 0);
7922 smb_ReleaseFID(fidp);
7924 return CM_ERROR_NOSUCHFILE;
7925 } else if (realDirFlag == 0 || realDirFlag == -1) {
7926 osi_assertx(dscp != NULL, "null cm_scache_t");
7927 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %S",
7928 osi_LogSaveClientString(smb_logp, lastNamep));
7929 openAction = 2; /* created file */
7930 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7931 setAttr.clientModTime = time(NULL);
7932 smb_SetInitialModeBitsForFile(extAttributes, &setAttr);
7934 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
7937 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7938 smb_NotifyChange(FILE_ACTION_ADDED,
7939 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7940 dscp, lastNamep, NULL, TRUE);
7941 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7942 /* Not an exclusive create, and someone else tried
7943 * creating it already, then we open it anyway. We
7944 * don't bother retrying after this, since if this next
7945 * fails, that means that the file was deleted after we
7946 * started this call.
7948 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7951 if (createDisp == FILE_OVERWRITE_IF) {
7952 setAttr.mask = CM_ATTRMASK_LENGTH;
7953 setAttr.length.LowPart = 0;
7954 setAttr.length.HighPart = 0;
7956 /* now watch for a symlink */
7958 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7960 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7962 /* we have a more accurate file to use (the
7963 * target of the symbolic link). Otherwise,
7964 * we'll just use the symlink anyway.
7966 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7968 cm_ReleaseSCache(scp);
7972 code = cm_SetAttr(scp, &setAttr, userp, &req);
7974 } /* lookup succeeded */
7977 clientchar_t *tp, *pp;
7978 clientchar_t *cp; /* This component */
7979 int clen = 0; /* length of component */
7980 cm_scache_t *tscp1, *tscp2;
7983 /* create directory */
7985 treeStartp = lastNamep;
7986 osi_assertx(dscp != NULL, "null cm_scache_t");
7987 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%S]",
7988 osi_LogSaveClientString(smb_logp, treeStartp));
7989 openAction = 2; /* created directory */
7991 /* if the request is to create the root directory
7992 * it will appear as a directory name of the nul-string
7993 * and a code of CM_ERROR_NOSUCHFILE
7995 if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
7996 code = CM_ERROR_EXISTS;
7998 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7999 setAttr.clientModTime = time(NULL);
8000 smb_SetInitialModeBitsForDir(extAttributes, &setAttr);
8005 cm_HoldSCache(tscp1);
8009 tp = cm_ClientStrChr(pp, '\\');
8011 cm_ClientStrCpy(cp, lengthof(spacep->wdata) - (cp - spacep->wdata), pp);
8012 clen = (int)cm_ClientStrLen(cp);
8013 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
8015 clen = (int)(tp - pp);
8016 cm_ClientStrCpyN(cp, lengthof(spacep->wdata) - (cp - spacep->wdata),
8024 continue; /* the supplied path can't have consecutive slashes either , but */
8026 /* cp is the next component to be created. */
8027 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req, NULL);
8028 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
8029 smb_NotifyChange(FILE_ACTION_ADDED,
8030 FILE_NOTIFY_CHANGE_DIR_NAME,
8031 tscp1, cp, NULL, TRUE);
8033 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
8034 /* Not an exclusive create, and someone else tried
8035 * creating it already, then we open it anyway. We
8036 * don't bother retrying after this, since if this next
8037 * fails, that means that the file was deleted after we
8038 * started this call.
8040 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
8041 userp, &req, &tscp2);
8046 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
8047 cm_ReleaseSCache(tscp1);
8048 tscp1 = tscp2; /* Newly created directory will be next parent */
8049 /* the hold is transfered to tscp1 from tscp2 */
8054 cm_ReleaseSCache(dscp);
8057 cm_ReleaseSCache(scp);
8060 * if we get here and code == 0, then scp is the last directory created, and dscp is the
8066 /* something went wrong creating or truncating the file */
8067 if (checkDoneRequired)
8068 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8070 cm_ReleaseSCache(scp);
8072 cm_ReleaseSCache(dscp);
8073 cm_ReleaseUser(userp);
8074 smb_CloseFID(vcp, fidp, NULL, 0);
8075 smb_ReleaseFID(fidp);
8080 /* make sure we have file vs. dir right (only applies for single component case) */
8081 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
8082 /* now watch for a symlink */
8084 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8085 cm_scache_t * targetScp = 0;
8086 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8088 /* we have a more accurate file to use (the
8089 * target of the symbolic link). Otherwise,
8090 * we'll just use the symlink anyway.
8092 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
8093 if (checkDoneRequired) {
8094 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8095 checkDoneRequired = 0;
8097 cm_ReleaseSCache(scp);
8102 if (scp->fileType != CM_SCACHETYPE_FILE) {
8103 if (checkDoneRequired)
8104 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8106 cm_ReleaseSCache(dscp);
8107 cm_ReleaseSCache(scp);
8108 cm_ReleaseUser(userp);
8109 smb_CloseFID(vcp, fidp, NULL, 0);
8110 smb_ReleaseFID(fidp);
8112 return CM_ERROR_ISDIR;
8116 /* (only applies to single component case) */
8117 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8118 if (checkDoneRequired)
8119 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8120 cm_ReleaseSCache(scp);
8122 cm_ReleaseSCache(dscp);
8123 cm_ReleaseUser(userp);
8124 smb_CloseFID(vcp, fidp, NULL, 0);
8125 smb_ReleaseFID(fidp);
8127 return CM_ERROR_NOTDIR;
8130 /* If we are restricting sharing, we should do so with a suitable
8132 if (scp->fileType == CM_SCACHETYPE_FILE &&
8133 !(fidflags & SMB_FID_SHARE_WRITE)) {
8135 LARGE_INTEGER LOffset, LLength;
8138 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8139 LOffset.LowPart = SMB_FID_QLOCK_LOW;
8140 LLength.HighPart = 0;
8141 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8143 /* If we are not opening the file for writing, then we don't
8144 try to get an exclusive lock. No one else should be able to
8145 get an exclusive lock on the file anyway, although someone
8146 else can get a shared lock. */
8147 if ((fidflags & SMB_FID_SHARE_READ) ||
8148 !(fidflags & SMB_FID_OPENWRITE)) {
8149 sLockType = LOCKING_ANDX_SHARED_LOCK;
8154 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8156 lock_ObtainWrite(&scp->rw);
8157 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8158 lock_ReleaseWrite(&scp->rw);
8161 if (checkDoneRequired)
8162 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8163 cm_ReleaseSCache(scp);
8165 cm_ReleaseSCache(dscp);
8166 cm_ReleaseUser(userp);
8167 smb_CloseFID(vcp, fidp, NULL, 0);
8168 smb_ReleaseFID(fidp);
8170 return CM_ERROR_SHARING_VIOLATION;
8174 /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
8175 if (checkDoneRequired) {
8176 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8177 checkDoneRequired = 0;
8180 lock_ObtainMutex(&fidp->mx);
8181 /* save a pointer to the vnode */
8182 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
8183 lock_ObtainWrite(&scp->rw);
8184 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8185 lock_ReleaseWrite(&scp->rw);
8186 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
8188 fidp->flags = fidflags;
8190 /* remember if the file was newly created */
8192 fidp->flags |= SMB_FID_CREATED;
8194 /* save parent dir and pathname for delete or change notification */
8195 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8196 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
8197 fidp->flags |= SMB_FID_NTOPEN;
8198 fidp->NTopen_dscp = dscp;
8200 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
8202 fidp->NTopen_wholepathp = realPathp;
8203 lock_ReleaseMutex(&fidp->mx);
8205 /* we don't need this any longer */
8207 cm_ReleaseSCache(dscp);
8211 cm_Open(scp, 0, userp);
8213 /* set inp->fid so that later read calls in same msg can find fid */
8214 inp->fid = fidp->fid;
8216 lock_ObtainRead(&scp->rw);
8219 * Always send the standard response. Sending the extended
8220 * response results in the Explorer Shell being unable to
8221 * access directories at random times.
8223 if (1 /*!extendedRespRequired */) {
8226 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
8227 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
8228 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
8229 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8230 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8231 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8232 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8233 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8234 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
8236 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8237 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8238 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
8239 smb_SetSMBParm(outp, parmSlot, NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS);
8240 parmSlot++; /* dev state */
8241 smb_SetSMBParmByte(outp, parmSlot,
8242 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8243 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8244 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
8245 smb_SetSMBDataLength(outp, 0);
8249 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
8250 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
8251 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
8252 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8253 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8254 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8255 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8256 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8257 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
8259 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8260 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8261 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
8262 smb_SetSMBParm(outp, parmSlot, NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS);
8263 parmSlot++; /* dev state */
8264 smb_SetSMBParmByte(outp, parmSlot,
8265 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8266 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8267 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
8268 /* Setting the GUID results in a failure with cygwin */
8269 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8270 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8271 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8272 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8273 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8274 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8275 /* Maxmimal access rights */
8276 smb_SetSMBParmLong(outp, parmSlot, 0x001f01ff); parmSlot += 2;
8277 /* Guest access rights */
8278 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8279 smb_SetSMBDataLength(outp, 0);
8282 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
8283 LargeIntegerGreaterThanZero(scp->length) &&
8284 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
8287 lock_ReleaseRead(&scp->rw);
8290 cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
8291 scp->length.LowPart, scp->length.HighPart,
8295 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %S", fidp->fid,
8296 osi_LogSaveClientString(smb_logp, realPathp));
8298 cm_ReleaseUser(userp);
8299 smb_ReleaseFID(fidp);
8301 /* Can't free realPathp if we get here since
8302 fidp->NTopen_wholepathp is pointing there */
8304 /* leave scp held since we put it in fidp->scp */
8309 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
8310 * Instead, ultimately, would like to use a subroutine for common code.
8313 /* NT_TRANSACT_CREATE (SMB_COM_NT_TRANSACT) */
8314 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8316 clientchar_t *pathp, *realPathp;
8320 cm_scache_t *dscp; /* parent dir */
8321 cm_scache_t *scp; /* file to create or open */
8322 cm_scache_t *targetScp; /* if scp is a symlink */
8324 clientchar_t *lastNamep;
8325 unsigned long nameLength;
8327 unsigned int requestOpLock;
8328 unsigned int requestBatchOpLock;
8329 unsigned int mustBeDir;
8330 unsigned int extendedRespRequired;
8332 unsigned int desiredAccess;
8333 unsigned int allocSize;
8334 unsigned int shareAccess;
8335 unsigned int extAttributes;
8336 unsigned int createDisp;
8339 unsigned int impLevel;
8340 unsigned int secFlags;
8341 unsigned int createOptions;
8342 unsigned short baseFid;
8343 smb_fid_t *baseFidp;
8345 cm_scache_t *baseDirp;
8346 unsigned short openAction;
8350 clientchar_t *tidPathp;
8352 int parmOffset, dataOffset;
8359 cm_lock_data_t *ldp = NULL;
8360 int checkDoneRequired = 0;
8367 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8368 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8369 parmp = inp->data + parmOffset;
8370 lparmp = (ULONG *) parmp;
8373 requestOpLock = flags & REQUEST_OPLOCK;
8374 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
8375 mustBeDir = flags & OPEN_DIRECTORY;
8376 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
8379 * Why all of a sudden 32-bit FID?
8380 * We will reject all bits higher than 16.
8382 if (lparmp[1] & 0xFFFF0000)
8383 return CM_ERROR_INVAL;
8384 baseFid = (unsigned short)lparmp[1];
8385 desiredAccess = lparmp[2];
8386 allocSize = lparmp[3];
8387 extAttributes = lparmp[5];
8388 shareAccess = lparmp[6];
8389 createDisp = lparmp[7];
8390 createOptions = lparmp[8];
8393 nameLength = lparmp[11]; /* spec says chars but appears to be bytes */
8394 impLevel = lparmp[12];
8395 secFlags = lparmp[13];
8397 /* mustBeDir is never set; createOptions directory bit seems to be
8400 if (createOptions & FILE_DIRECTORY_FILE)
8402 else if (createOptions & FILE_NON_DIRECTORY_FILE)
8407 pathp = smb_ParseStringCb(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
8408 nameLength, NULL, SMB_STRF_ANSIPATH);
8409 /* Sometimes path is not nul-terminated, so we make a copy. */
8410 realPathp = malloc(nameLength+sizeof(clientchar_t));
8411 memcpy(realPathp, pathp, nameLength);
8412 realPathp[nameLength/sizeof(clientchar_t)] = 0;
8413 spacep = cm_GetSpace();
8414 /* smb_StripLastComponent will strip "::$DATA" if present */
8415 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
8417 osi_Log1(smb_logp,"NTTranCreate %S",osi_LogSaveStringW(smb_logp,realPathp));
8418 osi_Log4(smb_logp,"... da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
8419 osi_Log4(smb_logp,"... co[%x],sdl[%x],eal[%x],as[%x],flags[%x]",createOptions,sdLen,eaLen,allocSize);
8420 osi_Log3(smb_logp,"... imp[%x],sec[%x],flags[%x]", impLevel, secFlags, flags);
8422 if ( realDirFlag == 1 &&
8423 ( createDisp == FILE_SUPERSEDE ||
8424 createDisp == FILE_OVERWRITE ||
8425 createDisp == FILE_OVERWRITE_IF))
8427 osi_Log0(smb_logp, "NTTranCreate rejecting invalid readDirFlag and createDisp combination");
8428 cm_FreeSpace(spacep);
8430 return CM_ERROR_INVAL;
8434 * Nothing here to handle SMB_IOCTL_FILENAME.
8435 * Will add it if necessary.
8438 if (!cm_IsValidClientString(realPathp)) {
8440 clientchar_t * hexp;
8442 hexp = cm_GetRawCharsAlloc(realPathp, -1);
8443 osi_Log1(smb_logp, "NTTranCreate rejecting invalid name. [%S]",
8444 osi_LogSaveClientString(smb_logp, hexp));
8448 osi_Log0(smb_logp, "NTTranCreate rejecting invalid name.");
8450 cm_FreeSpace(spacep);
8452 return CM_ERROR_BADNTFILENAME;
8455 userp = smb_GetUserFromVCP(vcp, inp);
8457 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
8458 cm_FreeSpace(spacep);
8460 return CM_ERROR_INVAL;
8465 baseDirp = cm_RootSCachep(cm_rootUserp, &req);
8466 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8467 if (code == CM_ERROR_TIDIPC) {
8468 /* Attempt to use a TID allocated for IPC. The client
8469 * is probably looking for DCE RPC end points which we
8470 * don't support OR it could be looking to make a DFS
8473 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
8475 cm_FreeSpace(spacep);
8477 cm_ReleaseUser(userp);
8478 return CM_ERROR_NOSUCHPATH;
8482 baseFidp = smb_FindFID(vcp, baseFid, 0);
8484 osi_Log2(smb_logp, "NTTranCreate Unknown SMB Fid vcp 0x%p fid %d",
8486 cm_FreeSpace(spacep);
8488 cm_ReleaseUser(userp);
8489 return CM_ERROR_BADFD;
8492 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8493 cm_FreeSpace(spacep);
8495 cm_ReleaseUser(userp);
8496 smb_CloseFID(vcp, baseFidp, NULL, 0);
8497 smb_ReleaseFID(baseFidp);
8498 return CM_ERROR_NOSUCHPATH;
8501 baseDirp = baseFidp->scp;
8505 /* compute open mode */
8507 if (desiredAccess & DELETE)
8508 fidflags |= SMB_FID_OPENDELETE;
8509 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
8510 fidflags |= SMB_FID_OPENREAD_LISTDIR;
8511 if (desiredAccess & AFS_ACCESS_WRITE)
8512 fidflags |= SMB_FID_OPENWRITE;
8513 if (createOptions & FILE_DELETE_ON_CLOSE)
8514 fidflags |= SMB_FID_DELONCLOSE;
8515 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
8516 fidflags |= SMB_FID_SEQUENTIAL;
8517 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
8518 fidflags |= SMB_FID_RANDOM;
8519 if (createOptions & FILE_OPEN_REPARSE_POINT)
8520 osi_Log0(smb_logp, "NTTranCreate Open Reparse Point");
8521 if (smb_IsExecutableFileName(lastNamep))
8522 fidflags |= SMB_FID_EXECUTABLE;
8524 /* And the share mode */
8525 if (shareAccess & FILE_SHARE_READ)
8526 fidflags |= SMB_FID_SHARE_READ;
8527 if (shareAccess & FILE_SHARE_WRITE)
8528 fidflags |= SMB_FID_SHARE_WRITE;
8533 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8534 userp, tidPathp, &req, &dscp);
8537 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8538 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8539 cm_ReleaseSCache(dscp);
8540 cm_ReleaseUser(userp);
8541 cm_FreeSpace(spacep);
8544 smb_ReleaseFID(baseFidp);
8545 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8546 return CM_ERROR_PATH_NOT_COVERED;
8548 return CM_ERROR_NOSUCHPATH;
8550 #endif /* DFS_SUPPORT */
8551 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
8553 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
8555 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
8556 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
8557 if (code == 0 && realDirFlag == 1 &&
8558 (createDisp == FILE_OPEN ||
8559 createDisp == FILE_OVERWRITE ||
8560 createDisp == FILE_OVERWRITE_IF)) {
8561 cm_ReleaseSCache(scp);
8562 cm_ReleaseSCache(dscp);
8563 cm_ReleaseUser(userp);
8564 cm_FreeSpace(spacep);
8567 smb_ReleaseFID(baseFidp);
8568 return CM_ERROR_EXISTS;
8572 cm_ReleaseUser(userp);
8574 smb_ReleaseFID(baseFidp);
8575 cm_FreeSpace(spacep);
8577 return CM_ERROR_NOSUCHPATH;
8583 if (code == CM_ERROR_NOSUCHFILE ||
8584 code == CM_ERROR_NOSUCHPATH ||
8585 code == CM_ERROR_BPLUS_NOMATCH ||
8586 (code == 0 && (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)))) {
8589 cm_FreeSpace(spacep);
8592 smb_ReleaseFID(baseFidp);
8595 cm_ReleaseSCache(dscp);
8596 cm_ReleaseUser(userp);
8602 lastNamep = realPathp;
8606 if (!smb_IsLegalFilename(lastNamep)) {
8607 cm_ReleaseSCache(dscp);
8608 cm_ReleaseUser(userp);
8610 return CM_ERROR_BADNTFILENAME;
8614 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF || createDisp == FILE_OPEN_IF) {
8615 code = cm_Lookup(dscp, lastNamep,
8616 CM_FLAG_FOLLOW, userp, &req, &scp);
8618 code = cm_Lookup(dscp, lastNamep,
8619 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8622 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8623 cm_ReleaseSCache(dscp);
8624 cm_ReleaseUser(userp);
8631 smb_ReleaseFID(baseFidp);
8632 cm_FreeSpace(spacep);
8635 /* if we get here, if code is 0, the file exists and is represented by
8636 * scp. Otherwise, we have to create it. The dir may be represented
8637 * by dscp, or we may have found the file directly. If code is non-zero,
8641 code = cm_CheckNTOpen(scp, desiredAccess, shareAccess, createDisp, 0, fidp->fid, userp, &req, &ldp);
8643 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8644 cm_ReleaseSCache(dscp);
8645 cm_ReleaseSCache(scp);
8646 cm_ReleaseUser(userp);
8650 checkDoneRequired = 1;
8652 if (createDisp == FILE_CREATE) {
8653 /* oops, file shouldn't be there */
8654 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8655 cm_ReleaseSCache(dscp);
8656 cm_ReleaseSCache(scp);
8657 cm_ReleaseUser(userp);
8659 return CM_ERROR_EXISTS;
8662 if (createDisp == FILE_OVERWRITE ||
8663 createDisp == FILE_OVERWRITE_IF) {
8664 setAttr.mask = CM_ATTRMASK_LENGTH;
8665 setAttr.length.LowPart = 0;
8666 setAttr.length.HighPart = 0;
8668 /* now watch for a symlink */
8670 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8672 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8674 /* we have a more accurate file to use (the
8675 * target of the symbolic link). Otherwise,
8676 * we'll just use the symlink anyway.
8678 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8680 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8681 cm_ReleaseSCache(scp);
8683 code = cm_CheckNTOpen(scp, desiredAccess, shareAccess, createDisp, 0, fidp->fid, userp, &req, &ldp);
8685 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8686 cm_ReleaseSCache(dscp);
8688 cm_ReleaseSCache(scp);
8689 cm_ReleaseUser(userp);
8695 code = cm_SetAttr(scp, &setAttr, userp, &req);
8696 openAction = 3; /* truncated existing file */
8698 else openAction = 1; /* found existing file */
8700 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
8701 /* don't create if not found */
8702 cm_ReleaseSCache(dscp);
8703 cm_ReleaseUser(userp);
8705 return CM_ERROR_NOSUCHFILE;
8707 else if (realDirFlag == 0 || realDirFlag == -1) {
8708 /* createDisp: FILE_SUPERSEDE, FILE_CREATE, FILE_OPEN_IF, FILE_OVERWRITE_IF */
8709 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %S",
8710 osi_LogSaveClientString(smb_logp, lastNamep));
8711 openAction = 2; /* created file */
8712 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8713 setAttr.clientModTime = time(NULL);
8714 smb_SetInitialModeBitsForFile(extAttributes, &setAttr);
8716 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8720 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8721 smb_NotifyChange(FILE_ACTION_ADDED,
8722 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8723 dscp, lastNamep, NULL, TRUE);
8724 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
8725 /* Not an exclusive create, and someone else tried
8726 * creating it already, then we open it anyway. We
8727 * don't bother retrying after this, since if this next
8728 * fails, that means that the file was deleted after we
8729 * started this call.
8731 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8734 if (createDisp == FILE_OVERWRITE_IF) {
8735 setAttr.mask = CM_ATTRMASK_LENGTH;
8736 setAttr.length.LowPart = 0;
8737 setAttr.length.HighPart = 0;
8739 /* now watch for a symlink */
8741 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8743 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8745 /* we have a more accurate file to use (the
8746 * target of the symbolic link). Otherwise,
8747 * we'll just use the symlink anyway.
8749 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8751 cm_ReleaseSCache(scp);
8755 code = cm_SetAttr(scp, &setAttr, userp, &req);
8757 } /* lookup succeeded */
8760 /* create directory; createDisp: FILE_CREATE, FILE_OPEN_IF */
8762 "smb_ReceiveNTTranCreate creating directory %S",
8763 osi_LogSaveClientString(smb_logp, lastNamep));
8764 openAction = 2; /* created directory */
8765 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8766 setAttr.clientModTime = time(NULL);
8767 smb_SetInitialModeBitsForDir(extAttributes, &setAttr);
8769 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8770 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8771 smb_NotifyChange(FILE_ACTION_ADDED,
8772 FILE_NOTIFY_CHANGE_DIR_NAME,
8773 dscp, lastNamep, NULL, TRUE);
8775 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
8776 /* Not an exclusive create, and someone else tried
8777 * creating it already, then we open it anyway. We
8778 * don't bother retrying after this, since if this next
8779 * fails, that means that the file was deleted after we
8780 * started this call.
8782 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8788 /* something went wrong creating or truncating the file */
8789 if (checkDoneRequired)
8790 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8792 cm_ReleaseSCache(scp);
8793 cm_ReleaseUser(userp);
8798 /* make sure we have file vs. dir right */
8799 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
8800 /* now watch for a symlink */
8802 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8804 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8806 /* we have a more accurate file to use (the
8807 * target of the symbolic link). Otherwise,
8808 * we'll just use the symlink anyway.
8810 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8812 if (checkDoneRequired) {
8813 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8814 checkDoneRequired = 0;
8816 cm_ReleaseSCache(scp);
8821 if (scp->fileType != CM_SCACHETYPE_FILE) {
8822 if (checkDoneRequired)
8823 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8824 cm_ReleaseSCache(scp);
8825 cm_ReleaseUser(userp);
8827 return CM_ERROR_ISDIR;
8831 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8832 if (checkDoneRequired)
8833 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8834 cm_ReleaseSCache(scp);
8835 cm_ReleaseUser(userp);
8837 return CM_ERROR_NOTDIR;
8840 /* open the file itself */
8841 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8842 osi_assertx(fidp, "null smb_fid_t");
8844 /* save a reference to the user */
8846 fidp->userp = userp;
8848 /* If we are restricting sharing, we should do so with a suitable
8850 if (scp->fileType == CM_SCACHETYPE_FILE &&
8851 !(fidflags & SMB_FID_SHARE_WRITE)) {
8853 LARGE_INTEGER LOffset, LLength;
8856 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8857 LOffset.LowPart = SMB_FID_QLOCK_LOW;
8858 LLength.HighPart = 0;
8859 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8861 /* Similar to what we do in handling NTCreateX. We get a
8862 shared lock if we are only opening the file for reading. */
8863 if ((fidflags & SMB_FID_SHARE_READ) ||
8864 !(fidflags & SMB_FID_OPENWRITE)) {
8865 sLockType = LOCKING_ANDX_SHARED_LOCK;
8870 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8872 lock_ObtainWrite(&scp->rw);
8873 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8874 lock_ReleaseWrite(&scp->rw);
8877 if (checkDoneRequired)
8878 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8879 cm_ReleaseSCache(scp);
8880 cm_ReleaseUser(userp);
8881 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
8882 smb_CloseFID(vcp, fidp, NULL, 0);
8883 smb_ReleaseFID(fidp);
8885 return CM_ERROR_SHARING_VIOLATION;
8889 /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
8890 if (checkDoneRequired) {
8891 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8892 checkDoneRequired = 0;
8895 lock_ObtainMutex(&fidp->mx);
8896 /* save a pointer to the vnode */
8898 lock_ObtainWrite(&scp->rw);
8899 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8900 lock_ReleaseWrite(&scp->rw);
8901 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
8903 fidp->flags = fidflags;
8905 /* remember if the file was newly created */
8907 fidp->flags |= SMB_FID_CREATED;
8909 /* save parent dir and pathname for deletion or change notification */
8910 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8911 fidp->flags |= SMB_FID_NTOPEN;
8912 fidp->NTopen_dscp = dscp;
8913 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
8915 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
8917 fidp->NTopen_wholepathp = realPathp;
8918 lock_ReleaseMutex(&fidp->mx);
8920 /* we don't need this any longer */
8922 cm_ReleaseSCache(dscp);
8924 cm_Open(scp, 0, userp);
8926 /* set inp->fid so that later read calls in same msg can find fid */
8927 inp->fid = fidp->fid;
8929 /* check whether we are required to send an extended response */
8930 if (!extendedRespRequired) {
8932 parmOffset = 8*4 + 39;
8933 parmOffset += 1; /* pad to 4 */
8934 dataOffset = parmOffset + 70;
8938 /* Total Parameter Count */
8939 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8940 /* Total Data Count */
8941 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8942 /* Parameter Count */
8943 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8944 /* Parameter Offset */
8945 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8946 /* Parameter Displacement */
8947 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8949 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8951 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8952 /* Data Displacement */
8953 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8954 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8955 smb_SetSMBDataLength(outp, 70);
8957 lock_ObtainRead(&scp->rw);
8958 outData = smb_GetSMBData(outp, NULL);
8959 outData++; /* round to get to parmOffset */
8960 *outData = 0; outData++; /* oplock */
8961 *outData = 0; outData++; /* reserved */
8962 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8963 *((ULONG *)outData) = openAction; outData += 4;
8964 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8965 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8966 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8967 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8968 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8969 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8970 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8971 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8972 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8973 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8974 *((USHORT *)outData) = NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS;
8975 outData += 2; /* dev state */
8976 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8977 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8978 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8979 outData += 2; /* is a dir? */
8982 parmOffset = 8*4 + 39;
8983 parmOffset += 1; /* pad to 4 */
8984 dataOffset = parmOffset + 104;
8988 /* Total Parameter Count */
8989 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8990 /* Total Data Count */
8991 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8992 /* Parameter Count */
8993 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8994 /* Parameter Offset */
8995 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8996 /* Parameter Displacement */
8997 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8999 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9001 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
9002 /* Data Displacement */
9003 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9004 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
9005 smb_SetSMBDataLength(outp, 105);
9007 lock_ObtainRead(&scp->rw);
9008 outData = smb_GetSMBData(outp, NULL);
9009 outData++; /* round to get to parmOffset */
9010 *outData = 0; outData++; /* oplock */
9011 *outData = 1; outData++; /* response type */
9012 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
9013 *((ULONG *)outData) = openAction; outData += 4;
9014 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
9015 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
9016 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
9017 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
9018 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
9019 *((FILETIME *)outData) = ft; outData += 8; /* change time */
9020 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
9021 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
9022 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
9023 *((USHORT *)outData) = 0; outData += 2; /* filetype */
9024 *((USHORT *)outData) = NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS;
9025 outData += 2; /* dev state */
9026 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
9027 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
9028 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
9029 outData += 1; /* is a dir? */
9030 /* Setting the GUID results in failures with cygwin */
9031 memset(outData,0,24); outData += 24; /* GUID */
9032 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
9033 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
9036 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
9037 LargeIntegerGreaterThanZero(scp->length) &&
9038 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
9041 lock_ReleaseRead(&scp->rw);
9044 cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
9045 scp->length.LowPart, scp->length.HighPart,
9048 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
9050 cm_ReleaseUser(userp);
9051 smb_ReleaseFID(fidp);
9053 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
9054 /* leave scp held since we put it in fidp->scp */
9058 /* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
9059 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
9062 smb_packet_t *savedPacketp;
9064 USHORT fid, watchtree;
9068 filter = smb_GetSMBParm(inp, 19) |
9069 (smb_GetSMBParm(inp, 20) << 16);
9070 fid = smb_GetSMBParm(inp, 21);
9071 watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
9073 fidp = smb_FindFID(vcp, fid, 0);
9075 osi_Log2(smb_logp, "NotifyChange Unknown SMB Fid vcp 0x%p fid %d",
9077 return CM_ERROR_BADFD;
9080 lock_ObtainMutex(&fidp->mx);
9081 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
9082 lock_ReleaseMutex(&fidp->mx);
9083 smb_CloseFID(vcp, fidp, NULL, 0);
9084 smb_ReleaseFID(fidp);
9085 return CM_ERROR_NOSUCHFILE;
9089 lock_ReleaseMutex(&fidp->mx);
9091 /* Create a copy of the Directory Watch Packet to use when sending the
9092 * notification if in the future a matching change is detected.
9094 savedPacketp = smb_CopyPacket(inp);
9095 if (vcp != savedPacketp->vcp) {
9097 if (savedPacketp->vcp)
9098 smb_ReleaseVC(savedPacketp->vcp);
9099 savedPacketp->vcp = vcp;
9102 /* Add the watch to the list of events to send notifications for */
9103 lock_ObtainMutex(&smb_Dir_Watch_Lock);
9104 savedPacketp->nextp = smb_Directory_Watches;
9105 smb_Directory_Watches = savedPacketp;
9106 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9108 osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%S\"",
9109 fidp, scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp));
9110 osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
9111 filter, fid, watchtree);
9112 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
9113 osi_Log0(smb_logp, " Notify Change File Name");
9114 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
9115 osi_Log0(smb_logp, " Notify Change Directory Name");
9116 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
9117 osi_Log0(smb_logp, " Notify Change Attributes");
9118 if (filter & FILE_NOTIFY_CHANGE_SIZE)
9119 osi_Log0(smb_logp, " Notify Change Size");
9120 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
9121 osi_Log0(smb_logp, " Notify Change Last Write");
9122 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
9123 osi_Log0(smb_logp, " Notify Change Last Access");
9124 if (filter & FILE_NOTIFY_CHANGE_CREATION)
9125 osi_Log0(smb_logp, " Notify Change Creation");
9126 if (filter & FILE_NOTIFY_CHANGE_EA)
9127 osi_Log0(smb_logp, " Notify Change Extended Attributes");
9128 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
9129 osi_Log0(smb_logp, " Notify Change Security");
9130 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
9131 osi_Log0(smb_logp, " Notify Change Stream Name");
9132 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
9133 osi_Log0(smb_logp, " Notify Change Stream Size");
9134 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
9135 osi_Log0(smb_logp, " Notify Change Stream Write");
9137 lock_ObtainWrite(&scp->rw);
9139 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
9141 scp->flags |= CM_SCACHEFLAG_WATCHED;
9142 lock_ReleaseWrite(&scp->rw);
9143 cm_ReleaseSCache(scp);
9144 smb_ReleaseFID(fidp);
9146 outp->flags |= SMB_PACKETFLAG_NOSEND;
9150 unsigned char nullSecurityDesc[] = {
9151 0x01, /* security descriptor revision */
9152 0x00, /* reserved, should be zero */
9153 0x04, 0x80, /* security descriptor control;
9154 * 0x0004 : null-DACL present - everyone has full access
9155 * 0x8000 : relative format */
9156 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
9157 0x20, 0x00, 0x00, 0x00, /* offset of group SID */
9158 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
9159 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
9160 0x01, 0x01, 0x00, 0x00, /* "everyone SID" owner SID */
9161 0x00, 0x00, 0x00, 0x01,
9162 0x00, 0x00, 0x00, 0x00,
9163 0x01, 0x01, 0x00, 0x00, /* "everyone SID" owner SID */
9164 0x00, 0x00, 0x00, 0x01,
9165 0x00, 0x00, 0x00, 0x00
9168 /* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
9169 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9171 int parmOffset, parmCount, dataOffset, dataCount;
9172 int totalParmCount, totalDataCount;
9174 int maxData, maxParm;
9175 int inTotalParm, inTotalData;
9177 int inParmOffset, inDataOffset;
9183 ULONG securityInformation;
9189 * For details on the meanings of the various
9190 * SMB_COM_TRANSACTION fields, see sections 2.2.4.33
9191 * of http://msdn.microsoft.com/en-us/library/ee442092%28PROT.13%29.aspx
9194 inTotalParm = smb_GetSMBOffsetParm(inp, 1, 1)
9195 | (smb_GetSMBOffsetParm(inp, 2, 1) << 16);
9197 inTotalData = smb_GetSMBOffsetParm(inp, 3, 1)
9198 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
9200 maxParm = smb_GetSMBOffsetParm(inp, 5, 1)
9201 | (smb_GetSMBOffsetParm(inp, 6, 1) << 16);
9203 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
9204 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
9206 inParm = smb_GetSMBOffsetParm(inp, 9, 1)
9207 | (smb_GetSMBOffsetParm(inp, 10, 1) << 16);
9209 inParmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
9210 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
9212 inData = smb_GetSMBOffsetParm(inp, 13, 1)
9213 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
9215 inDataOffset = smb_GetSMBOffsetParm(inp, 15, 1)
9216 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
9218 parmp = inp->data + inParmOffset;
9219 sparmp = (USHORT *) parmp;
9220 lparmp = (ULONG *) parmp;
9223 securityInformation = lparmp[1];
9225 fidp = smb_FindFID(vcp, fid, 0);
9227 osi_Log2(smb_logp, "smb_ReceiveNTTranQuerySecurityDesc Unknown SMB Fid vcp 0x%p fid %d",
9229 return CM_ERROR_BADFD;
9232 lock_ObtainMutex(&fidp->mx);
9233 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
9234 lock_ReleaseMutex(&fidp->mx);
9235 smb_CloseFID(vcp, fidp, NULL, 0);
9236 smb_ReleaseFID(fidp);
9237 return CM_ERROR_NOSUCHFILE;
9239 lock_ReleaseMutex(&fidp->mx);
9241 osi_Log4(smb_logp,"smb_ReceiveNTTranQuerySecurityDesc fidp 0x%p scp 0x%p file \"%S\" Info=0x%x",
9242 fidp, fidp->scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp),
9243 securityInformation);
9245 smb_ReleaseFID(fidp);
9247 if ( securityInformation & ~(OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION) )
9249 code = CM_ERROR_BAD_LEVEL;
9253 dwLength = sizeof( nullSecurityDesc);
9255 totalDataCount = dwLength;
9258 if (maxData >= totalDataCount) {
9259 dataCount = totalDataCount;
9260 parmCount = min(totalParmCount, maxParm);
9261 } else if (maxParm >= totalParmCount) {
9262 totalDataCount = dataCount = 0;
9263 parmCount = totalParmCount;
9265 totalDataCount = dataCount = 0;
9266 totalParmCount = parmCount = 0;
9270 parmOffset = 8*4 + 39;
9271 parmOffset += 1; /* pad to 4 */
9273 dataOffset = parmOffset + parmCount;
9277 /* Total Parameter Count */
9278 smb_SetSMBParmLong(outp, parmSlot, totalParmCount); parmSlot += 2;
9279 /* Total Data Count */
9280 smb_SetSMBParmLong(outp, parmSlot, totalDataCount); parmSlot += 2;
9281 /* Parameter Count */
9282 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
9283 /* Parameter Offset */
9284 smb_SetSMBParmLong(outp, parmSlot, parmCount ? parmOffset : 0); parmSlot += 2;
9285 /* Parameter Displacement */
9286 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9288 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
9290 smb_SetSMBParmLong(outp, parmSlot, dataCount ? dataOffset : 0); parmSlot += 2;
9291 /* Data Displacement */
9292 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9294 smb_SetSMBParmByte(outp, parmSlot, 0);
9296 if (parmCount == totalParmCount && dwLength == dataCount) {
9297 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
9300 outData = smb_GetSMBData(outp, NULL);
9301 outData++; /* round to get to dataOffset */
9303 *((ULONG *)outData) = dataCount; outData += 4; /* SD Length (4 bytes) */
9304 memcpy(outData, nullSecurityDesc, dataCount);
9305 outData += dataCount;
9308 } else if (parmCount >= 4) {
9309 smb_SetSMBDataLength(outp, 1 + parmCount);
9312 outData = smb_GetSMBData(outp, NULL);
9313 outData++; /* round to get to dataOffset */
9315 *((ULONG *)outData) = dwLength; outData += 4; /* SD Length (4 bytes) */
9316 code = CM_ERROR_BUFFERTOOSMALL;
9318 smb_SetSMBDataLength(outp, 0);
9319 code = CM_ERROR_BUFFER_OVERFLOW;
9326 /* SMB_COM_NT_TRANSACT
9328 SMB_COM_NT_TRANSACT_SECONDARY should also be handled here.
9330 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9332 unsigned short function;
9334 function = smb_GetSMBParm(inp, 18);
9336 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
9338 /* We can handle long names */
9339 if (vcp->flags & SMB_VCFLAG_USENT)
9340 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
9343 case 1: /* NT_TRANSACT_CREATE */
9344 return smb_ReceiveNTTranCreate(vcp, inp, outp);
9345 case 2: /* NT_TRANSACT_IOCTL */
9346 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
9348 case 3: /* NT_TRANSACT_SET_SECURITY_DESC */
9349 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
9351 case 4: /* NT_TRANSACT_NOTIFY_CHANGE */
9352 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
9353 case 5: /* NT_TRANSACT_RENAME */
9354 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
9356 case 6: /* NT_TRANSACT_QUERY_SECURITY_DESC */
9357 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
9359 osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
9362 osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
9365 return CM_ERROR_BADOP;
9369 * smb_NotifyChange -- find relevant change notification messages and
9372 * If we don't know the file name (i.e. a callback break), filename is
9373 * NULL, and we return a zero-length list.
9375 * At present there is not a single call to smb_NotifyChange that
9376 * has the isDirectParent parameter set to FALSE.
9378 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
9379 cm_scache_t *dscp, clientchar_t *filename, clientchar_t *otherFilename,
9380 BOOL isDirectParent)
9382 smb_packet_t *watch, *lastWatch, *nextWatch;
9383 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen = 0;
9384 char *outData, *oldOutData;
9388 BOOL twoEntries = FALSE;
9389 ULONG otherNameLen, oldParmCount = 0;
9393 /* Get ready for rename within directory */
9394 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
9396 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
9399 osi_Log4(smb_logp,"in smb_NotifyChange for file [%S] dscp [%p] notification 0x%x parent %d",
9400 osi_LogSaveClientString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
9402 osi_Log0(smb_logp," FILE_ACTION_NONE");
9403 if (action == FILE_ACTION_ADDED)
9404 osi_Log0(smb_logp," FILE_ACTION_ADDED");
9405 if (action == FILE_ACTION_REMOVED)
9406 osi_Log0(smb_logp," FILE_ACTION_REMOVED");
9407 if (action == FILE_ACTION_MODIFIED)
9408 osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
9409 if (action == FILE_ACTION_RENAMED_OLD_NAME)
9410 osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
9411 if (action == FILE_ACTION_RENAMED_NEW_NAME)
9412 osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
9414 lock_ObtainMutex(&smb_Dir_Watch_Lock);
9415 watch = smb_Directory_Watches;
9417 filter = smb_GetSMBParm(watch, 19)
9418 | (smb_GetSMBParm(watch, 20) << 16);
9419 fid = smb_GetSMBParm(watch, 21);
9420 wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
9422 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
9423 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
9426 * Strange hack - bug in NT Client and NT Server that we must emulate?
9428 if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
9429 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
9431 fidp = smb_FindFID(watch->vcp, fid, 0);
9433 osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
9435 watch = watch->nextp;
9439 if (fidp->scp != dscp ||
9440 fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
9441 (filter & notifyFilter) == 0 ||
9442 (!isDirectParent && !wtree))
9444 osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
9446 watch = watch->nextp;
9447 smb_ReleaseFID(fidp);
9452 "Sending Change Notification for fid %d filter 0x%x wtree %d file %S",
9453 fid, filter, wtree, osi_LogSaveClientString(smb_logp, filename));
9454 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
9455 osi_Log0(smb_logp, " Notify Change File Name");
9456 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
9457 osi_Log0(smb_logp, " Notify Change Directory Name");
9458 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
9459 osi_Log0(smb_logp, " Notify Change Attributes");
9460 if (filter & FILE_NOTIFY_CHANGE_SIZE)
9461 osi_Log0(smb_logp, " Notify Change Size");
9462 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
9463 osi_Log0(smb_logp, " Notify Change Last Write");
9464 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
9465 osi_Log0(smb_logp, " Notify Change Last Access");
9466 if (filter & FILE_NOTIFY_CHANGE_CREATION)
9467 osi_Log0(smb_logp, " Notify Change Creation");
9468 if (filter & FILE_NOTIFY_CHANGE_EA)
9469 osi_Log0(smb_logp, " Notify Change Extended Attributes");
9470 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
9471 osi_Log0(smb_logp, " Notify Change Security");
9472 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
9473 osi_Log0(smb_logp, " Notify Change Stream Name");
9474 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
9475 osi_Log0(smb_logp, " Notify Change Stream Size");
9476 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
9477 osi_Log0(smb_logp, " Notify Change Stream Write");
9479 /* A watch can only be notified once. Remove it from the list */
9480 nextWatch = watch->nextp;
9481 if (watch == smb_Directory_Watches)
9482 smb_Directory_Watches = nextWatch;
9484 lastWatch->nextp = nextWatch;
9486 /* Turn off WATCHED flag in dscp */
9487 lock_ObtainWrite(&dscp->rw);
9489 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
9491 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
9492 lock_ReleaseWrite(&dscp->rw);
9494 /* Convert to response packet */
9495 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
9496 #ifdef SEND_CANONICAL_PATHNAMES
9497 ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
9499 ((smb_t *) watch)->wct = 0;
9502 if (filename == NULL) {
9505 nameLen = (ULONG)cm_ClientStrLen(filename);
9506 parmCount = 3*4 + nameLen*2;
9507 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
9509 otherNameLen = (ULONG)cm_ClientStrLen(otherFilename);
9510 oldParmCount = parmCount;
9511 parmCount += 3*4 + otherNameLen*2;
9512 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
9514 if (maxLen < parmCount)
9515 parmCount = 0; /* not enough room */
9517 parmOffset = 8*4 + 39;
9518 parmOffset += 1; /* pad to 4 */
9519 dataOffset = parmOffset + parmCount;
9523 /* Total Parameter Count */
9524 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
9525 /* Total Data Count */
9526 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9527 /* Parameter Count */
9528 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
9529 /* Parameter Offset */
9530 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
9531 /* Parameter Displacement */
9532 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9534 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9536 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
9537 /* Data Displacement */
9538 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9539 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
9540 smb_SetSMBDataLength(watch, parmCount + 1);
9542 if (parmCount != 0) {
9543 outData = smb_GetSMBData(watch, NULL);
9544 outData++; /* round to get to parmOffset */
9545 oldOutData = outData;
9546 *((DWORD *)outData) = oldParmCount; outData += 4;
9547 /* Next Entry Offset */
9548 *((DWORD *)outData) = action; outData += 4;
9550 *((DWORD *)outData) = nameLen*2; outData += 4;
9551 /* File Name Length */
9553 smb_UnparseString(watch, outData, filename, NULL, 0);
9557 outData = oldOutData + oldParmCount;
9558 *((DWORD *)outData) = 0; outData += 4;
9559 /* Next Entry Offset */
9560 *((DWORD *)outData) = otherAction; outData += 4;
9562 *((DWORD *)outData) = otherNameLen*2;
9563 outData += 4; /* File Name Length */
9564 smb_UnparseString(watch, outData, otherFilename, NULL, 0);
9569 * If filename is null, we don't know the cause of the
9570 * change notification. We return zero data (see above),
9571 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
9572 * (= 0x010C). We set the error code here by hand, without
9573 * modifying wct and bcc.
9575 if (filename == NULL) {
9576 ((smb_t *) watch)->rcls = 0x0C;
9577 ((smb_t *) watch)->reh = 0x01;
9578 ((smb_t *) watch)->errLow = 0;
9579 ((smb_t *) watch)->errHigh = 0;
9580 /* Set NT Status codes flag */
9581 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9584 smb_SendPacket(watch->vcp, watch);
9585 smb_FreePacket(watch);
9587 smb_ReleaseFID(fidp);
9590 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9593 /* SMB_COM_NT_CANCEL */
9594 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9596 unsigned char *replyWctp;
9597 smb_packet_t *watch, *lastWatch;
9598 USHORT fid, watchtree;
9602 osi_Log0(smb_logp, "SMB3 receive NT cancel");
9604 lock_ObtainMutex(&smb_Dir_Watch_Lock);
9605 watch = smb_Directory_Watches;
9607 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
9608 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
9609 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
9610 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
9611 if (watch == smb_Directory_Watches)
9612 smb_Directory_Watches = watch->nextp;
9614 lastWatch->nextp = watch->nextp;
9615 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9617 /* Turn off WATCHED flag in scp */
9618 fid = smb_GetSMBParm(watch, 21);
9619 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
9621 if (vcp != watch->vcp)
9622 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
9625 fidp = smb_FindFID(vcp, fid, 0);
9627 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %S",
9629 (fidp ? osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp) :_C("")));
9632 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
9634 lock_ObtainWrite(&scp->rw);
9636 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
9638 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
9639 lock_ReleaseWrite(&scp->rw);
9641 smb_ReleaseFID(fidp);
9643 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
9646 /* assume STATUS32; return 0xC0000120 (CANCELED) */
9647 replyWctp = watch->wctp;
9651 ((smb_t *)watch)->rcls = 0x20;
9652 ((smb_t *)watch)->reh = 0x1;
9653 ((smb_t *)watch)->errLow = 0;
9654 ((smb_t *)watch)->errHigh = 0xC0;
9655 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9656 smb_SendPacket(vcp, watch);
9657 smb_FreePacket(watch);
9661 watch = watch->nextp;
9663 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9669 * NT rename also does hard links.
9672 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
9673 #define RENAME_FLAG_HARD_LINK 0x103
9674 #define RENAME_FLAG_RENAME 0x104
9675 #define RENAME_FLAG_COPY 0x105
9677 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9679 clientchar_t *oldPathp, *newPathp;
9685 attrs = smb_GetSMBParm(inp, 0);
9686 rename_type = smb_GetSMBParm(inp, 1);
9688 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
9689 osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
9690 return CM_ERROR_NOACCESS;
9693 tp = smb_GetSMBData(inp, NULL);
9694 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
9696 return CM_ERROR_BADSMB;
9697 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
9699 return CM_ERROR_BADSMB;
9701 osi_Log3(smb_logp, "NTRename for [%S]->[%S] type [%s]",
9702 osi_LogSaveClientString(smb_logp, oldPathp),
9703 osi_LogSaveClientString(smb_logp, newPathp),
9704 ((rename_type==RENAME_FLAG_RENAME)?"rename":(rename_type==RENAME_FLAG_HARD_LINK)?"hardlink":"other"));
9706 if (rename_type == RENAME_FLAG_RENAME) {
9707 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
9708 } else if (rename_type == RENAME_FLAG_HARD_LINK) { /* RENAME_FLAG_HARD_LINK */
9709 code = smb_Link(vcp,inp,oldPathp,newPathp);
9711 code = CM_ERROR_BADOP;
9717 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock", LOCK_HIERARCHY_SMB_DIRWATCH);
9720 cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
9722 smb_username_t *unp;
9725 unp = smb_FindUserByName(usern, machine, flags);
9727 lock_ObtainMutex(&unp->mx);
9728 unp->userp = cm_NewUser();
9729 lock_ReleaseMutex(&unp->mx);
9730 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9732 osi_Log2(smb_logp,"smb_FindCMUserByName Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9736 smb_ReleaseUsername(unp);
9740 cm_user_t *smb_FindCMUserBySID(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
9742 smb_username_t *unp;
9745 unp = smb_FindUserByName(usern, machine, flags);
9747 lock_ObtainMutex(&unp->mx);
9748 unp->flags |= SMB_USERNAMEFLAG_SID;
9749 unp->userp = cm_NewUser();
9750 lock_ReleaseMutex(&unp->mx);
9751 osi_Log2(smb_logp,"smb_FindCMUserBySID New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9753 osi_Log2(smb_logp,"smb_FindCMUserBySID Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9757 smb_ReleaseUsername(unp);