2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
15 #pragma warning(disable: 4005)
17 #define SECURITY_WIN32
30 #include <WINNT\afsreg.h>
36 extern osi_hyper_t hzero;
38 smb_packet_t *smb_Directory_Watches = NULL;
39 osi_mutex_t smb_Dir_Watch_Lock;
41 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
43 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
45 /* protected by the smb_globalLock */
46 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
48 const clientchar_t **smb_ExecutableExtensions = NULL;
50 /* retrieve a held reference to a user structure corresponding to an incoming
52 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
57 uidp = smb_FindUID(vcp, inp->uid, 0);
61 up = smb_GetUserFromUID(uidp);
69 * Return boolean specifying if the path name is thought to be an
70 * executable file. For now .exe or .dll.
72 afs_uint32 smb_IsExecutableFileName(const clientchar_t *name)
76 if ( smb_ExecutableExtensions == NULL || name == NULL)
79 len = (int)cm_ClientStrLen(name);
81 for ( i=0; smb_ExecutableExtensions[i]; i++) {
82 j = len - (int)cm_ClientStrLen(smb_ExecutableExtensions[i]);
83 if (cm_ClientStrCmpI(smb_ExecutableExtensions[i], &name[j]) == 0)
91 * Return extended attributes.
92 * Right now, we aren't using any of the "new" bits, so this looks exactly
93 * like smb_Attributes() (see smb.c).
95 unsigned long smb_ExtAttributes(cm_scache_t *scp)
99 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
100 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
101 scp->fileType == CM_SCACHETYPE_INVALID)
103 attrs = SMB_ATTR_DIRECTORY;
104 #ifdef SPECIAL_FOLDERS
105 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
106 #endif /* SPECIAL_FOLDERS */
107 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
108 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
109 } else if (scp->fid.vnode & 0x1)
110 attrs = SMB_ATTR_DIRECTORY;
115 * We used to mark a file RO if it was in an RO volume, but that
116 * turns out to be impolitic in NT. See defect 10007.
119 if ((scp->unixModeBits & 0200) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
120 attrs |= SMB_ATTR_READONLY; /* Read-only */
122 if ((scp->unixModeBits & 0200) == 0)
123 attrs |= SMB_ATTR_READONLY; /* Read-only */
127 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
132 int smb_V3IsStarMask(clientchar_t *maskp)
136 while (tc = *maskp++)
137 if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
142 void OutputDebugF(clientchar_t * format, ...) {
144 clientchar_t vbuffer[1024];
146 va_start( args, format );
147 cm_ClientStrPrintfV(vbuffer, lengthof(vbuffer), format, args);
148 osi_Log1(smb_logp, "%S", osi_LogSaveClientString(smb_logp, vbuffer));
151 void OutputDebugHexDump(unsigned char * buffer, int len) {
154 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
156 OutputDebugF(_C("Hexdump length [%d]"),len);
158 for (i=0;i<len;i++) {
161 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
163 StringCchPrintfA(buf, lengthof(buf), "%5x", i);
164 memset(buf+5,' ',80);
169 j = j*3 + 7 + ((j>7)?1:0);
172 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
175 j = j + 56 + ((j>7)?1:0);
177 buf[j] = (k>32 && k<127)?k:'.';
180 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
184 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
186 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
187 SECURITY_STATUS status, istatus;
188 CredHandle creds = {0,0};
190 SecBufferDesc secOut;
198 OutputDebugF(_C("Negotiating Extended Security"));
200 status = AcquireCredentialsHandle( NULL,
201 SMB_EXT_SEC_PACKAGE_NAME,
210 if (status != SEC_E_OK) {
211 /* Really bad. We return an empty security blob */
212 OutputDebugF(_C("AcquireCredentialsHandle failed with %lX"), status);
217 secOut.pBuffers = &secTok;
218 secOut.ulVersion = SECBUFFER_VERSION;
220 secTok.BufferType = SECBUFFER_TOKEN;
222 secTok.pvBuffer = NULL;
224 ctx.dwLower = ctx.dwUpper = 0;
226 status = AcceptSecurityContext( &creds,
229 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
230 SECURITY_NETWORK_DREP,
237 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
238 OutputDebugF(_C("Completing token..."));
239 istatus = CompleteAuthToken(&ctx, &secOut);
240 if ( istatus != SEC_E_OK )
241 OutputDebugF(_C("Token completion failed: %x"), istatus);
244 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
245 if (secTok.pvBuffer) {
246 *secBlobLength = secTok.cbBuffer;
247 *secBlob = malloc( secTok.cbBuffer );
248 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
251 if ( status != SEC_E_OK )
252 OutputDebugF(_C("AcceptSecurityContext status != CONTINUE %lX"), status);
255 /* Discard partial security context */
256 DeleteSecurityContext(&ctx);
258 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
260 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
261 FreeCredentialsHandle(&creds);
268 smb_GetLogonSID(HANDLE hToken, PSID *ppsid)
270 BOOL bSuccess = FALSE;
273 PTOKEN_GROUPS ptg = NULL;
275 // Verify the parameter passed in is not NULL.
279 // Get required buffer size and allocate the TOKEN_GROUPS buffer.
281 if (!GetTokenInformation( hToken, // handle to the access token
282 TokenGroups, // get information about the token's groups
283 (LPVOID) ptg, // pointer to TOKEN_GROUPS buffer
285 &dwLength // receives required buffer size
288 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
291 ptg = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(),
292 HEAP_ZERO_MEMORY, dwLength);
298 // Get the token group information from the access token.
300 if (!GetTokenInformation( hToken, // handle to the access token
301 TokenGroups, // get information about the token's groups
302 (LPVOID) ptg, // pointer to TOKEN_GROUPS buffer
303 dwLength, // size of buffer
304 &dwLength // receives required buffer size
310 // Loop through the groups to find the logon SID.
311 for (dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++) {
312 if ((ptg->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID)
314 // Found the logon SID; make a copy of it.
316 dwLength = GetLengthSid(ptg->Groups[dwIndex].Sid);
317 *ppsid = (PSID) HeapAlloc(GetProcessHeap(),
318 HEAP_ZERO_MEMORY, dwLength);
321 if (!CopySid(dwLength, *ppsid, ptg->Groups[dwIndex].Sid))
323 HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
333 // Free the buffer for the token groups.
335 HeapFree(GetProcessHeap(), 0, (LPVOID)ptg);
341 smb_GetUserSID(HANDLE hToken, PSID *ppsid)
343 BOOL bSuccess = FALSE;
345 PTOKEN_USER ptu = NULL;
347 // Verify the parameter passed in is not NULL.
351 // Get required buffer size and allocate the TOKEN_USER buffer.
353 if (!GetTokenInformation( hToken, // handle to the access token
354 TokenUser, // get information about the token's user
355 (LPVOID) ptu, // pointer to TOKEN_USER buffer
357 &dwLength // receives required buffer size
360 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
363 ptu = (PTOKEN_USER)HeapAlloc(GetProcessHeap(),
364 HEAP_ZERO_MEMORY, dwLength);
370 // Get the token group information from the access token.
372 if (!GetTokenInformation( hToken, // handle to the access token
373 TokenUser, // get information about the token's user
374 (LPVOID) ptu, // pointer to TOKEN_USER buffer
375 dwLength, // size of buffer
376 &dwLength // receives required buffer size
382 // Found the user SID; make a copy of it.
383 dwLength = GetLengthSid(ptu->User.Sid);
384 *ppsid = (PSID) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
387 if (!CopySid(dwLength, *ppsid, ptu->User.Sid))
389 HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
396 // Free the buffer for the token groups.
398 HeapFree(GetProcessHeap(), 0, (LPVOID)ptu);
404 smb_FreeSID (PSID psid)
406 HeapFree(GetProcessHeap(), 0, (LPVOID)psid);
410 struct smb_ext_context {
417 long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern,
418 char * secBlobIn, int secBlobInLength,
419 char ** secBlobOut, int * secBlobOutLength,
420 wchar_t **secSidString) {
421 SECURITY_STATUS status, istatus;
425 SecBufferDesc secBufIn;
427 SecBufferDesc secBufOut;
430 struct smb_ext_context * secCtx = NULL;
431 struct smb_ext_context * newSecCtx = NULL;
432 void * assembledBlob = NULL;
433 int assembledBlobLength = 0;
436 OutputDebugF(_C("In smb_AuthenticateUserExt"));
439 *secBlobOutLength = 0;
440 *secSidString = NULL;
442 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
443 secCtx = vcp->secCtx;
444 lock_ObtainMutex(&vcp->mx);
445 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
447 lock_ReleaseMutex(&vcp->mx);
451 OutputDebugF(_C("Received incoming token:"));
452 OutputDebugHexDump(secBlobIn,secBlobInLength);
456 OutputDebugF(_C("Continuing with existing context."));
457 creds = secCtx->creds;
460 if (secCtx->partialToken) {
461 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
462 assembledBlob = malloc(assembledBlobLength);
463 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
464 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
467 status = AcquireCredentialsHandle( NULL,
468 SMB_EXT_SEC_PACKAGE_NAME,
477 if (status != SEC_E_OK) {
478 OutputDebugF(_C("Can't acquire Credentials handle [%lX]"), status);
479 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
487 secBufIn.cBuffers = 1;
488 secBufIn.pBuffers = &secTokIn;
489 secBufIn.ulVersion = SECBUFFER_VERSION;
491 secTokIn.BufferType = SECBUFFER_TOKEN;
493 secTokIn.cbBuffer = assembledBlobLength;
494 secTokIn.pvBuffer = assembledBlob;
496 secTokIn.cbBuffer = secBlobInLength;
497 secTokIn.pvBuffer = secBlobIn;
500 secBufOut.cBuffers = 1;
501 secBufOut.pBuffers = &secTokOut;
502 secBufOut.ulVersion = SECBUFFER_VERSION;
504 secTokOut.BufferType = SECBUFFER_TOKEN;
505 secTokOut.cbBuffer = 0;
506 secTokOut.pvBuffer = NULL;
508 status = AcceptSecurityContext( &creds,
509 ((secCtx)?&ctx:NULL),
511 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
512 SECURITY_NETWORK_DREP,
519 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
520 OutputDebugF(_C("Completing token..."));
521 istatus = CompleteAuthToken(&ctx, &secBufOut);
522 if ( istatus != SEC_E_OK )
523 OutputDebugF(_C("Token completion failed: %lX"), istatus);
526 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
527 OutputDebugF(_C("Continue needed"));
529 newSecCtx = malloc(sizeof(*newSecCtx));
531 newSecCtx->creds = creds;
532 newSecCtx->ctx = ctx;
533 newSecCtx->partialToken = NULL;
534 newSecCtx->partialTokenLen = 0;
536 lock_ObtainMutex( &vcp->mx );
537 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
538 vcp->secCtx = newSecCtx;
539 lock_ReleaseMutex( &vcp->mx );
541 code = CM_ERROR_GSSCONTINUE;
544 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
545 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
546 secTokOut.pvBuffer) {
547 OutputDebugF(_C("Need to send token back to client"));
549 *secBlobOutLength = secTokOut.cbBuffer;
550 *secBlobOut = malloc(secTokOut.cbBuffer);
551 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
553 OutputDebugF(_C("Outgoing token:"));
554 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
555 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
556 OutputDebugF(_C("Incomplete message"));
558 newSecCtx = malloc(sizeof(*newSecCtx));
560 newSecCtx->creds = creds;
561 newSecCtx->ctx = ctx;
562 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
563 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
564 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
566 lock_ObtainMutex( &vcp->mx );
567 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
568 vcp->secCtx = newSecCtx;
569 lock_ReleaseMutex( &vcp->mx );
571 code = CM_ERROR_GSSCONTINUE;
574 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
577 SecPkgContext_NamesW names;
579 OutputDebugF(_C("Authentication completed"));
580 OutputDebugF(_C("Returned flags : [%lX]"), flags);
582 if (!QueryContextAttributesW(&ctx, SECPKG_ATTR_NAMES, &names)) {
583 OutputDebugF(_C("Received name [%s]"), names.sUserName);
584 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, names.sUserName);
585 cm_ClientStrLwr(usern); /* in tandem with smb_GetNormalizedUsername */
586 FreeContextBuffer(names.sUserName);
588 /* Force the user to retry if the context is invalid */
589 OutputDebugF(_C("QueryContextAttributes Names failed [%x]"), GetLastError());
590 code = CM_ERROR_BADPASSWORD;
593 /* Obtain the user's SID */
594 if (code == 0 && !QuerySecurityContextToken(((secCtx)?&ctx:NULL), &hToken)) {
596 OutputDebugF(_C("Received hToken"));
598 if (smb_GetUserSID(hToken, &pSid))
599 ConvertSidToStringSidW(pSid, secSidString);
605 OutputDebugF(_C("QueryContextToken failed [%x]"), GetLastError());
609 case SEC_E_INVALID_TOKEN:
610 OutputDebugF(_C("Returning bad password :: INVALID_TOKEN"));
612 case SEC_E_INVALID_HANDLE:
613 OutputDebugF(_C("Returning bad password :: INVALID_HANDLE"));
615 case SEC_E_LOGON_DENIED:
616 OutputDebugF(_C("Returning bad password :: LOGON_DENIED"));
618 case SEC_E_UNKNOWN_CREDENTIALS:
619 OutputDebugF(_C("Returning bad password :: UNKNOWN_CREDENTIALS"));
621 case SEC_E_NO_CREDENTIALS:
622 OutputDebugF(_C("Returning bad password :: NO_CREDENTIALS"));
624 case SEC_E_CONTEXT_EXPIRED:
625 OutputDebugF(_C("Returning bad password :: CONTEXT_EXPIRED"));
627 case SEC_E_INCOMPLETE_CREDENTIALS:
628 OutputDebugF(_C("Returning bad password :: INCOMPLETE_CREDENTIALS"));
630 case SEC_E_WRONG_PRINCIPAL:
631 OutputDebugF(_C("Returning bad password :: WRONG_PRINCIPAL"));
633 case SEC_E_TIME_SKEW:
634 OutputDebugF(_C("Returning bad password :: TIME_SKEW"));
637 OutputDebugF(_C("Returning bad password :: Status == %lX"), status);
639 code = CM_ERROR_BADPASSWORD;
643 if (secCtx->partialToken) free(secCtx->partialToken);
651 if (secTokOut.pvBuffer)
652 FreeContextBuffer(secTokOut.pvBuffer);
654 if (code != CM_ERROR_GSSCONTINUE) {
655 DeleteSecurityContext(&ctx);
656 FreeCredentialsHandle(&creds);
664 #define P_RESP_LEN 128
666 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
667 So put stuff in a struct. */
668 struct Lm20AuthBlob {
669 MSV1_0_LM20_LOGON lmlogon;
670 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
671 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
672 WCHAR accountNameW[P_LEN];
673 WCHAR primaryDomainW[P_LEN];
674 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
675 TOKEN_GROUPS tgroups;
676 TOKEN_SOURCE tsource;
679 long smb_AuthenticateUserLM(smb_vc_t *vcp, clientchar_t * accountName, clientchar_t * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
682 struct Lm20AuthBlob lmAuth;
683 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
684 QUOTA_LIMITS quotaLimits;
686 ULONG lmprofilepSize;
690 OutputDebugF(_C("In smb_AuthenticateUser for user [%s] domain [%s]"), accountName, primaryDomain);
691 OutputDebugF(_C("ciPwdLength is %d and csPwdLength is %d"), ciPwdLength, csPwdLength);
693 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
694 OutputDebugF(_C("ciPwdLength or csPwdLength is too long"));
695 return CM_ERROR_BADPASSWORD;
698 memset(&lmAuth,0,sizeof(lmAuth));
700 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
702 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
703 cm_ClientStringToUtf16(primaryDomain, -1, lmAuth.primaryDomainW, P_LEN);
704 lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
705 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
707 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
708 cm_ClientStringToUtf16(accountName, -1, lmAuth.accountNameW, P_LEN);
709 lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
710 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
712 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
713 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
714 size = MAX_COMPUTERNAME_LENGTH + 1;
715 GetComputerNameW(lmAuth.workstationW, &size);
716 lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
718 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
720 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
721 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
722 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
723 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
725 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
726 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
727 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
728 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
730 lmAuth.lmlogon.ParameterControl = 0;
732 lmAuth.tgroups.GroupCount = 0;
733 lmAuth.tgroups.Groups[0].Sid = NULL;
734 lmAuth.tgroups.Groups[0].Attributes = 0;
737 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
739 lmAuth.tsource.SourceIdentifier.HighPart = 0;
741 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
742 StringCchCopyA(lmAuth.tsource.SourceName, lengthof(lmAuth.tsource.SourceName),
743 "OpenAFS"); /* 8 char limit */
745 nts = LsaLogonUser( smb_lsaHandle,
760 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
761 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
764 OutputDebugF(_C("Return from LsaLogonUser is 0x%lX"), nts);
765 OutputDebugF(_C("Extended status is 0x%lX"), ntsEx);
767 if (nts == ERROR_SUCCESS) {
769 LsaFreeReturnBuffer(lmprofilep);
770 CloseHandle(lmToken);
774 if (nts == 0xC000015BL)
775 return CM_ERROR_BADLOGONTYPE;
776 else /* our catchall is a bad password though we could be more specific */
777 return CM_ERROR_BADPASSWORD;
781 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
782 long smb_GetNormalizedUsername(clientchar_t * usern, const clientchar_t * accountName, const clientchar_t * domainName)
784 clientchar_t * atsign;
785 const clientchar_t * domain;
787 /* check if we have sane input */
788 if ((cm_ClientStrLen(accountName) + cm_ClientStrLen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
791 /* we could get : [accountName][domainName]
797 atsign = cm_ClientStrChr(accountName, '@');
799 if (atsign) /* [user@domain][] -> [user@domain][domain] */
804 /* if for some reason the client doesn't know what domain to use,
805 it will either return an empty string or a '?' */
806 if (!domain[0] || domain[0] == '?')
807 /* Empty domains and empty usernames are usually sent from tokenless contexts.
808 This way such logins will get an empty username (easy to check). I don't know
809 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
810 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, accountName);
812 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
813 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, domain);
814 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, _C("\\"));
816 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
818 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
821 cm_ClientStrLwr(usern);
826 /* When using SMB auth, all SMB sessions have to pass through here
827 * first to authenticate the user.
829 * Caveat: If not using SMB auth, the protocol does not require
830 * sending a session setup packet, which means that we can't rely on a
831 * UID in subsequent packets. Though in practice we get one anyway.
833 /* SMB_COM_SESSION_SETUP_ANDX */
834 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
838 unsigned short newUid;
839 unsigned long caps = 0;
841 clientchar_t *s1 = _C(" ");
843 clientchar_t usern[SMB_MAX_USERNAME_LENGTH];
845 char *secBlobOut = NULL;
846 int secBlobOutLength = 0;
847 wchar_t *secSidString = 0;
848 int maxBufferSize = 0;
852 /* Check for bad conns */
853 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
854 return CM_ERROR_REMOTECONN;
857 maxBufferSize = smb_GetSMBParm(inp, 2);
858 maxMpxCount = smb_GetSMBParm(inp, 3);
859 vcNumber = smb_GetSMBParm(inp, 4);
861 osi_Log3(smb_logp, "SESSION_SETUP_ANDX with MaxBufferSize=%d, MaxMpxCount=%d, VCNumber=%d",
862 maxBufferSize, maxMpxCount, vcNumber);
864 if (maxMpxCount > smb_maxMpxRequests) {
865 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_MPX_COUNT, maxMpxCount, smb_maxMpxRequests);
866 osi_Log2(smb_logp, "MaxMpxCount for client is too large (Client=%d, Server=%d)",
867 maxMpxCount, smb_maxMpxRequests);
870 if (maxBufferSize < SMB_PACKETSIZE) {
871 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_BUFFER_SIZE, maxBufferSize, SMB_PACKETSIZE);
872 osi_Log2(smb_logp, "MaxBufferSize for client is too small (Client=%d, Server=%d)",
873 maxBufferSize, SMB_PACKETSIZE);
877 osi_Log0(smb_logp, "Resetting all VCs");
878 smb_MarkAllVCsDead(vcp);
881 if (vcp->flags & SMB_VCFLAG_USENT) {
882 if (smb_authType == SMB_AUTH_EXTENDED) {
883 /* extended authentication */
887 OutputDebugF(_C("NT Session Setup: Extended"));
889 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
890 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
893 secBlobInLength = smb_GetSMBParm(inp, 7);
894 secBlobIn = smb_GetSMBData(inp, NULL);
896 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength, &secSidString);
898 if (code == CM_ERROR_GSSCONTINUE) {
901 smb_SetSMBParm(outp, 2, 0);
902 smb_SetSMBParm(outp, 3, secBlobOutLength);
904 tp = smb_GetSMBData(outp, NULL);
905 if (secBlobOutLength) {
906 memcpy(tp, secBlobOut, secBlobOutLength);
908 tp += secBlobOutLength;
909 cb_data += secBlobOutLength;
911 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
912 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
913 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
915 smb_SetSMBDataLength(outp, cb_data);
918 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
920 unsigned ciPwdLength, csPwdLength;
922 clientchar_t *accountName;
923 clientchar_t *primaryDomain;
926 if (smb_authType == SMB_AUTH_NTLM)
927 OutputDebugF(_C("NT Session Setup: NTLM"));
929 OutputDebugF(_C("NT Session Setup: None"));
931 /* TODO: parse for extended auth as well */
932 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
933 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
935 tp = smb_GetSMBData(inp, &datalen);
937 OutputDebugF(_C("Session packet data size [%d]"),datalen);
944 accountName = smb_ParseString(inp, tp, &tp, 0);
945 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
947 OutputDebugF(_C("Account Name: %s"),accountName);
948 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
949 OutputDebugF(_C("Case Sensitive Password: %s"),
950 csPwd && csPwd[0] ? _C("yes") : _C("no"));
951 OutputDebugF(_C("Case Insensitive Password: %s"),
952 ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
954 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
955 /* shouldn't happen */
956 code = CM_ERROR_BADSMB;
957 goto after_read_packet;
960 /* capabilities are only valid for first session packet */
961 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
962 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
965 if (smb_authType == SMB_AUTH_NTLM) {
966 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
968 OutputDebugF(_C("LM authentication failed [%d]"), code);
970 OutputDebugF(_C("LM authentication succeeded"));
974 unsigned ciPwdLength;
976 clientchar_t *accountName;
977 clientchar_t *primaryDomain;
979 switch ( smb_authType ) {
980 case SMB_AUTH_EXTENDED:
981 OutputDebugF(_C("V3 Session Setup: Extended"));
984 OutputDebugF(_C("V3 Session Setup: NTLM"));
987 OutputDebugF(_C("V3 Session Setup: None"));
989 ciPwdLength = smb_GetSMBParm(inp, 7);
990 tp = smb_GetSMBData(inp, NULL);
994 accountName = smb_ParseString(inp, tp, &tp, 0);
995 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
997 OutputDebugF(_C("Account Name: %s"),accountName);
998 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
999 OutputDebugF(_C("Case Insensitive Password: %s"), ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
1001 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
1002 /* shouldn't happen */
1003 code = CM_ERROR_BADSMB;
1004 goto after_read_packet;
1007 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
1010 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
1011 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
1013 OutputDebugF(_C("LM authentication failed [%d]"), code);
1015 OutputDebugF(_C("LM authentication succeeded"));
1020 /* note down that we received a session setup X and set the capabilities flag */
1021 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
1022 lock_ObtainMutex(&vcp->mx);
1023 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
1024 /* for the moment we can only deal with NTSTATUS */
1025 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
1026 vcp->flags |= SMB_VCFLAG_STATUS32;
1030 if ((caps & NTNEGOTIATE_CAPABILITY_UNICODE) && smb_UseUnicode) {
1031 vcp->flags |= SMB_VCFLAG_USEUNICODE;
1034 lock_ReleaseMutex(&vcp->mx);
1037 /* code would be non-zero if there was an authentication failure.
1038 Ideally we would like to invalidate the uid for this session or break
1039 early to avoid accidently stealing someone else's tokens. */
1043 LocalFree(secSidString);
1048 * If the SidString for the user could be obtained, use that
1052 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, secSidString);
1056 OutputDebugF(_C("Received username=[%s]"), usern);
1058 /* On Windows 2000, this function appears to be called more often than
1059 it is expected to be called. This resulted in multiple smb_user_t
1060 records existing all for the same user session which results in all
1061 of the users tokens disappearing.
1063 To avoid this problem, we look for an existing smb_user_t record
1064 based on the users name, and use that one if we find it.
1067 uidp = smb_FindUserByNameThisSession(vcp, usern);
1068 if (uidp) { /* already there, so don't create a new one */
1070 newUid = uidp->userID;
1071 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
1072 vcp->lana,vcp->lsn,newUid);
1073 smb_ReleaseUID(uidp);
1078 /* do a global search for the username/machine name pair */
1079 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
1080 lock_ObtainMutex(&unp->mx);
1081 if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
1082 /* clear the afslogon flag so that the tickets can now
1083 * be freed when the refCount returns to zero.
1085 unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
1088 unp->flags |= SMB_USERNAMEFLAG_SID;
1089 lock_ReleaseMutex(&unp->mx);
1091 /* Create a new UID and cm_user_t structure */
1094 userp = cm_NewUser();
1095 cm_HoldUserVCRef(userp);
1096 lock_ObtainMutex(&vcp->mx);
1097 if (!vcp->uidCounter)
1098 vcp->uidCounter++; /* handle unlikely wraparounds */
1099 newUid = (cm_ClientStrLen(usern)==0)?0:vcp->uidCounter++;
1100 lock_ReleaseMutex(&vcp->mx);
1102 /* Create a new smb_user_t structure and connect them up */
1103 lock_ObtainMutex(&unp->mx);
1105 lock_ReleaseMutex(&unp->mx);
1107 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
1109 lock_ObtainMutex(&uidp->mx);
1111 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
1112 lock_ReleaseMutex(&uidp->mx);
1113 smb_ReleaseUID(uidp);
1117 /* Return UID to the client */
1118 ((smb_t *)outp)->uid = newUid;
1119 /* Also to the next chained message */
1120 ((smb_t *)inp)->uid = newUid;
1122 osi_Log3(smb_logp, "SMB3 session setup name %S creating ID %d%S",
1123 osi_LogSaveClientString(smb_logp, usern), newUid,
1124 osi_LogSaveClientString(smb_logp, s1));
1126 smb_SetSMBParm(outp, 2, 0);
1128 if (vcp->flags & SMB_VCFLAG_USENT) {
1129 if (smb_authType == SMB_AUTH_EXTENDED) {
1132 smb_SetSMBParm(outp, 3, secBlobOutLength);
1134 tp = smb_GetSMBData(outp, NULL);
1135 if (secBlobOutLength) {
1136 memcpy(tp, secBlobOut, secBlobOutLength);
1138 tp += secBlobOutLength;
1139 cb_data += secBlobOutLength;
1142 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
1143 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
1144 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
1146 smb_SetSMBDataLength(outp, cb_data);
1148 smb_SetSMBDataLength(outp, 0);
1151 if (smb_authType == SMB_AUTH_EXTENDED) {
1154 tp = smb_GetSMBData(outp, NULL);
1156 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
1157 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
1158 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
1160 smb_SetSMBDataLength(outp, cb_data);
1162 smb_SetSMBDataLength(outp, 0);
1167 LocalFree(secSidString);
1171 /* SMB_COM_LOGOFF_ANDX */
1172 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1176 /* find the tree and free it */
1177 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1179 smb_username_t * unp;
1181 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %S", uidp->userID,
1182 osi_LogSaveClientString(smb_logp, (uidp->unp) ? uidp->unp->name: _C(" ")));
1184 lock_ObtainMutex(&uidp->mx);
1185 uidp->flags |= SMB_USERFLAG_DELETE;
1187 * it doesn't get deleted right away
1188 * because the vcp points to it
1191 lock_ReleaseMutex(&uidp->mx);
1194 /* we can't do this. we get logoff messages prior to a session
1195 * disconnect even though it doesn't mean the user is logging out.
1196 * we need to create a new pioctl and EventLogoff handler to set
1197 * SMB_USERNAMEFLAG_LOGOFF.
1199 if (unp && smb_LogoffTokenTransfer) {
1200 lock_ObtainMutex(&unp->mx);
1201 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
1202 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
1203 lock_ReleaseMutex(&unp->mx);
1207 smb_ReleaseUID(uidp);
1210 osi_Log0(smb_logp, "SMB3 user logoffX");
1212 smb_SetSMBDataLength(outp, 0);
1216 #define SMB_SUPPORT_SEARCH_BITS 0x0001
1217 #define SMB_SHARE_IS_IN_DFS 0x0002
1219 /* SMB_COM_TREE_CONNECT_ANDX */
1220 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1223 smb_user_t *uidp = NULL;
1224 unsigned short newTid;
1225 clientchar_t shareName[AFSPATHMAX];
1226 clientchar_t *sharePath;
1229 clientchar_t *slashp;
1230 clientchar_t *pathp;
1231 clientchar_t *passwordp;
1232 clientchar_t *servicep;
1233 cm_user_t *userp = NULL;
1236 osi_Log0(smb_logp, "SMB3 receive tree connect");
1238 /* parse input parameters */
1239 tp = smb_GetSMBData(inp, NULL);
1240 passwordp = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1241 pathp = smb_ParseString(inp, tp, &tp, SMB_STRF_ANSIPATH);
1242 servicep = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1244 slashp = cm_ClientStrRChr(pathp, '\\');
1246 return CM_ERROR_BADSMB;
1248 cm_ClientStrCpy(shareName, lengthof(shareName), slashp+1);
1250 osi_Log3(smb_logp, "Tree connect pathp[%S] shareName[%S] service[%S]",
1251 osi_LogSaveClientString(smb_logp, pathp),
1252 osi_LogSaveClientString(smb_logp, shareName),
1253 osi_LogSaveClientString(smb_logp, servicep));
1255 if (cm_ClientStrCmp(servicep, _C("IPC")) == 0 ||
1256 cm_ClientStrCmp(shareName, _C("IPC$")) == 0) {
1258 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1261 return CM_ERROR_NOIPC;
1265 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1267 userp = smb_GetUserFromUID(uidp);
1269 lock_ObtainMutex(&vcp->mx);
1270 newTid = vcp->tidCounter++;
1271 lock_ReleaseMutex(&vcp->mx);
1273 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1276 if (!cm_ClientStrCmp(shareName, _C("*.")))
1277 cm_ClientStrCpy(shareName, lengthof(shareName), _C("all"));
1278 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1281 smb_ReleaseUID(uidp);
1282 smb_ReleaseTID(tidp, FALSE);
1283 return CM_ERROR_BADSHARENAME;
1286 if (vcp->flags & SMB_VCFLAG_USENT)
1288 int policy = smb_FindShareCSCPolicy(shareName);
1291 DWORD dwAdvertiseDFS = 0, dwSize = sizeof(DWORD);
1293 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1294 0, KEY_QUERY_VALUE, &parmKey);
1295 if (code == ERROR_SUCCESS) {
1296 code = RegQueryValueEx(parmKey, "AdvertiseDFS", NULL, NULL,
1297 (BYTE *)&dwAdvertiseDFS, &dwSize);
1298 if (code != ERROR_SUCCESS)
1300 RegCloseKey (parmKey);
1302 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1303 (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
1307 smb_SetSMBParm(outp, 2, 0);
1311 smb_ReleaseUID(uidp);
1313 lock_ObtainMutex(&tidp->mx);
1314 tidp->userp = userp;
1315 tidp->pathname = sharePath;
1317 tidp->flags |= SMB_TIDFLAG_IPC;
1318 lock_ReleaseMutex(&tidp->mx);
1319 smb_ReleaseTID(tidp, FALSE);
1321 ((smb_t *)outp)->tid = newTid;
1322 ((smb_t *)inp)->tid = newTid;
1323 tp = smb_GetSMBData(outp, NULL);
1327 tp = smb_UnparseString(outp, tp, _C("A:"), &cb_data, SMB_STRF_FORCEASCII);
1328 tp = smb_UnparseString(outp, tp, _C("AFS"), &cb_data, 0);
1329 smb_SetSMBDataLength(outp, cb_data);
1333 tp = smb_UnparseString(outp, tp, _C("IPC"), &cb_data, SMB_STRF_FORCEASCII);
1334 smb_SetSMBDataLength(outp, cb_data);
1337 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1341 /* must be called with global tran lock held */
1342 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1344 smb_tran2Packet_t *tp;
1347 smbp = (smb_t *) inp->data;
1348 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1349 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1355 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1356 int totalParms, int totalData)
1358 smb_tran2Packet_t *tp;
1361 smbp = (smb_t *) inp->data;
1362 tp = malloc(sizeof(*tp));
1363 memset(tp, 0, sizeof(*tp));
1366 tp->curData = tp->curParms = 0;
1367 tp->totalData = totalData;
1368 tp->totalParms = totalParms;
1369 tp->tid = smbp->tid;
1370 tp->mid = smbp->mid;
1371 tp->uid = smbp->uid;
1372 tp->pid = smbp->pid;
1373 tp->res[0] = smbp->res[0];
1374 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1375 if (totalParms != 0)
1376 tp->parmsp = malloc(totalParms);
1378 tp->datap = malloc(totalData);
1379 if (smbp->com == 0x25 || smbp->com == 0x26)
1382 tp->opcode = smb_GetSMBParm(inp, 14);
1385 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1387 if (WANTS_UNICODE(inp) && (vcp->flags & SMB_VCFLAG_USEUNICODE))
1388 tp->flags |= SMB_TRAN2PFLAG_USEUNICODE;
1393 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1394 smb_tran2Packet_t *inp, smb_packet_t *outp,
1395 int totalParms, int totalData)
1397 smb_tran2Packet_t *tp;
1398 unsigned short parmOffset;
1399 unsigned short dataOffset;
1400 unsigned short dataAlign;
1402 tp = malloc(sizeof(*tp));
1403 memset(tp, 0, sizeof(*tp));
1406 tp->curData = tp->curParms = 0;
1407 tp->totalData = totalData;
1408 tp->totalParms = totalParms;
1409 tp->oldTotalParms = totalParms;
1414 tp->res[0] = inp->res[0];
1415 tp->opcode = inp->opcode;
1419 * We calculate where the parameters and data will start.
1420 * This calculation must parallel the calculation in
1421 * smb_SendTran2Packet.
1424 parmOffset = 10*2 + 35;
1425 parmOffset++; /* round to even */
1426 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1428 dataOffset = parmOffset + totalParms;
1429 dataAlign = dataOffset & 2; /* quad-align */
1430 dataOffset += dataAlign;
1431 tp->datap = outp->data + dataOffset;
1436 /* free a tran2 packet */
1437 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1440 smb_ReleaseVC(t2p->vcp);
1443 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1453 while (t2p->stringsp) {
1457 t2p->stringsp = ns->nextp;
1463 clientchar_t *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
1464 char ** chainpp, int flags)
1469 if (!(p->flags & SMB_TRAN2PFLAG_USEUNICODE))
1470 flags |= SMB_STRF_FORCEASCII;
1473 cb = p->totalParms - (inp - (char *)p->parmsp);
1474 if (inp < (char *) p->parmsp ||
1475 inp >= ((char *) p->parmsp) + p->totalParms) {
1476 #ifdef DEBUG_UNICODE
1482 return smb_ParseStringBuf((unsigned char *) p->parmsp, &p->stringsp,
1483 inp, &cb, chainpp, flags);
1486 /* called with a VC, an input packet to respond to, and an error code.
1487 * sends an error response.
1489 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1490 smb_packet_t *tp, long code)
1493 unsigned short errCode;
1494 unsigned char errClass;
1495 unsigned long NTStatus;
1497 if (vcp->flags & SMB_VCFLAG_STATUS32)
1498 smb_MapNTError(code, &NTStatus);
1500 smb_MapCoreError(code, vcp, &errCode, &errClass);
1502 smb_FormatResponsePacket(vcp, NULL, tp);
1503 smbp = (smb_t *) tp;
1505 /* We can handle long names */
1506 if (vcp->flags & SMB_VCFLAG_USENT)
1507 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1509 /* now copy important fields from the tran 2 packet */
1510 smbp->com = t2p->com;
1511 smbp->tid = t2p->tid;
1512 smbp->mid = t2p->mid;
1513 smbp->pid = t2p->pid;
1514 smbp->uid = t2p->uid;
1515 smbp->res[0] = t2p->res[0];
1516 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1517 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1518 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1519 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1520 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1521 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1524 smbp->rcls = errClass;
1525 smbp->errLow = (unsigned char) (errCode & 0xff);
1526 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1530 smb_SendPacket(vcp, tp);
1533 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1536 unsigned short parmOffset;
1537 unsigned short dataOffset;
1538 unsigned short totalLength;
1539 unsigned short dataAlign;
1542 smb_FormatResponsePacket(vcp, NULL, tp);
1543 smbp = (smb_t *) tp;
1545 /* We can handle long names */
1546 if (vcp->flags & SMB_VCFLAG_USENT)
1547 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1549 /* now copy important fields from the tran 2 packet */
1550 smbp->com = t2p->com;
1551 smbp->tid = t2p->tid;
1552 smbp->mid = t2p->mid;
1553 smbp->pid = t2p->pid;
1554 smbp->uid = t2p->uid;
1555 smbp->res[0] = t2p->res[0];
1557 if (t2p->error_code) {
1558 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1559 unsigned long NTStatus;
1561 smb_MapNTError(t2p->error_code, &NTStatus);
1563 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1564 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1565 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1566 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1567 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1570 unsigned short errCode;
1571 unsigned char errClass;
1573 smb_MapCoreError(t2p->error_code, vcp, &errCode, &errClass);
1575 smbp->rcls = errClass;
1576 smbp->errLow = (unsigned char) (errCode & 0xff);
1577 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1581 totalLength = 1 + t2p->totalData + t2p->totalParms;
1583 /* now add the core parameters (tran2 info) to the packet */
1584 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1585 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1586 smb_SetSMBParm(tp, 2, 0); /* reserved */
1587 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1588 parmOffset = 10*2 + 35; /* parm offset in packet */
1589 parmOffset++; /* round to even */
1590 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1591 * hdr, bcc and wct */
1592 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1593 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1594 dataOffset = parmOffset + t2p->oldTotalParms;
1595 dataAlign = dataOffset & 2; /* quad-align */
1596 dataOffset += dataAlign;
1597 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1598 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1599 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1602 datap = smb_GetSMBData(tp, NULL);
1603 *datap++ = 0; /* we rounded to even */
1605 totalLength += dataAlign;
1606 smb_SetSMBDataLength(tp, totalLength);
1608 /* next, send the datagram */
1609 smb_SendPacket(vcp, tp);
1612 /* TRANS_SET_NMPIPE_STATE */
1613 long smb_nmpipeSetState(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1617 int pipeState = 0x0100; /* default */
1618 smb_tran2Packet_t *outp = NULL;
1621 if (p->totalParms > 0)
1622 pipeState = p->parmsp[0];
1624 osi_Log2(smb_logp, "smb_nmpipeSetState for fd[%d] with state[0x%x]", fd, pipeState);
1626 fidp = smb_FindFID(vcp, fd, 0);
1628 osi_Log2(smb_logp, "smb_nmpipeSetState Unknown SMB Fid vcp 0x%p fid %d",
1630 return CM_ERROR_BADFD;
1632 lock_ObtainMutex(&fidp->mx);
1633 if (pipeState & 0x8000)
1634 fidp->flags |= SMB_FID_BLOCKINGPIPE;
1635 if (pipeState & 0x0100)
1636 fidp->flags |= SMB_FID_MESSAGEMODEPIPE;
1637 lock_ReleaseMutex(&fidp->mx);
1639 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 0);
1640 smb_SendTran2Packet(vcp, outp, op);
1641 smb_FreeTran2Packet(outp);
1643 smb_ReleaseFID(fidp);
1648 long smb_nmpipeTransact(smb_vc_t * vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1658 osi_Log3(smb_logp, "smb_nmpipeTransact for fd[%d] %d bytes in, %d max bytes out",
1659 fd, p->totalData, p->maxReturnData);
1661 fidp = smb_FindFID(vcp, fd, 0);
1663 osi_Log2(smb_logp, "smb_nmpipeTransact Unknown SMB Fid vcp 0x%p fid %d",
1665 return CM_ERROR_BADFD;
1667 lock_ObtainMutex(&fidp->mx);
1668 if (fidp->flags & SMB_FID_RPC) {
1671 lock_ReleaseMutex(&fidp->mx);
1674 code = smb_RPCNmpipeTransact(fidp, vcp, p, op);
1675 smb_ReleaseFID(fidp);
1677 /* We only deal with RPC pipes */
1678 osi_Log2(smb_logp, "smb_nmpipeTransact Not a RPC vcp 0x%p fid %d",
1680 code = CM_ERROR_BADFD;
1687 /* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
1688 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1690 smb_tran2Packet_t *asp;
1703 /* We sometimes see 0 word count. What to do? */
1704 if (*inp->wctp == 0) {
1705 osi_Log0(smb_logp, "Transaction2 word count = 0");
1706 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1708 smb_SetSMBDataLength(outp, 0);
1709 smb_SendPacket(vcp, outp);
1713 totalParms = smb_GetSMBParm(inp, 0);
1714 totalData = smb_GetSMBParm(inp, 1);
1716 firstPacket = (inp->inCom == 0x25);
1718 /* find the packet we're reassembling */
1719 lock_ObtainWrite(&smb_globalLock);
1720 asp = smb_FindTran2Packet(vcp, inp);
1722 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1724 lock_ReleaseWrite(&smb_globalLock);
1726 /* now merge in this latest packet; start by looking up offsets */
1728 parmDisp = dataDisp = 0;
1729 parmOffset = smb_GetSMBParm(inp, 10);
1730 dataOffset = smb_GetSMBParm(inp, 12);
1731 parmCount = smb_GetSMBParm(inp, 9);
1732 dataCount = smb_GetSMBParm(inp, 11);
1733 asp->setupCount = smb_GetSMBParmByte(inp, 13);
1734 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1735 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1737 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1738 totalData, dataCount, asp->maxReturnData);
1740 if (asp->setupCount == 2) {
1741 clientchar_t * pname;
1743 asp->pipeCommand = smb_GetSMBParm(inp, 14);
1744 asp->pipeParam = smb_GetSMBParm(inp, 15);
1745 pname = smb_ParseString(inp, inp->wctp + 35, NULL, 0);
1747 asp->name = cm_ClientStrDup(pname);
1750 osi_Log2(smb_logp, " Named Pipe command id [%d] with name [%S]",
1751 asp->pipeCommand, osi_LogSaveClientString(smb_logp, asp->name));
1755 parmDisp = smb_GetSMBParm(inp, 4);
1756 parmOffset = smb_GetSMBParm(inp, 3);
1757 dataDisp = smb_GetSMBParm(inp, 7);
1758 dataOffset = smb_GetSMBParm(inp, 6);
1759 parmCount = smb_GetSMBParm(inp, 2);
1760 dataCount = smb_GetSMBParm(inp, 5);
1762 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1763 parmCount, dataCount);
1766 /* now copy the parms and data */
1767 if ( asp->totalParms > 0 && parmCount != 0 )
1769 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1771 if ( asp->totalData > 0 && dataCount != 0 ) {
1772 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1775 /* account for new bytes */
1776 asp->curData += dataCount;
1777 asp->curParms += parmCount;
1779 /* finally, if we're done, remove the packet from the queue and dispatch it */
1780 if (((asp->totalParms > 0 && asp->curParms > 0)
1781 || asp->setupCount == 2) &&
1782 asp->totalData <= asp->curData &&
1783 asp->totalParms <= asp->curParms) {
1785 /* we've received it all */
1786 lock_ObtainWrite(&smb_globalLock);
1787 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1788 lock_ReleaseWrite(&smb_globalLock);
1790 switch(asp->setupCount) {
1793 rapOp = asp->parmsp[0];
1795 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES &&
1796 smb_rapDispatchTable[rapOp].procp) {
1798 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",
1799 myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1801 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1803 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",
1804 code,vcp,vcp->lana,vcp->lsn);
1807 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]",
1808 rapOp, vcp, vcp->lana, vcp->lsn);
1810 code = CM_ERROR_BADOP;
1816 { /* Named pipe operation */
1817 osi_Log2(smb_logp, "Named Pipe: %s with name [%S]",
1818 myCrt_NmpipeDispatch(asp->pipeCommand),
1819 osi_LogSaveClientString(smb_logp, asp->name));
1821 code = CM_ERROR_BADOP;
1823 switch (asp->pipeCommand) {
1824 case SMB_TRANS_SET_NMPIPE_STATE:
1825 code = smb_nmpipeSetState(vcp, asp, outp);
1828 case SMB_TRANS_RAW_READ_NMPIPE:
1831 case SMB_TRANS_QUERY_NMPIPE_STATE:
1834 case SMB_TRANS_QUERY_NMPIPE_INFO:
1837 case SMB_TRANS_PEEK_NMPIPE:
1840 case SMB_TRANS_TRANSACT_NMPIPE:
1841 code = smb_nmpipeTransact(vcp, asp, outp);
1844 case SMB_TRANS_RAW_WRITE_NMPIPE:
1847 case SMB_TRANS_READ_NMPIPE:
1850 case SMB_TRANS_WRITE_NMPIPE:
1853 case SMB_TRANS_WAIT_NMPIPE:
1856 case SMB_TRANS_CALL_NMPIPE:
1863 code = CM_ERROR_BADOP;
1866 /* if an error is returned, we're supposed to send an error packet,
1867 * otherwise the dispatched function already did the data sending.
1868 * We give dispatched proc the responsibility since it knows how much
1869 * space to allocate.
1872 smb_SendTran2Error(vcp, asp, outp, code);
1875 /* free the input tran 2 packet */
1876 smb_FreeTran2Packet(asp);
1878 else if (firstPacket) {
1879 /* the first packet in a multi-packet request, we need to send an
1880 * ack to get more data.
1882 smb_SetSMBDataLength(outp, 0);
1883 smb_SendPacket(vcp, outp);
1889 /* ANSI versions. */
1891 #pragma pack(push, 1)
1893 typedef struct smb_rap_share_info_0 {
1894 BYTE shi0_netname[13];
1895 } smb_rap_share_info_0_t;
1897 typedef struct smb_rap_share_info_1 {
1898 BYTE shi1_netname[13];
1901 DWORD shi1_remark; /* char *shi1_remark; data offset */
1902 } smb_rap_share_info_1_t;
1904 typedef struct smb_rap_share_info_2 {
1905 BYTE shi2_netname[13];
1908 DWORD shi2_remark; /* char *shi2_remark; data offset */
1909 WORD shi2_permissions;
1911 WORD shi2_current_uses;
1912 DWORD shi2_path; /* char *shi2_path; data offset */
1913 WORD shi2_passwd[9];
1915 } smb_rap_share_info_2_t;
1917 #define SMB_RAP_MAX_SHARES 512
1919 typedef struct smb_rap_share_list {
1922 smb_rap_share_info_0_t * shares;
1923 } smb_rap_share_list_t;
1927 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1928 smb_rap_share_list_t * sp;
1930 if (dep->name[0] == '.' && (!dep->name[1] || (dep->name[1] == '.' && !dep->name[2])))
1931 return 0; /* skip over '.' and '..' */
1933 sp = (smb_rap_share_list_t *) vrockp;
1935 strncpy(sp->shares[sp->cShare].shi0_netname, dep->name, 12);
1936 sp->shares[sp->cShare].shi0_netname[12] = 0;
1940 if (sp->cShare >= sp->maxShares)
1941 return CM_ERROR_STOPNOW;
1946 /* RAP NetShareEnumRequest */
1947 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1949 smb_tran2Packet_t *outp;
1950 unsigned short * tp;
1954 int outParmsTotal; /* total parameter bytes */
1955 int outDataTotal; /* total data bytes */
1958 DWORD allSubmount = 0;
1960 DWORD nRegShares = 0;
1961 DWORD nSharesRet = 0;
1963 HKEY hkSubmount = NULL;
1964 smb_rap_share_info_1_t * shares;
1967 clientchar_t thisShare[AFSPATHMAX];
1971 smb_rap_share_list_t rootShares;
1975 cm_scache_t *rootScp;
1977 tp = p->parmsp + 1; /* skip over function number (always 0) */
1980 clientchar_t * cdescp;
1982 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1983 if (cm_ClientStrCmp(cdescp, _C("WrLeh")))
1984 return CM_ERROR_INVAL;
1985 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1986 if (cm_ClientStrCmp(cdescp, _C("B13BWz")))
1987 return CM_ERROR_INVAL;
1993 if (infoLevel != 1) {
1994 return CM_ERROR_INVAL;
1997 /* We are supposed to use the same ASCII data structure even if
1998 Unicode is negotiated, which ultimately means that the share
1999 names that we return must be at most 13 characters in length,
2000 including the NULL terminator.
2002 The RAP specification states that shares with names longer than
2003 12 characters should not be included in the enumeration.
2004 However, since we support prefix cell references and since many
2005 cell names are going to exceed 12 characters, we lie and send
2006 the first 12 characters.
2009 /* first figure out how many shares there are */
2010 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
2011 KEY_QUERY_VALUE, &hkParam);
2012 if (rv == ERROR_SUCCESS) {
2013 len = sizeof(allSubmount);
2014 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
2015 (BYTE *) &allSubmount, &len);
2016 if (rv != ERROR_SUCCESS || allSubmount != 0) {
2019 RegCloseKey (hkParam);
2022 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
2023 0, KEY_QUERY_VALUE, &hkSubmount);
2024 if (rv == ERROR_SUCCESS) {
2025 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
2026 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
2027 if (rv != ERROR_SUCCESS)
2033 /* fetch the root shares */
2034 rootShares.maxShares = SMB_RAP_MAX_SHARES;
2035 rootShares.cShare = 0;
2036 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
2040 userp = smb_GetTran2User(vcp,p);
2042 thyper.HighPart = 0;
2045 rootScp = cm_RootSCachep(userp, &req);
2046 cm_HoldSCache(rootScp);
2047 cm_ApplyDir(rootScp, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
2048 cm_ReleaseSCache(rootScp);
2050 cm_ReleaseUser(userp);
2052 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
2054 #define REMARK_LEN 1
2055 outParmsTotal = 8; /* 4 dwords */
2056 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
2057 if(outDataTotal > bufsize) {
2058 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
2059 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
2062 nSharesRet = nShares;
2065 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
2067 /* now for the submounts */
2068 shares = (smb_rap_share_info_1_t *) outp->datap;
2069 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
2071 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
2074 StringCchCopyA(shares[cshare].shi1_netname,
2075 lengthof(shares[cshare].shi1_netname), "all" );
2076 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
2077 /* type and pad are zero already */
2083 for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
2084 len = sizeof(thisShare);
2085 rv = RegEnumValueW(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
2086 if (rv == ERROR_SUCCESS &&
2087 cm_ClientStrLen(thisShare) &&
2088 (!allSubmount || cm_ClientStrCmpI(thisShare,_C("all")))) {
2089 cm_ClientStringToUtf8(thisShare, -1, shares[cshare].shi1_netname,
2090 lengthof( shares[cshare].shi1_netname ));
2091 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
2092 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
2097 nShares--; /* uncount key */
2100 RegCloseKey(hkSubmount);
2103 nonrootShares = cshare;
2105 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
2106 /* in case there are collisions with submounts, submounts have
2108 for (j=0; j < nonrootShares; j++)
2109 if (!cm_stricmp_utf8(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
2112 if (j < nonrootShares) {
2113 nShares--; /* uncount */
2117 StringCchCopyA(shares[cshare].shi1_netname, lengthof(shares[cshare].shi1_netname),
2118 rootShares.shares[i].shi0_netname);
2119 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
2124 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
2125 outp->parmsp[1] = 0;
2126 outp->parmsp[2] = cshare;
2127 outp->parmsp[3] = nShares;
2129 outp->totalData = (int)(cstrp - outp->datap);
2130 outp->totalParms = outParmsTotal;
2132 smb_SendTran2Packet(vcp, outp, op);
2133 smb_FreeTran2Packet(outp);
2135 free(rootShares.shares);
2140 /* RAP NetShareGetInfo */
2141 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2143 smb_tran2Packet_t *outp;
2144 unsigned short * tp;
2145 clientchar_t * shareName;
2146 BOOL shareFound = FALSE;
2147 unsigned short infoLevel;
2148 unsigned short bufsize;
2157 cm_scache_t *scp = NULL;
2163 tp = p->parmsp + 1; /* skip over function number (always 1) */
2166 clientchar_t * cdescp;
2168 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2169 if (cm_ClientStrCmp(cdescp, _C("zWrLh")))
2171 return CM_ERROR_INVAL;
2173 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2174 if (cm_ClientStrCmp(cdescp, _C("B13")) &&
2175 cm_ClientStrCmp(cdescp, _C("B13BWz")) &&
2176 cm_ClientStrCmp(cdescp, _C("B13BWzWWWzB9B")))
2178 return CM_ERROR_INVAL;
2180 shareName = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2188 totalData = sizeof(smb_rap_share_info_0_t);
2189 else if(infoLevel == SMB_INFO_STANDARD)
2190 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
2191 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
2192 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
2194 return CM_ERROR_INVAL;
2196 if(!cm_ClientStrCmpI(shareName, _C("all")) || !cm_ClientStrCmp(shareName,_C("*."))) {
2197 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
2198 KEY_QUERY_VALUE, &hkParam);
2199 if (rv == ERROR_SUCCESS) {
2200 len = sizeof(allSubmount);
2201 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
2202 (BYTE *) &allSubmount, &len);
2203 if (rv != ERROR_SUCCESS || allSubmount != 0) {
2206 RegCloseKey (hkParam);
2213 userp = smb_GetTran2User(vcp, p);
2215 osi_Log1(smb_logp,"ReceiveRAPNetShareGetInfo unable to resolve user [%d]", p->uid);
2216 return CM_ERROR_BADSMB;
2218 code = cm_NameI(cm_RootSCachep(userp, &req), shareName,
2219 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
2220 userp, NULL, &req, &scp);
2222 cm_ReleaseSCache(scp);
2225 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
2226 KEY_QUERY_VALUE, &hkSubmount);
2227 if (rv == ERROR_SUCCESS) {
2228 rv = RegQueryValueExW(hkSubmount, shareName, NULL, NULL, NULL, NULL);
2229 if (rv == ERROR_SUCCESS) {
2232 RegCloseKey(hkSubmount);
2238 return CM_ERROR_BADSHARENAME;
2240 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
2241 memset(outp->datap, 0, totalData);
2243 outp->parmsp[0] = 0;
2244 outp->parmsp[1] = 0;
2245 outp->parmsp[2] = totalData;
2247 if (infoLevel == 0) {
2248 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
2249 cm_ClientStringToUtf8(shareName, -1, info->shi0_netname,
2250 lengthof(info->shi0_netname));
2251 } else if(infoLevel == SMB_INFO_STANDARD) {
2252 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
2253 cm_ClientStringToUtf8(shareName, -1, info->shi1_netname, lengthof(info->shi1_netname));
2254 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
2255 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
2256 /* type and pad are already zero */
2257 } else { /* infoLevel==2 */
2258 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
2259 cm_ClientStringToUtf8(shareName, -1, info->shi2_netname, lengthof(info->shi2_netname));
2260 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
2261 info->shi2_permissions = ACCESS_ALL;
2262 info->shi2_max_uses = (unsigned short) -1;
2263 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
2266 outp->totalData = totalData;
2267 outp->totalParms = totalParam;
2269 smb_SendTran2Packet(vcp, outp, op);
2270 smb_FreeTran2Packet(outp);
2275 #pragma pack(push, 1)
2277 typedef struct smb_rap_wksta_info_10 {
2278 DWORD wki10_computername; /*char *wki10_computername;*/
2279 DWORD wki10_username; /* char *wki10_username; */
2280 DWORD wki10_langroup; /* char *wki10_langroup;*/
2281 BYTE wki10_ver_major;
2282 BYTE wki10_ver_minor;
2283 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
2284 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
2285 } smb_rap_wksta_info_10_t;
2289 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2291 smb_tran2Packet_t *outp;
2295 unsigned short * tp;
2298 smb_rap_wksta_info_10_t * info;
2302 tp = p->parmsp + 1; /* Skip over function number */
2305 clientchar_t * cdescp;
2307 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2308 SMB_STRF_FORCEASCII);
2309 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2310 return CM_ERROR_INVAL;
2312 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2313 SMB_STRF_FORCEASCII);
2314 if (cm_ClientStrCmp(cdescp, _C("zzzBBzz")))
2315 return CM_ERROR_INVAL;
2321 if (infoLevel != 10) {
2322 return CM_ERROR_INVAL;
2328 totalData = sizeof(*info) + /* info */
2329 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
2330 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
2331 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
2332 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
2333 1; /* wki10_oth_domains (null)*/
2335 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2337 memset(outp->parmsp,0,totalParams);
2338 memset(outp->datap,0,totalData);
2340 info = (smb_rap_wksta_info_10_t *) outp->datap;
2341 cstrp = (char *) (info + 1);
2343 info->wki10_computername = (DWORD) (cstrp - outp->datap);
2344 StringCbCopyA(cstrp, totalData, smb_localNamep);
2345 cstrp += strlen(cstrp) + 1;
2347 info->wki10_username = (DWORD) (cstrp - outp->datap);
2348 uidp = smb_FindUID(vcp, p->uid, 0);
2350 lock_ObtainMutex(&uidp->mx);
2351 if(uidp->unp && uidp->unp->name)
2352 cm_ClientStringToUtf8(uidp->unp->name, -1,
2353 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2354 lock_ReleaseMutex(&uidp->mx);
2355 smb_ReleaseUID(uidp);
2357 cstrp += strlen(cstrp) + 1;
2359 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
2360 StringCbCopyA(cstrp, totalData - (cstrp - outp->datap)*sizeof(char), "WORKGROUP");
2361 cstrp += strlen(cstrp) + 1;
2363 /* TODO: Not sure what values these should take, but these work */
2364 info->wki10_ver_major = 5;
2365 info->wki10_ver_minor = 1;
2367 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
2368 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
2369 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2370 cstrp += strlen(cstrp) + 1;
2372 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
2373 cstrp ++; /* no other domains */
2375 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
2376 outp->parmsp[2] = outp->totalData;
2377 outp->totalParms = totalParams;
2379 smb_SendTran2Packet(vcp,outp,op);
2380 smb_FreeTran2Packet(outp);
2385 #pragma pack(push, 1)
2387 typedef struct smb_rap_server_info_0 {
2389 } smb_rap_server_info_0_t;
2391 typedef struct smb_rap_server_info_1 {
2393 BYTE sv1_version_major;
2394 BYTE sv1_version_minor;
2396 DWORD sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
2397 } smb_rap_server_info_1_t;
2401 char smb_ServerComment[] = "OpenAFS Client";
2402 int smb_ServerCommentLen = sizeof(smb_ServerComment);
2404 #define SMB_SV_TYPE_SERVER 0x00000002L
2405 #define SMB_SV_TYPE_NT 0x00001000L
2406 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
2408 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2410 smb_tran2Packet_t *outp;
2414 unsigned short * tp;
2417 smb_rap_server_info_0_t * info0;
2418 smb_rap_server_info_1_t * info1;
2421 tp = p->parmsp + 1; /* Skip over function number */
2424 clientchar_t * cdescp;
2426 cdescp = smb_ParseStringT2Parm(p, (unsigned char *) tp, (char **) &tp,
2427 SMB_STRF_FORCEASCII);
2428 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2429 return CM_ERROR_INVAL;
2430 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2431 SMB_STRF_FORCEASCII);
2432 if (cm_ClientStrCmp(cdescp, _C("B16")) ||
2433 cm_ClientStrCmp(cdescp, _C("B16BBDz")))
2434 return CM_ERROR_INVAL;
2440 if (infoLevel != 0 && infoLevel != 1) {
2441 return CM_ERROR_INVAL;
2447 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
2448 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
2450 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2452 memset(outp->parmsp,0,totalParams);
2453 memset(outp->datap,0,totalData);
2455 if (infoLevel == 0) {
2456 info0 = (smb_rap_server_info_0_t *) outp->datap;
2457 cstrp = (char *) (info0 + 1);
2458 StringCchCopyA(info0->sv0_name, lengthof(info0->sv0_name), "AFS");
2459 } else { /* infoLevel == SMB_INFO_STANDARD */
2460 info1 = (smb_rap_server_info_1_t *) outp->datap;
2461 cstrp = (char *) (info1 + 1);
2462 StringCchCopyA(info1->sv1_name, lengthof(info1->sv1_name), "AFS");
2465 SMB_SV_TYPE_SERVER |
2467 SMB_SV_TYPE_SERVER_NT;
2469 info1->sv1_version_major = 5;
2470 info1->sv1_version_minor = 1;
2471 info1->sv1_comment_or_master_browser = (DWORD) (cstrp - outp->datap);
2473 StringCbCopyA(cstrp, smb_ServerCommentLen, smb_ServerComment);
2475 cstrp += smb_ServerCommentLen / sizeof(char);
2478 totalData = (DWORD)(cstrp - outp->datap);
2479 outp->totalData = min(bufsize,totalData); /* actual data size */
2480 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
2481 outp->parmsp[2] = totalData;
2482 outp->totalParms = totalParams;
2484 smb_SendTran2Packet(vcp,outp,op);
2485 smb_FreeTran2Packet(outp);
2490 /* SMB_COM_TRANSACTION2 and SMB_COM_TRANSACTION2_SECONDARY */
2491 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2493 smb_tran2Packet_t *asp;
2504 DWORD oldTime, newTime;
2506 /* We sometimes see 0 word count. What to do? */
2507 if (*inp->wctp == 0) {
2508 osi_Log0(smb_logp, "Transaction2 word count = 0");
2509 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
2511 smb_SetSMBDataLength(outp, 0);
2512 smb_SendPacket(vcp, outp);
2516 totalParms = smb_GetSMBParm(inp, 0);
2517 totalData = smb_GetSMBParm(inp, 1);
2519 firstPacket = (inp->inCom == 0x32);
2521 /* find the packet we're reassembling */
2522 lock_ObtainWrite(&smb_globalLock);
2523 asp = smb_FindTran2Packet(vcp, inp);
2525 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
2527 lock_ReleaseWrite(&smb_globalLock);
2529 /* now merge in this latest packet; start by looking up offsets */
2531 parmDisp = dataDisp = 0;
2532 parmOffset = smb_GetSMBParm(inp, 10);
2533 dataOffset = smb_GetSMBParm(inp, 12);
2534 parmCount = smb_GetSMBParm(inp, 9);
2535 dataCount = smb_GetSMBParm(inp, 11);
2536 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2537 asp->maxReturnData = smb_GetSMBParm(inp, 3);
2539 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2540 totalData, dataCount, asp->maxReturnData);
2543 parmDisp = smb_GetSMBParm(inp, 4);
2544 parmOffset = smb_GetSMBParm(inp, 3);
2545 dataDisp = smb_GetSMBParm(inp, 7);
2546 dataOffset = smb_GetSMBParm(inp, 6);
2547 parmCount = smb_GetSMBParm(inp, 2);
2548 dataCount = smb_GetSMBParm(inp, 5);
2550 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2551 parmCount, dataCount);
2554 /* now copy the parms and data */
2555 if ( asp->totalParms > 0 && parmCount != 0 )
2557 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2559 if ( asp->totalData > 0 && dataCount != 0 ) {
2560 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2563 /* account for new bytes */
2564 asp->curData += dataCount;
2565 asp->curParms += parmCount;
2567 /* finally, if we're done, remove the packet from the queue and dispatch it */
2568 if (asp->totalParms > 0 &&
2569 asp->curParms > 0 &&
2570 asp->totalData <= asp->curData &&
2571 asp->totalParms <= asp->curParms) {
2572 /* we've received it all */
2573 lock_ObtainWrite(&smb_globalLock);
2574 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2575 lock_ReleaseWrite(&smb_globalLock);
2577 oldTime = GetTickCount();
2579 /* now dispatch it */
2580 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2581 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2582 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2585 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2586 code = CM_ERROR_BADOP;
2589 /* if an error is returned, we're supposed to send an error packet,
2590 * otherwise the dispatched function already did the data sending.
2591 * We give dispatched proc the responsibility since it knows how much
2592 * space to allocate.
2595 smb_SendTran2Error(vcp, asp, outp, code);
2598 newTime = GetTickCount();
2599 if (newTime - oldTime > 45000) {
2602 clientchar_t *treepath = NULL; /* do not free */
2603 clientchar_t *pathname = NULL;
2604 cm_fid_t afid = {0,0,0,0,0};
2606 uidp = smb_FindUID(vcp, asp->uid, 0);
2607 smb_LookupTIDPath(vcp, asp->tid, &treepath);
2608 fidp = smb_FindFID(vcp, inp->fid, 0);
2611 lock_ObtainMutex(&fidp->mx);
2612 if (fidp->NTopen_pathp)
2613 pathname = fidp->NTopen_pathp;
2615 afid = fidp->scp->fid;
2617 if (inp->stringsp->wdata)
2618 pathname = inp->stringsp->wdata;
2621 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)",
2622 myCrt_2Dispatch(asp->opcode), newTime - oldTime,
2623 asp->uid, uidp ? uidp->unp->name : NULL,
2624 asp->pid, asp->mid, asp->tid,
2627 afid.cell, afid.volume, afid.vnode, afid.unique);
2630 lock_ReleaseMutex(&fidp->mx);
2633 smb_ReleaseUID(uidp);
2635 smb_ReleaseFID(fidp);
2638 /* free the input tran 2 packet */
2639 smb_FreeTran2Packet(asp);
2641 else if (firstPacket) {
2642 /* the first packet in a multi-packet request, we need to send an
2643 * ack to get more data.
2645 smb_SetSMBDataLength(outp, 0);
2646 smb_SendPacket(vcp, outp);
2653 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2655 clientchar_t *pathp;
2656 smb_tran2Packet_t *outp;
2661 cm_scache_t *dscp; /* dir we're dealing with */
2662 cm_scache_t *scp; /* file we're creating */
2666 clientchar_t *lastNamep;
2673 int parmSlot; /* which parm we're dealing with */
2674 long returnEALength;
2675 clientchar_t *tidPathp;
2678 BOOL is_rpc = FALSE;
2679 BOOL is_ipc = FALSE;
2685 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2686 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2688 openFun = p->parmsp[6]; /* open function */
2689 excl = ((openFun & 3) == 0);
2690 trunc = ((openFun & 3) == 2); /* truncate it */
2691 openMode = (p->parmsp[1] & 0x7);
2692 openAction = 0; /* tracks what we did */
2694 attributes = p->parmsp[3];
2695 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2697 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
2700 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2702 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2703 if (code == CM_ERROR_TIDIPC) {
2705 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2708 spacep = cm_GetSpace();
2709 /* smb_StripLastComponent will strip "::$DATA" if present */
2710 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2714 /* special case magic file name for receiving IOCTL requests
2715 * (since IOCTL calls themselves aren't getting through).
2717 (cm_ClientStrCmpI(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
2719 /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional)*/
2720 (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
2722 unsigned short file_type = 0;
2723 unsigned short device_state = 0;
2725 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2728 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
2729 osi_Log2(smb_logp, "smb_ReceiveTran2Open Creating RPC Fid [%d] code [%d]",
2732 smb_ReleaseFID(fidp);
2733 smb_FreeTran2Packet(outp);
2734 osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
2738 smb_SetupIoctlFid(fidp, spacep);
2739 osi_Log1(smb_logp, "smb_ReceiveTran2Open Creating IOCTL Fid [%d]", fidp->fid);
2742 /* copy out remainder of the parms */
2744 outp->parmsp[parmSlot++] = fidp->fid;
2746 outp->parmsp[parmSlot++] = 0; /* attrs */
2747 outp->parmsp[parmSlot++] = 0; /* mod time */
2748 outp->parmsp[parmSlot++] = 0;
2749 outp->parmsp[parmSlot++] = 0; /* len */
2750 outp->parmsp[parmSlot++] = 0x7fff;
2751 outp->parmsp[parmSlot++] = openMode;
2752 outp->parmsp[parmSlot++] = file_type;
2753 outp->parmsp[parmSlot++] = device_state;
2755 /* and the final "always present" stuff */
2756 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2757 /* next write out the "unique" ID */
2758 outp->parmsp[parmSlot++] = 0x1234;
2759 outp->parmsp[parmSlot++] = 0x5678;
2760 outp->parmsp[parmSlot++] = 0;
2761 if (returnEALength) {
2762 outp->parmsp[parmSlot++] = 0;
2763 outp->parmsp[parmSlot++] = 0;
2766 outp->totalData = 0;
2767 outp->totalParms = parmSlot * 2;
2769 smb_SendTran2Packet(vcp, outp, op);
2771 smb_FreeTran2Packet(outp);
2773 /* and clean up fid reference */
2774 smb_ReleaseFID(fidp);
2780 osi_Log1(smb_logp, "Tran2Open rejecting IPC TID vcp %p", vcp);
2781 smb_FreeTran2Packet(outp);
2782 return CM_ERROR_BADFD;
2786 if (!cm_IsValidClientString(pathp)) {
2788 clientchar_t * hexp;
2790 hexp = cm_GetRawCharsAlloc(pathp, -1);
2791 osi_Log1(smb_logp, "Tran2Open rejecting invalid name. [%S]",
2792 osi_LogSaveClientString(smb_logp, hexp));
2796 osi_Log0(smb_logp, "Tran2Open rejecting invalid name");
2798 smb_FreeTran2Packet(outp);
2799 return CM_ERROR_BADNTFILENAME;
2802 #ifdef DEBUG_VERBOSE
2804 char *hexp, *asciip;
2805 asciip = (lastNamep ? lastNamep : pathp);
2806 hexp = osi_HexifyString( asciip );
2807 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2812 userp = smb_GetTran2User(vcp, p);
2813 /* In the off chance that userp is NULL, we log and abandon */
2815 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2816 smb_FreeTran2Packet(outp);
2817 return CM_ERROR_BADSMB;
2821 code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
2822 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2823 userp, tidPathp, &req, &scp);
2825 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
2826 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2827 userp, tidPathp, &req, &dscp);
2828 cm_FreeSpace(spacep);
2831 cm_ReleaseUser(userp);
2832 smb_FreeTran2Packet(outp);
2837 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2838 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2839 (clientchar_t*) spacep->data);
2840 cm_ReleaseSCache(dscp);
2841 cm_ReleaseUser(userp);
2842 smb_FreeTran2Packet(outp);
2843 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2844 return CM_ERROR_PATH_NOT_COVERED;
2846 return CM_ERROR_NOSUCHPATH;
2848 #endif /* DFS_SUPPORT */
2850 /* otherwise, scp points to the parent directory. Do a lookup,
2851 * and truncate the file if we find it, otherwise we create the
2858 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2860 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2861 cm_ReleaseSCache(dscp);
2862 cm_ReleaseUser(userp);
2863 smb_FreeTran2Packet(outp);
2867 /* macintosh is expensive to program for it */
2868 cm_FreeSpace(spacep);
2871 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2872 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2873 cm_ReleaseSCache(scp);
2874 cm_ReleaseUser(userp);
2875 smb_FreeTran2Packet(outp);
2876 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2877 return CM_ERROR_PATH_NOT_COVERED;
2879 return CM_ERROR_NOSUCHPATH;
2881 #endif /* DFS_SUPPORT */
2884 /* if we get here, if code is 0, the file exists and is represented by
2885 * scp. Otherwise, we have to create it.
2888 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2891 cm_ReleaseSCache(dscp);
2892 cm_ReleaseSCache(scp);
2893 cm_ReleaseUser(userp);
2894 smb_FreeTran2Packet(outp);
2899 /* oops, file shouldn't be there */
2901 cm_ReleaseSCache(dscp);
2902 cm_ReleaseSCache(scp);
2903 cm_ReleaseUser(userp);
2904 smb_FreeTran2Packet(outp);
2905 return CM_ERROR_EXISTS;
2909 setAttr.mask = CM_ATTRMASK_LENGTH;
2910 setAttr.length.LowPart = 0;
2911 setAttr.length.HighPart = 0;
2912 code = cm_SetAttr(scp, &setAttr, userp, &req);
2913 openAction = 3; /* truncated existing file */
2916 openAction = 1; /* found existing file */
2918 else if (!(openFun & 0x10)) {
2919 /* don't create if not found */
2921 cm_ReleaseSCache(dscp);
2922 osi_assertx(scp == NULL, "null cm_scache_t");
2923 cm_ReleaseUser(userp);
2924 smb_FreeTran2Packet(outp);
2925 return CM_ERROR_NOSUCHFILE;
2928 osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2929 openAction = 2; /* created file */
2930 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2931 cm_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2932 smb_SetInitialModeBitsForFile(attributes, &setAttr);
2934 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2938 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2939 smb_NotifyChange(FILE_ACTION_ADDED,
2940 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2941 dscp, lastNamep, NULL, TRUE);
2942 } else if (!excl && code == CM_ERROR_EXISTS) {
2943 /* not an exclusive create, and someone else tried
2944 * creating it already, then we open it anyway. We
2945 * don't bother retrying after this, since if this next
2946 * fails, that means that the file was deleted after we
2947 * started this call.
2949 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2953 setAttr.mask = CM_ATTRMASK_LENGTH;
2954 setAttr.length.LowPart = 0;
2955 setAttr.length.HighPart = 0;
2956 code = cm_SetAttr(scp, &setAttr, userp,
2959 } /* lookup succeeded */
2963 /* we don't need this any longer */
2965 cm_ReleaseSCache(dscp);
2968 /* something went wrong creating or truncating the file */
2970 cm_ReleaseSCache(scp);
2971 cm_ReleaseUser(userp);
2972 smb_FreeTran2Packet(outp);
2976 /* make sure we're about to open a file */
2977 if (scp->fileType != CM_SCACHETYPE_FILE) {
2979 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2980 cm_scache_t * targetScp = 0;
2981 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2983 /* we have a more accurate file to use (the
2984 * target of the symbolic link). Otherwise,
2985 * we'll just use the symlink anyway.
2987 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2989 cm_ReleaseSCache(scp);
2993 if (scp->fileType != CM_SCACHETYPE_FILE) {
2994 cm_ReleaseSCache(scp);
2995 cm_ReleaseUser(userp);
2996 smb_FreeTran2Packet(outp);
2997 return CM_ERROR_ISDIR;
3001 /* now all we have to do is open the file itself */
3002 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3003 osi_assertx(fidp, "null smb_fid_t");
3006 lock_ObtainMutex(&fidp->mx);
3007 /* save a pointer to the vnode */
3008 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
3010 lock_ObtainWrite(&scp->rw);
3011 scp->flags |= CM_SCACHEFLAG_SMB_FID;
3012 lock_ReleaseWrite(&scp->rw);
3015 fidp->userp = userp;
3017 /* compute open mode */
3019 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
3020 if (openMode == 1 || openMode == 2)
3021 fidp->flags |= SMB_FID_OPENWRITE;
3023 /* remember that the file was newly created */
3025 fidp->flags |= SMB_FID_CREATED;
3027 lock_ReleaseMutex(&fidp->mx);
3029 smb_ReleaseFID(fidp);
3031 cm_Open(scp, 0, userp);
3033 /* copy out remainder of the parms */
3035 outp->parmsp[parmSlot++] = fidp->fid;
3036 lock_ObtainRead(&scp->rw);
3038 outp->parmsp[parmSlot++] = smb_Attributes(scp);
3039 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3040 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
3041 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
3042 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
3043 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
3044 outp->parmsp[parmSlot++] = openMode;
3045 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
3046 outp->parmsp[parmSlot++] = 0; /* IPC junk */
3048 /* and the final "always present" stuff */
3049 outp->parmsp[parmSlot++] = openAction;
3050 /* next write out the "unique" ID */
3051 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
3052 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
3053 outp->parmsp[parmSlot++] = 0;
3054 if (returnEALength) {
3055 outp->parmsp[parmSlot++] = 0;
3056 outp->parmsp[parmSlot++] = 0;
3058 lock_ReleaseRead(&scp->rw);
3059 outp->totalData = 0; /* total # of data bytes */
3060 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
3062 smb_SendTran2Packet(vcp, outp, op);
3064 smb_FreeTran2Packet(outp);
3066 cm_ReleaseUser(userp);
3067 /* leave scp held since we put it in fidp->scp */
3071 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3074 unsigned short infolevel;
3076 infolevel = p->parmsp[0];
3078 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
3080 return CM_ERROR_BAD_LEVEL;
3083 /* TRANS2_QUERY_FS_INFORMATION */
3084 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3086 smb_tran2Packet_t *outp;
3087 smb_tran2QFSInfo_t qi;
3091 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
3093 switch (p->parmsp[0]) {
3094 case SMB_INFO_ALLOCATION:
3096 responseSize = sizeof(qi.u.allocInfo);
3098 qi.u.allocInfo.FSID = 0;
3099 qi.u.allocInfo.sectorsPerAllocUnit = 1;
3100 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
3101 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
3102 qi.u.allocInfo.bytesPerSector = 1024;
3105 case SMB_INFO_VOLUME:
3107 qi.u.volumeInfo.vsn = 1234; /* Volume serial number */
3108 qi.u.volumeInfo.vnCount = 3; /* Number of characters in label (AFS\0)*/
3110 /* we're supposed to pad it out with zeroes to the end */
3111 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
3112 smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
3114 responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
3117 case SMB_QUERY_FS_VOLUME_INFO:
3118 /* FS volume info */
3119 responseSize = sizeof(qi.u.FSvolumeInfo);
3122 FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
3123 memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
3126 qi.u.FSvolumeInfo.vsn = 1234;
3127 qi.u.FSvolumeInfo.vnCount = 6; /* This is always in Unicode */
3128 memset(&qi.u.FSvolumeInfo.label, 0, sizeof(qi.u.FSvolumeInfo.label));
3129 memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
3132 case SMB_QUERY_FS_SIZE_INFO:
3134 responseSize = sizeof(qi.u.FSsizeInfo);
3136 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
3137 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
3138 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
3139 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
3140 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
3141 qi.u.FSsizeInfo.bytesPerSector = 1024;
3144 case SMB_QUERY_FS_DEVICE_INFO:
3145 /* FS device info */
3146 responseSize = sizeof(qi.u.FSdeviceInfo);
3148 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
3149 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
3152 case SMB_QUERY_FS_ATTRIBUTE_INFO:
3153 /* FS attribute info */
3155 /* attributes, defined in WINNT.H:
3156 * FILE_CASE_SENSITIVE_SEARCH 0x1
3157 * FILE_CASE_PRESERVED_NAMES 0x2
3158 * FILE_UNICODE_ON_DISK 0x4
3159 * FILE_VOLUME_QUOTAS 0x10
3160 * <no name defined> 0x4000
3161 * If bit 0x4000 is not set, Windows 95 thinks
3162 * we can't handle long (non-8.3) names,
3163 * despite our protestations to the contrary.
3165 qi.u.FSattributeInfo.attributes = 0x4003;
3166 /* The maxCompLength is supposed to be in bytes */
3168 qi.u.FSattributeInfo.attributes |= 0x04;
3170 qi.u.FSattributeInfo.maxCompLength = 255;
3171 smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
3172 qi.u.FSattributeInfo.FSnameLength = sz;
3175 sizeof(qi.u.FSattributeInfo.attributes) +
3176 sizeof(qi.u.FSattributeInfo.maxCompLength) +
3177 sizeof(qi.u.FSattributeInfo.FSnameLength) +
3182 case SMB_INFO_UNIX: /* CIFS Unix Info */
3183 case SMB_INFO_MACOS: /* Mac FS Info */
3185 return CM_ERROR_BADOP;
3188 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
3190 /* copy out return data, and set corresponding sizes */
3191 outp->totalParms = 0;
3192 outp->totalData = responseSize;
3193 memcpy(outp->datap, &qi, responseSize);
3195 /* send and free the packets */
3196 smb_SendTran2Packet(vcp, outp, op);
3197 smb_FreeTran2Packet(outp);
3202 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3204 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
3205 return CM_ERROR_BADOP;
3208 struct smb_ShortNameRock {
3209 clientchar_t *maskp;
3211 clientchar_t *shortName;
3212 size_t shortNameLen;
3215 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
3218 struct smb_ShortNameRock *rockp;
3219 normchar_t normName[MAX_PATH];
3220 clientchar_t *shortNameEnd;
3224 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t)) == 0) {
3225 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
3226 osi_LogSaveString(smb_logp, dep->name));
3230 /* compare both names and vnodes, though probably just comparing vnodes
3231 * would be safe enough.
3233 if (cm_NormStrCmpI(normName, rockp->maskp) != 0)
3235 if (ntohl(dep->fid.vnode) != rockp->vnode)
3238 /* This is the entry */
3239 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
3240 rockp->shortNameLen = shortNameEnd - rockp->shortName;
3242 return CM_ERROR_STOPNOW;
3245 long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
3246 clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
3248 struct smb_ShortNameRock rock;
3249 clientchar_t *lastNamep;
3252 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
3256 spacep = cm_GetSpace();
3257 /* smb_StripLastComponent will strip "::$DATA" if present */
3258 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
3260 code = cm_NameI(cm_RootSCachep(userp, reqp), spacep->wdata,
3261 caseFold, userp, tidPathp,
3263 cm_FreeSpace(spacep);
3268 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3269 cm_ReleaseSCache(dscp);
3270 cm_ReleaseUser(userp);
3274 return CM_ERROR_PATH_NOT_COVERED;
3276 #endif /* DFS_SUPPORT */
3278 if (!lastNamep) lastNamep = pathp;
3281 thyper.HighPart = 0;
3282 rock.shortName = shortName;
3284 rock.maskp = lastNamep;
3285 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
3287 cm_ReleaseSCache(dscp);
3290 return CM_ERROR_NOSUCHFILE;
3291 if (code == CM_ERROR_STOPNOW) {
3292 *shortNameLenp = rock.shortNameLen;
3298 /* TRANS2_QUERY_PATH_INFORMATION */
3299 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3301 smb_tran2Packet_t *outp;
3304 unsigned short infoLevel;
3305 smb_tran2QPathInfo_t qpi;
3307 unsigned short attributes;
3308 unsigned long extAttributes;
3309 clientchar_t shortName[13];
3313 cm_scache_t *scp, *dscp;
3314 int scp_rw_held = 0;
3317 clientchar_t *pathp;
3318 clientchar_t *tidPathp;
3319 clientchar_t *lastComp;
3324 infoLevel = p->parmsp[0];
3325 if (infoLevel == SMB_INFO_IS_NAME_VALID)
3327 else if (infoLevel == SMB_INFO_STANDARD)
3328 responseSize = sizeof(qpi.u.QPstandardInfo);
3329 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
3330 responseSize = sizeof(qpi.u.QPeaSizeInfo);
3331 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3332 responseSize = sizeof(qpi.u.QPfileBasicInfo);
3333 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3334 responseSize = sizeof(qpi.u.QPfileStandardInfo);
3335 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3336 responseSize = sizeof(qpi.u.QPfileEaInfo);
3337 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3338 responseSize = sizeof(qpi.u.QPfileNameInfo);
3339 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
3340 responseSize = sizeof(qpi.u.QPfileAllInfo);
3341 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
3342 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
3343 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO)
3344 responseSize = sizeof(qpi.u.QPfileStreamInfo);
3346 osi_Log2(smb_logp, "Bad Tran2QPathInfo op 0x%x infolevel 0x%x",
3347 p->opcode, infoLevel);
3348 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3351 memset(&qpi, 0, sizeof(qpi));
3353 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3354 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path \"%S\"", infoLevel,
3355 osi_LogSaveClientString(smb_logp, pathp));
3357 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3359 if (infoLevel > 0x100)
3360 outp->totalParms = 2;
3362 outp->totalParms = 0;
3364 /* now, if we're at infoLevel 6, we're only being asked to check
3365 * the syntax, so we just OK things now. In particular, we're *not*
3366 * being asked to verify anything about the state of any parent dirs.
3368 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
3369 smb_SendTran2Packet(vcp, outp, opx);
3370 smb_FreeTran2Packet(outp);
3374 userp = smb_GetTran2User(vcp, p);
3376 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
3377 smb_FreeTran2Packet(outp);
3378 return CM_ERROR_BADSMB;
3381 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3383 osi_Log1(smb_logp, "ReceiveTran2QPathInfo tid path lookup failure 0x%x", code);
3384 cm_ReleaseUser(userp);
3385 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
3386 smb_FreeTran2Packet(outp);
3390 osi_Log1(smb_logp, "T2 QPathInfo tidPathp \"%S\"",
3391 osi_LogSaveClientString(smb_logp, tidPathp));
3394 * XXX Strange hack XXX
3396 * As of Patch 7 (13 January 98), we are having the following problem:
3397 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3398 * requests to look up "desktop.ini" in all the subdirectories.
3399 * This can cause zillions of timeouts looking up non-existent cells
3400 * and volumes, especially in the top-level directory.
3402 * We have not found any way to avoid this or work around it except
3403 * to explicitly ignore the requests for mount points that haven't
3404 * yet been evaluated and for directories that haven't yet been
3407 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3408 spacep = cm_GetSpace();
3409 /* smb_StripLastComponent will strip "::$DATA" if present */
3410 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3411 #ifndef SPECIAL_FOLDERS
3412 /* Make sure that lastComp is not NULL */
3414 if (cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
3415 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
3419 userp, tidPathp, &req, &dscp);
3422 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3423 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3425 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3426 code = CM_ERROR_PATH_NOT_COVERED;
3428 code = CM_ERROR_NOSUCHPATH;
3430 #endif /* DFS_SUPPORT */
3431 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3432 code = CM_ERROR_NOSUCHFILE;
3433 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3434 cm_buf_t *bp = buf_Find(dscp, &hzero);
3440 code = CM_ERROR_NOSUCHFILE;
3442 cm_ReleaseSCache(dscp);
3444 cm_FreeSpace(spacep);
3445 cm_ReleaseUser(userp);
3446 smb_SendTran2Error(vcp, p, opx, code);
3447 smb_FreeTran2Packet(outp);
3453 #endif /* SPECIAL_FOLDERS */
3455 cm_FreeSpace(spacep);
3458 /* now do namei and stat, and copy out the info */
3459 code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
3460 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3463 cm_ReleaseUser(userp);
3464 smb_SendTran2Error(vcp, p, opx, code);
3465 smb_FreeTran2Packet(outp);
3470 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3471 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3472 cm_ReleaseSCache(scp);
3473 cm_ReleaseUser(userp);
3474 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3475 code = CM_ERROR_PATH_NOT_COVERED;
3477 code = CM_ERROR_NOSUCHPATH;
3478 smb_SendTran2Error(vcp, p, opx, code);
3479 smb_FreeTran2Packet(outp);
3482 #endif /* DFS_SUPPORT */
3484 lock_ObtainWrite(&scp->rw);
3486 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3487 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3491 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3493 lock_ConvertWToR(&scp->rw);
3498 /* now we have the status in the cache entry, and everything is locked.
3499 * Marshall the output data.
3501 /* for info level 108, figure out short name */
3502 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3503 code = cm_GetShortName(pathp, userp, &req,
3504 tidPathp, scp->fid.vnode, shortName,
3510 smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
3511 qpi.u.QPfileAltNameInfo.fileNameLength = len;
3512 responseSize = sizeof(unsigned long) + len;
3514 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3515 smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3516 qpi.u.QPfileNameInfo.fileNameLength = len;
3517 responseSize = sizeof(unsigned long) + len;
3519 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3520 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3521 qpi.u.QPstandardInfo.creationDateTime = dosTime;
3522 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3523 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3524 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3525 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3526 attributes = smb_Attributes(scp);
3527 qpi.u.QPstandardInfo.attributes = attributes;
3528 qpi.u.QPstandardInfo.eaSize = 0;
3530 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3531 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3532 qpi.u.QPfileBasicInfo.creationTime = ft;
3533 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3534 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3535 qpi.u.QPfileBasicInfo.changeTime = ft;
3536 extAttributes = smb_ExtAttributes(scp);
3537 qpi.u.QPfileBasicInfo.attributes = extAttributes;
3538 qpi.u.QPfileBasicInfo.reserved = 0;
3540 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3543 lock_ReleaseRead(&scp->rw);
3545 fidp = smb_FindFIDByScache(vcp, scp);
3547 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3548 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3549 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3550 qpi.u.QPfileStandardInfo.directory =
3551 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3552 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3553 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3554 qpi.u.QPfileStandardInfo.reserved = 0;
3557 lock_ObtainMutex(&fidp->mx);
3558 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3559 lock_ReleaseMutex(&fidp->mx);
3560 smb_ReleaseFID(fidp);
3562 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3564 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3565 qpi.u.QPfileEaInfo.eaSize = 0;
3567 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3570 lock_ReleaseRead(&scp->rw);
3572 fidp = smb_FindFIDByScache(vcp, scp);
3574 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3575 qpi.u.QPfileAllInfo.creationTime = ft;
3576 qpi.u.QPfileAllInfo.lastAccessTime = ft;
3577 qpi.u.QPfileAllInfo.lastWriteTime = ft;
3578 qpi.u.QPfileAllInfo.changeTime = ft;
3579 extAttributes = smb_ExtAttributes(scp);
3580 qpi.u.QPfileAllInfo.attributes = extAttributes;
3581 qpi.u.QPfileAllInfo.allocationSize = scp->length;
3582 qpi.u.QPfileAllInfo.endOfFile = scp->length;
3583 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3584 qpi.u.QPfileAllInfo.deletePending = 0;
3585 qpi.u.QPfileAllInfo.directory =
3586 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3587 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3588 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3589 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.vnode;
3590 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.unique;
3591 qpi.u.QPfileAllInfo.eaSize = 0;
3592 qpi.u.QPfileAllInfo.accessFlags = 0;
3594 lock_ObtainMutex(&fidp->mx);
3595 if (fidp->flags & SMB_FID_OPENDELETE)
3596 qpi.u.QPfileAllInfo.accessFlags |= DELETE;
3597 if (fidp->flags & SMB_FID_OPENREAD_LISTDIR)
3598 qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_READ|AFS_ACCESS_EXECUTE;
3599 if (fidp->flags & SMB_FID_OPENWRITE)
3600 qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_WRITE;
3601 if (fidp->flags & SMB_FID_DELONCLOSE)
3602 qpi.u.QPfileAllInfo.deletePending = 1;
3603 lock_ReleaseMutex(&fidp->mx);
3604 smb_ReleaseFID(fidp);
3606 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.cell;
3607 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.volume;
3608 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3609 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3610 qpi.u.QPfileAllInfo.mode = 0;
3611 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3613 smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3614 qpi.u.QPfileAllInfo.fileNameLength = len;
3615 responseSize -= (sizeof(qpi.u.QPfileAllInfo.fileName) - len);
3617 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO) {
3619 /* For now we have no streams */
3620 qpi.u.QPfileStreamInfo.nextEntryOffset = 0;
3621 if (scp->fileType == CM_SCACHETYPE_FILE) {
3622 qpi.u.QPfileStreamInfo.streamSize = scp->length;
3623 qpi.u.QPfileStreamInfo.streamAllocationSize = scp->length;
3624 smb_UnparseString(opx, qpi.u.QPfileStreamInfo.fileName, L"::$DATA", &len, SMB_STRF_IGNORENUL);
3625 qpi.u.QPfileStreamInfo.streamNameLength = len;
3626 responseSize -= (sizeof(qpi.u.QPfileStreamInfo.fileName) - len);
3628 qpi.u.QPfileStreamInfo.streamSize.QuadPart = 0;
3629 qpi.u.QPfileStreamInfo.streamAllocationSize.QuadPart = 0;
3630 smb_UnparseString(opx, qpi.u.QPfileStreamInfo.fileName, L"", &len, SMB_STRF_IGNORENUL);
3631 qpi.u.QPfileStreamInfo.streamNameLength = 0;
3635 outp->totalData = responseSize;
3637 /* send and free the packets */
3639 switch (scp_rw_held) {
3641 lock_ReleaseRead(&scp->rw);
3644 lock_ReleaseWrite(&scp->rw);
3648 cm_ReleaseSCache(scp);
3649 cm_ReleaseUser(userp);
3651 memcpy(outp->datap, &qpi, responseSize);
3652 smb_SendTran2Packet(vcp, outp, opx);
3654 smb_SendTran2Error(vcp, p, opx, code);
3656 smb_FreeTran2Packet(outp);
3661 /* TRANS2_SET_PATH_INFORMATION */
3662 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3665 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
3666 return CM_ERROR_BADOP;
3669 unsigned short infoLevel;
3670 clientchar_t * pathp;
3671 smb_tran2Packet_t *outp;
3672 smb_tran2QPathInfo_t *spi;
3674 cm_scache_t *scp, *dscp;
3677 clientchar_t *tidPathp;
3678 clientchar_t *lastComp;
3682 infoLevel = p->parmsp[0];
3683 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
3684 if (infoLevel != SMB_INFO_STANDARD &&
3685 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
3686 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
3687 osi_Log2(smb_logp, "Bad Tran2SetPathInfo op 0x%x infolevel 0x%x",
3688 p->opcode, infoLevel);
3689 smb_SendTran2Error(vcp, p, opx,
3690 infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3694 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3696 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
3697 osi_LogSaveClientString(smb_logp, pathp));
3699 userp = smb_GetTran2User(vcp, p);
3701 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3702 code = CM_ERROR_BADSMB;
3706 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3707 if (code == CM_ERROR_TIDIPC) {
3708 /* Attempt to use a TID allocated for IPC. The client
3709 * is probably looking for DCE RPC end points which we
3710 * don't support OR it could be looking to make a DFS
3713 osi_Log0(smb_logp, "Tran2Open received IPC TID");
3714 cm_ReleaseUser(userp);
3715 return CM_ERROR_NOSUCHPATH;
3719 * XXX Strange hack XXX
3721 * As of Patch 7 (13 January 98), we are having the following problem:
3722 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3723 * requests to look up "desktop.ini" in all the subdirectories.
3724 * This can cause zillions of timeouts looking up non-existent cells
3725 * and volumes, especially in the top-level directory.
3727 * We have not found any way to avoid this or work around it except
3728 * to explicitly ignore the requests for mount points that haven't
3729 * yet been evaluated and for directories that haven't yet been
3732 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3733 spacep = cm_GetSpace();
3734 /* smb_StripLastComponent will strip "::$DATA" if present */
3735 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3736 #ifndef SPECIAL_FOLDERS
3737 /* Make sure that lastComp is not NULL */
3739 if (cm_ClientStrCmpI(lastComp, _C("\\desktop.ini")) == 0) {
3740 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
3744 userp, tidPathp, &req, &dscp);
3747 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3748 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3750 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3751 code = CM_ERROR_PATH_NOT_COVERED;
3753 code = CM_ERROR_NOSUCHPATH;
3755 #endif /* DFS_SUPPORT */
3756 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3757 code = CM_ERROR_NOSUCHFILE;
3758 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3759 cm_buf_t *bp = buf_Find(dscp, &hzero);
3765 code = CM_ERROR_NOSUCHFILE;
3767 cm_ReleaseSCache(dscp);
3769 cm_FreeSpace(spacep);
3770 cm_ReleaseUser(userp);
3771 smb_SendTran2Error(vcp, p, opx, code);
3777 #endif /* SPECIAL_FOLDERS */
3779 cm_FreeSpace(spacep);
3782 /* now do namei and stat, and copy out the info */
3783 code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
3784 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3786 cm_ReleaseUser(userp);
3787 smb_SendTran2Error(vcp, p, opx, code);
3791 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3793 outp->totalParms = 2;
3794 outp->totalData = 0;
3796 spi = (smb_tran2QPathInfo_t *)p->datap;
3797 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3800 /* lock the vnode with a callback; we need the current status
3801 * to determine what the new status is, in some cases.
3803 lock_ObtainWrite(&scp->rw);
3804 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3805 CM_SCACHESYNC_GETSTATUS
3806 | CM_SCACHESYNC_NEEDCALLBACK);
3808 lock_ReleaseWrite(&scp->rw);
3811 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3813 /* prepare for setattr call */
3814 attr.mask = CM_ATTRMASK_LENGTH;
3815 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3816 attr.length.HighPart = 0;
3818 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3819 cm_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3820 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3823 if (spi->u.QPstandardInfo.attributes != 0) {
3824 if ((scp->unixModeBits & 0200)
3825 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3826 /* make a writable file read-only */
3827 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3828 attr.unixModeBits = scp->unixModeBits & ~0222;
3830 else if ((scp->unixModeBits & 0200) == 0
3831 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3832 /* make a read-only file writable */
3833 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3834 attr.unixModeBits = scp->unixModeBits | 0222;
3837 lock_ReleaseRead(&scp->rw);
3841 code = cm_SetAttr(scp, &attr, userp, &req);
3845 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3846 /* we don't support EAs */
3847 code = CM_ERROR_EAS_NOT_SUPPORTED;
3851 cm_ReleaseSCache(scp);
3852 cm_ReleaseUser(userp);
3854 smb_SendTran2Packet(vcp, outp, opx);
3856 smb_SendTran2Error(vcp, p, opx, code);
3857 smb_FreeTran2Packet(outp);
3863 /* TRANS2_QUERY_FILE_INFORMATION */
3864 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3866 smb_tran2Packet_t *outp;
3868 unsigned long attributes;
3869 unsigned short infoLevel;
3876 smb_tran2QFileInfo_t qfi;
3884 fidp = smb_FindFID(vcp, fid, 0);
3887 osi_Log2(smb_logp, "Tran2QFileInfo Unknown SMB Fid vcp 0x%p fid %d",
3889 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3893 lock_ObtainMutex(&fidp->mx);
3894 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3895 lock_ReleaseMutex(&fidp->mx);
3896 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3897 smb_CloseFID(vcp, fidp, NULL, 0);
3898 smb_ReleaseFID(fidp);
3901 lock_ReleaseMutex(&fidp->mx);
3903 infoLevel = p->parmsp[1];
3904 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3905 responseSize = sizeof(qfi.u.QFbasicInfo);
3906 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3907 responseSize = sizeof(qfi.u.QFstandardInfo);
3908 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3909 responseSize = sizeof(qfi.u.QFeaInfo);
3910 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3911 responseSize = sizeof(qfi.u.QFfileNameInfo);
3912 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO)
3913 responseSize = sizeof(qfi.u.QFfileStreamInfo);
3915 osi_Log2(smb_logp, "Bad Tran2QFileInfo op 0x%x infolevel 0x%x",
3916 p->opcode, infoLevel);
3917 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3918 smb_ReleaseFID(fidp);
3921 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3922 memset(&qfi, 0, sizeof(qfi));
3924 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3926 if (infoLevel > 0x100)
3927 outp->totalParms = 2;
3929 outp->totalParms = 0;
3931 userp = smb_GetTran2User(vcp, p);
3933 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3934 code = CM_ERROR_BADSMB;
3938 lock_ObtainMutex(&fidp->mx);
3939 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3941 osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3943 lock_ReleaseMutex(&fidp->mx);
3944 lock_ObtainWrite(&scp->rw);
3945 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3946 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3950 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3952 lock_ConvertWToR(&scp->rw);
3955 /* now we have the status in the cache entry, and everything is locked.
3956 * Marshall the output data.
3958 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3959 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3960 qfi.u.QFbasicInfo.creationTime = ft;
3961 qfi.u.QFbasicInfo.lastAccessTime = ft;
3962 qfi.u.QFbasicInfo.lastWriteTime = ft;
3963 qfi.u.QFbasicInfo.lastChangeTime = ft;
3964 attributes = smb_ExtAttributes(scp);
3965 qfi.u.QFbasicInfo.attributes = attributes;
3967 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3968 qfi.u.QFstandardInfo.allocationSize = scp->length;
3969 qfi.u.QFstandardInfo.endOfFile = scp->length;
3970 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3971 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3972 qfi.u.QFstandardInfo.directory =
3973 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3974 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3975 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3977 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3978 qfi.u.QFeaInfo.eaSize = 0;
3980 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3984 lock_ReleaseRead(&scp->rw);
3985 lock_ObtainMutex(&fidp->mx);
3986 lock_ObtainRead(&scp->rw);
3987 if (fidp->NTopen_wholepathp)
3988 name = fidp->NTopen_wholepathp;
3990 name = _C("\\"); /* probably can't happen */
3991 lock_ReleaseMutex(&fidp->mx);
3993 smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, SMB_STRF_IGNORENUL);
3994 responseSize = len + 4; /* this is actually what we want to return */
3995 qfi.u.QFfileNameInfo.fileNameLength = len;
3997 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO) {
4000 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
4001 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4002 scp->fileType == CM_SCACHETYPE_INVALID) {
4003 /* Do not return the alternate streams for directories */
4006 /* For now we have no alternate streams */
4007 qfi.u.QFfileStreamInfo.nextEntryOffset = 0;
4008 qfi.u.QFfileStreamInfo.streamSize = scp->length;
4009 qfi.u.QFfileStreamInfo.streamAllocationSize = scp->length;
4010 smb_UnparseString(opx, qfi.u.QFfileStreamInfo.fileName, L"::$DATA", &len, SMB_STRF_IGNORENUL);
4011 qfi.u.QFfileStreamInfo.streamNameLength = len;
4012 responseSize -= (sizeof(qfi.u.QFfileStreamInfo.fileName) - len);
4015 outp->totalData = responseSize;
4017 /* send and free the packets */
4020 lock_ReleaseRead(&scp->rw);
4022 lock_ReleaseWrite(&scp->rw);
4023 cm_ReleaseSCache(scp);
4024 cm_ReleaseUser(userp);
4025 smb_ReleaseFID(fidp);
4027 memcpy(outp->datap, &qfi, responseSize);
4028 smb_SendTran2Packet(vcp, outp, opx);
4030 smb_SendTran2Error(vcp, p, opx, code);
4032 smb_FreeTran2Packet(outp);
4038 /* TRANS2_SET_FILE_INFORMATION */
4039 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4044 unsigned short infoLevel;
4045 smb_tran2Packet_t *outp;
4046 cm_user_t *userp = NULL;
4047 cm_scache_t *scp = NULL;
4053 fidp = smb_FindFID(vcp, fid, 0);
4056 osi_Log2(smb_logp, "Tran2SetFileInfo Unknown SMB Fid vcp 0x%p fid %d",
4058 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
4062 infoLevel = p->parmsp[1];
4063 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
4064 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
4065 osi_Log2(smb_logp, "Bad Tran2SetFileInfo op 0x%x infolevel 0x%x",
4066 p->opcode, infoLevel);
4067 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
4068 smb_ReleaseFID(fidp);
4072 lock_ObtainMutex(&fidp->mx);
4073 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
4074 lock_ReleaseMutex(&fidp->mx);
4075 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
4076 smb_CloseFID(vcp, fidp, NULL, 0);
4077 smb_ReleaseFID(fidp);
4081 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
4082 !(fidp->flags & SMB_FID_OPENDELETE)) {
4083 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
4084 fidp, fidp->scp, fidp->flags);
4085 lock_ReleaseMutex(&fidp->mx);
4086 smb_ReleaseFID(fidp);
4087 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
4090 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
4091 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
4092 && !(fidp->flags & SMB_FID_OPENWRITE)) {
4093 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
4094 fidp, fidp->scp, fidp->flags);
4095 lock_ReleaseMutex(&fidp->mx);
4096 smb_ReleaseFID(fidp);
4097 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
4102 osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
4104 lock_ReleaseMutex(&fidp->mx);
4106 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
4108 outp->totalParms = 2;
4109 outp->totalData = 0;
4111 userp = smb_GetTran2User(vcp, p);
4113 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
4114 code = CM_ERROR_BADSMB;
4118 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
4120 unsigned int attribute;
4122 smb_tran2QFileInfo_t *sfi;
4124 sfi = (smb_tran2QFileInfo_t *)p->datap;
4126 /* lock the vnode with a callback; we need the current status
4127 * to determine what the new status is, in some cases.
4129 lock_ObtainWrite(&scp->rw);
4130 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4131 CM_SCACHESYNC_GETSTATUS
4132 | CM_SCACHESYNC_NEEDCALLBACK);
4134 lock_ReleaseWrite(&scp->rw);
4138 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4140 lock_ReleaseWrite(&scp->rw);
4141 lock_ObtainMutex(&fidp->mx);
4142 lock_ObtainRead(&scp->rw);
4144 /* prepare for setattr call */
4147 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
4148 /* when called as result of move a b, lastMod is (-1, -1).
4149 * If the check for -1 is not present, timestamp
4150 * of the resulting file will be 1969 (-1)
4152 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
4153 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
4154 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4155 cm_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
4156 fidp->flags |= SMB_FID_MTIMESETDONE;
4159 attribute = sfi->u.QFbasicInfo.attributes;
4160 if (attribute != 0) {
4161 if ((scp->unixModeBits & 0200)
4162 && (attribute & SMB_ATTR_READONLY) != 0) {
4163 /* make a writable file read-only */
4164 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4165 attr.unixModeBits = scp->unixModeBits & ~0222;
4167 else if ((scp->unixModeBits & 0200) == 0
4168 && (attribute & SMB_ATTR_READONLY) == 0) {
4169 /* make a read-only file writable */
4170 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4171 attr.unixModeBits = scp->unixModeBits | 0222;
4174 lock_ReleaseRead(&scp->rw);
4175 lock_ReleaseMutex(&fidp->mx);
4179 code = cm_SetAttr(scp, &attr, userp, &req);
4183 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
4184 int delflag = *((char *)(p->datap));
4185 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
4186 delflag, fidp, scp);
4187 if (*((char *)(p->datap))) { /* File is Deleted */
4188 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
4191 lock_ObtainMutex(&fidp->mx);
4192 fidp->flags |= SMB_FID_DELONCLOSE;
4193 lock_ReleaseMutex(&fidp->mx);
4195 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
4201 lock_ObtainMutex(&fidp->mx);
4202 fidp->flags &= ~SMB_FID_DELONCLOSE;
4203 lock_ReleaseMutex(&fidp->mx);
4206 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
4207 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
4208 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
4211 attr.mask = CM_ATTRMASK_LENGTH;
4212 attr.length.LowPart = size.LowPart;
4213 attr.length.HighPart = size.HighPart;
4214 code = cm_SetAttr(scp, &attr, userp, &req);
4218 cm_ReleaseSCache(scp);
4219 cm_ReleaseUser(userp);
4220 smb_ReleaseFID(fidp);
4222 smb_SendTran2Packet(vcp, outp, opx);
4224 smb_SendTran2Error(vcp, p, opx, code);
4225 smb_FreeTran2Packet(outp);
4232 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4234 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
4235 return CM_ERROR_BADOP;
4240 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4242 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
4243 return CM_ERROR_BADOP;
4246 /* TRANS2_FIND_NOTIFY_FIRST */
4248 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4250 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
4251 return CM_ERROR_BADOP;
4254 /* TRANS2_FIND_NOTIFY_NEXT */
4256 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4258 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
4259 return CM_ERROR_BADOP;
4262 /* TRANS2_CREATE_DIRECTORY */
4264 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4266 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
4267 return CM_ERROR_BADOP;
4270 /* TRANS2_SESSION_SETUP */
4272 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4274 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
4275 return CM_ERROR_BADOP;
4278 struct smb_v2_referral {
4280 USHORT ReferralFlags;
4283 USHORT DfsPathOffset;
4284 USHORT DfsAlternativePathOffset;
4285 USHORT NetworkAddressOffset;
4288 /* TRANS2_GET_DFS_REFERRAL */
4290 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
4292 /* This is a UNICODE only request (bit15 of Flags2) */
4293 /* The TID must be IPC$ */
4295 /* The documentation for the Flags response field is contradictory */
4297 /* Use Version 1 Referral Element Format */
4298 /* ServerType = 0; indicates the next server should be queried for the file */
4299 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
4300 /* Node = UnicodeString of UNC path of the next share name */
4303 int maxReferralLevel = 0;
4304 clientchar_t requestFileName[1024] = _C("");
4305 clientchar_t referralPath[1024] = _C("");
4306 smb_tran2Packet_t *outp = 0;
4307 cm_user_t *userp = 0;
4308 cm_scache_t *scp = 0;
4309 cm_scache_t *dscp = 0;
4311 CPINFO CodePageInfo;
4312 int i, nbnLen, reqLen, refLen;
4317 maxReferralLevel = p->parmsp[0];
4319 GetCPInfo(CP_ACP, &CodePageInfo);
4320 cm_Utf16ToClientString(&p->parmsp[1], -1, requestFileName, lengthof(requestFileName));
4322 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%S]",
4323 maxReferralLevel, osi_LogSaveClientString(smb_logp, requestFileName));
4325 nbnLen = (int)cm_ClientStrLen(cm_NetbiosNameC);
4326 reqLen = (int)cm_ClientStrLen(requestFileName);
4328 if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
4329 !cm_ClientStrCmpNI(cm_NetbiosNameC, &requestFileName[1], nbnLen) &&
4330 requestFileName[nbnLen+1] == '\\')
4334 if (!cm_ClientStrCmpNI(_C("all"), &requestFileName[nbnLen+2], 3) ||
4335 !cm_ClientStrCmpNI(_C("*."), &requestFileName[nbnLen+2], 2)) {
4337 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4340 userp = smb_GetTran2User(vcp, p);
4342 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
4343 code = CM_ERROR_BADSMB;
4348 * We have a requested path. Check to see if it is something
4351 * But be careful because the name that we might be searching
4352 * for might be a known name with the final character stripped
4355 code = cm_NameI(cm_RootSCachep(userp, &req), &requestFileName[nbnLen+2],
4356 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
4357 userp, NULL, &req, &scp);
4359 code == CM_ERROR_ALLDOWN ||
4360 code == CM_ERROR_ALLBUSY ||
4361 code == CM_ERROR_ALLOFFLINE ||
4362 code == CM_ERROR_NOSUCHCELL ||
4363 code == CM_ERROR_NOSUCHVOLUME ||
4364 code == CM_ERROR_NOACCESS) {
4367 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4369 } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
4370 clientchar_t temp[1024];
4371 clientchar_t pathName[1024];
4372 clientchar_t *lastComponent;
4374 * we have a msdfs link somewhere in the path
4375 * we should figure out where in the path the link is.
4378 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%S]", requestFileName);
4380 cm_ClientStrCpy(temp, lengthof(temp), &requestFileName[nbnLen+2]);
4384 cm_ReleaseSCache(dscp);
4388 cm_ReleaseSCache(scp);
4391 /* smb_StripLastComponent will strip "::$DATA" if present */
4392 smb_StripLastComponent(pathName, &lastComponent, temp);
4394 code = cm_NameI(cm_RootSCachep(userp, &req), pathName,
4395 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4396 userp, NULL, &req, &dscp);
4398 code = cm_NameI(dscp, ++lastComponent,
4400 userp, NULL, &req, &scp);
4401 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK)
4404 } while (code == CM_ERROR_PATH_NOT_COVERED);
4406 /* scp should now be the DfsLink we are looking for */
4408 /* figure out how much of the input path was used */
4409 reqLen = (int)(nbnLen+2 + cm_ClientStrLen(pathName) + 1 + cm_ClientStrLen(lastComponent));
4411 cm_FsStringToClientString(&scp->mountPointStringp[strlen("msdfs:")], -1,
4412 referralPath, lengthof(referralPath));
4413 refLen = (int)cm_ClientStrLen(referralPath);
4417 clientchar_t shareName[MAX_PATH + 1];
4418 clientchar_t *p, *q;
4419 /* we may have a sharename that is a volume reference */
4421 for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
4427 if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
4428 code = cm_NameI(cm_RootSCachep(userp, &req), _C(""),
4429 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
4430 userp, p, &req, &scp);
4435 cm_ClientStrCpy(referralPath, lengthof(referralPath),
4446 struct smb_v2_referral * v2ref;
4447 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (refLen + 8));
4449 sp = (USHORT *)outp->datap;
4451 sp[idx++] = reqLen; /* path consumed */
4452 sp[idx++] = 1; /* number of referrals */
4453 sp[idx++] = 0x03; /* flags */
4454 #ifdef DFS_VERSION_1
4455 sp[idx++] = 1; /* Version Number */
4456 sp[idx++] = refLen + 4; /* Referral Size */
4457 sp[idx++] = 1; /* Type = SMB Server */
4458 sp[idx++] = 0; /* Do not strip path consumed */
4459 for ( i=0;i<=refLen; i++ )
4460 sp[i+idx] = referralPath[i];
4461 #else /* DFS_VERSION_2 */
4462 sp[idx++] = 2; /* Version Number */
4463 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
4464 idx += (sizeof(struct smb_v2_referral) / 2);
4465 v2ref = (struct smb_v2_referral *) &sp[5];
4466 v2ref->ServerType = 1; /* SMB Server */
4467 v2ref->ReferralFlags = 0x03;
4468 v2ref->Proximity = 0; /* closest */
4469 v2ref->TimeToLive = 3600; /* seconds */
4470 v2ref->DfsPathOffset = idx * 2;
4471 v2ref->DfsAlternativePathOffset = idx * 2;
4472 v2ref->NetworkAddressOffset = 0;
4473 for ( i=0;i<=refLen; i++ )
4474 sp[i+idx] = referralPath[i];
4477 code = CM_ERROR_NOSUCHPATH;
4480 code = CM_ERROR_NOSUCHPATH;
4485 cm_ReleaseSCache(dscp);
4487 cm_ReleaseSCache(scp);
4489 cm_ReleaseUser(userp);
4491 smb_SendTran2Packet(vcp, outp, op);
4493 smb_SendTran2Error(vcp, p, op, code);
4495 smb_FreeTran2Packet(outp);
4498 #else /* DFS_SUPPORT */
4499 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
4500 return CM_ERROR_NOSUCHDEVICE;
4501 #endif /* DFS_SUPPORT */
4504 /* TRANS2_REPORT_DFS_INCONSISTENCY */
4506 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4508 /* This is a UNICODE only request (bit15 of Flags2) */
4510 /* There is nothing we can do about this operation. The client is going to
4511 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
4512 * Unfortunately, there is really nothing we can do about it other then log it
4513 * somewhere. Even then I don't think there is anything for us to do.
4514 * So let's return an error value.
4517 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
4518 return CM_ERROR_BADOP;
4522 smb_ApplyV3DirListPatches(cm_scache_t *dscp, smb_dirListPatch_t **dirPatchespp,
4523 clientchar_t * tidPathp, clientchar_t * relPathp,
4524 int infoLevel, cm_user_t *userp, cm_req_t *reqp)
4528 cm_scache_t *targetScp; /* target if scp is a symlink */
4531 unsigned short attr;
4532 unsigned long lattr;
4533 smb_dirListPatch_t *patchp;
4534 smb_dirListPatch_t *npatchp;
4536 afs_int32 mustFake = 0;
4537 clientchar_t path[AFSPATHMAX];
4539 code = cm_FindACLCache(dscp, userp, &rights);
4541 lock_ObtainWrite(&dscp->rw);
4542 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4543 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4545 cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4546 lock_ReleaseWrite(&dscp->rw);
4547 if (code == CM_ERROR_NOACCESS) {
4555 if (!mustFake) { /* Bulk Stat */
4557 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4559 memset(bsp, 0, sizeof(cm_bulkStat_t));
4561 for (patchp = *dirPatchespp, count=0;
4563 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4564 cm_scache_t *tscp = NULL;
4567 code = cm_GetSCache(&patchp->fid, &tscp, userp, reqp);
4569 if (lock_TryWrite(&tscp->rw)) {
4570 /* we have an entry that we can look at */
4571 #ifdef AFS_FREELANCE_CLIENT
4572 if (dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID && dscp->fid.volume == AFS_FAKE_ROOT_VOL_ID) {
4573 code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
4574 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4576 cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4578 lock_ReleaseWrite(&tscp->rw);
4579 cm_ReleaseSCache(tscp);
4582 #endif /* AFS_FREELANCE_CLIENT */
4583 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4584 /* we have a callback on it. Don't bother
4585 * fetching this stat entry, since we're happy
4586 * with the info we have.
4588 lock_ReleaseWrite(&tscp->rw);
4589 cm_ReleaseSCache(tscp);
4592 lock_ReleaseWrite(&tscp->rw);
4594 cm_ReleaseSCache(tscp);
4598 bsp->fids[i].Volume = patchp->fid.volume;
4599 bsp->fids[i].Vnode = patchp->fid.vnode;
4600 bsp->fids[i].Unique = patchp->fid.unique;
4602 if (bsp->counter == AFSCBMAX) {
4603 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4604 memset(bsp, 0, sizeof(cm_bulkStat_t));
4608 if (bsp->counter > 0)
4609 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4614 for( patchp = *dirPatchespp;
4616 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4617 cm_ClientStrPrintfN(path, lengthof(path),_C("%s\\%S"),
4618 relPathp ? relPathp : _C(""), patchp->dep->name);
4619 reqp->relPathp = path;
4620 reqp->tidPathp = tidPathp;
4622 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4623 reqp->relPathp = reqp->tidPathp = NULL;
4627 lock_ObtainWrite(&scp->rw);
4628 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4629 lock_ReleaseWrite(&scp->rw);
4631 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4632 errors in the client. */
4633 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4634 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4636 /* 1969-12-31 23:59:59 +00 */
4637 ft.dwHighDateTime = 0x19DB200;
4638 ft.dwLowDateTime = 0x5BB78980;
4640 /* copy to Creation Time */
4641 fa->creationTime = ft;
4642 fa->lastAccessTime = ft;
4643 fa->lastWriteTime = ft;
4644 fa->lastChangeTime = ft;
4646 switch (scp->fileType) {
4647 case CM_SCACHETYPE_DIRECTORY:
4648 case CM_SCACHETYPE_MOUNTPOINT:
4649 case CM_SCACHETYPE_INVALID:
4650 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4652 case CM_SCACHETYPE_SYMLINK:
4653 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4654 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4656 fa->extFileAttributes = SMB_ATTR_NORMAL;
4659 /* if we get here we either have a normal file
4660 * or we have a file for which we have never
4661 * received status info. In this case, we can
4662 * check the even/odd value of the entry's vnode.
4663 * odd means it is to be treated as a directory
4664 * and even means it is to be treated as a file.
4666 if (mustFake && (scp->fid.vnode & 0x1))
4667 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4669 fa->extFileAttributes = SMB_ATTR_NORMAL;
4671 /* merge in hidden attribute */
4672 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4673 fa->extFileAttributes |= SMB_ATTR_HIDDEN;
4676 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4678 /* 1969-12-31 23:59:58 +00*/
4679 dosTime = 0xEBBFBF7D;
4681 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4682 fa->lastAccessDateTime = fa->creationDateTime;
4683 fa->lastWriteDateTime = fa->creationDateTime;
4685 /* set the attribute */
4686 switch (scp->fileType) {
4687 case CM_SCACHETYPE_DIRECTORY:
4688 case CM_SCACHETYPE_MOUNTPOINT:
4689 case CM_SCACHETYPE_INVALID:
4690 fa->attributes = SMB_ATTR_DIRECTORY;
4692 case CM_SCACHETYPE_SYMLINK:
4693 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4694 fa->attributes = SMB_ATTR_DIRECTORY;
4696 fa->attributes = SMB_ATTR_NORMAL;
4699 /* if we get here we either have a normal file
4700 * or we have a file for which we have never
4701 * received status info. In this case, we can
4702 * check the even/odd value of the entry's vnode.
4703 * even means it is to be treated as a directory
4704 * and odd means it is to be treated as a file.
4706 if (mustFake && (scp->fid.vnode & 0x1))
4707 fa->attributes = SMB_ATTR_DIRECTORY;
4709 fa->attributes = SMB_ATTR_NORMAL;
4712 /* merge in hidden (dot file) attribute */
4713 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4714 fa->attributes |= SMB_ATTR_HIDDEN;
4718 cm_ReleaseSCache(scp);
4722 /* now watch for a symlink */
4724 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
4725 lock_ReleaseWrite(&scp->rw);
4726 cm_ClientStrPrintfN(path, lengthof(path), _C("%s\\%S"),
4727 relPathp ? relPathp : _C(""), patchp->dep->name);
4728 reqp->relPathp = path;
4729 reqp->tidPathp = tidPathp;
4730 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
4731 reqp->relPathp = reqp->tidPathp = NULL;
4733 /* we have a more accurate file to use (the
4734 * target of the symbolic link). Otherwise,
4735 * we'll just use the symlink anyway.
4737 osi_Log2(smb_logp, "symlink vp %x to vp %x",
4739 cm_ReleaseSCache(scp);
4742 lock_ObtainWrite(&scp->rw);
4745 lock_ConvertWToR(&scp->rw);
4747 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4748 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4751 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4753 fa->creationTime = ft;
4754 fa->lastAccessTime = ft;
4755 fa->lastWriteTime = ft;
4756 fa->lastChangeTime = ft;
4758 /* Use length for both file length and alloc length */
4759 fa->endOfFile = scp->length;
4760 fa->allocationSize = scp->length;
4762 /* Copy attributes */
4763 lattr = smb_ExtAttributes(scp);
4764 if ((code == CM_ERROR_NOSUCHPATH &&
4765 (scp->fileType == CM_SCACHETYPE_SYMLINK &&
4766 cm_TargetPerceivedAsDirectory(scp->mountPointStringp))) ||
4767 code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4768 if (lattr == SMB_ATTR_NORMAL)
4769 lattr = SMB_ATTR_DIRECTORY;
4771 lattr |= SMB_ATTR_DIRECTORY;
4773 /* merge in hidden (dot file) attribute */
4774 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4775 if (lattr == SMB_ATTR_NORMAL)
4776 lattr = SMB_ATTR_HIDDEN;
4778 lattr |= SMB_ATTR_HIDDEN;
4781 fa->extFileAttributes = lattr;
4783 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4786 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4788 fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
4789 fa->lastAccessDateTime = fa->creationDateTime;
4790 fa->lastWriteDateTime = fa->creationDateTime;
4792 /* copy out file length and alloc length,
4793 * using the same for both
4795 fa->dataSize = scp->length.LowPart;
4796 fa->allocationSize = scp->length.LowPart;
4798 /* finally copy out attributes as short */
4799 attr = smb_Attributes(scp);
4800 /* merge in hidden (dot file) attribute */
4801 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4802 if (lattr == SMB_ATTR_NORMAL)
4803 lattr = SMB_ATTR_HIDDEN;
4805 lattr |= SMB_ATTR_HIDDEN;
4807 fa->attributes = attr;
4810 lock_ReleaseRead(&scp->rw);
4811 cm_ReleaseSCache(scp);
4814 /* now free the patches */
4815 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4816 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4820 /* and mark the list as empty */
4821 *dirPatchespp = NULL;
4827 /* smb_ReceiveTran2SearchDir implements both
4828 * Tran2_Find_First and Tran2_Find_Next
4830 #define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
4831 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
4832 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
4833 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
4834 #define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
4836 /* this is an optimized handler for T2SearchDir that handles the case
4837 where there are no wildcards in the search path. I.e. an
4838 application is using FindFirst(Ex) to get information about a
4839 single file or directory. It will attempt to do a single lookup.
4840 If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4841 the usual mechanism.
4843 This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4845 TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
4847 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4851 long code = 0, code2 = 0;
4852 clientchar_t *pathp = 0;
4854 smb_dirListPatch_t *dirListPatchesp;
4855 smb_dirListPatch_t *curPatchp;
4856 size_t orbytes; /* # of bytes in this output record */
4857 size_t ohbytes; /* # of bytes, except file name */
4858 size_t onbytes; /* # of bytes in name, incl. term. null */
4859 cm_scache_t *scp = NULL;
4860 cm_scache_t *targetscp = NULL;
4861 cm_user_t *userp = NULL;
4862 char *op; /* output data ptr */
4863 char *origOp; /* original value of op */
4864 cm_space_t *spacep; /* for pathname buffer */
4865 unsigned long maxReturnData; /* max # of return data */
4866 long maxReturnParms; /* max # of return parms */
4867 long bytesInBuffer; /* # data bytes in the output buffer */
4868 clientchar_t *maskp; /* mask part of path */
4872 smb_tran2Packet_t *outp; /* response packet */
4873 clientchar_t *tidPathp = 0;
4875 clientchar_t shortName[13]; /* 8.3 name if needed */
4877 clientchar_t *shortNameEnd;
4878 cm_dirEntry_t * dep = NULL;
4881 void * attrp = NULL;
4882 smb_tran2Find_t * fp;
4887 osi_assertx(p->opcode == 1, "invalid opcode");
4889 /* find first; obtain basic parameters from request */
4891 /* note that since we are going to failover to regular
4892 * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4893 * modify any of the input parameters here. */
4894 attribute = p->parmsp[0];
4895 maxCount = p->parmsp[1];
4896 infoLevel = p->parmsp[3];
4897 searchFlags = p->parmsp[2];
4898 pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4900 maskp = cm_ClientStrRChr(pathp, '\\');
4904 maskp++; /* skip over backslash */
4905 /* track if this is likely to match a lot of entries */
4907 osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%S], mask[%S]",
4908 osi_LogSaveClientString(smb_logp, pathp),
4909 osi_LogSaveClientString(smb_logp, maskp));
4911 switch ( infoLevel ) {
4912 case SMB_INFO_STANDARD:
4914 ohbytes = sizeof(fp->u.FstandardInfo);
4917 case SMB_INFO_QUERY_EA_SIZE:
4918 ohbytes = sizeof(fp->u.FeaSizeInfo);
4919 s = "InfoQueryEaSize";
4922 case SMB_INFO_QUERY_EAS_FROM_LIST:
4923 ohbytes = sizeof(fp->u.FeasFromListInfo);
4924 s = "InfoQueryEasFromList";
4927 case SMB_FIND_FILE_DIRECTORY_INFO:
4928 s = "FindFileDirectoryInfo";
4929 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4932 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4933 s = "FindFileFullDirectoryInfo";
4934 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4937 case SMB_FIND_FILE_NAMES_INFO:
4938 s = "FindFileNamesInfo";
4939 ohbytes = sizeof(fp->u.FfileNamesInfo);
4942 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4943 s = "FindFileBothDirectoryInfo";
4944 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4948 s = "unknownInfoLevel";
4952 osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
4955 "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4956 attribute, infoLevel, maxCount, searchFlags);
4959 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4960 return CM_ERROR_INVAL;
4963 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4964 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4966 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4969 dirListPatchesp = NULL;
4971 maxReturnData = p->maxReturnData;
4972 maxReturnParms = 10; /* return params for findfirst, which
4973 is the only one we handle.*/
4975 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4978 osi_Log2(smb_logp, "T2SDSingle search dir count %d [%S]",
4979 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4981 /* bail out if request looks bad */
4983 smb_FreeTran2Packet(outp);
4984 return CM_ERROR_BADSMB;
4987 userp = smb_GetTran2User(vcp, p);
4989 osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
4990 smb_FreeTran2Packet(outp);
4991 return CM_ERROR_BADSMB;
4994 /* try to get the vnode for the path name next */
4995 spacep = cm_GetSpace();
4996 /* smb_StripLastComponent will strip "::$DATA" if present */
4997 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4998 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
5000 cm_ReleaseUser(userp);
5001 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
5002 smb_FreeTran2Packet(outp);
5006 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
5007 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5008 userp, tidPathp, &req, &scp);
5009 cm_FreeSpace(spacep);
5012 cm_ReleaseUser(userp);
5013 smb_SendTran2Error(vcp, p, opx, code);
5014 smb_FreeTran2Packet(outp);
5018 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
5019 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5020 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
5021 cm_ReleaseSCache(scp);
5022 cm_ReleaseUser(userp);
5023 if ( WANTS_DFS_PATHNAMES(p) || pnc )
5024 code = CM_ERROR_PATH_NOT_COVERED;
5026 code = CM_ERROR_NOSUCHPATH;
5027 smb_SendTran2Error(vcp, p, opx, code);
5028 smb_FreeTran2Packet(outp);
5031 #endif /* DFS_SUPPORT */
5032 osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
5034 /* now do a single case sensitive lookup for the file in question */
5035 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
5037 /* if a case sensitive match failed, we try a case insensitive one
5039 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
5040 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
5043 if (code == 0 && targetscp->fid.vnode == 0) {
5044 cm_ReleaseSCache(targetscp);
5045 code = CM_ERROR_NOSUCHFILE;
5049 /* if we can't find the directory entry, this block will
5050 return CM_ERROR_NOSUCHFILE, which we will pass on to
5051 smb_ReceiveTran2SearchDir(). */
5052 cm_ReleaseSCache(scp);
5053 cm_ReleaseUser(userp);
5054 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5055 smb_SendTran2Error(vcp, p, opx, code);
5058 smb_FreeTran2Packet(outp);
5062 /* now that we have the target in sight, we proceed with filling
5063 up the return data. */
5065 op = origOp = outp->datap;
5068 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
5069 /* skip over resume key */
5073 fp = (smb_tran2Find_t *) op;
5075 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
5076 && targetscp->fid.vnode != 0
5077 && !cm_Is8Dot3(maskp)) {
5080 dfid.vnode = htonl(targetscp->fid.vnode);
5081 dfid.unique = htonl(targetscp->fid.unique);
5083 cm_Gen8Dot3NameIntW(maskp, &dfid, shortName, &shortNameEnd);
5089 osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %S (%S)",
5090 htonl(targetscp->fid.vnode),
5091 htonl(targetscp->fid.unique),
5092 osi_LogSaveClientString(smb_logp, pathp),
5093 (NeedShortName)? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
5095 /* Eliminate entries that don't match requested attributes */
5096 if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
5097 smb_IsDotFile(maskp)) {
5099 code = CM_ERROR_NOSUCHFILE;
5100 osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
5105 if (!(attribute & SMB_ATTR_DIRECTORY) &&
5106 (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
5107 targetscp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
5108 targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
5109 targetscp->fileType == CM_SCACHETYPE_INVALID)) {
5111 code = CM_ERROR_NOSUCHFILE;
5112 osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
5117 /* add header to name & term. null */
5119 smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5120 orbytes = ohbytes + onbytes;
5122 /* now, we round up the record to a 4 byte alignment, and we make
5123 * sure that we have enough room here for even the aligned version
5124 * (so we don't have to worry about an * overflow when we pad
5125 * things out below). That's the reason for the alignment
5128 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5129 align = (4 - (orbytes & 3)) & 3;
5133 if (orbytes + align > maxReturnData) {
5135 /* even though this request is unlikely to succeed with a
5136 failover, we do it anyway. */
5137 code = CM_ERROR_NOSUCHFILE;
5138 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5143 /* this is one of the entries to use: it is not deleted and it
5144 * matches the star pattern we're looking for. Put out the name,
5145 * preceded by its length.
5147 /* First zero everything else */
5148 memset(origOp, 0, orbytes);
5151 smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5153 switch (infoLevel) {
5154 case SMB_INFO_STANDARD:
5155 fp->u.FstandardInfo.fileNameLength = onbytes;
5156 attrp = &fp->u.FstandardInfo.fileAttrs;
5159 case SMB_INFO_QUERY_EA_SIZE:
5160 fp->u.FeaSizeInfo.fileNameLength = onbytes;
5161 attrp = &fp->u.FeaSizeInfo.fileAttrs;
5162 fp->u.FeaSizeInfo.eaSize = 0;
5165 case SMB_INFO_QUERY_EAS_FROM_LIST:
5166 fp->u.FeasFromListInfo.fileNameLength = onbytes;
5167 attrp = &fp->u.FeasFromListInfo.fileAttrs;
5168 fp->u.FeasFromListInfo.eaSize = 0;
5171 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5172 if (NeedShortName) {
5176 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
5177 fp->u.FfileBothDirectoryInfo.shortName,
5178 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
5180 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
5182 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5183 fp->u.FfileBothDirectoryInfo.reserved = 0;
5185 strcpy(fp->u.FfileBothDirectoryInfo.shortName,
5187 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
5192 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5193 fp->u.FfileFullDirectoryInfo.eaSize = 0;
5196 case SMB_FIND_FILE_DIRECTORY_INFO:
5197 fp->u.FfileDirectoryInfo.nextEntryOffset = 0;
5198 fp->u.FfileDirectoryInfo.fileIndex = 0;
5199 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5200 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5203 case SMB_FIND_FILE_NAMES_INFO:
5204 fp->u.FfileNamesInfo.nextEntryOffset = 0;
5205 fp->u.FfileNamesInfo.fileIndex = 0;
5206 fp->u.FfileNamesInfo.fileNameLength = onbytes;
5210 /* we shouldn't hit this case */
5211 osi_assertx(FALSE, "Unknown query type");
5214 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5215 osi_assert(attrp != NULL);
5217 curPatchp = malloc(sizeof(*curPatchp));
5218 osi_QAdd((osi_queue_t **) &dirListPatchesp,
5220 curPatchp->dptr = attrp;
5222 if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
5223 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5225 curPatchp->flags = 0;
5228 cm_SetFid(&curPatchp->fid, targetscp->fid.cell, targetscp->fid.volume, targetscp->fid.vnode, targetscp->fid.unique);
5232 int namelen = cm_ClientStringToFsString(maskp, -1, NULL, 0);
5233 dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+namelen);
5234 cm_ClientStringToFsString(maskp, -1, dep->name, namelen);
5236 dep->fid.vnode = targetscp->fid.vnode;
5237 dep->fid.unique = targetscp->fid.unique;
5238 curPatchp->dep = dep;
5241 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
5242 /* put out resume key */
5243 *((u_long *)origOp) = 0;
5246 /* Adjust byte ptr and count */
5247 origOp += orbytes; /* skip entire record */
5248 bytesInBuffer += orbytes;
5250 /* and pad the record out */
5251 while (--align >= 0) {
5256 /* apply the patches */
5257 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->wdata, infoLevel, userp, &req);
5259 outp->parmsp[0] = 0;
5260 outp->parmsp[1] = 1; /* number of names returned */
5261 outp->parmsp[2] = 1; /* end of search */
5262 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5263 outp->parmsp[4] = 0;
5265 outp->totalParms = 10; /* in bytes */
5267 outp->totalData = bytesInBuffer;
5269 osi_Log0(smb_logp, "T2SDSingle done.");
5271 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5273 smb_SendTran2Error(vcp, p, opx, code);
5275 smb_SendTran2Packet(vcp, outp, opx);
5280 smb_FreeTran2Packet(outp);
5284 cm_ReleaseSCache(scp);
5285 cm_ReleaseSCache(targetscp);
5286 cm_ReleaseUser(userp);
5292 /* TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2 */
5293 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
5298 long code = 0, code2 = 0;
5299 clientchar_t *pathp;
5300 cm_dirEntry_t *dep = 0;
5302 smb_dirListPatch_t *dirListPatchesp = 0;
5303 smb_dirListPatch_t *curPatchp = 0;
5306 size_t orbytes; /* # of bytes in this output record */
5307 size_t ohbytes; /* # of bytes, except file name */
5308 size_t onbytes; /* # of bytes in name, incl. term. null */
5309 osi_hyper_t dirLength;
5310 osi_hyper_t bufferOffset;
5311 osi_hyper_t curOffset;
5313 smb_dirSearch_t *dsp;
5317 cm_pageHeader_t *pageHeaderp;
5318 cm_user_t *userp = NULL;
5321 long nextEntryCookie;
5322 int numDirChunks; /* # of 32 byte dir chunks in this entry */
5323 char *op; /* output data ptr */
5324 char *origOp; /* original value of op */
5325 cm_space_t *spacep; /* for pathname buffer */
5326 unsigned long maxReturnData; /* max # of return data */
5327 unsigned long maxReturnParms; /* max # of return parms */
5328 long bytesInBuffer; /* # data bytes in the output buffer */
5330 clientchar_t *maskp; /* mask part of path */
5334 smb_tran2Packet_t *outp; /* response packet */
5335 clientchar_t *tidPathp;
5337 clientchar_t shortName[13]; /* 8.3 name if needed */
5340 clientchar_t *shortNameEnd;
5346 smb_tran2Find_t * fp;
5351 if (p->opcode == 1) {
5352 /* find first; obtain basic parameters from request */
5353 attribute = p->parmsp[0];
5354 maxCount = p->parmsp[1];
5355 infoLevel = p->parmsp[3];
5356 searchFlags = p->parmsp[2];
5357 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
5359 maskp = cm_ClientStrRChr(pathp, '\\');
5363 maskp++; /* skip over backslash */
5365 /* track if this is likely to match a lot of entries */
5366 starPattern = smb_V3IsStarMask(maskp);
5368 #ifndef NOFINDFIRSTOPTIMIZE
5370 /* if this is for a single directory or file, we let the
5371 optimized routine handle it. The only error it
5372 returns is CM_ERROR_NOSUCHFILE. The */
5373 code = smb_T2SearchDirSingle(vcp, p, opx);
5375 /* we only failover if we see a CM_ERROR_NOSUCHFILE */
5376 if (code != CM_ERROR_NOSUCHFILE) {
5378 /* unless we are using the BPlusTree */
5379 if (code == CM_ERROR_BPLUS_NOMATCH)
5380 code = CM_ERROR_NOSUCHFILE;
5381 #endif /* USE_BPLUS */
5385 #endif /* NOFINDFIRSTOPTIMIZE */
5388 dsp = smb_NewDirSearch(1);
5389 dsp->attribute = attribute;
5390 cm_ClientStrCpy(dsp->mask, lengthof(dsp->mask), maskp); /* and save mask */
5393 osi_assertx(p->opcode == 2, "invalid opcode");
5394 /* find next; obtain basic parameters from request or open dir file */
5395 dsp = smb_FindDirSearch(p->parmsp[0]);
5396 maxCount = p->parmsp[1];
5397 infoLevel = p->parmsp[2];
5398 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
5399 searchFlags = p->parmsp[5];
5401 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
5402 p->parmsp[0], nextCookie);
5403 return CM_ERROR_BADFD;
5405 attribute = dsp->attribute;
5408 starPattern = 1; /* assume, since required a Find Next */
5411 switch ( infoLevel ) {
5412 case SMB_INFO_STANDARD:
5414 ohbytes = sizeof(fp->u.FstandardInfo);
5417 case SMB_INFO_QUERY_EA_SIZE:
5418 ohbytes = sizeof(fp->u.FeaSizeInfo);
5419 s = "InfoQueryEaSize";
5422 case SMB_INFO_QUERY_EAS_FROM_LIST:
5423 ohbytes = sizeof(fp->u.FeasFromListInfo);
5424 s = "InfoQueryEasFromList";
5427 case SMB_FIND_FILE_DIRECTORY_INFO:
5428 s = "FindFileDirectoryInfo";
5429 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
5432 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5433 s = "FindFileFullDirectoryInfo";
5434 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
5437 case SMB_FIND_FILE_NAMES_INFO:
5438 s = "FindFileNamesInfo";
5439 ohbytes = sizeof(fp->u.FfileNamesInfo);
5442 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5443 s = "FindFileBothDirectoryInfo";
5444 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
5448 s = "unknownInfoLevel";
5452 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
5455 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
5456 attribute, infoLevel, maxCount, searchFlags);
5458 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
5459 p->opcode, dsp->cookie, nextCookie);
5462 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
5463 smb_ReleaseDirSearch(dsp);
5464 return CM_ERROR_INVAL;
5467 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5468 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
5470 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5473 dirListPatchesp = NULL;
5475 maxReturnData = p->maxReturnData;
5476 if (p->opcode == 1) /* find first */
5477 maxReturnParms = 10; /* bytes */
5479 maxReturnParms = 8; /* bytes */
5481 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
5487 osi_Log2(smb_logp, "T2 receive search dir count %d [%S]",
5488 maxCount, osi_LogSaveClientString(smb_logp, pathp));
5490 /* bail out if request looks bad */
5491 if (p->opcode == 1 && !pathp) {
5492 smb_ReleaseDirSearch(dsp);
5493 smb_FreeTran2Packet(outp);
5494 return CM_ERROR_BADSMB;
5497 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
5498 dsp->cookie, nextCookie, attribute);
5500 userp = smb_GetTran2User(vcp, p);
5502 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
5503 smb_ReleaseDirSearch(dsp);
5504 smb_FreeTran2Packet(outp);
5505 return CM_ERROR_BADSMB;
5508 /* try to get the vnode for the path name next */
5509 lock_ObtainMutex(&dsp->mx);
5512 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5516 spacep = cm_GetSpace();
5517 /* smb_StripLastComponent will strip "::$DATA" if present */
5518 smb_StripLastComponent(spacep->wdata, NULL, pathp);
5519 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
5521 cm_ReleaseUser(userp);
5522 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
5523 smb_FreeTran2Packet(outp);
5524 lock_ReleaseMutex(&dsp->mx);
5525 smb_DeleteDirSearch(dsp);
5526 smb_ReleaseDirSearch(dsp);
5530 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
5531 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
5533 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
5534 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5535 userp, tidPathp, &req, &scp);
5536 cm_FreeSpace(spacep);
5539 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
5540 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5541 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
5542 cm_ReleaseSCache(scp);
5543 cm_ReleaseUser(userp);
5544 if ( WANTS_DFS_PATHNAMES(p) || pnc )
5545 code = CM_ERROR_PATH_NOT_COVERED;
5547 code = CM_ERROR_NOSUCHPATH;
5548 smb_SendTran2Error(vcp, p, opx, code);
5549 smb_FreeTran2Packet(outp);
5550 lock_ReleaseMutex(&dsp->mx);
5551 smb_DeleteDirSearch(dsp);
5552 smb_ReleaseDirSearch(dsp);
5555 #endif /* DFS_SUPPORT */
5557 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5558 /* we need one hold for the entry we just stored into,
5559 * and one for our own processing. When we're done
5560 * with this function, we'll drop the one for our own
5561 * processing. We held it once from the namei call,
5562 * and so we do another hold now.
5565 dsp->flags |= SMB_DIRSEARCH_BULKST;
5568 lock_ReleaseMutex(&dsp->mx);
5570 cm_ReleaseUser(userp);
5571 smb_FreeTran2Packet(outp);
5572 smb_DeleteDirSearch(dsp);
5573 smb_ReleaseDirSearch(dsp);
5577 /* get the directory size */
5578 lock_ObtainWrite(&scp->rw);
5579 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5580 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5582 lock_ReleaseWrite(&scp->rw);
5583 cm_ReleaseSCache(scp);
5584 cm_ReleaseUser(userp);
5585 smb_FreeTran2Packet(outp);
5586 smb_DeleteDirSearch(dsp);
5587 smb_ReleaseDirSearch(dsp);
5591 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5594 dirLength = scp->length;
5596 bufferOffset.LowPart = bufferOffset.HighPart = 0;
5597 curOffset.HighPart = 0;
5598 curOffset.LowPart = nextCookie;
5599 origOp = outp->datap;
5606 normchar_t normName[MAX_PATH]; /* Normalized name */
5607 clientchar_t cfileName[MAX_PATH]; /* Non-normalized name */
5610 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5611 /* skip over resume key */
5614 fp = (smb_tran2Find_t *) op;
5616 /* make sure that curOffset.LowPart doesn't point to the first
5617 * 32 bytes in the 2nd through last dir page, and that it doesn't
5618 * point at the first 13 32-byte chunks in the first dir page,
5619 * since those are dir and page headers, and don't contain useful
5622 temp = curOffset.LowPart & (2048-1);
5623 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5624 /* we're in the first page */
5625 if (temp < 13*32) temp = 13*32;
5628 /* we're in a later dir page */
5629 if (temp < 32) temp = 32;
5632 /* make sure the low order 5 bits are zero */
5635 /* now put temp bits back ito curOffset.LowPart */
5636 curOffset.LowPart &= ~(2048-1);
5637 curOffset.LowPart |= temp;
5639 /* check if we've passed the dir's EOF */
5640 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
5641 osi_Log0(smb_logp, "T2 search dir passed eof");
5646 /* check if we've returned all the names that will fit in the
5647 * response packet; we check return count as well as the number
5648 * of bytes requested. We check the # of bytes after we find
5649 * the dir entry, since we'll need to check its size.
5651 if (returnedNames >= maxCount) {
5652 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
5653 returnedNames, maxCount);
5657 /* when we have obtained as many entries as can be processed in
5658 * a single Bulk Status call to the file server, apply the dir listing
5661 if (returnedNames > 0 && returnedNames % AFSCBMAX == 0) {
5662 lock_ReleaseWrite(&scp->rw);
5663 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5664 dsp->relPath, infoLevel, userp, &req);
5665 lock_ObtainWrite(&scp->rw);
5667 /* Then check to see if we have time left to process more entries */
5668 if (GetTickCount() - req.startTime > (RDRtimeout - 15) * 1000) {
5669 osi_Log0(smb_logp, "T2 search dir RDRtimeout exceeded");
5673 /* see if we can use the bufferp we have now; compute in which
5674 * page the current offset would be, and check whether that's
5675 * the offset of the buffer we have. If not, get the buffer.
5677 thyper.HighPart = curOffset.HighPart;
5678 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5679 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5682 buf_Release(bufferp);
5685 lock_ReleaseWrite(&scp->rw);
5686 code = buf_Get(scp, &thyper, &req, &bufferp);
5687 lock_ObtainWrite(&scp->rw);
5689 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
5693 bufferOffset = thyper;
5695 /* now get the data in the cache */
5697 code = cm_SyncOp(scp, bufferp, userp, &req,
5699 CM_SCACHESYNC_NEEDCALLBACK
5700 | CM_SCACHESYNC_READ);
5702 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5706 if (cm_HaveBuffer(scp, bufferp, 0)) {
5707 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5708 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5712 /* otherwise, load the buffer and try again */
5713 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5715 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5717 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5718 scp, bufferp, code);
5723 buf_Release(bufferp);
5727 } /* if (wrong buffer) ... */
5729 /* now we have the buffer containing the entry we're interested
5730 * in; copy it out if it represents a non-deleted entry.
5732 entryInDir = curOffset.LowPart & (2048-1);
5733 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5735 /* page header will help tell us which entries are free. Page
5736 * header can change more often than once per buffer, since
5737 * AFS 3 dir page size may be less than (but not more than)
5738 * a buffer package buffer.
5740 /* only look intra-buffer */
5741 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5742 temp &= ~(2048 - 1); /* turn off intra-page bits */
5743 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5745 /* now determine which entry we're looking at in the page.
5746 * If it is free (there's a free bitmap at the start of the
5747 * dir), we should skip these 32 bytes.
5749 slotInPage = (entryInDir & 0x7e0) >> 5;
5750 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5751 (1 << (slotInPage & 0x7)))) {
5752 /* this entry is free */
5753 numDirChunks = 1; /* only skip this guy */
5757 tp = bufferp->datap + entryInBuffer;
5758 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5760 /* while we're here, compute the next entry's location, too,
5761 * since we'll need it when writing out the cookie into the dir
5764 * XXXX Probably should do more sanity checking.
5766 numDirChunks = cm_NameEntries(dep->name, &onbytes);
5768 /* compute offset of cookie representing next entry */
5769 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5771 if (dep->fid.vnode == 0)
5772 goto nextEntry; /* This entry is not in use */
5774 if (cm_FsStringToClientString(dep->name, -1, cfileName, lengthof(cfileName)) == 0 ||
5775 cm_ClientStringToNormString(cfileName, -1, normName, lengthof(normName)) == 0) {
5777 osi_Log1(smb_logp, "Skipping entry [%s]. Can't convert or normalize FS String",
5778 osi_LogSaveString(smb_logp, dep->name));
5782 /* Need 8.3 name? */
5784 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
5785 !cm_Is8Dot3(cfileName)) {
5786 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5790 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %S (%S)",
5791 dep->fid.vnode, dep->fid.unique,
5792 osi_LogSaveClientString(smb_logp, cfileName),
5793 NeedShortName ? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
5795 /* When matching, we are using doing a case fold if we have a wildcard mask.
5796 * If we get a non-wildcard match, it's a lookup for a specific file.
5798 if (cm_MatchMask(normName, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5799 (NeedShortName && cm_MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))
5801 /* Eliminate entries that don't match requested attributes */
5802 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5803 smb_IsDotFile(cfileName)) {
5804 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5805 goto nextEntry; /* no hidden files */
5808 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5810 /* We have already done the cm_TryBulkStat above */
5811 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume,
5812 ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5813 fileType = cm_FindFileType(&fid);
5814 /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5815 * "has filetype %d", dep->name, fileType);
5817 if ( fileType == CM_SCACHETYPE_DIRECTORY ||
5818 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5819 fileType == CM_SCACHETYPE_DFSLINK ||
5820 fileType == CM_SCACHETYPE_INVALID)
5821 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5825 /* finally check if this name will fit */
5827 smb_UnparseString(opx, NULL, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5828 orbytes = ohbytes + onbytes;
5830 /* now, we round up the record to a 4 byte alignment,
5831 * and we make sure that we have enough room here for
5832 * even the aligned version (so we don't have to worry
5833 * about an overflow when we pad things out below).
5834 * That's the reason for the alignment arithmetic below.
5836 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5837 align = (4 - (orbytes & 3)) & 3;
5841 if (orbytes + bytesInBuffer + align > maxReturnData) {
5842 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5847 /* this is one of the entries to use: it is not deleted
5848 * and it matches the star pattern we're looking for.
5849 * Put out the name, preceded by its length.
5851 /* First zero everything else */
5852 memset(origOp, 0, orbytes);
5855 smb_UnparseString(opx, origOp + ohbytes, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5857 switch (infoLevel) {
5858 case SMB_INFO_STANDARD:
5859 fp->u.FstandardInfo.fileNameLength = onbytes;
5860 attrp = &fp->u.FstandardInfo.fileAttrs;
5863 case SMB_INFO_QUERY_EA_SIZE:
5864 fp->u.FeaSizeInfo.fileNameLength = onbytes;
5865 attrp = &fp->u.FeaSizeInfo.fileAttrs;
5866 fp->u.FeaSizeInfo.eaSize = 0;
5869 case SMB_INFO_QUERY_EAS_FROM_LIST:
5870 fp->u.FeasFromListInfo.fileNameLength = onbytes;
5871 attrp = &fp->u.FeasFromListInfo.fileAttrs;
5872 fp->u.FeasFromListInfo.eaSize = 0;
5875 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5876 if (NeedShortName) {
5880 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
5881 fp->u.FfileBothDirectoryInfo.shortName,
5882 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
5884 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
5886 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5887 fp->u.FfileBothDirectoryInfo.reserved = 0;
5889 cm_ClientStrCpy(fp->u.FfileBothDirectoryInfo.shortName,
5890 lengthof(fp->u.FfileBothDirectoryInfo.shortName),
5892 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
5897 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5898 fp->u.FfileFullDirectoryInfo.eaSize = 0;
5901 case SMB_FIND_FILE_DIRECTORY_INFO:
5902 fp->u.FfileDirectoryInfo.nextEntryOffset = orbytes + align;
5903 fp->u.FfileDirectoryInfo.fileIndex = nextEntryCookie;
5904 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5905 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5908 case SMB_FIND_FILE_NAMES_INFO:
5909 fp->u.FfileNamesInfo.nextEntryOffset = orbytes + align;
5910 fp->u.FfileNamesInfo.fileIndex = nextEntryCookie;
5911 fp->u.FfileNamesInfo.fileNameLength = onbytes;
5916 /* we shouldn't hit this case */
5917 osi_assertx(FALSE, "Unknown query type");
5920 /* now, adjust the # of entries copied */
5923 /* now we emit the attribute. This is tricky, since
5924 * we need to really stat the file to find out what
5925 * type of entry we've got. Right now, we're copying
5926 * out data from a buffer, while holding the scp
5927 * locked, so it isn't really convenient to stat
5928 * something now. We'll put in a place holder
5929 * now, and make a second pass before returning this
5930 * to get the real attributes. So, we just skip the
5931 * data for now, and adjust it later. We allocate a
5932 * patch record to make it easy to find this point
5933 * later. The replay will happen at a time when it is
5934 * safe to unlock the directory.
5936 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5937 osi_assert(attrp != NULL);
5938 curPatchp = malloc(sizeof(*curPatchp));
5939 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5940 curPatchp->dptr = attrp;
5942 if (smb_hideDotFiles && smb_IsDotFile(cfileName)) {
5943 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5945 curPatchp->flags = 0;
5948 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5951 curPatchp->dep = dep;
5954 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5955 /* put out resume key */
5956 *((u_long *)origOp) = nextEntryCookie;
5958 /* Adjust byte ptr and count */
5959 origOp += orbytes; /* skip entire record */
5960 bytesInBuffer += orbytes;
5962 /* and pad the record out */
5963 while (align-- > 0) {
5967 } /* if we're including this name */
5968 else if (!starPattern &&
5970 cm_MatchMask(normName, maskp, CM_FLAG_CASEFOLD)) {
5971 /* We were looking for exact matches, but here's an inexact one*/
5976 /* and adjust curOffset to be where the new cookie is */
5977 thyper.HighPart = 0;
5978 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5979 curOffset = LargeIntegerAdd(thyper, curOffset);
5980 } /* while copying data for dir listing */
5982 /* If we didn't get a star pattern, we did an exact match during the first pass.
5983 * If there were no exact matches found, we fail over to inexact matches by
5984 * marking the query as a star pattern (matches all case permutations), and
5985 * re-running the query.
5987 if (returnedNames == 0 && !starPattern && foundInexact) {
5988 osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
5993 /* release the mutex */
5994 lock_ReleaseWrite(&scp->rw);
5996 buf_Release(bufferp);
6001 * Finally, process whatever entries we have left.
6003 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
6004 dsp->relPath, infoLevel, userp, &req);
6006 /* now put out the final parameters */
6007 if (returnedNames == 0)
6009 if (p->opcode == 1) {
6011 outp->parmsp[0] = (unsigned short) dsp->cookie;
6012 outp->parmsp[1] = returnedNames;
6013 outp->parmsp[2] = eos;
6014 outp->parmsp[3] = 0; /* nothing wrong with EAS */
6015 outp->parmsp[4] = 0;
6016 /* don't need last name to continue
6017 * search, cookie is enough. Normally,
6018 * this is the offset of the file name
6019 * of the last entry returned.
6021 outp->totalParms = 10; /* in bytes */
6025 outp->parmsp[0] = returnedNames;
6026 outp->parmsp[1] = eos;
6027 outp->parmsp[2] = 0; /* EAS error */
6028 outp->parmsp[3] = 0; /* last name, as above */
6029 outp->totalParms = 8; /* in bytes */
6032 /* return # of bytes in the buffer */
6033 outp->totalData = bytesInBuffer;
6035 /* Return error code if unsuccessful on first request */
6036 if (code == 0 && p->opcode == 1 && returnedNames == 0)
6037 code = CM_ERROR_NOSUCHFILE;
6039 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
6040 p->opcode, dsp->cookie, returnedNames, code);
6042 /* if we're supposed to close the search after this request, or if
6043 * we're supposed to close the search if we're done, and we're done,
6044 * or if something went wrong, close the search.
6046 if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
6047 (returnedNames == 0) ||
6048 ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
6050 smb_DeleteDirSearch(dsp);
6053 smb_SendTran2Error(vcp, p, opx, code);
6055 smb_SendTran2Packet(vcp, outp, opx);
6057 smb_FreeTran2Packet(outp);
6058 smb_ReleaseDirSearch(dsp);
6059 cm_ReleaseSCache(scp);
6060 cm_ReleaseUser(userp);
6064 /* SMB_COM_FIND_CLOSE2 */
6065 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6068 smb_dirSearch_t *dsp;
6070 dirHandle = smb_GetSMBParm(inp, 0);
6072 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
6074 dsp = smb_FindDirSearch(dirHandle);
6077 return CM_ERROR_BADFD;
6079 /* otherwise, we have an FD to destroy */
6080 smb_DeleteDirSearch(dsp);
6081 smb_ReleaseDirSearch(dsp);
6083 /* and return results */
6084 smb_SetSMBDataLength(outp, 0);
6090 /* SMB_COM_FIND_NOTIFY_CLOSE */
6091 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6093 smb_SetSMBDataLength(outp, 0);
6097 /* SMB_COM_OPEN_ANDX */
6098 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6100 clientchar_t *pathp;
6105 cm_scache_t *dscp; /* dir we're dealing with */
6106 cm_scache_t *scp; /* file we're creating */
6110 clientchar_t *lastNamep;
6111 unsigned long dosTime;
6117 int parmSlot; /* which parm we're dealing with */
6118 clientchar_t *tidPathp;
6121 BOOL is_rpc = FALSE;
6122 BOOL is_ipc = FALSE;
6128 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
6129 openFun = smb_GetSMBParm(inp, 8); /* open function */
6130 excl = ((openFun & 3) == 0);
6131 trunc = ((openFun & 3) == 2); /* truncate it */
6132 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
6133 openAction = 0; /* tracks what we did */
6135 attributes = smb_GetSMBParm(inp, 5);
6136 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
6138 pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
6141 return CM_ERROR_BADSMB;
6143 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6145 if (code == CM_ERROR_TIDIPC) {
6148 return CM_ERROR_NOSUCHPATH;
6152 spacep = inp->spacep;
6153 /* smb_StripLastComponent will strip "::$DATA" if present */
6154 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6158 /* special case magic file name for receiving IOCTL requests
6159 * (since IOCTL calls themselves aren't getting through).
6161 (cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
6163 /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional) */
6164 (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
6166 unsigned short file_type = 0;
6167 unsigned short device_state = 0;
6169 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6171 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
6172 osi_Log1(smb_logp, "OpenAndX Setting up RPC on fid[%d]", fidp->fid);
6174 osi_Log1(smb_logp, "smb_SetupRPCFid failure code [%d]", code);
6175 smb_ReleaseFID(fidp);
6179 smb_SetupIoctlFid(fidp, spacep);
6180 osi_Log1(smb_logp, "OpenAndX Setting up IOCTL on fid[%d]", fidp->fid);
6183 /* set inp->fid so that later read calls in same msg can find fid */
6184 inp->fid = fidp->fid;
6186 /* copy out remainder of the parms */
6188 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6190 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
6191 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
6192 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6193 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
6194 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
6195 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
6196 smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++;
6197 smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++;
6199 /* and the final "always present" stuff */
6200 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
6201 /* next write out the "unique" ID */
6202 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
6203 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
6204 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6205 smb_SetSMBDataLength(outp, 0);
6207 /* and clean up fid reference */
6208 smb_ReleaseFID(fidp);
6214 osi_Log0(smb_logp, "NTOpenX rejecting IPC TID");
6215 return CM_ERROR_BADFD;
6219 if (!cm_IsValidClientString(pathp)) {
6221 clientchar_t * hexp;
6223 hexp = cm_GetRawCharsAlloc(pathp, -1);
6224 osi_Log1(smb_logp, "NTOpenX rejecting invalid name. [%S]",
6225 osi_LogSaveClientString(smb_logp, hexp));
6229 osi_Log0(smb_logp, "NTOpenX rejecting invalid name");
6231 return CM_ERROR_BADNTFILENAME;
6234 #ifdef DEBUG_VERBOSE
6236 char *hexp, *asciip;
6237 asciip = (lastNamep ? lastNamep : pathp );
6238 hexp = osi_HexifyString(asciip);
6239 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
6243 userp = smb_GetUserFromVCP(vcp, inp);
6246 code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
6247 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6248 userp, tidPathp, &req, &scp);
6251 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6252 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
6253 cm_ReleaseSCache(scp);
6254 cm_ReleaseUser(userp);
6255 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6256 return CM_ERROR_PATH_NOT_COVERED;
6258 return CM_ERROR_NOSUCHPATH;
6260 #endif /* DFS_SUPPORT */
6263 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
6264 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6265 userp, tidPathp, &req, &dscp);
6267 cm_ReleaseUser(userp);
6272 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6273 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
6275 cm_ReleaseSCache(dscp);
6276 cm_ReleaseUser(userp);
6277 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6278 return CM_ERROR_PATH_NOT_COVERED;
6280 return CM_ERROR_NOSUCHPATH;
6282 #endif /* DFS_SUPPORT */
6283 /* otherwise, scp points to the parent directory. Do a lookup,
6284 * and truncate the file if we find it, otherwise we create the
6291 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
6293 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
6294 cm_ReleaseSCache(dscp);
6295 cm_ReleaseUser(userp);
6300 /* if we get here, if code is 0, the file exists and is represented by
6301 * scp. Otherwise, we have to create it. The dir may be represented
6302 * by dscp, or we may have found the file directly. If code is non-zero,
6306 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
6308 if (dscp) cm_ReleaseSCache(dscp);
6309 cm_ReleaseSCache(scp);
6310 cm_ReleaseUser(userp);
6315 /* oops, file shouldn't be there */
6317 cm_ReleaseSCache(dscp);
6318 cm_ReleaseSCache(scp);
6319 cm_ReleaseUser(userp);
6320 return CM_ERROR_EXISTS;
6324 setAttr.mask = CM_ATTRMASK_LENGTH;
6325 setAttr.length.LowPart = 0;
6326 setAttr.length.HighPart = 0;
6327 code = cm_SetAttr(scp, &setAttr, userp, &req);
6328 openAction = 3; /* truncated existing file */
6330 else openAction = 1; /* found existing file */
6332 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
6333 /* don't create if not found */
6334 if (dscp) cm_ReleaseSCache(dscp);
6335 cm_ReleaseUser(userp);
6336 return CM_ERROR_NOSUCHFILE;
6339 osi_assertx(dscp != NULL, "null cm_scache_t");
6340 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %S",
6341 osi_LogSaveClientString(smb_logp, lastNamep));
6342 openAction = 2; /* created file */
6343 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6344 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6345 smb_SetInitialModeBitsForFile(attributes, &setAttr);
6347 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6351 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6352 smb_NotifyChange(FILE_ACTION_ADDED,
6353 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6354 dscp, lastNamep, NULL, TRUE);
6355 } else if (!excl && code == CM_ERROR_EXISTS) {
6356 /* not an exclusive create, and someone else tried
6357 * creating it already, then we open it anyway. We
6358 * don't bother retrying after this, since if this next
6359 * fails, that means that the file was deleted after we
6360 * started this call.
6362 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6366 setAttr.mask = CM_ATTRMASK_LENGTH;
6367 setAttr.length.LowPart = 0;
6368 setAttr.length.HighPart = 0;
6369 code = cm_SetAttr(scp, &setAttr, userp, &req);
6371 } /* lookup succeeded */
6375 /* we don't need this any longer */
6377 cm_ReleaseSCache(dscp);
6380 /* something went wrong creating or truncating the file */
6382 cm_ReleaseSCache(scp);
6383 cm_ReleaseUser(userp);
6387 /* make sure we're about to open a file */
6388 if (scp->fileType != CM_SCACHETYPE_FILE) {
6389 cm_ReleaseSCache(scp);
6390 cm_ReleaseUser(userp);
6391 return CM_ERROR_ISDIR;
6394 /* now all we have to do is open the file itself */
6395 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6396 osi_assertx(fidp, "null smb_fid_t");
6399 lock_ObtainMutex(&fidp->mx);
6400 /* save a pointer to the vnode */
6402 lock_ObtainWrite(&scp->rw);
6403 scp->flags |= CM_SCACHEFLAG_SMB_FID;
6404 lock_ReleaseWrite(&scp->rw);
6405 osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
6407 fidp->userp = userp;
6409 /* compute open mode */
6411 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
6412 if (openMode == 1 || openMode == 2)
6413 fidp->flags |= SMB_FID_OPENWRITE;
6415 /* remember if the file was newly created */
6417 fidp->flags |= SMB_FID_CREATED;
6419 lock_ReleaseMutex(&fidp->mx);
6420 smb_ReleaseFID(fidp);
6422 cm_Open(scp, 0, userp);
6424 /* set inp->fid so that later read calls in same msg can find fid */
6425 inp->fid = fidp->fid;
6427 /* copy out remainder of the parms */
6429 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6430 lock_ObtainRead(&scp->rw);
6432 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
6433 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
6434 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
6435 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
6436 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
6437 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
6438 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
6439 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
6440 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
6442 /* and the final "always present" stuff */
6443 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
6444 /* next write out the "unique" ID */
6445 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
6446 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
6447 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6448 lock_ReleaseRead(&scp->rw);
6449 smb_SetSMBDataLength(outp, 0);
6451 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
6453 cm_ReleaseUser(userp);
6454 /* leave scp held since we put it in fidp->scp */
6458 static void smb_GetLockParams(unsigned char LockType,
6460 unsigned int * ppid,
6461 LARGE_INTEGER * pOffset,
6462 LARGE_INTEGER * pLength)
6464 if (LockType & LOCKING_ANDX_LARGE_FILES) {
6466 *ppid = *((USHORT *) *buf);
6467 pOffset->HighPart = *((LONG *)(*buf + 4));
6468 pOffset->LowPart = *((DWORD *)(*buf + 8));
6469 pLength->HighPart = *((LONG *)(*buf + 12));
6470 pLength->LowPart = *((DWORD *)(*buf + 16));
6474 /* Not Large Files */
6475 *ppid = *((USHORT *) *buf);
6476 pOffset->HighPart = 0;
6477 pOffset->LowPart = *((DWORD *)(*buf + 2));
6478 pLength->HighPart = 0;
6479 pLength->LowPart = *((DWORD *)(*buf + 6));
6484 /* SMB_COM_LOCKING_ANDX */
6485 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6492 unsigned char LockType;
6493 unsigned short NumberOfUnlocks, NumberOfLocks;
6497 LARGE_INTEGER LOffset, LLength;
6498 smb_waitingLockRequest_t *wlRequest = NULL;
6499 cm_file_lock_t *lockp;
6507 fid = smb_GetSMBParm(inp, 2);
6508 fid = smb_ChainFID(fid, inp);
6510 fidp = smb_FindFID(vcp, fid, 0);
6512 osi_Log2(smb_logp, "V3LockingX Unknown SMB Fid vcp 0x%p fid %d",
6514 return CM_ERROR_BADFD;
6516 lock_ObtainMutex(&fidp->mx);
6517 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6518 lock_ReleaseMutex(&fidp->mx);
6519 smb_CloseFID(vcp, fidp, NULL, 0);
6520 smb_ReleaseFID(fidp);
6521 return CM_ERROR_NOSUCHFILE;
6524 if (fidp->flags & SMB_FID_IOCTL) {
6525 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
6526 lock_ReleaseMutex(&fidp->mx);
6527 smb_ReleaseFID(fidp);
6528 return CM_ERROR_BADFD;
6531 osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
6533 lock_ReleaseMutex(&fidp->mx);
6535 /* set inp->fid so that later read calls in same msg can find fid */
6538 userp = smb_GetUserFromVCP(vcp, inp);
6540 lock_ObtainWrite(&scp->rw);
6541 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6542 CM_SCACHESYNC_NEEDCALLBACK
6543 | CM_SCACHESYNC_GETSTATUS
6544 | CM_SCACHESYNC_LOCK);
6546 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
6550 LockType = smb_GetSMBParm(inp, 3) & 0xff;
6551 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
6552 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
6553 NumberOfLocks = smb_GetSMBParm(inp, 7);
6555 if (!(fidp->flags & SMB_FID_OPENWRITE) &&
6556 !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
6557 /* somebody wants exclusive locks on a file that they only
6558 opened for reading. We downgrade this to a shared lock. */
6559 osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
6560 LockType |= LOCKING_ANDX_SHARED_LOCK;
6563 if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
6564 /* AFS does not support atomic changes of lock types from read or write and vice-versa */
6565 osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]");
6566 code = CM_ERROR_BADOP;
6571 op = smb_GetSMBData(inp, NULL);
6573 if (LockType & LOCKING_ANDX_CANCEL_LOCK) {
6574 /* Cancel outstanding lock requests */
6575 smb_waitingLock_t * wl;
6577 for (i=0; i<NumberOfLocks; i++) {
6578 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6580 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6582 lock_ObtainWrite(&smb_globalLock);
6583 for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
6585 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
6586 if (cm_KeyEquals(&wl->key, &key, 0) && LargeIntegerEqualTo(wl->LOffset, LOffset) &&
6587 LargeIntegerEqualTo(wl->LLength, LLength)) {
6588 wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
6589 goto found_lock_request;
6594 lock_ReleaseWrite(&smb_globalLock);
6597 smb_SetSMBDataLength(outp, 0);
6602 for (i=0; i<NumberOfUnlocks; i++) {
6603 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6605 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6607 code = cm_Unlock(scp, LockType, LOffset, LLength, key, 0, userp, &req);
6615 for (i=0; i<NumberOfLocks; i++) {
6616 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6618 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6620 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
6621 userp, &req, &lockp);
6623 if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
6624 (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
6626 code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
6627 userp, &req, &lockp);
6630 if (code == CM_ERROR_LOCK_NOT_GRANTED && Timeout != 0) {
6631 smb_waitingLock_t * wLock;
6633 /* Put on waiting list */
6634 if(wlRequest == NULL) {
6638 LARGE_INTEGER tOffset, tLength;
6640 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
6642 osi_assertx(wlRequest != NULL, "null wlRequest");
6644 wlRequest->vcp = vcp;
6646 wlRequest->scp = scp;
6647 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
6649 wlRequest->inp = smb_CopyPacket(inp);
6650 wlRequest->outp = smb_CopyPacket(outp);
6651 wlRequest->lockType = LockType;
6652 wlRequest->msTimeout = Timeout;
6653 wlRequest->start_t = osi_Time();
6654 wlRequest->locks = NULL;
6656 /* The waiting lock request needs to have enough
6657 information to undo all the locks in the request.
6658 We do the following to store info about locks that
6659 have already been granted. Sure, we can get most
6660 of the info from the packet, but the packet doesn't
6661 hold the result of cm_Lock call. In practice we
6662 only receive packets with one or two locks, so we
6663 are only wasting a few bytes here and there and
6664 only for a limited period of time until the waiting
6665 lock times out or is freed. */
6667 for(opt = op_locks, j=i; j > 0; j--) {
6668 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
6670 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6672 wLock = malloc(sizeof(smb_waitingLock_t));
6674 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6677 wLock->LOffset = tOffset;
6678 wLock->LLength = tLength;
6679 wLock->lockp = NULL;
6680 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
6681 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6686 wLock = malloc(sizeof(smb_waitingLock_t));
6688 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6691 wLock->LOffset = LOffset;
6692 wLock->LLength = LLength;
6693 wLock->lockp = lockp;
6694 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
6695 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6698 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
6706 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
6713 /* Since something went wrong with the lock number i, we now
6714 have to go ahead and release any locks acquired before the
6715 failure. All locks before lock number i (of which there
6716 are i of them) have either been successful or are waiting.
6717 Either case requires calling cm_Unlock(). */
6719 /* And purge the waiting lock */
6720 if(wlRequest != NULL) {
6721 smb_waitingLock_t * wl;
6722 smb_waitingLock_t * wlNext;
6725 for(wl = wlRequest->locks; wl; wl = wlNext) {
6727 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
6729 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, 0, userp, &req);
6732 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
6734 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
6737 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
6742 smb_ReleaseVC(wlRequest->vcp);
6743 cm_ReleaseSCache(wlRequest->scp);
6744 smb_FreePacket(wlRequest->inp);
6745 smb_FreePacket(wlRequest->outp);
6754 if (wlRequest != NULL) {
6756 lock_ObtainWrite(&smb_globalLock);
6757 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
6759 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
6760 lock_ReleaseWrite(&smb_globalLock);
6762 /* don't send reply immediately */
6763 outp->flags |= SMB_PACKETFLAG_NOSEND;
6766 smb_SetSMBDataLength(outp, 0);
6770 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
6773 lock_ReleaseWrite(&scp->rw);
6774 cm_ReleaseSCache(scp);
6775 cm_ReleaseUser(userp);
6776 smb_ReleaseFID(fidp);
6781 /* SMB_COM_QUERY_INFORMATION2 */
6782 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6788 afs_uint32 searchTime;
6795 fid = smb_GetSMBParm(inp, 0);
6796 fid = smb_ChainFID(fid, inp);
6798 fidp = smb_FindFID(vcp, fid, 0);
6800 osi_Log2(smb_logp, "V3GetAttributes Unknown SMB Fid vcp 0x%p fid %d",
6802 return CM_ERROR_BADFD;
6804 lock_ObtainMutex(&fidp->mx);
6805 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6806 lock_ReleaseMutex(&fidp->mx);
6807 smb_CloseFID(vcp, fidp, NULL, 0);
6808 smb_ReleaseFID(fidp);
6809 return CM_ERROR_NOSUCHFILE;
6812 if (fidp->flags & SMB_FID_IOCTL) {
6813 lock_ReleaseMutex(&fidp->mx);
6814 smb_ReleaseFID(fidp);
6815 return CM_ERROR_BADFD;
6818 osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6820 lock_ReleaseMutex(&fidp->mx);
6822 userp = smb_GetUserFromVCP(vcp, inp);
6825 /* otherwise, stat the file */
6826 lock_ObtainWrite(&scp->rw);
6827 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6828 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6832 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6834 lock_ConvertWToR(&scp->rw);
6837 /* decode times. We need a search time, but the response to this
6838 * call provides the date first, not the time, as returned in the
6839 * searchTime variable. So we take the high-order bits first.
6841 cm_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
6842 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
6843 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
6844 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
6845 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
6846 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
6847 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
6849 /* now handle file size and allocation size */
6850 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
6851 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
6852 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
6853 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
6855 /* file attribute */
6856 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
6858 /* and finalize stuff */
6859 smb_SetSMBDataLength(outp, 0);
6864 lock_ReleaseRead(&scp->rw);
6866 lock_ReleaseWrite(&scp->rw);
6867 cm_ReleaseSCache(scp);
6868 cm_ReleaseUser(userp);
6869 smb_ReleaseFID(fidp);
6873 /* SMB_COM_SET_INFORMATION2 */
6874 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6880 afs_uint32 searchTime;
6888 fid = smb_GetSMBParm(inp, 0);
6889 fid = smb_ChainFID(fid, inp);
6891 fidp = smb_FindFID(vcp, fid, 0);
6893 osi_Log2(smb_logp, "V3SetAttributes Unknown SMB Fid vcp 0x%p fid %d",
6895 return CM_ERROR_BADFD;
6897 lock_ObtainMutex(&fidp->mx);
6898 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6899 lock_ReleaseMutex(&fidp->mx);
6900 smb_CloseFID(vcp, fidp, NULL, 0);
6901 smb_ReleaseFID(fidp);
6902 return CM_ERROR_NOSUCHFILE;
6905 if (fidp->flags & SMB_FID_IOCTL) {
6906 lock_ReleaseMutex(&fidp->mx);
6907 smb_ReleaseFID(fidp);
6908 return CM_ERROR_BADFD;
6911 osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6913 lock_ReleaseMutex(&fidp->mx);
6915 userp = smb_GetUserFromVCP(vcp, inp);
6917 /* now prepare to call cm_setattr. This message only sets various times,
6918 * and AFS only implements mtime, and we'll set the mtime if that's
6919 * requested. The others we'll ignore.
6921 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
6923 if (searchTime != 0) {
6924 cm_UnixTimeFromSearchTime(&unixTime, searchTime);
6926 if ( unixTime != -1 ) {
6927 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
6928 attrs.clientModTime = unixTime;
6929 code = cm_SetAttr(scp, &attrs, userp, &req);
6931 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
6933 osi_Log1(smb_logp, "**cm_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
6939 cm_ReleaseSCache(scp);
6940 cm_ReleaseUser(userp);
6941 smb_ReleaseFID(fidp);
6945 /* SMB_COM_WRITE_ANDX */
6946 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6949 long count, written = 0, total_written = 0;
6953 smb_t *smbp = (smb_t*) inp;
6958 int inDataBlockCount;
6960 fd = smb_GetSMBParm(inp, 2);
6961 count = smb_GetSMBParm(inp, 10);
6963 offset.HighPart = 0;
6964 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6966 if (*inp->wctp == 14) {
6967 /* we have a request with 64-bit file offsets */
6968 #ifdef AFS_LARGEFILES
6969 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6971 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6973 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
6974 /* we shouldn't have received this op if we didn't specify
6975 largefile support */
6976 return CM_ERROR_INVAL;
6981 op = inp->data + smb_GetSMBParm(inp, 11);
6982 inDataBlockCount = count;
6984 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
6985 fd, offset.HighPart, offset.LowPart, count);
6987 fd = smb_ChainFID(fd, inp);
6988 fidp = smb_FindFID(vcp, fd, 0);
6990 osi_Log2(smb_logp, "smb_ReceiveV3WriteX Unknown SMB Fid vcp 0x%p fid %d",
6992 return CM_ERROR_BADFD;
6994 lock_ObtainMutex(&fidp->mx);
6995 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6996 lock_ReleaseMutex(&fidp->mx);
6997 smb_CloseFID(vcp, fidp, NULL, 0);
6998 smb_ReleaseFID(fidp);
6999 return CM_ERROR_NOSUCHFILE;
7002 if (fidp->flags & SMB_FID_IOCTL) {
7003 lock_ReleaseMutex(&fidp->mx);
7004 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
7005 smb_ReleaseFID(fidp);
7009 if (fidp->flags & SMB_FID_RPC) {
7010 lock_ReleaseMutex(&fidp->mx);
7011 code = smb_RPCV3Write(fidp, vcp, inp, outp);
7012 smb_ReleaseFID(fidp);
7017 lock_ReleaseMutex(&fidp->mx);
7018 smb_ReleaseFID(fidp);
7019 return CM_ERROR_BADFDOP;
7024 lock_ReleaseMutex(&fidp->mx);
7026 userp = smb_GetUserFromVCP(vcp, inp);
7028 /* special case: 0 bytes transferred means there is no data
7029 transferred. A slight departure from SMB_COM_WRITE where this
7030 means that we are supposed to truncate the file at this
7035 LARGE_INTEGER LOffset;
7036 LARGE_INTEGER LLength;
7039 key = cm_GenerateKey(vcp->vcID, pid, fd);
7041 LOffset.HighPart = offset.HighPart;
7042 LOffset.LowPart = offset.LowPart;
7043 LLength.HighPart = 0;
7044 LLength.LowPart = count;
7046 lock_ObtainWrite(&scp->rw);
7047 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7048 lock_ReleaseWrite(&scp->rw);
7055 * Work around bug in NT client
7057 * When copying a file, the NT client should first copy the data,
7058 * then copy the last write time. But sometimes the NT client does
7059 * these in the wrong order, so the data copies would inadvertently
7060 * cause the last write time to be overwritten. We try to detect this,
7061 * and don't set client mod time if we think that would go against the
7064 lock_ObtainMutex(&fidp->mx);
7065 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7066 lock_ObtainWrite(&fidp->scp->rw);
7067 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7068 scp->clientModTime = time(NULL);
7069 lock_ReleaseWrite(&fidp->scp->rw);
7071 lock_ReleaseMutex(&fidp->mx);
7074 while ( code == 0 && count > 0 ) {
7075 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7076 if (code == 0 && written == 0)
7077 code = CM_ERROR_PARTIALWRITE;
7079 offset = LargeIntegerAdd(offset,
7080 ConvertLongToLargeInteger(written));
7082 total_written += written;
7086 /* slots 0 and 1 are reserved for request chaining and will be
7087 filled in when we return. */
7088 smb_SetSMBParm(outp, 2, total_written);
7089 smb_SetSMBParm(outp, 3, 0); /* reserved */
7090 smb_SetSMBParm(outp, 4, 0); /* reserved */
7091 smb_SetSMBParm(outp, 5, 0); /* reserved */
7092 smb_SetSMBDataLength(outp, 0);
7096 cm_ReleaseSCache(scp);
7097 cm_ReleaseUser(userp);
7098 smb_ReleaseFID(fidp);
7103 /* SMB_COM_READ_ANDX */
7104 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7108 long finalCount = 0;
7112 smb_t *smbp = (smb_t*) inp;
7119 fd = smb_GetSMBParm(inp, 2); /* File ID */
7120 count = smb_GetSMBParm(inp, 5); /* MaxCount */
7121 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7123 if (*inp->wctp == 12) {
7124 /* a request with 64-bit offsets */
7125 #ifdef AFS_LARGEFILES
7126 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
7128 if (LargeIntegerLessThanZero(offset)) {
7129 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
7130 offset.HighPart, offset.LowPart);
7131 return CM_ERROR_BADSMB;
7134 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
7135 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
7136 return CM_ERROR_BADSMB;
7138 offset.HighPart = 0;
7142 offset.HighPart = 0;
7145 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
7146 fd, offset.HighPart, offset.LowPart, count);
7148 fd = smb_ChainFID(fd, inp);
7149 fidp = smb_FindFID(vcp, fd, 0);
7151 osi_Log2(smb_logp, "smb_ReceiveV3Read Unknown SMB Fid vcp 0x%p fid %d",
7153 return CM_ERROR_BADFD;
7156 lock_ObtainMutex(&fidp->mx);
7158 if (fidp->flags & SMB_FID_IOCTL) {
7159 lock_ReleaseMutex(&fidp->mx);
7161 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
7162 smb_ReleaseFID(fidp);
7166 if (fidp->flags & SMB_FID_RPC) {
7167 lock_ReleaseMutex(&fidp->mx);
7169 code = smb_RPCV3Read(fidp, vcp, inp, outp);
7170 smb_ReleaseFID(fidp);
7174 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7175 lock_ReleaseMutex(&fidp->mx);
7176 smb_CloseFID(vcp, fidp, NULL, 0);
7177 smb_ReleaseFID(fidp);
7178 return CM_ERROR_NOSUCHFILE;
7182 lock_ReleaseMutex(&fidp->mx);
7183 smb_ReleaseFID(fidp);
7184 return CM_ERROR_BADFDOP;
7190 lock_ReleaseMutex(&fidp->mx);
7193 key = cm_GenerateKey(vcp->vcID, pid, fd);
7195 LARGE_INTEGER LOffset, LLength;
7197 LOffset.HighPart = offset.HighPart;
7198 LOffset.LowPart = offset.LowPart;
7199 LLength.HighPart = 0;
7200 LLength.LowPart = count;
7202 lock_ObtainWrite(&scp->rw);
7203 code = cm_LockCheckRead(scp, LOffset, LLength, key);
7204 lock_ReleaseWrite(&scp->rw);
7206 cm_ReleaseSCache(scp);
7209 smb_ReleaseFID(fidp);
7213 /* set inp->fid so that later read calls in same msg can find fid */
7216 userp = smb_GetUserFromVCP(vcp, inp);
7218 /* 0 and 1 are reserved for request chaining, were setup by our caller,
7219 * and will be further filled in after we return.
7221 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
7222 smb_SetSMBParm(outp, 3, 0); /* resvd */
7223 smb_SetSMBParm(outp, 4, 0); /* resvd */
7224 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
7225 /* fill in #6 when we have all the parameters' space reserved */
7226 smb_SetSMBParm(outp, 7, 0); /* resv'd */
7227 smb_SetSMBParm(outp, 8, 0); /* resv'd */
7228 smb_SetSMBParm(outp, 9, 0); /* resv'd */
7229 smb_SetSMBParm(outp, 10, 0); /* resv'd */
7230 smb_SetSMBParm(outp, 11, 0); /* reserved */
7232 /* get op ptr after putting in the parms, since otherwise we don't
7233 * know where the data really is.
7235 op = smb_GetSMBData(outp, NULL);
7237 /* now fill in offset from start of SMB header to first data byte (to op) */
7238 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
7240 /* set the packet data length the count of the # of bytes */
7241 smb_SetSMBDataLength(outp, count);
7243 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7245 /* fix some things up */
7246 smb_SetSMBParm(outp, 5, finalCount);
7247 smb_SetSMBDataLength(outp, finalCount);
7249 cm_ReleaseUser(userp);
7250 smb_ReleaseFID(fidp);
7255 * Values for createDisp, copied from NTDDK.H
7257 #define FILE_SUPERSEDE 0 // (???)
7258 #define FILE_OPEN 1 // (open)
7259 #define FILE_CREATE 2 // (exclusive)
7260 #define FILE_OPEN_IF 3 // (non-exclusive)
7261 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
7262 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
7265 #define REQUEST_OPLOCK 2
7266 #define REQUEST_BATCH_OPLOCK 4
7267 #define OPEN_DIRECTORY 8
7268 #define EXTENDED_RESPONSE_REQUIRED 0x10
7270 /* CreateOptions field. */
7271 #define FILE_DIRECTORY_FILE 0x0001
7272 #define FILE_WRITE_THROUGH 0x0002
7273 #define FILE_SEQUENTIAL_ONLY 0x0004
7274 #define FILE_NON_DIRECTORY_FILE 0x0040
7275 #define FILE_NO_EA_KNOWLEDGE 0x0200
7276 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
7277 #define FILE_RANDOM_ACCESS 0x0800
7278 #define FILE_DELETE_ON_CLOSE 0x1000
7279 #define FILE_OPEN_BY_FILE_ID 0x2000
7280 #define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000
7281 #define FILE_NO_COMPRESSION 0x00008000
7282 #define FILE_RESERVE_OPFILTER 0x00100000
7283 #define FILE_OPEN_REPARSE_POINT 0x00200000
7284 #define FILE_OPEN_NO_RECALL 0x00400000
7285 #define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000
7287 /* SMB_COM_NT_CREATE_ANDX */
7288 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7290 clientchar_t *pathp, *realPathp;
7294 cm_scache_t *dscp; /* parent dir */
7295 cm_scache_t *scp; /* file to create or open */
7296 cm_scache_t *targetScp; /* if scp is a symlink */
7298 clientchar_t *lastNamep;
7299 clientchar_t *treeStartp;
7300 unsigned short nameLength;
7302 unsigned int requestOpLock;
7303 unsigned int requestBatchOpLock;
7304 unsigned int mustBeDir;
7305 unsigned int extendedRespRequired;
7306 unsigned int treeCreate;
7308 unsigned int desiredAccess;
7309 unsigned int extAttributes;
7310 unsigned int createDisp;
7311 unsigned int createOptions;
7312 unsigned int shareAccess;
7313 unsigned short baseFid;
7314 smb_fid_t *baseFidp;
7316 cm_scache_t *baseDirp;
7317 unsigned short openAction;
7322 clientchar_t *tidPathp;
7327 int checkDoneRequired = 0;
7328 cm_lock_data_t *ldp = NULL;
7329 BOOL is_rpc = FALSE;
7330 BOOL is_ipc = FALSE;
7334 /* This code is very long and has a lot of if-then-else clauses
7335 * scp and dscp get reused frequently and we need to ensure that
7336 * we don't lose a reference. Start by ensuring that they are NULL.
7343 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
7344 flags = smb_GetSMBOffsetParm(inp, 3, 1)
7345 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
7346 requestOpLock = flags & REQUEST_OPLOCK;
7347 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7348 mustBeDir = flags & OPEN_DIRECTORY;
7349 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7352 * Why all of a sudden 32-bit FID?
7353 * We will reject all bits higher than 16.
7355 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
7356 return CM_ERROR_INVAL;
7357 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
7358 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
7359 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
7360 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
7361 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
7362 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
7363 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
7364 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
7365 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
7366 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
7367 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
7369 /* mustBeDir is never set; createOptions directory bit seems to be
7372 if (createOptions & FILE_DIRECTORY_FILE)
7374 else if (createOptions & FILE_NON_DIRECTORY_FILE)
7379 pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
7380 NULL, SMB_STRF_ANSIPATH);
7382 /* Sometimes path is not null-terminated, so we make a copy. */
7383 realPathp = malloc(nameLength+sizeof(clientchar_t));
7384 memcpy(realPathp, pathp, nameLength+sizeof(clientchar_t));
7385 realPathp[nameLength/sizeof(clientchar_t)] = 0;
7387 spacep = inp->spacep;
7388 /* smb_StripLastComponent will strip "::$DATA" if present */
7389 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
7391 osi_Log1(smb_logp,"NTCreateX for [%S]",osi_LogSaveClientString(smb_logp,realPathp));
7392 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
7393 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%S]", shareAccess, flags, osi_LogSaveClientString(smb_logp,(lastNamep?lastNamep:_C("null"))));
7397 baseDirp = cm_RootSCachep(cm_rootUserp, &req);
7398 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7399 if (code == CM_ERROR_TIDIPC) {
7400 /* Attempt to use a TID allocated for IPC. The client
7401 * is probably looking for DCE RPC end points which we
7402 * don't support OR it could be looking to make a DFS
7405 osi_Log0(smb_logp, "NTCreateX received IPC TID");
7410 osi_Log1(smb_logp, "NTCreateX tidPathp=[%S]", (tidPathp==NULL)?_C("null"): osi_LogSaveClientString(smb_logp,tidPathp));
7414 ((is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)) ||
7416 /* special case magic file name for receiving IOCTL requests
7417 * (since IOCTL calls themselves aren't getting through).
7419 cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0)) {
7421 unsigned short file_type = 0;
7422 unsigned short device_state = 0;
7424 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7427 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
7428 osi_Log1(smb_logp, "NTCreateX Setting up RPC on fid[%d]", fidp->fid);
7430 osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
7431 smb_ReleaseFID(fidp);
7436 smb_SetupIoctlFid(fidp, spacep);
7437 osi_Log1(smb_logp, "NTCreateX Setting up IOCTL on fid[%d]", fidp->fid);
7440 /* set inp->fid so that later read calls in same msg can find fid */
7441 inp->fid = fidp->fid;
7445 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7446 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7447 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
7449 memset(&ft, 0, sizeof(ft));
7450 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7451 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7452 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7453 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7454 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
7455 sz.HighPart = 0x7fff; sz.LowPart = 0;
7456 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
7457 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
7458 smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++; /* filetype */
7459 smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++; /* dev state */
7460 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
7461 smb_SetSMBDataLength(outp, 0);
7463 /* clean up fid reference */
7464 smb_ReleaseFID(fidp);
7471 osi_Log0(smb_logp, "NTCreateX rejecting IPC TID");
7473 return CM_ERROR_BADFD;
7477 if (!cm_IsValidClientString(realPathp)) {
7479 clientchar_t * hexp;
7481 hexp = cm_GetRawCharsAlloc(realPathp, -1);
7482 osi_Log1(smb_logp, "NTCreateX rejecting invalid name. [%S]",
7483 osi_LogSaveClientString(smb_logp, hexp));
7487 osi_Log0(smb_logp, "NTCreateX rejecting invalid name");
7490 return CM_ERROR_BADNTFILENAME;
7493 userp = smb_GetUserFromVCP(vcp, inp);
7495 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
7497 return CM_ERROR_INVAL;
7500 if (baseFidp != 0) {
7501 baseFidp = smb_FindFID(vcp, baseFid, 0);
7503 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
7504 cm_ReleaseUser(userp);
7506 return CM_ERROR_INVAL;
7509 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7511 smb_CloseFID(vcp, baseFidp, NULL, 0);
7512 smb_ReleaseFID(baseFidp);
7513 cm_ReleaseUser(userp);
7514 return CM_ERROR_NOSUCHPATH;
7517 baseDirp = baseFidp->scp;
7521 /* compute open mode */
7523 if (desiredAccess & DELETE)
7524 fidflags |= SMB_FID_OPENDELETE;
7525 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
7526 fidflags |= SMB_FID_OPENREAD_LISTDIR;
7527 if (desiredAccess & AFS_ACCESS_WRITE)
7528 fidflags |= SMB_FID_OPENWRITE;
7529 if (createOptions & FILE_DELETE_ON_CLOSE)
7530 fidflags |= SMB_FID_DELONCLOSE;
7531 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7532 fidflags |= SMB_FID_SEQUENTIAL;
7533 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7534 fidflags |= SMB_FID_RANDOM;
7535 if (createOptions & FILE_OPEN_REPARSE_POINT)
7536 osi_Log0(smb_logp, "NTCreateX Open Reparse Point");
7537 if (smb_IsExecutableFileName(lastNamep))
7538 fidflags |= SMB_FID_EXECUTABLE;
7540 /* and the share mode */
7541 if (shareAccess & FILE_SHARE_READ)
7542 fidflags |= SMB_FID_SHARE_READ;
7543 if (shareAccess & FILE_SHARE_WRITE)
7544 fidflags |= SMB_FID_SHARE_WRITE;
7546 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
7549 /* For an exclusive create, we want to do a case sensitive match for the last component. */
7550 if ( createDisp == FILE_CREATE ||
7551 createDisp == FILE_OVERWRITE ||
7552 createDisp == FILE_OVERWRITE_IF) {
7553 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7554 userp, tidPathp, &req, &dscp);
7557 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7558 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7560 cm_ReleaseSCache(dscp);
7561 cm_ReleaseUser(userp);
7564 smb_ReleaseFID(baseFidp);
7565 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7566 return CM_ERROR_PATH_NOT_COVERED;
7568 return CM_ERROR_NOSUCHPATH;
7570 #endif /* DFS_SUPPORT */
7571 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7573 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7574 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7575 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7576 if (code == 0 && realDirFlag == 1) {
7577 cm_ReleaseSCache(scp);
7578 cm_ReleaseSCache(dscp);
7579 cm_ReleaseUser(userp);
7582 smb_ReleaseFID(baseFidp);
7583 return CM_ERROR_EXISTS;
7587 /* we have both scp and dscp */
7589 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7590 userp, tidPathp, &req, &scp);
7592 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7593 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7594 cm_ReleaseSCache(scp);
7595 cm_ReleaseUser(userp);
7598 smb_ReleaseFID(baseFidp);
7599 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7600 return CM_ERROR_PATH_NOT_COVERED;
7602 return CM_ERROR_NOSUCHPATH;
7604 #endif /* DFS_SUPPORT */
7605 /* we might have scp but not dscp */
7611 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7612 /* look up parent directory */
7613 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
7614 * the immediate parent. We have to work our way up realPathp until we hit something that we
7618 /* we might or might not have scp */
7624 code = cm_NameI(baseDirp, spacep->wdata,
7625 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7626 userp, tidPathp, &req, &dscp);
7629 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7630 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7633 cm_ReleaseSCache(scp);
7634 cm_ReleaseSCache(dscp);
7635 cm_ReleaseUser(userp);
7638 smb_ReleaseFID(baseFidp);
7639 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7640 return CM_ERROR_PATH_NOT_COVERED;
7642 return CM_ERROR_NOSUCHPATH;
7644 #endif /* DFS_SUPPORT */
7647 (tp = cm_ClientStrRChr(spacep->wdata, '\\')) &&
7648 (createDisp == FILE_CREATE) &&
7649 (realDirFlag == 1)) {
7652 treeStartp = realPathp + (tp - spacep->wdata);
7654 if (*tp && !smb_IsLegalFilename(tp)) {
7655 cm_ReleaseUser(userp);
7657 smb_ReleaseFID(baseFidp);
7660 cm_ReleaseSCache(scp);
7661 return CM_ERROR_BADNTFILENAME;
7665 } while (dscp == NULL && code == 0);
7669 /* we might have scp and we might have dscp */
7672 smb_ReleaseFID(baseFidp);
7675 osi_Log0(smb_logp,"NTCreateX parent not found");
7677 cm_ReleaseSCache(scp);
7679 cm_ReleaseSCache(dscp);
7680 cm_ReleaseUser(userp);
7685 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
7686 /* A file exists where we want a directory. */
7688 cm_ReleaseSCache(scp);
7689 cm_ReleaseSCache(dscp);
7690 cm_ReleaseUser(userp);
7692 return CM_ERROR_EXISTS;
7696 lastNamep = realPathp;
7700 if (!smb_IsLegalFilename(lastNamep)) {
7702 cm_ReleaseSCache(scp);
7704 cm_ReleaseSCache(dscp);
7705 cm_ReleaseUser(userp);
7707 return CM_ERROR_BADNTFILENAME;
7710 if (!foundscp && !treeCreate) {
7711 if ( createDisp == FILE_CREATE ||
7712 createDisp == FILE_OVERWRITE ||
7713 createDisp == FILE_OVERWRITE_IF)
7715 code = cm_Lookup(dscp, lastNamep,
7716 CM_FLAG_FOLLOW, userp, &req, &scp);
7718 code = cm_Lookup(dscp, lastNamep,
7719 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7722 if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
7724 cm_ReleaseSCache(dscp);
7725 cm_ReleaseUser(userp);
7730 /* we have scp and dscp */
7732 /* we have scp but not dscp */
7734 smb_ReleaseFID(baseFidp);
7737 /* if we get here, if code is 0, the file exists and is represented by
7738 * scp. Otherwise, we have to create it. The dir may be represented
7739 * by dscp, or we may have found the file directly. If code is non-zero,
7742 if (code == 0 && !treeCreate) {
7743 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7745 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7747 cm_ReleaseSCache(dscp);
7749 cm_ReleaseSCache(scp);
7750 cm_ReleaseUser(userp);
7754 checkDoneRequired = 1;
7756 if (createDisp == FILE_CREATE) {
7757 /* oops, file shouldn't be there */
7758 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7760 cm_ReleaseSCache(dscp);
7762 cm_ReleaseSCache(scp);
7763 cm_ReleaseUser(userp);
7765 return CM_ERROR_EXISTS;
7768 if ( createDisp == FILE_OVERWRITE ||
7769 createDisp == FILE_OVERWRITE_IF) {
7771 setAttr.mask = CM_ATTRMASK_LENGTH;
7772 setAttr.length.LowPart = 0;
7773 setAttr.length.HighPart = 0;
7774 /* now watch for a symlink */
7776 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7778 osi_assertx(dscp != NULL, "null cm_scache_t");
7779 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7781 /* we have a more accurate file to use (the
7782 * target of the symbolic link). Otherwise,
7783 * we'll just use the symlink anyway.
7785 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7787 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7788 cm_ReleaseSCache(scp);
7790 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7792 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7794 cm_ReleaseSCache(dscp);
7796 cm_ReleaseSCache(scp);
7797 cm_ReleaseUser(userp);
7803 code = cm_SetAttr(scp, &setAttr, userp, &req);
7804 openAction = 3; /* truncated existing file */
7807 openAction = 1; /* found existing file */
7809 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7810 /* don't create if not found */
7812 cm_ReleaseSCache(dscp);
7814 cm_ReleaseSCache(scp);
7815 cm_ReleaseUser(userp);
7817 return CM_ERROR_NOSUCHFILE;
7818 } else if (realDirFlag == 0 || realDirFlag == -1) {
7819 osi_assertx(dscp != NULL, "null cm_scache_t");
7820 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %S",
7821 osi_LogSaveClientString(smb_logp, lastNamep));
7822 openAction = 2; /* created file */
7823 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7824 setAttr.clientModTime = time(NULL);
7825 smb_SetInitialModeBitsForFile(extAttributes, &setAttr);
7827 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
7830 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7831 smb_NotifyChange(FILE_ACTION_ADDED,
7832 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7833 dscp, lastNamep, NULL, TRUE);
7834 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7835 /* Not an exclusive create, and someone else tried
7836 * creating it already, then we open it anyway. We
7837 * don't bother retrying after this, since if this next
7838 * fails, that means that the file was deleted after we
7839 * started this call.
7841 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7844 if (createDisp == FILE_OVERWRITE_IF) {
7845 setAttr.mask = CM_ATTRMASK_LENGTH;
7846 setAttr.length.LowPart = 0;
7847 setAttr.length.HighPart = 0;
7849 /* now watch for a symlink */
7851 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7853 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7855 /* we have a more accurate file to use (the
7856 * target of the symbolic link). Otherwise,
7857 * we'll just use the symlink anyway.
7859 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7861 cm_ReleaseSCache(scp);
7865 code = cm_SetAttr(scp, &setAttr, userp, &req);
7867 } /* lookup succeeded */
7870 clientchar_t *tp, *pp;
7871 clientchar_t *cp; /* This component */
7872 int clen = 0; /* length of component */
7873 cm_scache_t *tscp1, *tscp2;
7876 /* create directory */
7878 treeStartp = lastNamep;
7879 osi_assertx(dscp != NULL, "null cm_scache_t");
7880 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%S]",
7881 osi_LogSaveClientString(smb_logp, treeStartp));
7882 openAction = 2; /* created directory */
7884 /* if the request is to create the root directory
7885 * it will appear as a directory name of the nul-string
7886 * and a code of CM_ERROR_NOSUCHFILE
7888 if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
7889 code = CM_ERROR_EXISTS;
7891 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7892 setAttr.clientModTime = time(NULL);
7893 smb_SetInitialModeBitsForDir(extAttributes, &setAttr);
7898 cm_HoldSCache(tscp1);
7902 tp = cm_ClientStrChr(pp, '\\');
7904 cm_ClientStrCpy(cp, lengthof(spacep->wdata) - (cp - spacep->wdata), pp);
7905 clen = (int)cm_ClientStrLen(cp);
7906 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
7908 clen = (int)(tp - pp);
7909 cm_ClientStrCpyN(cp, lengthof(spacep->wdata) - (cp - spacep->wdata),
7917 continue; /* the supplied path can't have consecutive slashes either , but */
7919 /* cp is the next component to be created. */
7920 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req, NULL);
7921 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
7922 smb_NotifyChange(FILE_ACTION_ADDED,
7923 FILE_NOTIFY_CHANGE_DIR_NAME,
7924 tscp1, cp, NULL, TRUE);
7926 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7927 /* Not an exclusive create, and someone else tried
7928 * creating it already, then we open it anyway. We
7929 * don't bother retrying after this, since if this next
7930 * fails, that means that the file was deleted after we
7931 * started this call.
7933 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
7934 userp, &req, &tscp2);
7939 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
7940 cm_ReleaseSCache(tscp1);
7941 tscp1 = tscp2; /* Newly created directory will be next parent */
7942 /* the hold is transfered to tscp1 from tscp2 */
7947 cm_ReleaseSCache(dscp);
7950 cm_ReleaseSCache(scp);
7953 * if we get here and code == 0, then scp is the last directory created, and dscp is the
7959 /* something went wrong creating or truncating the file */
7960 if (checkDoneRequired)
7961 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7963 cm_ReleaseSCache(scp);
7965 cm_ReleaseSCache(dscp);
7966 cm_ReleaseUser(userp);
7971 /* make sure we have file vs. dir right (only applies for single component case) */
7972 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7973 /* now watch for a symlink */
7975 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7976 cm_scache_t * targetScp = 0;
7977 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7979 /* we have a more accurate file to use (the
7980 * target of the symbolic link). Otherwise,
7981 * we'll just use the symlink anyway.
7983 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
7984 if (checkDoneRequired) {
7985 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7986 checkDoneRequired = 0;
7988 cm_ReleaseSCache(scp);
7993 if (scp->fileType != CM_SCACHETYPE_FILE) {
7994 if (checkDoneRequired)
7995 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7997 cm_ReleaseSCache(dscp);
7998 cm_ReleaseSCache(scp);
7999 cm_ReleaseUser(userp);
8001 return CM_ERROR_ISDIR;
8005 /* (only applies to single component case) */
8006 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8007 if (checkDoneRequired)
8008 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8009 cm_ReleaseSCache(scp);
8011 cm_ReleaseSCache(dscp);
8012 cm_ReleaseUser(userp);
8014 return CM_ERROR_NOTDIR;
8017 /* open the file itself */
8018 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8019 osi_assertx(fidp, "null smb_fid_t");
8021 /* save a reference to the user */
8023 fidp->userp = userp;
8025 /* If we are restricting sharing, we should do so with a suitable
8027 if (scp->fileType == CM_SCACHETYPE_FILE &&
8028 !(fidflags & SMB_FID_SHARE_WRITE)) {
8030 LARGE_INTEGER LOffset, LLength;
8033 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8034 LOffset.LowPart = SMB_FID_QLOCK_LOW;
8035 LLength.HighPart = 0;
8036 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8038 /* If we are not opening the file for writing, then we don't
8039 try to get an exclusive lock. No one else should be able to
8040 get an exclusive lock on the file anyway, although someone
8041 else can get a shared lock. */
8042 if ((fidflags & SMB_FID_SHARE_READ) ||
8043 !(fidflags & SMB_FID_OPENWRITE)) {
8044 sLockType = LOCKING_ANDX_SHARED_LOCK;
8049 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8051 lock_ObtainWrite(&scp->rw);
8052 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8053 lock_ReleaseWrite(&scp->rw);
8056 if (checkDoneRequired)
8057 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8058 cm_ReleaseSCache(scp);
8060 cm_ReleaseSCache(dscp);
8061 cm_ReleaseUser(userp);
8062 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
8063 smb_CloseFID(vcp, fidp, NULL, 0);
8064 smb_ReleaseFID(fidp);
8066 return CM_ERROR_SHARING_VIOLATION;
8070 /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
8071 if (checkDoneRequired) {
8072 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8073 checkDoneRequired = 0;
8076 lock_ObtainMutex(&fidp->mx);
8077 /* save a pointer to the vnode */
8078 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
8079 lock_ObtainWrite(&scp->rw);
8080 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8081 lock_ReleaseWrite(&scp->rw);
8082 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
8084 fidp->flags = fidflags;
8086 /* remember if the file was newly created */
8088 fidp->flags |= SMB_FID_CREATED;
8090 /* save parent dir and pathname for delete or change notification */
8091 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8092 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
8093 fidp->flags |= SMB_FID_NTOPEN;
8094 fidp->NTopen_dscp = dscp;
8096 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
8098 fidp->NTopen_wholepathp = realPathp;
8099 lock_ReleaseMutex(&fidp->mx);
8101 /* we don't need this any longer */
8103 cm_ReleaseSCache(dscp);
8107 cm_Open(scp, 0, userp);
8109 /* set inp->fid so that later read calls in same msg can find fid */
8110 inp->fid = fidp->fid;
8112 lock_ObtainRead(&scp->rw);
8115 * Always send the standard response. Sending the extended
8116 * response results in the Explorer Shell being unable to
8117 * access directories at random times.
8119 if (1 /*!extendedRespRequired */) {
8122 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
8123 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
8124 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
8125 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8126 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8127 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8128 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8129 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8130 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
8132 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8133 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8134 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
8135 smb_SetSMBParm(outp, parmSlot, NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS);
8136 parmSlot++; /* dev state */
8137 smb_SetSMBParmByte(outp, parmSlot,
8138 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8139 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8140 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
8141 smb_SetSMBDataLength(outp, 0);
8145 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
8146 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
8147 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
8148 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8149 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8150 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8151 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8152 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8153 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
8155 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8156 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8157 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
8158 smb_SetSMBParm(outp, parmSlot, NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS);
8159 parmSlot++; /* dev state */
8160 smb_SetSMBParmByte(outp, parmSlot,
8161 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8162 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8163 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
8164 /* Setting the GUID results in a failure with cygwin */
8165 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8166 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8167 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8168 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8169 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8170 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8171 /* Maxmimal access rights */
8172 smb_SetSMBParmLong(outp, parmSlot, 0x001f01ff); parmSlot += 2;
8173 /* Guest access rights */
8174 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8175 smb_SetSMBDataLength(outp, 0);
8178 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
8179 LargeIntegerGreaterThanZero(scp->length) &&
8180 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
8183 lock_ReleaseRead(&scp->rw);
8186 cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
8187 scp->length.LowPart, scp->length.HighPart,
8191 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %S", fidp->fid,
8192 osi_LogSaveClientString(smb_logp, realPathp));
8194 cm_ReleaseUser(userp);
8195 smb_ReleaseFID(fidp);
8197 /* Can't free realPathp if we get here since
8198 fidp->NTopen_wholepathp is pointing there */
8200 /* leave scp held since we put it in fidp->scp */
8205 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
8206 * Instead, ultimately, would like to use a subroutine for common code.
8209 /* NT_TRANSACT_CREATE (SMB_COM_NT_TRANSACT) */
8210 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8212 clientchar_t *pathp, *realPathp;
8216 cm_scache_t *dscp; /* parent dir */
8217 cm_scache_t *scp; /* file to create or open */
8218 cm_scache_t *targetScp; /* if scp is a symlink */
8220 clientchar_t *lastNamep;
8221 unsigned long nameLength;
8223 unsigned int requestOpLock;
8224 unsigned int requestBatchOpLock;
8225 unsigned int mustBeDir;
8226 unsigned int extendedRespRequired;
8228 unsigned int desiredAccess;
8229 unsigned int allocSize;
8230 unsigned int shareAccess;
8231 unsigned int extAttributes;
8232 unsigned int createDisp;
8235 unsigned int impLevel;
8236 unsigned int secFlags;
8237 unsigned int createOptions;
8238 unsigned short baseFid;
8239 smb_fid_t *baseFidp;
8241 cm_scache_t *baseDirp;
8242 unsigned short openAction;
8246 clientchar_t *tidPathp;
8248 int parmOffset, dataOffset;
8255 cm_lock_data_t *ldp = NULL;
8256 int checkDoneRequired = 0;
8263 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8264 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8265 parmp = inp->data + parmOffset;
8266 lparmp = (ULONG *) parmp;
8269 requestOpLock = flags & REQUEST_OPLOCK;
8270 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
8271 mustBeDir = flags & OPEN_DIRECTORY;
8272 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
8275 * Why all of a sudden 32-bit FID?
8276 * We will reject all bits higher than 16.
8278 if (lparmp[1] & 0xFFFF0000)
8279 return CM_ERROR_INVAL;
8280 baseFid = (unsigned short)lparmp[1];
8281 desiredAccess = lparmp[2];
8282 allocSize = lparmp[3];
8283 extAttributes = lparmp[5];
8284 shareAccess = lparmp[6];
8285 createDisp = lparmp[7];
8286 createOptions = lparmp[8];
8289 nameLength = lparmp[11]; /* spec says chars but appears to be bytes */
8290 impLevel = lparmp[12];
8291 secFlags = lparmp[13];
8293 /* mustBeDir is never set; createOptions directory bit seems to be
8296 if (createOptions & FILE_DIRECTORY_FILE)
8298 else if (createOptions & FILE_NON_DIRECTORY_FILE)
8303 pathp = smb_ParseStringCb(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
8304 nameLength, NULL, SMB_STRF_ANSIPATH);
8305 /* Sometimes path is not nul-terminated, so we make a copy. */
8306 realPathp = malloc(nameLength+sizeof(clientchar_t));
8307 memcpy(realPathp, pathp, nameLength);
8308 realPathp[nameLength/sizeof(clientchar_t)] = 0;
8309 spacep = cm_GetSpace();
8310 /* smb_StripLastComponent will strip "::$DATA" if present */
8311 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
8313 osi_Log1(smb_logp,"NTTranCreate %S",osi_LogSaveStringW(smb_logp,realPathp));
8314 osi_Log4(smb_logp,"... da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
8315 osi_Log4(smb_logp,"... co[%x],sdl[%x],eal[%x],as[%x],flags[%x]",createOptions,sdLen,eaLen,allocSize);
8316 osi_Log3(smb_logp,"... imp[%x],sec[%x],flags[%x]", impLevel, secFlags, flags);
8319 * Nothing here to handle SMB_IOCTL_FILENAME.
8320 * Will add it if necessary.
8323 if (!cm_IsValidClientString(realPathp)) {
8325 clientchar_t * hexp;
8327 hexp = cm_GetRawCharsAlloc(realPathp, -1);
8328 osi_Log1(smb_logp, "NTTranCreate rejecting invalid name. [%S]",
8329 osi_LogSaveClientString(smb_logp, hexp));
8333 osi_Log0(smb_logp, "NTTranCreate rejecting invalid name.");
8336 return CM_ERROR_BADNTFILENAME;
8339 userp = smb_GetUserFromVCP(vcp, inp);
8341 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
8343 return CM_ERROR_INVAL;
8348 baseDirp = cm_RootSCachep(cm_rootUserp, &req);
8349 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8350 if (code == CM_ERROR_TIDIPC) {
8351 /* Attempt to use a TID allocated for IPC. The client
8352 * is probably looking for DCE RPC end points which we
8353 * don't support OR it could be looking to make a DFS
8356 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
8359 cm_ReleaseUser(userp);
8360 return CM_ERROR_NOSUCHPATH;
8364 baseFidp = smb_FindFID(vcp, baseFid, 0);
8366 osi_Log2(smb_logp, "NTTranCreate Unknown SMB Fid vcp 0x%p fid %d",
8369 cm_ReleaseUser(userp);
8370 return CM_ERROR_BADFD;
8373 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8375 cm_ReleaseUser(userp);
8376 smb_CloseFID(vcp, baseFidp, NULL, 0);
8377 smb_ReleaseFID(baseFidp);
8378 return CM_ERROR_NOSUCHPATH;
8381 baseDirp = baseFidp->scp;
8385 /* compute open mode */
8387 if (desiredAccess & DELETE)
8388 fidflags |= SMB_FID_OPENDELETE;
8389 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
8390 fidflags |= SMB_FID_OPENREAD_LISTDIR;
8391 if (desiredAccess & AFS_ACCESS_WRITE)
8392 fidflags |= SMB_FID_OPENWRITE;
8393 if (createOptions & FILE_DELETE_ON_CLOSE)
8394 fidflags |= SMB_FID_DELONCLOSE;
8395 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
8396 fidflags |= SMB_FID_SEQUENTIAL;
8397 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
8398 fidflags |= SMB_FID_RANDOM;
8399 if (createOptions & FILE_OPEN_REPARSE_POINT)
8400 osi_Log0(smb_logp, "NTTranCreate Open Reparse Point");
8401 if (smb_IsExecutableFileName(lastNamep))
8402 fidflags |= SMB_FID_EXECUTABLE;
8404 /* And the share mode */
8405 if (shareAccess & FILE_SHARE_READ)
8406 fidflags |= SMB_FID_SHARE_READ;
8407 if (shareAccess & FILE_SHARE_WRITE)
8408 fidflags |= SMB_FID_SHARE_WRITE;
8412 if ( createDisp == FILE_OPEN ||
8413 createDisp == FILE_OVERWRITE ||
8414 createDisp == FILE_OVERWRITE_IF) {
8415 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8416 userp, tidPathp, &req, &dscp);
8419 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8420 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8421 cm_ReleaseSCache(dscp);
8422 cm_ReleaseUser(userp);
8425 smb_ReleaseFID(baseFidp);
8426 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8427 return CM_ERROR_PATH_NOT_COVERED;
8429 return CM_ERROR_NOSUCHPATH;
8431 #endif /* DFS_SUPPORT */
8432 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
8434 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
8435 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
8436 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
8437 if (code == 0 && realDirFlag == 1) {
8438 cm_ReleaseSCache(scp);
8439 cm_ReleaseSCache(dscp);
8440 cm_ReleaseUser(userp);
8443 smb_ReleaseFID(baseFidp);
8444 return CM_ERROR_EXISTS;
8450 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8451 userp, tidPathp, &req, &scp);
8453 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
8454 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
8455 cm_ReleaseSCache(scp);
8456 cm_ReleaseUser(userp);
8459 smb_ReleaseFID(baseFidp);
8460 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8461 return CM_ERROR_PATH_NOT_COVERED;
8463 return CM_ERROR_NOSUCHPATH;
8465 #endif /* DFS_SUPPORT */
8471 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
8472 /* look up parent directory */
8474 code = cm_NameI(baseDirp, spacep->wdata,
8475 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8476 userp, tidPathp, &req, &dscp);
8478 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8479 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8480 cm_ReleaseSCache(dscp);
8481 cm_ReleaseUser(userp);
8484 smb_ReleaseFID(baseFidp);
8485 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8486 return CM_ERROR_PATH_NOT_COVERED;
8488 return CM_ERROR_NOSUCHPATH;
8490 #endif /* DFS_SUPPORT */
8494 cm_FreeSpace(spacep);
8497 smb_ReleaseFID(baseFidp);
8500 cm_ReleaseUser(userp);
8506 lastNamep = realPathp;
8510 if (!smb_IsLegalFilename(lastNamep))
8511 return CM_ERROR_BADNTFILENAME;
8514 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
8515 code = cm_Lookup(dscp, lastNamep,
8516 CM_FLAG_FOLLOW, userp, &req, &scp);
8518 code = cm_Lookup(dscp, lastNamep,
8519 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8522 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8523 cm_ReleaseSCache(dscp);
8524 cm_ReleaseUser(userp);
8531 smb_ReleaseFID(baseFidp);
8532 cm_FreeSpace(spacep);
8535 /* if we get here, if code is 0, the file exists and is represented by
8536 * scp. Otherwise, we have to create it. The dir may be represented
8537 * by dscp, or we may have found the file directly. If code is non-zero,
8541 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
8543 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8545 cm_ReleaseSCache(dscp);
8546 cm_ReleaseSCache(scp);
8547 cm_ReleaseUser(userp);
8551 checkDoneRequired = 1;
8553 if (createDisp == FILE_CREATE) {
8554 /* oops, file shouldn't be there */
8555 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8557 cm_ReleaseSCache(dscp);
8558 cm_ReleaseSCache(scp);
8559 cm_ReleaseUser(userp);
8561 return CM_ERROR_EXISTS;
8564 if (createDisp == FILE_OVERWRITE ||
8565 createDisp == FILE_OVERWRITE_IF) {
8566 setAttr.mask = CM_ATTRMASK_LENGTH;
8567 setAttr.length.LowPart = 0;
8568 setAttr.length.HighPart = 0;
8570 /* now watch for a symlink */
8572 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8574 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8576 /* we have a more accurate file to use (the
8577 * target of the symbolic link). Otherwise,
8578 * we'll just use the symlink anyway.
8580 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8582 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8583 cm_ReleaseSCache(scp);
8585 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
8587 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8589 cm_ReleaseSCache(dscp);
8591 cm_ReleaseSCache(scp);
8592 cm_ReleaseUser(userp);
8598 code = cm_SetAttr(scp, &setAttr, userp, &req);
8599 openAction = 3; /* truncated existing file */
8601 else openAction = 1; /* found existing file */
8603 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
8604 /* don't create if not found */
8606 cm_ReleaseSCache(dscp);
8607 cm_ReleaseUser(userp);
8609 return CM_ERROR_NOSUCHFILE;
8611 else if (realDirFlag == 0 || realDirFlag == -1) {
8612 osi_assertx(dscp != NULL, "null cm_scache_t");
8613 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %S",
8614 osi_LogSaveClientString(smb_logp, lastNamep));
8615 openAction = 2; /* created file */
8616 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8617 setAttr.clientModTime = time(NULL);
8618 smb_SetInitialModeBitsForFile(extAttributes, &setAttr);
8620 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8624 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8625 smb_NotifyChange(FILE_ACTION_ADDED,
8626 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8627 dscp, lastNamep, NULL, TRUE);
8628 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
8629 /* Not an exclusive create, and someone else tried
8630 * creating it already, then we open it anyway. We
8631 * don't bother retrying after this, since if this next
8632 * fails, that means that the file was deleted after we
8633 * started this call.
8635 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8638 if (createDisp == FILE_OVERWRITE_IF) {
8639 setAttr.mask = CM_ATTRMASK_LENGTH;
8640 setAttr.length.LowPart = 0;
8641 setAttr.length.HighPart = 0;
8643 /* now watch for a symlink */
8645 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8647 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8649 /* we have a more accurate file to use (the
8650 * target of the symbolic link). Otherwise,
8651 * we'll just use the symlink anyway.
8653 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8655 cm_ReleaseSCache(scp);
8659 code = cm_SetAttr(scp, &setAttr, userp, &req);
8661 } /* lookup succeeded */
8664 /* create directory */
8665 osi_assertx(dscp != NULL, "null cm_scache_t");
8667 "smb_ReceiveNTTranCreate creating directory %S",
8668 osi_LogSaveClientString(smb_logp, lastNamep));
8669 openAction = 2; /* created directory */
8670 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8671 setAttr.clientModTime = time(NULL);
8672 smb_SetInitialModeBitsForDir(extAttributes, &setAttr);
8674 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8675 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8676 smb_NotifyChange(FILE_ACTION_ADDED,
8677 FILE_NOTIFY_CHANGE_DIR_NAME,
8678 dscp, lastNamep, NULL, TRUE);
8680 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
8681 /* Not an exclusive create, and someone else tried
8682 * creating it already, then we open it anyway. We
8683 * don't bother retrying after this, since if this next
8684 * fails, that means that the file was deleted after we
8685 * started this call.
8687 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8693 /* something went wrong creating or truncating the file */
8694 if (checkDoneRequired)
8695 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8697 cm_ReleaseSCache(scp);
8698 cm_ReleaseUser(userp);
8703 /* make sure we have file vs. dir right */
8704 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
8705 /* now watch for a symlink */
8707 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8709 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8711 /* we have a more accurate file to use (the
8712 * target of the symbolic link). Otherwise,
8713 * we'll just use the symlink anyway.
8715 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8717 if (checkDoneRequired) {
8718 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8719 checkDoneRequired = 0;
8721 cm_ReleaseSCache(scp);
8726 if (scp->fileType != CM_SCACHETYPE_FILE) {
8727 if (checkDoneRequired)
8728 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8729 cm_ReleaseSCache(scp);
8730 cm_ReleaseUser(userp);
8732 return CM_ERROR_ISDIR;
8736 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8737 if (checkDoneRequired)
8738 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8739 cm_ReleaseSCache(scp);
8740 cm_ReleaseUser(userp);
8742 return CM_ERROR_NOTDIR;
8745 /* open the file itself */
8746 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8747 osi_assertx(fidp, "null smb_fid_t");
8749 /* save a reference to the user */
8751 fidp->userp = userp;
8753 /* If we are restricting sharing, we should do so with a suitable
8755 if (scp->fileType == CM_SCACHETYPE_FILE &&
8756 !(fidflags & SMB_FID_SHARE_WRITE)) {
8758 LARGE_INTEGER LOffset, LLength;
8761 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8762 LOffset.LowPart = SMB_FID_QLOCK_LOW;
8763 LLength.HighPart = 0;
8764 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8766 /* Similar to what we do in handling NTCreateX. We get a
8767 shared lock if we are only opening the file for reading. */
8768 if ((fidflags & SMB_FID_SHARE_READ) ||
8769 !(fidflags & SMB_FID_OPENWRITE)) {
8770 sLockType = LOCKING_ANDX_SHARED_LOCK;
8775 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8777 lock_ObtainWrite(&scp->rw);
8778 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8779 lock_ReleaseWrite(&scp->rw);
8782 if (checkDoneRequired)
8783 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8784 cm_ReleaseSCache(scp);
8785 cm_ReleaseUser(userp);
8786 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
8787 smb_CloseFID(vcp, fidp, NULL, 0);
8788 smb_ReleaseFID(fidp);
8790 return CM_ERROR_SHARING_VIOLATION;
8794 /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
8795 if (checkDoneRequired) {
8796 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8797 checkDoneRequired = 0;
8800 lock_ObtainMutex(&fidp->mx);
8801 /* save a pointer to the vnode */
8803 lock_ObtainWrite(&scp->rw);
8804 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8805 lock_ReleaseWrite(&scp->rw);
8806 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
8808 fidp->flags = fidflags;
8810 /* remember if the file was newly created */
8812 fidp->flags |= SMB_FID_CREATED;
8814 /* save parent dir and pathname for deletion or change notification */
8815 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8816 fidp->flags |= SMB_FID_NTOPEN;
8817 fidp->NTopen_dscp = dscp;
8818 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
8820 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
8822 fidp->NTopen_wholepathp = realPathp;
8823 lock_ReleaseMutex(&fidp->mx);
8825 /* we don't need this any longer */
8827 cm_ReleaseSCache(dscp);
8829 cm_Open(scp, 0, userp);
8831 /* set inp->fid so that later read calls in same msg can find fid */
8832 inp->fid = fidp->fid;
8834 /* check whether we are required to send an extended response */
8835 if (!extendedRespRequired) {
8837 parmOffset = 8*4 + 39;
8838 parmOffset += 1; /* pad to 4 */
8839 dataOffset = parmOffset + 70;
8843 /* Total Parameter Count */
8844 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8845 /* Total Data Count */
8846 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8847 /* Parameter Count */
8848 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8849 /* Parameter Offset */
8850 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8851 /* Parameter Displacement */
8852 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8854 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8856 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8857 /* Data Displacement */
8858 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8859 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8860 smb_SetSMBDataLength(outp, 70);
8862 lock_ObtainRead(&scp->rw);
8863 outData = smb_GetSMBData(outp, NULL);
8864 outData++; /* round to get to parmOffset */
8865 *outData = 0; outData++; /* oplock */
8866 *outData = 0; outData++; /* reserved */
8867 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8868 *((ULONG *)outData) = openAction; outData += 4;
8869 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8870 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8871 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8872 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8873 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8874 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8875 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8876 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8877 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8878 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8879 *((USHORT *)outData) = NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS;
8880 outData += 2; /* dev state */
8881 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8882 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8883 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8884 outData += 2; /* is a dir? */
8887 parmOffset = 8*4 + 39;
8888 parmOffset += 1; /* pad to 4 */
8889 dataOffset = parmOffset + 104;
8893 /* Total Parameter Count */
8894 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8895 /* Total Data Count */
8896 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8897 /* Parameter Count */
8898 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8899 /* Parameter Offset */
8900 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8901 /* Parameter Displacement */
8902 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8904 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8906 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8907 /* Data Displacement */
8908 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8909 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8910 smb_SetSMBDataLength(outp, 105);
8912 lock_ObtainRead(&scp->rw);
8913 outData = smb_GetSMBData(outp, NULL);
8914 outData++; /* round to get to parmOffset */
8915 *outData = 0; outData++; /* oplock */
8916 *outData = 1; outData++; /* response type */
8917 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8918 *((ULONG *)outData) = openAction; outData += 4;
8919 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8920 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8921 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8922 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8923 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8924 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8925 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8926 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8927 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8928 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8929 *((USHORT *)outData) = NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS;
8930 outData += 2; /* dev state */
8931 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8932 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8933 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8934 outData += 1; /* is a dir? */
8935 /* Setting the GUID results in failures with cygwin */
8936 memset(outData,0,24); outData += 24; /* GUID */
8937 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
8938 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
8941 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
8942 LargeIntegerGreaterThanZero(scp->length) &&
8943 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
8946 lock_ReleaseRead(&scp->rw);
8949 cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
8950 scp->length.LowPart, scp->length.HighPart,
8953 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
8955 cm_ReleaseUser(userp);
8956 smb_ReleaseFID(fidp);
8958 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
8959 /* leave scp held since we put it in fidp->scp */
8963 /* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
8964 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
8967 smb_packet_t *savedPacketp;
8969 USHORT fid, watchtree;
8973 filter = smb_GetSMBParm(inp, 19) |
8974 (smb_GetSMBParm(inp, 20) << 16);
8975 fid = smb_GetSMBParm(inp, 21);
8976 watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
8978 fidp = smb_FindFID(vcp, fid, 0);
8980 osi_Log2(smb_logp, "NotifyChange Unknown SMB Fid vcp 0x%p fid %d",
8982 return CM_ERROR_BADFD;
8985 lock_ObtainMutex(&fidp->mx);
8986 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8987 lock_ReleaseMutex(&fidp->mx);
8988 smb_CloseFID(vcp, fidp, NULL, 0);
8989 smb_ReleaseFID(fidp);
8990 return CM_ERROR_NOSUCHFILE;
8994 lock_ReleaseMutex(&fidp->mx);
8996 /* Create a copy of the Directory Watch Packet to use when sending the
8997 * notification if in the future a matching change is detected.
8999 savedPacketp = smb_CopyPacket(inp);
9000 if (vcp != savedPacketp->vcp) {
9002 if (savedPacketp->vcp)
9003 smb_ReleaseVC(savedPacketp->vcp);
9004 savedPacketp->vcp = vcp;
9007 /* Add the watch to the list of events to send notifications for */
9008 lock_ObtainMutex(&smb_Dir_Watch_Lock);
9009 savedPacketp->nextp = smb_Directory_Watches;
9010 smb_Directory_Watches = savedPacketp;
9011 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9013 osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%S\"",
9014 fidp, scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp));
9015 osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
9016 filter, fid, watchtree);
9017 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
9018 osi_Log0(smb_logp, " Notify Change File Name");
9019 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
9020 osi_Log0(smb_logp, " Notify Change Directory Name");
9021 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
9022 osi_Log0(smb_logp, " Notify Change Attributes");
9023 if (filter & FILE_NOTIFY_CHANGE_SIZE)
9024 osi_Log0(smb_logp, " Notify Change Size");
9025 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
9026 osi_Log0(smb_logp, " Notify Change Last Write");
9027 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
9028 osi_Log0(smb_logp, " Notify Change Last Access");
9029 if (filter & FILE_NOTIFY_CHANGE_CREATION)
9030 osi_Log0(smb_logp, " Notify Change Creation");
9031 if (filter & FILE_NOTIFY_CHANGE_EA)
9032 osi_Log0(smb_logp, " Notify Change Extended Attributes");
9033 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
9034 osi_Log0(smb_logp, " Notify Change Security");
9035 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
9036 osi_Log0(smb_logp, " Notify Change Stream Name");
9037 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
9038 osi_Log0(smb_logp, " Notify Change Stream Size");
9039 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
9040 osi_Log0(smb_logp, " Notify Change Stream Write");
9042 lock_ObtainWrite(&scp->rw);
9044 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
9046 scp->flags |= CM_SCACHEFLAG_WATCHED;
9047 lock_ReleaseWrite(&scp->rw);
9048 cm_ReleaseSCache(scp);
9049 smb_ReleaseFID(fidp);
9051 outp->flags |= SMB_PACKETFLAG_NOSEND;
9055 unsigned char nullSecurityDesc[] = {
9056 0x01, /* security descriptor revision */
9057 0x00, /* reserved, should be zero */
9058 0x04, 0x80, /* security descriptor control;
9059 * 0x0004 : null-DACL present - everyone has full access
9060 * 0x8000 : relative format */
9061 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
9062 0x20, 0x00, 0x00, 0x00, /* offset of group SID */
9063 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
9064 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
9065 0x01, 0x01, 0x00, 0x00, /* "everyone SID" owner SID */
9066 0x00, 0x00, 0x00, 0x01,
9067 0x00, 0x00, 0x00, 0x00,
9068 0x01, 0x01, 0x00, 0x00, /* "everyone SID" owner SID */
9069 0x00, 0x00, 0x00, 0x01,
9070 0x00, 0x00, 0x00, 0x00
9073 /* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
9074 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9076 int parmOffset, parmCount, dataOffset, dataCount;
9077 int totalParmCount, totalDataCount;
9079 int maxData, maxParm;
9080 int inTotalParm, inTotalData;
9082 int inParmOffset, inDataOffset;
9088 ULONG securityInformation;
9094 * For details on the meanings of the various
9095 * SMB_COM_TRANSACTION fields, see sections 2.2.4.33
9096 * of http://msdn.microsoft.com/en-us/library/ee442092%28PROT.13%29.aspx
9099 inTotalParm = smb_GetSMBOffsetParm(inp, 1, 1)
9100 | (smb_GetSMBOffsetParm(inp, 2, 1) << 16);
9102 inTotalData = smb_GetSMBOffsetParm(inp, 3, 1)
9103 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
9105 maxParm = smb_GetSMBOffsetParm(inp, 5, 1)
9106 | (smb_GetSMBOffsetParm(inp, 6, 1) << 16);
9108 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
9109 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
9111 inParm = smb_GetSMBOffsetParm(inp, 9, 1)
9112 | (smb_GetSMBOffsetParm(inp, 10, 1) << 16);
9114 inParmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
9115 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
9117 inData = smb_GetSMBOffsetParm(inp, 13, 1)
9118 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
9120 inDataOffset = smb_GetSMBOffsetParm(inp, 15, 1)
9121 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
9123 parmp = inp->data + inParmOffset;
9124 sparmp = (USHORT *) parmp;
9125 lparmp = (ULONG *) parmp;
9128 securityInformation = lparmp[1];
9130 fidp = smb_FindFID(vcp, fid, 0);
9132 osi_Log2(smb_logp, "smb_ReceiveNTTranQuerySecurityDesc Unknown SMB Fid vcp 0x%p fid %d",
9134 return CM_ERROR_BADFD;
9137 lock_ObtainMutex(&fidp->mx);
9138 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
9139 lock_ReleaseMutex(&fidp->mx);
9140 smb_CloseFID(vcp, fidp, NULL, 0);
9141 smb_ReleaseFID(fidp);
9142 return CM_ERROR_NOSUCHFILE;
9144 lock_ReleaseMutex(&fidp->mx);
9146 osi_Log4(smb_logp,"smb_ReceiveNTTranQuerySecurityDesc fidp 0x%p scp 0x%p file \"%S\" Info=0x%x",
9147 fidp, fidp->scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp),
9148 securityInformation);
9150 smb_ReleaseFID(fidp);
9152 if ( securityInformation & ~(OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION) )
9154 code = CM_ERROR_BAD_LEVEL;
9158 dwLength = sizeof( nullSecurityDesc);
9160 totalDataCount = dwLength;
9163 if (maxData >= totalDataCount) {
9164 dataCount = totalDataCount;
9165 parmCount = min(totalParmCount, maxParm);
9166 } else if (maxParm >= totalParmCount) {
9167 totalDataCount = dataCount = 0;
9168 parmCount = totalParmCount;
9170 totalDataCount = dataCount = 0;
9171 totalParmCount = parmCount = 0;
9175 parmOffset = 8*4 + 39;
9176 parmOffset += 1; /* pad to 4 */
9178 dataOffset = parmOffset + parmCount;
9182 /* Total Parameter Count */
9183 smb_SetSMBParmLong(outp, parmSlot, totalParmCount); parmSlot += 2;
9184 /* Total Data Count */
9185 smb_SetSMBParmLong(outp, parmSlot, totalDataCount); parmSlot += 2;
9186 /* Parameter Count */
9187 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
9188 /* Parameter Offset */
9189 smb_SetSMBParmLong(outp, parmSlot, parmCount ? parmOffset : 0); parmSlot += 2;
9190 /* Parameter Displacement */
9191 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9193 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
9195 smb_SetSMBParmLong(outp, parmSlot, dataCount ? dataOffset : 0); parmSlot += 2;
9196 /* Data Displacement */
9197 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9199 smb_SetSMBParmByte(outp, parmSlot, 0);
9201 if (parmCount == totalParmCount && dwLength == dataCount) {
9202 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
9205 outData = smb_GetSMBData(outp, NULL);
9206 outData++; /* round to get to dataOffset */
9208 *((ULONG *)outData) = dataCount; outData += 4; /* SD Length (4 bytes) */
9209 memcpy(outData, nullSecurityDesc, dataCount);
9210 outData += dataCount;
9213 } else if (parmCount >= 4) {
9214 smb_SetSMBDataLength(outp, 1 + parmCount);
9217 outData = smb_GetSMBData(outp, NULL);
9218 outData++; /* round to get to dataOffset */
9220 *((ULONG *)outData) = dwLength; outData += 4; /* SD Length (4 bytes) */
9221 code = CM_ERROR_BUFFERTOOSMALL;
9223 smb_SetSMBDataLength(outp, 0);
9224 code = CM_ERROR_BUFFER_OVERFLOW;
9231 /* SMB_COM_NT_TRANSACT
9233 SMB_COM_NT_TRANSACT_SECONDARY should also be handled here.
9235 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9237 unsigned short function;
9239 function = smb_GetSMBParm(inp, 18);
9241 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
9243 /* We can handle long names */
9244 if (vcp->flags & SMB_VCFLAG_USENT)
9245 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
9248 case 1: /* NT_TRANSACT_CREATE */
9249 return smb_ReceiveNTTranCreate(vcp, inp, outp);
9250 case 2: /* NT_TRANSACT_IOCTL */
9251 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
9253 case 3: /* NT_TRANSACT_SET_SECURITY_DESC */
9254 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
9256 case 4: /* NT_TRANSACT_NOTIFY_CHANGE */
9257 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
9258 case 5: /* NT_TRANSACT_RENAME */
9259 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
9261 case 6: /* NT_TRANSACT_QUERY_SECURITY_DESC */
9262 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
9264 osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
9267 osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
9270 return CM_ERROR_BADOP;
9274 * smb_NotifyChange -- find relevant change notification messages and
9277 * If we don't know the file name (i.e. a callback break), filename is
9278 * NULL, and we return a zero-length list.
9280 * At present there is not a single call to smb_NotifyChange that
9281 * has the isDirectParent parameter set to FALSE.
9283 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
9284 cm_scache_t *dscp, clientchar_t *filename, clientchar_t *otherFilename,
9285 BOOL isDirectParent)
9287 smb_packet_t *watch, *lastWatch, *nextWatch;
9288 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen = 0;
9289 char *outData, *oldOutData;
9293 BOOL twoEntries = FALSE;
9294 ULONG otherNameLen, oldParmCount = 0;
9298 /* Get ready for rename within directory */
9299 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
9301 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
9304 osi_Log4(smb_logp,"in smb_NotifyChange for file [%S] dscp [%p] notification 0x%x parent %d",
9305 osi_LogSaveClientString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
9307 osi_Log0(smb_logp," FILE_ACTION_NONE");
9308 if (action == FILE_ACTION_ADDED)
9309 osi_Log0(smb_logp," FILE_ACTION_ADDED");
9310 if (action == FILE_ACTION_REMOVED)
9311 osi_Log0(smb_logp," FILE_ACTION_REMOVED");
9312 if (action == FILE_ACTION_MODIFIED)
9313 osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
9314 if (action == FILE_ACTION_RENAMED_OLD_NAME)
9315 osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
9316 if (action == FILE_ACTION_RENAMED_NEW_NAME)
9317 osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
9319 lock_ObtainMutex(&smb_Dir_Watch_Lock);
9320 watch = smb_Directory_Watches;
9322 filter = smb_GetSMBParm(watch, 19)
9323 | (smb_GetSMBParm(watch, 20) << 16);
9324 fid = smb_GetSMBParm(watch, 21);
9325 wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
9327 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
9328 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
9331 * Strange hack - bug in NT Client and NT Server that we must emulate?
9333 if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
9334 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
9336 fidp = smb_FindFID(watch->vcp, fid, 0);
9338 osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
9340 watch = watch->nextp;
9344 if (fidp->scp != dscp ||
9345 fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
9346 (filter & notifyFilter) == 0 ||
9347 (!isDirectParent && !wtree))
9349 osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
9351 watch = watch->nextp;
9352 smb_ReleaseFID(fidp);
9357 "Sending Change Notification for fid %d filter 0x%x wtree %d file %S",
9358 fid, filter, wtree, osi_LogSaveClientString(smb_logp, filename));
9359 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
9360 osi_Log0(smb_logp, " Notify Change File Name");
9361 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
9362 osi_Log0(smb_logp, " Notify Change Directory Name");
9363 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
9364 osi_Log0(smb_logp, " Notify Change Attributes");
9365 if (filter & FILE_NOTIFY_CHANGE_SIZE)
9366 osi_Log0(smb_logp, " Notify Change Size");
9367 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
9368 osi_Log0(smb_logp, " Notify Change Last Write");
9369 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
9370 osi_Log0(smb_logp, " Notify Change Last Access");
9371 if (filter & FILE_NOTIFY_CHANGE_CREATION)
9372 osi_Log0(smb_logp, " Notify Change Creation");
9373 if (filter & FILE_NOTIFY_CHANGE_EA)
9374 osi_Log0(smb_logp, " Notify Change Extended Attributes");
9375 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
9376 osi_Log0(smb_logp, " Notify Change Security");
9377 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
9378 osi_Log0(smb_logp, " Notify Change Stream Name");
9379 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
9380 osi_Log0(smb_logp, " Notify Change Stream Size");
9381 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
9382 osi_Log0(smb_logp, " Notify Change Stream Write");
9384 /* A watch can only be notified once. Remove it from the list */
9385 nextWatch = watch->nextp;
9386 if (watch == smb_Directory_Watches)
9387 smb_Directory_Watches = nextWatch;
9389 lastWatch->nextp = nextWatch;
9391 /* Turn off WATCHED flag in dscp */
9392 lock_ObtainWrite(&dscp->rw);
9394 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
9396 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
9397 lock_ReleaseWrite(&dscp->rw);
9399 /* Convert to response packet */
9400 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
9401 #ifdef SEND_CANONICAL_PATHNAMES
9402 ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
9404 ((smb_t *) watch)->wct = 0;
9407 if (filename == NULL) {
9410 nameLen = (ULONG)cm_ClientStrLen(filename);
9411 parmCount = 3*4 + nameLen*2;
9412 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
9414 otherNameLen = (ULONG)cm_ClientStrLen(otherFilename);
9415 oldParmCount = parmCount;
9416 parmCount += 3*4 + otherNameLen*2;
9417 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
9419 if (maxLen < parmCount)
9420 parmCount = 0; /* not enough room */
9422 parmOffset = 8*4 + 39;
9423 parmOffset += 1; /* pad to 4 */
9424 dataOffset = parmOffset + parmCount;
9428 /* Total Parameter Count */
9429 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
9430 /* Total Data Count */
9431 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9432 /* Parameter Count */
9433 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
9434 /* Parameter Offset */
9435 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
9436 /* Parameter Displacement */
9437 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9439 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9441 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
9442 /* Data Displacement */
9443 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9444 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
9445 smb_SetSMBDataLength(watch, parmCount + 1);
9447 if (parmCount != 0) {
9448 outData = smb_GetSMBData(watch, NULL);
9449 outData++; /* round to get to parmOffset */
9450 oldOutData = outData;
9451 *((DWORD *)outData) = oldParmCount; outData += 4;
9452 /* Next Entry Offset */
9453 *((DWORD *)outData) = action; outData += 4;
9455 *((DWORD *)outData) = nameLen*2; outData += 4;
9456 /* File Name Length */
9458 smb_UnparseString(watch, outData, filename, NULL, 0);
9462 outData = oldOutData + oldParmCount;
9463 *((DWORD *)outData) = 0; outData += 4;
9464 /* Next Entry Offset */
9465 *((DWORD *)outData) = otherAction; outData += 4;
9467 *((DWORD *)outData) = otherNameLen*2;
9468 outData += 4; /* File Name Length */
9469 smb_UnparseString(watch, outData, otherFilename, NULL, 0);
9474 * If filename is null, we don't know the cause of the
9475 * change notification. We return zero data (see above),
9476 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
9477 * (= 0x010C). We set the error code here by hand, without
9478 * modifying wct and bcc.
9480 if (filename == NULL) {
9481 ((smb_t *) watch)->rcls = 0x0C;
9482 ((smb_t *) watch)->reh = 0x01;
9483 ((smb_t *) watch)->errLow = 0;
9484 ((smb_t *) watch)->errHigh = 0;
9485 /* Set NT Status codes flag */
9486 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9489 smb_SendPacket(watch->vcp, watch);
9490 smb_FreePacket(watch);
9492 smb_ReleaseFID(fidp);
9495 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9498 /* SMB_COM_NT_CANCEL */
9499 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9501 unsigned char *replyWctp;
9502 smb_packet_t *watch, *lastWatch;
9503 USHORT fid, watchtree;
9507 osi_Log0(smb_logp, "SMB3 receive NT cancel");
9509 lock_ObtainMutex(&smb_Dir_Watch_Lock);
9510 watch = smb_Directory_Watches;
9512 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
9513 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
9514 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
9515 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
9516 if (watch == smb_Directory_Watches)
9517 smb_Directory_Watches = watch->nextp;
9519 lastWatch->nextp = watch->nextp;
9520 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9522 /* Turn off WATCHED flag in scp */
9523 fid = smb_GetSMBParm(watch, 21);
9524 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
9526 if (vcp != watch->vcp)
9527 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
9530 fidp = smb_FindFID(vcp, fid, 0);
9532 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %S",
9534 (fidp ? osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp) :_C("")));
9537 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
9539 lock_ObtainWrite(&scp->rw);
9541 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
9543 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
9544 lock_ReleaseWrite(&scp->rw);
9546 smb_ReleaseFID(fidp);
9548 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
9551 /* assume STATUS32; return 0xC0000120 (CANCELED) */
9552 replyWctp = watch->wctp;
9556 ((smb_t *)watch)->rcls = 0x20;
9557 ((smb_t *)watch)->reh = 0x1;
9558 ((smb_t *)watch)->errLow = 0;
9559 ((smb_t *)watch)->errHigh = 0xC0;
9560 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9561 smb_SendPacket(vcp, watch);
9562 smb_FreePacket(watch);
9566 watch = watch->nextp;
9568 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9574 * NT rename also does hard links.
9577 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
9578 #define RENAME_FLAG_HARD_LINK 0x103
9579 #define RENAME_FLAG_RENAME 0x104
9580 #define RENAME_FLAG_COPY 0x105
9582 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9584 clientchar_t *oldPathp, *newPathp;
9590 attrs = smb_GetSMBParm(inp, 0);
9591 rename_type = smb_GetSMBParm(inp, 1);
9593 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
9594 osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
9595 return CM_ERROR_NOACCESS;
9598 tp = smb_GetSMBData(inp, NULL);
9599 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
9601 return CM_ERROR_BADSMB;
9602 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
9604 return CM_ERROR_BADSMB;
9606 osi_Log3(smb_logp, "NTRename for [%S]->[%S] type [%s]",
9607 osi_LogSaveClientString(smb_logp, oldPathp),
9608 osi_LogSaveClientString(smb_logp, newPathp),
9609 ((rename_type==RENAME_FLAG_RENAME)?"rename":(rename_type==RENAME_FLAG_HARD_LINK)?"hardlink":"other"));
9611 if (rename_type == RENAME_FLAG_RENAME) {
9612 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
9613 } else if (rename_type == RENAME_FLAG_HARD_LINK) { /* RENAME_FLAG_HARD_LINK */
9614 code = smb_Link(vcp,inp,oldPathp,newPathp);
9616 code = CM_ERROR_BADOP;
9622 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock", LOCK_HIERARCHY_SMB_DIRWATCH);
9625 cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
9627 smb_username_t *unp;
9630 unp = smb_FindUserByName(usern, machine, flags);
9632 lock_ObtainMutex(&unp->mx);
9633 unp->userp = cm_NewUser();
9634 lock_ReleaseMutex(&unp->mx);
9635 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9637 osi_Log2(smb_logp,"smb_FindCMUserByName Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9641 smb_ReleaseUsername(unp);
9645 cm_user_t *smb_FindCMUserBySID(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
9647 smb_username_t *unp;
9650 unp = smb_FindUserByName(usern, machine, flags);
9652 lock_ObtainMutex(&unp->mx);
9653 unp->flags |= SMB_USERNAMEFLAG_SID;
9654 unp->userp = cm_NewUser();
9655 lock_ReleaseMutex(&unp->mx);
9656 osi_Log2(smb_logp,"smb_FindCMUserBySID New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9658 osi_Log2(smb_logp,"smb_FindCMUserBySID Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9662 smb_ReleaseUsername(unp);