3 * Copyright 2000, International Business Machines Corporation and others.
6 * This software has been released under the terms of the IBM Public
7 * License. For details, see the LICENSE file in the top-level source
8 * directory or online at http://www.openafs.org/dl/license10.html
11 #include <afsconfig.h>
12 #include <afs/param.h>
19 #pragma warning(disable: 4005)
21 #define SECURITY_WIN32
34 #include <WINNT\afsreg.h>
40 extern osi_hyper_t hzero;
42 smb_packet_t *smb_Directory_Watches = NULL;
43 osi_mutex_t smb_Dir_Watch_Lock;
45 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
47 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
49 /* protected by the smb_globalLock */
50 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
52 const clientchar_t **smb_ExecutableExtensions = NULL;
54 /* retrieve a held reference to a user structure corresponding to an incoming
56 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
61 uidp = smb_FindUID(vcp, inp->uid, 0);
65 up = smb_GetUserFromUID(uidp);
73 * Return boolean specifying if the path name is thought to be an
74 * executable file. For now .exe or .dll.
76 afs_uint32 smb_IsExecutableFileName(const clientchar_t *name)
80 if ( smb_ExecutableExtensions == NULL || name == NULL)
83 len = (int)cm_ClientStrLen(name);
85 for ( i=0; smb_ExecutableExtensions[i]; i++) {
86 j = len - (int)cm_ClientStrLen(smb_ExecutableExtensions[i]);
87 if (cm_ClientStrCmpI(smb_ExecutableExtensions[i], &name[j]) == 0)
95 * Return extended attributes.
96 * Right now, we aren't using any of the "new" bits, so this looks exactly
97 * like smb_Attributes() (see smb.c).
99 unsigned long smb_ExtAttributes(cm_scache_t *scp)
103 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
104 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
105 scp->fileType == CM_SCACHETYPE_INVALID)
107 attrs = SMB_ATTR_DIRECTORY;
108 #ifdef SPECIAL_FOLDERS
109 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
110 #endif /* SPECIAL_FOLDERS */
111 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
112 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
113 } else if (scp->fid.vnode & 0x1)
114 attrs = SMB_ATTR_DIRECTORY;
119 * We used to mark a file RO if it was in an RO volume, but that
120 * turns out to be impolitic in NT. See defect 10007.
123 if ((scp->unixModeBits & 0200) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
124 attrs |= SMB_ATTR_READONLY; /* Read-only */
126 if ((scp->unixModeBits & 0200) == 0)
127 attrs |= SMB_ATTR_READONLY; /* Read-only */
131 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
136 int smb_V3IsStarMask(clientchar_t *maskp)
140 while (tc = *maskp++)
141 if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
146 void OutputDebugF(clientchar_t * format, ...) {
148 clientchar_t vbuffer[1024];
150 va_start( args, format );
151 cm_ClientStrPrintfV(vbuffer, lengthof(vbuffer), format, args);
152 osi_Log1(smb_logp, "%S", osi_LogSaveClientString(smb_logp, vbuffer));
155 void OutputDebugHexDump(unsigned char * buffer, int len) {
158 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
160 OutputDebugF(_C("Hexdump length [%d]"),len);
162 for (i=0;i<len;i++) {
165 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
167 StringCchPrintfA(buf, lengthof(buf), "%5x", i);
168 memset(buf+5,' ',80);
173 j = j*3 + 7 + ((j>7)?1:0);
176 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
179 j = j + 56 + ((j>7)?1:0);
181 buf[j] = (k>32 && k<127)?k:'.';
184 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
188 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
190 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
191 SECURITY_STATUS status, istatus;
192 CredHandle creds = {0,0};
194 SecBufferDesc secOut;
202 OutputDebugF(_C("Negotiating Extended Security"));
204 status = AcquireCredentialsHandle( NULL,
205 SMB_EXT_SEC_PACKAGE_NAME,
214 if (status != SEC_E_OK) {
215 /* Really bad. We return an empty security blob */
216 OutputDebugF(_C("AcquireCredentialsHandle failed with %lX"), status);
221 secOut.pBuffers = &secTok;
222 secOut.ulVersion = SECBUFFER_VERSION;
224 secTok.BufferType = SECBUFFER_TOKEN;
226 secTok.pvBuffer = NULL;
228 ctx.dwLower = ctx.dwUpper = 0;
230 status = AcceptSecurityContext( &creds,
233 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
234 SECURITY_NETWORK_DREP,
241 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
242 OutputDebugF(_C("Completing token..."));
243 istatus = CompleteAuthToken(&ctx, &secOut);
244 if ( istatus != SEC_E_OK )
245 OutputDebugF(_C("Token completion failed: %x"), istatus);
248 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
249 if (secTok.pvBuffer) {
250 *secBlobLength = secTok.cbBuffer;
251 *secBlob = malloc( secTok.cbBuffer );
252 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
255 if ( status != SEC_E_OK )
256 OutputDebugF(_C("AcceptSecurityContext status != CONTINUE %lX"), status);
259 /* Discard partial security context */
260 DeleteSecurityContext(&ctx);
262 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
264 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
265 FreeCredentialsHandle(&creds);
272 smb_GetLogonSID(HANDLE hToken, PSID *ppsid)
274 BOOL bSuccess = FALSE;
277 PTOKEN_GROUPS ptg = NULL;
279 // Verify the parameter passed in is not NULL.
283 // Get required buffer size and allocate the TOKEN_GROUPS buffer.
285 if (!GetTokenInformation( hToken, // handle to the access token
286 TokenGroups, // get information about the token's groups
287 (LPVOID) ptg, // pointer to TOKEN_GROUPS buffer
289 &dwLength // receives required buffer size
292 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
295 ptg = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(),
296 HEAP_ZERO_MEMORY, dwLength);
302 // Get the token group information from the access token.
304 if (!GetTokenInformation( hToken, // handle to the access token
305 TokenGroups, // get information about the token's groups
306 (LPVOID) ptg, // pointer to TOKEN_GROUPS buffer
307 dwLength, // size of buffer
308 &dwLength // receives required buffer size
314 // Loop through the groups to find the logon SID.
315 for (dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++) {
316 if ((ptg->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID)
318 // Found the logon SID; make a copy of it.
320 dwLength = GetLengthSid(ptg->Groups[dwIndex].Sid);
321 *ppsid = (PSID) HeapAlloc(GetProcessHeap(),
322 HEAP_ZERO_MEMORY, dwLength);
325 if (!CopySid(dwLength, *ppsid, ptg->Groups[dwIndex].Sid))
327 HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
337 // Free the buffer for the token groups.
339 HeapFree(GetProcessHeap(), 0, (LPVOID)ptg);
345 smb_GetUserSID(HANDLE hToken, PSID *ppsid)
347 BOOL bSuccess = FALSE;
349 PTOKEN_USER ptu = NULL;
351 // Verify the parameter passed in is not NULL.
355 // Get required buffer size and allocate the TOKEN_USER buffer.
357 if (!GetTokenInformation( hToken, // handle to the access token
358 TokenUser, // get information about the token's user
359 (LPVOID) ptu, // pointer to TOKEN_USER buffer
361 &dwLength // receives required buffer size
364 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
367 ptu = (PTOKEN_USER)HeapAlloc(GetProcessHeap(),
368 HEAP_ZERO_MEMORY, dwLength);
374 // Get the token group information from the access token.
376 if (!GetTokenInformation( hToken, // handle to the access token
377 TokenUser, // get information about the token's user
378 (LPVOID) ptu, // pointer to TOKEN_USER buffer
379 dwLength, // size of buffer
380 &dwLength // receives required buffer size
386 // Found the user SID; make a copy of it.
387 dwLength = GetLengthSid(ptu->User.Sid);
388 *ppsid = (PSID) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
391 if (!CopySid(dwLength, *ppsid, ptu->User.Sid))
393 HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
400 // Free the buffer for the token groups.
402 HeapFree(GetProcessHeap(), 0, (LPVOID)ptu);
408 smb_FreeSID (PSID psid)
410 HeapFree(GetProcessHeap(), 0, (LPVOID)psid);
414 struct smb_ext_context {
421 long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern,
422 char * secBlobIn, int secBlobInLength,
423 char ** secBlobOut, int * secBlobOutLength,
424 wchar_t **secSidString) {
425 SECURITY_STATUS status, istatus;
429 SecBufferDesc secBufIn;
431 SecBufferDesc secBufOut;
434 struct smb_ext_context * secCtx = NULL;
435 struct smb_ext_context * newSecCtx = NULL;
436 void * assembledBlob = NULL;
437 int assembledBlobLength = 0;
440 OutputDebugF(_C("In smb_AuthenticateUserExt"));
443 *secBlobOutLength = 0;
444 *secSidString = NULL;
446 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
447 secCtx = vcp->secCtx;
448 lock_ObtainMutex(&vcp->mx);
449 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
451 lock_ReleaseMutex(&vcp->mx);
455 OutputDebugF(_C("Received incoming token:"));
456 OutputDebugHexDump(secBlobIn,secBlobInLength);
460 OutputDebugF(_C("Continuing with existing context."));
461 creds = secCtx->creds;
464 if (secCtx->partialToken) {
465 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
466 assembledBlob = malloc(assembledBlobLength);
467 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
468 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
471 status = AcquireCredentialsHandle( NULL,
472 SMB_EXT_SEC_PACKAGE_NAME,
481 if (status != SEC_E_OK) {
482 OutputDebugF(_C("Can't acquire Credentials handle [%lX]"), status);
483 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
491 secBufIn.cBuffers = 1;
492 secBufIn.pBuffers = &secTokIn;
493 secBufIn.ulVersion = SECBUFFER_VERSION;
495 secTokIn.BufferType = SECBUFFER_TOKEN;
497 secTokIn.cbBuffer = assembledBlobLength;
498 secTokIn.pvBuffer = assembledBlob;
500 secTokIn.cbBuffer = secBlobInLength;
501 secTokIn.pvBuffer = secBlobIn;
504 secBufOut.cBuffers = 1;
505 secBufOut.pBuffers = &secTokOut;
506 secBufOut.ulVersion = SECBUFFER_VERSION;
508 secTokOut.BufferType = SECBUFFER_TOKEN;
509 secTokOut.cbBuffer = 0;
510 secTokOut.pvBuffer = NULL;
512 status = AcceptSecurityContext( &creds,
513 ((secCtx)?&ctx:NULL),
515 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
516 SECURITY_NETWORK_DREP,
523 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
524 OutputDebugF(_C("Completing token..."));
525 istatus = CompleteAuthToken(&ctx, &secBufOut);
526 if ( istatus != SEC_E_OK )
527 OutputDebugF(_C("Token completion failed: %lX"), istatus);
530 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
531 OutputDebugF(_C("Continue needed"));
533 newSecCtx = malloc(sizeof(*newSecCtx));
535 newSecCtx->creds = creds;
536 newSecCtx->ctx = ctx;
537 newSecCtx->partialToken = NULL;
538 newSecCtx->partialTokenLen = 0;
540 lock_ObtainMutex( &vcp->mx );
541 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
542 vcp->secCtx = newSecCtx;
543 lock_ReleaseMutex( &vcp->mx );
545 code = CM_ERROR_GSSCONTINUE;
548 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
549 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
550 secTokOut.pvBuffer) {
551 OutputDebugF(_C("Need to send token back to client"));
553 *secBlobOutLength = secTokOut.cbBuffer;
554 *secBlobOut = malloc(secTokOut.cbBuffer);
555 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
557 OutputDebugF(_C("Outgoing token:"));
558 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
559 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
560 OutputDebugF(_C("Incomplete message"));
562 newSecCtx = malloc(sizeof(*newSecCtx));
564 newSecCtx->creds = creds;
565 newSecCtx->ctx = ctx;
566 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
567 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
568 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
570 lock_ObtainMutex( &vcp->mx );
571 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
572 vcp->secCtx = newSecCtx;
573 lock_ReleaseMutex( &vcp->mx );
575 code = CM_ERROR_GSSCONTINUE;
578 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
581 SecPkgContext_NamesW names;
583 OutputDebugF(_C("Authentication completed"));
584 OutputDebugF(_C("Returned flags : [%lX]"), flags);
586 if (!QueryContextAttributesW(&ctx, SECPKG_ATTR_NAMES, &names)) {
587 OutputDebugF(_C("Received name [%s]"), names.sUserName);
588 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, names.sUserName);
589 cm_ClientStrLwr(usern); /* in tandem with smb_GetNormalizedUsername */
590 FreeContextBuffer(names.sUserName);
592 /* Force the user to retry if the context is invalid */
593 OutputDebugF(_C("QueryContextAttributes Names failed [%x]"), GetLastError());
594 code = CM_ERROR_BADPASSWORD;
597 /* Obtain the user's SID */
598 if (code == 0 && !QuerySecurityContextToken(((secCtx)?&ctx:NULL), &hToken)) {
600 OutputDebugF(_C("Received hToken"));
602 if (smb_GetUserSID(hToken, &pSid))
603 ConvertSidToStringSidW(pSid, secSidString);
609 OutputDebugF(_C("QueryContextToken failed [%x]"), GetLastError());
613 case SEC_E_INVALID_TOKEN:
614 OutputDebugF(_C("Returning bad password :: INVALID_TOKEN"));
616 case SEC_E_INVALID_HANDLE:
617 OutputDebugF(_C("Returning bad password :: INVALID_HANDLE"));
619 case SEC_E_LOGON_DENIED:
620 OutputDebugF(_C("Returning bad password :: LOGON_DENIED"));
622 case SEC_E_UNKNOWN_CREDENTIALS:
623 OutputDebugF(_C("Returning bad password :: UNKNOWN_CREDENTIALS"));
625 case SEC_E_NO_CREDENTIALS:
626 OutputDebugF(_C("Returning bad password :: NO_CREDENTIALS"));
628 case SEC_E_CONTEXT_EXPIRED:
629 OutputDebugF(_C("Returning bad password :: CONTEXT_EXPIRED"));
631 case SEC_E_INCOMPLETE_CREDENTIALS:
632 OutputDebugF(_C("Returning bad password :: INCOMPLETE_CREDENTIALS"));
634 case SEC_E_WRONG_PRINCIPAL:
635 OutputDebugF(_C("Returning bad password :: WRONG_PRINCIPAL"));
637 case SEC_E_TIME_SKEW:
638 OutputDebugF(_C("Returning bad password :: TIME_SKEW"));
641 OutputDebugF(_C("Returning bad password :: Status == %lX"), status);
643 code = CM_ERROR_BADPASSWORD;
647 if (secCtx->partialToken) free(secCtx->partialToken);
655 if (secTokOut.pvBuffer)
656 FreeContextBuffer(secTokOut.pvBuffer);
658 if (code != CM_ERROR_GSSCONTINUE) {
659 DeleteSecurityContext(&ctx);
660 FreeCredentialsHandle(&creds);
668 #define P_RESP_LEN 128
670 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
671 So put stuff in a struct. */
672 struct Lm20AuthBlob {
673 MSV1_0_LM20_LOGON lmlogon;
674 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
675 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
676 WCHAR accountNameW[P_LEN];
677 WCHAR primaryDomainW[P_LEN];
678 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
679 TOKEN_GROUPS tgroups;
680 TOKEN_SOURCE tsource;
683 long smb_AuthenticateUserLM(smb_vc_t *vcp, clientchar_t * accountName, clientchar_t * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
686 struct Lm20AuthBlob lmAuth;
687 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
688 QUOTA_LIMITS quotaLimits;
690 ULONG lmprofilepSize;
694 OutputDebugF(_C("In smb_AuthenticateUser for user [%s] domain [%s]"), accountName, primaryDomain);
695 OutputDebugF(_C("ciPwdLength is %d and csPwdLength is %d"), ciPwdLength, csPwdLength);
697 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
698 OutputDebugF(_C("ciPwdLength or csPwdLength is too long"));
699 return CM_ERROR_BADPASSWORD;
702 memset(&lmAuth,0,sizeof(lmAuth));
704 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
706 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
707 cm_ClientStringToUtf16(primaryDomain, -1, lmAuth.primaryDomainW, P_LEN);
708 lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
709 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
711 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
712 cm_ClientStringToUtf16(accountName, -1, lmAuth.accountNameW, P_LEN);
713 lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
714 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
716 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
717 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
718 size = MAX_COMPUTERNAME_LENGTH + 1;
719 GetComputerNameW(lmAuth.workstationW, &size);
720 lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
722 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
724 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
725 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
726 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
727 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
729 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
730 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
731 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
732 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
734 lmAuth.lmlogon.ParameterControl = 0;
736 lmAuth.tgroups.GroupCount = 0;
737 lmAuth.tgroups.Groups[0].Sid = NULL;
738 lmAuth.tgroups.Groups[0].Attributes = 0;
741 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
743 lmAuth.tsource.SourceIdentifier.HighPart = 0;
745 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
746 StringCchCopyA(lmAuth.tsource.SourceName, lengthof(lmAuth.tsource.SourceName),
747 "OpenAFS"); /* 8 char limit */
749 nts = LsaLogonUser( smb_lsaHandle,
764 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
765 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
768 OutputDebugF(_C("Return from LsaLogonUser is 0x%lX"), nts);
769 OutputDebugF(_C("Extended status is 0x%lX"), ntsEx);
771 if (nts == ERROR_SUCCESS) {
773 LsaFreeReturnBuffer(lmprofilep);
774 CloseHandle(lmToken);
778 if (nts == 0xC000015BL)
779 return CM_ERROR_BADLOGONTYPE;
780 else /* our catchall is a bad password though we could be more specific */
781 return CM_ERROR_BADPASSWORD;
785 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
786 long smb_GetNormalizedUsername(clientchar_t * usern, const clientchar_t * accountName, const clientchar_t * domainName)
788 clientchar_t * atsign;
789 const clientchar_t * domain;
791 /* check if we have sane input */
792 if ((cm_ClientStrLen(accountName) + cm_ClientStrLen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
795 /* we could get : [accountName][domainName]
801 atsign = cm_ClientStrChr(accountName, '@');
803 if (atsign) /* [user@domain][] -> [user@domain][domain] */
808 /* if for some reason the client doesn't know what domain to use,
809 it will either return an empty string or a '?' */
810 if (!domain[0] || domain[0] == '?')
811 /* Empty domains and empty usernames are usually sent from tokenless contexts.
812 This way such logins will get an empty username (easy to check). I don't know
813 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
814 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, accountName);
816 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
817 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, domain);
818 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, _C("\\"));
820 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
822 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
825 cm_ClientStrLwr(usern);
830 /* When using SMB auth, all SMB sessions have to pass through here
831 * first to authenticate the user.
833 * Caveat: If not using SMB auth, the protocol does not require
834 * sending a session setup packet, which means that we can't rely on a
835 * UID in subsequent packets. Though in practice we get one anyway.
837 /* SMB_COM_SESSION_SETUP_ANDX */
838 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
842 unsigned short newUid;
843 unsigned long caps = 0;
845 clientchar_t *s1 = _C(" ");
847 clientchar_t usern[SMB_MAX_USERNAME_LENGTH];
849 char *secBlobOut = NULL;
850 int secBlobOutLength = 0;
851 wchar_t *secSidString = 0;
852 int maxBufferSize = 0;
856 /* Check for bad conns */
857 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
858 return CM_ERROR_REMOTECONN;
861 maxBufferSize = smb_GetSMBParm(inp, 2);
862 maxMpxCount = smb_GetSMBParm(inp, 3);
863 vcNumber = smb_GetSMBParm(inp, 4);
865 osi_Log3(smb_logp, "SESSION_SETUP_ANDX with MaxBufferSize=%d, MaxMpxCount=%d, VCNumber=%d",
866 maxBufferSize, maxMpxCount, vcNumber);
868 if (maxMpxCount > smb_maxMpxRequests) {
869 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_MPX_COUNT, maxMpxCount, smb_maxMpxRequests);
870 osi_Log2(smb_logp, "MaxMpxCount for client is too large (Client=%d, Server=%d)",
871 maxMpxCount, smb_maxMpxRequests);
874 if (maxBufferSize < SMB_PACKETSIZE) {
875 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_BUFFER_SIZE, maxBufferSize, SMB_PACKETSIZE);
876 osi_Log2(smb_logp, "MaxBufferSize for client is too small (Client=%d, Server=%d)",
877 maxBufferSize, SMB_PACKETSIZE);
881 osi_Log0(smb_logp, "Resetting all VCs");
882 smb_MarkAllVCsDead(vcp);
885 if (vcp->flags & SMB_VCFLAG_USENT) {
886 if (smb_authType == SMB_AUTH_EXTENDED) {
887 /* extended authentication */
891 OutputDebugF(_C("NT Session Setup: Extended"));
893 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
894 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
897 secBlobInLength = smb_GetSMBParm(inp, 7);
898 secBlobIn = smb_GetSMBData(inp, NULL);
900 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength, &secSidString);
902 if (code == CM_ERROR_GSSCONTINUE) {
905 smb_SetSMBParm(outp, 2, 0);
906 smb_SetSMBParm(outp, 3, secBlobOutLength);
908 tp = smb_GetSMBData(outp, NULL);
909 if (secBlobOutLength) {
910 memcpy(tp, secBlobOut, secBlobOutLength);
912 tp += secBlobOutLength;
913 cb_data += secBlobOutLength;
915 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
916 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
917 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
919 smb_SetSMBDataLength(outp, cb_data);
922 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
924 unsigned ciPwdLength, csPwdLength;
926 clientchar_t *accountName;
927 clientchar_t *primaryDomain;
930 if (smb_authType == SMB_AUTH_NTLM)
931 OutputDebugF(_C("NT Session Setup: NTLM"));
933 OutputDebugF(_C("NT Session Setup: None"));
935 /* TODO: parse for extended auth as well */
936 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
937 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
939 tp = smb_GetSMBData(inp, &datalen);
941 OutputDebugF(_C("Session packet data size [%d]"),datalen);
948 accountName = smb_ParseString(inp, tp, &tp, 0);
949 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
951 OutputDebugF(_C("Account Name: %s"),accountName);
952 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
953 OutputDebugF(_C("Case Sensitive Password: %s"),
954 csPwd && csPwd[0] ? _C("yes") : _C("no"));
955 OutputDebugF(_C("Case Insensitive Password: %s"),
956 ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
958 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
959 /* shouldn't happen */
960 code = CM_ERROR_BADSMB;
961 goto after_read_packet;
964 /* capabilities are only valid for first session packet */
965 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
966 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
969 if (smb_authType == SMB_AUTH_NTLM) {
970 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
972 OutputDebugF(_C("LM authentication failed [%d]"), code);
974 OutputDebugF(_C("LM authentication succeeded"));
978 unsigned ciPwdLength;
980 clientchar_t *accountName;
981 clientchar_t *primaryDomain;
983 switch ( smb_authType ) {
984 case SMB_AUTH_EXTENDED:
985 OutputDebugF(_C("V3 Session Setup: Extended"));
988 OutputDebugF(_C("V3 Session Setup: NTLM"));
991 OutputDebugF(_C("V3 Session Setup: None"));
993 ciPwdLength = smb_GetSMBParm(inp, 7);
994 tp = smb_GetSMBData(inp, NULL);
998 accountName = smb_ParseString(inp, tp, &tp, 0);
999 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
1001 OutputDebugF(_C("Account Name: %s"),accountName);
1002 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
1003 OutputDebugF(_C("Case Insensitive Password: %s"), ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
1005 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
1006 /* shouldn't happen */
1007 code = CM_ERROR_BADSMB;
1008 goto after_read_packet;
1011 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
1014 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
1015 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
1017 OutputDebugF(_C("LM authentication failed [%d]"), code);
1019 OutputDebugF(_C("LM authentication succeeded"));
1024 /* note down that we received a session setup X and set the capabilities flag */
1025 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
1026 lock_ObtainMutex(&vcp->mx);
1027 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
1028 /* for the moment we can only deal with NTSTATUS */
1029 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
1030 vcp->flags |= SMB_VCFLAG_STATUS32;
1034 if ((caps & NTNEGOTIATE_CAPABILITY_UNICODE) && smb_UseUnicode) {
1035 vcp->flags |= SMB_VCFLAG_USEUNICODE;
1038 lock_ReleaseMutex(&vcp->mx);
1041 /* code would be non-zero if there was an authentication failure.
1042 Ideally we would like to invalidate the uid for this session or break
1043 early to avoid accidently stealing someone else's tokens. */
1047 LocalFree(secSidString);
1052 * If the SidString for the user could be obtained, use that
1056 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, secSidString);
1060 OutputDebugF(_C("Received username=[%s]"), usern);
1062 /* On Windows 2000, this function appears to be called more often than
1063 it is expected to be called. This resulted in multiple smb_user_t
1064 records existing all for the same user session which results in all
1065 of the users tokens disappearing.
1067 To avoid this problem, we look for an existing smb_user_t record
1068 based on the users name, and use that one if we find it.
1071 uidp = smb_FindUserByNameThisSession(vcp, usern);
1072 if (uidp) { /* already there, so don't create a new one */
1074 newUid = uidp->userID;
1075 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
1076 vcp->lana,vcp->lsn,newUid);
1077 smb_ReleaseUID(uidp);
1082 /* do a global search for the username/machine name pair */
1083 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
1084 lock_ObtainMutex(&unp->mx);
1085 if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
1086 /* clear the afslogon flag so that the tickets can now
1087 * be freed when the refCount returns to zero.
1089 unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
1092 unp->flags |= SMB_USERNAMEFLAG_SID;
1093 lock_ReleaseMutex(&unp->mx);
1095 /* Create a new UID and cm_user_t structure */
1098 userp = cm_NewUser();
1099 cm_HoldUserVCRef(userp);
1100 lock_ObtainMutex(&vcp->mx);
1101 if (!vcp->uidCounter)
1102 vcp->uidCounter++; /* handle unlikely wraparounds */
1103 newUid = (cm_ClientStrLen(usern)==0)?0:vcp->uidCounter++;
1104 lock_ReleaseMutex(&vcp->mx);
1106 /* Create a new smb_user_t structure and connect them up */
1107 lock_ObtainMutex(&unp->mx);
1109 lock_ReleaseMutex(&unp->mx);
1111 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
1113 lock_ObtainMutex(&uidp->mx);
1115 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
1116 lock_ReleaseMutex(&uidp->mx);
1117 smb_ReleaseUID(uidp);
1121 /* Return UID to the client */
1122 ((smb_t *)outp)->uid = newUid;
1123 /* Also to the next chained message */
1124 ((smb_t *)inp)->uid = newUid;
1126 osi_Log3(smb_logp, "SMB3 session setup name %S creating ID %d%S",
1127 osi_LogSaveClientString(smb_logp, usern), newUid,
1128 osi_LogSaveClientString(smb_logp, s1));
1130 smb_SetSMBParm(outp, 2, 0);
1132 if (vcp->flags & SMB_VCFLAG_USENT) {
1133 if (smb_authType == SMB_AUTH_EXTENDED) {
1136 smb_SetSMBParm(outp, 3, secBlobOutLength);
1138 tp = smb_GetSMBData(outp, NULL);
1139 if (secBlobOutLength) {
1140 memcpy(tp, secBlobOut, secBlobOutLength);
1142 tp += secBlobOutLength;
1143 cb_data += secBlobOutLength;
1146 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
1147 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
1148 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
1150 smb_SetSMBDataLength(outp, cb_data);
1152 smb_SetSMBDataLength(outp, 0);
1155 if (smb_authType == SMB_AUTH_EXTENDED) {
1158 tp = smb_GetSMBData(outp, NULL);
1160 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
1161 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
1162 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
1164 smb_SetSMBDataLength(outp, cb_data);
1166 smb_SetSMBDataLength(outp, 0);
1171 LocalFree(secSidString);
1175 /* SMB_COM_LOGOFF_ANDX */
1176 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1180 /* find the tree and free it */
1181 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1183 smb_username_t * unp;
1185 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %S", uidp->userID,
1186 osi_LogSaveClientString(smb_logp, (uidp->unp) ? uidp->unp->name: _C(" ")));
1188 lock_ObtainMutex(&uidp->mx);
1189 uidp->flags |= SMB_USERFLAG_DELETE;
1191 * it doesn't get deleted right away
1192 * because the vcp points to it
1195 lock_ReleaseMutex(&uidp->mx);
1198 /* we can't do this. we get logoff messages prior to a session
1199 * disconnect even though it doesn't mean the user is logging out.
1200 * we need to create a new pioctl and EventLogoff handler to set
1201 * SMB_USERNAMEFLAG_LOGOFF.
1203 if (unp && smb_LogoffTokenTransfer) {
1204 lock_ObtainMutex(&unp->mx);
1205 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
1206 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
1207 lock_ReleaseMutex(&unp->mx);
1211 smb_ReleaseUID(uidp);
1214 osi_Log0(smb_logp, "SMB3 user logoffX");
1216 smb_SetSMBDataLength(outp, 0);
1220 #define SMB_SUPPORT_SEARCH_BITS 0x0001
1221 #define SMB_SHARE_IS_IN_DFS 0x0002
1223 /* SMB_COM_TREE_CONNECT_ANDX */
1224 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1227 smb_user_t *uidp = NULL;
1228 unsigned short newTid;
1229 clientchar_t shareName[AFSPATHMAX];
1230 clientchar_t *sharePath;
1233 clientchar_t *slashp;
1234 clientchar_t *pathp;
1235 clientchar_t *passwordp;
1236 clientchar_t *servicep;
1237 cm_user_t *userp = NULL;
1240 osi_Log0(smb_logp, "SMB3 receive tree connect");
1242 /* parse input parameters */
1243 tp = smb_GetSMBData(inp, NULL);
1244 passwordp = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1245 pathp = smb_ParseString(inp, tp, &tp, SMB_STRF_ANSIPATH);
1246 servicep = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1248 slashp = cm_ClientStrRChr(pathp, '\\');
1250 return CM_ERROR_BADSMB;
1252 cm_ClientStrCpy(shareName, lengthof(shareName), slashp+1);
1254 osi_Log3(smb_logp, "Tree connect pathp[%S] shareName[%S] service[%S]",
1255 osi_LogSaveClientString(smb_logp, pathp),
1256 osi_LogSaveClientString(smb_logp, shareName),
1257 osi_LogSaveClientString(smb_logp, servicep));
1259 if (cm_ClientStrCmp(servicep, _C("IPC")) == 0 ||
1260 cm_ClientStrCmp(shareName, _C("IPC$")) == 0) {
1262 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1265 return CM_ERROR_NOIPC;
1269 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1271 userp = smb_GetUserFromUID(uidp);
1273 lock_ObtainMutex(&vcp->mx);
1274 newTid = vcp->tidCounter++;
1275 lock_ReleaseMutex(&vcp->mx);
1277 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1280 if (!cm_ClientStrCmp(shareName, _C("*.")))
1281 cm_ClientStrCpy(shareName, lengthof(shareName), _C("all"));
1282 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1285 smb_ReleaseUID(uidp);
1286 smb_ReleaseTID(tidp, FALSE);
1287 return CM_ERROR_BADSHARENAME;
1290 if (vcp->flags & SMB_VCFLAG_USENT)
1292 int policy = smb_FindShareCSCPolicy(shareName);
1295 DWORD dwAdvertiseDFS = 0, dwSize = sizeof(DWORD);
1297 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1298 0, KEY_QUERY_VALUE, &parmKey);
1299 if (code == ERROR_SUCCESS) {
1300 code = RegQueryValueEx(parmKey, "AdvertiseDFS", NULL, NULL,
1301 (BYTE *)&dwAdvertiseDFS, &dwSize);
1302 if (code != ERROR_SUCCESS)
1304 RegCloseKey (parmKey);
1306 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1307 (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
1311 smb_SetSMBParm(outp, 2, 0);
1315 smb_ReleaseUID(uidp);
1317 lock_ObtainMutex(&tidp->mx);
1318 tidp->userp = userp;
1319 tidp->pathname = sharePath;
1321 tidp->flags |= SMB_TIDFLAG_IPC;
1322 lock_ReleaseMutex(&tidp->mx);
1323 smb_ReleaseTID(tidp, FALSE);
1325 ((smb_t *)outp)->tid = newTid;
1326 ((smb_t *)inp)->tid = newTid;
1327 tp = smb_GetSMBData(outp, NULL);
1331 tp = smb_UnparseString(outp, tp, _C("A:"), &cb_data, SMB_STRF_FORCEASCII);
1332 tp = smb_UnparseString(outp, tp, _C("AFS"), &cb_data, 0);
1333 smb_SetSMBDataLength(outp, cb_data);
1337 tp = smb_UnparseString(outp, tp, _C("IPC"), &cb_data, SMB_STRF_FORCEASCII);
1338 smb_SetSMBDataLength(outp, cb_data);
1341 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1345 /* must be called with global tran lock held */
1346 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1348 smb_tran2Packet_t *tp;
1351 smbp = (smb_t *) inp->data;
1352 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1353 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1359 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1360 int totalParms, int totalData)
1362 smb_tran2Packet_t *tp;
1365 smbp = (smb_t *) inp->data;
1366 tp = malloc(sizeof(*tp));
1367 memset(tp, 0, sizeof(*tp));
1370 tp->curData = tp->curParms = 0;
1371 tp->totalData = totalData;
1372 tp->totalParms = totalParms;
1373 tp->tid = smbp->tid;
1374 tp->mid = smbp->mid;
1375 tp->uid = smbp->uid;
1376 tp->pid = smbp->pid;
1377 tp->res[0] = smbp->res[0];
1378 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1379 if (totalParms != 0)
1380 tp->parmsp = malloc(totalParms);
1382 tp->datap = malloc(totalData);
1383 if (smbp->com == 0x25 || smbp->com == 0x26)
1386 tp->opcode = smb_GetSMBParm(inp, 14);
1389 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1391 if (WANTS_UNICODE(inp) && (vcp->flags & SMB_VCFLAG_USEUNICODE))
1392 tp->flags |= SMB_TRAN2PFLAG_USEUNICODE;
1397 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1398 smb_tran2Packet_t *inp, smb_packet_t *outp,
1399 int totalParms, int totalData)
1401 smb_tran2Packet_t *tp;
1402 unsigned short parmOffset;
1403 unsigned short dataOffset;
1404 unsigned short dataAlign;
1406 tp = malloc(sizeof(*tp));
1407 memset(tp, 0, sizeof(*tp));
1410 tp->curData = tp->curParms = 0;
1411 tp->totalData = totalData;
1412 tp->totalParms = totalParms;
1413 tp->oldTotalParms = totalParms;
1418 tp->res[0] = inp->res[0];
1419 tp->opcode = inp->opcode;
1423 * We calculate where the parameters and data will start.
1424 * This calculation must parallel the calculation in
1425 * smb_SendTran2Packet.
1428 parmOffset = 10*2 + 35;
1429 parmOffset++; /* round to even */
1430 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1432 dataOffset = parmOffset + totalParms;
1433 dataAlign = dataOffset & 2; /* quad-align */
1434 dataOffset += dataAlign;
1435 tp->datap = outp->data + dataOffset;
1440 /* free a tran2 packet */
1441 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1444 smb_ReleaseVC(t2p->vcp);
1447 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1457 while (t2p->stringsp) {
1461 t2p->stringsp = ns->nextp;
1467 clientchar_t *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
1468 char ** chainpp, int flags)
1473 if (!(p->flags & SMB_TRAN2PFLAG_USEUNICODE))
1474 flags |= SMB_STRF_FORCEASCII;
1477 cb = p->totalParms - (inp - (char *)p->parmsp);
1478 if (inp < (char *) p->parmsp ||
1479 inp >= ((char *) p->parmsp) + p->totalParms) {
1480 #ifdef DEBUG_UNICODE
1486 return smb_ParseStringBuf((unsigned char *) p->parmsp, &p->stringsp,
1487 inp, &cb, chainpp, flags);
1490 /* called with a VC, an input packet to respond to, and an error code.
1491 * sends an error response.
1493 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1494 smb_packet_t *tp, long code)
1497 unsigned short errCode;
1498 unsigned char errClass;
1499 unsigned long NTStatus;
1501 if (vcp->flags & SMB_VCFLAG_STATUS32)
1502 smb_MapNTError(code, &NTStatus);
1504 smb_MapCoreError(code, vcp, &errCode, &errClass);
1506 smb_FormatResponsePacket(vcp, NULL, tp);
1507 smbp = (smb_t *) tp;
1509 /* We can handle long names */
1510 if (vcp->flags & SMB_VCFLAG_USENT)
1511 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1513 /* now copy important fields from the tran 2 packet */
1514 smbp->com = t2p->com;
1515 smbp->tid = t2p->tid;
1516 smbp->mid = t2p->mid;
1517 smbp->pid = t2p->pid;
1518 smbp->uid = t2p->uid;
1519 smbp->res[0] = t2p->res[0];
1520 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1521 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1522 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1523 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1524 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1525 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1528 smbp->rcls = errClass;
1529 smbp->errLow = (unsigned char) (errCode & 0xff);
1530 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1534 smb_SendPacket(vcp, tp);
1537 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1540 unsigned short parmOffset;
1541 unsigned short dataOffset;
1542 unsigned short totalLength;
1543 unsigned short dataAlign;
1546 smb_FormatResponsePacket(vcp, NULL, tp);
1547 smbp = (smb_t *) tp;
1549 /* We can handle long names */
1550 if (vcp->flags & SMB_VCFLAG_USENT)
1551 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1553 /* now copy important fields from the tran 2 packet */
1554 smbp->com = t2p->com;
1555 smbp->tid = t2p->tid;
1556 smbp->mid = t2p->mid;
1557 smbp->pid = t2p->pid;
1558 smbp->uid = t2p->uid;
1559 smbp->res[0] = t2p->res[0];
1561 if (t2p->error_code) {
1562 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1563 unsigned long NTStatus;
1565 smb_MapNTError(t2p->error_code, &NTStatus);
1567 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1568 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1569 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1570 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1571 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1574 unsigned short errCode;
1575 unsigned char errClass;
1577 smb_MapCoreError(t2p->error_code, vcp, &errCode, &errClass);
1579 smbp->rcls = errClass;
1580 smbp->errLow = (unsigned char) (errCode & 0xff);
1581 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1585 totalLength = 1 + t2p->totalData + t2p->totalParms;
1587 /* now add the core parameters (tran2 info) to the packet */
1588 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1589 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1590 smb_SetSMBParm(tp, 2, 0); /* reserved */
1591 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1592 parmOffset = 10*2 + 35; /* parm offset in packet */
1593 parmOffset++; /* round to even */
1594 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1595 * hdr, bcc and wct */
1596 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1597 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1598 dataOffset = parmOffset + t2p->oldTotalParms;
1599 dataAlign = dataOffset & 2; /* quad-align */
1600 dataOffset += dataAlign;
1601 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1602 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1603 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1606 datap = smb_GetSMBData(tp, NULL);
1607 *datap++ = 0; /* we rounded to even */
1609 totalLength += dataAlign;
1610 smb_SetSMBDataLength(tp, totalLength);
1612 /* next, send the datagram */
1613 smb_SendPacket(vcp, tp);
1616 /* TRANS_SET_NMPIPE_STATE */
1617 long smb_nmpipeSetState(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1621 int pipeState = 0x0100; /* default */
1622 smb_tran2Packet_t *outp = NULL;
1625 if (p->totalParms > 0)
1626 pipeState = p->parmsp[0];
1628 osi_Log2(smb_logp, "smb_nmpipeSetState for fd[%d] with state[0x%x]", fd, pipeState);
1630 fidp = smb_FindFID(vcp, fd, 0);
1632 osi_Log2(smb_logp, "smb_nmpipeSetState Unknown SMB Fid vcp 0x%p fid %d",
1634 return CM_ERROR_BADFD;
1636 lock_ObtainMutex(&fidp->mx);
1637 if (pipeState & 0x8000)
1638 fidp->flags |= SMB_FID_BLOCKINGPIPE;
1639 if (pipeState & 0x0100)
1640 fidp->flags |= SMB_FID_MESSAGEMODEPIPE;
1641 lock_ReleaseMutex(&fidp->mx);
1643 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 0);
1644 smb_SendTran2Packet(vcp, outp, op);
1645 smb_FreeTran2Packet(outp);
1647 smb_ReleaseFID(fidp);
1652 long smb_nmpipeTransact(smb_vc_t * vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1662 osi_Log3(smb_logp, "smb_nmpipeTransact for fd[%d] %d bytes in, %d max bytes out",
1663 fd, p->totalData, p->maxReturnData);
1665 fidp = smb_FindFID(vcp, fd, 0);
1667 osi_Log2(smb_logp, "smb_nmpipeTransact Unknown SMB Fid vcp 0x%p fid %d",
1669 return CM_ERROR_BADFD;
1671 lock_ObtainMutex(&fidp->mx);
1672 if (fidp->flags & SMB_FID_RPC) {
1675 lock_ReleaseMutex(&fidp->mx);
1678 code = smb_RPCNmpipeTransact(fidp, vcp, p, op);
1679 smb_ReleaseFID(fidp);
1681 /* We only deal with RPC pipes */
1682 osi_Log2(smb_logp, "smb_nmpipeTransact Not a RPC vcp 0x%p fid %d",
1684 code = CM_ERROR_BADFD;
1691 /* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
1692 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1694 smb_tran2Packet_t *asp;
1707 /* We sometimes see 0 word count. What to do? */
1708 if (*inp->wctp == 0) {
1709 osi_Log0(smb_logp, "Transaction2 word count = 0");
1710 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1712 smb_SetSMBDataLength(outp, 0);
1713 smb_SendPacket(vcp, outp);
1717 totalParms = smb_GetSMBParm(inp, 0);
1718 totalData = smb_GetSMBParm(inp, 1);
1720 firstPacket = (inp->inCom == 0x25);
1722 /* find the packet we're reassembling */
1723 lock_ObtainWrite(&smb_globalLock);
1724 asp = smb_FindTran2Packet(vcp, inp);
1726 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1728 lock_ReleaseWrite(&smb_globalLock);
1730 /* now merge in this latest packet; start by looking up offsets */
1732 parmDisp = dataDisp = 0;
1733 parmOffset = smb_GetSMBParm(inp, 10);
1734 dataOffset = smb_GetSMBParm(inp, 12);
1735 parmCount = smb_GetSMBParm(inp, 9);
1736 dataCount = smb_GetSMBParm(inp, 11);
1737 asp->setupCount = smb_GetSMBParmByte(inp, 13);
1738 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1739 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1741 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1742 totalData, dataCount, asp->maxReturnData);
1744 if (asp->setupCount == 2) {
1745 clientchar_t * pname;
1747 asp->pipeCommand = smb_GetSMBParm(inp, 14);
1748 asp->pipeParam = smb_GetSMBParm(inp, 15);
1749 pname = smb_ParseString(inp, inp->wctp + 35, NULL, 0);
1751 asp->name = cm_ClientStrDup(pname);
1754 osi_Log2(smb_logp, " Named Pipe command id [%d] with name [%S]",
1755 asp->pipeCommand, osi_LogSaveClientString(smb_logp, asp->name));
1759 parmDisp = smb_GetSMBParm(inp, 4);
1760 parmOffset = smb_GetSMBParm(inp, 3);
1761 dataDisp = smb_GetSMBParm(inp, 7);
1762 dataOffset = smb_GetSMBParm(inp, 6);
1763 parmCount = smb_GetSMBParm(inp, 2);
1764 dataCount = smb_GetSMBParm(inp, 5);
1766 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1767 parmCount, dataCount);
1770 /* now copy the parms and data */
1771 if ( asp->totalParms > 0 && parmCount != 0 )
1773 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1775 if ( asp->totalData > 0 && dataCount != 0 ) {
1776 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1779 /* account for new bytes */
1780 asp->curData += dataCount;
1781 asp->curParms += parmCount;
1783 /* finally, if we're done, remove the packet from the queue and dispatch it */
1784 if (((asp->totalParms > 0 && asp->curParms > 0)
1785 || asp->setupCount == 2) &&
1786 asp->totalData <= asp->curData &&
1787 asp->totalParms <= asp->curParms) {
1789 /* we've received it all */
1790 lock_ObtainWrite(&smb_globalLock);
1791 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1792 lock_ReleaseWrite(&smb_globalLock);
1794 switch(asp->setupCount) {
1797 rapOp = asp->parmsp[0];
1799 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES &&
1800 smb_rapDispatchTable[rapOp].procp) {
1802 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",
1803 myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1805 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1807 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",
1808 code,vcp,vcp->lana,vcp->lsn);
1811 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]",
1812 rapOp, vcp, vcp->lana, vcp->lsn);
1814 code = CM_ERROR_BADOP;
1820 { /* Named pipe operation */
1821 osi_Log2(smb_logp, "Named Pipe: %s with name [%S]",
1822 myCrt_NmpipeDispatch(asp->pipeCommand),
1823 osi_LogSaveClientString(smb_logp, asp->name));
1825 code = CM_ERROR_BADOP;
1827 switch (asp->pipeCommand) {
1828 case SMB_TRANS_SET_NMPIPE_STATE:
1829 code = smb_nmpipeSetState(vcp, asp, outp);
1832 case SMB_TRANS_RAW_READ_NMPIPE:
1835 case SMB_TRANS_QUERY_NMPIPE_STATE:
1838 case SMB_TRANS_QUERY_NMPIPE_INFO:
1841 case SMB_TRANS_PEEK_NMPIPE:
1844 case SMB_TRANS_TRANSACT_NMPIPE:
1845 code = smb_nmpipeTransact(vcp, asp, outp);
1848 case SMB_TRANS_RAW_WRITE_NMPIPE:
1851 case SMB_TRANS_READ_NMPIPE:
1854 case SMB_TRANS_WRITE_NMPIPE:
1857 case SMB_TRANS_WAIT_NMPIPE:
1860 case SMB_TRANS_CALL_NMPIPE:
1867 code = CM_ERROR_BADOP;
1870 /* if an error is returned, we're supposed to send an error packet,
1871 * otherwise the dispatched function already did the data sending.
1872 * We give dispatched proc the responsibility since it knows how much
1873 * space to allocate.
1876 smb_SendTran2Error(vcp, asp, outp, code);
1879 /* free the input tran 2 packet */
1880 smb_FreeTran2Packet(asp);
1882 else if (firstPacket) {
1883 /* the first packet in a multi-packet request, we need to send an
1884 * ack to get more data.
1886 smb_SetSMBDataLength(outp, 0);
1887 smb_SendPacket(vcp, outp);
1893 /* ANSI versions. */
1895 #pragma pack(push, 1)
1897 typedef struct smb_rap_share_info_0 {
1898 BYTE shi0_netname[13];
1899 } smb_rap_share_info_0_t;
1901 typedef struct smb_rap_share_info_1 {
1902 BYTE shi1_netname[13];
1905 DWORD shi1_remark; /* char *shi1_remark; data offset */
1906 } smb_rap_share_info_1_t;
1908 typedef struct smb_rap_share_info_2 {
1909 BYTE shi2_netname[13];
1912 DWORD shi2_remark; /* char *shi2_remark; data offset */
1913 WORD shi2_permissions;
1915 WORD shi2_current_uses;
1916 DWORD shi2_path; /* char *shi2_path; data offset */
1917 WORD shi2_passwd[9];
1919 } smb_rap_share_info_2_t;
1921 #define SMB_RAP_MAX_SHARES 512
1923 typedef struct smb_rap_share_list {
1926 smb_rap_share_info_0_t * shares;
1927 } smb_rap_share_list_t;
1931 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1932 smb_rap_share_list_t * sp;
1934 if (dep->name[0] == '.' && (!dep->name[1] || (dep->name[1] == '.' && !dep->name[2])))
1935 return 0; /* skip over '.' and '..' */
1937 sp = (smb_rap_share_list_t *) vrockp;
1939 strncpy(sp->shares[sp->cShare].shi0_netname, dep->name, 12);
1940 sp->shares[sp->cShare].shi0_netname[12] = 0;
1944 if (sp->cShare >= sp->maxShares)
1945 return CM_ERROR_STOPNOW;
1950 /* RAP NetShareEnumRequest */
1951 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1953 smb_tran2Packet_t *outp;
1954 unsigned short * tp;
1958 int outParmsTotal; /* total parameter bytes */
1959 int outDataTotal; /* total data bytes */
1962 DWORD allSubmount = 0;
1964 DWORD nRegShares = 0;
1965 DWORD nSharesRet = 0;
1967 HKEY hkSubmount = NULL;
1968 smb_rap_share_info_1_t * shares;
1971 clientchar_t thisShare[AFSPATHMAX];
1975 smb_rap_share_list_t rootShares;
1979 cm_scache_t *rootScp;
1981 tp = p->parmsp + 1; /* skip over function number (always 0) */
1984 clientchar_t * cdescp;
1986 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1987 if (cm_ClientStrCmp(cdescp, _C("WrLeh")))
1988 return CM_ERROR_INVAL;
1989 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1990 if (cm_ClientStrCmp(cdescp, _C("B13BWz")))
1991 return CM_ERROR_INVAL;
1997 if (infoLevel != 1) {
1998 return CM_ERROR_INVAL;
2001 /* We are supposed to use the same ASCII data structure even if
2002 Unicode is negotiated, which ultimately means that the share
2003 names that we return must be at most 13 characters in length,
2004 including the NULL terminator.
2006 The RAP specification states that shares with names longer than
2007 12 characters should not be included in the enumeration.
2008 However, since we support prefix cell references and since many
2009 cell names are going to exceed 12 characters, we lie and send
2010 the first 12 characters.
2013 /* first figure out how many shares there are */
2014 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
2015 KEY_QUERY_VALUE, &hkParam);
2016 if (rv == ERROR_SUCCESS) {
2017 len = sizeof(allSubmount);
2018 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
2019 (BYTE *) &allSubmount, &len);
2020 if (rv != ERROR_SUCCESS || allSubmount != 0) {
2023 RegCloseKey (hkParam);
2026 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
2027 0, KEY_QUERY_VALUE, &hkSubmount);
2028 if (rv == ERROR_SUCCESS) {
2029 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
2030 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
2031 if (rv != ERROR_SUCCESS)
2037 /* fetch the root shares */
2038 rootShares.maxShares = SMB_RAP_MAX_SHARES;
2039 rootShares.cShare = 0;
2040 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
2044 userp = smb_GetTran2User(vcp,p);
2046 thyper.HighPart = 0;
2049 rootScp = cm_RootSCachep(userp, &req);
2050 cm_HoldSCache(rootScp);
2051 cm_ApplyDir(rootScp, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
2052 cm_ReleaseSCache(rootScp);
2054 cm_ReleaseUser(userp);
2056 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
2058 #define REMARK_LEN 1
2059 outParmsTotal = 8; /* 4 dwords */
2060 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
2061 if(outDataTotal > bufsize) {
2062 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
2063 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
2066 nSharesRet = nShares;
2069 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
2071 /* now for the submounts */
2072 shares = (smb_rap_share_info_1_t *) outp->datap;
2073 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
2075 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
2078 StringCchCopyA(shares[cshare].shi1_netname,
2079 lengthof(shares[cshare].shi1_netname), "all" );
2080 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
2081 /* type and pad are zero already */
2087 for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
2088 len = sizeof(thisShare);
2089 rv = RegEnumValueW(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
2090 if (rv == ERROR_SUCCESS &&
2091 cm_ClientStrLen(thisShare) &&
2092 (!allSubmount || cm_ClientStrCmpI(thisShare,_C("all")))) {
2093 cm_ClientStringToUtf8(thisShare, -1, shares[cshare].shi1_netname,
2094 lengthof( shares[cshare].shi1_netname ));
2095 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
2096 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
2101 nShares--; /* uncount key */
2104 RegCloseKey(hkSubmount);
2107 nonrootShares = cshare;
2109 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
2110 /* in case there are collisions with submounts, submounts have
2112 for (j=0; j < nonrootShares; j++)
2113 if (!cm_stricmp_utf8(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
2116 if (j < nonrootShares) {
2117 nShares--; /* uncount */
2121 StringCchCopyA(shares[cshare].shi1_netname, lengthof(shares[cshare].shi1_netname),
2122 rootShares.shares[i].shi0_netname);
2123 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
2128 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
2129 outp->parmsp[1] = 0;
2130 outp->parmsp[2] = cshare;
2131 outp->parmsp[3] = nShares;
2133 outp->totalData = (int)(cstrp - outp->datap);
2134 outp->totalParms = outParmsTotal;
2136 smb_SendTran2Packet(vcp, outp, op);
2137 smb_FreeTran2Packet(outp);
2139 free(rootShares.shares);
2144 /* RAP NetShareGetInfo */
2145 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2147 smb_tran2Packet_t *outp;
2148 unsigned short * tp;
2149 clientchar_t * shareName;
2150 BOOL shareFound = FALSE;
2151 unsigned short infoLevel;
2152 unsigned short bufsize;
2161 cm_scache_t *scp = NULL;
2167 tp = p->parmsp + 1; /* skip over function number (always 1) */
2170 clientchar_t * cdescp;
2172 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2173 if (cm_ClientStrCmp(cdescp, _C("zWrLh")))
2175 return CM_ERROR_INVAL;
2177 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2178 if (cm_ClientStrCmp(cdescp, _C("B13")) &&
2179 cm_ClientStrCmp(cdescp, _C("B13BWz")) &&
2180 cm_ClientStrCmp(cdescp, _C("B13BWzWWWzB9B")))
2182 return CM_ERROR_INVAL;
2184 shareName = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2192 totalData = sizeof(smb_rap_share_info_0_t);
2193 else if(infoLevel == SMB_INFO_STANDARD)
2194 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
2195 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
2196 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
2198 return CM_ERROR_INVAL;
2200 if(!cm_ClientStrCmpI(shareName, _C("all")) || !cm_ClientStrCmp(shareName,_C("*."))) {
2201 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
2202 KEY_QUERY_VALUE, &hkParam);
2203 if (rv == ERROR_SUCCESS) {
2204 len = sizeof(allSubmount);
2205 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
2206 (BYTE *) &allSubmount, &len);
2207 if (rv != ERROR_SUCCESS || allSubmount != 0) {
2210 RegCloseKey (hkParam);
2217 userp = smb_GetTran2User(vcp, p);
2219 osi_Log1(smb_logp,"ReceiveRAPNetShareGetInfo unable to resolve user [%d]", p->uid);
2220 return CM_ERROR_BADSMB;
2222 code = cm_NameI(cm_RootSCachep(userp, &req), shareName,
2223 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
2224 userp, NULL, &req, &scp);
2226 cm_ReleaseSCache(scp);
2229 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
2230 KEY_QUERY_VALUE, &hkSubmount);
2231 if (rv == ERROR_SUCCESS) {
2232 rv = RegQueryValueExW(hkSubmount, shareName, NULL, NULL, NULL, NULL);
2233 if (rv == ERROR_SUCCESS) {
2236 RegCloseKey(hkSubmount);
2242 return CM_ERROR_BADSHARENAME;
2244 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
2245 memset(outp->datap, 0, totalData);
2247 outp->parmsp[0] = 0;
2248 outp->parmsp[1] = 0;
2249 outp->parmsp[2] = totalData;
2251 if (infoLevel == 0) {
2252 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
2253 cm_ClientStringToUtf8(shareName, -1, info->shi0_netname,
2254 lengthof(info->shi0_netname));
2255 } else if(infoLevel == SMB_INFO_STANDARD) {
2256 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
2257 cm_ClientStringToUtf8(shareName, -1, info->shi1_netname, lengthof(info->shi1_netname));
2258 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
2259 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
2260 /* type and pad are already zero */
2261 } else { /* infoLevel==2 */
2262 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
2263 cm_ClientStringToUtf8(shareName, -1, info->shi2_netname, lengthof(info->shi2_netname));
2264 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
2265 info->shi2_permissions = ACCESS_ALL;
2266 info->shi2_max_uses = (unsigned short) -1;
2267 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
2270 outp->totalData = totalData;
2271 outp->totalParms = totalParam;
2273 smb_SendTran2Packet(vcp, outp, op);
2274 smb_FreeTran2Packet(outp);
2279 #pragma pack(push, 1)
2281 typedef struct smb_rap_wksta_info_10 {
2282 DWORD wki10_computername; /*char *wki10_computername;*/
2283 DWORD wki10_username; /* char *wki10_username; */
2284 DWORD wki10_langroup; /* char *wki10_langroup;*/
2285 BYTE wki10_ver_major;
2286 BYTE wki10_ver_minor;
2287 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
2288 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
2289 } smb_rap_wksta_info_10_t;
2293 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2295 smb_tran2Packet_t *outp;
2299 unsigned short * tp;
2302 smb_rap_wksta_info_10_t * info;
2306 tp = p->parmsp + 1; /* Skip over function number */
2309 clientchar_t * cdescp;
2311 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2312 SMB_STRF_FORCEASCII);
2313 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2314 return CM_ERROR_INVAL;
2316 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2317 SMB_STRF_FORCEASCII);
2318 if (cm_ClientStrCmp(cdescp, _C("zzzBBzz")))
2319 return CM_ERROR_INVAL;
2325 if (infoLevel != 10) {
2326 return CM_ERROR_INVAL;
2332 totalData = sizeof(*info) + /* info */
2333 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
2334 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
2335 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
2336 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
2337 1; /* wki10_oth_domains (null)*/
2339 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2341 memset(outp->parmsp,0,totalParams);
2342 memset(outp->datap,0,totalData);
2344 info = (smb_rap_wksta_info_10_t *) outp->datap;
2345 cstrp = (char *) (info + 1);
2347 info->wki10_computername = (DWORD) (cstrp - outp->datap);
2348 StringCbCopyA(cstrp, totalData, smb_localNamep);
2349 cstrp += strlen(cstrp) + 1;
2351 info->wki10_username = (DWORD) (cstrp - outp->datap);
2352 uidp = smb_FindUID(vcp, p->uid, 0);
2354 lock_ObtainMutex(&uidp->mx);
2355 if(uidp->unp && uidp->unp->name)
2356 cm_ClientStringToUtf8(uidp->unp->name, -1,
2357 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2358 lock_ReleaseMutex(&uidp->mx);
2359 smb_ReleaseUID(uidp);
2361 cstrp += strlen(cstrp) + 1;
2363 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
2364 StringCbCopyA(cstrp, totalData - (cstrp - outp->datap)*sizeof(char), "WORKGROUP");
2365 cstrp += strlen(cstrp) + 1;
2367 /* TODO: Not sure what values these should take, but these work */
2368 info->wki10_ver_major = 5;
2369 info->wki10_ver_minor = 1;
2371 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
2372 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
2373 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2374 cstrp += strlen(cstrp) + 1;
2376 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
2377 cstrp ++; /* no other domains */
2379 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
2380 outp->parmsp[2] = outp->totalData;
2381 outp->totalParms = totalParams;
2383 smb_SendTran2Packet(vcp,outp,op);
2384 smb_FreeTran2Packet(outp);
2389 #pragma pack(push, 1)
2391 typedef struct smb_rap_server_info_0 {
2393 } smb_rap_server_info_0_t;
2395 typedef struct smb_rap_server_info_1 {
2397 BYTE sv1_version_major;
2398 BYTE sv1_version_minor;
2400 DWORD sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
2401 } smb_rap_server_info_1_t;
2405 char smb_ServerComment[] = "OpenAFS Client";
2406 int smb_ServerCommentLen = sizeof(smb_ServerComment);
2408 #define SMB_SV_TYPE_SERVER 0x00000002L
2409 #define SMB_SV_TYPE_NT 0x00001000L
2410 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
2412 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2414 smb_tran2Packet_t *outp;
2418 unsigned short * tp;
2421 smb_rap_server_info_0_t * info0;
2422 smb_rap_server_info_1_t * info1;
2425 tp = p->parmsp + 1; /* Skip over function number */
2428 clientchar_t * cdescp;
2430 cdescp = smb_ParseStringT2Parm(p, (unsigned char *) tp, (char **) &tp,
2431 SMB_STRF_FORCEASCII);
2432 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2433 return CM_ERROR_INVAL;
2434 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2435 SMB_STRF_FORCEASCII);
2436 if (cm_ClientStrCmp(cdescp, _C("B16")) ||
2437 cm_ClientStrCmp(cdescp, _C("B16BBDz")))
2438 return CM_ERROR_INVAL;
2444 if (infoLevel != 0 && infoLevel != 1) {
2445 return CM_ERROR_INVAL;
2451 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
2452 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
2454 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2456 memset(outp->parmsp,0,totalParams);
2457 memset(outp->datap,0,totalData);
2459 if (infoLevel == 0) {
2460 info0 = (smb_rap_server_info_0_t *) outp->datap;
2461 cstrp = (char *) (info0 + 1);
2462 StringCchCopyA(info0->sv0_name, lengthof(info0->sv0_name), "AFS");
2463 } else { /* infoLevel == SMB_INFO_STANDARD */
2464 info1 = (smb_rap_server_info_1_t *) outp->datap;
2465 cstrp = (char *) (info1 + 1);
2466 StringCchCopyA(info1->sv1_name, lengthof(info1->sv1_name), "AFS");
2469 SMB_SV_TYPE_SERVER |
2471 SMB_SV_TYPE_SERVER_NT;
2473 info1->sv1_version_major = 5;
2474 info1->sv1_version_minor = 1;
2475 info1->sv1_comment_or_master_browser = (DWORD) (cstrp - outp->datap);
2477 StringCbCopyA(cstrp, smb_ServerCommentLen, smb_ServerComment);
2479 cstrp += smb_ServerCommentLen / sizeof(char);
2482 totalData = (DWORD)(cstrp - outp->datap);
2483 outp->totalData = min(bufsize,totalData); /* actual data size */
2484 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
2485 outp->parmsp[2] = totalData;
2486 outp->totalParms = totalParams;
2488 smb_SendTran2Packet(vcp,outp,op);
2489 smb_FreeTran2Packet(outp);
2494 /* SMB_COM_TRANSACTION2 and SMB_COM_TRANSACTION2_SECONDARY */
2495 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2497 smb_tran2Packet_t *asp;
2508 DWORD oldTime, newTime;
2510 /* We sometimes see 0 word count. What to do? */
2511 if (*inp->wctp == 0) {
2512 osi_Log0(smb_logp, "Transaction2 word count = 0");
2513 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
2515 smb_SetSMBDataLength(outp, 0);
2516 smb_SendPacket(vcp, outp);
2520 totalParms = smb_GetSMBParm(inp, 0);
2521 totalData = smb_GetSMBParm(inp, 1);
2523 firstPacket = (inp->inCom == 0x32);
2525 /* find the packet we're reassembling */
2526 lock_ObtainWrite(&smb_globalLock);
2527 asp = smb_FindTran2Packet(vcp, inp);
2529 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
2531 lock_ReleaseWrite(&smb_globalLock);
2533 /* now merge in this latest packet; start by looking up offsets */
2535 parmDisp = dataDisp = 0;
2536 parmOffset = smb_GetSMBParm(inp, 10);
2537 dataOffset = smb_GetSMBParm(inp, 12);
2538 parmCount = smb_GetSMBParm(inp, 9);
2539 dataCount = smb_GetSMBParm(inp, 11);
2540 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2541 asp->maxReturnData = smb_GetSMBParm(inp, 3);
2543 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2544 totalData, dataCount, asp->maxReturnData);
2547 parmDisp = smb_GetSMBParm(inp, 4);
2548 parmOffset = smb_GetSMBParm(inp, 3);
2549 dataDisp = smb_GetSMBParm(inp, 7);
2550 dataOffset = smb_GetSMBParm(inp, 6);
2551 parmCount = smb_GetSMBParm(inp, 2);
2552 dataCount = smb_GetSMBParm(inp, 5);
2554 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2555 parmCount, dataCount);
2558 /* now copy the parms and data */
2559 if ( asp->totalParms > 0 && parmCount != 0 )
2561 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2563 if ( asp->totalData > 0 && dataCount != 0 ) {
2564 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2567 /* account for new bytes */
2568 asp->curData += dataCount;
2569 asp->curParms += parmCount;
2571 /* finally, if we're done, remove the packet from the queue and dispatch it */
2572 if (asp->totalParms > 0 &&
2573 asp->curParms > 0 &&
2574 asp->totalData <= asp->curData &&
2575 asp->totalParms <= asp->curParms) {
2576 /* we've received it all */
2577 lock_ObtainWrite(&smb_globalLock);
2578 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2579 lock_ReleaseWrite(&smb_globalLock);
2581 oldTime = GetTickCount();
2583 /* now dispatch it */
2584 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2585 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2586 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2589 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2590 code = CM_ERROR_BADOP;
2593 /* if an error is returned, we're supposed to send an error packet,
2594 * otherwise the dispatched function already did the data sending.
2595 * We give dispatched proc the responsibility since it knows how much
2596 * space to allocate.
2599 smb_SendTran2Error(vcp, asp, outp, code);
2602 newTime = GetTickCount();
2603 if (newTime - oldTime > 45000) {
2606 clientchar_t *treepath = NULL; /* do not free */
2607 clientchar_t *pathname = NULL;
2608 cm_fid_t afid = {0,0,0,0,0};
2610 uidp = smb_FindUID(vcp, asp->uid, 0);
2611 smb_LookupTIDPath(vcp, asp->tid, &treepath);
2612 fidp = smb_FindFID(vcp, inp->fid, 0);
2615 lock_ObtainMutex(&fidp->mx);
2616 if (fidp->NTopen_pathp)
2617 pathname = fidp->NTopen_pathp;
2619 afid = fidp->scp->fid;
2621 if (inp->stringsp->wdata)
2622 pathname = inp->stringsp->wdata;
2625 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)",
2626 myCrt_2Dispatch(asp->opcode), newTime - oldTime,
2627 asp->uid, uidp ? uidp->unp->name : NULL,
2628 asp->pid, asp->mid, asp->tid,
2631 afid.cell, afid.volume, afid.vnode, afid.unique);
2634 lock_ReleaseMutex(&fidp->mx);
2637 smb_ReleaseUID(uidp);
2639 smb_ReleaseFID(fidp);
2642 /* free the input tran 2 packet */
2643 smb_FreeTran2Packet(asp);
2645 else if (firstPacket) {
2646 /* the first packet in a multi-packet request, we need to send an
2647 * ack to get more data.
2649 smb_SetSMBDataLength(outp, 0);
2650 smb_SendPacket(vcp, outp);
2657 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2659 clientchar_t *pathp;
2660 smb_tran2Packet_t *outp;
2665 cm_scache_t *dscp; /* dir we're dealing with */
2666 cm_scache_t *scp; /* file we're creating */
2670 clientchar_t *lastNamep;
2677 int parmSlot; /* which parm we're dealing with */
2678 long returnEALength;
2679 clientchar_t *tidPathp;
2682 BOOL is_rpc = FALSE;
2683 BOOL is_ipc = FALSE;
2689 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2690 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2692 openFun = p->parmsp[6]; /* open function */
2693 excl = ((openFun & 3) == 0);
2694 trunc = ((openFun & 3) == 2); /* truncate it */
2695 openMode = (p->parmsp[1] & 0x7);
2696 openAction = 0; /* tracks what we did */
2698 attributes = p->parmsp[3];
2699 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2701 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
2704 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2706 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2707 if (code == CM_ERROR_TIDIPC) {
2709 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2712 spacep = cm_GetSpace();
2713 /* smb_StripLastComponent will strip "::$DATA" if present */
2714 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2718 /* special case magic file name for receiving IOCTL requests
2719 * (since IOCTL calls themselves aren't getting through).
2721 (cm_ClientStrCmpI(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
2723 /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional)*/
2724 (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
2726 unsigned short file_type = 0;
2727 unsigned short device_state = 0;
2729 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2732 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
2733 osi_Log2(smb_logp, "smb_ReceiveTran2Open Creating RPC Fid [%d] code [%d]",
2736 smb_ReleaseFID(fidp);
2737 smb_FreeTran2Packet(outp);
2738 osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
2742 smb_SetupIoctlFid(fidp, spacep);
2743 osi_Log1(smb_logp, "smb_ReceiveTran2Open Creating IOCTL Fid [%d]", fidp->fid);
2746 /* copy out remainder of the parms */
2748 outp->parmsp[parmSlot++] = fidp->fid;
2750 outp->parmsp[parmSlot++] = 0; /* attrs */
2751 outp->parmsp[parmSlot++] = 0; /* mod time */
2752 outp->parmsp[parmSlot++] = 0;
2753 outp->parmsp[parmSlot++] = 0; /* len */
2754 outp->parmsp[parmSlot++] = 0x7fff;
2755 outp->parmsp[parmSlot++] = openMode;
2756 outp->parmsp[parmSlot++] = file_type;
2757 outp->parmsp[parmSlot++] = device_state;
2759 /* and the final "always present" stuff */
2760 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2761 /* next write out the "unique" ID */
2762 outp->parmsp[parmSlot++] = 0x1234;
2763 outp->parmsp[parmSlot++] = 0x5678;
2764 outp->parmsp[parmSlot++] = 0;
2765 if (returnEALength) {
2766 outp->parmsp[parmSlot++] = 0;
2767 outp->parmsp[parmSlot++] = 0;
2770 outp->totalData = 0;
2771 outp->totalParms = parmSlot * 2;
2773 smb_SendTran2Packet(vcp, outp, op);
2775 smb_FreeTran2Packet(outp);
2777 /* and clean up fid reference */
2778 smb_ReleaseFID(fidp);
2784 osi_Log1(smb_logp, "Tran2Open rejecting IPC TID vcp %p", vcp);
2785 smb_FreeTran2Packet(outp);
2786 return CM_ERROR_BADFD;
2790 if (!cm_IsValidClientString(pathp)) {
2792 clientchar_t * hexp;
2794 hexp = cm_GetRawCharsAlloc(pathp, -1);
2795 osi_Log1(smb_logp, "Tran2Open rejecting invalid name. [%S]",
2796 osi_LogSaveClientString(smb_logp, hexp));
2800 osi_Log0(smb_logp, "Tran2Open rejecting invalid name");
2802 smb_FreeTran2Packet(outp);
2803 return CM_ERROR_BADNTFILENAME;
2806 #ifdef DEBUG_VERBOSE
2808 char *hexp, *asciip;
2809 asciip = (lastNamep ? lastNamep : pathp);
2810 hexp = osi_HexifyString( asciip );
2811 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2816 userp = smb_GetTran2User(vcp, p);
2817 /* In the off chance that userp is NULL, we log and abandon */
2819 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2820 smb_FreeTran2Packet(outp);
2821 return CM_ERROR_BADSMB;
2825 code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
2826 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2827 userp, tidPathp, &req, &scp);
2829 if (code == CM_ERROR_NOSUCHFILE ||
2830 code == CM_ERROR_NOSUCHPATH ||
2831 code == CM_ERROR_BPLUS_NOMATCH)
2832 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
2833 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2834 userp, tidPathp, &req, &dscp);
2835 cm_FreeSpace(spacep);
2838 cm_ReleaseUser(userp);
2839 smb_FreeTran2Packet(outp);
2844 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2845 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2846 (clientchar_t*) spacep->data);
2847 cm_ReleaseSCache(dscp);
2848 cm_ReleaseUser(userp);
2849 smb_FreeTran2Packet(outp);
2850 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2851 return CM_ERROR_PATH_NOT_COVERED;
2853 return CM_ERROR_NOSUCHPATH;
2855 #endif /* DFS_SUPPORT */
2857 /* otherwise, scp points to the parent directory. Do a lookup,
2858 * and truncate the file if we find it, otherwise we create the
2865 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2867 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2868 cm_ReleaseSCache(dscp);
2869 cm_ReleaseUser(userp);
2870 smb_FreeTran2Packet(outp);
2874 /* macintosh is expensive to program for it */
2875 cm_FreeSpace(spacep);
2878 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2879 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2880 cm_ReleaseSCache(scp);
2881 cm_ReleaseUser(userp);
2882 smb_FreeTran2Packet(outp);
2883 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2884 return CM_ERROR_PATH_NOT_COVERED;
2886 return CM_ERROR_NOSUCHPATH;
2888 #endif /* DFS_SUPPORT */
2891 /* if we get here, if code is 0, the file exists and is represented by
2892 * scp. Otherwise, we have to create it.
2895 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2898 cm_ReleaseSCache(dscp);
2899 cm_ReleaseSCache(scp);
2900 cm_ReleaseUser(userp);
2901 smb_FreeTran2Packet(outp);
2906 /* oops, file shouldn't be there */
2908 cm_ReleaseSCache(dscp);
2909 cm_ReleaseSCache(scp);
2910 cm_ReleaseUser(userp);
2911 smb_FreeTran2Packet(outp);
2912 return CM_ERROR_EXISTS;
2916 setAttr.mask = CM_ATTRMASK_LENGTH;
2917 setAttr.length.LowPart = 0;
2918 setAttr.length.HighPart = 0;
2919 code = cm_SetAttr(scp, &setAttr, userp, &req);
2920 openAction = 3; /* truncated existing file */
2923 openAction = 1; /* found existing file */
2925 else if (!(openFun & 0x10)) {
2926 /* don't create if not found */
2928 cm_ReleaseSCache(dscp);
2929 osi_assertx(scp == NULL, "null cm_scache_t");
2930 cm_ReleaseUser(userp);
2931 smb_FreeTran2Packet(outp);
2932 return CM_ERROR_NOSUCHFILE;
2935 osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2936 openAction = 2; /* created file */
2937 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2938 cm_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2939 smb_SetInitialModeBitsForFile(attributes, &setAttr);
2941 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2945 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2946 smb_NotifyChange(FILE_ACTION_ADDED,
2947 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2948 dscp, lastNamep, NULL, TRUE);
2949 } else if (!excl && code == CM_ERROR_EXISTS) {
2950 /* not an exclusive create, and someone else tried
2951 * creating it already, then we open it anyway. We
2952 * don't bother retrying after this, since if this next
2953 * fails, that means that the file was deleted after we
2954 * started this call.
2956 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2960 setAttr.mask = CM_ATTRMASK_LENGTH;
2961 setAttr.length.LowPart = 0;
2962 setAttr.length.HighPart = 0;
2963 code = cm_SetAttr(scp, &setAttr, userp,
2966 } /* lookup succeeded */
2970 /* we don't need this any longer */
2972 cm_ReleaseSCache(dscp);
2975 /* something went wrong creating or truncating the file */
2977 cm_ReleaseSCache(scp);
2978 cm_ReleaseUser(userp);
2979 smb_FreeTran2Packet(outp);
2983 /* make sure we're about to open a file */
2984 if (scp->fileType != CM_SCACHETYPE_FILE) {
2986 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2987 cm_scache_t * targetScp = 0;
2988 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2990 /* we have a more accurate file to use (the
2991 * target of the symbolic link). Otherwise,
2992 * we'll just use the symlink anyway.
2994 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2996 cm_ReleaseSCache(scp);
3000 if (scp->fileType != CM_SCACHETYPE_FILE) {
3001 cm_ReleaseSCache(scp);
3002 cm_ReleaseUser(userp);
3003 smb_FreeTran2Packet(outp);
3004 return CM_ERROR_ISDIR;
3008 /* now all we have to do is open the file itself */
3009 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3010 osi_assertx(fidp, "null smb_fid_t");
3013 lock_ObtainMutex(&fidp->mx);
3014 /* save a pointer to the vnode */
3015 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
3017 lock_ObtainWrite(&scp->rw);
3018 scp->flags |= CM_SCACHEFLAG_SMB_FID;
3019 lock_ReleaseWrite(&scp->rw);
3022 fidp->userp = userp;
3024 /* compute open mode */
3026 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
3027 if (openMode == 1 || openMode == 2)
3028 fidp->flags |= SMB_FID_OPENWRITE;
3030 /* remember that the file was newly created */
3032 fidp->flags |= SMB_FID_CREATED;
3034 lock_ReleaseMutex(&fidp->mx);
3036 smb_ReleaseFID(fidp);
3038 cm_Open(scp, 0, userp);
3040 /* copy out remainder of the parms */
3042 outp->parmsp[parmSlot++] = fidp->fid;
3043 lock_ObtainRead(&scp->rw);
3045 outp->parmsp[parmSlot++] = smb_Attributes(scp);
3046 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3047 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
3048 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
3049 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
3050 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
3051 outp->parmsp[parmSlot++] = openMode;
3052 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
3053 outp->parmsp[parmSlot++] = 0; /* IPC junk */
3055 /* and the final "always present" stuff */
3056 outp->parmsp[parmSlot++] = openAction;
3057 /* next write out the "unique" ID */
3058 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
3059 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
3060 outp->parmsp[parmSlot++] = 0;
3061 if (returnEALength) {
3062 outp->parmsp[parmSlot++] = 0;
3063 outp->parmsp[parmSlot++] = 0;
3065 lock_ReleaseRead(&scp->rw);
3066 outp->totalData = 0; /* total # of data bytes */
3067 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
3069 smb_SendTran2Packet(vcp, outp, op);
3071 smb_FreeTran2Packet(outp);
3073 cm_ReleaseUser(userp);
3074 /* leave scp held since we put it in fidp->scp */
3078 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3081 unsigned short infolevel;
3083 infolevel = p->parmsp[0];
3085 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
3087 return CM_ERROR_BAD_LEVEL;
3090 /* TRANS2_QUERY_FS_INFORMATION */
3091 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3093 smb_tran2Packet_t *outp;
3094 smb_tran2QFSInfo_t qi;
3098 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
3100 switch (p->parmsp[0]) {
3101 case SMB_INFO_ALLOCATION:
3103 responseSize = sizeof(qi.u.allocInfo);
3105 qi.u.allocInfo.FSID = 0;
3106 qi.u.allocInfo.sectorsPerAllocUnit = 1;
3107 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
3108 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
3109 qi.u.allocInfo.bytesPerSector = 1024;
3112 case SMB_INFO_VOLUME:
3114 qi.u.volumeInfo.vsn = 1234; /* Volume serial number */
3115 qi.u.volumeInfo.vnCount = 3; /* Number of characters in label (AFS\0)*/
3117 /* we're supposed to pad it out with zeroes to the end */
3118 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
3119 smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
3121 responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
3124 case SMB_QUERY_FS_VOLUME_INFO:
3125 /* FS volume info */
3126 responseSize = sizeof(qi.u.FSvolumeInfo);
3129 FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
3130 memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
3133 qi.u.FSvolumeInfo.vsn = 1234;
3134 qi.u.FSvolumeInfo.vnCount = 6; /* This is always in Unicode */
3135 memset(&qi.u.FSvolumeInfo.label, 0, sizeof(qi.u.FSvolumeInfo.label));
3136 memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
3139 case SMB_QUERY_FS_SIZE_INFO:
3141 responseSize = sizeof(qi.u.FSsizeInfo);
3143 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
3144 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
3145 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
3146 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
3147 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
3148 qi.u.FSsizeInfo.bytesPerSector = 1024;
3151 case SMB_QUERY_FS_DEVICE_INFO:
3152 /* FS device info */
3153 responseSize = sizeof(qi.u.FSdeviceInfo);
3155 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
3156 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
3159 case SMB_QUERY_FS_ATTRIBUTE_INFO:
3160 /* FS attribute info */
3162 /* attributes, defined in WINNT.H:
3163 * FILE_CASE_SENSITIVE_SEARCH 0x1
3164 * FILE_CASE_PRESERVED_NAMES 0x2
3165 * FILE_UNICODE_ON_DISK 0x4
3166 * FILE_VOLUME_QUOTAS 0x10
3167 * <no name defined> 0x4000
3168 * If bit 0x4000 is not set, Windows 95 thinks
3169 * we can't handle long (non-8.3) names,
3170 * despite our protestations to the contrary.
3172 qi.u.FSattributeInfo.attributes = 0x4003;
3173 /* The maxCompLength is supposed to be in bytes */
3175 qi.u.FSattributeInfo.attributes |= 0x04;
3177 qi.u.FSattributeInfo.maxCompLength = 255;
3178 smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
3179 qi.u.FSattributeInfo.FSnameLength = sz;
3182 sizeof(qi.u.FSattributeInfo.attributes) +
3183 sizeof(qi.u.FSattributeInfo.maxCompLength) +
3184 sizeof(qi.u.FSattributeInfo.FSnameLength) +
3189 case SMB_INFO_UNIX: /* CIFS Unix Info */
3190 case SMB_INFO_MACOS: /* Mac FS Info */
3192 return CM_ERROR_BADOP;
3195 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
3197 /* copy out return data, and set corresponding sizes */
3198 outp->totalParms = 0;
3199 outp->totalData = responseSize;
3200 memcpy(outp->datap, &qi, responseSize);
3202 /* send and free the packets */
3203 smb_SendTran2Packet(vcp, outp, op);
3204 smb_FreeTran2Packet(outp);
3209 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3211 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
3212 return CM_ERROR_BADOP;
3215 struct smb_ShortNameRock {
3216 clientchar_t *maskp;
3218 clientchar_t *shortName;
3219 size_t shortNameLen;
3222 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
3225 struct smb_ShortNameRock *rockp;
3226 normchar_t normName[MAX_PATH];
3227 clientchar_t *shortNameEnd;
3231 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t)) == 0) {
3232 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
3233 osi_LogSaveString(smb_logp, dep->name));
3237 /* compare both names and vnodes, though probably just comparing vnodes
3238 * would be safe enough.
3240 if (cm_NormStrCmpI(normName, rockp->maskp) != 0)
3242 if (ntohl(dep->fid.vnode) != rockp->vnode)
3245 /* This is the entry */
3246 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
3247 rockp->shortNameLen = shortNameEnd - rockp->shortName;
3249 return CM_ERROR_STOPNOW;
3252 long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
3253 clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
3255 struct smb_ShortNameRock rock;
3256 clientchar_t *lastNamep;
3259 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
3263 spacep = cm_GetSpace();
3264 /* smb_StripLastComponent will strip "::$DATA" if present */
3265 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
3267 code = cm_NameI(cm_RootSCachep(userp, reqp), spacep->wdata,
3268 caseFold, userp, tidPathp,
3270 cm_FreeSpace(spacep);
3275 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3276 cm_ReleaseSCache(dscp);
3277 cm_ReleaseUser(userp);
3281 return CM_ERROR_PATH_NOT_COVERED;
3283 #endif /* DFS_SUPPORT */
3285 if (!lastNamep) lastNamep = pathp;
3288 thyper.HighPart = 0;
3289 rock.shortName = shortName;
3291 rock.maskp = lastNamep;
3292 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
3294 cm_ReleaseSCache(dscp);
3297 return CM_ERROR_NOSUCHFILE;
3298 if (code == CM_ERROR_STOPNOW) {
3299 *shortNameLenp = rock.shortNameLen;
3305 /* TRANS2_QUERY_PATH_INFORMATION */
3306 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3308 smb_tran2Packet_t *outp;
3311 unsigned short infoLevel;
3312 smb_tran2QPathInfo_t qpi;
3314 unsigned short attributes;
3315 unsigned long extAttributes;
3316 clientchar_t shortName[13];
3320 cm_scache_t *scp, *dscp;
3321 int scp_rw_held = 0;
3324 clientchar_t *pathp;
3325 clientchar_t *tidPathp;
3326 clientchar_t *lastComp;
3331 infoLevel = p->parmsp[0];
3332 if (infoLevel == SMB_INFO_IS_NAME_VALID)
3334 else if (infoLevel == SMB_INFO_STANDARD)
3335 responseSize = sizeof(qpi.u.QPstandardInfo);
3336 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
3337 responseSize = sizeof(qpi.u.QPeaSizeInfo);
3338 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3339 responseSize = sizeof(qpi.u.QPfileBasicInfo);
3340 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3341 responseSize = sizeof(qpi.u.QPfileStandardInfo);
3342 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3343 responseSize = sizeof(qpi.u.QPfileEaInfo);
3344 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3345 responseSize = sizeof(qpi.u.QPfileNameInfo);
3346 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
3347 responseSize = sizeof(qpi.u.QPfileAllInfo);
3348 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
3349 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
3350 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO)
3351 responseSize = sizeof(qpi.u.QPfileStreamInfo);
3353 osi_Log2(smb_logp, "Bad Tran2QPathInfo op 0x%x infolevel 0x%x",
3354 p->opcode, infoLevel);
3355 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3358 memset(&qpi, 0, sizeof(qpi));
3360 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3361 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path \"%S\"", infoLevel,
3362 osi_LogSaveClientString(smb_logp, pathp));
3364 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3366 if (infoLevel > 0x100)
3367 outp->totalParms = 2;
3369 outp->totalParms = 0;
3371 /* now, if we're at infoLevel 6, we're only being asked to check
3372 * the syntax, so we just OK things now. In particular, we're *not*
3373 * being asked to verify anything about the state of any parent dirs.
3375 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
3376 smb_SendTran2Packet(vcp, outp, opx);
3377 smb_FreeTran2Packet(outp);
3381 userp = smb_GetTran2User(vcp, p);
3383 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
3384 smb_FreeTran2Packet(outp);
3385 return CM_ERROR_BADSMB;
3388 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3390 osi_Log1(smb_logp, "ReceiveTran2QPathInfo tid path lookup failure 0x%x", code);
3391 cm_ReleaseUser(userp);
3392 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
3393 smb_FreeTran2Packet(outp);
3397 osi_Log1(smb_logp, "T2 QPathInfo tidPathp \"%S\"",
3398 osi_LogSaveClientString(smb_logp, tidPathp));
3401 * XXX Strange hack XXX
3403 * As of Patch 7 (13 January 98), we are having the following problem:
3404 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3405 * requests to look up "desktop.ini" in all the subdirectories.
3406 * This can cause zillions of timeouts looking up non-existent cells
3407 * and volumes, especially in the top-level directory.
3409 * We have not found any way to avoid this or work around it except
3410 * to explicitly ignore the requests for mount points that haven't
3411 * yet been evaluated and for directories that haven't yet been
3414 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3415 spacep = cm_GetSpace();
3416 /* smb_StripLastComponent will strip "::$DATA" if present */
3417 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3418 #ifndef SPECIAL_FOLDERS
3419 /* Make sure that lastComp is not NULL */
3421 if (cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
3422 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
3426 userp, tidPathp, &req, &dscp);
3429 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3430 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3432 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3433 code = CM_ERROR_PATH_NOT_COVERED;
3435 code = CM_ERROR_NOSUCHPATH;
3437 #endif /* DFS_SUPPORT */
3438 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3439 code = CM_ERROR_NOSUCHFILE;
3440 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3441 cm_buf_t *bp = buf_Find(dscp, &hzero);
3447 code = CM_ERROR_NOSUCHFILE;
3449 cm_ReleaseSCache(dscp);
3451 cm_FreeSpace(spacep);
3452 cm_ReleaseUser(userp);
3453 smb_SendTran2Error(vcp, p, opx, code);
3454 smb_FreeTran2Packet(outp);
3460 #endif /* SPECIAL_FOLDERS */
3462 cm_FreeSpace(spacep);
3466 code == CM_ERROR_NOSUCHFILE ||
3467 code == CM_ERROR_NOSUCHPATH ||
3468 code == CM_ERROR_BPLUS_NOMATCH) {
3469 /* now do namei and stat, and copy out the info */
3470 code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
3471 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3475 cm_ReleaseUser(userp);
3476 smb_SendTran2Error(vcp, p, opx, code);
3477 smb_FreeTran2Packet(outp);
3482 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3483 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3484 cm_ReleaseSCache(scp);
3485 cm_ReleaseUser(userp);
3486 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3487 code = CM_ERROR_PATH_NOT_COVERED;
3489 code = CM_ERROR_NOSUCHPATH;
3490 smb_SendTran2Error(vcp, p, opx, code);
3491 smb_FreeTran2Packet(outp);
3494 #endif /* DFS_SUPPORT */
3496 lock_ObtainWrite(&scp->rw);
3498 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3499 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3503 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3505 lock_ConvertWToR(&scp->rw);
3510 /* now we have the status in the cache entry, and everything is locked.
3511 * Marshall the output data.
3513 /* for info level 108, figure out short name */
3514 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3515 code = cm_GetShortName(pathp, userp, &req,
3516 tidPathp, scp->fid.vnode, shortName,
3522 smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
3523 qpi.u.QPfileAltNameInfo.fileNameLength = len;
3524 responseSize = sizeof(unsigned long) + len;
3526 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3527 smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3528 qpi.u.QPfileNameInfo.fileNameLength = len;
3529 responseSize = sizeof(unsigned long) + len;
3531 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3532 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3533 qpi.u.QPstandardInfo.creationDateTime = dosTime;
3534 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3535 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3536 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3537 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3538 attributes = smb_Attributes(scp);
3539 qpi.u.QPstandardInfo.attributes = attributes;
3540 qpi.u.QPstandardInfo.eaSize = 0;
3542 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3543 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3544 qpi.u.QPfileBasicInfo.creationTime = ft;
3545 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3546 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3547 qpi.u.QPfileBasicInfo.changeTime = ft;
3548 extAttributes = smb_ExtAttributes(scp);
3549 qpi.u.QPfileBasicInfo.attributes = extAttributes;
3550 qpi.u.QPfileBasicInfo.reserved = 0;
3552 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3555 lock_ReleaseRead(&scp->rw);
3557 fidp = smb_FindFIDByScache(vcp, scp);
3559 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3560 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3561 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3562 qpi.u.QPfileStandardInfo.directory =
3563 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3564 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3565 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3566 qpi.u.QPfileStandardInfo.reserved = 0;
3569 lock_ObtainMutex(&fidp->mx);
3570 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3571 lock_ReleaseMutex(&fidp->mx);
3572 smb_ReleaseFID(fidp);
3574 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3576 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3577 qpi.u.QPfileEaInfo.eaSize = 0;
3579 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3582 lock_ReleaseRead(&scp->rw);
3584 fidp = smb_FindFIDByScache(vcp, scp);
3586 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3587 qpi.u.QPfileAllInfo.creationTime = ft;
3588 qpi.u.QPfileAllInfo.lastAccessTime = ft;
3589 qpi.u.QPfileAllInfo.lastWriteTime = ft;
3590 qpi.u.QPfileAllInfo.changeTime = ft;
3591 extAttributes = smb_ExtAttributes(scp);
3592 qpi.u.QPfileAllInfo.attributes = extAttributes;
3593 qpi.u.QPfileAllInfo.allocationSize = scp->length;
3594 qpi.u.QPfileAllInfo.endOfFile = scp->length;
3595 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3596 qpi.u.QPfileAllInfo.deletePending = 0;
3597 qpi.u.QPfileAllInfo.directory =
3598 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3599 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3600 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3601 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.vnode;
3602 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.unique;
3603 qpi.u.QPfileAllInfo.eaSize = 0;
3604 qpi.u.QPfileAllInfo.accessFlags = 0;
3606 lock_ObtainMutex(&fidp->mx);
3607 if (fidp->flags & SMB_FID_OPENDELETE)
3608 qpi.u.QPfileAllInfo.accessFlags |= DELETE;
3609 if (fidp->flags & SMB_FID_OPENREAD_LISTDIR)
3610 qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_READ|AFS_ACCESS_EXECUTE;
3611 if (fidp->flags & SMB_FID_OPENWRITE)
3612 qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_WRITE;
3613 if (fidp->flags & SMB_FID_DELONCLOSE)
3614 qpi.u.QPfileAllInfo.deletePending = 1;
3615 lock_ReleaseMutex(&fidp->mx);
3616 smb_ReleaseFID(fidp);
3618 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.cell;
3619 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.volume;
3620 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3621 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3622 qpi.u.QPfileAllInfo.mode = 0;
3623 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3625 smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3626 qpi.u.QPfileAllInfo.fileNameLength = len;
3627 responseSize -= (sizeof(qpi.u.QPfileAllInfo.fileName) - len);
3629 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO) {
3631 /* For now we have no streams */
3632 qpi.u.QPfileStreamInfo.nextEntryOffset = 0;
3633 if (scp->fileType == CM_SCACHETYPE_FILE) {
3634 qpi.u.QPfileStreamInfo.streamSize = scp->length;
3635 qpi.u.QPfileStreamInfo.streamAllocationSize = scp->length;
3636 smb_UnparseString(opx, qpi.u.QPfileStreamInfo.fileName, L"::$DATA", &len, SMB_STRF_IGNORENUL);
3637 qpi.u.QPfileStreamInfo.streamNameLength = len;
3638 responseSize -= (sizeof(qpi.u.QPfileStreamInfo.fileName) - len);
3640 qpi.u.QPfileStreamInfo.streamSize.QuadPart = 0;
3641 qpi.u.QPfileStreamInfo.streamAllocationSize.QuadPart = 0;
3642 smb_UnparseString(opx, qpi.u.QPfileStreamInfo.fileName, L"", &len, SMB_STRF_IGNORENUL);
3643 qpi.u.QPfileStreamInfo.streamNameLength = 0;
3647 outp->totalData = responseSize;
3649 /* send and free the packets */
3651 switch (scp_rw_held) {
3653 lock_ReleaseRead(&scp->rw);
3656 lock_ReleaseWrite(&scp->rw);
3660 cm_ReleaseSCache(scp);
3661 cm_ReleaseUser(userp);
3663 memcpy(outp->datap, &qpi, responseSize);
3664 smb_SendTran2Packet(vcp, outp, opx);
3666 smb_SendTran2Error(vcp, p, opx, code);
3668 smb_FreeTran2Packet(outp);
3673 /* TRANS2_SET_PATH_INFORMATION */
3674 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3677 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
3678 return CM_ERROR_BADOP;
3681 unsigned short infoLevel;
3682 clientchar_t * pathp;
3683 smb_tran2Packet_t *outp;
3684 smb_tran2QPathInfo_t *spi;
3686 cm_scache_t *scp, *dscp;
3689 clientchar_t *tidPathp;
3690 clientchar_t *lastComp;
3694 infoLevel = p->parmsp[0];
3695 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
3696 if (infoLevel != SMB_INFO_STANDARD &&
3697 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
3698 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
3699 osi_Log2(smb_logp, "Bad Tran2SetPathInfo op 0x%x infolevel 0x%x",
3700 p->opcode, infoLevel);
3701 smb_SendTran2Error(vcp, p, opx,
3702 infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3706 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3708 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
3709 osi_LogSaveClientString(smb_logp, pathp));
3711 userp = smb_GetTran2User(vcp, p);
3713 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3714 code = CM_ERROR_BADSMB;
3718 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3719 if (code == CM_ERROR_TIDIPC) {
3720 /* Attempt to use a TID allocated for IPC. The client
3721 * is probably looking for DCE RPC end points which we
3722 * don't support OR it could be looking to make a DFS
3725 osi_Log0(smb_logp, "Tran2Open received IPC TID");
3726 cm_ReleaseUser(userp);
3727 return CM_ERROR_NOSUCHPATH;
3731 * XXX Strange hack XXX
3733 * As of Patch 7 (13 January 98), we are having the following problem:
3734 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3735 * requests to look up "desktop.ini" in all the subdirectories.
3736 * This can cause zillions of timeouts looking up non-existent cells
3737 * and volumes, especially in the top-level directory.
3739 * We have not found any way to avoid this or work around it except
3740 * to explicitly ignore the requests for mount points that haven't
3741 * yet been evaluated and for directories that haven't yet been
3744 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3745 spacep = cm_GetSpace();
3746 /* smb_StripLastComponent will strip "::$DATA" if present */
3747 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3748 #ifndef SPECIAL_FOLDERS
3749 /* Make sure that lastComp is not NULL */
3751 if (cm_ClientStrCmpI(lastComp, _C("\\desktop.ini")) == 0) {
3752 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
3756 userp, tidPathp, &req, &dscp);
3759 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3760 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3762 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3763 code = CM_ERROR_PATH_NOT_COVERED;
3765 code = CM_ERROR_NOSUCHPATH;
3767 #endif /* DFS_SUPPORT */
3768 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3769 code = CM_ERROR_NOSUCHFILE;
3770 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3771 cm_buf_t *bp = buf_Find(dscp, &hzero);
3777 code = CM_ERROR_NOSUCHFILE;
3779 cm_ReleaseSCache(dscp);
3781 cm_FreeSpace(spacep);
3782 cm_ReleaseUser(userp);
3783 smb_SendTran2Error(vcp, p, opx, code);
3789 #endif /* SPECIAL_FOLDERS */
3791 cm_FreeSpace(spacep);
3795 code == CM_ERROR_NOSUCHFILE ||
3796 code == CM_ERROR_NOSUCHPATH ||
3797 code == CM_ERROR_BPLUS_NOMATCH) {
3798 /* now do namei and stat, and copy out the info */
3799 code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
3800 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3804 cm_ReleaseUser(userp);
3805 smb_SendTran2Error(vcp, p, opx, code);
3809 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3811 outp->totalParms = 2;
3812 outp->totalData = 0;
3814 spi = (smb_tran2QPathInfo_t *)p->datap;
3815 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3818 /* lock the vnode with a callback; we need the current status
3819 * to determine what the new status is, in some cases.
3821 lock_ObtainWrite(&scp->rw);
3822 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3823 CM_SCACHESYNC_GETSTATUS
3824 | CM_SCACHESYNC_NEEDCALLBACK);
3826 lock_ReleaseWrite(&scp->rw);
3829 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3831 /* prepare for setattr call */
3832 attr.mask = CM_ATTRMASK_LENGTH;
3833 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3834 attr.length.HighPart = 0;
3836 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3837 cm_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3838 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3841 if (spi->u.QPstandardInfo.attributes != 0) {
3842 if ((scp->unixModeBits & 0200)
3843 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3844 /* make a writable file read-only */
3845 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3846 attr.unixModeBits = scp->unixModeBits & ~0222;
3848 else if ((scp->unixModeBits & 0200) == 0
3849 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3850 /* make a read-only file writable */
3851 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3852 attr.unixModeBits = scp->unixModeBits | 0222;
3855 lock_ReleaseRead(&scp->rw);
3859 code = cm_SetAttr(scp, &attr, userp, &req);
3863 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3864 /* we don't support EAs */
3865 code = CM_ERROR_EAS_NOT_SUPPORTED;
3869 cm_ReleaseSCache(scp);
3870 cm_ReleaseUser(userp);
3872 smb_SendTran2Packet(vcp, outp, opx);
3874 smb_SendTran2Error(vcp, p, opx, code);
3875 smb_FreeTran2Packet(outp);
3881 /* TRANS2_QUERY_FILE_INFORMATION */
3882 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3884 smb_tran2Packet_t *outp;
3886 unsigned long attributes;
3887 unsigned short infoLevel;
3894 smb_tran2QFileInfo_t qfi;
3902 fidp = smb_FindFID(vcp, fid, 0);
3905 osi_Log2(smb_logp, "Tran2QFileInfo Unknown SMB Fid vcp 0x%p fid %d",
3907 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3911 lock_ObtainMutex(&fidp->mx);
3912 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3913 lock_ReleaseMutex(&fidp->mx);
3914 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3915 smb_CloseFID(vcp, fidp, NULL, 0);
3916 smb_ReleaseFID(fidp);
3919 lock_ReleaseMutex(&fidp->mx);
3921 infoLevel = p->parmsp[1];
3922 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3923 responseSize = sizeof(qfi.u.QFbasicInfo);
3924 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3925 responseSize = sizeof(qfi.u.QFstandardInfo);
3926 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3927 responseSize = sizeof(qfi.u.QFeaInfo);
3928 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3929 responseSize = sizeof(qfi.u.QFfileNameInfo);
3930 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO)
3931 responseSize = sizeof(qfi.u.QFfileStreamInfo);
3933 osi_Log2(smb_logp, "Bad Tran2QFileInfo op 0x%x infolevel 0x%x",
3934 p->opcode, infoLevel);
3935 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3936 smb_ReleaseFID(fidp);
3939 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3940 memset(&qfi, 0, sizeof(qfi));
3942 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3944 if (infoLevel > 0x100)
3945 outp->totalParms = 2;
3947 outp->totalParms = 0;
3949 userp = smb_GetTran2User(vcp, p);
3951 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3952 code = CM_ERROR_BADSMB;
3956 lock_ObtainMutex(&fidp->mx);
3957 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3959 osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3961 lock_ReleaseMutex(&fidp->mx);
3962 lock_ObtainWrite(&scp->rw);
3963 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3964 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3968 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3970 lock_ConvertWToR(&scp->rw);
3973 /* now we have the status in the cache entry, and everything is locked.
3974 * Marshall the output data.
3976 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3977 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3978 qfi.u.QFbasicInfo.creationTime = ft;
3979 qfi.u.QFbasicInfo.lastAccessTime = ft;
3980 qfi.u.QFbasicInfo.lastWriteTime = ft;
3981 qfi.u.QFbasicInfo.lastChangeTime = ft;
3982 attributes = smb_ExtAttributes(scp);
3983 qfi.u.QFbasicInfo.attributes = attributes;
3985 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3986 qfi.u.QFstandardInfo.allocationSize = scp->length;
3987 qfi.u.QFstandardInfo.endOfFile = scp->length;
3988 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3989 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3990 qfi.u.QFstandardInfo.directory =
3991 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3992 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3993 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3995 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3996 qfi.u.QFeaInfo.eaSize = 0;
3998 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
4002 lock_ReleaseRead(&scp->rw);
4003 lock_ObtainMutex(&fidp->mx);
4004 lock_ObtainRead(&scp->rw);
4005 if (fidp->NTopen_wholepathp)
4006 name = fidp->NTopen_wholepathp;
4008 name = _C("\\"); /* probably can't happen */
4009 lock_ReleaseMutex(&fidp->mx);
4011 smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, SMB_STRF_IGNORENUL);
4012 responseSize = len + 4; /* this is actually what we want to return */
4013 qfi.u.QFfileNameInfo.fileNameLength = len;
4015 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO) {
4018 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
4019 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4020 scp->fileType == CM_SCACHETYPE_INVALID) {
4021 /* Do not return the alternate streams for directories */
4024 /* For now we have no alternate streams */
4025 qfi.u.QFfileStreamInfo.nextEntryOffset = 0;
4026 qfi.u.QFfileStreamInfo.streamSize = scp->length;
4027 qfi.u.QFfileStreamInfo.streamAllocationSize = scp->length;
4028 smb_UnparseString(opx, qfi.u.QFfileStreamInfo.fileName, L"::$DATA", &len, SMB_STRF_IGNORENUL);
4029 qfi.u.QFfileStreamInfo.streamNameLength = len;
4030 responseSize -= (sizeof(qfi.u.QFfileStreamInfo.fileName) - len);
4033 outp->totalData = responseSize;
4035 /* send and free the packets */
4038 lock_ReleaseRead(&scp->rw);
4040 lock_ReleaseWrite(&scp->rw);
4041 cm_ReleaseSCache(scp);
4042 cm_ReleaseUser(userp);
4043 smb_ReleaseFID(fidp);
4045 memcpy(outp->datap, &qfi, responseSize);
4046 smb_SendTran2Packet(vcp, outp, opx);
4048 smb_SendTran2Error(vcp, p, opx, code);
4050 smb_FreeTran2Packet(outp);
4056 /* TRANS2_SET_FILE_INFORMATION */
4057 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4062 unsigned short infoLevel;
4063 smb_tran2Packet_t *outp;
4064 cm_user_t *userp = NULL;
4065 cm_scache_t *scp = NULL;
4071 fidp = smb_FindFID(vcp, fid, 0);
4074 osi_Log2(smb_logp, "Tran2SetFileInfo Unknown SMB Fid vcp 0x%p fid %d",
4076 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
4080 infoLevel = p->parmsp[1];
4081 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
4082 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
4083 osi_Log2(smb_logp, "Bad Tran2SetFileInfo op 0x%x infolevel 0x%x",
4084 p->opcode, infoLevel);
4085 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
4086 smb_ReleaseFID(fidp);
4090 lock_ObtainMutex(&fidp->mx);
4091 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
4092 lock_ReleaseMutex(&fidp->mx);
4093 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
4094 smb_CloseFID(vcp, fidp, NULL, 0);
4095 smb_ReleaseFID(fidp);
4099 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
4100 !(fidp->flags & SMB_FID_OPENDELETE)) {
4101 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
4102 fidp, fidp->scp, fidp->flags);
4103 lock_ReleaseMutex(&fidp->mx);
4104 smb_ReleaseFID(fidp);
4105 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
4108 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
4109 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
4110 && !(fidp->flags & SMB_FID_OPENWRITE)) {
4111 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
4112 fidp, fidp->scp, fidp->flags);
4113 lock_ReleaseMutex(&fidp->mx);
4114 smb_ReleaseFID(fidp);
4115 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
4120 osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
4122 lock_ReleaseMutex(&fidp->mx);
4124 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
4126 outp->totalParms = 2;
4127 outp->totalData = 0;
4129 userp = smb_GetTran2User(vcp, p);
4131 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
4132 code = CM_ERROR_BADSMB;
4136 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
4138 unsigned int attribute;
4140 smb_tran2QFileInfo_t *sfi;
4142 sfi = (smb_tran2QFileInfo_t *)p->datap;
4144 /* lock the vnode with a callback; we need the current status
4145 * to determine what the new status is, in some cases.
4147 lock_ObtainWrite(&scp->rw);
4148 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4149 CM_SCACHESYNC_GETSTATUS
4150 | CM_SCACHESYNC_NEEDCALLBACK);
4152 lock_ReleaseWrite(&scp->rw);
4156 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4158 lock_ReleaseWrite(&scp->rw);
4159 lock_ObtainMutex(&fidp->mx);
4160 lock_ObtainRead(&scp->rw);
4162 /* prepare for setattr call */
4165 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
4166 /* when called as result of move a b, lastMod is (-1, -1).
4167 * If the check for -1 is not present, timestamp
4168 * of the resulting file will be 1969 (-1)
4170 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
4171 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
4172 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4173 cm_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
4174 fidp->flags |= SMB_FID_MTIMESETDONE;
4177 attribute = sfi->u.QFbasicInfo.attributes;
4178 if (attribute != 0) {
4179 if ((scp->unixModeBits & 0200)
4180 && (attribute & SMB_ATTR_READONLY) != 0) {
4181 /* make a writable file read-only */
4182 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4183 attr.unixModeBits = scp->unixModeBits & ~0222;
4185 else if ((scp->unixModeBits & 0200) == 0
4186 && (attribute & SMB_ATTR_READONLY) == 0) {
4187 /* make a read-only file writable */
4188 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4189 attr.unixModeBits = scp->unixModeBits | 0222;
4192 lock_ReleaseRead(&scp->rw);
4193 lock_ReleaseMutex(&fidp->mx);
4197 code = cm_SetAttr(scp, &attr, userp, &req);
4201 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
4202 int delflag = *((char *)(p->datap));
4203 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
4204 delflag, fidp, scp);
4205 if (*((char *)(p->datap))) { /* File is Deleted */
4206 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
4209 lock_ObtainMutex(&fidp->mx);
4210 fidp->flags |= SMB_FID_DELONCLOSE;
4211 lock_ReleaseMutex(&fidp->mx);
4213 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
4219 lock_ObtainMutex(&fidp->mx);
4220 fidp->flags &= ~SMB_FID_DELONCLOSE;
4221 lock_ReleaseMutex(&fidp->mx);
4224 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
4225 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
4226 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
4229 attr.mask = CM_ATTRMASK_LENGTH;
4230 attr.length.LowPart = size.LowPart;
4231 attr.length.HighPart = size.HighPart;
4232 code = cm_SetAttr(scp, &attr, userp, &req);
4236 cm_ReleaseSCache(scp);
4237 cm_ReleaseUser(userp);
4238 smb_ReleaseFID(fidp);
4240 smb_SendTran2Packet(vcp, outp, opx);
4242 smb_SendTran2Error(vcp, p, opx, code);
4243 smb_FreeTran2Packet(outp);
4250 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4252 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
4253 return CM_ERROR_BADOP;
4258 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4260 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
4261 return CM_ERROR_BADOP;
4264 /* TRANS2_FIND_NOTIFY_FIRST */
4266 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4268 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
4269 return CM_ERROR_BADOP;
4272 /* TRANS2_FIND_NOTIFY_NEXT */
4274 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4276 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
4277 return CM_ERROR_BADOP;
4280 /* TRANS2_CREATE_DIRECTORY */
4282 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4284 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
4285 return CM_ERROR_BADOP;
4288 /* TRANS2_SESSION_SETUP */
4290 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4292 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
4293 return CM_ERROR_BADOP;
4296 struct smb_v2_referral {
4298 USHORT ReferralFlags;
4301 USHORT DfsPathOffset;
4302 USHORT DfsAlternativePathOffset;
4303 USHORT NetworkAddressOffset;
4306 /* TRANS2_GET_DFS_REFERRAL */
4308 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
4310 /* This is a UNICODE only request (bit15 of Flags2) */
4311 /* The TID must be IPC$ */
4313 /* The documentation for the Flags response field is contradictory */
4315 /* Use Version 1 Referral Element Format */
4316 /* ServerType = 0; indicates the next server should be queried for the file */
4317 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
4318 /* Node = UnicodeString of UNC path of the next share name */
4321 int maxReferralLevel = 0;
4322 clientchar_t requestFileName[1024] = _C("");
4323 clientchar_t referralPath[1024] = _C("");
4324 smb_tran2Packet_t *outp = 0;
4325 cm_user_t *userp = 0;
4326 cm_scache_t *scp = 0;
4327 cm_scache_t *dscp = 0;
4329 CPINFO CodePageInfo;
4330 int i, nbnLen, reqLen, refLen;
4335 maxReferralLevel = p->parmsp[0];
4337 GetCPInfo(CP_ACP, &CodePageInfo);
4338 cm_Utf16ToClientString(&p->parmsp[1], -1, requestFileName, lengthof(requestFileName));
4340 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%S]",
4341 maxReferralLevel, osi_LogSaveClientString(smb_logp, requestFileName));
4343 nbnLen = (int)cm_ClientStrLen(cm_NetbiosNameC);
4344 reqLen = (int)cm_ClientStrLen(requestFileName);
4346 if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
4347 !cm_ClientStrCmpNI(cm_NetbiosNameC, &requestFileName[1], nbnLen) &&
4348 requestFileName[nbnLen+1] == '\\')
4352 if (!cm_ClientStrCmpNI(_C("all"), &requestFileName[nbnLen+2], 3) ||
4353 !cm_ClientStrCmpNI(_C("*."), &requestFileName[nbnLen+2], 2)) {
4355 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4358 userp = smb_GetTran2User(vcp, p);
4360 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
4361 code = CM_ERROR_BADSMB;
4366 * We have a requested path. Check to see if it is something
4369 * But be careful because the name that we might be searching
4370 * for might be a known name with the final character stripped
4373 code = cm_NameI(cm_RootSCachep(userp, &req), &requestFileName[nbnLen+2],
4374 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
4375 userp, NULL, &req, &scp);
4377 code == CM_ERROR_ALLDOWN ||
4378 code == CM_ERROR_ALLBUSY ||
4379 code == CM_ERROR_ALLOFFLINE ||
4380 code == CM_ERROR_NOSUCHCELL ||
4381 code == CM_ERROR_NOSUCHVOLUME ||
4382 code == CM_ERROR_NOACCESS) {
4385 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4387 } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
4388 clientchar_t temp[1024];
4389 clientchar_t pathName[1024];
4390 clientchar_t *lastComponent;
4392 * we have a msdfs link somewhere in the path
4393 * we should figure out where in the path the link is.
4396 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%S]", requestFileName);
4398 cm_ClientStrCpy(temp, lengthof(temp), &requestFileName[nbnLen+2]);
4402 cm_ReleaseSCache(dscp);
4406 cm_ReleaseSCache(scp);
4409 /* smb_StripLastComponent will strip "::$DATA" if present */
4410 smb_StripLastComponent(pathName, &lastComponent, temp);
4412 code = cm_NameI(cm_RootSCachep(userp, &req), pathName,
4413 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4414 userp, NULL, &req, &dscp);
4416 code = cm_NameI(dscp, ++lastComponent,
4418 userp, NULL, &req, &scp);
4419 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK)
4422 } while (code == CM_ERROR_PATH_NOT_COVERED);
4424 /* scp should now be the DfsLink we are looking for */
4426 /* figure out how much of the input path was used */
4427 reqLen = (int)(nbnLen+2 + cm_ClientStrLen(pathName) + 1 + cm_ClientStrLen(lastComponent));
4429 cm_FsStringToClientString(&scp->mountPointStringp[strlen("msdfs:")], -1,
4430 referralPath, lengthof(referralPath));
4431 refLen = (int)cm_ClientStrLen(referralPath);
4435 clientchar_t shareName[MAX_PATH + 1];
4436 clientchar_t *p, *q;
4437 /* we may have a sharename that is a volume reference */
4439 for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
4445 if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
4446 code = cm_NameI(cm_RootSCachep(userp, &req), _C(""),
4447 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
4448 userp, p, &req, &scp);
4453 cm_ClientStrCpy(referralPath, lengthof(referralPath),
4464 struct smb_v2_referral * v2ref;
4465 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (refLen + 8));
4467 sp = (USHORT *)outp->datap;
4469 sp[idx++] = reqLen; /* path consumed */
4470 sp[idx++] = 1; /* number of referrals */
4471 sp[idx++] = 0x03; /* flags */
4472 #ifdef DFS_VERSION_1
4473 sp[idx++] = 1; /* Version Number */
4474 sp[idx++] = refLen + 4; /* Referral Size */
4475 sp[idx++] = 1; /* Type = SMB Server */
4476 sp[idx++] = 0; /* Do not strip path consumed */
4477 for ( i=0;i<=refLen; i++ )
4478 sp[i+idx] = referralPath[i];
4479 #else /* DFS_VERSION_2 */
4480 sp[idx++] = 2; /* Version Number */
4481 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
4482 idx += (sizeof(struct smb_v2_referral) / 2);
4483 v2ref = (struct smb_v2_referral *) &sp[5];
4484 v2ref->ServerType = 1; /* SMB Server */
4485 v2ref->ReferralFlags = 0x03;
4486 v2ref->Proximity = 0; /* closest */
4487 v2ref->TimeToLive = 3600; /* seconds */
4488 v2ref->DfsPathOffset = idx * 2;
4489 v2ref->DfsAlternativePathOffset = idx * 2;
4490 v2ref->NetworkAddressOffset = 0;
4491 for ( i=0;i<=refLen; i++ )
4492 sp[i+idx] = referralPath[i];
4495 code = CM_ERROR_NOSUCHPATH;
4498 code = CM_ERROR_NOSUCHPATH;
4503 cm_ReleaseSCache(dscp);
4505 cm_ReleaseSCache(scp);
4507 cm_ReleaseUser(userp);
4509 smb_SendTran2Packet(vcp, outp, op);
4511 smb_SendTran2Error(vcp, p, op, code);
4513 smb_FreeTran2Packet(outp);
4516 #else /* DFS_SUPPORT */
4517 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
4518 return CM_ERROR_NOSUCHDEVICE;
4519 #endif /* DFS_SUPPORT */
4522 /* TRANS2_REPORT_DFS_INCONSISTENCY */
4524 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4526 /* This is a UNICODE only request (bit15 of Flags2) */
4528 /* There is nothing we can do about this operation. The client is going to
4529 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
4530 * Unfortunately, there is really nothing we can do about it other then log it
4531 * somewhere. Even then I don't think there is anything for us to do.
4532 * So let's return an error value.
4535 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
4536 return CM_ERROR_BADOP;
4540 smb_ApplyV3DirListPatches(cm_scache_t *dscp, smb_dirListPatch_t **dirPatchespp,
4541 clientchar_t * tidPathp, clientchar_t * relPathp,
4542 int infoLevel, cm_user_t *userp, cm_req_t *reqp)
4546 cm_scache_t *targetScp; /* target if scp is a symlink */
4549 unsigned short attr;
4550 unsigned long lattr;
4551 smb_dirListPatch_t *patchp;
4552 smb_dirListPatch_t *npatchp;
4554 afs_int32 mustFake = 0;
4555 clientchar_t path[AFSPATHMAX];
4557 code = cm_FindACLCache(dscp, userp, &rights);
4559 lock_ObtainWrite(&dscp->rw);
4560 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4561 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4563 cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4564 lock_ReleaseWrite(&dscp->rw);
4565 if (code == CM_ERROR_NOACCESS) {
4573 if (!mustFake) { /* Bulk Stat */
4575 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4577 memset(bsp, 0, sizeof(cm_bulkStat_t));
4579 for (patchp = *dirPatchespp, count=0;
4581 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4582 cm_scache_t *tscp = NULL;
4585 /* Do not look for a cm_scache_t or bulkstat an ioctl entry */
4586 if (patchp->flags & SMB_DIRLISTPATCH_IOCTL)
4589 code = cm_GetSCache(&patchp->fid, &tscp, userp, reqp);
4591 if (lock_TryWrite(&tscp->rw)) {
4592 /* we have an entry that we can look at */
4593 #ifdef AFS_FREELANCE_CLIENT
4594 if (dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID && dscp->fid.volume == AFS_FAKE_ROOT_VOL_ID) {
4595 code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
4596 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4598 cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4600 lock_ReleaseWrite(&tscp->rw);
4601 cm_ReleaseSCache(tscp);
4604 #endif /* AFS_FREELANCE_CLIENT */
4605 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4606 /* we have a callback on it. Don't bother
4607 * fetching this stat entry, since we're happy
4608 * with the info we have.
4610 lock_ReleaseWrite(&tscp->rw);
4611 cm_ReleaseSCache(tscp);
4614 lock_ReleaseWrite(&tscp->rw);
4616 cm_ReleaseSCache(tscp);
4620 bsp->fids[i].Volume = patchp->fid.volume;
4621 bsp->fids[i].Vnode = patchp->fid.vnode;
4622 bsp->fids[i].Unique = patchp->fid.unique;
4624 if (bsp->counter == AFSCBMAX) {
4625 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4626 memset(bsp, 0, sizeof(cm_bulkStat_t));
4630 if (bsp->counter > 0)
4631 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4636 for( patchp = *dirPatchespp;
4638 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4639 cm_ClientStrPrintfN(path, lengthof(path),_C("%s\\%S"),
4640 relPathp ? relPathp : _C(""), patchp->dep->name);
4641 reqp->relPathp = path;
4642 reqp->tidPathp = tidPathp;
4644 if (patchp->flags & SMB_DIRLISTPATCH_IOCTL) {
4645 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4646 errors in the client. */
4647 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4648 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4650 /* 1969-12-31 23:59:59 +00 */
4651 ft.dwHighDateTime = 0x19DB200;
4652 ft.dwLowDateTime = 0x5BB78980;
4654 /* copy to Creation Time */
4655 fa->creationTime = ft;
4656 fa->lastAccessTime = ft;
4657 fa->lastWriteTime = ft;
4658 fa->lastChangeTime = ft;
4659 fa->extFileAttributes = SMB_ATTR_SYSTEM | SMB_ATTR_HIDDEN;
4661 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4663 /* 1969-12-31 23:59:58 +00*/
4664 dosTime = 0xEBBFBF7D;
4666 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4667 fa->lastAccessDateTime = fa->creationDateTime;
4668 fa->lastWriteDateTime = fa->creationDateTime;
4669 fa->attributes = SMB_ATTR_SYSTEM|SMB_ATTR_HIDDEN;
4674 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4675 reqp->relPathp = reqp->tidPathp = NULL;
4679 lock_ObtainWrite(&scp->rw);
4680 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4681 lock_ReleaseWrite(&scp->rw);
4683 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4684 errors in the client. */
4685 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4686 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4688 /* 1969-12-31 23:59:59 +00 */
4689 ft.dwHighDateTime = 0x19DB200;
4690 ft.dwLowDateTime = 0x5BB78980;
4692 /* copy to Creation Time */
4693 fa->creationTime = ft;
4694 fa->lastAccessTime = ft;
4695 fa->lastWriteTime = ft;
4696 fa->lastChangeTime = ft;
4698 switch (scp->fileType) {
4699 case CM_SCACHETYPE_DIRECTORY:
4700 case CM_SCACHETYPE_MOUNTPOINT:
4701 case CM_SCACHETYPE_INVALID:
4702 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4704 case CM_SCACHETYPE_SYMLINK:
4705 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4706 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4708 fa->extFileAttributes = SMB_ATTR_NORMAL;
4711 /* if we get here we either have a normal file
4712 * or we have a file for which we have never
4713 * received status info. In this case, we can
4714 * check the even/odd value of the entry's vnode.
4715 * odd means it is to be treated as a directory
4716 * and even means it is to be treated as a file.
4718 if (mustFake && (scp->fid.vnode & 0x1))
4719 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4721 fa->extFileAttributes = SMB_ATTR_NORMAL;
4723 /* merge in hidden attribute */
4724 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4725 fa->extFileAttributes |= SMB_ATTR_HIDDEN;
4728 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4730 /* 1969-12-31 23:59:58 +00*/
4731 dosTime = 0xEBBFBF7D;
4733 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4734 fa->lastAccessDateTime = fa->creationDateTime;
4735 fa->lastWriteDateTime = fa->creationDateTime;
4737 /* set the attribute */
4738 switch (scp->fileType) {
4739 case CM_SCACHETYPE_DIRECTORY:
4740 case CM_SCACHETYPE_MOUNTPOINT:
4741 case CM_SCACHETYPE_INVALID:
4742 fa->attributes = SMB_ATTR_DIRECTORY;
4744 case CM_SCACHETYPE_SYMLINK:
4745 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4746 fa->attributes = SMB_ATTR_DIRECTORY;
4748 fa->attributes = SMB_ATTR_NORMAL;
4751 /* if we get here we either have a normal file
4752 * or we have a file for which we have never
4753 * received status info. In this case, we can
4754 * check the even/odd value of the entry's vnode.
4755 * even means it is to be treated as a directory
4756 * and odd means it is to be treated as a file.
4758 if (mustFake && (scp->fid.vnode & 0x1))
4759 fa->attributes = SMB_ATTR_DIRECTORY;
4761 fa->attributes = SMB_ATTR_NORMAL;
4764 /* merge in hidden (dot file) attribute */
4765 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4766 fa->attributes |= SMB_ATTR_HIDDEN;
4770 cm_ReleaseSCache(scp);
4774 /* now watch for a symlink */
4776 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
4777 lock_ReleaseWrite(&scp->rw);
4778 cm_ClientStrPrintfN(path, lengthof(path), _C("%s\\%S"),
4779 relPathp ? relPathp : _C(""), patchp->dep->name);
4780 reqp->relPathp = path;
4781 reqp->tidPathp = tidPathp;
4782 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
4783 reqp->relPathp = reqp->tidPathp = NULL;
4785 /* we have a more accurate file to use (the
4786 * target of the symbolic link). Otherwise,
4787 * we'll just use the symlink anyway.
4789 osi_Log2(smb_logp, "symlink vp %x to vp %x",
4791 cm_ReleaseSCache(scp);
4794 lock_ObtainWrite(&scp->rw);
4797 lock_ConvertWToR(&scp->rw);
4799 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4800 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4803 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4805 fa->creationTime = ft;
4806 fa->lastAccessTime = ft;
4807 fa->lastWriteTime = ft;
4808 fa->lastChangeTime = ft;
4810 /* Use length for both file length and alloc length */
4811 fa->endOfFile = scp->length;
4812 fa->allocationSize = scp->length;
4814 /* Copy attributes */
4815 lattr = smb_ExtAttributes(scp);
4816 if ((code == CM_ERROR_NOSUCHPATH &&
4817 (scp->fileType == CM_SCACHETYPE_SYMLINK &&
4818 cm_TargetPerceivedAsDirectory(scp->mountPointStringp))) ||
4819 code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4820 if (lattr == SMB_ATTR_NORMAL)
4821 lattr = SMB_ATTR_DIRECTORY;
4823 lattr |= SMB_ATTR_DIRECTORY;
4825 /* merge in hidden (dot file) attribute */
4826 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4827 if (lattr == SMB_ATTR_NORMAL)
4828 lattr = SMB_ATTR_HIDDEN;
4830 lattr |= SMB_ATTR_HIDDEN;
4833 fa->extFileAttributes = lattr;
4835 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4838 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4840 fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
4841 fa->lastAccessDateTime = fa->creationDateTime;
4842 fa->lastWriteDateTime = fa->creationDateTime;
4844 /* copy out file length and alloc length,
4845 * using the same for both
4847 fa->dataSize = scp->length.LowPart;
4848 fa->allocationSize = scp->length.LowPart;
4850 /* finally copy out attributes as short */
4851 attr = smb_Attributes(scp);
4852 /* merge in hidden (dot file) attribute */
4853 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4854 if (lattr == SMB_ATTR_NORMAL)
4855 lattr = SMB_ATTR_HIDDEN;
4857 lattr |= SMB_ATTR_HIDDEN;
4859 fa->attributes = attr;
4862 lock_ReleaseRead(&scp->rw);
4863 cm_ReleaseSCache(scp);
4866 /* now free the patches */
4867 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4868 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4872 /* and mark the list as empty */
4873 *dirPatchespp = NULL;
4879 /* smb_ReceiveTran2SearchDir implements both
4880 * Tran2_Find_First and Tran2_Find_Next
4882 #define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
4883 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
4884 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
4885 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
4886 #define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
4888 /* this is an optimized handler for T2SearchDir that handles the case
4889 where there are no wildcards in the search path. I.e. an
4890 application is using FindFirst(Ex) to get information about a
4891 single file or directory. It will attempt to do a single lookup.
4892 If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4893 the usual mechanism.
4895 This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4897 TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
4899 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4903 long code = 0, code2 = 0;
4904 clientchar_t *pathp = 0;
4906 smb_dirListPatch_t *dirListPatchesp;
4907 smb_dirListPatch_t *curPatchp;
4908 size_t orbytes; /* # of bytes in this output record */
4909 size_t ohbytes; /* # of bytes, except file name */
4910 size_t onbytes; /* # of bytes in name, incl. term. null */
4911 cm_scache_t *scp = NULL;
4912 cm_scache_t *targetScp = NULL;
4913 cm_user_t *userp = NULL;
4914 char *op; /* output data ptr */
4915 char *origOp; /* original value of op */
4916 cm_space_t *spacep; /* for pathname buffer */
4917 unsigned long maxReturnData; /* max # of return data */
4918 long maxReturnParms; /* max # of return parms */
4919 long bytesInBuffer; /* # data bytes in the output buffer */
4920 clientchar_t *maskp; /* mask part of path */
4924 smb_tran2Packet_t *outp; /* response packet */
4925 clientchar_t *tidPathp = 0;
4927 clientchar_t shortName[13]; /* 8.3 name if needed */
4929 clientchar_t *shortNameEnd;
4930 cm_dirEntry_t * dep = NULL;
4933 void * attrp = NULL;
4934 smb_tran2Find_t * fp;
4935 int afs_ioctl = 0; /* is this query for _._AFS_IOCTL_._? */
4941 osi_assertx(p->opcode == 1, "invalid opcode");
4943 /* find first; obtain basic parameters from request */
4945 /* note that since we are going to failover to regular
4946 * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4947 * modify any of the input parameters here. */
4948 attribute = p->parmsp[0];
4949 maxCount = p->parmsp[1];
4950 infoLevel = p->parmsp[3];
4951 searchFlags = p->parmsp[2];
4952 pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4954 maskp = cm_ClientStrRChr(pathp, '\\');
4958 maskp++; /* skip over backslash */
4959 /* track if this is likely to match a lot of entries */
4961 osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%S], mask[%S]",
4962 osi_LogSaveClientString(smb_logp, pathp),
4963 osi_LogSaveClientString(smb_logp, maskp));
4965 switch ( infoLevel ) {
4966 case SMB_INFO_STANDARD:
4968 ohbytes = sizeof(fp->u.FstandardInfo);
4971 case SMB_INFO_QUERY_EA_SIZE:
4972 ohbytes = sizeof(fp->u.FeaSizeInfo);
4973 s = "InfoQueryEaSize";
4976 case SMB_INFO_QUERY_EAS_FROM_LIST:
4977 ohbytes = sizeof(fp->u.FeasFromListInfo);
4978 s = "InfoQueryEasFromList";
4981 case SMB_FIND_FILE_DIRECTORY_INFO:
4982 s = "FindFileDirectoryInfo";
4983 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4986 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4987 s = "FindFileFullDirectoryInfo";
4988 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4991 case SMB_FIND_FILE_NAMES_INFO:
4992 s = "FindFileNamesInfo";
4993 ohbytes = sizeof(fp->u.FfileNamesInfo);
4996 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4997 s = "FindFileBothDirectoryInfo";
4998 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
5002 s = "unknownInfoLevel";
5006 osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
5009 "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
5010 attribute, infoLevel, maxCount, searchFlags);
5013 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
5014 return CM_ERROR_INVAL;
5017 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5018 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
5020 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5023 dirListPatchesp = NULL;
5025 maxReturnData = p->maxReturnData;
5026 maxReturnParms = 10; /* return params for findfirst, which
5027 is the only one we handle.*/
5029 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
5032 osi_Log2(smb_logp, "T2SDSingle search dir count %d [%S]",
5033 maxCount, osi_LogSaveClientString(smb_logp, pathp));
5035 /* bail out if request looks bad */
5037 smb_FreeTran2Packet(outp);
5038 return CM_ERROR_BADSMB;
5041 userp = smb_GetTran2User(vcp, p);
5043 osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
5044 smb_FreeTran2Packet(outp);
5045 return CM_ERROR_BADSMB;
5048 /* try to get the vnode for the path name next */
5049 spacep = cm_GetSpace();
5050 /* smb_StripLastComponent will strip "::$DATA" if present */
5051 smb_StripLastComponent(spacep->wdata, NULL, pathp);
5052 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
5054 cm_ReleaseUser(userp);
5055 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
5056 smb_FreeTran2Packet(outp);
5060 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
5061 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5062 userp, tidPathp, &req, &scp);
5063 cm_FreeSpace(spacep);
5066 cm_ReleaseUser(userp);
5067 smb_SendTran2Error(vcp, p, opx, code);
5068 smb_FreeTran2Packet(outp);
5072 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
5073 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5074 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
5075 cm_ReleaseSCache(scp);
5076 cm_ReleaseUser(userp);
5077 if ( WANTS_DFS_PATHNAMES(p) || pnc )
5078 code = CM_ERROR_PATH_NOT_COVERED;
5080 code = CM_ERROR_NOSUCHPATH;
5081 smb_SendTran2Error(vcp, p, opx, code);
5082 smb_FreeTran2Packet(outp);
5085 #endif /* DFS_SUPPORT */
5086 osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
5088 afs_ioctl = (cm_ClientStrCmpI(maskp, CM_IOCTL_FILENAME_NOSLASH_W) == 0);
5091 * If we are not searching for _._AFS_IOCTL_._, then we need to obtain
5095 /* now do a single case sensitive lookup for the file in question */
5096 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetScp);
5099 * if a case sensitive match failed, we try a case insensitive
5102 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH)
5103 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetScp);
5105 if (code == 0 && targetScp->fid.vnode == 0) {
5106 cm_ReleaseSCache(targetScp);
5107 code = CM_ERROR_NOSUCHFILE;
5112 * if we can't find the directory entry, this block will
5113 * return CM_ERROR_NOSUCHFILE, which we will pass on to
5114 * smb_ReceiveTran2SearchDir().
5116 cm_ReleaseSCache(scp);
5117 cm_ReleaseUser(userp);
5118 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5119 smb_SendTran2Error(vcp, p, opx, code);
5122 smb_FreeTran2Packet(outp);
5127 /* now that we have the target in sight, we proceed with filling
5128 up the return data. */
5130 op = origOp = outp->datap;
5133 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
5134 /* skip over resume key */
5138 fp = (smb_tran2Find_t *) op;
5140 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
5141 && !cm_Is8Dot3(maskp)) {
5144 * Since the _._AFS_IOCTL_._ file does not actually exist
5145 * we will make up a per directory FID equivalent to the
5146 * directory vnode and the uniqifier 0.
5149 dfid.vnode = htonl(scp->fid.vnode);
5150 dfid.unique = htonl(0);
5152 dfid.vnode = htonl(targetScp->fid.vnode);
5153 dfid.unique = htonl(targetScp->fid.unique);
5156 cm_Gen8Dot3NameIntW(maskp, &dfid, shortName, &shortNameEnd);
5162 osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %S (%S)",
5165 osi_LogSaveClientString(smb_logp, pathp),
5166 (NeedShortName)? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
5168 /* Eliminate entries that don't match requested attributes */
5169 if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
5170 smb_IsDotFile(maskp)) {
5172 code = CM_ERROR_NOSUCHFILE;
5173 osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
5178 if (!(attribute & SMB_ATTR_DIRECTORY) &&
5180 (targetScp->fileType == CM_SCACHETYPE_DIRECTORY ||
5181 targetScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
5182 targetScp->fileType == CM_SCACHETYPE_DFSLINK ||
5183 targetScp->fileType == CM_SCACHETYPE_INVALID)) {
5185 code = CM_ERROR_NOSUCHFILE;
5186 osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
5191 /* add header to name & term. null */
5193 smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5194 orbytes = ohbytes + onbytes;
5196 /* now, we round up the record to a 4 byte alignment, and we make
5197 * sure that we have enough room here for even the aligned version
5198 * (so we don't have to worry about an * overflow when we pad
5199 * things out below). That's the reason for the alignment
5202 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5203 align = (4 - (orbytes & 3)) & 3;
5207 if (orbytes + align > maxReturnData) {
5209 /* even though this request is unlikely to succeed with a
5210 failover, we do it anyway. */
5211 code = CM_ERROR_NOSUCHFILE;
5212 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5217 /* this is one of the entries to use: it is not deleted and it
5218 * matches the star pattern we're looking for. Put out the name,
5219 * preceded by its length.
5221 /* First zero everything else */
5222 memset(origOp, 0, orbytes);
5225 smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5227 switch (infoLevel) {
5228 case SMB_INFO_STANDARD:
5229 fp->u.FstandardInfo.fileNameLength = onbytes;
5230 attrp = &fp->u.FstandardInfo.fileAttrs;
5233 case SMB_INFO_QUERY_EA_SIZE:
5234 fp->u.FeaSizeInfo.fileNameLength = onbytes;
5235 attrp = &fp->u.FeaSizeInfo.fileAttrs;
5236 fp->u.FeaSizeInfo.eaSize = 0;
5239 case SMB_INFO_QUERY_EAS_FROM_LIST:
5240 fp->u.FeasFromListInfo.fileNameLength = onbytes;
5241 attrp = &fp->u.FeasFromListInfo.fileAttrs;
5242 fp->u.FeasFromListInfo.eaSize = 0;
5245 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5246 if (NeedShortName) {
5250 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
5251 fp->u.FfileBothDirectoryInfo.shortName,
5252 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
5254 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
5256 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5257 fp->u.FfileBothDirectoryInfo.reserved = 0;
5259 strcpy(fp->u.FfileBothDirectoryInfo.shortName,
5261 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
5266 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5267 fp->u.FfileFullDirectoryInfo.eaSize = 0;
5270 case SMB_FIND_FILE_DIRECTORY_INFO:
5271 fp->u.FfileDirectoryInfo.nextEntryOffset = 0;
5272 fp->u.FfileDirectoryInfo.fileIndex = 0;
5273 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5274 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5277 case SMB_FIND_FILE_NAMES_INFO:
5278 fp->u.FfileNamesInfo.nextEntryOffset = 0;
5279 fp->u.FfileNamesInfo.fileIndex = 0;
5280 fp->u.FfileNamesInfo.fileNameLength = onbytes;
5284 /* we shouldn't hit this case */
5285 osi_assertx(FALSE, "Unknown query type");
5288 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5289 osi_assert(attrp != NULL);
5291 curPatchp = malloc(sizeof(*curPatchp));
5292 osi_QAdd((osi_queue_t **) &dirListPatchesp,
5294 curPatchp->dptr = attrp;
5296 if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
5297 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5299 curPatchp->flags = 0;
5304 int namelen = cm_ClientStringToFsString(maskp, -1, NULL, 0);
5305 dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+namelen);
5306 cm_ClientStringToFsString(maskp, -1, dep->name, namelen);
5310 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, scp->fid.vnode, 0);
5311 dep->fid.vnode = scp->fid.vnode;
5312 dep->fid.unique = 0;
5313 curPatchp->flags |= SMB_DIRLISTPATCH_IOCTL;
5315 cm_SetFid(&curPatchp->fid, targetScp->fid.cell, targetScp->fid.volume, targetScp->fid.vnode, targetScp->fid.unique);
5316 dep->fid.vnode = targetScp->fid.vnode;
5317 dep->fid.unique = targetScp->fid.unique;
5320 curPatchp->dep = dep;
5323 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
5324 /* put out resume key */
5325 *((u_long *)origOp) = 0;
5328 /* Adjust byte ptr and count */
5329 origOp += orbytes; /* skip entire record */
5330 bytesInBuffer += orbytes;
5332 /* and pad the record out */
5333 while (--align >= 0) {
5338 /* apply the patches */
5339 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->wdata, infoLevel, userp, &req);
5341 outp->parmsp[0] = 0;
5342 outp->parmsp[1] = 1; /* number of names returned */
5343 outp->parmsp[2] = 1; /* end of search */
5344 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5345 outp->parmsp[4] = 0;
5347 outp->totalParms = 10; /* in bytes */
5349 outp->totalData = bytesInBuffer;
5351 osi_Log0(smb_logp, "T2SDSingle done.");
5353 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5355 smb_SendTran2Error(vcp, p, opx, code);
5357 smb_SendTran2Packet(vcp, outp, opx);
5362 smb_FreeTran2Packet(outp);
5366 cm_ReleaseSCache(scp);
5368 cm_ReleaseSCache(targetScp);
5369 cm_ReleaseUser(userp);
5375 /* TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2 */
5376 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
5381 long code = 0, code2 = 0;
5382 clientchar_t *pathp;
5383 cm_dirEntry_t *dep = 0;
5385 smb_dirListPatch_t *dirListPatchesp = 0;
5386 smb_dirListPatch_t *curPatchp = 0;
5389 size_t orbytes; /* # of bytes in this output record */
5390 size_t ohbytes; /* # of bytes, except file name */
5391 size_t onbytes; /* # of bytes in name, incl. term. null */
5392 osi_hyper_t dirLength;
5393 osi_hyper_t bufferOffset;
5394 osi_hyper_t curOffset;
5396 smb_dirSearch_t *dsp;
5400 cm_pageHeader_t *pageHeaderp;
5401 cm_user_t *userp = NULL;
5404 long nextEntryCookie;
5405 int numDirChunks; /* # of 32 byte dir chunks in this entry */
5406 char *op; /* output data ptr */
5407 char *origOp; /* original value of op */
5408 cm_space_t *spacep; /* for pathname buffer */
5409 unsigned long maxReturnData; /* max # of return data */
5410 unsigned long maxReturnParms; /* max # of return parms */
5411 long bytesInBuffer; /* # data bytes in the output buffer */
5413 clientchar_t *maskp; /* mask part of path */
5417 smb_tran2Packet_t *outp; /* response packet */
5418 clientchar_t *tidPathp;
5420 clientchar_t shortName[13]; /* 8.3 name if needed */
5423 clientchar_t *shortNameEnd;
5429 smb_tran2Find_t * fp;
5434 if (p->opcode == 1) {
5435 /* find first; obtain basic parameters from request */
5436 attribute = p->parmsp[0];
5437 maxCount = p->parmsp[1];
5438 infoLevel = p->parmsp[3];
5439 searchFlags = p->parmsp[2];
5440 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
5442 maskp = cm_ClientStrRChr(pathp, '\\');
5446 maskp++; /* skip over backslash */
5448 /* track if this is likely to match a lot of entries */
5449 starPattern = smb_V3IsStarMask(maskp);
5451 #ifndef NOFINDFIRSTOPTIMIZE
5453 /* if this is for a single directory or file, we let the
5454 optimized routine handle it. The only error it
5455 returns is CM_ERROR_NOSUCHFILE. The */
5456 code = smb_T2SearchDirSingle(vcp, p, opx);
5458 /* we only failover if we see a CM_ERROR_NOSUCHFILE */
5459 if (code != CM_ERROR_NOSUCHFILE) {
5461 /* unless we are using the BPlusTree */
5462 if (code == CM_ERROR_BPLUS_NOMATCH)
5463 code = CM_ERROR_NOSUCHFILE;
5464 #endif /* USE_BPLUS */
5468 #endif /* NOFINDFIRSTOPTIMIZE */
5471 dsp = smb_NewDirSearch(1);
5472 dsp->attribute = attribute;
5473 cm_ClientStrCpy(dsp->mask, lengthof(dsp->mask), maskp); /* and save mask */
5476 osi_assertx(p->opcode == 2, "invalid opcode");
5477 /* find next; obtain basic parameters from request or open dir file */
5478 dsp = smb_FindDirSearch(p->parmsp[0]);
5479 maxCount = p->parmsp[1];
5480 infoLevel = p->parmsp[2];
5481 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
5482 searchFlags = p->parmsp[5];
5484 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
5485 p->parmsp[0], nextCookie);
5486 return CM_ERROR_BADFD;
5488 attribute = dsp->attribute;
5491 starPattern = 1; /* assume, since required a Find Next */
5494 switch ( infoLevel ) {
5495 case SMB_INFO_STANDARD:
5497 ohbytes = sizeof(fp->u.FstandardInfo);
5500 case SMB_INFO_QUERY_EA_SIZE:
5501 ohbytes = sizeof(fp->u.FeaSizeInfo);
5502 s = "InfoQueryEaSize";
5505 case SMB_INFO_QUERY_EAS_FROM_LIST:
5506 ohbytes = sizeof(fp->u.FeasFromListInfo);
5507 s = "InfoQueryEasFromList";
5510 case SMB_FIND_FILE_DIRECTORY_INFO:
5511 s = "FindFileDirectoryInfo";
5512 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
5515 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5516 s = "FindFileFullDirectoryInfo";
5517 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
5520 case SMB_FIND_FILE_NAMES_INFO:
5521 s = "FindFileNamesInfo";
5522 ohbytes = sizeof(fp->u.FfileNamesInfo);
5525 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5526 s = "FindFileBothDirectoryInfo";
5527 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
5531 s = "unknownInfoLevel";
5535 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
5538 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
5539 attribute, infoLevel, maxCount, searchFlags);
5541 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
5542 p->opcode, dsp->cookie, nextCookie);
5545 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
5546 smb_ReleaseDirSearch(dsp);
5547 return CM_ERROR_INVAL;
5550 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5551 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
5553 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5556 dirListPatchesp = NULL;
5558 maxReturnData = p->maxReturnData;
5559 if (p->opcode == 1) /* find first */
5560 maxReturnParms = 10; /* bytes */
5562 maxReturnParms = 8; /* bytes */
5564 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
5570 osi_Log2(smb_logp, "T2 receive search dir count %d [%S]",
5571 maxCount, osi_LogSaveClientString(smb_logp, pathp));
5573 /* bail out if request looks bad */
5574 if (p->opcode == 1 && !pathp) {
5575 smb_ReleaseDirSearch(dsp);
5576 smb_FreeTran2Packet(outp);
5577 return CM_ERROR_BADSMB;
5580 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
5581 dsp->cookie, nextCookie, attribute);
5583 userp = smb_GetTran2User(vcp, p);
5585 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
5586 smb_ReleaseDirSearch(dsp);
5587 smb_FreeTran2Packet(outp);
5588 return CM_ERROR_BADSMB;
5591 /* try to get the vnode for the path name next */
5592 lock_ObtainMutex(&dsp->mx);
5595 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5599 spacep = cm_GetSpace();
5600 /* smb_StripLastComponent will strip "::$DATA" if present */
5601 smb_StripLastComponent(spacep->wdata, NULL, pathp);
5602 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
5604 cm_ReleaseUser(userp);
5605 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
5606 smb_FreeTran2Packet(outp);
5607 lock_ReleaseMutex(&dsp->mx);
5608 smb_DeleteDirSearch(dsp);
5609 smb_ReleaseDirSearch(dsp);
5613 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
5614 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
5616 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
5617 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5618 userp, tidPathp, &req, &scp);
5619 cm_FreeSpace(spacep);
5622 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
5623 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5624 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
5625 cm_ReleaseSCache(scp);
5626 cm_ReleaseUser(userp);
5627 if ( WANTS_DFS_PATHNAMES(p) || pnc )
5628 code = CM_ERROR_PATH_NOT_COVERED;
5630 code = CM_ERROR_NOSUCHPATH;
5631 smb_SendTran2Error(vcp, p, opx, code);
5632 smb_FreeTran2Packet(outp);
5633 lock_ReleaseMutex(&dsp->mx);
5634 smb_DeleteDirSearch(dsp);
5635 smb_ReleaseDirSearch(dsp);
5638 #endif /* DFS_SUPPORT */
5640 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5641 /* we need one hold for the entry we just stored into,
5642 * and one for our own processing. When we're done
5643 * with this function, we'll drop the one for our own
5644 * processing. We held it once from the namei call,
5645 * and so we do another hold now.
5648 dsp->flags |= SMB_DIRSEARCH_BULKST;
5651 lock_ReleaseMutex(&dsp->mx);
5653 cm_ReleaseUser(userp);
5654 smb_FreeTran2Packet(outp);
5655 smb_DeleteDirSearch(dsp);
5656 smb_ReleaseDirSearch(dsp);
5660 /* get the directory size */
5661 lock_ObtainWrite(&scp->rw);
5662 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5663 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5665 lock_ReleaseWrite(&scp->rw);
5666 cm_ReleaseSCache(scp);
5667 cm_ReleaseUser(userp);
5668 smb_FreeTran2Packet(outp);
5669 smb_DeleteDirSearch(dsp);
5670 smb_ReleaseDirSearch(dsp);
5674 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5677 dirLength = scp->length;
5679 bufferOffset.LowPart = bufferOffset.HighPart = 0;
5680 curOffset.HighPart = 0;
5681 curOffset.LowPart = nextCookie;
5682 origOp = outp->datap;
5689 normchar_t normName[MAX_PATH]; /* Normalized name */
5690 clientchar_t cfileName[MAX_PATH]; /* Non-normalized name */
5693 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5694 /* skip over resume key */
5697 fp = (smb_tran2Find_t *) op;
5699 /* make sure that curOffset.LowPart doesn't point to the first
5700 * 32 bytes in the 2nd through last dir page, and that it doesn't
5701 * point at the first 13 32-byte chunks in the first dir page,
5702 * since those are dir and page headers, and don't contain useful
5705 temp = curOffset.LowPart & (2048-1);
5706 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5707 /* we're in the first page */
5708 if (temp < 13*32) temp = 13*32;
5711 /* we're in a later dir page */
5712 if (temp < 32) temp = 32;
5715 /* make sure the low order 5 bits are zero */
5718 /* now put temp bits back ito curOffset.LowPart */
5719 curOffset.LowPart &= ~(2048-1);
5720 curOffset.LowPart |= temp;
5722 /* check if we've passed the dir's EOF */
5723 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
5724 osi_Log0(smb_logp, "T2 search dir passed eof");
5729 /* check if we've returned all the names that will fit in the
5730 * response packet; we check return count as well as the number
5731 * of bytes requested. We check the # of bytes after we find
5732 * the dir entry, since we'll need to check its size.
5734 if (returnedNames >= maxCount) {
5735 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
5736 returnedNames, maxCount);
5740 /* when we have obtained as many entries as can be processed in
5741 * a single Bulk Status call to the file server, apply the dir listing
5744 if (returnedNames > 0 && returnedNames % AFSCBMAX == 0) {
5745 lock_ReleaseWrite(&scp->rw);
5746 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5747 dsp->relPath, infoLevel, userp, &req);
5748 lock_ObtainWrite(&scp->rw);
5750 /* Then check to see if we have time left to process more entries */
5751 if (GetTickCount() - req.startTime > (RDRtimeout - 15) * 1000) {
5752 osi_Log0(smb_logp, "T2 search dir RDRtimeout exceeded");
5756 /* see if we can use the bufferp we have now; compute in which
5757 * page the current offset would be, and check whether that's
5758 * the offset of the buffer we have. If not, get the buffer.
5760 thyper.HighPart = curOffset.HighPart;
5761 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5762 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5765 buf_Release(bufferp);
5768 lock_ReleaseWrite(&scp->rw);
5769 code = buf_Get(scp, &thyper, &req, &bufferp);
5770 lock_ObtainWrite(&scp->rw);
5772 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
5776 bufferOffset = thyper;
5778 /* now get the data in the cache */
5780 code = cm_SyncOp(scp, bufferp, userp, &req,
5782 CM_SCACHESYNC_NEEDCALLBACK
5783 | CM_SCACHESYNC_READ);
5785 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5789 if (cm_HaveBuffer(scp, bufferp, 0)) {
5790 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5791 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5795 /* otherwise, load the buffer and try again */
5796 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5798 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5800 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5801 scp, bufferp, code);
5806 buf_Release(bufferp);
5810 } /* if (wrong buffer) ... */
5812 /* now we have the buffer containing the entry we're interested
5813 * in; copy it out if it represents a non-deleted entry.
5815 entryInDir = curOffset.LowPart & (2048-1);
5816 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5818 /* page header will help tell us which entries are free. Page
5819 * header can change more often than once per buffer, since
5820 * AFS 3 dir page size may be less than (but not more than)
5821 * a buffer package buffer.
5823 /* only look intra-buffer */
5824 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5825 temp &= ~(2048 - 1); /* turn off intra-page bits */
5826 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5828 /* now determine which entry we're looking at in the page.
5829 * If it is free (there's a free bitmap at the start of the
5830 * dir), we should skip these 32 bytes.
5832 slotInPage = (entryInDir & 0x7e0) >> 5;
5833 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5834 (1 << (slotInPage & 0x7)))) {
5835 /* this entry is free */
5836 numDirChunks = 1; /* only skip this guy */
5840 tp = bufferp->datap + entryInBuffer;
5841 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5843 /* while we're here, compute the next entry's location, too,
5844 * since we'll need it when writing out the cookie into the dir
5847 * XXXX Probably should do more sanity checking.
5849 numDirChunks = cm_NameEntries(dep->name, &onbytes);
5851 /* compute offset of cookie representing next entry */
5852 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5854 if (dep->fid.vnode == 0)
5855 goto nextEntry; /* This entry is not in use */
5857 if (cm_FsStringToClientString(dep->name, -1, cfileName, lengthof(cfileName)) == 0 ||
5858 cm_ClientStringToNormString(cfileName, -1, normName, lengthof(normName)) == 0) {
5860 osi_Log1(smb_logp, "Skipping entry [%s]. Can't convert or normalize FS String",
5861 osi_LogSaveString(smb_logp, dep->name));
5865 /* Need 8.3 name? */
5867 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
5868 !cm_Is8Dot3(cfileName)) {
5869 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5873 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %S (%S)",
5874 dep->fid.vnode, dep->fid.unique,
5875 osi_LogSaveClientString(smb_logp, cfileName),
5876 NeedShortName ? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
5878 /* When matching, we are using doing a case fold if we have a wildcard mask.
5879 * If we get a non-wildcard match, it's a lookup for a specific file.
5881 if (cm_MatchMask(normName, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5882 (NeedShortName && cm_MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))
5884 /* Eliminate entries that don't match requested attributes */
5885 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5886 smb_IsDotFile(cfileName)) {
5887 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5888 goto nextEntry; /* no hidden files */
5891 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5893 /* We have already done the cm_TryBulkStat above */
5894 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume,
5895 ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5896 fileType = cm_FindFileType(&fid);
5897 /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5898 * "has filetype %d", dep->name, fileType);
5900 if ( fileType == CM_SCACHETYPE_DIRECTORY ||
5901 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5902 fileType == CM_SCACHETYPE_DFSLINK ||
5903 fileType == CM_SCACHETYPE_INVALID)
5904 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5908 /* finally check if this name will fit */
5910 smb_UnparseString(opx, NULL, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5911 orbytes = ohbytes + onbytes;
5913 /* now, we round up the record to a 4 byte alignment,
5914 * and we make sure that we have enough room here for
5915 * even the aligned version (so we don't have to worry
5916 * about an overflow when we pad things out below).
5917 * That's the reason for the alignment arithmetic below.
5919 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5920 align = (4 - (orbytes & 3)) & 3;
5924 if (orbytes + bytesInBuffer + align > maxReturnData) {
5925 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5930 /* this is one of the entries to use: it is not deleted
5931 * and it matches the star pattern we're looking for.
5932 * Put out the name, preceded by its length.
5934 /* First zero everything else */
5935 memset(origOp, 0, orbytes);
5938 smb_UnparseString(opx, origOp + ohbytes, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5940 switch (infoLevel) {
5941 case SMB_INFO_STANDARD:
5942 fp->u.FstandardInfo.fileNameLength = onbytes;
5943 attrp = &fp->u.FstandardInfo.fileAttrs;
5946 case SMB_INFO_QUERY_EA_SIZE:
5947 fp->u.FeaSizeInfo.fileNameLength = onbytes;
5948 attrp = &fp->u.FeaSizeInfo.fileAttrs;
5949 fp->u.FeaSizeInfo.eaSize = 0;
5952 case SMB_INFO_QUERY_EAS_FROM_LIST:
5953 fp->u.FeasFromListInfo.fileNameLength = onbytes;
5954 attrp = &fp->u.FeasFromListInfo.fileAttrs;
5955 fp->u.FeasFromListInfo.eaSize = 0;
5958 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5959 if (NeedShortName) {
5963 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
5964 fp->u.FfileBothDirectoryInfo.shortName,
5965 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
5967 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
5969 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5970 fp->u.FfileBothDirectoryInfo.reserved = 0;
5972 cm_ClientStrCpy(fp->u.FfileBothDirectoryInfo.shortName,
5973 lengthof(fp->u.FfileBothDirectoryInfo.shortName),
5975 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
5980 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5981 fp->u.FfileFullDirectoryInfo.eaSize = 0;
5984 case SMB_FIND_FILE_DIRECTORY_INFO:
5985 fp->u.FfileDirectoryInfo.nextEntryOffset = orbytes + align;
5986 fp->u.FfileDirectoryInfo.fileIndex = nextEntryCookie;
5987 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5988 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5991 case SMB_FIND_FILE_NAMES_INFO:
5992 fp->u.FfileNamesInfo.nextEntryOffset = orbytes + align;
5993 fp->u.FfileNamesInfo.fileIndex = nextEntryCookie;
5994 fp->u.FfileNamesInfo.fileNameLength = onbytes;
5999 /* we shouldn't hit this case */
6000 osi_assertx(FALSE, "Unknown query type");
6003 /* now, adjust the # of entries copied */
6006 /* now we emit the attribute. This is tricky, since
6007 * we need to really stat the file to find out what
6008 * type of entry we've got. Right now, we're copying
6009 * out data from a buffer, while holding the scp
6010 * locked, so it isn't really convenient to stat
6011 * something now. We'll put in a place holder
6012 * now, and make a second pass before returning this
6013 * to get the real attributes. So, we just skip the
6014 * data for now, and adjust it later. We allocate a
6015 * patch record to make it easy to find this point
6016 * later. The replay will happen at a time when it is
6017 * safe to unlock the directory.
6019 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
6020 osi_assert(attrp != NULL);
6021 curPatchp = malloc(sizeof(*curPatchp));
6022 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
6023 curPatchp->dptr = attrp;
6025 if (smb_hideDotFiles && smb_IsDotFile(cfileName)) {
6026 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
6028 curPatchp->flags = 0;
6031 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
6034 curPatchp->dep = dep;
6037 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
6038 /* put out resume key */
6039 *((u_long *)origOp) = nextEntryCookie;
6041 /* Adjust byte ptr and count */
6042 origOp += orbytes; /* skip entire record */
6043 bytesInBuffer += orbytes;
6045 /* and pad the record out */
6046 while (align-- > 0) {
6050 } /* if we're including this name */
6051 else if (!starPattern &&
6053 cm_MatchMask(normName, maskp, CM_FLAG_CASEFOLD)) {
6054 /* We were looking for exact matches, but here's an inexact one*/
6059 /* and adjust curOffset to be where the new cookie is */
6060 thyper.HighPart = 0;
6061 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
6062 curOffset = LargeIntegerAdd(thyper, curOffset);
6063 } /* while copying data for dir listing */
6065 /* If we didn't get a star pattern, we did an exact match during the first pass.
6066 * If there were no exact matches found, we fail over to inexact matches by
6067 * marking the query as a star pattern (matches all case permutations), and
6068 * re-running the query.
6070 if (returnedNames == 0 && !starPattern && foundInexact) {
6071 osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
6076 /* release the mutex */
6077 lock_ReleaseWrite(&scp->rw);
6079 buf_Release(bufferp);
6084 * Finally, process whatever entries we have left.
6086 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
6087 dsp->relPath, infoLevel, userp, &req);
6089 /* now put out the final parameters */
6090 if (returnedNames == 0)
6092 if (p->opcode == 1) {
6094 outp->parmsp[0] = (unsigned short) dsp->cookie;
6095 outp->parmsp[1] = returnedNames;
6096 outp->parmsp[2] = eos;
6097 outp->parmsp[3] = 0; /* nothing wrong with EAS */
6098 outp->parmsp[4] = 0;
6099 /* don't need last name to continue
6100 * search, cookie is enough. Normally,
6101 * this is the offset of the file name
6102 * of the last entry returned.
6104 outp->totalParms = 10; /* in bytes */
6108 outp->parmsp[0] = returnedNames;
6109 outp->parmsp[1] = eos;
6110 outp->parmsp[2] = 0; /* EAS error */
6111 outp->parmsp[3] = 0; /* last name, as above */
6112 outp->totalParms = 8; /* in bytes */
6115 /* return # of bytes in the buffer */
6116 outp->totalData = bytesInBuffer;
6118 /* Return error code if unsuccessful on first request */
6119 if (code == 0 && p->opcode == 1 && returnedNames == 0)
6120 code = CM_ERROR_NOSUCHFILE;
6122 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
6123 p->opcode, dsp->cookie, returnedNames, code);
6125 /* if we're supposed to close the search after this request, or if
6126 * we're supposed to close the search if we're done, and we're done,
6127 * or if something went wrong, close the search.
6129 if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
6130 (returnedNames == 0) ||
6131 ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
6133 smb_DeleteDirSearch(dsp);
6136 smb_SendTran2Error(vcp, p, opx, code);
6138 smb_SendTran2Packet(vcp, outp, opx);
6140 smb_FreeTran2Packet(outp);
6141 smb_ReleaseDirSearch(dsp);
6142 cm_ReleaseSCache(scp);
6143 cm_ReleaseUser(userp);
6147 /* SMB_COM_FIND_CLOSE2 */
6148 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6151 smb_dirSearch_t *dsp;
6153 dirHandle = smb_GetSMBParm(inp, 0);
6155 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
6157 dsp = smb_FindDirSearch(dirHandle);
6160 return CM_ERROR_BADFD;
6162 /* otherwise, we have an FD to destroy */
6163 smb_DeleteDirSearch(dsp);
6164 smb_ReleaseDirSearch(dsp);
6166 /* and return results */
6167 smb_SetSMBDataLength(outp, 0);
6173 /* SMB_COM_FIND_NOTIFY_CLOSE */
6174 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6176 smb_SetSMBDataLength(outp, 0);
6180 /* SMB_COM_OPEN_ANDX */
6181 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6183 clientchar_t *pathp;
6188 cm_scache_t *dscp; /* dir we're dealing with */
6189 cm_scache_t *scp; /* file we're creating */
6193 clientchar_t *lastNamep;
6194 unsigned long dosTime;
6200 int parmSlot; /* which parm we're dealing with */
6201 clientchar_t *tidPathp;
6204 BOOL is_rpc = FALSE;
6205 BOOL is_ipc = FALSE;
6211 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
6212 openFun = smb_GetSMBParm(inp, 8); /* open function */
6213 excl = ((openFun & 3) == 0);
6214 trunc = ((openFun & 3) == 2); /* truncate it */
6215 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
6216 openAction = 0; /* tracks what we did */
6218 attributes = smb_GetSMBParm(inp, 5);
6219 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
6221 pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
6224 return CM_ERROR_BADSMB;
6226 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6228 if (code == CM_ERROR_TIDIPC) {
6231 return CM_ERROR_NOSUCHPATH;
6235 spacep = inp->spacep;
6236 /* smb_StripLastComponent will strip "::$DATA" if present */
6237 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6241 /* special case magic file name for receiving IOCTL requests
6242 * (since IOCTL calls themselves aren't getting through).
6244 (cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
6246 /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional) */
6247 (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
6249 unsigned short file_type = 0;
6250 unsigned short device_state = 0;
6252 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6254 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
6255 osi_Log1(smb_logp, "OpenAndX Setting up RPC on fid[%d]", fidp->fid);
6257 osi_Log1(smb_logp, "smb_SetupRPCFid failure code [%d]", code);
6258 smb_ReleaseFID(fidp);
6262 smb_SetupIoctlFid(fidp, spacep);
6263 osi_Log1(smb_logp, "OpenAndX Setting up IOCTL on fid[%d]", fidp->fid);
6266 /* set inp->fid so that later read calls in same msg can find fid */
6267 inp->fid = fidp->fid;
6269 /* copy out remainder of the parms */
6271 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6273 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
6274 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
6275 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6276 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
6277 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
6278 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
6279 smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++;
6280 smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++;
6282 /* and the final "always present" stuff */
6283 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
6284 /* next write out the "unique" ID */
6285 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
6286 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
6287 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6288 smb_SetSMBDataLength(outp, 0);
6290 /* and clean up fid reference */
6291 smb_ReleaseFID(fidp);
6297 osi_Log0(smb_logp, "NTOpenX rejecting IPC TID");
6298 return CM_ERROR_BADFD;
6302 if (!cm_IsValidClientString(pathp)) {
6304 clientchar_t * hexp;
6306 hexp = cm_GetRawCharsAlloc(pathp, -1);
6307 osi_Log1(smb_logp, "NTOpenX rejecting invalid name. [%S]",
6308 osi_LogSaveClientString(smb_logp, hexp));
6312 osi_Log0(smb_logp, "NTOpenX rejecting invalid name");
6314 return CM_ERROR_BADNTFILENAME;
6317 #ifdef DEBUG_VERBOSE
6319 char *hexp, *asciip;
6320 asciip = (lastNamep ? lastNamep : pathp );
6321 hexp = osi_HexifyString(asciip);
6322 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
6326 userp = smb_GetUserFromVCP(vcp, inp);
6329 code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
6330 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6331 userp, tidPathp, &req, &scp);
6334 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6335 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
6336 cm_ReleaseSCache(scp);
6337 cm_ReleaseUser(userp);
6338 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6339 return CM_ERROR_PATH_NOT_COVERED;
6341 return CM_ERROR_NOSUCHPATH;
6343 #endif /* DFS_SUPPORT */
6346 if (code == CM_ERROR_NOSUCHFILE ||
6347 code == CM_ERROR_NOSUCHPATH ||
6348 code == CM_ERROR_BPLUS_NOMATCH)
6349 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
6350 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6351 userp, tidPathp, &req, &dscp);
6353 cm_ReleaseUser(userp);
6358 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6359 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
6361 cm_ReleaseSCache(dscp);
6362 cm_ReleaseUser(userp);
6363 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6364 return CM_ERROR_PATH_NOT_COVERED;
6366 return CM_ERROR_NOSUCHPATH;
6368 #endif /* DFS_SUPPORT */
6369 /* otherwise, scp points to the parent directory. Do a lookup,
6370 * and truncate the file if we find it, otherwise we create the
6377 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
6379 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
6380 cm_ReleaseSCache(dscp);
6381 cm_ReleaseUser(userp);
6386 /* if we get here, if code is 0, the file exists and is represented by
6387 * scp. Otherwise, we have to create it. The dir may be represented
6388 * by dscp, or we may have found the file directly. If code is non-zero,
6392 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
6394 if (dscp) cm_ReleaseSCache(dscp);
6395 cm_ReleaseSCache(scp);
6396 cm_ReleaseUser(userp);
6401 /* oops, file shouldn't be there */
6403 cm_ReleaseSCache(dscp);
6404 cm_ReleaseSCache(scp);
6405 cm_ReleaseUser(userp);
6406 return CM_ERROR_EXISTS;
6410 setAttr.mask = CM_ATTRMASK_LENGTH;
6411 setAttr.length.LowPart = 0;
6412 setAttr.length.HighPart = 0;
6413 code = cm_SetAttr(scp, &setAttr, userp, &req);
6414 openAction = 3; /* truncated existing file */
6416 else openAction = 1; /* found existing file */
6418 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
6419 /* don't create if not found */
6420 if (dscp) cm_ReleaseSCache(dscp);
6421 cm_ReleaseUser(userp);
6422 return CM_ERROR_NOSUCHFILE;
6425 osi_assertx(dscp != NULL, "null cm_scache_t");
6426 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %S",
6427 osi_LogSaveClientString(smb_logp, lastNamep));
6428 openAction = 2; /* created file */
6429 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6430 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6431 smb_SetInitialModeBitsForFile(attributes, &setAttr);
6433 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6437 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6438 smb_NotifyChange(FILE_ACTION_ADDED,
6439 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6440 dscp, lastNamep, NULL, TRUE);
6441 } else if (!excl && code == CM_ERROR_EXISTS) {
6442 /* not an exclusive create, and someone else tried
6443 * creating it already, then we open it anyway. We
6444 * don't bother retrying after this, since if this next
6445 * fails, that means that the file was deleted after we
6446 * started this call.
6448 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6452 setAttr.mask = CM_ATTRMASK_LENGTH;
6453 setAttr.length.LowPart = 0;
6454 setAttr.length.HighPart = 0;
6455 code = cm_SetAttr(scp, &setAttr, userp, &req);
6457 } /* lookup succeeded */
6461 /* we don't need this any longer */
6463 cm_ReleaseSCache(dscp);
6466 /* something went wrong creating or truncating the file */
6468 cm_ReleaseSCache(scp);
6469 cm_ReleaseUser(userp);
6473 /* make sure we're about to open a file */
6474 if (scp->fileType != CM_SCACHETYPE_FILE) {
6475 cm_ReleaseSCache(scp);
6476 cm_ReleaseUser(userp);
6477 return CM_ERROR_ISDIR;
6480 /* now all we have to do is open the file itself */
6481 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6482 osi_assertx(fidp, "null smb_fid_t");
6485 lock_ObtainMutex(&fidp->mx);
6486 /* save a pointer to the vnode */
6488 lock_ObtainWrite(&scp->rw);
6489 scp->flags |= CM_SCACHEFLAG_SMB_FID;
6490 lock_ReleaseWrite(&scp->rw);
6491 osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
6493 fidp->userp = userp;
6495 /* compute open mode */
6497 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
6498 if (openMode == 1 || openMode == 2)
6499 fidp->flags |= SMB_FID_OPENWRITE;
6501 /* remember if the file was newly created */
6503 fidp->flags |= SMB_FID_CREATED;
6505 lock_ReleaseMutex(&fidp->mx);
6506 smb_ReleaseFID(fidp);
6508 cm_Open(scp, 0, userp);
6510 /* set inp->fid so that later read calls in same msg can find fid */
6511 inp->fid = fidp->fid;
6513 /* copy out remainder of the parms */
6515 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6516 lock_ObtainRead(&scp->rw);
6518 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
6519 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
6520 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
6521 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
6522 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
6523 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
6524 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
6525 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
6526 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
6528 /* and the final "always present" stuff */
6529 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
6530 /* next write out the "unique" ID */
6531 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
6532 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
6533 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6534 lock_ReleaseRead(&scp->rw);
6535 smb_SetSMBDataLength(outp, 0);
6537 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
6539 cm_ReleaseUser(userp);
6540 /* leave scp held since we put it in fidp->scp */
6544 static void smb_GetLockParams(unsigned char LockType,
6546 unsigned int * ppid,
6547 LARGE_INTEGER * pOffset,
6548 LARGE_INTEGER * pLength)
6550 if (LockType & LOCKING_ANDX_LARGE_FILES) {
6552 *ppid = *((USHORT *) *buf);
6553 pOffset->HighPart = *((LONG *)(*buf + 4));
6554 pOffset->LowPart = *((DWORD *)(*buf + 8));
6555 pLength->HighPart = *((LONG *)(*buf + 12));
6556 pLength->LowPart = *((DWORD *)(*buf + 16));
6560 /* Not Large Files */
6561 *ppid = *((USHORT *) *buf);
6562 pOffset->HighPart = 0;
6563 pOffset->LowPart = *((DWORD *)(*buf + 2));
6564 pLength->HighPart = 0;
6565 pLength->LowPart = *((DWORD *)(*buf + 6));
6570 /* SMB_COM_LOCKING_ANDX */
6571 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6578 unsigned char LockType;
6579 unsigned short NumberOfUnlocks, NumberOfLocks;
6583 LARGE_INTEGER LOffset, LLength;
6584 smb_waitingLockRequest_t *wlRequest = NULL;
6585 cm_file_lock_t *lockp;
6590 afs_uint32 smb_vc_hold_required = 0;
6594 fid = smb_GetSMBParm(inp, 2);
6595 fid = smb_ChainFID(fid, inp);
6597 fidp = smb_FindFID(vcp, fid, 0);
6599 osi_Log2(smb_logp, "V3LockingX Unknown SMB Fid vcp 0x%p fid %d",
6601 return CM_ERROR_BADFD;
6603 lock_ObtainMutex(&fidp->mx);
6604 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6605 lock_ReleaseMutex(&fidp->mx);
6606 smb_CloseFID(vcp, fidp, NULL, 0);
6607 smb_ReleaseFID(fidp);
6608 return CM_ERROR_NOSUCHFILE;
6611 if (fidp->flags & SMB_FID_IOCTL) {
6612 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
6613 lock_ReleaseMutex(&fidp->mx);
6614 smb_ReleaseFID(fidp);
6615 return CM_ERROR_BADFD;
6618 osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
6620 lock_ReleaseMutex(&fidp->mx);
6622 /* set inp->fid so that later read calls in same msg can find fid */
6625 userp = smb_GetUserFromVCP(vcp, inp);
6628 lock_ObtainWrite(&scp->rw);
6629 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6630 CM_SCACHESYNC_NEEDCALLBACK
6631 | CM_SCACHESYNC_GETSTATUS
6632 | CM_SCACHESYNC_LOCK);
6634 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
6638 LockType = smb_GetSMBParm(inp, 3) & 0xff;
6639 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
6640 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
6641 NumberOfLocks = smb_GetSMBParm(inp, 7);
6643 if (!(fidp->flags & SMB_FID_OPENWRITE) &&
6644 !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
6645 /* somebody wants exclusive locks on a file that they only
6646 opened for reading. We downgrade this to a shared lock. */
6647 osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
6648 LockType |= LOCKING_ANDX_SHARED_LOCK;
6651 if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
6652 /* AFS does not support atomic changes of lock types from read or write and vice-versa */
6653 osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]");
6654 code = CM_ERROR_BADOP;
6659 op = smb_GetSMBData(inp, NULL);
6661 if (LockType & LOCKING_ANDX_CANCEL_LOCK) {
6662 /* Cancel outstanding lock requests */
6663 smb_waitingLock_t * wl;
6665 for (i=0; i<NumberOfLocks; i++) {
6666 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6668 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6670 lock_ObtainWrite(&smb_globalLock);
6671 for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
6673 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
6674 if (cm_KeyEquals(&wl->key, &key, 0) && LargeIntegerEqualTo(wl->LOffset, LOffset) &&
6675 LargeIntegerEqualTo(wl->LLength, LLength)) {
6676 wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
6677 goto found_lock_request;
6682 lock_ReleaseWrite(&smb_globalLock);
6685 smb_SetSMBDataLength(outp, 0);
6690 for (i=0; i<NumberOfUnlocks; i++) {
6691 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6693 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6695 code = cm_Unlock(scp, LockType, LOffset, LLength, key, 0, userp, &req);
6703 for (i=0; i<NumberOfLocks; i++) {
6704 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6706 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6708 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
6709 userp, &req, &lockp);
6711 if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
6712 (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
6714 code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
6715 userp, &req, &lockp);
6718 if (code == CM_ERROR_LOCK_NOT_GRANTED && Timeout != 0) {
6719 smb_waitingLock_t * wLock;
6721 /* Put on waiting list */
6722 if(wlRequest == NULL) {
6726 LARGE_INTEGER tOffset, tLength;
6728 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
6730 osi_assertx(wlRequest != NULL, "null wlRequest");
6732 wlRequest->vcp = vcp;
6733 smb_vc_hold_required = 1;
6734 wlRequest->scp = scp;
6735 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
6737 wlRequest->inp = smb_CopyPacket(inp);
6738 wlRequest->outp = smb_CopyPacket(outp);
6739 wlRequest->lockType = LockType;
6740 wlRequest->msTimeout = Timeout;
6741 wlRequest->start_t = osi_Time();
6742 wlRequest->locks = NULL;
6744 /* The waiting lock request needs to have enough
6745 information to undo all the locks in the request.
6746 We do the following to store info about locks that
6747 have already been granted. Sure, we can get most
6748 of the info from the packet, but the packet doesn't
6749 hold the result of cm_Lock call. In practice we
6750 only receive packets with one or two locks, so we
6751 are only wasting a few bytes here and there and
6752 only for a limited period of time until the waiting
6753 lock times out or is freed. */
6755 for(opt = op_locks, j=i; j > 0; j--) {
6756 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
6758 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6760 wLock = malloc(sizeof(smb_waitingLock_t));
6762 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6765 wLock->LOffset = tOffset;
6766 wLock->LLength = tLength;
6767 wLock->lockp = NULL;
6768 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
6769 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6774 wLock = malloc(sizeof(smb_waitingLock_t));
6776 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6779 wLock->LOffset = LOffset;
6780 wLock->LLength = LLength;
6781 wLock->lockp = lockp;
6782 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
6783 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6786 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
6794 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
6801 /* Since something went wrong with the lock number i, we now
6802 have to go ahead and release any locks acquired before the
6803 failure. All locks before lock number i (of which there
6804 are i of them) have either been successful or are waiting.
6805 Either case requires calling cm_Unlock(). */
6807 /* And purge the waiting lock */
6808 if(wlRequest != NULL) {
6809 smb_waitingLock_t * wl;
6810 smb_waitingLock_t * wlNext;
6813 for(wl = wlRequest->locks; wl; wl = wlNext) {
6815 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
6817 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, 0, userp, &req);
6820 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
6822 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
6825 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
6830 smb_ReleaseVC(wlRequest->vcp);
6831 cm_ReleaseSCache(wlRequest->scp);
6832 smb_FreePacket(wlRequest->inp);
6833 smb_FreePacket(wlRequest->outp);
6842 if (wlRequest != NULL) {
6844 lock_ObtainWrite(&smb_globalLock);
6845 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
6847 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
6848 lock_ReleaseWrite(&smb_globalLock);
6850 /* don't send reply immediately */
6851 outp->flags |= SMB_PACKETFLAG_NOSEND;
6854 smb_SetSMBDataLength(outp, 0);
6858 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
6861 lock_ReleaseWrite(&scp->rw);
6862 cm_ReleaseSCache(scp);
6863 cm_ReleaseUser(userp);
6864 smb_ReleaseFID(fidp);
6865 if (!smb_vc_hold_required)
6871 /* SMB_COM_QUERY_INFORMATION2 */
6872 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6878 afs_uint32 searchTime;
6885 fid = smb_GetSMBParm(inp, 0);
6886 fid = smb_ChainFID(fid, inp);
6888 fidp = smb_FindFID(vcp, fid, 0);
6890 osi_Log2(smb_logp, "V3GetAttributes Unknown SMB Fid vcp 0x%p fid %d",
6892 return CM_ERROR_BADFD;
6894 lock_ObtainMutex(&fidp->mx);
6895 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6896 lock_ReleaseMutex(&fidp->mx);
6897 smb_CloseFID(vcp, fidp, NULL, 0);
6898 smb_ReleaseFID(fidp);
6899 return CM_ERROR_NOSUCHFILE;
6902 if (fidp->flags & SMB_FID_IOCTL) {
6903 lock_ReleaseMutex(&fidp->mx);
6904 smb_ReleaseFID(fidp);
6905 return CM_ERROR_BADFD;
6908 osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6910 lock_ReleaseMutex(&fidp->mx);
6912 userp = smb_GetUserFromVCP(vcp, inp);
6915 /* otherwise, stat the file */
6916 lock_ObtainWrite(&scp->rw);
6917 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6918 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6922 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6924 lock_ConvertWToR(&scp->rw);
6927 /* decode times. We need a search time, but the response to this
6928 * call provides the date first, not the time, as returned in the
6929 * searchTime variable. So we take the high-order bits first.
6931 cm_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
6932 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
6933 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
6934 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
6935 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
6936 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
6937 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
6939 /* now handle file size and allocation size */
6940 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
6941 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
6942 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
6943 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
6945 /* file attribute */
6946 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
6948 /* and finalize stuff */
6949 smb_SetSMBDataLength(outp, 0);
6954 lock_ReleaseRead(&scp->rw);
6956 lock_ReleaseWrite(&scp->rw);
6957 cm_ReleaseSCache(scp);
6958 cm_ReleaseUser(userp);
6959 smb_ReleaseFID(fidp);
6963 /* SMB_COM_SET_INFORMATION2 */
6964 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6970 afs_uint32 searchTime;
6978 fid = smb_GetSMBParm(inp, 0);
6979 fid = smb_ChainFID(fid, inp);
6981 fidp = smb_FindFID(vcp, fid, 0);
6983 osi_Log2(smb_logp, "V3SetAttributes Unknown SMB Fid vcp 0x%p fid %d",
6985 return CM_ERROR_BADFD;
6987 lock_ObtainMutex(&fidp->mx);
6988 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6989 lock_ReleaseMutex(&fidp->mx);
6990 smb_CloseFID(vcp, fidp, NULL, 0);
6991 smb_ReleaseFID(fidp);
6992 return CM_ERROR_NOSUCHFILE;
6995 if (fidp->flags & SMB_FID_IOCTL) {
6996 lock_ReleaseMutex(&fidp->mx);
6997 smb_ReleaseFID(fidp);
6998 return CM_ERROR_BADFD;
7001 osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
7003 lock_ReleaseMutex(&fidp->mx);
7005 userp = smb_GetUserFromVCP(vcp, inp);
7007 /* now prepare to call cm_setattr. This message only sets various times,
7008 * and AFS only implements mtime, and we'll set the mtime if that's
7009 * requested. The others we'll ignore.
7011 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
7013 if (searchTime != 0) {
7014 cm_UnixTimeFromSearchTime(&unixTime, searchTime);
7016 if ( unixTime != -1 ) {
7017 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
7018 attrs.clientModTime = unixTime;
7019 code = cm_SetAttr(scp, &attrs, userp, &req);
7021 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
7023 osi_Log1(smb_logp, "**cm_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
7029 cm_ReleaseSCache(scp);
7030 cm_ReleaseUser(userp);
7031 smb_ReleaseFID(fidp);
7035 /* SMB_COM_WRITE_ANDX */
7036 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7039 long count, written = 0, total_written = 0;
7043 smb_t *smbp = (smb_t*) inp;
7048 int inDataBlockCount;
7050 fd = smb_GetSMBParm(inp, 2);
7051 count = smb_GetSMBParm(inp, 10);
7053 offset.HighPart = 0;
7054 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7056 if (*inp->wctp == 14) {
7057 /* we have a request with 64-bit file offsets */
7058 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7061 op = inp->data + smb_GetSMBParm(inp, 11);
7062 inDataBlockCount = count;
7064 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
7065 fd, offset.HighPart, offset.LowPart, count);
7067 fd = smb_ChainFID(fd, inp);
7068 fidp = smb_FindFID(vcp, fd, 0);
7070 osi_Log2(smb_logp, "smb_ReceiveV3WriteX Unknown SMB Fid vcp 0x%p fid %d",
7072 return CM_ERROR_BADFD;
7074 lock_ObtainMutex(&fidp->mx);
7075 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7076 lock_ReleaseMutex(&fidp->mx);
7077 smb_CloseFID(vcp, fidp, NULL, 0);
7078 smb_ReleaseFID(fidp);
7079 return CM_ERROR_NOSUCHFILE;
7082 if (fidp->flags & SMB_FID_IOCTL) {
7083 lock_ReleaseMutex(&fidp->mx);
7084 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
7085 smb_ReleaseFID(fidp);
7089 if (fidp->flags & SMB_FID_RPC) {
7090 lock_ReleaseMutex(&fidp->mx);
7091 code = smb_RPCV3Write(fidp, vcp, inp, outp);
7092 smb_ReleaseFID(fidp);
7097 lock_ReleaseMutex(&fidp->mx);
7098 smb_ReleaseFID(fidp);
7099 return CM_ERROR_BADFDOP;
7104 lock_ReleaseMutex(&fidp->mx);
7106 userp = smb_GetUserFromVCP(vcp, inp);
7108 /* special case: 0 bytes transferred means there is no data
7109 transferred. A slight departure from SMB_COM_WRITE where this
7110 means that we are supposed to truncate the file at this
7115 LARGE_INTEGER LOffset;
7116 LARGE_INTEGER LLength;
7119 key = cm_GenerateKey(vcp->vcID, pid, fd);
7121 LOffset.HighPart = offset.HighPart;
7122 LOffset.LowPart = offset.LowPart;
7123 LLength.HighPart = 0;
7124 LLength.LowPart = count;
7126 lock_ObtainWrite(&scp->rw);
7127 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7128 lock_ReleaseWrite(&scp->rw);
7135 * Work around bug in NT client
7137 * When copying a file, the NT client should first copy the data,
7138 * then copy the last write time. But sometimes the NT client does
7139 * these in the wrong order, so the data copies would inadvertently
7140 * cause the last write time to be overwritten. We try to detect this,
7141 * and don't set client mod time if we think that would go against the
7144 lock_ObtainMutex(&fidp->mx);
7145 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7146 lock_ObtainWrite(&fidp->scp->rw);
7147 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7148 scp->clientModTime = time(NULL);
7149 lock_ReleaseWrite(&fidp->scp->rw);
7151 lock_ReleaseMutex(&fidp->mx);
7154 while ( code == 0 && count > 0 ) {
7155 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7156 if (code == 0 && written == 0)
7157 code = CM_ERROR_PARTIALWRITE;
7159 offset = LargeIntegerAdd(offset,
7160 ConvertLongToLargeInteger(written));
7162 total_written += written;
7166 /* slots 0 and 1 are reserved for request chaining and will be
7167 filled in when we return. */
7168 smb_SetSMBParm(outp, 2, total_written);
7169 smb_SetSMBParm(outp, 3, 0); /* reserved */
7170 smb_SetSMBParm(outp, 4, 0); /* reserved */
7171 smb_SetSMBParm(outp, 5, 0); /* reserved */
7172 smb_SetSMBDataLength(outp, 0);
7176 cm_ReleaseSCache(scp);
7177 cm_ReleaseUser(userp);
7178 smb_ReleaseFID(fidp);
7183 /* SMB_COM_READ_ANDX */
7184 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7188 long finalCount = 0;
7192 smb_t *smbp = (smb_t*) inp;
7199 fd = smb_GetSMBParm(inp, 2); /* File ID */
7200 count = smb_GetSMBParm(inp, 5); /* MaxCount */
7201 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7203 if (*inp->wctp == 12) {
7204 /* a request with 64-bit offsets */
7205 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
7207 if (LargeIntegerLessThanZero(offset)) {
7208 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
7209 offset.HighPart, offset.LowPart);
7210 return CM_ERROR_BADSMB;
7213 offset.HighPart = 0;
7216 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
7217 fd, offset.HighPart, offset.LowPart, count);
7219 fd = smb_ChainFID(fd, inp);
7220 fidp = smb_FindFID(vcp, fd, 0);
7222 osi_Log2(smb_logp, "smb_ReceiveV3Read Unknown SMB Fid vcp 0x%p fid %d",
7224 return CM_ERROR_BADFD;
7227 lock_ObtainMutex(&fidp->mx);
7229 if (fidp->flags & SMB_FID_IOCTL) {
7230 lock_ReleaseMutex(&fidp->mx);
7232 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
7233 smb_ReleaseFID(fidp);
7237 if (fidp->flags & SMB_FID_RPC) {
7238 lock_ReleaseMutex(&fidp->mx);
7240 code = smb_RPCV3Read(fidp, vcp, inp, outp);
7241 smb_ReleaseFID(fidp);
7245 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7246 lock_ReleaseMutex(&fidp->mx);
7247 smb_CloseFID(vcp, fidp, NULL, 0);
7248 smb_ReleaseFID(fidp);
7249 return CM_ERROR_NOSUCHFILE;
7253 lock_ReleaseMutex(&fidp->mx);
7254 smb_ReleaseFID(fidp);
7255 return CM_ERROR_BADFDOP;
7261 lock_ReleaseMutex(&fidp->mx);
7264 key = cm_GenerateKey(vcp->vcID, pid, fd);
7266 LARGE_INTEGER LOffset, LLength;
7268 LOffset.HighPart = offset.HighPart;
7269 LOffset.LowPart = offset.LowPart;
7270 LLength.HighPart = 0;
7271 LLength.LowPart = count;
7273 lock_ObtainWrite(&scp->rw);
7274 code = cm_LockCheckRead(scp, LOffset, LLength, key);
7275 lock_ReleaseWrite(&scp->rw);
7277 cm_ReleaseSCache(scp);
7280 smb_ReleaseFID(fidp);
7284 /* set inp->fid so that later read calls in same msg can find fid */
7287 userp = smb_GetUserFromVCP(vcp, inp);
7289 /* 0 and 1 are reserved for request chaining, were setup by our caller,
7290 * and will be further filled in after we return.
7292 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
7293 smb_SetSMBParm(outp, 3, 0); /* resvd */
7294 smb_SetSMBParm(outp, 4, 0); /* resvd */
7295 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
7296 /* fill in #6 when we have all the parameters' space reserved */
7297 smb_SetSMBParm(outp, 7, 0); /* resv'd */
7298 smb_SetSMBParm(outp, 8, 0); /* resv'd */
7299 smb_SetSMBParm(outp, 9, 0); /* resv'd */
7300 smb_SetSMBParm(outp, 10, 0); /* resv'd */
7301 smb_SetSMBParm(outp, 11, 0); /* reserved */
7303 /* get op ptr after putting in the parms, since otherwise we don't
7304 * know where the data really is.
7306 op = smb_GetSMBData(outp, NULL);
7308 /* now fill in offset from start of SMB header to first data byte (to op) */
7309 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
7311 /* set the packet data length the count of the # of bytes */
7312 smb_SetSMBDataLength(outp, count);
7314 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7316 /* fix some things up */
7317 smb_SetSMBParm(outp, 5, finalCount);
7318 smb_SetSMBDataLength(outp, finalCount);
7320 cm_ReleaseUser(userp);
7321 smb_ReleaseFID(fidp);
7326 * Values for createDisp, copied from NTDDK.H
7328 #define FILE_SUPERSEDE 0 // (???)
7329 #define FILE_OPEN 1 // (open)
7330 #define FILE_CREATE 2 // (exclusive)
7331 #define FILE_OPEN_IF 3 // (non-exclusive)
7332 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
7333 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
7336 #define REQUEST_OPLOCK 2
7337 #define REQUEST_BATCH_OPLOCK 4
7338 #define OPEN_DIRECTORY 8
7339 #define EXTENDED_RESPONSE_REQUIRED 0x10
7341 /* CreateOptions field. */
7342 #define FILE_DIRECTORY_FILE 0x0001
7343 #define FILE_WRITE_THROUGH 0x0002
7344 #define FILE_SEQUENTIAL_ONLY 0x0004
7345 #define FILE_NON_DIRECTORY_FILE 0x0040
7346 #define FILE_NO_EA_KNOWLEDGE 0x0200
7347 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
7348 #define FILE_RANDOM_ACCESS 0x0800
7349 #define FILE_DELETE_ON_CLOSE 0x1000
7350 #define FILE_OPEN_BY_FILE_ID 0x2000
7351 #define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000
7352 #define FILE_NO_COMPRESSION 0x00008000
7353 #define FILE_RESERVE_OPFILTER 0x00100000
7354 #define FILE_OPEN_REPARSE_POINT 0x00200000
7355 #define FILE_OPEN_NO_RECALL 0x00400000
7356 #define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000
7358 /* SMB_COM_NT_CREATE_ANDX */
7359 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7361 clientchar_t *pathp, *realPathp;
7365 cm_scache_t *dscp; /* parent dir */
7366 cm_scache_t *scp; /* file to create or open */
7367 cm_scache_t *targetScp; /* if scp is a symlink */
7369 clientchar_t *lastNamep;
7370 clientchar_t *treeStartp;
7371 unsigned short nameLength;
7373 unsigned int requestOpLock;
7374 unsigned int requestBatchOpLock;
7375 unsigned int mustBeDir;
7376 unsigned int extendedRespRequired;
7377 unsigned int treeCreate;
7379 unsigned int desiredAccess;
7380 unsigned int extAttributes;
7381 unsigned int createDisp;
7382 unsigned int createOptions;
7383 unsigned int shareAccess;
7384 unsigned short baseFid;
7385 smb_fid_t *baseFidp;
7387 cm_scache_t *baseDirp;
7388 unsigned short openAction;
7393 clientchar_t *tidPathp;
7398 int checkDoneRequired = 0;
7399 cm_lock_data_t *ldp = NULL;
7400 BOOL is_rpc = FALSE;
7401 BOOL is_ipc = FALSE;
7405 /* This code is very long and has a lot of if-then-else clauses
7406 * scp and dscp get reused frequently and we need to ensure that
7407 * we don't lose a reference. Start by ensuring that they are NULL.
7414 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
7415 flags = smb_GetSMBOffsetParm(inp, 3, 1)
7416 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
7417 requestOpLock = flags & REQUEST_OPLOCK;
7418 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7419 mustBeDir = flags & OPEN_DIRECTORY;
7420 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7423 * Why all of a sudden 32-bit FID?
7424 * We will reject all bits higher than 16.
7426 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
7427 return CM_ERROR_INVAL;
7428 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
7429 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
7430 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
7431 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
7432 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
7433 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
7434 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
7435 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
7436 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
7437 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
7438 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
7440 /* mustBeDir is never set; createOptions directory bit seems to be
7443 if (createOptions & FILE_DIRECTORY_FILE)
7445 else if (createOptions & FILE_NON_DIRECTORY_FILE)
7450 pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
7451 NULL, SMB_STRF_ANSIPATH);
7453 /* Sometimes path is not null-terminated, so we make a copy. */
7454 realPathp = malloc(nameLength+sizeof(clientchar_t));
7455 memcpy(realPathp, pathp, nameLength+sizeof(clientchar_t));
7456 realPathp[nameLength/sizeof(clientchar_t)] = 0;
7458 spacep = inp->spacep;
7459 /* smb_StripLastComponent will strip "::$DATA" if present */
7460 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
7462 osi_Log1(smb_logp,"NTCreateX for [%S]",osi_LogSaveClientString(smb_logp,realPathp));
7463 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
7464 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%S]", shareAccess, flags, osi_LogSaveClientString(smb_logp,(lastNamep?lastNamep:_C("null"))));
7468 baseDirp = cm_RootSCachep(cm_rootUserp, &req);
7469 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7470 if (code == CM_ERROR_TIDIPC) {
7471 /* Attempt to use a TID allocated for IPC. The client
7472 * is probably looking for DCE RPC end points which we
7473 * don't support OR it could be looking to make a DFS
7476 osi_Log0(smb_logp, "NTCreateX received IPC TID");
7481 osi_Log1(smb_logp, "NTCreateX tidPathp=[%S]", (tidPathp==NULL)?_C("null"): osi_LogSaveClientString(smb_logp,tidPathp));
7485 ((is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)) ||
7487 /* special case magic file name for receiving IOCTL requests
7488 * (since IOCTL calls themselves aren't getting through).
7490 cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0)) {
7492 unsigned short file_type = 0;
7493 unsigned short device_state = 0;
7495 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7498 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
7499 osi_Log1(smb_logp, "NTCreateX Setting up RPC on fid[%d]", fidp->fid);
7501 osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
7502 smb_ReleaseFID(fidp);
7507 smb_SetupIoctlFid(fidp, spacep);
7508 osi_Log1(smb_logp, "NTCreateX Setting up IOCTL on fid[%d]", fidp->fid);
7511 /* set inp->fid so that later read calls in same msg can find fid */
7512 inp->fid = fidp->fid;
7516 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7517 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7518 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
7520 memset(&ft, 0, sizeof(ft));
7521 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7522 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7523 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7524 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7525 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
7526 sz.HighPart = 0x7fff; sz.LowPart = 0;
7527 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
7528 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
7529 smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++; /* filetype */
7530 smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++; /* dev state */
7531 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
7532 smb_SetSMBDataLength(outp, 0);
7534 /* clean up fid reference */
7535 smb_ReleaseFID(fidp);
7542 osi_Log0(smb_logp, "NTCreateX rejecting IPC TID");
7544 return CM_ERROR_BADFD;
7548 if (!cm_IsValidClientString(realPathp)) {
7550 clientchar_t * hexp;
7552 hexp = cm_GetRawCharsAlloc(realPathp, -1);
7553 osi_Log1(smb_logp, "NTCreateX rejecting invalid name. [%S]",
7554 osi_LogSaveClientString(smb_logp, hexp));
7558 osi_Log0(smb_logp, "NTCreateX rejecting invalid name");
7561 return CM_ERROR_BADNTFILENAME;
7564 userp = smb_GetUserFromVCP(vcp, inp);
7566 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
7568 return CM_ERROR_INVAL;
7571 if (baseFidp != 0) {
7572 baseFidp = smb_FindFID(vcp, baseFid, 0);
7574 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
7575 cm_ReleaseUser(userp);
7577 return CM_ERROR_INVAL;
7580 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7582 smb_CloseFID(vcp, baseFidp, NULL, 0);
7583 smb_ReleaseFID(baseFidp);
7584 cm_ReleaseUser(userp);
7585 return CM_ERROR_NOSUCHPATH;
7588 baseDirp = baseFidp->scp;
7592 /* compute open mode */
7594 if (desiredAccess & DELETE)
7595 fidflags |= SMB_FID_OPENDELETE;
7596 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
7597 fidflags |= SMB_FID_OPENREAD_LISTDIR;
7598 if (desiredAccess & AFS_ACCESS_WRITE)
7599 fidflags |= SMB_FID_OPENWRITE;
7600 if (createOptions & FILE_DELETE_ON_CLOSE)
7601 fidflags |= SMB_FID_DELONCLOSE;
7602 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7603 fidflags |= SMB_FID_SEQUENTIAL;
7604 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7605 fidflags |= SMB_FID_RANDOM;
7606 if (createOptions & FILE_OPEN_REPARSE_POINT)
7607 osi_Log0(smb_logp, "NTCreateX Open Reparse Point");
7608 if (smb_IsExecutableFileName(lastNamep))
7609 fidflags |= SMB_FID_EXECUTABLE;
7611 /* and the share mode */
7612 if (shareAccess & FILE_SHARE_READ)
7613 fidflags |= SMB_FID_SHARE_READ;
7614 if (shareAccess & FILE_SHARE_WRITE)
7615 fidflags |= SMB_FID_SHARE_WRITE;
7617 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
7620 /* For an exclusive create, we want to do a case sensitive match for the last component. */
7621 if ( createDisp == FILE_CREATE ||
7622 createDisp == FILE_OVERWRITE ||
7623 createDisp == FILE_OVERWRITE_IF) {
7624 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7625 userp, tidPathp, &req, &dscp);
7628 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7629 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7631 cm_ReleaseSCache(dscp);
7632 cm_ReleaseUser(userp);
7635 smb_ReleaseFID(baseFidp);
7636 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7637 return CM_ERROR_PATH_NOT_COVERED;
7639 return CM_ERROR_NOSUCHPATH;
7641 #endif /* DFS_SUPPORT */
7642 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7644 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7645 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7646 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7647 if (code == 0 && realDirFlag == 1) {
7648 cm_ReleaseSCache(scp);
7649 cm_ReleaseSCache(dscp);
7650 cm_ReleaseUser(userp);
7653 smb_ReleaseFID(baseFidp);
7654 return CM_ERROR_EXISTS;
7657 /* we have both scp and dscp */
7660 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7661 userp, tidPathp, &req, &scp);
7663 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7664 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7665 cm_ReleaseSCache(scp);
7666 cm_ReleaseUser(userp);
7669 smb_ReleaseFID(baseFidp);
7670 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7671 return CM_ERROR_PATH_NOT_COVERED;
7673 return CM_ERROR_NOSUCHPATH;
7675 #endif /* DFS_SUPPORT */
7676 /* we might have scp but not dscp */
7680 code != CM_ERROR_NOSUCHFILE &&
7681 code != CM_ERROR_NOSUCHPATH &&
7682 code != CM_ERROR_BPLUS_NOMATCH) {
7683 cm_ReleaseUser(userp);
7686 smb_ReleaseFID(baseFidp);
7693 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7694 /* look up parent directory */
7695 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
7696 * the immediate parent. We have to work our way up realPathp until we hit something that we
7700 /* we might or might not have scp */
7706 code = cm_NameI(baseDirp, spacep->wdata,
7707 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7708 userp, tidPathp, &req, &dscp);
7711 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7712 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7715 cm_ReleaseSCache(scp);
7716 cm_ReleaseSCache(dscp);
7717 cm_ReleaseUser(userp);
7720 smb_ReleaseFID(baseFidp);
7721 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7722 return CM_ERROR_PATH_NOT_COVERED;
7724 return CM_ERROR_NOSUCHPATH;
7726 #endif /* DFS_SUPPORT */
7729 (code == CM_ERROR_NOSUCHFILE ||
7730 code == CM_ERROR_NOSUCHPATH ||
7731 code == CM_ERROR_BPLUS_NOMATCH) &&
7732 (tp = cm_ClientStrRChr(spacep->wdata, '\\')) &&
7733 (createDisp == FILE_CREATE) &&
7734 (realDirFlag == 1)) {
7737 treeStartp = realPathp + (tp - spacep->wdata);
7739 if (*tp && !smb_IsLegalFilename(tp)) {
7740 cm_ReleaseUser(userp);
7742 smb_ReleaseFID(baseFidp);
7745 cm_ReleaseSCache(scp);
7746 return CM_ERROR_BADNTFILENAME;
7750 } while (dscp == NULL && code == 0);
7754 /* we might have scp and we might have dscp */
7757 smb_ReleaseFID(baseFidp);
7760 osi_Log0(smb_logp,"NTCreateX parent not found");
7762 cm_ReleaseSCache(scp);
7764 cm_ReleaseSCache(dscp);
7765 cm_ReleaseUser(userp);
7770 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
7771 /* A file exists where we want a directory. */
7773 cm_ReleaseSCache(scp);
7774 cm_ReleaseSCache(dscp);
7775 cm_ReleaseUser(userp);
7777 return CM_ERROR_EXISTS;
7781 lastNamep = realPathp;
7785 if (!smb_IsLegalFilename(lastNamep)) {
7787 cm_ReleaseSCache(scp);
7789 cm_ReleaseSCache(dscp);
7790 cm_ReleaseUser(userp);
7792 return CM_ERROR_BADNTFILENAME;
7795 if (!foundscp && !treeCreate) {
7796 if ( createDisp == FILE_CREATE ||
7797 createDisp == FILE_OVERWRITE ||
7798 createDisp == FILE_OVERWRITE_IF)
7800 code = cm_Lookup(dscp, lastNamep,
7801 CM_FLAG_FOLLOW, userp, &req, &scp);
7803 code = cm_Lookup(dscp, lastNamep,
7804 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7807 if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
7809 cm_ReleaseSCache(dscp);
7810 cm_ReleaseUser(userp);
7815 /* we have scp and dscp */
7817 /* we have scp but not dscp */
7819 smb_ReleaseFID(baseFidp);
7822 /* if we get here, if code is 0, the file exists and is represented by
7823 * scp. Otherwise, we have to create it. The dir may be represented
7824 * by dscp, or we may have found the file directly. If code is non-zero,
7827 if (code == 0 && !treeCreate) {
7828 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7830 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7832 cm_ReleaseSCache(dscp);
7834 cm_ReleaseSCache(scp);
7835 cm_ReleaseUser(userp);
7839 checkDoneRequired = 1;
7841 if (createDisp == FILE_CREATE) {
7842 /* oops, file shouldn't be there */
7843 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7845 cm_ReleaseSCache(dscp);
7847 cm_ReleaseSCache(scp);
7848 cm_ReleaseUser(userp);
7850 return CM_ERROR_EXISTS;
7853 if ( createDisp == FILE_OVERWRITE ||
7854 createDisp == FILE_OVERWRITE_IF) {
7856 setAttr.mask = CM_ATTRMASK_LENGTH;
7857 setAttr.length.LowPart = 0;
7858 setAttr.length.HighPart = 0;
7859 /* now watch for a symlink */
7861 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7863 osi_assertx(dscp != NULL, "null cm_scache_t");
7864 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7866 /* we have a more accurate file to use (the
7867 * target of the symbolic link). Otherwise,
7868 * we'll just use the symlink anyway.
7870 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7872 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7873 cm_ReleaseSCache(scp);
7875 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7877 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7879 cm_ReleaseSCache(dscp);
7881 cm_ReleaseSCache(scp);
7882 cm_ReleaseUser(userp);
7888 code = cm_SetAttr(scp, &setAttr, userp, &req);
7889 openAction = 3; /* truncated existing file */
7892 openAction = 1; /* found existing file */
7894 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7895 /* don't create if not found */
7897 cm_ReleaseSCache(dscp);
7899 cm_ReleaseSCache(scp);
7900 cm_ReleaseUser(userp);
7902 return CM_ERROR_NOSUCHFILE;
7903 } else if (realDirFlag == 0 || realDirFlag == -1) {
7904 osi_assertx(dscp != NULL, "null cm_scache_t");
7905 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %S",
7906 osi_LogSaveClientString(smb_logp, lastNamep));
7907 openAction = 2; /* created file */
7908 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7909 setAttr.clientModTime = time(NULL);
7910 smb_SetInitialModeBitsForFile(extAttributes, &setAttr);
7912 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
7915 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7916 smb_NotifyChange(FILE_ACTION_ADDED,
7917 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7918 dscp, lastNamep, NULL, TRUE);
7919 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7920 /* Not an exclusive create, and someone else tried
7921 * creating it already, then we open it anyway. We
7922 * don't bother retrying after this, since if this next
7923 * fails, that means that the file was deleted after we
7924 * started this call.
7926 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7929 if (createDisp == FILE_OVERWRITE_IF) {
7930 setAttr.mask = CM_ATTRMASK_LENGTH;
7931 setAttr.length.LowPart = 0;
7932 setAttr.length.HighPart = 0;
7934 /* now watch for a symlink */
7936 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7938 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7940 /* we have a more accurate file to use (the
7941 * target of the symbolic link). Otherwise,
7942 * we'll just use the symlink anyway.
7944 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7946 cm_ReleaseSCache(scp);
7950 code = cm_SetAttr(scp, &setAttr, userp, &req);
7952 } /* lookup succeeded */
7955 clientchar_t *tp, *pp;
7956 clientchar_t *cp; /* This component */
7957 int clen = 0; /* length of component */
7958 cm_scache_t *tscp1, *tscp2;
7961 /* create directory */
7963 treeStartp = lastNamep;
7964 osi_assertx(dscp != NULL, "null cm_scache_t");
7965 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%S]",
7966 osi_LogSaveClientString(smb_logp, treeStartp));
7967 openAction = 2; /* created directory */
7969 /* if the request is to create the root directory
7970 * it will appear as a directory name of the nul-string
7971 * and a code of CM_ERROR_NOSUCHFILE
7973 if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
7974 code = CM_ERROR_EXISTS;
7976 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7977 setAttr.clientModTime = time(NULL);
7978 smb_SetInitialModeBitsForDir(extAttributes, &setAttr);
7983 cm_HoldSCache(tscp1);
7987 tp = cm_ClientStrChr(pp, '\\');
7989 cm_ClientStrCpy(cp, lengthof(spacep->wdata) - (cp - spacep->wdata), pp);
7990 clen = (int)cm_ClientStrLen(cp);
7991 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
7993 clen = (int)(tp - pp);
7994 cm_ClientStrCpyN(cp, lengthof(spacep->wdata) - (cp - spacep->wdata),
8002 continue; /* the supplied path can't have consecutive slashes either , but */
8004 /* cp is the next component to be created. */
8005 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req, NULL);
8006 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
8007 smb_NotifyChange(FILE_ACTION_ADDED,
8008 FILE_NOTIFY_CHANGE_DIR_NAME,
8009 tscp1, cp, NULL, TRUE);
8011 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
8012 /* Not an exclusive create, and someone else tried
8013 * creating it already, then we open it anyway. We
8014 * don't bother retrying after this, since if this next
8015 * fails, that means that the file was deleted after we
8016 * started this call.
8018 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
8019 userp, &req, &tscp2);
8024 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
8025 cm_ReleaseSCache(tscp1);
8026 tscp1 = tscp2; /* Newly created directory will be next parent */
8027 /* the hold is transfered to tscp1 from tscp2 */
8032 cm_ReleaseSCache(dscp);
8035 cm_ReleaseSCache(scp);
8038 * if we get here and code == 0, then scp is the last directory created, and dscp is the
8044 /* something went wrong creating or truncating the file */
8045 if (checkDoneRequired)
8046 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8048 cm_ReleaseSCache(scp);
8050 cm_ReleaseSCache(dscp);
8051 cm_ReleaseUser(userp);
8056 /* make sure we have file vs. dir right (only applies for single component case) */
8057 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
8058 /* now watch for a symlink */
8060 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8061 cm_scache_t * targetScp = 0;
8062 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8064 /* we have a more accurate file to use (the
8065 * target of the symbolic link). Otherwise,
8066 * we'll just use the symlink anyway.
8068 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
8069 if (checkDoneRequired) {
8070 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8071 checkDoneRequired = 0;
8073 cm_ReleaseSCache(scp);
8078 if (scp->fileType != CM_SCACHETYPE_FILE) {
8079 if (checkDoneRequired)
8080 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8082 cm_ReleaseSCache(dscp);
8083 cm_ReleaseSCache(scp);
8084 cm_ReleaseUser(userp);
8086 return CM_ERROR_ISDIR;
8090 /* (only applies to single component case) */
8091 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8092 if (checkDoneRequired)
8093 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8094 cm_ReleaseSCache(scp);
8096 cm_ReleaseSCache(dscp);
8097 cm_ReleaseUser(userp);
8099 return CM_ERROR_NOTDIR;
8102 /* open the file itself */
8103 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8104 osi_assertx(fidp, "null smb_fid_t");
8106 /* save a reference to the user */
8108 fidp->userp = userp;
8110 /* If we are restricting sharing, we should do so with a suitable
8112 if (scp->fileType == CM_SCACHETYPE_FILE &&
8113 !(fidflags & SMB_FID_SHARE_WRITE)) {
8115 LARGE_INTEGER LOffset, LLength;
8118 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8119 LOffset.LowPart = SMB_FID_QLOCK_LOW;
8120 LLength.HighPart = 0;
8121 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8123 /* If we are not opening the file for writing, then we don't
8124 try to get an exclusive lock. No one else should be able to
8125 get an exclusive lock on the file anyway, although someone
8126 else can get a shared lock. */
8127 if ((fidflags & SMB_FID_SHARE_READ) ||
8128 !(fidflags & SMB_FID_OPENWRITE)) {
8129 sLockType = LOCKING_ANDX_SHARED_LOCK;
8134 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8136 lock_ObtainWrite(&scp->rw);
8137 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8138 lock_ReleaseWrite(&scp->rw);
8141 if (checkDoneRequired)
8142 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8143 cm_ReleaseSCache(scp);
8145 cm_ReleaseSCache(dscp);
8146 cm_ReleaseUser(userp);
8147 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
8148 smb_CloseFID(vcp, fidp, NULL, 0);
8149 smb_ReleaseFID(fidp);
8151 return CM_ERROR_SHARING_VIOLATION;
8155 /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
8156 if (checkDoneRequired) {
8157 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8158 checkDoneRequired = 0;
8161 lock_ObtainMutex(&fidp->mx);
8162 /* save a pointer to the vnode */
8163 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
8164 lock_ObtainWrite(&scp->rw);
8165 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8166 lock_ReleaseWrite(&scp->rw);
8167 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
8169 fidp->flags = fidflags;
8171 /* remember if the file was newly created */
8173 fidp->flags |= SMB_FID_CREATED;
8175 /* save parent dir and pathname for delete or change notification */
8176 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8177 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
8178 fidp->flags |= SMB_FID_NTOPEN;
8179 fidp->NTopen_dscp = dscp;
8181 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
8183 fidp->NTopen_wholepathp = realPathp;
8184 lock_ReleaseMutex(&fidp->mx);
8186 /* we don't need this any longer */
8188 cm_ReleaseSCache(dscp);
8192 cm_Open(scp, 0, userp);
8194 /* set inp->fid so that later read calls in same msg can find fid */
8195 inp->fid = fidp->fid;
8197 lock_ObtainRead(&scp->rw);
8200 * Always send the standard response. Sending the extended
8201 * response results in the Explorer Shell being unable to
8202 * access directories at random times.
8204 if (1 /*!extendedRespRequired */) {
8207 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
8208 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
8209 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
8210 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8211 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8212 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8213 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8214 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8215 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
8217 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8218 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8219 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
8220 smb_SetSMBParm(outp, parmSlot, NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS);
8221 parmSlot++; /* dev state */
8222 smb_SetSMBParmByte(outp, parmSlot,
8223 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8224 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8225 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
8226 smb_SetSMBDataLength(outp, 0);
8230 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
8231 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
8232 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
8233 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8234 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8235 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8236 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8237 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8238 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
8240 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8241 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8242 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
8243 smb_SetSMBParm(outp, parmSlot, NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS);
8244 parmSlot++; /* dev state */
8245 smb_SetSMBParmByte(outp, parmSlot,
8246 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8247 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8248 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
8249 /* Setting the GUID results in a failure with cygwin */
8250 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8251 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8252 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8253 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8254 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8255 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8256 /* Maxmimal access rights */
8257 smb_SetSMBParmLong(outp, parmSlot, 0x001f01ff); parmSlot += 2;
8258 /* Guest access rights */
8259 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8260 smb_SetSMBDataLength(outp, 0);
8263 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
8264 LargeIntegerGreaterThanZero(scp->length) &&
8265 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
8268 lock_ReleaseRead(&scp->rw);
8271 cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
8272 scp->length.LowPart, scp->length.HighPart,
8276 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %S", fidp->fid,
8277 osi_LogSaveClientString(smb_logp, realPathp));
8279 cm_ReleaseUser(userp);
8280 smb_ReleaseFID(fidp);
8282 /* Can't free realPathp if we get here since
8283 fidp->NTopen_wholepathp is pointing there */
8285 /* leave scp held since we put it in fidp->scp */
8290 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
8291 * Instead, ultimately, would like to use a subroutine for common code.
8294 /* NT_TRANSACT_CREATE (SMB_COM_NT_TRANSACT) */
8295 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8297 clientchar_t *pathp, *realPathp;
8301 cm_scache_t *dscp; /* parent dir */
8302 cm_scache_t *scp; /* file to create or open */
8303 cm_scache_t *targetScp; /* if scp is a symlink */
8305 clientchar_t *lastNamep;
8306 unsigned long nameLength;
8308 unsigned int requestOpLock;
8309 unsigned int requestBatchOpLock;
8310 unsigned int mustBeDir;
8311 unsigned int extendedRespRequired;
8313 unsigned int desiredAccess;
8314 unsigned int allocSize;
8315 unsigned int shareAccess;
8316 unsigned int extAttributes;
8317 unsigned int createDisp;
8320 unsigned int impLevel;
8321 unsigned int secFlags;
8322 unsigned int createOptions;
8323 unsigned short baseFid;
8324 smb_fid_t *baseFidp;
8326 cm_scache_t *baseDirp;
8327 unsigned short openAction;
8331 clientchar_t *tidPathp;
8333 int parmOffset, dataOffset;
8340 cm_lock_data_t *ldp = NULL;
8341 int checkDoneRequired = 0;
8348 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8349 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8350 parmp = inp->data + parmOffset;
8351 lparmp = (ULONG *) parmp;
8354 requestOpLock = flags & REQUEST_OPLOCK;
8355 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
8356 mustBeDir = flags & OPEN_DIRECTORY;
8357 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
8360 * Why all of a sudden 32-bit FID?
8361 * We will reject all bits higher than 16.
8363 if (lparmp[1] & 0xFFFF0000)
8364 return CM_ERROR_INVAL;
8365 baseFid = (unsigned short)lparmp[1];
8366 desiredAccess = lparmp[2];
8367 allocSize = lparmp[3];
8368 extAttributes = lparmp[5];
8369 shareAccess = lparmp[6];
8370 createDisp = lparmp[7];
8371 createOptions = lparmp[8];
8374 nameLength = lparmp[11]; /* spec says chars but appears to be bytes */
8375 impLevel = lparmp[12];
8376 secFlags = lparmp[13];
8378 /* mustBeDir is never set; createOptions directory bit seems to be
8381 if (createOptions & FILE_DIRECTORY_FILE)
8383 else if (createOptions & FILE_NON_DIRECTORY_FILE)
8388 pathp = smb_ParseStringCb(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
8389 nameLength, NULL, SMB_STRF_ANSIPATH);
8390 /* Sometimes path is not nul-terminated, so we make a copy. */
8391 realPathp = malloc(nameLength+sizeof(clientchar_t));
8392 memcpy(realPathp, pathp, nameLength);
8393 realPathp[nameLength/sizeof(clientchar_t)] = 0;
8394 spacep = cm_GetSpace();
8395 /* smb_StripLastComponent will strip "::$DATA" if present */
8396 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
8398 osi_Log1(smb_logp,"NTTranCreate %S",osi_LogSaveStringW(smb_logp,realPathp));
8399 osi_Log4(smb_logp,"... da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
8400 osi_Log4(smb_logp,"... co[%x],sdl[%x],eal[%x],as[%x],flags[%x]",createOptions,sdLen,eaLen,allocSize);
8401 osi_Log3(smb_logp,"... imp[%x],sec[%x],flags[%x]", impLevel, secFlags, flags);
8403 if ( realDirFlag == 1 &&
8404 ( createDisp == FILE_SUPERSEDE ||
8405 createDisp == FILE_OVERWRITE ||
8406 createDisp == FILE_OVERWRITE_IF))
8408 osi_Log0(smb_logp, "NTTranCreate rejecting invalid readDirFlag and createDisp combination");
8409 cm_FreeSpace(spacep);
8411 return CM_ERROR_INVAL;
8415 * Nothing here to handle SMB_IOCTL_FILENAME.
8416 * Will add it if necessary.
8419 if (!cm_IsValidClientString(realPathp)) {
8421 clientchar_t * hexp;
8423 hexp = cm_GetRawCharsAlloc(realPathp, -1);
8424 osi_Log1(smb_logp, "NTTranCreate rejecting invalid name. [%S]",
8425 osi_LogSaveClientString(smb_logp, hexp));
8429 osi_Log0(smb_logp, "NTTranCreate rejecting invalid name.");
8431 cm_FreeSpace(spacep);
8433 return CM_ERROR_BADNTFILENAME;
8436 userp = smb_GetUserFromVCP(vcp, inp);
8438 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
8439 cm_FreeSpace(spacep);
8441 return CM_ERROR_INVAL;
8446 baseDirp = cm_RootSCachep(cm_rootUserp, &req);
8447 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8448 if (code == CM_ERROR_TIDIPC) {
8449 /* Attempt to use a TID allocated for IPC. The client
8450 * is probably looking for DCE RPC end points which we
8451 * don't support OR it could be looking to make a DFS
8454 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
8456 cm_FreeSpace(spacep);
8458 cm_ReleaseUser(userp);
8459 return CM_ERROR_NOSUCHPATH;
8463 baseFidp = smb_FindFID(vcp, baseFid, 0);
8465 osi_Log2(smb_logp, "NTTranCreate Unknown SMB Fid vcp 0x%p fid %d",
8467 cm_FreeSpace(spacep);
8469 cm_ReleaseUser(userp);
8470 return CM_ERROR_BADFD;
8473 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8474 cm_FreeSpace(spacep);
8476 cm_ReleaseUser(userp);
8477 smb_CloseFID(vcp, baseFidp, NULL, 0);
8478 smb_ReleaseFID(baseFidp);
8479 return CM_ERROR_NOSUCHPATH;
8482 baseDirp = baseFidp->scp;
8486 /* compute open mode */
8488 if (desiredAccess & DELETE)
8489 fidflags |= SMB_FID_OPENDELETE;
8490 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
8491 fidflags |= SMB_FID_OPENREAD_LISTDIR;
8492 if (desiredAccess & AFS_ACCESS_WRITE)
8493 fidflags |= SMB_FID_OPENWRITE;
8494 if (createOptions & FILE_DELETE_ON_CLOSE)
8495 fidflags |= SMB_FID_DELONCLOSE;
8496 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
8497 fidflags |= SMB_FID_SEQUENTIAL;
8498 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
8499 fidflags |= SMB_FID_RANDOM;
8500 if (createOptions & FILE_OPEN_REPARSE_POINT)
8501 osi_Log0(smb_logp, "NTTranCreate Open Reparse Point");
8502 if (smb_IsExecutableFileName(lastNamep))
8503 fidflags |= SMB_FID_EXECUTABLE;
8505 /* And the share mode */
8506 if (shareAccess & FILE_SHARE_READ)
8507 fidflags |= SMB_FID_SHARE_READ;
8508 if (shareAccess & FILE_SHARE_WRITE)
8509 fidflags |= SMB_FID_SHARE_WRITE;
8514 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8515 userp, tidPathp, &req, &dscp);
8518 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8519 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8520 cm_ReleaseSCache(dscp);
8521 cm_ReleaseUser(userp);
8522 cm_FreeSpace(spacep);
8525 smb_ReleaseFID(baseFidp);
8526 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8527 return CM_ERROR_PATH_NOT_COVERED;
8529 return CM_ERROR_NOSUCHPATH;
8531 #endif /* DFS_SUPPORT */
8532 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
8534 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
8536 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
8537 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
8538 if (code == 0 && realDirFlag == 1 &&
8539 (createDisp == FILE_OPEN ||
8540 createDisp == FILE_OVERWRITE ||
8541 createDisp == FILE_OVERWRITE_IF)) {
8542 cm_ReleaseSCache(scp);
8543 cm_ReleaseSCache(dscp);
8544 cm_ReleaseUser(userp);
8545 cm_FreeSpace(spacep);
8548 smb_ReleaseFID(baseFidp);
8549 return CM_ERROR_EXISTS;
8553 cm_ReleaseUser(userp);
8555 smb_ReleaseFID(baseFidp);
8556 cm_FreeSpace(spacep);
8558 return CM_ERROR_NOSUCHPATH;
8564 if (code == CM_ERROR_NOSUCHFILE ||
8565 code == CM_ERROR_NOSUCHPATH ||
8566 code == CM_ERROR_BPLUS_NOMATCH ||
8567 (code == 0 && (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)))) {
8570 cm_FreeSpace(spacep);
8573 smb_ReleaseFID(baseFidp);
8576 cm_ReleaseSCache(dscp);
8577 cm_ReleaseUser(userp);
8583 lastNamep = realPathp;
8587 if (!smb_IsLegalFilename(lastNamep)) {
8588 cm_ReleaseSCache(dscp);
8589 cm_ReleaseUser(userp);
8591 return CM_ERROR_BADNTFILENAME;
8595 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF || createDisp == FILE_OPEN_IF) {
8596 code = cm_Lookup(dscp, lastNamep,
8597 CM_FLAG_FOLLOW, userp, &req, &scp);
8599 code = cm_Lookup(dscp, lastNamep,
8600 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8603 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8604 cm_ReleaseSCache(dscp);
8605 cm_ReleaseUser(userp);
8612 smb_ReleaseFID(baseFidp);
8613 cm_FreeSpace(spacep);
8616 /* if we get here, if code is 0, the file exists and is represented by
8617 * scp. Otherwise, we have to create it. The dir may be represented
8618 * by dscp, or we may have found the file directly. If code is non-zero,
8622 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
8624 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8625 cm_ReleaseSCache(dscp);
8626 cm_ReleaseSCache(scp);
8627 cm_ReleaseUser(userp);
8631 checkDoneRequired = 1;
8633 if (createDisp == FILE_CREATE) {
8634 /* oops, file shouldn't be there */
8635 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8636 cm_ReleaseSCache(dscp);
8637 cm_ReleaseSCache(scp);
8638 cm_ReleaseUser(userp);
8640 return CM_ERROR_EXISTS;
8643 if (createDisp == FILE_OVERWRITE ||
8644 createDisp == FILE_OVERWRITE_IF) {
8645 setAttr.mask = CM_ATTRMASK_LENGTH;
8646 setAttr.length.LowPart = 0;
8647 setAttr.length.HighPart = 0;
8649 /* now watch for a symlink */
8651 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8653 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8655 /* we have a more accurate file to use (the
8656 * target of the symbolic link). Otherwise,
8657 * we'll just use the symlink anyway.
8659 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8661 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8662 cm_ReleaseSCache(scp);
8664 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
8666 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8667 cm_ReleaseSCache(dscp);
8669 cm_ReleaseSCache(scp);
8670 cm_ReleaseUser(userp);
8676 code = cm_SetAttr(scp, &setAttr, userp, &req);
8677 openAction = 3; /* truncated existing file */
8679 else openAction = 1; /* found existing file */
8681 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
8682 /* don't create if not found */
8683 cm_ReleaseSCache(dscp);
8684 cm_ReleaseUser(userp);
8686 return CM_ERROR_NOSUCHFILE;
8688 else if (realDirFlag == 0 || realDirFlag == -1) {
8689 /* createDisp: FILE_SUPERSEDE, FILE_CREATE, FILE_OPEN_IF, FILE_OVERWRITE_IF */
8690 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %S",
8691 osi_LogSaveClientString(smb_logp, lastNamep));
8692 openAction = 2; /* created file */
8693 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8694 setAttr.clientModTime = time(NULL);
8695 smb_SetInitialModeBitsForFile(extAttributes, &setAttr);
8697 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8701 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8702 smb_NotifyChange(FILE_ACTION_ADDED,
8703 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8704 dscp, lastNamep, NULL, TRUE);
8705 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
8706 /* Not an exclusive create, and someone else tried
8707 * creating it already, then we open it anyway. We
8708 * don't bother retrying after this, since if this next
8709 * fails, that means that the file was deleted after we
8710 * started this call.
8712 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8715 if (createDisp == FILE_OVERWRITE_IF) {
8716 setAttr.mask = CM_ATTRMASK_LENGTH;
8717 setAttr.length.LowPart = 0;
8718 setAttr.length.HighPart = 0;
8720 /* now watch for a symlink */
8722 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8724 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8726 /* we have a more accurate file to use (the
8727 * target of the symbolic link). Otherwise,
8728 * we'll just use the symlink anyway.
8730 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8732 cm_ReleaseSCache(scp);
8736 code = cm_SetAttr(scp, &setAttr, userp, &req);
8738 } /* lookup succeeded */
8741 /* create directory; createDisp: FILE_CREATE, FILE_OPEN_IF */
8743 "smb_ReceiveNTTranCreate creating directory %S",
8744 osi_LogSaveClientString(smb_logp, lastNamep));
8745 openAction = 2; /* created directory */
8746 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8747 setAttr.clientModTime = time(NULL);
8748 smb_SetInitialModeBitsForDir(extAttributes, &setAttr);
8750 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8751 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8752 smb_NotifyChange(FILE_ACTION_ADDED,
8753 FILE_NOTIFY_CHANGE_DIR_NAME,
8754 dscp, lastNamep, NULL, TRUE);
8756 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
8757 /* Not an exclusive create, and someone else tried
8758 * creating it already, then we open it anyway. We
8759 * don't bother retrying after this, since if this next
8760 * fails, that means that the file was deleted after we
8761 * started this call.
8763 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8769 /* something went wrong creating or truncating the file */
8770 if (checkDoneRequired)
8771 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8773 cm_ReleaseSCache(scp);
8774 cm_ReleaseUser(userp);
8779 /* make sure we have file vs. dir right */
8780 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
8781 /* now watch for a symlink */
8783 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8785 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8787 /* we have a more accurate file to use (the
8788 * target of the symbolic link). Otherwise,
8789 * we'll just use the symlink anyway.
8791 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8793 if (checkDoneRequired) {
8794 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8795 checkDoneRequired = 0;
8797 cm_ReleaseSCache(scp);
8802 if (scp->fileType != CM_SCACHETYPE_FILE) {
8803 if (checkDoneRequired)
8804 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8805 cm_ReleaseSCache(scp);
8806 cm_ReleaseUser(userp);
8808 return CM_ERROR_ISDIR;
8812 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8813 if (checkDoneRequired)
8814 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8815 cm_ReleaseSCache(scp);
8816 cm_ReleaseUser(userp);
8818 return CM_ERROR_NOTDIR;
8821 /* open the file itself */
8822 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8823 osi_assertx(fidp, "null smb_fid_t");
8825 /* save a reference to the user */
8827 fidp->userp = userp;
8829 /* If we are restricting sharing, we should do so with a suitable
8831 if (scp->fileType == CM_SCACHETYPE_FILE &&
8832 !(fidflags & SMB_FID_SHARE_WRITE)) {
8834 LARGE_INTEGER LOffset, LLength;
8837 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8838 LOffset.LowPart = SMB_FID_QLOCK_LOW;
8839 LLength.HighPart = 0;
8840 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8842 /* Similar to what we do in handling NTCreateX. We get a
8843 shared lock if we are only opening the file for reading. */
8844 if ((fidflags & SMB_FID_SHARE_READ) ||
8845 !(fidflags & SMB_FID_OPENWRITE)) {
8846 sLockType = LOCKING_ANDX_SHARED_LOCK;
8851 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8853 lock_ObtainWrite(&scp->rw);
8854 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8855 lock_ReleaseWrite(&scp->rw);
8858 if (checkDoneRequired)
8859 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8860 cm_ReleaseSCache(scp);
8861 cm_ReleaseUser(userp);
8862 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
8863 smb_CloseFID(vcp, fidp, NULL, 0);
8864 smb_ReleaseFID(fidp);
8866 return CM_ERROR_SHARING_VIOLATION;
8870 /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
8871 if (checkDoneRequired) {
8872 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8873 checkDoneRequired = 0;
8876 lock_ObtainMutex(&fidp->mx);
8877 /* save a pointer to the vnode */
8879 lock_ObtainWrite(&scp->rw);
8880 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8881 lock_ReleaseWrite(&scp->rw);
8882 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
8884 fidp->flags = fidflags;
8886 /* remember if the file was newly created */
8888 fidp->flags |= SMB_FID_CREATED;
8890 /* save parent dir and pathname for deletion or change notification */
8891 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8892 fidp->flags |= SMB_FID_NTOPEN;
8893 fidp->NTopen_dscp = dscp;
8894 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
8896 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
8898 fidp->NTopen_wholepathp = realPathp;
8899 lock_ReleaseMutex(&fidp->mx);
8901 /* we don't need this any longer */
8903 cm_ReleaseSCache(dscp);
8905 cm_Open(scp, 0, userp);
8907 /* set inp->fid so that later read calls in same msg can find fid */
8908 inp->fid = fidp->fid;
8910 /* check whether we are required to send an extended response */
8911 if (!extendedRespRequired) {
8913 parmOffset = 8*4 + 39;
8914 parmOffset += 1; /* pad to 4 */
8915 dataOffset = parmOffset + 70;
8919 /* Total Parameter Count */
8920 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8921 /* Total Data Count */
8922 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8923 /* Parameter Count */
8924 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8925 /* Parameter Offset */
8926 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8927 /* Parameter Displacement */
8928 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8930 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8932 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8933 /* Data Displacement */
8934 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8935 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8936 smb_SetSMBDataLength(outp, 70);
8938 lock_ObtainRead(&scp->rw);
8939 outData = smb_GetSMBData(outp, NULL);
8940 outData++; /* round to get to parmOffset */
8941 *outData = 0; outData++; /* oplock */
8942 *outData = 0; outData++; /* reserved */
8943 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8944 *((ULONG *)outData) = openAction; outData += 4;
8945 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8946 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8947 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8948 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8949 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8950 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8951 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8952 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8953 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8954 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8955 *((USHORT *)outData) = NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS;
8956 outData += 2; /* dev state */
8957 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8958 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8959 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8960 outData += 2; /* is a dir? */
8963 parmOffset = 8*4 + 39;
8964 parmOffset += 1; /* pad to 4 */
8965 dataOffset = parmOffset + 104;
8969 /* Total Parameter Count */
8970 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8971 /* Total Data Count */
8972 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8973 /* Parameter Count */
8974 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8975 /* Parameter Offset */
8976 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8977 /* Parameter Displacement */
8978 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8980 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8982 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8983 /* Data Displacement */
8984 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8985 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8986 smb_SetSMBDataLength(outp, 105);
8988 lock_ObtainRead(&scp->rw);
8989 outData = smb_GetSMBData(outp, NULL);
8990 outData++; /* round to get to parmOffset */
8991 *outData = 0; outData++; /* oplock */
8992 *outData = 1; outData++; /* response type */
8993 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8994 *((ULONG *)outData) = openAction; outData += 4;
8995 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8996 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8997 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8998 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8999 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
9000 *((FILETIME *)outData) = ft; outData += 8; /* change time */
9001 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
9002 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
9003 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
9004 *((USHORT *)outData) = 0; outData += 2; /* filetype */
9005 *((USHORT *)outData) = NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS;
9006 outData += 2; /* dev state */
9007 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
9008 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
9009 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
9010 outData += 1; /* is a dir? */
9011 /* Setting the GUID results in failures with cygwin */
9012 memset(outData,0,24); outData += 24; /* GUID */
9013 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
9014 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
9017 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
9018 LargeIntegerGreaterThanZero(scp->length) &&
9019 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
9022 lock_ReleaseRead(&scp->rw);
9025 cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
9026 scp->length.LowPart, scp->length.HighPart,
9029 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
9031 cm_ReleaseUser(userp);
9032 smb_ReleaseFID(fidp);
9034 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
9035 /* leave scp held since we put it in fidp->scp */
9039 /* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
9040 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
9043 smb_packet_t *savedPacketp;
9045 USHORT fid, watchtree;
9049 filter = smb_GetSMBParm(inp, 19) |
9050 (smb_GetSMBParm(inp, 20) << 16);
9051 fid = smb_GetSMBParm(inp, 21);
9052 watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
9054 fidp = smb_FindFID(vcp, fid, 0);
9056 osi_Log2(smb_logp, "NotifyChange Unknown SMB Fid vcp 0x%p fid %d",
9058 return CM_ERROR_BADFD;
9061 lock_ObtainMutex(&fidp->mx);
9062 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
9063 lock_ReleaseMutex(&fidp->mx);
9064 smb_CloseFID(vcp, fidp, NULL, 0);
9065 smb_ReleaseFID(fidp);
9066 return CM_ERROR_NOSUCHFILE;
9070 lock_ReleaseMutex(&fidp->mx);
9072 /* Create a copy of the Directory Watch Packet to use when sending the
9073 * notification if in the future a matching change is detected.
9075 savedPacketp = smb_CopyPacket(inp);
9076 if (vcp != savedPacketp->vcp) {
9078 if (savedPacketp->vcp)
9079 smb_ReleaseVC(savedPacketp->vcp);
9080 savedPacketp->vcp = vcp;
9083 /* Add the watch to the list of events to send notifications for */
9084 lock_ObtainMutex(&smb_Dir_Watch_Lock);
9085 savedPacketp->nextp = smb_Directory_Watches;
9086 smb_Directory_Watches = savedPacketp;
9087 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9089 osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%S\"",
9090 fidp, scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp));
9091 osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
9092 filter, fid, watchtree);
9093 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
9094 osi_Log0(smb_logp, " Notify Change File Name");
9095 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
9096 osi_Log0(smb_logp, " Notify Change Directory Name");
9097 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
9098 osi_Log0(smb_logp, " Notify Change Attributes");
9099 if (filter & FILE_NOTIFY_CHANGE_SIZE)
9100 osi_Log0(smb_logp, " Notify Change Size");
9101 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
9102 osi_Log0(smb_logp, " Notify Change Last Write");
9103 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
9104 osi_Log0(smb_logp, " Notify Change Last Access");
9105 if (filter & FILE_NOTIFY_CHANGE_CREATION)
9106 osi_Log0(smb_logp, " Notify Change Creation");
9107 if (filter & FILE_NOTIFY_CHANGE_EA)
9108 osi_Log0(smb_logp, " Notify Change Extended Attributes");
9109 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
9110 osi_Log0(smb_logp, " Notify Change Security");
9111 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
9112 osi_Log0(smb_logp, " Notify Change Stream Name");
9113 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
9114 osi_Log0(smb_logp, " Notify Change Stream Size");
9115 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
9116 osi_Log0(smb_logp, " Notify Change Stream Write");
9118 lock_ObtainWrite(&scp->rw);
9120 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
9122 scp->flags |= CM_SCACHEFLAG_WATCHED;
9123 lock_ReleaseWrite(&scp->rw);
9124 cm_ReleaseSCache(scp);
9125 smb_ReleaseFID(fidp);
9127 outp->flags |= SMB_PACKETFLAG_NOSEND;
9131 unsigned char nullSecurityDesc[] = {
9132 0x01, /* security descriptor revision */
9133 0x00, /* reserved, should be zero */
9134 0x04, 0x80, /* security descriptor control;
9135 * 0x0004 : null-DACL present - everyone has full access
9136 * 0x8000 : relative format */
9137 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
9138 0x20, 0x00, 0x00, 0x00, /* offset of group SID */
9139 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
9140 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
9141 0x01, 0x01, 0x00, 0x00, /* "everyone SID" owner SID */
9142 0x00, 0x00, 0x00, 0x01,
9143 0x00, 0x00, 0x00, 0x00,
9144 0x01, 0x01, 0x00, 0x00, /* "everyone SID" owner SID */
9145 0x00, 0x00, 0x00, 0x01,
9146 0x00, 0x00, 0x00, 0x00
9149 /* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
9150 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9152 int parmOffset, parmCount, dataOffset, dataCount;
9153 int totalParmCount, totalDataCount;
9155 int maxData, maxParm;
9156 int inTotalParm, inTotalData;
9158 int inParmOffset, inDataOffset;
9164 ULONG securityInformation;
9170 * For details on the meanings of the various
9171 * SMB_COM_TRANSACTION fields, see sections 2.2.4.33
9172 * of http://msdn.microsoft.com/en-us/library/ee442092%28PROT.13%29.aspx
9175 inTotalParm = smb_GetSMBOffsetParm(inp, 1, 1)
9176 | (smb_GetSMBOffsetParm(inp, 2, 1) << 16);
9178 inTotalData = smb_GetSMBOffsetParm(inp, 3, 1)
9179 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
9181 maxParm = smb_GetSMBOffsetParm(inp, 5, 1)
9182 | (smb_GetSMBOffsetParm(inp, 6, 1) << 16);
9184 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
9185 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
9187 inParm = smb_GetSMBOffsetParm(inp, 9, 1)
9188 | (smb_GetSMBOffsetParm(inp, 10, 1) << 16);
9190 inParmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
9191 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
9193 inData = smb_GetSMBOffsetParm(inp, 13, 1)
9194 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
9196 inDataOffset = smb_GetSMBOffsetParm(inp, 15, 1)
9197 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
9199 parmp = inp->data + inParmOffset;
9200 sparmp = (USHORT *) parmp;
9201 lparmp = (ULONG *) parmp;
9204 securityInformation = lparmp[1];
9206 fidp = smb_FindFID(vcp, fid, 0);
9208 osi_Log2(smb_logp, "smb_ReceiveNTTranQuerySecurityDesc Unknown SMB Fid vcp 0x%p fid %d",
9210 return CM_ERROR_BADFD;
9213 lock_ObtainMutex(&fidp->mx);
9214 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
9215 lock_ReleaseMutex(&fidp->mx);
9216 smb_CloseFID(vcp, fidp, NULL, 0);
9217 smb_ReleaseFID(fidp);
9218 return CM_ERROR_NOSUCHFILE;
9220 lock_ReleaseMutex(&fidp->mx);
9222 osi_Log4(smb_logp,"smb_ReceiveNTTranQuerySecurityDesc fidp 0x%p scp 0x%p file \"%S\" Info=0x%x",
9223 fidp, fidp->scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp),
9224 securityInformation);
9226 smb_ReleaseFID(fidp);
9228 if ( securityInformation & ~(OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION) )
9230 code = CM_ERROR_BAD_LEVEL;
9234 dwLength = sizeof( nullSecurityDesc);
9236 totalDataCount = dwLength;
9239 if (maxData >= totalDataCount) {
9240 dataCount = totalDataCount;
9241 parmCount = min(totalParmCount, maxParm);
9242 } else if (maxParm >= totalParmCount) {
9243 totalDataCount = dataCount = 0;
9244 parmCount = totalParmCount;
9246 totalDataCount = dataCount = 0;
9247 totalParmCount = parmCount = 0;
9251 parmOffset = 8*4 + 39;
9252 parmOffset += 1; /* pad to 4 */
9254 dataOffset = parmOffset + parmCount;
9258 /* Total Parameter Count */
9259 smb_SetSMBParmLong(outp, parmSlot, totalParmCount); parmSlot += 2;
9260 /* Total Data Count */
9261 smb_SetSMBParmLong(outp, parmSlot, totalDataCount); parmSlot += 2;
9262 /* Parameter Count */
9263 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
9264 /* Parameter Offset */
9265 smb_SetSMBParmLong(outp, parmSlot, parmCount ? parmOffset : 0); parmSlot += 2;
9266 /* Parameter Displacement */
9267 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9269 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
9271 smb_SetSMBParmLong(outp, parmSlot, dataCount ? dataOffset : 0); parmSlot += 2;
9272 /* Data Displacement */
9273 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9275 smb_SetSMBParmByte(outp, parmSlot, 0);
9277 if (parmCount == totalParmCount && dwLength == dataCount) {
9278 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
9281 outData = smb_GetSMBData(outp, NULL);
9282 outData++; /* round to get to dataOffset */
9284 *((ULONG *)outData) = dataCount; outData += 4; /* SD Length (4 bytes) */
9285 memcpy(outData, nullSecurityDesc, dataCount);
9286 outData += dataCount;
9289 } else if (parmCount >= 4) {
9290 smb_SetSMBDataLength(outp, 1 + parmCount);
9293 outData = smb_GetSMBData(outp, NULL);
9294 outData++; /* round to get to dataOffset */
9296 *((ULONG *)outData) = dwLength; outData += 4; /* SD Length (4 bytes) */
9297 code = CM_ERROR_BUFFERTOOSMALL;
9299 smb_SetSMBDataLength(outp, 0);
9300 code = CM_ERROR_BUFFER_OVERFLOW;
9307 /* SMB_COM_NT_TRANSACT
9309 SMB_COM_NT_TRANSACT_SECONDARY should also be handled here.
9311 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9313 unsigned short function;
9315 function = smb_GetSMBParm(inp, 18);
9317 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
9319 /* We can handle long names */
9320 if (vcp->flags & SMB_VCFLAG_USENT)
9321 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
9324 case 1: /* NT_TRANSACT_CREATE */
9325 return smb_ReceiveNTTranCreate(vcp, inp, outp);
9326 case 2: /* NT_TRANSACT_IOCTL */
9327 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
9329 case 3: /* NT_TRANSACT_SET_SECURITY_DESC */
9330 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
9332 case 4: /* NT_TRANSACT_NOTIFY_CHANGE */
9333 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
9334 case 5: /* NT_TRANSACT_RENAME */
9335 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
9337 case 6: /* NT_TRANSACT_QUERY_SECURITY_DESC */
9338 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
9340 osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
9343 osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
9346 return CM_ERROR_BADOP;
9350 * smb_NotifyChange -- find relevant change notification messages and
9353 * If we don't know the file name (i.e. a callback break), filename is
9354 * NULL, and we return a zero-length list.
9356 * At present there is not a single call to smb_NotifyChange that
9357 * has the isDirectParent parameter set to FALSE.
9359 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
9360 cm_scache_t *dscp, clientchar_t *filename, clientchar_t *otherFilename,
9361 BOOL isDirectParent)
9363 smb_packet_t *watch, *lastWatch, *nextWatch;
9364 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen = 0;
9365 char *outData, *oldOutData;
9369 BOOL twoEntries = FALSE;
9370 ULONG otherNameLen, oldParmCount = 0;
9374 /* Get ready for rename within directory */
9375 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
9377 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
9380 osi_Log4(smb_logp,"in smb_NotifyChange for file [%S] dscp [%p] notification 0x%x parent %d",
9381 osi_LogSaveClientString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
9383 osi_Log0(smb_logp," FILE_ACTION_NONE");
9384 if (action == FILE_ACTION_ADDED)
9385 osi_Log0(smb_logp," FILE_ACTION_ADDED");
9386 if (action == FILE_ACTION_REMOVED)
9387 osi_Log0(smb_logp," FILE_ACTION_REMOVED");
9388 if (action == FILE_ACTION_MODIFIED)
9389 osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
9390 if (action == FILE_ACTION_RENAMED_OLD_NAME)
9391 osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
9392 if (action == FILE_ACTION_RENAMED_NEW_NAME)
9393 osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
9395 lock_ObtainMutex(&smb_Dir_Watch_Lock);
9396 watch = smb_Directory_Watches;
9398 filter = smb_GetSMBParm(watch, 19)
9399 | (smb_GetSMBParm(watch, 20) << 16);
9400 fid = smb_GetSMBParm(watch, 21);
9401 wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
9403 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
9404 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
9407 * Strange hack - bug in NT Client and NT Server that we must emulate?
9409 if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
9410 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
9412 fidp = smb_FindFID(watch->vcp, fid, 0);
9414 osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
9416 watch = watch->nextp;
9420 if (fidp->scp != dscp ||
9421 fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
9422 (filter & notifyFilter) == 0 ||
9423 (!isDirectParent && !wtree))
9425 osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
9427 watch = watch->nextp;
9428 smb_ReleaseFID(fidp);
9433 "Sending Change Notification for fid %d filter 0x%x wtree %d file %S",
9434 fid, filter, wtree, osi_LogSaveClientString(smb_logp, filename));
9435 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
9436 osi_Log0(smb_logp, " Notify Change File Name");
9437 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
9438 osi_Log0(smb_logp, " Notify Change Directory Name");
9439 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
9440 osi_Log0(smb_logp, " Notify Change Attributes");
9441 if (filter & FILE_NOTIFY_CHANGE_SIZE)
9442 osi_Log0(smb_logp, " Notify Change Size");
9443 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
9444 osi_Log0(smb_logp, " Notify Change Last Write");
9445 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
9446 osi_Log0(smb_logp, " Notify Change Last Access");
9447 if (filter & FILE_NOTIFY_CHANGE_CREATION)
9448 osi_Log0(smb_logp, " Notify Change Creation");
9449 if (filter & FILE_NOTIFY_CHANGE_EA)
9450 osi_Log0(smb_logp, " Notify Change Extended Attributes");
9451 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
9452 osi_Log0(smb_logp, " Notify Change Security");
9453 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
9454 osi_Log0(smb_logp, " Notify Change Stream Name");
9455 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
9456 osi_Log0(smb_logp, " Notify Change Stream Size");
9457 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
9458 osi_Log0(smb_logp, " Notify Change Stream Write");
9460 /* A watch can only be notified once. Remove it from the list */
9461 nextWatch = watch->nextp;
9462 if (watch == smb_Directory_Watches)
9463 smb_Directory_Watches = nextWatch;
9465 lastWatch->nextp = nextWatch;
9467 /* Turn off WATCHED flag in dscp */
9468 lock_ObtainWrite(&dscp->rw);
9470 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
9472 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
9473 lock_ReleaseWrite(&dscp->rw);
9475 /* Convert to response packet */
9476 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
9477 #ifdef SEND_CANONICAL_PATHNAMES
9478 ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
9480 ((smb_t *) watch)->wct = 0;
9483 if (filename == NULL) {
9486 nameLen = (ULONG)cm_ClientStrLen(filename);
9487 parmCount = 3*4 + nameLen*2;
9488 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
9490 otherNameLen = (ULONG)cm_ClientStrLen(otherFilename);
9491 oldParmCount = parmCount;
9492 parmCount += 3*4 + otherNameLen*2;
9493 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
9495 if (maxLen < parmCount)
9496 parmCount = 0; /* not enough room */
9498 parmOffset = 8*4 + 39;
9499 parmOffset += 1; /* pad to 4 */
9500 dataOffset = parmOffset + parmCount;
9504 /* Total Parameter Count */
9505 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
9506 /* Total Data Count */
9507 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9508 /* Parameter Count */
9509 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
9510 /* Parameter Offset */
9511 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
9512 /* Parameter Displacement */
9513 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9515 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9517 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
9518 /* Data Displacement */
9519 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9520 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
9521 smb_SetSMBDataLength(watch, parmCount + 1);
9523 if (parmCount != 0) {
9524 outData = smb_GetSMBData(watch, NULL);
9525 outData++; /* round to get to parmOffset */
9526 oldOutData = outData;
9527 *((DWORD *)outData) = oldParmCount; outData += 4;
9528 /* Next Entry Offset */
9529 *((DWORD *)outData) = action; outData += 4;
9531 *((DWORD *)outData) = nameLen*2; outData += 4;
9532 /* File Name Length */
9534 smb_UnparseString(watch, outData, filename, NULL, 0);
9538 outData = oldOutData + oldParmCount;
9539 *((DWORD *)outData) = 0; outData += 4;
9540 /* Next Entry Offset */
9541 *((DWORD *)outData) = otherAction; outData += 4;
9543 *((DWORD *)outData) = otherNameLen*2;
9544 outData += 4; /* File Name Length */
9545 smb_UnparseString(watch, outData, otherFilename, NULL, 0);
9550 * If filename is null, we don't know the cause of the
9551 * change notification. We return zero data (see above),
9552 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
9553 * (= 0x010C). We set the error code here by hand, without
9554 * modifying wct and bcc.
9556 if (filename == NULL) {
9557 ((smb_t *) watch)->rcls = 0x0C;
9558 ((smb_t *) watch)->reh = 0x01;
9559 ((smb_t *) watch)->errLow = 0;
9560 ((smb_t *) watch)->errHigh = 0;
9561 /* Set NT Status codes flag */
9562 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9565 smb_SendPacket(watch->vcp, watch);
9566 smb_FreePacket(watch);
9568 smb_ReleaseFID(fidp);
9571 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9574 /* SMB_COM_NT_CANCEL */
9575 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9577 unsigned char *replyWctp;
9578 smb_packet_t *watch, *lastWatch;
9579 USHORT fid, watchtree;
9583 osi_Log0(smb_logp, "SMB3 receive NT cancel");
9585 lock_ObtainMutex(&smb_Dir_Watch_Lock);
9586 watch = smb_Directory_Watches;
9588 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
9589 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
9590 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
9591 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
9592 if (watch == smb_Directory_Watches)
9593 smb_Directory_Watches = watch->nextp;
9595 lastWatch->nextp = watch->nextp;
9596 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9598 /* Turn off WATCHED flag in scp */
9599 fid = smb_GetSMBParm(watch, 21);
9600 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
9602 if (vcp != watch->vcp)
9603 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
9606 fidp = smb_FindFID(vcp, fid, 0);
9608 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %S",
9610 (fidp ? osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp) :_C("")));
9613 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
9615 lock_ObtainWrite(&scp->rw);
9617 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
9619 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
9620 lock_ReleaseWrite(&scp->rw);
9622 smb_ReleaseFID(fidp);
9624 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
9627 /* assume STATUS32; return 0xC0000120 (CANCELED) */
9628 replyWctp = watch->wctp;
9632 ((smb_t *)watch)->rcls = 0x20;
9633 ((smb_t *)watch)->reh = 0x1;
9634 ((smb_t *)watch)->errLow = 0;
9635 ((smb_t *)watch)->errHigh = 0xC0;
9636 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9637 smb_SendPacket(vcp, watch);
9638 smb_FreePacket(watch);
9642 watch = watch->nextp;
9644 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9650 * NT rename also does hard links.
9653 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
9654 #define RENAME_FLAG_HARD_LINK 0x103
9655 #define RENAME_FLAG_RENAME 0x104
9656 #define RENAME_FLAG_COPY 0x105
9658 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9660 clientchar_t *oldPathp, *newPathp;
9666 attrs = smb_GetSMBParm(inp, 0);
9667 rename_type = smb_GetSMBParm(inp, 1);
9669 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
9670 osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
9671 return CM_ERROR_NOACCESS;
9674 tp = smb_GetSMBData(inp, NULL);
9675 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
9677 return CM_ERROR_BADSMB;
9678 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
9680 return CM_ERROR_BADSMB;
9682 osi_Log3(smb_logp, "NTRename for [%S]->[%S] type [%s]",
9683 osi_LogSaveClientString(smb_logp, oldPathp),
9684 osi_LogSaveClientString(smb_logp, newPathp),
9685 ((rename_type==RENAME_FLAG_RENAME)?"rename":(rename_type==RENAME_FLAG_HARD_LINK)?"hardlink":"other"));
9687 if (rename_type == RENAME_FLAG_RENAME) {
9688 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
9689 } else if (rename_type == RENAME_FLAG_HARD_LINK) { /* RENAME_FLAG_HARD_LINK */
9690 code = smb_Link(vcp,inp,oldPathp,newPathp);
9692 code = CM_ERROR_BADOP;
9698 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock", LOCK_HIERARCHY_SMB_DIRWATCH);
9701 cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
9703 smb_username_t *unp;
9706 unp = smb_FindUserByName(usern, machine, flags);
9708 lock_ObtainMutex(&unp->mx);
9709 unp->userp = cm_NewUser();
9710 lock_ReleaseMutex(&unp->mx);
9711 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9713 osi_Log2(smb_logp,"smb_FindCMUserByName Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9717 smb_ReleaseUsername(unp);
9721 cm_user_t *smb_FindCMUserBySID(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
9723 smb_username_t *unp;
9726 unp = smb_FindUserByName(usern, machine, flags);
9728 lock_ObtainMutex(&unp->mx);
9729 unp->flags |= SMB_USERNAMEFLAG_SID;
9730 unp->userp = cm_NewUser();
9731 lock_ReleaseMutex(&unp->mx);
9732 osi_Log2(smb_logp,"smb_FindCMUserBySID New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9734 osi_Log2(smb_logp,"smb_FindCMUserBySID Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9738 smb_ReleaseUsername(unp);