3 * Copyright 2000, International Business Machines Corporation and others.
6 * This software has been released under the terms of the IBM Public
7 * License. For details, see the LICENSE file in the top-level source
8 * directory or online at http://www.openafs.org/dl/license10.html
11 #include <afsconfig.h>
12 #include <afs/param.h>
19 #pragma warning(disable: 4005)
21 #define SECURITY_WIN32
34 #include <WINNT\afsreg.h>
40 extern osi_hyper_t hzero;
42 smb_packet_t *smb_Directory_Watches = NULL;
43 osi_mutex_t smb_Dir_Watch_Lock;
45 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
47 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
49 /* protected by the smb_globalLock */
50 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
52 const clientchar_t **smb_ExecutableExtensions = NULL;
54 /* retrieve a held reference to a user structure corresponding to an incoming
56 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
61 uidp = smb_FindUID(vcp, inp->uid, 0);
65 up = smb_GetUserFromUID(uidp);
73 * Return boolean specifying if the path name is thought to be an
74 * executable file. For now .exe or .dll.
76 afs_uint32 smb_IsExecutableFileName(const clientchar_t *name)
80 if ( smb_ExecutableExtensions == NULL || name == NULL)
83 len = (int)cm_ClientStrLen(name);
85 for ( i=0; smb_ExecutableExtensions[i]; i++) {
86 j = len - (int)cm_ClientStrLen(smb_ExecutableExtensions[i]);
87 if (cm_ClientStrCmpI(smb_ExecutableExtensions[i], &name[j]) == 0)
95 * Return extended attributes.
96 * Right now, we aren't using any of the "new" bits, so this looks exactly
97 * like smb_Attributes() (see smb.c).
99 unsigned long smb_ExtAttributes(cm_scache_t *scp)
103 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
104 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
105 scp->fileType == CM_SCACHETYPE_INVALID)
107 attrs = SMB_ATTR_DIRECTORY;
108 #ifdef SPECIAL_FOLDERS
109 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
110 #endif /* SPECIAL_FOLDERS */
111 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
112 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
113 } else if (scp->fid.vnode & 0x1)
114 attrs = SMB_ATTR_DIRECTORY;
119 * We used to mark a file RO if it was in an RO volume, but that
120 * turns out to be impolitic in NT. See defect 10007.
123 if ((scp->unixModeBits & 0200) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
124 attrs |= SMB_ATTR_READONLY; /* Read-only */
126 if ((scp->unixModeBits & 0200) == 0)
127 attrs |= SMB_ATTR_READONLY; /* Read-only */
131 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
136 int smb_V3IsStarMask(clientchar_t *maskp)
140 while (tc = *maskp++)
141 if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
146 void OutputDebugF(clientchar_t * format, ...) {
148 clientchar_t vbuffer[1024];
150 va_start( args, format );
151 cm_ClientStrPrintfV(vbuffer, lengthof(vbuffer), format, args);
152 osi_Log1(smb_logp, "%S", osi_LogSaveClientString(smb_logp, vbuffer));
155 void OutputDebugHexDump(unsigned char * buffer, int len) {
158 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
160 OutputDebugF(_C("Hexdump length [%d]"),len);
162 for (i=0;i<len;i++) {
165 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
167 StringCchPrintfA(buf, lengthof(buf), "%5x", i);
168 memset(buf+5,' ',80);
173 j = j*3 + 7 + ((j>7)?1:0);
176 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
179 j = j + 56 + ((j>7)?1:0);
181 buf[j] = (k>32 && k<127)?k:'.';
184 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
188 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
190 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
191 SECURITY_STATUS status, istatus;
192 CredHandle creds = {0,0};
194 SecBufferDesc secOut;
202 OutputDebugF(_C("Negotiating Extended Security"));
204 status = AcquireCredentialsHandle( NULL,
205 SMB_EXT_SEC_PACKAGE_NAME,
214 if (status != SEC_E_OK) {
215 /* Really bad. We return an empty security blob */
216 OutputDebugF(_C("AcquireCredentialsHandle failed with %lX"), status);
221 secOut.pBuffers = &secTok;
222 secOut.ulVersion = SECBUFFER_VERSION;
224 secTok.BufferType = SECBUFFER_TOKEN;
226 secTok.pvBuffer = NULL;
228 ctx.dwLower = ctx.dwUpper = 0;
230 status = AcceptSecurityContext( &creds,
233 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
234 SECURITY_NETWORK_DREP,
241 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
242 OutputDebugF(_C("Completing token..."));
243 istatus = CompleteAuthToken(&ctx, &secOut);
244 if ( istatus != SEC_E_OK )
245 OutputDebugF(_C("Token completion failed: %x"), istatus);
248 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
249 if (secTok.pvBuffer) {
250 *secBlobLength = secTok.cbBuffer;
251 *secBlob = malloc( secTok.cbBuffer );
252 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
255 if ( status != SEC_E_OK )
256 OutputDebugF(_C("AcceptSecurityContext status != CONTINUE %lX"), status);
259 /* Discard partial security context */
260 DeleteSecurityContext(&ctx);
262 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
264 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
265 FreeCredentialsHandle(&creds);
272 smb_GetLogonSID(HANDLE hToken, PSID *ppsid)
274 BOOL bSuccess = FALSE;
277 PTOKEN_GROUPS ptg = NULL;
279 // Verify the parameter passed in is not NULL.
283 // Get required buffer size and allocate the TOKEN_GROUPS buffer.
285 if (!GetTokenInformation( hToken, // handle to the access token
286 TokenGroups, // get information about the token's groups
287 (LPVOID) ptg, // pointer to TOKEN_GROUPS buffer
289 &dwLength // receives required buffer size
292 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
295 ptg = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(),
296 HEAP_ZERO_MEMORY, dwLength);
302 // Get the token group information from the access token.
304 if (!GetTokenInformation( hToken, // handle to the access token
305 TokenGroups, // get information about the token's groups
306 (LPVOID) ptg, // pointer to TOKEN_GROUPS buffer
307 dwLength, // size of buffer
308 &dwLength // receives required buffer size
314 // Loop through the groups to find the logon SID.
315 for (dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++) {
316 if ((ptg->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID)
318 // Found the logon SID; make a copy of it.
320 dwLength = GetLengthSid(ptg->Groups[dwIndex].Sid);
321 *ppsid = (PSID) HeapAlloc(GetProcessHeap(),
322 HEAP_ZERO_MEMORY, dwLength);
325 if (!CopySid(dwLength, *ppsid, ptg->Groups[dwIndex].Sid))
327 HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
337 // Free the buffer for the token groups.
339 HeapFree(GetProcessHeap(), 0, (LPVOID)ptg);
345 smb_GetUserSID(HANDLE hToken, PSID *ppsid)
347 BOOL bSuccess = FALSE;
349 PTOKEN_USER ptu = NULL;
351 // Verify the parameter passed in is not NULL.
355 // Get required buffer size and allocate the TOKEN_USER buffer.
357 if (!GetTokenInformation( hToken, // handle to the access token
358 TokenUser, // get information about the token's user
359 (LPVOID) ptu, // pointer to TOKEN_USER buffer
361 &dwLength // receives required buffer size
364 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
367 ptu = (PTOKEN_USER)HeapAlloc(GetProcessHeap(),
368 HEAP_ZERO_MEMORY, dwLength);
374 // Get the token group information from the access token.
376 if (!GetTokenInformation( hToken, // handle to the access token
377 TokenUser, // get information about the token's user
378 (LPVOID) ptu, // pointer to TOKEN_USER buffer
379 dwLength, // size of buffer
380 &dwLength // receives required buffer size
386 // Found the user SID; make a copy of it.
387 dwLength = GetLengthSid(ptu->User.Sid);
388 *ppsid = (PSID) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
391 if (!CopySid(dwLength, *ppsid, ptu->User.Sid))
393 HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
400 // Free the buffer for the token groups.
402 HeapFree(GetProcessHeap(), 0, (LPVOID)ptu);
408 smb_FreeSID (PSID psid)
410 HeapFree(GetProcessHeap(), 0, (LPVOID)psid);
414 struct smb_ext_context {
421 long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern,
422 char * secBlobIn, int secBlobInLength,
423 char ** secBlobOut, int * secBlobOutLength,
424 wchar_t **secSidString) {
425 SECURITY_STATUS status, istatus;
429 SecBufferDesc secBufIn;
431 SecBufferDesc secBufOut;
434 struct smb_ext_context * secCtx = NULL;
435 struct smb_ext_context * newSecCtx = NULL;
436 void * assembledBlob = NULL;
437 int assembledBlobLength = 0;
440 OutputDebugF(_C("In smb_AuthenticateUserExt"));
443 *secBlobOutLength = 0;
444 *secSidString = NULL;
446 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
447 secCtx = vcp->secCtx;
448 lock_ObtainMutex(&vcp->mx);
449 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
451 lock_ReleaseMutex(&vcp->mx);
455 OutputDebugF(_C("Received incoming token:"));
456 OutputDebugHexDump(secBlobIn,secBlobInLength);
460 OutputDebugF(_C("Continuing with existing context."));
461 creds = secCtx->creds;
464 if (secCtx->partialToken) {
465 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
466 assembledBlob = malloc(assembledBlobLength);
467 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
468 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
471 status = AcquireCredentialsHandle( NULL,
472 SMB_EXT_SEC_PACKAGE_NAME,
481 if (status != SEC_E_OK) {
482 OutputDebugF(_C("Can't acquire Credentials handle [%lX]"), status);
483 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
491 secBufIn.cBuffers = 1;
492 secBufIn.pBuffers = &secTokIn;
493 secBufIn.ulVersion = SECBUFFER_VERSION;
495 secTokIn.BufferType = SECBUFFER_TOKEN;
497 secTokIn.cbBuffer = assembledBlobLength;
498 secTokIn.pvBuffer = assembledBlob;
500 secTokIn.cbBuffer = secBlobInLength;
501 secTokIn.pvBuffer = secBlobIn;
504 secBufOut.cBuffers = 1;
505 secBufOut.pBuffers = &secTokOut;
506 secBufOut.ulVersion = SECBUFFER_VERSION;
508 secTokOut.BufferType = SECBUFFER_TOKEN;
509 secTokOut.cbBuffer = 0;
510 secTokOut.pvBuffer = NULL;
512 status = AcceptSecurityContext( &creds,
513 ((secCtx)?&ctx:NULL),
515 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
516 SECURITY_NETWORK_DREP,
523 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
524 OutputDebugF(_C("Completing token..."));
525 istatus = CompleteAuthToken(&ctx, &secBufOut);
526 if ( istatus != SEC_E_OK )
527 OutputDebugF(_C("Token completion failed: %lX"), istatus);
530 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
531 OutputDebugF(_C("Continue needed"));
533 newSecCtx = malloc(sizeof(*newSecCtx));
535 newSecCtx->creds = creds;
536 newSecCtx->ctx = ctx;
537 newSecCtx->partialToken = NULL;
538 newSecCtx->partialTokenLen = 0;
540 lock_ObtainMutex( &vcp->mx );
541 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
542 vcp->secCtx = newSecCtx;
543 lock_ReleaseMutex( &vcp->mx );
545 code = CM_ERROR_GSSCONTINUE;
548 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
549 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
550 secTokOut.pvBuffer) {
551 OutputDebugF(_C("Need to send token back to client"));
553 *secBlobOutLength = secTokOut.cbBuffer;
554 *secBlobOut = malloc(secTokOut.cbBuffer);
555 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
557 OutputDebugF(_C("Outgoing token:"));
558 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
559 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
560 OutputDebugF(_C("Incomplete message"));
562 newSecCtx = malloc(sizeof(*newSecCtx));
564 newSecCtx->creds = creds;
565 newSecCtx->ctx = ctx;
566 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
567 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
568 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
570 lock_ObtainMutex( &vcp->mx );
571 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
572 vcp->secCtx = newSecCtx;
573 lock_ReleaseMutex( &vcp->mx );
575 code = CM_ERROR_GSSCONTINUE;
578 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
581 SecPkgContext_NamesW names;
583 OutputDebugF(_C("Authentication completed"));
584 OutputDebugF(_C("Returned flags : [%lX]"), flags);
586 if (!QueryContextAttributesW(&ctx, SECPKG_ATTR_NAMES, &names)) {
587 OutputDebugF(_C("Received name [%s]"), names.sUserName);
588 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, names.sUserName);
589 cm_ClientStrLwr(usern); /* in tandem with smb_GetNormalizedUsername */
590 FreeContextBuffer(names.sUserName);
592 /* Force the user to retry if the context is invalid */
593 OutputDebugF(_C("QueryContextAttributes Names failed [%x]"), GetLastError());
594 code = CM_ERROR_BADPASSWORD;
597 /* Obtain the user's SID */
598 if (code == 0 && !QuerySecurityContextToken(((secCtx)?&ctx:NULL), &hToken)) {
600 OutputDebugF(_C("Received hToken"));
602 if (smb_GetUserSID(hToken, &pSid))
603 ConvertSidToStringSidW(pSid, secSidString);
609 OutputDebugF(_C("QueryContextToken failed [%x]"), GetLastError());
613 case SEC_E_INVALID_TOKEN:
614 OutputDebugF(_C("Returning bad password :: INVALID_TOKEN"));
616 case SEC_E_INVALID_HANDLE:
617 OutputDebugF(_C("Returning bad password :: INVALID_HANDLE"));
619 case SEC_E_LOGON_DENIED:
620 OutputDebugF(_C("Returning bad password :: LOGON_DENIED"));
622 case SEC_E_UNKNOWN_CREDENTIALS:
623 OutputDebugF(_C("Returning bad password :: UNKNOWN_CREDENTIALS"));
625 case SEC_E_NO_CREDENTIALS:
626 OutputDebugF(_C("Returning bad password :: NO_CREDENTIALS"));
628 case SEC_E_CONTEXT_EXPIRED:
629 OutputDebugF(_C("Returning bad password :: CONTEXT_EXPIRED"));
631 case SEC_E_INCOMPLETE_CREDENTIALS:
632 OutputDebugF(_C("Returning bad password :: INCOMPLETE_CREDENTIALS"));
634 case SEC_E_WRONG_PRINCIPAL:
635 OutputDebugF(_C("Returning bad password :: WRONG_PRINCIPAL"));
637 case SEC_E_TIME_SKEW:
638 OutputDebugF(_C("Returning bad password :: TIME_SKEW"));
641 OutputDebugF(_C("Returning bad password :: Status == %lX"), status);
643 code = CM_ERROR_BADPASSWORD;
647 if (secCtx->partialToken) free(secCtx->partialToken);
655 if (secTokOut.pvBuffer)
656 FreeContextBuffer(secTokOut.pvBuffer);
658 if (code != CM_ERROR_GSSCONTINUE) {
659 DeleteSecurityContext(&ctx);
660 FreeCredentialsHandle(&creds);
668 #define P_RESP_LEN 128
670 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
671 So put stuff in a struct. */
672 struct Lm20AuthBlob {
673 MSV1_0_LM20_LOGON lmlogon;
674 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
675 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
676 WCHAR accountNameW[P_LEN];
677 WCHAR primaryDomainW[P_LEN];
678 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
679 TOKEN_GROUPS tgroups;
680 TOKEN_SOURCE tsource;
683 long smb_AuthenticateUserLM(smb_vc_t *vcp, clientchar_t * accountName, clientchar_t * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
686 struct Lm20AuthBlob lmAuth;
687 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
688 QUOTA_LIMITS quotaLimits;
690 ULONG lmprofilepSize;
694 OutputDebugF(_C("In smb_AuthenticateUser for user [%s] domain [%s]"), accountName, primaryDomain);
695 OutputDebugF(_C("ciPwdLength is %d and csPwdLength is %d"), ciPwdLength, csPwdLength);
697 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
698 OutputDebugF(_C("ciPwdLength or csPwdLength is too long"));
699 return CM_ERROR_BADPASSWORD;
702 memset(&lmAuth,0,sizeof(lmAuth));
704 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
706 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
707 cm_ClientStringToUtf16(primaryDomain, -1, lmAuth.primaryDomainW, P_LEN);
708 lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
709 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
711 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
712 cm_ClientStringToUtf16(accountName, -1, lmAuth.accountNameW, P_LEN);
713 lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
714 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
716 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
717 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
718 size = MAX_COMPUTERNAME_LENGTH + 1;
719 GetComputerNameW(lmAuth.workstationW, &size);
720 lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
722 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
724 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
725 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
726 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
727 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
729 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
730 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
731 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
732 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
734 lmAuth.lmlogon.ParameterControl = 0;
736 lmAuth.tgroups.GroupCount = 0;
737 lmAuth.tgroups.Groups[0].Sid = NULL;
738 lmAuth.tgroups.Groups[0].Attributes = 0;
741 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
743 lmAuth.tsource.SourceIdentifier.HighPart = 0;
745 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
746 StringCchCopyA(lmAuth.tsource.SourceName, lengthof(lmAuth.tsource.SourceName),
747 "OpenAFS"); /* 8 char limit */
749 nts = LsaLogonUser( smb_lsaHandle,
764 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
765 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
768 OutputDebugF(_C("Return from LsaLogonUser is 0x%lX"), nts);
769 OutputDebugF(_C("Extended status is 0x%lX"), ntsEx);
771 if (nts == ERROR_SUCCESS) {
773 LsaFreeReturnBuffer(lmprofilep);
774 CloseHandle(lmToken);
778 if (nts == 0xC000015BL)
779 return CM_ERROR_BADLOGONTYPE;
780 else /* our catchall is a bad password though we could be more specific */
781 return CM_ERROR_BADPASSWORD;
785 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
786 long smb_GetNormalizedUsername(clientchar_t * usern, const clientchar_t * accountName, const clientchar_t * domainName)
788 clientchar_t * atsign;
789 const clientchar_t * domain;
791 /* check if we have sane input */
792 if ((cm_ClientStrLen(accountName) + cm_ClientStrLen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
795 /* we could get : [accountName][domainName]
801 atsign = cm_ClientStrChr(accountName, '@');
803 if (atsign) /* [user@domain][] -> [user@domain][domain] */
808 /* if for some reason the client doesn't know what domain to use,
809 it will either return an empty string or a '?' */
810 if (!domain[0] || domain[0] == '?')
811 /* Empty domains and empty usernames are usually sent from tokenless contexts.
812 This way such logins will get an empty username (easy to check). I don't know
813 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
814 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, accountName);
816 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
817 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, domain);
818 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, _C("\\"));
820 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
822 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
825 cm_ClientStrLwr(usern);
830 /* When using SMB auth, all SMB sessions have to pass through here
831 * first to authenticate the user.
833 * Caveat: If not using SMB auth, the protocol does not require
834 * sending a session setup packet, which means that we can't rely on a
835 * UID in subsequent packets. Though in practice we get one anyway.
837 /* SMB_COM_SESSION_SETUP_ANDX */
838 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
842 unsigned short newUid;
843 unsigned long caps = 0;
845 clientchar_t *s1 = _C(" ");
847 clientchar_t usern[SMB_MAX_USERNAME_LENGTH];
849 char *secBlobOut = NULL;
850 int secBlobOutLength = 0;
851 wchar_t *secSidString = 0;
852 int maxBufferSize = 0;
856 /* Check for bad conns */
857 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
858 return CM_ERROR_REMOTECONN;
861 maxBufferSize = smb_GetSMBParm(inp, 2);
862 maxMpxCount = smb_GetSMBParm(inp, 3);
863 vcNumber = smb_GetSMBParm(inp, 4);
865 osi_Log3(smb_logp, "SESSION_SETUP_ANDX with MaxBufferSize=%d, MaxMpxCount=%d, VCNumber=%d",
866 maxBufferSize, maxMpxCount, vcNumber);
868 if (maxMpxCount > smb_maxMpxRequests) {
869 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_MPX_COUNT, maxMpxCount, smb_maxMpxRequests);
870 osi_Log2(smb_logp, "MaxMpxCount for client is too large (Client=%d, Server=%d)",
871 maxMpxCount, smb_maxMpxRequests);
874 if (maxBufferSize < SMB_PACKETSIZE) {
875 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_BUFFER_SIZE, maxBufferSize, SMB_PACKETSIZE);
876 osi_Log2(smb_logp, "MaxBufferSize for client is too small (Client=%d, Server=%d)",
877 maxBufferSize, SMB_PACKETSIZE);
881 osi_Log0(smb_logp, "Resetting all VCs");
882 smb_MarkAllVCsDead(vcp);
885 if (vcp->flags & SMB_VCFLAG_USENT) {
886 if (smb_authType == SMB_AUTH_EXTENDED) {
887 /* extended authentication */
891 OutputDebugF(_C("NT Session Setup: Extended"));
893 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
894 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
897 secBlobInLength = smb_GetSMBParm(inp, 7);
898 secBlobIn = smb_GetSMBData(inp, NULL);
900 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength, &secSidString);
902 if (code == CM_ERROR_GSSCONTINUE) {
905 smb_SetSMBParm(outp, 2, 0);
906 smb_SetSMBParm(outp, 3, secBlobOutLength);
908 tp = smb_GetSMBData(outp, NULL);
909 if (secBlobOutLength) {
910 memcpy(tp, secBlobOut, secBlobOutLength);
912 tp += secBlobOutLength;
913 cb_data += secBlobOutLength;
915 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
916 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
917 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
919 smb_SetSMBDataLength(outp, cb_data);
922 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
924 unsigned ciPwdLength, csPwdLength;
926 clientchar_t *accountName;
927 clientchar_t *primaryDomain;
930 if (smb_authType == SMB_AUTH_NTLM)
931 OutputDebugF(_C("NT Session Setup: NTLM"));
933 OutputDebugF(_C("NT Session Setup: None"));
935 /* TODO: parse for extended auth as well */
936 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
937 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
939 tp = smb_GetSMBData(inp, &datalen);
941 OutputDebugF(_C("Session packet data size [%d]"),datalen);
948 accountName = smb_ParseString(inp, tp, &tp, 0);
949 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
951 OutputDebugF(_C("Account Name: %s"),accountName);
952 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
953 OutputDebugF(_C("Case Sensitive Password: %s"),
954 csPwd && csPwd[0] ? _C("yes") : _C("no"));
955 OutputDebugF(_C("Case Insensitive Password: %s"),
956 ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
958 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
959 /* shouldn't happen */
960 code = CM_ERROR_BADSMB;
961 goto after_read_packet;
964 /* capabilities are only valid for first session packet */
965 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
966 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
969 if (smb_authType == SMB_AUTH_NTLM) {
970 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
972 OutputDebugF(_C("LM authentication failed [%d]"), code);
974 OutputDebugF(_C("LM authentication succeeded"));
978 unsigned ciPwdLength;
980 clientchar_t *accountName;
981 clientchar_t *primaryDomain;
983 switch ( smb_authType ) {
984 case SMB_AUTH_EXTENDED:
985 OutputDebugF(_C("V3 Session Setup: Extended"));
988 OutputDebugF(_C("V3 Session Setup: NTLM"));
991 OutputDebugF(_C("V3 Session Setup: None"));
993 ciPwdLength = smb_GetSMBParm(inp, 7);
994 tp = smb_GetSMBData(inp, NULL);
998 accountName = smb_ParseString(inp, tp, &tp, 0);
999 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
1001 OutputDebugF(_C("Account Name: %s"),accountName);
1002 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
1003 OutputDebugF(_C("Case Insensitive Password: %s"), ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
1005 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
1006 /* shouldn't happen */
1007 code = CM_ERROR_BADSMB;
1008 goto after_read_packet;
1011 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
1014 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
1015 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
1017 OutputDebugF(_C("LM authentication failed [%d]"), code);
1019 OutputDebugF(_C("LM authentication succeeded"));
1024 /* note down that we received a session setup X and set the capabilities flag */
1025 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
1026 lock_ObtainMutex(&vcp->mx);
1027 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
1028 /* for the moment we can only deal with NTSTATUS */
1029 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
1030 vcp->flags |= SMB_VCFLAG_STATUS32;
1034 if ((caps & NTNEGOTIATE_CAPABILITY_UNICODE) && smb_UseUnicode) {
1035 vcp->flags |= SMB_VCFLAG_USEUNICODE;
1038 lock_ReleaseMutex(&vcp->mx);
1041 /* code would be non-zero if there was an authentication failure.
1042 Ideally we would like to invalidate the uid for this session or break
1043 early to avoid accidently stealing someone else's tokens. */
1047 LocalFree(secSidString);
1052 * If the SidString for the user could be obtained, use that
1056 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, secSidString);
1060 OutputDebugF(_C("Received username=[%s]"), usern);
1062 /* On Windows 2000, this function appears to be called more often than
1063 it is expected to be called. This resulted in multiple smb_user_t
1064 records existing all for the same user session which results in all
1065 of the users tokens disappearing.
1067 To avoid this problem, we look for an existing smb_user_t record
1068 based on the users name, and use that one if we find it.
1071 uidp = smb_FindUserByNameThisSession(vcp, usern);
1072 if (uidp) { /* already there, so don't create a new one */
1074 newUid = uidp->userID;
1075 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
1076 vcp->lana,vcp->lsn,newUid);
1077 smb_ReleaseUID(uidp);
1082 /* do a global search for the username/machine name pair */
1083 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
1084 lock_ObtainMutex(&unp->mx);
1085 if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
1086 /* clear the afslogon flag so that the tickets can now
1087 * be freed when the refCount returns to zero.
1089 unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
1091 unp->flags |= SMB_USERNAMEFLAG_SID;
1094 unp->flags |= SMB_USERNAMEFLAG_SID;
1095 lock_ReleaseMutex(&unp->mx);
1097 /* Create a new UID and cm_user_t structure */
1100 userp = cm_NewUser();
1101 cm_HoldUserVCRef(userp);
1102 lock_ObtainMutex(&vcp->mx);
1103 if (!vcp->uidCounter)
1104 vcp->uidCounter++; /* handle unlikely wraparounds */
1105 newUid = (cm_ClientStrLen(usern)==0)?0:vcp->uidCounter++;
1106 lock_ReleaseMutex(&vcp->mx);
1108 /* Create a new smb_user_t structure and connect them up */
1109 lock_ObtainMutex(&unp->mx);
1111 lock_ReleaseMutex(&unp->mx);
1113 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
1115 lock_ObtainMutex(&uidp->mx);
1117 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
1118 lock_ReleaseMutex(&uidp->mx);
1119 smb_ReleaseUID(uidp);
1123 /* Return UID to the client */
1124 ((smb_t *)outp)->uid = newUid;
1125 /* Also to the next chained message */
1126 ((smb_t *)inp)->uid = newUid;
1128 osi_Log3(smb_logp, "SMB3 session setup name %S creating ID %d%S",
1129 osi_LogSaveClientString(smb_logp, usern), newUid,
1130 osi_LogSaveClientString(smb_logp, s1));
1132 smb_SetSMBParm(outp, 2, 0);
1134 if (vcp->flags & SMB_VCFLAG_USENT) {
1135 if (smb_authType == SMB_AUTH_EXTENDED) {
1138 smb_SetSMBParm(outp, 3, secBlobOutLength);
1140 tp = smb_GetSMBData(outp, NULL);
1141 if (secBlobOutLength) {
1142 memcpy(tp, secBlobOut, secBlobOutLength);
1144 tp += secBlobOutLength;
1145 cb_data += secBlobOutLength;
1148 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
1149 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
1150 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
1152 smb_SetSMBDataLength(outp, cb_data);
1154 smb_SetSMBDataLength(outp, 0);
1157 if (smb_authType == SMB_AUTH_EXTENDED) {
1160 tp = smb_GetSMBData(outp, NULL);
1162 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
1163 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
1164 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
1166 smb_SetSMBDataLength(outp, cb_data);
1168 smb_SetSMBDataLength(outp, 0);
1173 LocalFree(secSidString);
1177 /* SMB_COM_LOGOFF_ANDX */
1178 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1182 /* find the tree and free it */
1183 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1185 smb_username_t * unp;
1187 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %S", uidp->userID,
1188 osi_LogSaveClientString(smb_logp, (uidp->unp) ? uidp->unp->name: _C(" ")));
1190 lock_ObtainMutex(&uidp->mx);
1191 uidp->flags |= SMB_USERFLAG_DELETE;
1193 * it doesn't get deleted right away
1194 * because the vcp points to it
1197 lock_ReleaseMutex(&uidp->mx);
1200 /* we can't do this. we get logoff messages prior to a session
1201 * disconnect even though it doesn't mean the user is logging out.
1202 * we need to create a new pioctl and EventLogoff handler to set
1203 * SMB_USERNAMEFLAG_LOGOFF.
1205 if (unp && smb_LogoffTokenTransfer) {
1206 lock_ObtainMutex(&unp->mx);
1207 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
1208 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
1209 lock_ReleaseMutex(&unp->mx);
1213 smb_ReleaseUID(uidp);
1216 osi_Log0(smb_logp, "SMB3 user logoffX");
1218 smb_SetSMBDataLength(outp, 0);
1222 #define SMB_SUPPORT_SEARCH_BITS 0x0001
1223 #define SMB_SHARE_IS_IN_DFS 0x0002
1225 /* SMB_COM_TREE_CONNECT_ANDX */
1226 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1229 smb_user_t *uidp = NULL;
1230 unsigned short newTid;
1231 clientchar_t shareName[AFSPATHMAX];
1232 clientchar_t *sharePath;
1235 clientchar_t *slashp;
1236 clientchar_t *pathp;
1237 clientchar_t *passwordp;
1238 clientchar_t *servicep;
1239 cm_user_t *userp = NULL;
1242 osi_Log0(smb_logp, "SMB3 receive tree connect");
1244 /* parse input parameters */
1245 tp = smb_GetSMBData(inp, NULL);
1246 passwordp = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1247 pathp = smb_ParseString(inp, tp, &tp, SMB_STRF_ANSIPATH);
1248 servicep = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1250 slashp = cm_ClientStrRChr(pathp, '\\');
1252 return CM_ERROR_BADSMB;
1254 cm_ClientStrCpy(shareName, lengthof(shareName), slashp+1);
1256 osi_Log3(smb_logp, "Tree connect pathp[%S] shareName[%S] service[%S]",
1257 osi_LogSaveClientString(smb_logp, pathp),
1258 osi_LogSaveClientString(smb_logp, shareName),
1259 osi_LogSaveClientString(smb_logp, servicep));
1261 if (cm_ClientStrCmp(servicep, _C("IPC")) == 0 ||
1262 cm_ClientStrCmp(shareName, _C("IPC$")) == 0) {
1264 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1267 return CM_ERROR_NOIPC;
1271 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1273 userp = smb_GetUserFromUID(uidp);
1275 lock_ObtainMutex(&vcp->mx);
1276 newTid = vcp->tidCounter++;
1277 lock_ReleaseMutex(&vcp->mx);
1279 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1282 if (!cm_ClientStrCmp(shareName, _C("*.")))
1283 cm_ClientStrCpy(shareName, lengthof(shareName), _C("all"));
1284 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1287 smb_ReleaseUID(uidp);
1288 smb_ReleaseTID(tidp, FALSE);
1289 return CM_ERROR_BADSHARENAME;
1292 if (vcp->flags & SMB_VCFLAG_USENT)
1294 int policy = smb_FindShareCSCPolicy(shareName);
1297 DWORD dwAdvertiseDFS = 0, dwSize = sizeof(DWORD);
1299 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1300 0, KEY_QUERY_VALUE, &parmKey);
1301 if (code == ERROR_SUCCESS) {
1302 code = RegQueryValueEx(parmKey, "AdvertiseDFS", NULL, NULL,
1303 (BYTE *)&dwAdvertiseDFS, &dwSize);
1304 if (code != ERROR_SUCCESS)
1306 RegCloseKey (parmKey);
1308 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1309 (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
1313 smb_SetSMBParm(outp, 2, 0);
1317 smb_ReleaseUID(uidp);
1319 lock_ObtainMutex(&tidp->mx);
1320 tidp->userp = userp;
1321 tidp->pathname = sharePath;
1323 tidp->flags |= SMB_TIDFLAG_IPC;
1324 lock_ReleaseMutex(&tidp->mx);
1325 smb_ReleaseTID(tidp, FALSE);
1327 ((smb_t *)outp)->tid = newTid;
1328 ((smb_t *)inp)->tid = newTid;
1329 tp = smb_GetSMBData(outp, NULL);
1333 tp = smb_UnparseString(outp, tp, _C("A:"), &cb_data, SMB_STRF_FORCEASCII);
1334 tp = smb_UnparseString(outp, tp, _C("AFS"), &cb_data, 0);
1335 smb_SetSMBDataLength(outp, cb_data);
1339 tp = smb_UnparseString(outp, tp, _C("IPC"), &cb_data, SMB_STRF_FORCEASCII);
1340 smb_SetSMBDataLength(outp, cb_data);
1343 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1347 /* must be called with global tran lock held */
1348 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1350 smb_tran2Packet_t *tp;
1353 smbp = (smb_t *) inp->data;
1354 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1355 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1361 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1362 int totalParms, int totalData)
1364 smb_tran2Packet_t *tp;
1367 smbp = (smb_t *) inp->data;
1368 tp = malloc(sizeof(*tp));
1369 memset(tp, 0, sizeof(*tp));
1372 tp->curData = tp->curParms = 0;
1373 tp->totalData = totalData;
1374 tp->totalParms = totalParms;
1375 tp->tid = smbp->tid;
1376 tp->mid = smbp->mid;
1377 tp->uid = smbp->uid;
1378 tp->pid = smbp->pid;
1379 tp->res[0] = smbp->res[0];
1380 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1381 if (totalParms != 0)
1382 tp->parmsp = malloc(totalParms);
1384 tp->datap = malloc(totalData);
1385 if (smbp->com == 0x25 || smbp->com == 0x26)
1388 tp->opcode = smb_GetSMBParm(inp, 14);
1391 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1393 if (WANTS_UNICODE(inp) && (vcp->flags & SMB_VCFLAG_USEUNICODE))
1394 tp->flags |= SMB_TRAN2PFLAG_USEUNICODE;
1399 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1400 smb_tran2Packet_t *inp, smb_packet_t *outp,
1401 int totalParms, int totalData)
1403 smb_tran2Packet_t *tp;
1404 unsigned short parmOffset;
1405 unsigned short dataOffset;
1406 unsigned short dataAlign;
1408 tp = malloc(sizeof(*tp));
1409 memset(tp, 0, sizeof(*tp));
1412 tp->curData = tp->curParms = 0;
1413 tp->totalData = totalData;
1414 tp->totalParms = totalParms;
1415 tp->oldTotalParms = totalParms;
1420 tp->res[0] = inp->res[0];
1421 tp->opcode = inp->opcode;
1425 * We calculate where the parameters and data will start.
1426 * This calculation must parallel the calculation in
1427 * smb_SendTran2Packet.
1430 parmOffset = 10*2 + 35;
1431 parmOffset++; /* round to even */
1432 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1434 dataOffset = parmOffset + totalParms;
1435 dataAlign = dataOffset & 2; /* quad-align */
1436 dataOffset += dataAlign;
1437 tp->datap = outp->data + dataOffset;
1442 /* free a tran2 packet */
1443 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1446 smb_ReleaseVC(t2p->vcp);
1449 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1459 while (t2p->stringsp) {
1463 t2p->stringsp = ns->nextp;
1469 clientchar_t *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
1470 char ** chainpp, int flags)
1475 if (!(p->flags & SMB_TRAN2PFLAG_USEUNICODE))
1476 flags |= SMB_STRF_FORCEASCII;
1479 cb = p->totalParms - (inp - (char *)p->parmsp);
1480 if (inp < (char *) p->parmsp ||
1481 inp >= ((char *) p->parmsp) + p->totalParms) {
1482 #ifdef DEBUG_UNICODE
1488 return smb_ParseStringBuf((unsigned char *) p->parmsp, &p->stringsp,
1489 inp, &cb, chainpp, flags);
1492 /* called with a VC, an input packet to respond to, and an error code.
1493 * sends an error response.
1495 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1496 smb_packet_t *tp, long code)
1499 unsigned short errCode;
1500 unsigned char errClass;
1501 unsigned long NTStatus;
1503 if (vcp->flags & SMB_VCFLAG_STATUS32)
1504 smb_MapNTError(code, &NTStatus, FALSE);
1506 smb_MapCoreError(code, vcp, &errCode, &errClass);
1508 smb_FormatResponsePacket(vcp, NULL, tp);
1509 smbp = (smb_t *) tp;
1511 /* We can handle long names */
1512 if (vcp->flags & SMB_VCFLAG_USENT)
1513 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1515 /* now copy important fields from the tran 2 packet */
1516 smbp->com = t2p->com;
1517 smbp->tid = t2p->tid;
1518 smbp->mid = t2p->mid;
1519 smbp->pid = t2p->pid;
1520 smbp->uid = t2p->uid;
1521 smbp->res[0] = t2p->res[0];
1522 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1523 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1524 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1525 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1526 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1527 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1530 smbp->rcls = errClass;
1531 smbp->errLow = (unsigned char) (errCode & 0xff);
1532 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1536 smb_SendPacket(vcp, tp);
1539 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1542 unsigned short parmOffset;
1543 unsigned short dataOffset;
1544 unsigned short totalLength;
1545 unsigned short dataAlign;
1548 smb_FormatResponsePacket(vcp, NULL, tp);
1549 smbp = (smb_t *) tp;
1551 /* We can handle long names */
1552 if (vcp->flags & SMB_VCFLAG_USENT)
1553 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1555 /* now copy important fields from the tran 2 packet */
1556 smbp->com = t2p->com;
1557 smbp->tid = t2p->tid;
1558 smbp->mid = t2p->mid;
1559 smbp->pid = t2p->pid;
1560 smbp->uid = t2p->uid;
1561 smbp->res[0] = t2p->res[0];
1563 if (t2p->error_code) {
1564 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1565 unsigned long NTStatus;
1567 smb_MapNTError(t2p->error_code, &NTStatus, FALSE);
1569 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1570 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1571 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1572 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1573 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1576 unsigned short errCode;
1577 unsigned char errClass;
1579 smb_MapCoreError(t2p->error_code, vcp, &errCode, &errClass);
1581 smbp->rcls = errClass;
1582 smbp->errLow = (unsigned char) (errCode & 0xff);
1583 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1587 totalLength = 1 + t2p->totalData + t2p->totalParms;
1589 /* now add the core parameters (tran2 info) to the packet */
1590 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1591 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1592 smb_SetSMBParm(tp, 2, 0); /* reserved */
1593 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1594 parmOffset = 10*2 + 35; /* parm offset in packet */
1595 parmOffset++; /* round to even */
1596 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1597 * hdr, bcc and wct */
1598 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1599 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1600 dataOffset = parmOffset + t2p->oldTotalParms;
1601 dataAlign = dataOffset & 2; /* quad-align */
1602 dataOffset += dataAlign;
1603 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1604 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1605 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1608 datap = smb_GetSMBData(tp, NULL);
1609 *datap++ = 0; /* we rounded to even */
1611 totalLength += dataAlign;
1612 smb_SetSMBDataLength(tp, totalLength);
1614 /* next, send the datagram */
1615 smb_SendPacket(vcp, tp);
1618 /* TRANS_SET_NMPIPE_STATE */
1619 long smb_nmpipeSetState(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1623 int pipeState = 0x0100; /* default */
1624 smb_tran2Packet_t *outp = NULL;
1627 if (p->totalParms > 0)
1628 pipeState = p->parmsp[0];
1630 osi_Log2(smb_logp, "smb_nmpipeSetState for fd[%d] with state[0x%x]", fd, pipeState);
1632 fidp = smb_FindFID(vcp, fd, 0);
1634 osi_Log2(smb_logp, "smb_nmpipeSetState Unknown SMB Fid vcp 0x%p fid %d",
1636 return CM_ERROR_BADFD;
1638 lock_ObtainMutex(&fidp->mx);
1639 if (pipeState & 0x8000)
1640 fidp->flags |= SMB_FID_BLOCKINGPIPE;
1641 if (pipeState & 0x0100)
1642 fidp->flags |= SMB_FID_MESSAGEMODEPIPE;
1643 lock_ReleaseMutex(&fidp->mx);
1645 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 0);
1646 smb_SendTran2Packet(vcp, outp, op);
1647 smb_FreeTran2Packet(outp);
1649 smb_ReleaseFID(fidp);
1654 long smb_nmpipeTransact(smb_vc_t * vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1664 osi_Log3(smb_logp, "smb_nmpipeTransact for fd[%d] %d bytes in, %d max bytes out",
1665 fd, p->totalData, p->maxReturnData);
1667 fidp = smb_FindFID(vcp, fd, 0);
1669 osi_Log2(smb_logp, "smb_nmpipeTransact Unknown SMB Fid vcp 0x%p fid %d",
1671 return CM_ERROR_BADFD;
1673 lock_ObtainMutex(&fidp->mx);
1674 if (fidp->flags & SMB_FID_RPC) {
1677 lock_ReleaseMutex(&fidp->mx);
1680 code = smb_RPCNmpipeTransact(fidp, vcp, p, op);
1681 smb_ReleaseFID(fidp);
1683 /* We only deal with RPC pipes */
1684 osi_Log2(smb_logp, "smb_nmpipeTransact Not a RPC vcp 0x%p fid %d",
1686 code = CM_ERROR_BADFD;
1693 /* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
1694 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1696 smb_tran2Packet_t *asp;
1709 /* We sometimes see 0 word count. What to do? */
1710 if (*inp->wctp == 0) {
1711 osi_Log0(smb_logp, "Transaction2 word count = 0");
1712 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1714 smb_SetSMBDataLength(outp, 0);
1715 smb_SendPacket(vcp, outp);
1719 totalParms = smb_GetSMBParm(inp, 0);
1720 totalData = smb_GetSMBParm(inp, 1);
1722 firstPacket = (inp->inCom == 0x25);
1724 /* find the packet we're reassembling */
1725 lock_ObtainWrite(&smb_globalLock);
1726 asp = smb_FindTran2Packet(vcp, inp);
1728 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1730 lock_ReleaseWrite(&smb_globalLock);
1732 /* now merge in this latest packet; start by looking up offsets */
1734 parmDisp = dataDisp = 0;
1735 parmOffset = smb_GetSMBParm(inp, 10);
1736 dataOffset = smb_GetSMBParm(inp, 12);
1737 parmCount = smb_GetSMBParm(inp, 9);
1738 dataCount = smb_GetSMBParm(inp, 11);
1739 asp->setupCount = smb_GetSMBParmByte(inp, 13);
1740 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1741 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1743 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1744 totalData, dataCount, asp->maxReturnData);
1746 if (asp->setupCount == 2) {
1747 clientchar_t * pname;
1749 asp->pipeCommand = smb_GetSMBParm(inp, 14);
1750 asp->pipeParam = smb_GetSMBParm(inp, 15);
1751 pname = smb_ParseString(inp, inp->wctp + 35, NULL, 0);
1753 asp->name = cm_ClientStrDup(pname);
1756 osi_Log2(smb_logp, " Named Pipe command id [%d] with name [%S]",
1757 asp->pipeCommand, osi_LogSaveClientString(smb_logp, asp->name));
1761 parmDisp = smb_GetSMBParm(inp, 4);
1762 parmOffset = smb_GetSMBParm(inp, 3);
1763 dataDisp = smb_GetSMBParm(inp, 7);
1764 dataOffset = smb_GetSMBParm(inp, 6);
1765 parmCount = smb_GetSMBParm(inp, 2);
1766 dataCount = smb_GetSMBParm(inp, 5);
1768 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1769 parmCount, dataCount);
1772 /* now copy the parms and data */
1773 if ( asp->totalParms > 0 && parmCount != 0 )
1775 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1777 if ( asp->totalData > 0 && dataCount != 0 ) {
1778 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1781 /* account for new bytes */
1782 asp->curData += dataCount;
1783 asp->curParms += parmCount;
1785 /* finally, if we're done, remove the packet from the queue and dispatch it */
1786 if (((asp->totalParms > 0 && asp->curParms > 0)
1787 || asp->setupCount == 2) &&
1788 asp->totalData <= asp->curData &&
1789 asp->totalParms <= asp->curParms) {
1791 /* we've received it all */
1792 lock_ObtainWrite(&smb_globalLock);
1793 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1794 lock_ReleaseWrite(&smb_globalLock);
1796 switch(asp->setupCount) {
1799 rapOp = asp->parmsp[0];
1801 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES &&
1802 smb_rapDispatchTable[rapOp].procp) {
1804 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",
1805 myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1807 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1809 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",
1810 code,vcp,vcp->lana,vcp->lsn);
1813 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]",
1814 rapOp, vcp, vcp->lana, vcp->lsn);
1816 code = CM_ERROR_BADOP;
1822 { /* Named pipe operation */
1823 osi_Log2(smb_logp, "Named Pipe: %s with name [%S]",
1824 myCrt_NmpipeDispatch(asp->pipeCommand),
1825 osi_LogSaveClientString(smb_logp, asp->name));
1827 code = CM_ERROR_BADOP;
1829 switch (asp->pipeCommand) {
1830 case SMB_TRANS_SET_NMPIPE_STATE:
1831 code = smb_nmpipeSetState(vcp, asp, outp);
1834 case SMB_TRANS_RAW_READ_NMPIPE:
1837 case SMB_TRANS_QUERY_NMPIPE_STATE:
1840 case SMB_TRANS_QUERY_NMPIPE_INFO:
1843 case SMB_TRANS_PEEK_NMPIPE:
1846 case SMB_TRANS_TRANSACT_NMPIPE:
1847 code = smb_nmpipeTransact(vcp, asp, outp);
1850 case SMB_TRANS_RAW_WRITE_NMPIPE:
1853 case SMB_TRANS_READ_NMPIPE:
1856 case SMB_TRANS_WRITE_NMPIPE:
1859 case SMB_TRANS_WAIT_NMPIPE:
1862 case SMB_TRANS_CALL_NMPIPE:
1869 code = CM_ERROR_BADOP;
1872 /* if an error is returned, we're supposed to send an error packet,
1873 * otherwise the dispatched function already did the data sending.
1874 * We give dispatched proc the responsibility since it knows how much
1875 * space to allocate.
1878 smb_SendTran2Error(vcp, asp, outp, code);
1881 /* free the input tran 2 packet */
1882 smb_FreeTran2Packet(asp);
1884 else if (firstPacket) {
1885 /* the first packet in a multi-packet request, we need to send an
1886 * ack to get more data.
1888 smb_SetSMBDataLength(outp, 0);
1889 smb_SendPacket(vcp, outp);
1895 /* ANSI versions. */
1897 #pragma pack(push, 1)
1899 typedef struct smb_rap_share_info_0 {
1900 BYTE shi0_netname[13];
1901 } smb_rap_share_info_0_t;
1903 typedef struct smb_rap_share_info_1 {
1904 BYTE shi1_netname[13];
1907 DWORD shi1_remark; /* char *shi1_remark; data offset */
1908 } smb_rap_share_info_1_t;
1910 typedef struct smb_rap_share_info_2 {
1911 BYTE shi2_netname[13];
1914 DWORD shi2_remark; /* char *shi2_remark; data offset */
1915 WORD shi2_permissions;
1917 WORD shi2_current_uses;
1918 DWORD shi2_path; /* char *shi2_path; data offset */
1919 WORD shi2_passwd[9];
1921 } smb_rap_share_info_2_t;
1923 #define SMB_RAP_MAX_SHARES 512
1925 typedef struct smb_rap_share_list {
1928 smb_rap_share_info_0_t * shares;
1929 } smb_rap_share_list_t;
1933 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1934 smb_rap_share_list_t * sp;
1936 if (dep->name[0] == '.' && (!dep->name[1] || (dep->name[1] == '.' && !dep->name[2])))
1937 return 0; /* skip over '.' and '..' */
1939 sp = (smb_rap_share_list_t *) vrockp;
1941 strncpy(sp->shares[sp->cShare].shi0_netname, dep->name, 12);
1942 sp->shares[sp->cShare].shi0_netname[12] = 0;
1946 if (sp->cShare >= sp->maxShares)
1947 return CM_ERROR_STOPNOW;
1952 /* RAP NetShareEnumRequest */
1953 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1955 smb_tran2Packet_t *outp;
1956 unsigned short * tp;
1960 int outParmsTotal; /* total parameter bytes */
1961 int outDataTotal; /* total data bytes */
1964 DWORD allSubmount = 0;
1966 DWORD nRegShares = 0;
1967 DWORD nSharesRet = 0;
1969 HKEY hkSubmount = NULL;
1970 smb_rap_share_info_1_t * shares;
1973 clientchar_t thisShare[AFSPATHMAX];
1977 smb_rap_share_list_t rootShares;
1981 cm_scache_t *rootScp;
1983 tp = p->parmsp + 1; /* skip over function number (always 0) */
1986 clientchar_t * cdescp;
1988 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1989 if (cm_ClientStrCmp(cdescp, _C("WrLeh")))
1990 return CM_ERROR_INVAL;
1991 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1992 if (cm_ClientStrCmp(cdescp, _C("B13BWz")))
1993 return CM_ERROR_INVAL;
1999 if (infoLevel != 1) {
2000 return CM_ERROR_INVAL;
2003 /* We are supposed to use the same ASCII data structure even if
2004 Unicode is negotiated, which ultimately means that the share
2005 names that we return must be at most 13 characters in length,
2006 including the NULL terminator.
2008 The RAP specification states that shares with names longer than
2009 12 characters should not be included in the enumeration.
2010 However, since we support prefix cell references and since many
2011 cell names are going to exceed 12 characters, we lie and send
2012 the first 12 characters.
2015 /* first figure out how many shares there are */
2016 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
2017 KEY_QUERY_VALUE, &hkParam);
2018 if (rv == ERROR_SUCCESS) {
2019 len = sizeof(allSubmount);
2020 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
2021 (BYTE *) &allSubmount, &len);
2022 if (rv != ERROR_SUCCESS || allSubmount != 0) {
2025 RegCloseKey (hkParam);
2028 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
2029 0, KEY_QUERY_VALUE, &hkSubmount);
2030 if (rv == ERROR_SUCCESS) {
2031 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
2032 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
2033 if (rv != ERROR_SUCCESS)
2039 /* fetch the root shares */
2040 rootShares.maxShares = SMB_RAP_MAX_SHARES;
2041 rootShares.cShare = 0;
2042 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
2046 userp = smb_GetTran2User(vcp,p);
2048 thyper.HighPart = 0;
2051 rootScp = cm_RootSCachep(userp, &req);
2052 cm_HoldSCache(rootScp);
2053 cm_ApplyDir(rootScp, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
2054 cm_ReleaseSCache(rootScp);
2056 cm_ReleaseUser(userp);
2058 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
2060 #define REMARK_LEN 1
2061 outParmsTotal = 8; /* 4 dwords */
2062 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
2063 if(outDataTotal > bufsize) {
2064 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
2065 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
2068 nSharesRet = nShares;
2071 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
2073 /* now for the submounts */
2074 shares = (smb_rap_share_info_1_t *) outp->datap;
2075 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
2077 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
2080 StringCchCopyA(shares[cshare].shi1_netname,
2081 lengthof(shares[cshare].shi1_netname), "all" );
2082 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
2083 /* type and pad are zero already */
2089 for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
2090 len = sizeof(thisShare);
2091 rv = RegEnumValueW(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
2092 if (rv == ERROR_SUCCESS &&
2093 cm_ClientStrLen(thisShare) &&
2094 (!allSubmount || cm_ClientStrCmpI(thisShare,_C("all")))) {
2095 cm_ClientStringToUtf8(thisShare, -1, shares[cshare].shi1_netname,
2096 lengthof( shares[cshare].shi1_netname ));
2097 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
2098 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
2103 nShares--; /* uncount key */
2106 RegCloseKey(hkSubmount);
2109 nonrootShares = cshare;
2111 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
2112 /* in case there are collisions with submounts, submounts have
2114 for (j=0; j < nonrootShares; j++)
2115 if (!cm_stricmp_utf8(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
2118 if (j < nonrootShares) {
2119 nShares--; /* uncount */
2123 StringCchCopyA(shares[cshare].shi1_netname, lengthof(shares[cshare].shi1_netname),
2124 rootShares.shares[i].shi0_netname);
2125 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
2130 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
2131 outp->parmsp[1] = 0;
2132 outp->parmsp[2] = cshare;
2133 outp->parmsp[3] = nShares;
2135 outp->totalData = (int)(cstrp - outp->datap);
2136 outp->totalParms = outParmsTotal;
2138 smb_SendTran2Packet(vcp, outp, op);
2139 smb_FreeTran2Packet(outp);
2141 free(rootShares.shares);
2146 /* RAP NetShareGetInfo */
2147 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2149 smb_tran2Packet_t *outp;
2150 unsigned short * tp;
2151 clientchar_t * shareName;
2152 BOOL shareFound = FALSE;
2153 unsigned short infoLevel;
2154 unsigned short bufsize;
2163 cm_scache_t *scp = NULL;
2169 tp = p->parmsp + 1; /* skip over function number (always 1) */
2172 clientchar_t * cdescp;
2174 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2175 if (cm_ClientStrCmp(cdescp, _C("zWrLh")))
2177 return CM_ERROR_INVAL;
2179 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2180 if (cm_ClientStrCmp(cdescp, _C("B13")) &&
2181 cm_ClientStrCmp(cdescp, _C("B13BWz")) &&
2182 cm_ClientStrCmp(cdescp, _C("B13BWzWWWzB9B")))
2184 return CM_ERROR_INVAL;
2186 shareName = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2194 totalData = sizeof(smb_rap_share_info_0_t);
2195 else if(infoLevel == SMB_INFO_STANDARD)
2196 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
2197 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
2198 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
2200 return CM_ERROR_INVAL;
2202 if(!cm_ClientStrCmpI(shareName, _C("all")) || !cm_ClientStrCmp(shareName,_C("*."))) {
2203 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
2204 KEY_QUERY_VALUE, &hkParam);
2205 if (rv == ERROR_SUCCESS) {
2206 len = sizeof(allSubmount);
2207 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
2208 (BYTE *) &allSubmount, &len);
2209 if (rv != ERROR_SUCCESS || allSubmount != 0) {
2212 RegCloseKey (hkParam);
2219 userp = smb_GetTran2User(vcp, p);
2221 osi_Log1(smb_logp,"ReceiveRAPNetShareGetInfo unable to resolve user [%d]", p->uid);
2222 return CM_ERROR_BADSMB;
2224 code = cm_NameI(cm_RootSCachep(userp, &req), shareName,
2225 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
2226 userp, NULL, &req, &scp);
2228 cm_ReleaseSCache(scp);
2231 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
2232 KEY_QUERY_VALUE, &hkSubmount);
2233 if (rv == ERROR_SUCCESS) {
2234 rv = RegQueryValueExW(hkSubmount, shareName, NULL, NULL, NULL, NULL);
2235 if (rv == ERROR_SUCCESS) {
2238 RegCloseKey(hkSubmount);
2244 return CM_ERROR_BADSHARENAME;
2246 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
2247 memset(outp->datap, 0, totalData);
2249 outp->parmsp[0] = 0;
2250 outp->parmsp[1] = 0;
2251 outp->parmsp[2] = totalData;
2253 if (infoLevel == 0) {
2254 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
2255 cm_ClientStringToUtf8(shareName, -1, info->shi0_netname,
2256 lengthof(info->shi0_netname));
2257 } else if(infoLevel == SMB_INFO_STANDARD) {
2258 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
2259 cm_ClientStringToUtf8(shareName, -1, info->shi1_netname, lengthof(info->shi1_netname));
2260 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
2261 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
2262 /* type and pad are already zero */
2263 } else { /* infoLevel==2 */
2264 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
2265 cm_ClientStringToUtf8(shareName, -1, info->shi2_netname, lengthof(info->shi2_netname));
2266 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
2267 info->shi2_permissions = ACCESS_ALL;
2268 info->shi2_max_uses = (unsigned short) -1;
2269 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
2272 outp->totalData = totalData;
2273 outp->totalParms = totalParam;
2275 smb_SendTran2Packet(vcp, outp, op);
2276 smb_FreeTran2Packet(outp);
2281 #pragma pack(push, 1)
2283 typedef struct smb_rap_wksta_info_10 {
2284 DWORD wki10_computername; /*char *wki10_computername;*/
2285 DWORD wki10_username; /* char *wki10_username; */
2286 DWORD wki10_langroup; /* char *wki10_langroup;*/
2287 BYTE wki10_ver_major;
2288 BYTE wki10_ver_minor;
2289 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
2290 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
2291 } smb_rap_wksta_info_10_t;
2295 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2297 smb_tran2Packet_t *outp;
2301 unsigned short * tp;
2304 smb_rap_wksta_info_10_t * info;
2308 tp = p->parmsp + 1; /* Skip over function number */
2311 clientchar_t * cdescp;
2313 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2314 SMB_STRF_FORCEASCII);
2315 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2316 return CM_ERROR_INVAL;
2318 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2319 SMB_STRF_FORCEASCII);
2320 if (cm_ClientStrCmp(cdescp, _C("zzzBBzz")))
2321 return CM_ERROR_INVAL;
2327 if (infoLevel != 10) {
2328 return CM_ERROR_INVAL;
2334 totalData = sizeof(*info) + /* info */
2335 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
2336 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
2337 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
2338 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
2339 1; /* wki10_oth_domains (null)*/
2341 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2343 memset(outp->parmsp,0,totalParams);
2344 memset(outp->datap,0,totalData);
2346 info = (smb_rap_wksta_info_10_t *) outp->datap;
2347 cstrp = (char *) (info + 1);
2349 info->wki10_computername = (DWORD) (cstrp - outp->datap);
2350 StringCbCopyA(cstrp, totalData, smb_localNamep);
2351 cstrp += strlen(cstrp) + 1;
2353 info->wki10_username = (DWORD) (cstrp - outp->datap);
2354 uidp = smb_FindUID(vcp, p->uid, 0);
2356 lock_ObtainMutex(&uidp->mx);
2357 if(uidp->unp && uidp->unp->name)
2358 cm_ClientStringToUtf8(uidp->unp->name, -1,
2359 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2360 lock_ReleaseMutex(&uidp->mx);
2361 smb_ReleaseUID(uidp);
2363 cstrp += strlen(cstrp) + 1;
2365 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
2366 StringCbCopyA(cstrp, totalData - (cstrp - outp->datap)*sizeof(char), "WORKGROUP");
2367 cstrp += strlen(cstrp) + 1;
2369 /* TODO: Not sure what values these should take, but these work */
2370 info->wki10_ver_major = 5;
2371 info->wki10_ver_minor = 1;
2373 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
2374 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
2375 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2376 cstrp += strlen(cstrp) + 1;
2378 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
2379 cstrp ++; /* no other domains */
2381 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
2382 outp->parmsp[2] = outp->totalData;
2383 outp->totalParms = totalParams;
2385 smb_SendTran2Packet(vcp,outp,op);
2386 smb_FreeTran2Packet(outp);
2391 #pragma pack(push, 1)
2393 typedef struct smb_rap_server_info_0 {
2395 } smb_rap_server_info_0_t;
2397 typedef struct smb_rap_server_info_1 {
2399 BYTE sv1_version_major;
2400 BYTE sv1_version_minor;
2402 DWORD sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
2403 } smb_rap_server_info_1_t;
2407 char smb_ServerComment[] = "OpenAFS Client";
2408 int smb_ServerCommentLen = sizeof(smb_ServerComment);
2410 #define SMB_SV_TYPE_SERVER 0x00000002L
2411 #define SMB_SV_TYPE_NT 0x00001000L
2412 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
2414 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2416 smb_tran2Packet_t *outp;
2420 unsigned short * tp;
2423 smb_rap_server_info_0_t * info0;
2424 smb_rap_server_info_1_t * info1;
2427 tp = p->parmsp + 1; /* Skip over function number */
2430 clientchar_t * cdescp;
2432 cdescp = smb_ParseStringT2Parm(p, (unsigned char *) tp, (char **) &tp,
2433 SMB_STRF_FORCEASCII);
2434 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2435 return CM_ERROR_INVAL;
2436 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2437 SMB_STRF_FORCEASCII);
2438 if (cm_ClientStrCmp(cdescp, _C("B16")) ||
2439 cm_ClientStrCmp(cdescp, _C("B16BBDz")))
2440 return CM_ERROR_INVAL;
2446 if (infoLevel != 0 && infoLevel != 1) {
2447 return CM_ERROR_INVAL;
2453 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
2454 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
2456 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2458 memset(outp->parmsp,0,totalParams);
2459 memset(outp->datap,0,totalData);
2461 if (infoLevel == 0) {
2462 info0 = (smb_rap_server_info_0_t *) outp->datap;
2463 cstrp = (char *) (info0 + 1);
2464 StringCchCopyA(info0->sv0_name, lengthof(info0->sv0_name), "AFS");
2465 } else { /* infoLevel == SMB_INFO_STANDARD */
2466 info1 = (smb_rap_server_info_1_t *) outp->datap;
2467 cstrp = (char *) (info1 + 1);
2468 StringCchCopyA(info1->sv1_name, lengthof(info1->sv1_name), "AFS");
2471 SMB_SV_TYPE_SERVER |
2473 SMB_SV_TYPE_SERVER_NT;
2475 info1->sv1_version_major = 5;
2476 info1->sv1_version_minor = 1;
2477 info1->sv1_comment_or_master_browser = (DWORD) (cstrp - outp->datap);
2479 StringCbCopyA(cstrp, smb_ServerCommentLen, smb_ServerComment);
2481 cstrp += smb_ServerCommentLen / sizeof(char);
2484 totalData = (DWORD)(cstrp - outp->datap);
2485 outp->totalData = min(bufsize,totalData); /* actual data size */
2486 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
2487 outp->parmsp[2] = totalData;
2488 outp->totalParms = totalParams;
2490 smb_SendTran2Packet(vcp,outp,op);
2491 smb_FreeTran2Packet(outp);
2496 /* SMB_COM_TRANSACTION2 and SMB_COM_TRANSACTION2_SECONDARY */
2497 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2499 smb_tran2Packet_t *asp;
2510 DWORD oldTime, newTime;
2512 /* We sometimes see 0 word count. What to do? */
2513 if (*inp->wctp == 0) {
2514 osi_Log0(smb_logp, "Transaction2 word count = 0");
2515 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
2517 smb_SetSMBDataLength(outp, 0);
2518 smb_SendPacket(vcp, outp);
2522 totalParms = smb_GetSMBParm(inp, 0);
2523 totalData = smb_GetSMBParm(inp, 1);
2525 firstPacket = (inp->inCom == 0x32);
2527 /* find the packet we're reassembling */
2528 lock_ObtainWrite(&smb_globalLock);
2529 asp = smb_FindTran2Packet(vcp, inp);
2531 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
2533 lock_ReleaseWrite(&smb_globalLock);
2535 /* now merge in this latest packet; start by looking up offsets */
2537 parmDisp = dataDisp = 0;
2538 parmOffset = smb_GetSMBParm(inp, 10);
2539 dataOffset = smb_GetSMBParm(inp, 12);
2540 parmCount = smb_GetSMBParm(inp, 9);
2541 dataCount = smb_GetSMBParm(inp, 11);
2542 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2543 asp->maxReturnData = smb_GetSMBParm(inp, 3);
2545 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2546 totalData, dataCount, asp->maxReturnData);
2549 parmDisp = smb_GetSMBParm(inp, 4);
2550 parmOffset = smb_GetSMBParm(inp, 3);
2551 dataDisp = smb_GetSMBParm(inp, 7);
2552 dataOffset = smb_GetSMBParm(inp, 6);
2553 parmCount = smb_GetSMBParm(inp, 2);
2554 dataCount = smb_GetSMBParm(inp, 5);
2556 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2557 parmCount, dataCount);
2560 /* now copy the parms and data */
2561 if ( asp->totalParms > 0 && parmCount != 0 )
2563 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2565 if ( asp->totalData > 0 && dataCount != 0 ) {
2566 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2569 /* account for new bytes */
2570 asp->curData += dataCount;
2571 asp->curParms += parmCount;
2573 /* finally, if we're done, remove the packet from the queue and dispatch it */
2574 if (asp->totalParms > 0 &&
2575 asp->curParms > 0 &&
2576 asp->totalData <= asp->curData &&
2577 asp->totalParms <= asp->curParms) {
2578 /* we've received it all */
2579 lock_ObtainWrite(&smb_globalLock);
2580 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2581 lock_ReleaseWrite(&smb_globalLock);
2583 oldTime = GetTickCount();
2585 /* now dispatch it */
2586 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2587 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2588 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2591 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2592 code = CM_ERROR_BADOP;
2595 /* if an error is returned, we're supposed to send an error packet,
2596 * otherwise the dispatched function already did the data sending.
2597 * We give dispatched proc the responsibility since it knows how much
2598 * space to allocate.
2601 smb_SendTran2Error(vcp, asp, outp, code);
2604 newTime = GetTickCount();
2605 if (newTime - oldTime > 45000) {
2608 clientchar_t *treepath = NULL; /* do not free */
2609 clientchar_t *pathname = NULL;
2610 cm_fid_t afid = {0,0,0,0,0};
2612 uidp = smb_FindUID(vcp, asp->uid, 0);
2613 smb_LookupTIDPath(vcp, asp->tid, &treepath);
2614 fidp = smb_FindFID(vcp, inp->fid, 0);
2617 lock_ObtainMutex(&fidp->mx);
2618 if (fidp->NTopen_pathp)
2619 pathname = fidp->NTopen_pathp;
2621 afid = fidp->scp->fid;
2623 if (inp->stringsp->wdata)
2624 pathname = inp->stringsp->wdata;
2627 afsi_log("Request %s duration %d ms user 0x%x \"%S\" pid 0x%x mid 0x%x tid 0x%x \"%S\" path? \"%S\" afid (%d.%d.%d.%d)",
2628 myCrt_2Dispatch(asp->opcode), newTime - oldTime,
2629 asp->uid, uidp ? uidp->unp->name : NULL,
2630 asp->pid, asp->mid, asp->tid,
2633 afid.cell, afid.volume, afid.vnode, afid.unique);
2636 lock_ReleaseMutex(&fidp->mx);
2639 smb_ReleaseUID(uidp);
2641 smb_ReleaseFID(fidp);
2644 /* free the input tran 2 packet */
2645 smb_FreeTran2Packet(asp);
2647 else if (firstPacket) {
2648 /* the first packet in a multi-packet request, we need to send an
2649 * ack to get more data.
2651 smb_SetSMBDataLength(outp, 0);
2652 smb_SendPacket(vcp, outp);
2659 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2661 clientchar_t *pathp;
2662 smb_tran2Packet_t *outp;
2667 cm_scache_t *dscp; /* dir we're dealing with */
2668 cm_scache_t *scp; /* file we're creating */
2672 clientchar_t *lastNamep;
2679 int parmSlot; /* which parm we're dealing with */
2680 long returnEALength;
2681 clientchar_t *tidPathp;
2684 BOOL is_rpc = FALSE;
2685 BOOL is_ipc = FALSE;
2691 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2692 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2694 openFun = p->parmsp[6]; /* open function */
2695 excl = ((openFun & 3) == 0);
2696 trunc = ((openFun & 3) == 2); /* truncate it */
2697 openMode = (p->parmsp[1] & 0x7);
2698 openAction = 0; /* tracks what we did */
2700 attributes = p->parmsp[3];
2701 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2703 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
2706 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2708 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2709 if (code == CM_ERROR_TIDIPC) {
2711 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2714 spacep = cm_GetSpace();
2715 /* smb_StripLastComponent will strip "::$DATA" if present */
2716 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2720 /* special case magic file name for receiving IOCTL requests
2721 * (since IOCTL calls themselves aren't getting through).
2723 (cm_ClientStrCmpI(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
2725 /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional)*/
2726 (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
2728 unsigned short file_type = 0;
2729 unsigned short device_state = 0;
2731 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2734 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
2735 osi_Log2(smb_logp, "smb_ReceiveTran2Open Creating RPC Fid [%d] code [%d]",
2738 smb_ReleaseFID(fidp);
2739 smb_FreeTran2Packet(outp);
2740 osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
2744 smb_SetupIoctlFid(fidp, spacep);
2745 osi_Log1(smb_logp, "smb_ReceiveTran2Open Creating IOCTL Fid [%d]", fidp->fid);
2748 /* copy out remainder of the parms */
2750 outp->parmsp[parmSlot++] = fidp->fid;
2752 outp->parmsp[parmSlot++] = 0; /* attrs */
2753 outp->parmsp[parmSlot++] = 0; /* mod time */
2754 outp->parmsp[parmSlot++] = 0;
2755 outp->parmsp[parmSlot++] = 0; /* len */
2756 outp->parmsp[parmSlot++] = 0x7fff;
2757 outp->parmsp[parmSlot++] = openMode;
2758 outp->parmsp[parmSlot++] = file_type;
2759 outp->parmsp[parmSlot++] = device_state;
2761 /* and the final "always present" stuff */
2762 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2763 /* next write out the "unique" ID */
2764 outp->parmsp[parmSlot++] = 0x1234;
2765 outp->parmsp[parmSlot++] = 0x5678;
2766 outp->parmsp[parmSlot++] = 0;
2767 if (returnEALength) {
2768 outp->parmsp[parmSlot++] = 0;
2769 outp->parmsp[parmSlot++] = 0;
2772 outp->totalData = 0;
2773 outp->totalParms = parmSlot * 2;
2775 smb_SendTran2Packet(vcp, outp, op);
2777 smb_FreeTran2Packet(outp);
2779 /* and clean up fid reference */
2780 smb_ReleaseFID(fidp);
2786 osi_Log1(smb_logp, "Tran2Open rejecting IPC TID vcp %p", vcp);
2787 smb_FreeTran2Packet(outp);
2788 return CM_ERROR_BADFD;
2792 if (!cm_IsValidClientString(pathp)) {
2794 clientchar_t * hexp;
2796 hexp = cm_GetRawCharsAlloc(pathp, -1);
2797 osi_Log1(smb_logp, "Tran2Open rejecting invalid name. [%S]",
2798 osi_LogSaveClientString(smb_logp, hexp));
2802 osi_Log0(smb_logp, "Tran2Open rejecting invalid name");
2804 smb_FreeTran2Packet(outp);
2805 return CM_ERROR_BADNTFILENAME;
2808 #ifdef DEBUG_VERBOSE
2810 char *hexp, *asciip;
2811 asciip = (lastNamep ? lastNamep : pathp);
2812 hexp = osi_HexifyString( asciip );
2813 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2818 userp = smb_GetTran2User(vcp, p);
2819 /* In the off chance that userp is NULL, we log and abandon */
2821 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2822 smb_FreeTran2Packet(outp);
2823 return CM_ERROR_BADSMB;
2827 code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
2828 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2829 userp, tidPathp, &req, &scp);
2831 if (code == CM_ERROR_NOSUCHFILE ||
2832 code == CM_ERROR_NOSUCHPATH ||
2833 code == CM_ERROR_BPLUS_NOMATCH)
2834 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
2835 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2836 userp, tidPathp, &req, &dscp);
2837 cm_FreeSpace(spacep);
2840 cm_ReleaseUser(userp);
2841 smb_FreeTran2Packet(outp);
2846 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2847 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2848 (clientchar_t*) spacep->data);
2849 cm_ReleaseSCache(dscp);
2850 cm_ReleaseUser(userp);
2851 smb_FreeTran2Packet(outp);
2852 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2853 return CM_ERROR_PATH_NOT_COVERED;
2855 return CM_ERROR_NOSUCHPATH;
2857 #endif /* DFS_SUPPORT */
2859 /* otherwise, scp points to the parent directory. Do a lookup,
2860 * and truncate the file if we find it, otherwise we create the
2867 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2869 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2870 cm_ReleaseSCache(dscp);
2871 cm_ReleaseUser(userp);
2872 smb_FreeTran2Packet(outp);
2876 /* macintosh is expensive to program for it */
2877 cm_FreeSpace(spacep);
2880 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2881 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2882 cm_ReleaseSCache(scp);
2883 cm_ReleaseUser(userp);
2884 smb_FreeTran2Packet(outp);
2885 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2886 return CM_ERROR_PATH_NOT_COVERED;
2888 return CM_ERROR_NOSUCHPATH;
2890 #endif /* DFS_SUPPORT */
2893 /* if we get here, if code is 0, the file exists and is represented by
2894 * scp. Otherwise, we have to create it.
2897 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2900 cm_ReleaseSCache(dscp);
2901 cm_ReleaseSCache(scp);
2902 cm_ReleaseUser(userp);
2903 smb_FreeTran2Packet(outp);
2908 /* oops, file shouldn't be there */
2910 cm_ReleaseSCache(dscp);
2911 cm_ReleaseSCache(scp);
2912 cm_ReleaseUser(userp);
2913 smb_FreeTran2Packet(outp);
2914 return CM_ERROR_EXISTS;
2918 setAttr.mask = CM_ATTRMASK_LENGTH;
2919 setAttr.length.LowPart = 0;
2920 setAttr.length.HighPart = 0;
2921 code = cm_SetAttr(scp, &setAttr, userp, &req);
2922 openAction = 3; /* truncated existing file */
2925 openAction = 1; /* found existing file */
2927 else if (!(openFun & 0x10)) {
2928 /* don't create if not found */
2930 cm_ReleaseSCache(dscp);
2931 osi_assertx(scp == NULL, "null cm_scache_t");
2932 cm_ReleaseUser(userp);
2933 smb_FreeTran2Packet(outp);
2934 return CM_ERROR_NOSUCHFILE;
2937 osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2938 openAction = 2; /* created file */
2939 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2940 cm_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2941 smb_SetInitialModeBitsForFile(attributes, &setAttr);
2943 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2947 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2948 smb_NotifyChange(FILE_ACTION_ADDED,
2949 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2950 dscp, lastNamep, NULL, TRUE);
2951 } else if (!excl && code == CM_ERROR_EXISTS) {
2952 /* not an exclusive create, and someone else tried
2953 * creating it already, then we open it anyway. We
2954 * don't bother retrying after this, since if this next
2955 * fails, that means that the file was deleted after we
2956 * started this call.
2958 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2962 setAttr.mask = CM_ATTRMASK_LENGTH;
2963 setAttr.length.LowPart = 0;
2964 setAttr.length.HighPart = 0;
2965 code = cm_SetAttr(scp, &setAttr, userp,
2968 } /* lookup succeeded */
2972 /* we don't need this any longer */
2974 cm_ReleaseSCache(dscp);
2977 /* something went wrong creating or truncating the file */
2979 cm_ReleaseSCache(scp);
2980 cm_ReleaseUser(userp);
2981 smb_FreeTran2Packet(outp);
2985 /* make sure we're about to open a file */
2986 if (scp->fileType != CM_SCACHETYPE_FILE) {
2988 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2989 cm_scache_t * targetScp = 0;
2990 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2992 /* we have a more accurate file to use (the
2993 * target of the symbolic link). Otherwise,
2994 * we'll just use the symlink anyway.
2996 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2998 cm_ReleaseSCache(scp);
3002 if (scp->fileType != CM_SCACHETYPE_FILE) {
3003 cm_ReleaseSCache(scp);
3004 cm_ReleaseUser(userp);
3005 smb_FreeTran2Packet(outp);
3006 return CM_ERROR_ISDIR;
3010 /* now all we have to do is open the file itself */
3011 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3012 osi_assertx(fidp, "null smb_fid_t");
3015 lock_ObtainMutex(&fidp->mx);
3016 /* save a pointer to the vnode */
3017 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
3019 lock_ObtainWrite(&scp->rw);
3020 scp->flags |= CM_SCACHEFLAG_SMB_FID;
3021 lock_ReleaseWrite(&scp->rw);
3024 fidp->userp = userp;
3026 /* compute open mode */
3028 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
3029 if (openMode == 1 || openMode == 2)
3030 fidp->flags |= SMB_FID_OPENWRITE;
3032 /* remember that the file was newly created */
3034 fidp->flags |= SMB_FID_CREATED;
3036 lock_ReleaseMutex(&fidp->mx);
3038 smb_ReleaseFID(fidp);
3040 cm_Open(scp, 0, userp);
3042 /* copy out remainder of the parms */
3044 outp->parmsp[parmSlot++] = fidp->fid;
3045 lock_ObtainRead(&scp->rw);
3047 outp->parmsp[parmSlot++] = smb_Attributes(scp);
3048 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3049 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
3050 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
3051 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
3052 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
3053 outp->parmsp[parmSlot++] = openMode;
3054 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
3055 outp->parmsp[parmSlot++] = 0; /* IPC junk */
3057 /* and the final "always present" stuff */
3058 outp->parmsp[parmSlot++] = openAction;
3059 /* next write out the "unique" ID */
3060 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
3061 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
3062 outp->parmsp[parmSlot++] = 0;
3063 if (returnEALength) {
3064 outp->parmsp[parmSlot++] = 0;
3065 outp->parmsp[parmSlot++] = 0;
3067 lock_ReleaseRead(&scp->rw);
3068 outp->totalData = 0; /* total # of data bytes */
3069 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
3071 smb_SendTran2Packet(vcp, outp, op);
3073 smb_FreeTran2Packet(outp);
3075 cm_ReleaseUser(userp);
3076 /* leave scp held since we put it in fidp->scp */
3080 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3083 unsigned short infolevel;
3085 infolevel = p->parmsp[0];
3087 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
3089 return CM_ERROR_BAD_LEVEL;
3092 /* TRANS2_QUERY_FS_INFORMATION */
3093 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3095 smb_tran2Packet_t *outp;
3096 smb_tran2QFSInfo_t qi;
3100 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
3102 switch (p->parmsp[0]) {
3103 case SMB_INFO_ALLOCATION:
3105 responseSize = sizeof(qi.u.allocInfo);
3107 qi.u.allocInfo.FSID = 0;
3108 qi.u.allocInfo.sectorsPerAllocUnit = 1;
3109 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
3110 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
3111 qi.u.allocInfo.bytesPerSector = 1024;
3114 case SMB_INFO_VOLUME:
3116 qi.u.volumeInfo.vsn = 1234; /* Volume serial number */
3117 qi.u.volumeInfo.vnCount = 3; /* Number of characters in label (AFS\0)*/
3119 /* we're supposed to pad it out with zeroes to the end */
3120 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
3121 smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
3123 responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
3126 case SMB_QUERY_FS_VOLUME_INFO:
3127 /* FS volume info */
3128 responseSize = sizeof(qi.u.FSvolumeInfo);
3131 FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
3132 memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
3135 qi.u.FSvolumeInfo.vsn = 1234;
3136 qi.u.FSvolumeInfo.vnCount = 6; /* This is always in Unicode */
3137 memset(&qi.u.FSvolumeInfo.label, 0, sizeof(qi.u.FSvolumeInfo.label));
3138 memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
3141 case SMB_QUERY_FS_SIZE_INFO:
3143 responseSize = sizeof(qi.u.FSsizeInfo);
3145 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
3146 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
3147 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
3148 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
3149 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
3150 qi.u.FSsizeInfo.bytesPerSector = 1024;
3153 case SMB_QUERY_FS_DEVICE_INFO:
3154 /* FS device info */
3155 responseSize = sizeof(qi.u.FSdeviceInfo);
3157 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
3158 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
3161 case SMB_QUERY_FS_ATTRIBUTE_INFO:
3162 /* FS attribute info */
3164 /* attributes, defined in WINNT.H:
3165 * FILE_CASE_SENSITIVE_SEARCH 0x1
3166 * FILE_CASE_PRESERVED_NAMES 0x2
3167 * FILE_UNICODE_ON_DISK 0x4
3168 * FILE_VOLUME_QUOTAS 0x10
3169 * <no name defined> 0x4000
3170 * If bit 0x4000 is not set, Windows 95 thinks
3171 * we can't handle long (non-8.3) names,
3172 * despite our protestations to the contrary.
3174 qi.u.FSattributeInfo.attributes = 0x4003;
3175 /* The maxCompLength is supposed to be in bytes */
3177 qi.u.FSattributeInfo.attributes |= 0x04;
3179 qi.u.FSattributeInfo.maxCompLength = 255;
3180 smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
3181 qi.u.FSattributeInfo.FSnameLength = sz;
3184 sizeof(qi.u.FSattributeInfo.attributes) +
3185 sizeof(qi.u.FSattributeInfo.maxCompLength) +
3186 sizeof(qi.u.FSattributeInfo.FSnameLength) +
3191 case SMB_INFO_UNIX: /* CIFS Unix Info */
3192 case SMB_INFO_MACOS: /* Mac FS Info */
3194 return CM_ERROR_BADOP;
3197 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
3199 /* copy out return data, and set corresponding sizes */
3200 outp->totalParms = 0;
3201 outp->totalData = responseSize;
3202 memcpy(outp->datap, &qi, responseSize);
3204 /* send and free the packets */
3205 smb_SendTran2Packet(vcp, outp, op);
3206 smb_FreeTran2Packet(outp);
3211 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3213 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
3214 return CM_ERROR_BADOP;
3217 struct smb_ShortNameRock {
3218 clientchar_t *maskp;
3220 clientchar_t *shortName;
3221 size_t shortNameLen;
3224 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
3227 struct smb_ShortNameRock *rockp;
3228 normchar_t normName[MAX_PATH];
3229 clientchar_t *shortNameEnd;
3233 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t)) == 0) {
3234 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
3235 osi_LogSaveString(smb_logp, dep->name));
3239 /* compare both names and vnodes, though probably just comparing vnodes
3240 * would be safe enough.
3242 if (cm_NormStrCmpI(normName, rockp->maskp) != 0)
3244 if (ntohl(dep->fid.vnode) != rockp->vnode)
3247 /* This is the entry */
3248 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
3249 rockp->shortNameLen = shortNameEnd - rockp->shortName;
3251 return CM_ERROR_STOPNOW;
3254 long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
3255 clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
3257 struct smb_ShortNameRock rock;
3258 clientchar_t *lastNamep;
3261 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
3265 spacep = cm_GetSpace();
3266 /* smb_StripLastComponent will strip "::$DATA" if present */
3267 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
3269 code = cm_NameI(cm_RootSCachep(userp, reqp), spacep->wdata,
3270 caseFold, userp, tidPathp,
3272 cm_FreeSpace(spacep);
3277 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3278 cm_ReleaseSCache(dscp);
3279 cm_ReleaseUser(userp);
3283 return CM_ERROR_PATH_NOT_COVERED;
3285 #endif /* DFS_SUPPORT */
3287 if (!lastNamep) lastNamep = pathp;
3290 thyper.HighPart = 0;
3291 rock.shortName = shortName;
3293 rock.maskp = lastNamep;
3294 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
3296 cm_ReleaseSCache(dscp);
3299 return CM_ERROR_NOSUCHFILE;
3300 if (code == CM_ERROR_STOPNOW) {
3301 *shortNameLenp = rock.shortNameLen;
3307 /* TRANS2_QUERY_PATH_INFORMATION */
3308 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3310 smb_tran2Packet_t *outp;
3313 unsigned short infoLevel;
3314 smb_tran2QPathInfo_t qpi;
3316 unsigned short attributes;
3317 unsigned long extAttributes;
3318 clientchar_t shortName[13];
3322 cm_scache_t *scp, *dscp;
3323 int scp_rw_held = 0;
3326 clientchar_t *pathp;
3327 clientchar_t *tidPathp;
3328 clientchar_t *lastComp;
3333 infoLevel = p->parmsp[0];
3334 if (infoLevel == SMB_INFO_IS_NAME_VALID)
3336 else if (infoLevel == SMB_INFO_STANDARD)
3337 responseSize = sizeof(qpi.u.QPstandardInfo);
3338 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
3339 responseSize = sizeof(qpi.u.QPeaSizeInfo);
3340 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3341 responseSize = sizeof(qpi.u.QPfileBasicInfo);
3342 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3343 responseSize = sizeof(qpi.u.QPfileStandardInfo);
3344 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3345 responseSize = sizeof(qpi.u.QPfileEaInfo);
3346 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3347 responseSize = sizeof(qpi.u.QPfileNameInfo);
3348 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
3349 responseSize = sizeof(qpi.u.QPfileAllInfo);
3350 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
3351 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
3352 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO)
3353 responseSize = sizeof(qpi.u.QPfileStreamInfo);
3355 osi_Log2(smb_logp, "Bad Tran2QPathInfo op 0x%x infolevel 0x%x",
3356 p->opcode, infoLevel);
3357 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3360 memset(&qpi, 0, sizeof(qpi));
3362 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3363 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path \"%S\"", infoLevel,
3364 osi_LogSaveClientString(smb_logp, pathp));
3366 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3368 if (infoLevel > 0x100)
3369 outp->totalParms = 2;
3371 outp->totalParms = 0;
3373 /* now, if we're at infoLevel 6, we're only being asked to check
3374 * the syntax, so we just OK things now. In particular, we're *not*
3375 * being asked to verify anything about the state of any parent dirs.
3377 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
3378 smb_SendTran2Packet(vcp, outp, opx);
3379 smb_FreeTran2Packet(outp);
3383 userp = smb_GetTran2User(vcp, p);
3385 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
3386 smb_FreeTran2Packet(outp);
3387 return CM_ERROR_BADSMB;
3390 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3392 osi_Log1(smb_logp, "ReceiveTran2QPathInfo tid path lookup failure 0x%x", code);
3393 cm_ReleaseUser(userp);
3394 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
3395 smb_FreeTran2Packet(outp);
3399 osi_Log1(smb_logp, "T2 QPathInfo tidPathp \"%S\"",
3400 osi_LogSaveClientString(smb_logp, tidPathp));
3403 * If the query is regarding the special _._AFS_IOCTL_._ file
3404 * a reply must be sent even though the file doesn't exist.
3406 if (cm_ClientStrCmpI(pathp, CM_IOCTL_FILENAME_NOSLASH_W) == 0)
3408 /* for info level 108, figure out short name */
3409 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3410 smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, L"_IOCTL_.AFS", &len, SMB_STRF_IGNORENUL);
3411 qpi.u.QPfileAltNameInfo.fileNameLength = len;
3412 responseSize = sizeof(unsigned long) + len;
3414 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3415 smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, CM_IOCTL_FILENAME_NOSLASH_W, &len, SMB_STRF_IGNORENUL);
3416 qpi.u.QPfileNameInfo.fileNameLength = len;
3417 responseSize = sizeof(unsigned long) + len;
3419 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3420 cm_SearchTimeFromUnixTime(&dosTime, 0);
3421 qpi.u.QPstandardInfo.creationDateTime = dosTime;
3422 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3423 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3424 qpi.u.QPstandardInfo.dataSize = 0;
3425 qpi.u.QPstandardInfo.allocationSize = 0;
3426 qpi.u.QPstandardInfo.attributes = SMB_ATTR_SYSTEM | SMB_ATTR_HIDDEN;
3427 qpi.u.QPstandardInfo.eaSize = 0;
3429 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3430 cm_LargeSearchTimeFromUnixTime(&ft, 0);
3431 qpi.u.QPfileBasicInfo.creationTime = ft;
3432 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3433 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3434 qpi.u.QPfileBasicInfo.changeTime = ft;
3435 qpi.u.QPfileBasicInfo.attributes = SMB_ATTR_SYSTEM | SMB_ATTR_HIDDEN;
3436 qpi.u.QPfileBasicInfo.reserved = 0;
3438 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3439 qpi.u.QPfileStandardInfo.allocationSize.QuadPart = 0;
3440 qpi.u.QPfileStandardInfo.endOfFile.QuadPart = 0;
3441 qpi.u.QPfileStandardInfo.numberOfLinks = 1;
3442 qpi.u.QPfileStandardInfo.directory = 0;
3443 qpi.u.QPfileStandardInfo.reserved = 0;
3444 qpi.u.QPfileStandardInfo.deletePending = 0;
3446 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3447 qpi.u.QPfileEaInfo.eaSize = 0;
3449 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3450 cm_LargeSearchTimeFromUnixTime(&ft, 0);
3451 qpi.u.QPfileAllInfo.creationTime = ft;
3452 qpi.u.QPfileAllInfo.lastAccessTime = ft;
3453 qpi.u.QPfileAllInfo.lastWriteTime = ft;
3454 qpi.u.QPfileAllInfo.changeTime = ft;
3455 qpi.u.QPfileAllInfo.attributes = SMB_ATTR_SYSTEM | SMB_ATTR_HIDDEN;
3456 qpi.u.QPfileAllInfo.allocationSize.QuadPart = 0;
3457 qpi.u.QPfileAllInfo.endOfFile.QuadPart = 0;
3458 qpi.u.QPfileAllInfo.numberOfLinks = 1;
3459 qpi.u.QPfileAllInfo.deletePending = 0;
3460 qpi.u.QPfileAllInfo.directory = 0;
3461 qpi.u.QPfileAllInfo.indexNumber.HighPart = 0;
3462 qpi.u.QPfileAllInfo.indexNumber.LowPart = 0;
3463 qpi.u.QPfileAllInfo.eaSize = 0;
3464 qpi.u.QPfileAllInfo.accessFlags = 0;
3465 qpi.u.QPfileAllInfo.indexNumber2.HighPart = 0;
3466 qpi.u.QPfileAllInfo.indexNumber2.LowPart = 0;
3467 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3468 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3469 qpi.u.QPfileAllInfo.mode = 0;
3470 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3472 smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, CM_IOCTL_FILENAME_NOSLASH_W, &len, SMB_STRF_IGNORENUL);
3473 qpi.u.QPfileAllInfo.fileNameLength = len;
3474 responseSize -= (sizeof(qpi.u.QPfileAllInfo.fileName) - len);
3476 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO) {
3478 /* For now we have no streams */
3479 qpi.u.QPfileStreamInfo.nextEntryOffset = 0;
3480 qpi.u.QPfileStreamInfo.streamSize.QuadPart = 0;
3481 qpi.u.QPfileStreamInfo.streamAllocationSize.QuadPart = 0;
3482 smb_UnparseString(opx, qpi.u.QPfileStreamInfo.fileName, L"::$DATA", &len, SMB_STRF_IGNORENUL);
3483 qpi.u.QPfileStreamInfo.streamNameLength = len;
3484 responseSize -= (sizeof(qpi.u.QPfileStreamInfo.fileName) - len);
3487 outp->totalData = responseSize;
3488 goto done_afs_ioctl;
3492 * XXX Strange hack XXX
3494 * As of Patch 7 (13 January 98), we are having the following problem:
3495 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3496 * requests to look up "desktop.ini" in all the subdirectories.
3497 * This can cause zillions of timeouts looking up non-existent cells
3498 * and volumes, especially in the top-level directory.
3500 * We have not found any way to avoid this or work around it except
3501 * to explicitly ignore the requests for mount points that haven't
3502 * yet been evaluated and for directories that haven't yet been
3505 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3506 spacep = cm_GetSpace();
3507 /* smb_StripLastComponent will strip "::$DATA" if present */
3508 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3509 #ifndef SPECIAL_FOLDERS
3510 /* Make sure that lastComp is not NULL */
3512 if (cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
3513 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
3517 userp, tidPathp, &req, &dscp);
3520 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3521 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3523 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3524 code = CM_ERROR_PATH_NOT_COVERED;
3526 code = CM_ERROR_NOSUCHPATH;
3528 #endif /* DFS_SUPPORT */
3529 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3530 code = CM_ERROR_NOSUCHFILE;
3531 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3532 cm_buf_t *bp = buf_Find(&dscp->fid, &hzero);
3538 code = CM_ERROR_NOSUCHFILE;
3540 cm_ReleaseSCache(dscp);
3542 cm_FreeSpace(spacep);
3543 cm_ReleaseUser(userp);
3544 smb_SendTran2Error(vcp, p, opx, code);
3545 smb_FreeTran2Packet(outp);
3551 #endif /* SPECIAL_FOLDERS */
3553 cm_FreeSpace(spacep);
3557 code == CM_ERROR_NOSUCHFILE ||
3558 code == CM_ERROR_NOSUCHPATH ||
3559 code == CM_ERROR_BPLUS_NOMATCH) {
3560 /* now do namei and stat, and copy out the info */
3561 code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
3562 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3566 cm_ReleaseUser(userp);
3567 smb_SendTran2Error(vcp, p, opx, code);
3568 smb_FreeTran2Packet(outp);
3573 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3574 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3575 cm_ReleaseSCache(scp);
3576 cm_ReleaseUser(userp);
3577 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3578 code = CM_ERROR_PATH_NOT_COVERED;
3580 code = CM_ERROR_NOSUCHPATH;
3581 smb_SendTran2Error(vcp, p, opx, code);
3582 smb_FreeTran2Packet(outp);
3585 #endif /* DFS_SUPPORT */
3587 lock_ObtainWrite(&scp->rw);
3589 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3590 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3594 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3596 lock_ConvertWToR(&scp->rw);
3601 /* now we have the status in the cache entry, and everything is locked.
3602 * Marshall the output data.
3604 /* for info level 108, figure out short name */
3605 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3606 code = cm_GetShortName(pathp, userp, &req,
3607 tidPathp, scp->fid.vnode, shortName,
3613 smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
3614 qpi.u.QPfileAltNameInfo.fileNameLength = len;
3615 responseSize = sizeof(unsigned long) + len;
3617 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3618 smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3619 qpi.u.QPfileNameInfo.fileNameLength = len;
3620 responseSize = sizeof(unsigned long) + len;
3622 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3623 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3624 qpi.u.QPstandardInfo.creationDateTime = dosTime;
3625 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3626 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3627 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3628 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3629 attributes = smb_Attributes(scp);
3630 qpi.u.QPstandardInfo.attributes = attributes;
3631 qpi.u.QPstandardInfo.eaSize = 0;
3633 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3634 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3635 qpi.u.QPfileBasicInfo.creationTime = ft;
3636 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3637 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3638 qpi.u.QPfileBasicInfo.changeTime = ft;
3639 extAttributes = smb_ExtAttributes(scp);
3640 qpi.u.QPfileBasicInfo.attributes = extAttributes;
3641 qpi.u.QPfileBasicInfo.reserved = 0;
3643 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3646 lock_ReleaseRead(&scp->rw);
3648 fidp = smb_FindFIDByScache(vcp, scp);
3650 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3651 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3652 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3653 qpi.u.QPfileStandardInfo.directory =
3654 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3655 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3656 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3657 qpi.u.QPfileStandardInfo.reserved = 0;
3660 lock_ObtainMutex(&fidp->mx);
3661 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3662 lock_ReleaseMutex(&fidp->mx);
3663 smb_ReleaseFID(fidp);
3665 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3667 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3668 qpi.u.QPfileEaInfo.eaSize = 0;
3670 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3673 lock_ReleaseRead(&scp->rw);
3675 fidp = smb_FindFIDByScache(vcp, scp);
3677 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3678 qpi.u.QPfileAllInfo.creationTime = ft;
3679 qpi.u.QPfileAllInfo.lastAccessTime = ft;
3680 qpi.u.QPfileAllInfo.lastWriteTime = ft;
3681 qpi.u.QPfileAllInfo.changeTime = ft;
3682 extAttributes = smb_ExtAttributes(scp);
3683 qpi.u.QPfileAllInfo.attributes = extAttributes;
3684 qpi.u.QPfileAllInfo.allocationSize = scp->length;
3685 qpi.u.QPfileAllInfo.endOfFile = scp->length;
3686 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3687 qpi.u.QPfileAllInfo.deletePending = 0;
3688 qpi.u.QPfileAllInfo.directory =
3689 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3690 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3691 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3692 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.vnode;
3693 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.unique;
3694 qpi.u.QPfileAllInfo.eaSize = 0;
3695 qpi.u.QPfileAllInfo.accessFlags = 0;
3697 lock_ObtainMutex(&fidp->mx);
3698 if (fidp->flags & SMB_FID_OPENDELETE)
3699 qpi.u.QPfileAllInfo.accessFlags |= DELETE;
3700 if (fidp->flags & SMB_FID_OPENREAD_LISTDIR)
3701 qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_READ|AFS_ACCESS_EXECUTE;
3702 if (fidp->flags & SMB_FID_OPENWRITE)
3703 qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_WRITE;
3704 if (fidp->flags & SMB_FID_DELONCLOSE)
3705 qpi.u.QPfileAllInfo.deletePending = 1;
3706 lock_ReleaseMutex(&fidp->mx);
3707 smb_ReleaseFID(fidp);
3709 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.cell;
3710 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.volume;
3711 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3712 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3713 qpi.u.QPfileAllInfo.mode = 0;
3714 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3716 smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3717 qpi.u.QPfileAllInfo.fileNameLength = len;
3718 responseSize -= (sizeof(qpi.u.QPfileAllInfo.fileName) - len);
3720 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO) {
3722 /* For now we have no streams */
3723 qpi.u.QPfileStreamInfo.nextEntryOffset = 0;
3724 if (scp->fileType == CM_SCACHETYPE_FILE) {
3725 qpi.u.QPfileStreamInfo.streamSize = scp->length;
3726 qpi.u.QPfileStreamInfo.streamAllocationSize = scp->length;
3727 smb_UnparseString(opx, qpi.u.QPfileStreamInfo.fileName, L"::$DATA", &len, SMB_STRF_IGNORENUL);
3728 qpi.u.QPfileStreamInfo.streamNameLength = len;
3729 responseSize -= (sizeof(qpi.u.QPfileStreamInfo.fileName) - len);
3731 qpi.u.QPfileStreamInfo.streamSize.QuadPart = 0;
3732 qpi.u.QPfileStreamInfo.streamAllocationSize.QuadPart = 0;
3733 smb_UnparseString(opx, qpi.u.QPfileStreamInfo.fileName, L"", &len, SMB_STRF_IGNORENUL);
3734 qpi.u.QPfileStreamInfo.streamNameLength = 0;
3738 outp->totalData = responseSize;
3740 /* send and free the packets */
3742 switch (scp_rw_held) {
3744 lock_ReleaseRead(&scp->rw);
3747 lock_ReleaseWrite(&scp->rw);
3751 cm_ReleaseSCache(scp);
3754 cm_ReleaseUser(userp);
3756 memcpy(outp->datap, &qpi, responseSize);
3757 smb_SendTran2Packet(vcp, outp, opx);
3759 smb_SendTran2Error(vcp, p, opx, code);
3761 smb_FreeTran2Packet(outp);
3766 /* TRANS2_SET_PATH_INFORMATION */
3767 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3770 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
3771 return CM_ERROR_BADOP;
3774 unsigned short infoLevel;
3775 clientchar_t * pathp;
3776 smb_tran2Packet_t *outp;
3777 smb_tran2QPathInfo_t *spi;
3779 cm_scache_t *scp, *dscp;
3782 clientchar_t *tidPathp;
3783 clientchar_t *lastComp;
3787 infoLevel = p->parmsp[0];
3788 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
3789 if (infoLevel != SMB_INFO_STANDARD &&
3790 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
3791 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
3792 osi_Log2(smb_logp, "Bad Tran2SetPathInfo op 0x%x infolevel 0x%x",
3793 p->opcode, infoLevel);
3794 smb_SendTran2Error(vcp, p, opx,
3795 infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3799 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3801 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
3802 osi_LogSaveClientString(smb_logp, pathp));
3804 userp = smb_GetTran2User(vcp, p);
3806 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3807 code = CM_ERROR_BADSMB;
3811 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3812 if (code == CM_ERROR_TIDIPC) {
3813 /* Attempt to use a TID allocated for IPC. The client
3814 * is probably looking for DCE RPC end points which we
3815 * don't support OR it could be looking to make a DFS
3818 osi_Log0(smb_logp, "Tran2Open received IPC TID");
3819 cm_ReleaseUser(userp);
3820 return CM_ERROR_NOSUCHPATH;
3824 * XXX Strange hack XXX
3826 * As of Patch 7 (13 January 98), we are having the following problem:
3827 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3828 * requests to look up "desktop.ini" in all the subdirectories.
3829 * This can cause zillions of timeouts looking up non-existent cells
3830 * and volumes, especially in the top-level directory.
3832 * We have not found any way to avoid this or work around it except
3833 * to explicitly ignore the requests for mount points that haven't
3834 * yet been evaluated and for directories that haven't yet been
3837 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3838 spacep = cm_GetSpace();
3839 /* smb_StripLastComponent will strip "::$DATA" if present */
3840 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3841 #ifndef SPECIAL_FOLDERS
3842 /* Make sure that lastComp is not NULL */
3844 if (cm_ClientStrCmpI(lastComp, _C("\\desktop.ini")) == 0) {
3845 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
3849 userp, tidPathp, &req, &dscp);
3852 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3853 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3855 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3856 code = CM_ERROR_PATH_NOT_COVERED;
3858 code = CM_ERROR_NOSUCHPATH;
3860 #endif /* DFS_SUPPORT */
3861 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3862 code = CM_ERROR_NOSUCHFILE;
3863 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3864 cm_buf_t *bp = buf_Find(&dscp->fid, &hzero);
3870 code = CM_ERROR_NOSUCHFILE;
3872 cm_ReleaseSCache(dscp);
3874 cm_FreeSpace(spacep);
3875 cm_ReleaseUser(userp);
3876 smb_SendTran2Error(vcp, p, opx, code);
3882 #endif /* SPECIAL_FOLDERS */
3884 cm_FreeSpace(spacep);
3888 code == CM_ERROR_NOSUCHFILE ||
3889 code == CM_ERROR_NOSUCHPATH ||
3890 code == CM_ERROR_BPLUS_NOMATCH) {
3891 /* now do namei and stat, and copy out the info */
3892 code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
3893 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3897 cm_ReleaseUser(userp);
3898 smb_SendTran2Error(vcp, p, opx, code);
3902 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3904 outp->totalParms = 2;
3905 outp->totalData = 0;
3907 spi = (smb_tran2QPathInfo_t *)p->datap;
3908 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3911 /* lock the vnode with a callback; we need the current status
3912 * to determine what the new status is, in some cases.
3914 lock_ObtainWrite(&scp->rw);
3915 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3916 CM_SCACHESYNC_GETSTATUS
3917 | CM_SCACHESYNC_NEEDCALLBACK);
3919 lock_ReleaseWrite(&scp->rw);
3922 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3924 /* prepare for setattr call */
3925 attr.mask = CM_ATTRMASK_LENGTH;
3926 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3927 attr.length.HighPart = 0;
3929 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3930 cm_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3931 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3934 if (spi->u.QPstandardInfo.attributes != 0) {
3935 if ((scp->unixModeBits & 0200)
3936 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3937 /* make a writable file read-only */
3938 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3939 attr.unixModeBits = scp->unixModeBits & ~0222;
3941 else if ((scp->unixModeBits & 0200) == 0
3942 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3943 /* make a read-only file writable */
3944 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3945 attr.unixModeBits = scp->unixModeBits | 0222;
3948 lock_ReleaseRead(&scp->rw);
3952 code = cm_SetAttr(scp, &attr, userp, &req);
3956 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3957 /* we don't support EAs */
3958 code = CM_ERROR_EAS_NOT_SUPPORTED;
3962 cm_ReleaseSCache(scp);
3963 cm_ReleaseUser(userp);
3965 smb_SendTran2Packet(vcp, outp, opx);
3967 smb_SendTran2Error(vcp, p, opx, code);
3968 smb_FreeTran2Packet(outp);
3974 /* TRANS2_QUERY_FILE_INFORMATION */
3975 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3977 smb_tran2Packet_t *outp;
3979 unsigned long attributes;
3980 unsigned short infoLevel;
3987 smb_tran2QFileInfo_t qfi;
3995 fidp = smb_FindFID(vcp, fid, 0);
3998 osi_Log2(smb_logp, "Tran2QFileInfo Unknown SMB Fid vcp 0x%p fid %d",
4000 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
4004 lock_ObtainMutex(&fidp->mx);
4005 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
4006 lock_ReleaseMutex(&fidp->mx);
4007 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
4008 smb_CloseFID(vcp, fidp, NULL, 0);
4009 smb_ReleaseFID(fidp);
4012 lock_ReleaseMutex(&fidp->mx);
4014 infoLevel = p->parmsp[1];
4015 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
4016 responseSize = sizeof(qfi.u.QFbasicInfo);
4017 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
4018 responseSize = sizeof(qfi.u.QFstandardInfo);
4019 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
4020 responseSize = sizeof(qfi.u.QFeaInfo);
4021 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
4022 responseSize = sizeof(qfi.u.QFfileNameInfo);
4023 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO)
4024 responseSize = sizeof(qfi.u.QFfileStreamInfo);
4026 osi_Log2(smb_logp, "Bad Tran2QFileInfo op 0x%x infolevel 0x%x",
4027 p->opcode, infoLevel);
4028 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
4029 smb_ReleaseFID(fidp);
4032 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
4033 memset(&qfi, 0, sizeof(qfi));
4035 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
4037 if (infoLevel > 0x100)
4038 outp->totalParms = 2;
4040 outp->totalParms = 0;
4042 userp = smb_GetTran2User(vcp, p);
4044 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
4045 code = CM_ERROR_BADSMB;
4049 lock_ObtainMutex(&fidp->mx);
4050 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
4052 osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
4054 lock_ReleaseMutex(&fidp->mx);
4055 lock_ObtainWrite(&scp->rw);
4056 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4057 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4061 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4063 lock_ConvertWToR(&scp->rw);
4066 /* now we have the status in the cache entry, and everything is locked.
4067 * Marshall the output data.
4069 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
4070 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4071 qfi.u.QFbasicInfo.creationTime = ft;
4072 qfi.u.QFbasicInfo.lastAccessTime = ft;
4073 qfi.u.QFbasicInfo.lastWriteTime = ft;
4074 qfi.u.QFbasicInfo.lastChangeTime = ft;
4075 attributes = smb_ExtAttributes(scp);
4076 qfi.u.QFbasicInfo.attributes = attributes;
4078 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
4079 qfi.u.QFstandardInfo.allocationSize = scp->length;
4080 qfi.u.QFstandardInfo.endOfFile = scp->length;
4081 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
4082 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
4083 qfi.u.QFstandardInfo.directory =
4084 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
4085 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4086 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
4088 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
4089 qfi.u.QFeaInfo.eaSize = 0;
4091 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
4095 lock_ReleaseRead(&scp->rw);
4096 lock_ObtainMutex(&fidp->mx);
4097 lock_ObtainRead(&scp->rw);
4098 if (fidp->NTopen_wholepathp)
4099 name = fidp->NTopen_wholepathp;
4101 name = _C("\\"); /* probably can't happen */
4102 lock_ReleaseMutex(&fidp->mx);
4104 smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, SMB_STRF_IGNORENUL);
4105 responseSize = len + 4; /* this is actually what we want to return */
4106 qfi.u.QFfileNameInfo.fileNameLength = len;
4108 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO) {
4111 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
4112 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4113 scp->fileType == CM_SCACHETYPE_INVALID) {
4114 /* Do not return the alternate streams for directories */
4117 /* For now we have no alternate streams */
4118 qfi.u.QFfileStreamInfo.nextEntryOffset = 0;
4119 qfi.u.QFfileStreamInfo.streamSize = scp->length;
4120 qfi.u.QFfileStreamInfo.streamAllocationSize = scp->length;
4121 smb_UnparseString(opx, qfi.u.QFfileStreamInfo.fileName, L"::$DATA", &len, SMB_STRF_IGNORENUL);
4122 qfi.u.QFfileStreamInfo.streamNameLength = len;
4123 responseSize -= (sizeof(qfi.u.QFfileStreamInfo.fileName) - len);
4126 outp->totalData = responseSize;
4128 /* send and free the packets */
4131 lock_ReleaseRead(&scp->rw);
4133 lock_ReleaseWrite(&scp->rw);
4134 cm_ReleaseSCache(scp);
4135 cm_ReleaseUser(userp);
4136 smb_ReleaseFID(fidp);
4138 memcpy(outp->datap, &qfi, responseSize);
4139 smb_SendTran2Packet(vcp, outp, opx);
4141 smb_SendTran2Error(vcp, p, opx, code);
4143 smb_FreeTran2Packet(outp);
4149 /* TRANS2_SET_FILE_INFORMATION */
4150 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4155 unsigned short infoLevel;
4156 smb_tran2Packet_t *outp;
4157 cm_user_t *userp = NULL;
4158 cm_scache_t *scp = NULL;
4164 fidp = smb_FindFID(vcp, fid, 0);
4167 osi_Log2(smb_logp, "Tran2SetFileInfo Unknown SMB Fid vcp 0x%p fid %d",
4169 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
4173 infoLevel = p->parmsp[1];
4174 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
4175 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
4176 osi_Log2(smb_logp, "Bad Tran2SetFileInfo op 0x%x infolevel 0x%x",
4177 p->opcode, infoLevel);
4178 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
4179 smb_ReleaseFID(fidp);
4183 lock_ObtainMutex(&fidp->mx);
4184 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
4185 lock_ReleaseMutex(&fidp->mx);
4186 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
4187 smb_CloseFID(vcp, fidp, NULL, 0);
4188 smb_ReleaseFID(fidp);
4192 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
4193 !(fidp->flags & SMB_FID_OPENDELETE)) {
4194 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
4195 fidp, fidp->scp, fidp->flags);
4196 lock_ReleaseMutex(&fidp->mx);
4197 smb_ReleaseFID(fidp);
4198 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
4201 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
4202 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
4203 && !(fidp->flags & SMB_FID_OPENWRITE)) {
4204 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
4205 fidp, fidp->scp, fidp->flags);
4206 lock_ReleaseMutex(&fidp->mx);
4207 smb_ReleaseFID(fidp);
4208 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
4213 osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
4215 lock_ReleaseMutex(&fidp->mx);
4217 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
4219 outp->totalParms = 2;
4220 outp->totalData = 0;
4222 userp = smb_GetTran2User(vcp, p);
4224 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
4225 code = CM_ERROR_BADSMB;
4229 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
4231 unsigned int attribute;
4233 smb_tran2QFileInfo_t *sfi;
4235 sfi = (smb_tran2QFileInfo_t *)p->datap;
4237 /* lock the vnode with a callback; we need the current status
4238 * to determine what the new status is, in some cases.
4240 lock_ObtainWrite(&scp->rw);
4241 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4242 CM_SCACHESYNC_GETSTATUS
4243 | CM_SCACHESYNC_NEEDCALLBACK);
4245 lock_ReleaseWrite(&scp->rw);
4249 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4251 lock_ReleaseWrite(&scp->rw);
4252 lock_ObtainMutex(&fidp->mx);
4253 lock_ObtainRead(&scp->rw);
4255 /* prepare for setattr call */
4258 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
4259 /* when called as result of move a b, lastMod is (-1, -1).
4260 * If the check for -1 is not present, timestamp
4261 * of the resulting file will be 1969 (-1)
4263 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
4264 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
4265 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4266 cm_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
4267 fidp->flags |= SMB_FID_MTIMESETDONE;
4270 attribute = sfi->u.QFbasicInfo.attributes;
4271 if (attribute != 0) {
4272 if ((scp->unixModeBits & 0200)
4273 && (attribute & SMB_ATTR_READONLY) != 0) {
4274 /* make a writable file read-only */
4275 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4276 attr.unixModeBits = scp->unixModeBits & ~0222;
4278 else if ((scp->unixModeBits & 0200) == 0
4279 && (attribute & SMB_ATTR_READONLY) == 0) {
4280 /* make a read-only file writable */
4281 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4282 attr.unixModeBits = scp->unixModeBits | 0222;
4285 lock_ReleaseRead(&scp->rw);
4286 lock_ReleaseMutex(&fidp->mx);
4290 code = cm_SetAttr(scp, &attr, userp, &req);
4294 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
4295 int delflag = *((char *)(p->datap));
4296 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
4297 delflag, fidp, scp);
4298 if (*((char *)(p->datap))) { /* File is Deleted */
4299 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
4302 lock_ObtainMutex(&fidp->mx);
4303 fidp->flags |= SMB_FID_DELONCLOSE;
4304 lock_ReleaseMutex(&fidp->mx);
4306 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
4312 lock_ObtainMutex(&fidp->mx);
4313 fidp->flags &= ~SMB_FID_DELONCLOSE;
4314 lock_ReleaseMutex(&fidp->mx);
4317 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
4318 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
4319 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
4322 attr.mask = CM_ATTRMASK_LENGTH;
4323 attr.length.LowPart = size.LowPart;
4324 attr.length.HighPart = size.HighPart;
4325 code = cm_SetAttr(scp, &attr, userp, &req);
4329 cm_ReleaseSCache(scp);
4330 cm_ReleaseUser(userp);
4331 smb_ReleaseFID(fidp);
4333 smb_SendTran2Packet(vcp, outp, opx);
4335 smb_SendTran2Error(vcp, p, opx, code);
4336 smb_FreeTran2Packet(outp);
4343 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4345 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
4346 return CM_ERROR_BADOP;
4351 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4353 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
4354 return CM_ERROR_BADOP;
4357 /* TRANS2_FIND_NOTIFY_FIRST */
4359 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4361 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
4362 return CM_ERROR_BADOP;
4365 /* TRANS2_FIND_NOTIFY_NEXT */
4367 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4369 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
4370 return CM_ERROR_BADOP;
4373 /* TRANS2_CREATE_DIRECTORY */
4375 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4377 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
4378 return CM_ERROR_BADOP;
4381 /* TRANS2_SESSION_SETUP */
4383 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4385 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
4386 return CM_ERROR_BADOP;
4389 struct smb_v2_referral {
4391 USHORT ReferralFlags;
4394 USHORT DfsPathOffset;
4395 USHORT DfsAlternativePathOffset;
4396 USHORT NetworkAddressOffset;
4399 /* TRANS2_GET_DFS_REFERRAL */
4401 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
4403 /* This is a UNICODE only request (bit15 of Flags2) */
4404 /* The TID must be IPC$ */
4406 /* The documentation for the Flags response field is contradictory */
4408 /* Use Version 1 Referral Element Format */
4409 /* ServerType = 0; indicates the next server should be queried for the file */
4410 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
4411 /* Node = UnicodeString of UNC path of the next share name */
4414 int maxReferralLevel = 0;
4415 clientchar_t requestFileName[1024] = _C("");
4416 clientchar_t referralPath[1024] = _C("");
4417 smb_tran2Packet_t *outp = 0;
4418 cm_user_t *userp = 0;
4419 cm_scache_t *scp = 0;
4420 cm_scache_t *dscp = 0;
4422 CPINFO CodePageInfo;
4423 int i, nbnLen, reqLen, refLen;
4428 maxReferralLevel = p->parmsp[0];
4430 GetCPInfo(CP_ACP, &CodePageInfo);
4431 cm_Utf16ToClientString(&p->parmsp[1], -1, requestFileName, lengthof(requestFileName));
4433 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%S]",
4434 maxReferralLevel, osi_LogSaveClientString(smb_logp, requestFileName));
4436 nbnLen = (int)cm_ClientStrLen(cm_NetbiosNameC);
4437 reqLen = (int)cm_ClientStrLen(requestFileName);
4439 if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
4440 !cm_ClientStrCmpNI(cm_NetbiosNameC, &requestFileName[1], nbnLen) &&
4441 requestFileName[nbnLen+1] == '\\')
4445 if (!cm_ClientStrCmpNI(_C("all"), &requestFileName[nbnLen+2], 3) ||
4446 !cm_ClientStrCmpNI(_C("*."), &requestFileName[nbnLen+2], 2)) {
4448 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4451 userp = smb_GetTran2User(vcp, p);
4453 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
4454 code = CM_ERROR_BADSMB;
4459 * We have a requested path. Check to see if it is something
4462 * But be careful because the name that we might be searching
4463 * for might be a known name with the final character stripped
4466 code = cm_NameI(cm_RootSCachep(userp, &req), &requestFileName[nbnLen+2],
4467 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
4468 userp, NULL, &req, &scp);
4470 code == CM_ERROR_ALLDOWN ||
4471 code == CM_ERROR_ALLBUSY ||
4472 code == CM_ERROR_ALLOFFLINE ||
4473 code == CM_ERROR_NOSUCHCELL ||
4474 code == CM_ERROR_NOSUCHVOLUME ||
4475 code == CM_ERROR_NOACCESS) {
4478 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4480 } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
4481 clientchar_t temp[1024];
4482 clientchar_t pathName[1024];
4483 clientchar_t *lastComponent;
4485 * we have a msdfs link somewhere in the path
4486 * we should figure out where in the path the link is.
4489 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%S]", requestFileName);
4491 cm_ClientStrCpy(temp, lengthof(temp), &requestFileName[nbnLen+2]);
4495 cm_ReleaseSCache(dscp);
4499 cm_ReleaseSCache(scp);
4502 /* smb_StripLastComponent will strip "::$DATA" if present */
4503 smb_StripLastComponent(pathName, &lastComponent, temp);
4505 code = cm_NameI(cm_RootSCachep(userp, &req), pathName,
4506 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4507 userp, NULL, &req, &dscp);
4509 code = cm_NameI(dscp, ++lastComponent,
4511 userp, NULL, &req, &scp);
4512 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK)
4515 } while (code == CM_ERROR_PATH_NOT_COVERED);
4517 /* scp should now be the DfsLink we are looking for */
4519 /* figure out how much of the input path was used */
4520 reqLen = (int)(nbnLen+2 + cm_ClientStrLen(pathName) + 1 + cm_ClientStrLen(lastComponent));
4522 cm_FsStringToClientString(&scp->mountPointStringp[strlen("msdfs:")], -1,
4523 referralPath, lengthof(referralPath));
4524 refLen = (int)cm_ClientStrLen(referralPath);
4528 clientchar_t shareName[MAX_PATH + 1];
4529 clientchar_t *p, *q;
4530 /* we may have a sharename that is a volume reference */
4532 for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
4538 if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
4539 code = cm_NameI(cm_RootSCachep(userp, &req), _C(""),
4540 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
4541 userp, p, &req, &scp);
4546 cm_ClientStrCpy(referralPath, lengthof(referralPath),
4557 struct smb_v2_referral * v2ref;
4558 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (refLen + 8));
4560 sp = (USHORT *)outp->datap;
4562 sp[idx++] = reqLen; /* path consumed */
4563 sp[idx++] = 1; /* number of referrals */
4564 sp[idx++] = 0x03; /* flags */
4565 #ifdef DFS_VERSION_1
4566 sp[idx++] = 1; /* Version Number */
4567 sp[idx++] = refLen + 4; /* Referral Size */
4568 sp[idx++] = 1; /* Type = SMB Server */
4569 sp[idx++] = 0; /* Do not strip path consumed */
4570 for ( i=0;i<=refLen; i++ )
4571 sp[i+idx] = referralPath[i];
4572 #else /* DFS_VERSION_2 */
4573 sp[idx++] = 2; /* Version Number */
4574 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
4575 idx += (sizeof(struct smb_v2_referral) / 2);
4576 v2ref = (struct smb_v2_referral *) &sp[5];
4577 v2ref->ServerType = 1; /* SMB Server */
4578 v2ref->ReferralFlags = 0x03;
4579 v2ref->Proximity = 0; /* closest */
4580 v2ref->TimeToLive = 3600; /* seconds */
4581 v2ref->DfsPathOffset = idx * 2;
4582 v2ref->DfsAlternativePathOffset = idx * 2;
4583 v2ref->NetworkAddressOffset = 0;
4584 for ( i=0;i<=refLen; i++ )
4585 sp[i+idx] = referralPath[i];
4588 code = CM_ERROR_NOSUCHPATH;
4591 code = CM_ERROR_NOSUCHPATH;
4596 cm_ReleaseSCache(dscp);
4598 cm_ReleaseSCache(scp);
4600 cm_ReleaseUser(userp);
4602 smb_SendTran2Packet(vcp, outp, op);
4604 smb_SendTran2Error(vcp, p, op, code);
4606 smb_FreeTran2Packet(outp);
4609 #else /* DFS_SUPPORT */
4610 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
4611 return CM_ERROR_NOSUCHDEVICE;
4612 #endif /* DFS_SUPPORT */
4615 /* TRANS2_REPORT_DFS_INCONSISTENCY */
4617 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4619 /* This is a UNICODE only request (bit15 of Flags2) */
4621 /* There is nothing we can do about this operation. The client is going to
4622 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
4623 * Unfortunately, there is really nothing we can do about it other then log it
4624 * somewhere. Even then I don't think there is anything for us to do.
4625 * So let's return an error value.
4628 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
4629 return CM_ERROR_BADOP;
4633 smb_ApplyV3DirListPatches(cm_scache_t *dscp, smb_dirListPatch_t **dirPatchespp,
4634 clientchar_t * tidPathp, clientchar_t * relPathp,
4635 int infoLevel, cm_user_t *userp, cm_req_t *reqp)
4639 cm_scache_t *targetScp; /* target if scp is a symlink */
4642 unsigned short attr;
4643 unsigned long lattr;
4644 smb_dirListPatch_t *patchp;
4645 smb_dirListPatch_t *npatchp;
4647 afs_int32 mustFake = 0;
4648 clientchar_t path[AFSPATHMAX];
4650 lock_ObtainWrite(&dscp->rw);
4651 code = cm_FindACLCache(dscp, userp, &rights);
4653 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4654 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4656 cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4657 if (code == CM_ERROR_NOACCESS) {
4662 lock_ReleaseWrite(&dscp->rw);
4666 if (!mustFake) { /* Bulk Stat */
4668 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4670 memset(bsp, 0, sizeof(cm_bulkStat_t));
4673 for (patchp = *dirPatchespp, count=0;
4675 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4676 cm_scache_t *tscp = NULL;
4679 /* Do not look for a cm_scache_t or bulkstat an ioctl entry */
4680 if (patchp->flags & SMB_DIRLISTPATCH_IOCTL)
4683 code = cm_GetSCache(&patchp->fid, &dscp->fid, &tscp, userp, reqp);
4685 if (lock_TryWrite(&tscp->rw)) {
4686 /* we have an entry that we can look at */
4687 #ifdef AFS_FREELANCE_CLIENT
4688 if (dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID && dscp->fid.volume == AFS_FAKE_ROOT_VOL_ID) {
4689 code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
4690 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4692 cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4694 lock_ReleaseWrite(&tscp->rw);
4695 cm_ReleaseSCache(tscp);
4698 #endif /* AFS_FREELANCE_CLIENT */
4699 if (!cm_EAccesFindEntry(userp, &tscp->fid) && cm_HaveCallback(tscp)) {
4700 /* we have a callback on it. Don't bother
4701 * fetching this stat entry, since we're happy
4702 * with the info we have.
4704 lock_ReleaseWrite(&tscp->rw);
4705 cm_ReleaseSCache(tscp);
4708 lock_ReleaseWrite(&tscp->rw);
4710 cm_ReleaseSCache(tscp);
4714 bsp->fids[i].Volume = patchp->fid.volume;
4715 bsp->fids[i].Vnode = patchp->fid.vnode;
4716 bsp->fids[i].Unique = patchp->fid.unique;
4718 if (bsp->counter == AFSCBMAX) {
4719 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4720 memset(bsp, 0, sizeof(cm_bulkStat_t));
4725 if (bsp->counter > 0)
4726 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4731 for( patchp = *dirPatchespp;
4733 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4734 cm_ClientStrPrintfN(path, lengthof(path),_C("%s\\%S"),
4735 relPathp ? relPathp : _C(""), patchp->dep->name);
4736 reqp->relPathp = path;
4737 reqp->tidPathp = tidPathp;
4739 if (patchp->flags & SMB_DIRLISTPATCH_IOCTL) {
4740 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4741 errors in the client. */
4742 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4743 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4745 /* 1969-12-31 23:59:59 +00 */
4746 ft.dwHighDateTime = 0x19DB200;
4747 ft.dwLowDateTime = 0x5BB78980;
4749 /* copy to Creation Time */
4750 fa->creationTime = ft;
4751 fa->lastAccessTime = ft;
4752 fa->lastWriteTime = ft;
4753 fa->lastChangeTime = ft;
4754 fa->extFileAttributes = SMB_ATTR_SYSTEM | SMB_ATTR_HIDDEN;
4756 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4758 /* 1969-12-31 23:59:58 +00*/
4759 dosTime = 0xEBBFBF7D;
4761 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4762 fa->lastAccessDateTime = fa->creationDateTime;
4763 fa->lastWriteDateTime = fa->creationDateTime;
4764 fa->attributes = SMB_ATTR_SYSTEM|SMB_ATTR_HIDDEN;
4769 code = cm_GetSCache(&patchp->fid, &dscp->fid, &scp, userp, reqp);
4770 reqp->relPathp = reqp->tidPathp = NULL;
4774 lock_ObtainWrite(&scp->rw);
4775 if (mustFake || cm_EAccesFindEntry(userp, &scp->fid) || !cm_HaveCallback(scp)) {
4776 lock_ReleaseWrite(&scp->rw);
4778 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4779 errors in the client. */
4780 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4781 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4783 /* 1969-12-31 23:59:59 +00 */
4784 ft.dwHighDateTime = 0x19DB200;
4785 ft.dwLowDateTime = 0x5BB78980;
4787 /* copy to Creation Time */
4788 fa->creationTime = ft;
4789 fa->lastAccessTime = ft;
4790 fa->lastWriteTime = ft;
4791 fa->lastChangeTime = ft;
4793 switch (scp->fileType) {
4794 case CM_SCACHETYPE_DIRECTORY:
4795 case CM_SCACHETYPE_MOUNTPOINT:
4796 case CM_SCACHETYPE_INVALID:
4797 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4799 case CM_SCACHETYPE_SYMLINK:
4800 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4801 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4803 fa->extFileAttributes = SMB_ATTR_NORMAL;
4806 /* if we get here we either have a normal file
4807 * or we have a file for which we have never
4808 * received status info. In this case, we can
4809 * check the even/odd value of the entry's vnode.
4810 * odd means it is to be treated as a directory
4811 * and even means it is to be treated as a file.
4813 if (mustFake && (scp->fid.vnode & 0x1))
4814 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4816 fa->extFileAttributes = SMB_ATTR_NORMAL;
4818 /* merge in hidden attribute */
4819 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4820 fa->extFileAttributes |= SMB_ATTR_HIDDEN;
4823 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4825 /* 1969-12-31 23:59:58 +00*/
4826 dosTime = 0xEBBFBF7D;
4828 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4829 fa->lastAccessDateTime = fa->creationDateTime;
4830 fa->lastWriteDateTime = fa->creationDateTime;
4832 /* set the attribute */
4833 switch (scp->fileType) {
4834 case CM_SCACHETYPE_DIRECTORY:
4835 case CM_SCACHETYPE_MOUNTPOINT:
4836 case CM_SCACHETYPE_INVALID:
4837 fa->attributes = SMB_ATTR_DIRECTORY;
4839 case CM_SCACHETYPE_SYMLINK:
4840 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4841 fa->attributes = SMB_ATTR_DIRECTORY;
4843 fa->attributes = SMB_ATTR_NORMAL;
4846 /* if we get here we either have a normal file
4847 * or we have a file for which we have never
4848 * received status info. In this case, we can
4849 * check the even/odd value of the entry's vnode.
4850 * even means it is to be treated as a directory
4851 * and odd means it is to be treated as a file.
4853 if (mustFake && (scp->fid.vnode & 0x1))
4854 fa->attributes = SMB_ATTR_DIRECTORY;
4856 fa->attributes = SMB_ATTR_NORMAL;
4859 /* merge in hidden (dot file) attribute */
4860 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4861 fa->attributes |= SMB_ATTR_HIDDEN;
4865 cm_ReleaseSCache(scp);
4869 /* now watch for a symlink */
4871 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
4872 lock_ReleaseWrite(&scp->rw);
4873 cm_ClientStrPrintfN(path, lengthof(path), _C("%s\\%S"),
4874 relPathp ? relPathp : _C(""), patchp->dep->name);
4875 reqp->relPathp = path;
4876 reqp->tidPathp = tidPathp;
4877 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
4878 reqp->relPathp = reqp->tidPathp = NULL;
4880 /* we have a more accurate file to use (the
4881 * target of the symbolic link). Otherwise,
4882 * we'll just use the symlink anyway.
4884 osi_Log2(smb_logp, "symlink vp %x to vp %x",
4886 cm_ReleaseSCache(scp);
4889 lock_ObtainWrite(&scp->rw);
4892 lock_ConvertWToR(&scp->rw);
4894 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4895 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4898 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4900 fa->creationTime = ft;
4901 fa->lastAccessTime = ft;
4902 fa->lastWriteTime = ft;
4903 fa->lastChangeTime = ft;
4905 /* Use length for both file length and alloc length */
4906 fa->endOfFile = scp->length;
4907 fa->allocationSize = scp->length;
4909 /* Copy attributes */
4910 lattr = smb_ExtAttributes(scp);
4911 if ((code == CM_ERROR_NOSUCHPATH &&
4912 (scp->fileType == CM_SCACHETYPE_SYMLINK &&
4913 cm_TargetPerceivedAsDirectory(scp->mountPointStringp))) ||
4914 code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4915 if (lattr == SMB_ATTR_NORMAL)
4916 lattr = SMB_ATTR_DIRECTORY;
4918 lattr |= SMB_ATTR_DIRECTORY;
4920 /* merge in hidden (dot file) attribute */
4921 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4922 if (lattr == SMB_ATTR_NORMAL)
4923 lattr = SMB_ATTR_HIDDEN;
4925 lattr |= SMB_ATTR_HIDDEN;
4928 fa->extFileAttributes = lattr;
4930 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4933 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4935 fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
4936 fa->lastAccessDateTime = fa->creationDateTime;
4937 fa->lastWriteDateTime = fa->creationDateTime;
4939 /* copy out file length and alloc length,
4940 * using the same for both
4942 fa->dataSize = scp->length.LowPart;
4943 fa->allocationSize = scp->length.LowPart;
4945 /* finally copy out attributes as short */
4946 attr = smb_Attributes(scp);
4947 /* merge in hidden (dot file) attribute */
4948 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4949 if (lattr == SMB_ATTR_NORMAL)
4950 lattr = SMB_ATTR_HIDDEN;
4952 lattr |= SMB_ATTR_HIDDEN;
4954 fa->attributes = attr;
4957 lock_ReleaseRead(&scp->rw);
4958 cm_ReleaseSCache(scp);
4961 /* now free the patches */
4962 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4963 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4967 /* and mark the list as empty */
4968 *dirPatchespp = NULL;
4974 /* smb_ReceiveTran2SearchDir implements both
4975 * Tran2_Find_First and Tran2_Find_Next
4977 #define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
4978 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
4979 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
4980 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
4981 #define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
4983 /* this is an optimized handler for T2SearchDir that handles the case
4984 where there are no wildcards in the search path. I.e. an
4985 application is using FindFirst(Ex) to get information about a
4986 single file or directory. It will attempt to do a single lookup.
4987 If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4988 the usual mechanism.
4990 This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4992 TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
4994 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4998 long code = 0, code2 = 0;
4999 clientchar_t *pathp = 0;
5001 smb_dirListPatch_t *dirListPatchesp;
5002 smb_dirListPatch_t *curPatchp;
5003 size_t orbytes; /* # of bytes in this output record */
5004 size_t ohbytes; /* # of bytes, except file name */
5005 size_t onbytes; /* # of bytes in name, incl. term. null */
5006 cm_scache_t *scp = NULL;
5007 cm_scache_t *targetScp = NULL;
5008 cm_user_t *userp = NULL;
5009 char *op; /* output data ptr */
5010 char *origOp; /* original value of op */
5011 cm_space_t *spacep; /* for pathname buffer */
5012 unsigned long maxReturnData; /* max # of return data */
5013 long maxReturnParms; /* max # of return parms */
5014 long bytesInBuffer; /* # data bytes in the output buffer */
5015 clientchar_t *maskp; /* mask part of path */
5019 smb_tran2Packet_t *outp; /* response packet */
5020 clientchar_t *tidPathp = 0;
5022 clientchar_t shortName[13]; /* 8.3 name if needed */
5024 clientchar_t *shortNameEnd;
5025 cm_dirEntry_t * dep = NULL;
5028 void * attrp = NULL;
5029 smb_tran2Find_t * fp;
5030 int afs_ioctl = 0; /* is this query for _._AFS_IOCTL_._? */
5036 osi_assertx(p->opcode == 1, "invalid opcode");
5038 /* find first; obtain basic parameters from request */
5040 /* note that since we are going to failover to regular
5041 * processing at smb_ReceiveTran2SearchDir(), we shouldn't
5042 * modify any of the input parameters here. */
5043 attribute = p->parmsp[0];
5044 maxCount = p->parmsp[1];
5045 infoLevel = p->parmsp[3];
5046 searchFlags = p->parmsp[2];
5047 pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
5049 maskp = cm_ClientStrRChr(pathp, '\\');
5053 maskp++; /* skip over backslash */
5054 /* track if this is likely to match a lot of entries */
5056 osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%S], mask[%S]",
5057 osi_LogSaveClientString(smb_logp, pathp),
5058 osi_LogSaveClientString(smb_logp, maskp));
5060 switch ( infoLevel ) {
5061 case SMB_INFO_STANDARD:
5063 ohbytes = sizeof(fp->u.FstandardInfo);
5066 case SMB_INFO_QUERY_EA_SIZE:
5067 ohbytes = sizeof(fp->u.FeaSizeInfo);
5068 s = "InfoQueryEaSize";
5071 case SMB_INFO_QUERY_EAS_FROM_LIST:
5072 ohbytes = sizeof(fp->u.FeasFromListInfo);
5073 s = "InfoQueryEasFromList";
5076 case SMB_FIND_FILE_DIRECTORY_INFO:
5077 s = "FindFileDirectoryInfo";
5078 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
5081 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5082 s = "FindFileFullDirectoryInfo";
5083 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
5086 case SMB_FIND_FILE_NAMES_INFO:
5087 s = "FindFileNamesInfo";
5088 ohbytes = sizeof(fp->u.FfileNamesInfo);
5091 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5092 s = "FindFileBothDirectoryInfo";
5093 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
5097 s = "unknownInfoLevel";
5101 osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
5104 "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
5105 attribute, infoLevel, maxCount, searchFlags);
5108 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
5109 return CM_ERROR_INVAL;
5112 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5113 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
5115 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5118 dirListPatchesp = NULL;
5120 maxReturnData = p->maxReturnData;
5121 maxReturnParms = 10; /* return params for findfirst, which
5122 is the only one we handle.*/
5124 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
5127 osi_Log2(smb_logp, "T2SDSingle search dir count %d [%S]",
5128 maxCount, osi_LogSaveClientString(smb_logp, pathp));
5130 /* bail out if request looks bad */
5132 smb_FreeTran2Packet(outp);
5133 return CM_ERROR_BADSMB;
5136 userp = smb_GetTran2User(vcp, p);
5138 osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
5139 smb_FreeTran2Packet(outp);
5140 return CM_ERROR_BADSMB;
5143 /* try to get the vnode for the path name next */
5144 spacep = cm_GetSpace();
5145 /* smb_StripLastComponent will strip "::$DATA" if present */
5146 smb_StripLastComponent(spacep->wdata, NULL, pathp);
5147 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
5149 cm_ReleaseUser(userp);
5150 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
5151 smb_FreeTran2Packet(outp);
5155 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
5156 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5157 userp, tidPathp, &req, &scp);
5158 cm_FreeSpace(spacep);
5161 cm_ReleaseUser(userp);
5162 smb_SendTran2Error(vcp, p, opx, code);
5163 smb_FreeTran2Packet(outp);
5167 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
5168 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5169 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
5170 cm_ReleaseSCache(scp);
5171 cm_ReleaseUser(userp);
5172 if ( WANTS_DFS_PATHNAMES(p) || pnc )
5173 code = CM_ERROR_PATH_NOT_COVERED;
5175 code = CM_ERROR_NOSUCHPATH;
5176 smb_SendTran2Error(vcp, p, opx, code);
5177 smb_FreeTran2Packet(outp);
5180 #endif /* DFS_SUPPORT */
5181 osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
5183 afs_ioctl = (cm_ClientStrCmpI(maskp, CM_IOCTL_FILENAME_NOSLASH_W) == 0);
5186 * If we are not searching for _._AFS_IOCTL_._, then we need to obtain
5190 /* now do a single case sensitive lookup for the file in question */
5191 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetScp);
5194 * if a case sensitive match failed, we try a case insensitive
5197 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH)
5198 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetScp);
5200 if (code == 0 && targetScp->fid.vnode == 0) {
5201 cm_ReleaseSCache(targetScp);
5202 code = CM_ERROR_NOSUCHFILE;
5207 * if we can't find the directory entry, this block will
5208 * return CM_ERROR_NOSUCHFILE, which we will pass on to
5209 * smb_ReceiveTran2SearchDir().
5211 cm_ReleaseSCache(scp);
5212 cm_ReleaseUser(userp);
5213 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5214 smb_SendTran2Error(vcp, p, opx, code);
5217 smb_FreeTran2Packet(outp);
5222 /* now that we have the target in sight, we proceed with filling
5223 up the return data. */
5225 op = origOp = outp->datap;
5228 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
5229 /* skip over resume key */
5233 fp = (smb_tran2Find_t *) op;
5235 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
5236 cm_shortNames && !cm_Is8Dot3(maskp)) {
5239 * Since the _._AFS_IOCTL_._ file does not actually exist
5240 * we will make up a per directory FID equivalent to the
5241 * directory vnode and the uniqifier 0.
5244 dfid.vnode = htonl(scp->fid.vnode);
5245 dfid.unique = htonl(0);
5247 dfid.vnode = htonl(targetScp->fid.vnode);
5248 dfid.unique = htonl(targetScp->fid.unique);
5251 cm_Gen8Dot3NameIntW(maskp, &dfid, shortName, &shortNameEnd);
5257 osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %S (%S)",
5260 osi_LogSaveClientString(smb_logp, pathp),
5261 (NeedShortName)? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
5263 /* Eliminate entries that don't match requested attributes */
5264 if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
5265 smb_IsDotFile(maskp)) {
5267 code = CM_ERROR_NOSUCHFILE;
5268 osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
5273 if (!(attribute & SMB_ATTR_DIRECTORY) &&
5275 (targetScp->fileType == CM_SCACHETYPE_DIRECTORY ||
5276 targetScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
5277 targetScp->fileType == CM_SCACHETYPE_DFSLINK ||
5278 targetScp->fileType == CM_SCACHETYPE_INVALID)) {
5280 code = CM_ERROR_NOSUCHFILE;
5281 osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
5286 /* add header to name & term. null */
5288 smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5289 orbytes = ohbytes + onbytes;
5291 /* now, we round up the record to a 4 byte alignment, and we make
5292 * sure that we have enough room here for even the aligned version
5293 * (so we don't have to worry about an * overflow when we pad
5294 * things out below). That's the reason for the alignment
5297 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5298 align = (4 - (orbytes & 3)) & 3;
5302 if (orbytes + align > maxReturnData) {
5304 /* even though this request is unlikely to succeed with a
5305 failover, we do it anyway. */
5306 code = CM_ERROR_NOSUCHFILE;
5307 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5312 /* this is one of the entries to use: it is not deleted and it
5313 * matches the star pattern we're looking for. Put out the name,
5314 * preceded by its length.
5316 /* First zero everything else */
5317 memset(origOp, 0, orbytes);
5320 smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5322 switch (infoLevel) {
5323 case SMB_INFO_STANDARD:
5324 fp->u.FstandardInfo.fileNameLength = onbytes;
5325 attrp = &fp->u.FstandardInfo.fileAttrs;
5328 case SMB_INFO_QUERY_EA_SIZE:
5329 fp->u.FeaSizeInfo.fileNameLength = onbytes;
5330 attrp = &fp->u.FeaSizeInfo.fileAttrs;
5331 fp->u.FeaSizeInfo.eaSize = 0;
5334 case SMB_INFO_QUERY_EAS_FROM_LIST:
5335 fp->u.FeasFromListInfo.fileNameLength = onbytes;
5336 attrp = &fp->u.FeasFromListInfo.fileAttrs;
5337 fp->u.FeasFromListInfo.eaSize = 0;
5340 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5341 if (NeedShortName) {
5345 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
5346 fp->u.FfileBothDirectoryInfo.shortName,
5347 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
5349 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
5351 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5352 fp->u.FfileBothDirectoryInfo.reserved = 0;
5354 strcpy(fp->u.FfileBothDirectoryInfo.shortName,
5356 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
5361 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5362 fp->u.FfileFullDirectoryInfo.eaSize = 0;
5365 case SMB_FIND_FILE_DIRECTORY_INFO:
5366 fp->u.FfileDirectoryInfo.nextEntryOffset = 0;
5367 fp->u.FfileDirectoryInfo.fileIndex = 0;
5368 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5369 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5372 case SMB_FIND_FILE_NAMES_INFO:
5373 fp->u.FfileNamesInfo.nextEntryOffset = 0;
5374 fp->u.FfileNamesInfo.fileIndex = 0;
5375 fp->u.FfileNamesInfo.fileNameLength = onbytes;
5379 /* we shouldn't hit this case */
5380 osi_assertx(FALSE, "Unknown query type");
5383 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5384 osi_assert(attrp != NULL);
5386 curPatchp = malloc(sizeof(*curPatchp));
5387 osi_QAdd((osi_queue_t **) &dirListPatchesp,
5389 curPatchp->dptr = attrp;
5391 if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
5392 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5394 curPatchp->flags = 0;
5399 int namelen = cm_ClientStringToFsString(maskp, -1, NULL, 0);
5400 dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+namelen);
5401 cm_ClientStringToFsString(maskp, -1, dep->name, namelen);
5405 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, scp->fid.vnode, 0);
5406 dep->fid.vnode = scp->fid.vnode;
5407 dep->fid.unique = 0;
5408 curPatchp->flags |= SMB_DIRLISTPATCH_IOCTL;
5410 cm_SetFid(&curPatchp->fid, targetScp->fid.cell, targetScp->fid.volume, targetScp->fid.vnode, targetScp->fid.unique);
5411 dep->fid.vnode = targetScp->fid.vnode;
5412 dep->fid.unique = targetScp->fid.unique;
5415 curPatchp->dep = dep;
5418 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
5419 /* put out resume key */
5420 *((u_long *)origOp) = 0;
5423 /* Adjust byte ptr and count */
5424 origOp += orbytes; /* skip entire record */
5425 bytesInBuffer += orbytes;
5427 /* and pad the record out */
5428 while (--align >= 0) {
5433 /* apply the patches */
5434 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->wdata, infoLevel, userp, &req);
5436 outp->parmsp[0] = 0;
5437 outp->parmsp[1] = 1; /* number of names returned */
5438 outp->parmsp[2] = 1; /* end of search */
5439 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5440 outp->parmsp[4] = 0;
5442 outp->totalParms = 10; /* in bytes */
5444 outp->totalData = bytesInBuffer;
5446 osi_Log0(smb_logp, "T2SDSingle done.");
5448 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5450 smb_SendTran2Error(vcp, p, opx, code);
5452 smb_SendTran2Packet(vcp, outp, opx);
5457 smb_FreeTran2Packet(outp);
5461 cm_ReleaseSCache(scp);
5463 cm_ReleaseSCache(targetScp);
5464 cm_ReleaseUser(userp);
5470 /* TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2 */
5471 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
5476 long code = 0, code2 = 0;
5477 clientchar_t *pathp;
5478 cm_dirEntry_t *dep = 0;
5480 smb_dirListPatch_t *dirListPatchesp = 0;
5481 smb_dirListPatch_t *curPatchp = 0;
5484 size_t orbytes; /* # of bytes in this output record */
5485 size_t ohbytes; /* # of bytes, except file name */
5486 size_t onbytes; /* # of bytes in name, incl. term. null */
5487 osi_hyper_t dirLength;
5488 osi_hyper_t bufferOffset;
5489 osi_hyper_t curOffset;
5491 smb_dirSearch_t *dsp;
5495 cm_pageHeader_t *pageHeaderp;
5496 cm_user_t *userp = NULL;
5499 long nextEntryCookie;
5500 int numDirChunks; /* # of 32 byte dir chunks in this entry */
5501 char *op; /* output data ptr */
5502 char *origOp; /* original value of op */
5503 cm_space_t *spacep; /* for pathname buffer */
5504 unsigned long maxReturnData; /* max # of return data */
5505 unsigned long maxReturnParms; /* max # of return parms */
5506 long bytesInBuffer; /* # data bytes in the output buffer */
5508 clientchar_t *maskp; /* mask part of path */
5512 smb_tran2Packet_t *outp; /* response packet */
5513 clientchar_t *tidPathp;
5515 clientchar_t shortName[13]; /* 8.3 name if needed */
5518 clientchar_t *shortNameEnd;
5524 smb_tran2Find_t * fp;
5529 if (p->opcode == 1) {
5530 /* find first; obtain basic parameters from request */
5531 attribute = p->parmsp[0];
5532 maxCount = p->parmsp[1];
5533 infoLevel = p->parmsp[3];
5534 searchFlags = p->parmsp[2];
5535 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
5537 maskp = cm_ClientStrRChr(pathp, '\\');
5541 maskp++; /* skip over backslash */
5543 /* track if this is likely to match a lot of entries */
5544 starPattern = smb_V3IsStarMask(maskp);
5546 #ifndef NOFINDFIRSTOPTIMIZE
5548 /* if this is for a single directory or file, we let the
5549 optimized routine handle it. The only error it
5550 returns is CM_ERROR_NOSUCHFILE. The */
5551 code = smb_T2SearchDirSingle(vcp, p, opx);
5553 /* we only failover if we see a CM_ERROR_NOSUCHFILE */
5554 if (code != CM_ERROR_NOSUCHFILE) {
5556 /* unless we are using the BPlusTree */
5557 if (code == CM_ERROR_BPLUS_NOMATCH)
5558 code = CM_ERROR_NOSUCHFILE;
5559 #endif /* USE_BPLUS */
5563 #endif /* NOFINDFIRSTOPTIMIZE */
5566 dsp = smb_NewDirSearch(1);
5567 dsp->attribute = attribute;
5568 cm_ClientStrCpy(dsp->mask, lengthof(dsp->mask), maskp); /* and save mask */
5571 osi_assertx(p->opcode == 2, "invalid opcode");
5572 /* find next; obtain basic parameters from request or open dir file */
5573 dsp = smb_FindDirSearch(p->parmsp[0]);
5574 maxCount = p->parmsp[1];
5575 infoLevel = p->parmsp[2];
5576 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
5577 searchFlags = p->parmsp[5];
5579 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
5580 p->parmsp[0], nextCookie);
5581 return CM_ERROR_BADFD;
5583 attribute = dsp->attribute;
5586 starPattern = 1; /* assume, since required a Find Next */
5589 switch ( infoLevel ) {
5590 case SMB_INFO_STANDARD:
5592 ohbytes = sizeof(fp->u.FstandardInfo);
5595 case SMB_INFO_QUERY_EA_SIZE:
5596 ohbytes = sizeof(fp->u.FeaSizeInfo);
5597 s = "InfoQueryEaSize";
5600 case SMB_INFO_QUERY_EAS_FROM_LIST:
5601 ohbytes = sizeof(fp->u.FeasFromListInfo);
5602 s = "InfoQueryEasFromList";
5605 case SMB_FIND_FILE_DIRECTORY_INFO:
5606 s = "FindFileDirectoryInfo";
5607 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
5610 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5611 s = "FindFileFullDirectoryInfo";
5612 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
5615 case SMB_FIND_FILE_NAMES_INFO:
5616 s = "FindFileNamesInfo";
5617 ohbytes = sizeof(fp->u.FfileNamesInfo);
5620 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5621 s = "FindFileBothDirectoryInfo";
5622 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
5626 s = "unknownInfoLevel";
5630 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
5633 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
5634 attribute, infoLevel, maxCount, searchFlags);
5636 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
5637 p->opcode, dsp->cookie, nextCookie);
5640 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
5641 smb_ReleaseDirSearch(dsp);
5642 return CM_ERROR_INVAL;
5645 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5646 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
5648 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5651 dirListPatchesp = NULL;
5653 maxReturnData = p->maxReturnData;
5654 if (p->opcode == 1) /* find first */
5655 maxReturnParms = 10; /* bytes */
5657 maxReturnParms = 8; /* bytes */
5659 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
5665 osi_Log2(smb_logp, "T2 receive search dir count %d [%S]",
5666 maxCount, osi_LogSaveClientString(smb_logp, pathp));
5668 /* bail out if request looks bad */
5669 if (p->opcode == 1 && !pathp) {
5670 smb_ReleaseDirSearch(dsp);
5671 smb_FreeTran2Packet(outp);
5672 return CM_ERROR_BADSMB;
5675 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
5676 dsp->cookie, nextCookie, attribute);
5678 userp = smb_GetTran2User(vcp, p);
5680 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
5681 smb_ReleaseDirSearch(dsp);
5682 smb_FreeTran2Packet(outp);
5683 return CM_ERROR_BADSMB;
5686 /* try to get the vnode for the path name next */
5687 lock_ObtainMutex(&dsp->mx);
5690 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5694 spacep = cm_GetSpace();
5695 /* smb_StripLastComponent will strip "::$DATA" if present */
5696 smb_StripLastComponent(spacep->wdata, NULL, pathp);
5697 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
5699 cm_ReleaseUser(userp);
5700 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
5701 smb_FreeTran2Packet(outp);
5702 lock_ReleaseMutex(&dsp->mx);
5703 smb_DeleteDirSearch(dsp);
5704 smb_ReleaseDirSearch(dsp);
5708 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
5709 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
5711 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
5712 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5713 userp, tidPathp, &req, &scp);
5714 cm_FreeSpace(spacep);
5717 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
5718 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5719 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
5720 cm_ReleaseSCache(scp);
5721 cm_ReleaseUser(userp);
5722 if ( WANTS_DFS_PATHNAMES(p) || pnc )
5723 code = CM_ERROR_PATH_NOT_COVERED;
5725 code = CM_ERROR_NOSUCHPATH;
5726 smb_SendTran2Error(vcp, p, opx, code);
5727 smb_FreeTran2Packet(outp);
5728 lock_ReleaseMutex(&dsp->mx);
5729 smb_DeleteDirSearch(dsp);
5730 smb_ReleaseDirSearch(dsp);
5733 #endif /* DFS_SUPPORT */
5735 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5736 /* we need one hold for the entry we just stored into,
5737 * and one for our own processing. When we're done
5738 * with this function, we'll drop the one for our own
5739 * processing. We held it once from the namei call,
5740 * and so we do another hold now.
5743 dsp->flags |= SMB_DIRSEARCH_BULKST;
5746 lock_ReleaseMutex(&dsp->mx);
5748 cm_ReleaseUser(userp);
5749 smb_FreeTran2Packet(outp);
5750 smb_DeleteDirSearch(dsp);
5751 smb_ReleaseDirSearch(dsp);
5755 /* get the directory size */
5756 lock_ObtainWrite(&scp->rw);
5757 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5758 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5760 lock_ReleaseWrite(&scp->rw);
5761 cm_ReleaseSCache(scp);
5762 cm_ReleaseUser(userp);
5763 smb_FreeTran2Packet(outp);
5764 smb_DeleteDirSearch(dsp);
5765 smb_ReleaseDirSearch(dsp);
5769 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5772 dirLength = scp->length;
5774 bufferOffset.LowPart = bufferOffset.HighPart = 0;
5775 curOffset.HighPart = 0;
5776 curOffset.LowPart = nextCookie;
5777 origOp = outp->datap;
5784 normchar_t normName[MAX_PATH]; /* Normalized name */
5785 clientchar_t cfileName[MAX_PATH]; /* Non-normalized name */
5788 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5789 /* skip over resume key */
5792 fp = (smb_tran2Find_t *) op;
5794 /* make sure that curOffset.LowPart doesn't point to the first
5795 * 32 bytes in the 2nd through last dir page, and that it doesn't
5796 * point at the first 13 32-byte chunks in the first dir page,
5797 * since those are dir and page headers, and don't contain useful
5800 temp = curOffset.LowPart & (2048-1);
5801 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5802 /* we're in the first page */
5803 if (temp < 13*32) temp = 13*32;
5806 /* we're in a later dir page */
5807 if (temp < 32) temp = 32;
5810 /* make sure the low order 5 bits are zero */
5813 /* now put temp bits back ito curOffset.LowPart */
5814 curOffset.LowPart &= ~(2048-1);
5815 curOffset.LowPart |= temp;
5817 /* check if we've passed the dir's EOF */
5818 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
5819 osi_Log0(smb_logp, "T2 search dir passed eof");
5824 /* check if we've returned all the names that will fit in the
5825 * response packet; we check return count as well as the number
5826 * of bytes requested. We check the # of bytes after we find
5827 * the dir entry, since we'll need to check its size.
5829 if (returnedNames >= maxCount) {
5830 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
5831 returnedNames, maxCount);
5835 /* when we have obtained as many entries as can be processed in
5836 * a single Bulk Status call to the file server, apply the dir listing
5839 if (returnedNames > 0 && returnedNames % AFSCBMAX == 0) {
5840 lock_ReleaseWrite(&scp->rw);
5841 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5842 dsp->relPath, infoLevel, userp, &req);
5843 lock_ObtainWrite(&scp->rw);
5845 /* Then check to see if we have time left to process more entries */
5846 if (GetTickCount() - req.startTime > (RDRtimeout - 15) * 1000) {
5847 osi_Log0(smb_logp, "T2 search dir RDRtimeout exceeded");
5851 /* see if we can use the bufferp we have now; compute in which
5852 * page the current offset would be, and check whether that's
5853 * the offset of the buffer we have. If not, get the buffer.
5855 thyper.HighPart = curOffset.HighPart;
5856 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5857 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5860 buf_Release(bufferp);
5863 lock_ReleaseWrite(&scp->rw);
5864 code = buf_Get(scp, &thyper, &req, &bufferp);
5865 lock_ObtainWrite(&scp->rw);
5867 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
5871 bufferOffset = thyper;
5873 /* now get the data in the cache */
5875 code = cm_SyncOp(scp, bufferp, userp, &req,
5877 CM_SCACHESYNC_NEEDCALLBACK
5878 | CM_SCACHESYNC_READ);
5880 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5884 if (cm_HaveBuffer(scp, bufferp, 0)) {
5885 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5886 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5890 /* otherwise, load the buffer and try again */
5891 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5893 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5895 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5896 scp, bufferp, code);
5901 buf_Release(bufferp);
5905 } /* if (wrong buffer) ... */
5907 /* now we have the buffer containing the entry we're interested
5908 * in; copy it out if it represents a non-deleted entry.
5910 entryInDir = curOffset.LowPart & (2048-1);
5911 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5913 /* page header will help tell us which entries are free. Page
5914 * header can change more often than once per buffer, since
5915 * AFS 3 dir page size may be less than (but not more than)
5916 * a buffer package buffer.
5918 /* only look intra-buffer */
5919 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5920 temp &= ~(2048 - 1); /* turn off intra-page bits */
5921 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5923 /* now determine which entry we're looking at in the page.
5924 * If it is free (there's a free bitmap at the start of the
5925 * dir), we should skip these 32 bytes.
5927 slotInPage = (entryInDir & 0x7e0) >> 5;
5928 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5929 (1 << (slotInPage & 0x7)))) {
5930 /* this entry is free */
5931 numDirChunks = 1; /* only skip this guy */
5935 tp = bufferp->datap + entryInBuffer;
5936 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5938 /* while we're here, compute the next entry's location, too,
5939 * since we'll need it when writing out the cookie into the dir
5942 * XXXX Probably should do more sanity checking.
5944 numDirChunks = cm_NameEntries(dep->name, &onbytes);
5946 /* compute offset of cookie representing next entry */
5947 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5949 if (dep->fid.vnode == 0)
5950 goto nextEntry; /* This entry is not in use */
5952 if (cm_FsStringToClientString(dep->name, -1, cfileName, lengthof(cfileName)) == 0 ||
5953 cm_ClientStringToNormString(cfileName, -1, normName, lengthof(normName)) == 0) {
5955 osi_Log1(smb_logp, "Skipping entry [%s]. Can't convert or normalize FS String",
5956 osi_LogSaveString(smb_logp, dep->name));
5960 /* Need 8.3 name? */
5962 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
5964 !cm_Is8Dot3(cfileName)) {
5965 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5969 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %S (%S)",
5970 dep->fid.vnode, dep->fid.unique,
5971 osi_LogSaveClientString(smb_logp, cfileName),
5972 NeedShortName ? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
5974 /* When matching, we are using doing a case fold if we have a wildcard mask.
5975 * If we get a non-wildcard match, it's a lookup for a specific file.
5977 if (cm_MatchMask(normName, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5978 (NeedShortName && cm_MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))
5980 /* Eliminate entries that don't match requested attributes */
5981 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5982 smb_IsDotFile(cfileName)) {
5983 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5984 goto nextEntry; /* no hidden files */
5987 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5989 /* We have already done the cm_TryBulkStat above */
5990 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume,
5991 ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5992 fileType = cm_FindFileType(&fid);
5993 /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5994 * "has filetype %d", dep->name, fileType);
5996 if ( fileType == CM_SCACHETYPE_DIRECTORY ||
5997 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5998 fileType == CM_SCACHETYPE_DFSLINK ||
5999 fileType == CM_SCACHETYPE_INVALID)
6000 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
6004 /* finally check if this name will fit */
6006 smb_UnparseString(opx, NULL, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
6007 orbytes = ohbytes + onbytes;
6009 /* now, we round up the record to a 4 byte alignment,
6010 * and we make sure that we have enough room here for
6011 * even the aligned version (so we don't have to worry
6012 * about an overflow when we pad things out below).
6013 * That's the reason for the alignment arithmetic below.
6015 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
6016 align = (4 - (orbytes & 3)) & 3;
6020 if (orbytes + bytesInBuffer + align > maxReturnData) {
6021 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
6026 /* this is one of the entries to use: it is not deleted
6027 * and it matches the star pattern we're looking for.
6028 * Put out the name, preceded by its length.
6030 /* First zero everything else */
6031 memset(origOp, 0, orbytes);
6034 smb_UnparseString(opx, origOp + ohbytes, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
6036 switch (infoLevel) {
6037 case SMB_INFO_STANDARD:
6038 fp->u.FstandardInfo.fileNameLength = onbytes;
6039 attrp = &fp->u.FstandardInfo.fileAttrs;
6042 case SMB_INFO_QUERY_EA_SIZE:
6043 fp->u.FeaSizeInfo.fileNameLength = onbytes;
6044 attrp = &fp->u.FeaSizeInfo.fileAttrs;
6045 fp->u.FeaSizeInfo.eaSize = 0;
6048 case SMB_INFO_QUERY_EAS_FROM_LIST:
6049 fp->u.FeasFromListInfo.fileNameLength = onbytes;
6050 attrp = &fp->u.FeasFromListInfo.fileAttrs;
6051 fp->u.FeasFromListInfo.eaSize = 0;
6054 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
6055 if (NeedShortName) {
6059 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
6060 fp->u.FfileBothDirectoryInfo.shortName,
6061 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
6063 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
6065 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
6066 fp->u.FfileBothDirectoryInfo.reserved = 0;
6068 cm_ClientStrCpy(fp->u.FfileBothDirectoryInfo.shortName,
6069 lengthof(fp->u.FfileBothDirectoryInfo.shortName),
6071 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
6076 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
6077 fp->u.FfileFullDirectoryInfo.eaSize = 0;
6080 case SMB_FIND_FILE_DIRECTORY_INFO:
6081 fp->u.FfileDirectoryInfo.nextEntryOffset = orbytes + align;
6082 fp->u.FfileDirectoryInfo.fileIndex = nextEntryCookie;
6083 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
6084 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
6087 case SMB_FIND_FILE_NAMES_INFO:
6088 fp->u.FfileNamesInfo.nextEntryOffset = orbytes + align;
6089 fp->u.FfileNamesInfo.fileIndex = nextEntryCookie;
6090 fp->u.FfileNamesInfo.fileNameLength = onbytes;
6095 /* we shouldn't hit this case */
6096 osi_assertx(FALSE, "Unknown query type");
6099 /* now, adjust the # of entries copied */
6102 /* now we emit the attribute. This is tricky, since
6103 * we need to really stat the file to find out what
6104 * type of entry we've got. Right now, we're copying
6105 * out data from a buffer, while holding the scp
6106 * locked, so it isn't really convenient to stat
6107 * something now. We'll put in a place holder
6108 * now, and make a second pass before returning this
6109 * to get the real attributes. So, we just skip the
6110 * data for now, and adjust it later. We allocate a
6111 * patch record to make it easy to find this point
6112 * later. The replay will happen at a time when it is
6113 * safe to unlock the directory.
6115 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
6116 osi_assert(attrp != NULL);
6117 curPatchp = malloc(sizeof(*curPatchp));
6118 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
6119 curPatchp->dptr = attrp;
6121 if (smb_hideDotFiles && smb_IsDotFile(cfileName)) {
6122 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
6124 curPatchp->flags = 0;
6127 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
6130 curPatchp->dep = dep;
6133 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
6134 /* put out resume key */
6135 *((u_long *)origOp) = nextEntryCookie;
6137 /* Adjust byte ptr and count */
6138 origOp += orbytes; /* skip entire record */
6139 bytesInBuffer += orbytes;
6141 /* and pad the record out */
6142 while (align-- > 0) {
6146 } /* if we're including this name */
6147 else if (!starPattern &&
6149 cm_MatchMask(normName, maskp, CM_FLAG_CASEFOLD)) {
6150 /* We were looking for exact matches, but here's an inexact one*/
6155 /* and adjust curOffset to be where the new cookie is */
6156 thyper.HighPart = 0;
6157 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
6158 curOffset = LargeIntegerAdd(thyper, curOffset);
6159 } /* while copying data for dir listing */
6161 /* If we didn't get a star pattern, we did an exact match during the first pass.
6162 * If there were no exact matches found, we fail over to inexact matches by
6163 * marking the query as a star pattern (matches all case permutations), and
6164 * re-running the query.
6166 if (returnedNames == 0 && !starPattern && foundInexact) {
6167 osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
6172 /* release the mutex */
6173 lock_ReleaseWrite(&scp->rw);
6175 buf_Release(bufferp);
6180 * Finally, process whatever entries we have left.
6182 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
6183 dsp->relPath, infoLevel, userp, &req);
6185 /* now put out the final parameters */
6186 if (returnedNames == 0)
6188 if (p->opcode == 1) {
6190 outp->parmsp[0] = (unsigned short) dsp->cookie;
6191 outp->parmsp[1] = returnedNames;
6192 outp->parmsp[2] = eos;
6193 outp->parmsp[3] = 0; /* nothing wrong with EAS */
6194 outp->parmsp[4] = 0;
6195 /* don't need last name to continue
6196 * search, cookie is enough. Normally,
6197 * this is the offset of the file name
6198 * of the last entry returned.
6200 outp->totalParms = 10; /* in bytes */
6204 outp->parmsp[0] = returnedNames;
6205 outp->parmsp[1] = eos;
6206 outp->parmsp[2] = 0; /* EAS error */
6207 outp->parmsp[3] = 0; /* last name, as above */
6208 outp->totalParms = 8; /* in bytes */
6211 /* return # of bytes in the buffer */
6212 outp->totalData = bytesInBuffer;
6214 /* Return error code if unsuccessful on first request */
6215 if (code == 0 && p->opcode == 1 && returnedNames == 0)
6216 code = CM_ERROR_NOSUCHFILE;
6218 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
6219 p->opcode, dsp->cookie, returnedNames, code);
6221 /* if we're supposed to close the search after this request, or if
6222 * we're supposed to close the search if we're done, and we're done,
6223 * or if something went wrong, close the search.
6225 if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
6226 (returnedNames == 0) ||
6227 ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
6229 smb_DeleteDirSearch(dsp);
6232 smb_SendTran2Error(vcp, p, opx, code);
6234 smb_SendTran2Packet(vcp, outp, opx);
6236 smb_FreeTran2Packet(outp);
6237 smb_ReleaseDirSearch(dsp);
6238 cm_ReleaseSCache(scp);
6239 cm_ReleaseUser(userp);
6243 /* SMB_COM_FIND_CLOSE2 */
6244 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6247 smb_dirSearch_t *dsp;
6249 dirHandle = smb_GetSMBParm(inp, 0);
6251 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
6253 dsp = smb_FindDirSearch(dirHandle);
6256 return CM_ERROR_BADFD;
6258 /* otherwise, we have an FD to destroy */
6259 smb_DeleteDirSearch(dsp);
6260 smb_ReleaseDirSearch(dsp);
6262 /* and return results */
6263 smb_SetSMBDataLength(outp, 0);
6269 /* SMB_COM_FIND_NOTIFY_CLOSE */
6270 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6272 smb_SetSMBDataLength(outp, 0);
6276 /* SMB_COM_OPEN_ANDX */
6277 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6279 clientchar_t *pathp;
6284 cm_scache_t *dscp; /* dir we're dealing with */
6285 cm_scache_t *scp; /* file we're creating */
6289 clientchar_t *lastNamep;
6290 unsigned long dosTime;
6296 int parmSlot; /* which parm we're dealing with */
6297 clientchar_t *tidPathp;
6300 BOOL is_rpc = FALSE;
6301 BOOL is_ipc = FALSE;
6307 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
6308 openFun = smb_GetSMBParm(inp, 8); /* open function */
6309 excl = ((openFun & 3) == 0);
6310 trunc = ((openFun & 3) == 2); /* truncate it */
6311 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
6312 openAction = 0; /* tracks what we did */
6314 attributes = smb_GetSMBParm(inp, 5);
6315 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
6317 pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
6320 return CM_ERROR_BADSMB;
6322 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6324 if (code == CM_ERROR_TIDIPC) {
6327 return CM_ERROR_NOSUCHPATH;
6331 spacep = inp->spacep;
6332 /* smb_StripLastComponent will strip "::$DATA" if present */
6333 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6337 /* special case magic file name for receiving IOCTL requests
6338 * (since IOCTL calls themselves aren't getting through).
6340 (cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
6342 /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional) */
6343 (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
6345 unsigned short file_type = 0;
6346 unsigned short device_state = 0;
6348 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6350 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
6351 osi_Log1(smb_logp, "OpenAndX Setting up RPC on fid[%d]", fidp->fid);
6353 osi_Log1(smb_logp, "smb_SetupRPCFid failure code [%d]", code);
6354 smb_ReleaseFID(fidp);
6358 smb_SetupIoctlFid(fidp, spacep);
6359 osi_Log1(smb_logp, "OpenAndX Setting up IOCTL on fid[%d]", fidp->fid);
6362 /* set inp->fid so that later read calls in same msg can find fid */
6363 inp->fid = fidp->fid;
6365 /* copy out remainder of the parms */
6367 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6369 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
6370 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
6371 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6372 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
6373 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
6374 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
6375 smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++;
6376 smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++;
6378 /* and the final "always present" stuff */
6379 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
6380 /* next write out the "unique" ID */
6381 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
6382 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
6383 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6384 smb_SetSMBDataLength(outp, 0);
6386 /* and clean up fid reference */
6387 smb_ReleaseFID(fidp);
6393 osi_Log0(smb_logp, "NTOpenX rejecting IPC TID");
6394 return CM_ERROR_BADFD;
6398 if (!cm_IsValidClientString(pathp)) {
6400 clientchar_t * hexp;
6402 hexp = cm_GetRawCharsAlloc(pathp, -1);
6403 osi_Log1(smb_logp, "NTOpenX rejecting invalid name. [%S]",
6404 osi_LogSaveClientString(smb_logp, hexp));
6408 osi_Log0(smb_logp, "NTOpenX rejecting invalid name");
6410 return CM_ERROR_BADNTFILENAME;
6413 #ifdef DEBUG_VERBOSE
6415 char *hexp, *asciip;
6416 asciip = (lastNamep ? lastNamep : pathp );
6417 hexp = osi_HexifyString(asciip);
6418 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
6422 userp = smb_GetUserFromVCP(vcp, inp);
6425 code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
6426 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6427 userp, tidPathp, &req, &scp);
6430 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6431 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
6432 cm_ReleaseSCache(scp);
6433 cm_ReleaseUser(userp);
6434 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6435 return CM_ERROR_PATH_NOT_COVERED;
6437 return CM_ERROR_NOSUCHPATH;
6439 #endif /* DFS_SUPPORT */
6442 if (code == CM_ERROR_NOSUCHFILE ||
6443 code == CM_ERROR_NOSUCHPATH ||
6444 code == CM_ERROR_BPLUS_NOMATCH)
6445 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
6446 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6447 userp, tidPathp, &req, &dscp);
6449 cm_ReleaseUser(userp);
6454 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6455 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
6457 cm_ReleaseSCache(dscp);
6458 cm_ReleaseUser(userp);
6459 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6460 return CM_ERROR_PATH_NOT_COVERED;
6462 return CM_ERROR_NOSUCHPATH;
6464 #endif /* DFS_SUPPORT */
6465 /* otherwise, scp points to the parent directory. Do a lookup,
6466 * and truncate the file if we find it, otherwise we create the
6473 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
6475 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
6476 cm_ReleaseSCache(dscp);
6477 cm_ReleaseUser(userp);
6482 /* if we get here, if code is 0, the file exists and is represented by
6483 * scp. Otherwise, we have to create it. The dir may be represented
6484 * by dscp, or we may have found the file directly. If code is non-zero,
6488 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
6490 if (dscp) cm_ReleaseSCache(dscp);
6491 cm_ReleaseSCache(scp);
6492 cm_ReleaseUser(userp);
6497 /* oops, file shouldn't be there */
6499 cm_ReleaseSCache(dscp);
6500 cm_ReleaseSCache(scp);
6501 cm_ReleaseUser(userp);
6502 return CM_ERROR_EXISTS;
6506 setAttr.mask = CM_ATTRMASK_LENGTH;
6507 setAttr.length.LowPart = 0;
6508 setAttr.length.HighPart = 0;
6509 code = cm_SetAttr(scp, &setAttr, userp, &req);
6510 openAction = 3; /* truncated existing file */
6512 else openAction = 1; /* found existing file */
6514 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
6515 /* don't create if not found */
6516 if (dscp) cm_ReleaseSCache(dscp);
6517 cm_ReleaseUser(userp);
6518 return CM_ERROR_NOSUCHFILE;
6521 osi_assertx(dscp != NULL, "null cm_scache_t");
6522 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %S",
6523 osi_LogSaveClientString(smb_logp, lastNamep));
6524 openAction = 2; /* created file */
6525 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6526 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6527 smb_SetInitialModeBitsForFile(attributes, &setAttr);
6529 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6533 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6534 smb_NotifyChange(FILE_ACTION_ADDED,
6535 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6536 dscp, lastNamep, NULL, TRUE);
6537 } else if (!excl && code == CM_ERROR_EXISTS) {
6538 /* not an exclusive create, and someone else tried
6539 * creating it already, then we open it anyway. We
6540 * don't bother retrying after this, since if this next
6541 * fails, that means that the file was deleted after we
6542 * started this call.
6544 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6548 setAttr.mask = CM_ATTRMASK_LENGTH;
6549 setAttr.length.LowPart = 0;
6550 setAttr.length.HighPart = 0;
6551 code = cm_SetAttr(scp, &setAttr, userp, &req);
6553 } /* lookup succeeded */
6557 /* we don't need this any longer */
6559 cm_ReleaseSCache(dscp);
6562 /* something went wrong creating or truncating the file */
6564 cm_ReleaseSCache(scp);
6565 cm_ReleaseUser(userp);
6569 /* make sure we're about to open a file */
6570 if (scp->fileType != CM_SCACHETYPE_FILE) {
6571 cm_ReleaseSCache(scp);
6572 cm_ReleaseUser(userp);
6573 return CM_ERROR_ISDIR;
6576 /* now all we have to do is open the file itself */
6577 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6578 osi_assertx(fidp, "null smb_fid_t");
6581 lock_ObtainMutex(&fidp->mx);
6582 /* save a pointer to the vnode */
6584 lock_ObtainWrite(&scp->rw);
6585 scp->flags |= CM_SCACHEFLAG_SMB_FID;
6586 lock_ReleaseWrite(&scp->rw);
6587 osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
6589 fidp->userp = userp;
6591 /* compute open mode */
6593 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
6594 if (openMode == 1 || openMode == 2)
6595 fidp->flags |= SMB_FID_OPENWRITE;
6597 /* remember if the file was newly created */
6599 fidp->flags |= SMB_FID_CREATED;
6601 lock_ReleaseMutex(&fidp->mx);
6602 smb_ReleaseFID(fidp);
6604 cm_Open(scp, 0, userp);
6606 /* set inp->fid so that later read calls in same msg can find fid */
6607 inp->fid = fidp->fid;
6609 /* copy out remainder of the parms */
6611 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6612 lock_ObtainRead(&scp->rw);
6614 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
6615 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
6616 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
6617 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
6618 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
6619 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
6620 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
6621 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
6622 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
6624 /* and the final "always present" stuff */
6625 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
6626 /* next write out the "unique" ID */
6627 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
6628 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
6629 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6630 lock_ReleaseRead(&scp->rw);
6631 smb_SetSMBDataLength(outp, 0);
6633 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
6635 cm_ReleaseUser(userp);
6636 /* leave scp held since we put it in fidp->scp */
6640 static void smb_GetLockParams(unsigned char LockType,
6642 unsigned int * ppid,
6643 LARGE_INTEGER * pOffset,
6644 LARGE_INTEGER * pLength)
6646 if (LockType & LOCKING_ANDX_LARGE_FILES) {
6648 *ppid = *((USHORT *) *buf);
6649 pOffset->HighPart = *((LONG *)(*buf + 4));
6650 pOffset->LowPart = *((DWORD *)(*buf + 8));
6651 pLength->HighPart = *((LONG *)(*buf + 12));
6652 pLength->LowPart = *((DWORD *)(*buf + 16));
6656 /* Not Large Files */
6657 *ppid = *((USHORT *) *buf);
6658 pOffset->HighPart = 0;
6659 pOffset->LowPart = *((DWORD *)(*buf + 2));
6660 pLength->HighPart = 0;
6661 pLength->LowPart = *((DWORD *)(*buf + 6));
6666 /* SMB_COM_LOCKING_ANDX */
6667 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6674 unsigned char LockType;
6675 unsigned short NumberOfUnlocks, NumberOfLocks;
6679 LARGE_INTEGER LOffset, LLength;
6680 smb_waitingLockRequest_t *wlRequest = NULL;
6681 cm_file_lock_t *lockp;
6686 afs_uint32 smb_vc_hold_required = 0;
6690 fid = smb_GetSMBParm(inp, 2);
6691 fid = smb_ChainFID(fid, inp);
6693 fidp = smb_FindFID(vcp, fid, 0);
6695 osi_Log2(smb_logp, "V3LockingX Unknown SMB Fid vcp 0x%p fid %d",
6697 return CM_ERROR_BADFD;
6699 lock_ObtainMutex(&fidp->mx);
6700 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6701 lock_ReleaseMutex(&fidp->mx);
6702 smb_CloseFID(vcp, fidp, NULL, 0);
6703 smb_ReleaseFID(fidp);
6704 return CM_ERROR_NOSUCHFILE;
6707 if (fidp->flags & SMB_FID_IOCTL) {
6708 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
6709 lock_ReleaseMutex(&fidp->mx);
6710 smb_ReleaseFID(fidp);
6711 return CM_ERROR_BADFD;
6714 osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
6716 lock_ReleaseMutex(&fidp->mx);
6718 /* set inp->fid so that later read calls in same msg can find fid */
6721 userp = smb_GetUserFromVCP(vcp, inp);
6724 lock_ObtainWrite(&scp->rw);
6725 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6726 CM_SCACHESYNC_NEEDCALLBACK
6727 | CM_SCACHESYNC_GETSTATUS
6728 | CM_SCACHESYNC_LOCK);
6730 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
6734 LockType = smb_GetSMBParm(inp, 3) & 0xff;
6735 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
6736 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
6737 NumberOfLocks = smb_GetSMBParm(inp, 7);
6739 if (!(fidp->flags & SMB_FID_OPENWRITE) &&
6740 !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
6741 /* somebody wants exclusive locks on a file that they only
6742 opened for reading. We downgrade this to a shared lock. */
6743 osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
6744 LockType |= LOCKING_ANDX_SHARED_LOCK;
6747 if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
6748 /* AFS does not support atomic changes of lock types from read or write and vice-versa */
6749 osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]");
6750 code = CM_ERROR_BADOP;
6755 op = smb_GetSMBData(inp, NULL);
6757 if (LockType & LOCKING_ANDX_CANCEL_LOCK) {
6758 /* Cancel outstanding lock requests */
6759 smb_waitingLock_t * wl;
6761 for (i=0; i<NumberOfLocks; i++) {
6762 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6764 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6766 lock_ObtainWrite(&smb_globalLock);
6767 for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
6769 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
6770 if (cm_KeyEquals(&wl->key, &key, 0) && LargeIntegerEqualTo(wl->LOffset, LOffset) &&
6771 LargeIntegerEqualTo(wl->LLength, LLength)) {
6772 wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
6773 goto found_lock_request;
6778 lock_ReleaseWrite(&smb_globalLock);
6781 smb_SetSMBDataLength(outp, 0);
6786 for (i=0; i<NumberOfUnlocks; i++) {
6787 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6789 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6791 code = cm_Unlock(scp, LockType, LOffset, LLength, key, 0, userp, &req);
6799 for (i=0; i<NumberOfLocks; i++) {
6800 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6802 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6804 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
6805 userp, &req, &lockp);
6807 if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
6808 (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
6810 code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
6811 userp, &req, &lockp);
6814 if (code == CM_ERROR_LOCK_NOT_GRANTED && Timeout != 0) {
6815 smb_waitingLock_t * wLock;
6817 /* Put on waiting list */
6818 if(wlRequest == NULL) {
6822 LARGE_INTEGER tOffset, tLength;
6824 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
6826 osi_assertx(wlRequest != NULL, "null wlRequest");
6828 wlRequest->vcp = vcp;
6829 smb_vc_hold_required = 1;
6830 wlRequest->scp = scp;
6831 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
6833 wlRequest->inp = smb_CopyPacket(inp);
6834 wlRequest->outp = smb_CopyPacket(outp);
6835 wlRequest->lockType = LockType;
6836 wlRequest->msTimeout = Timeout;
6837 wlRequest->start_t = osi_Time();
6838 wlRequest->locks = NULL;
6840 /* The waiting lock request needs to have enough
6841 information to undo all the locks in the request.
6842 We do the following to store info about locks that
6843 have already been granted. Sure, we can get most
6844 of the info from the packet, but the packet doesn't
6845 hold the result of cm_Lock call. In practice we
6846 only receive packets with one or two locks, so we
6847 are only wasting a few bytes here and there and
6848 only for a limited period of time until the waiting
6849 lock times out or is freed. */
6851 for(opt = op_locks, j=i; j > 0; j--) {
6852 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
6854 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6856 wLock = malloc(sizeof(smb_waitingLock_t));
6858 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6861 wLock->LOffset = tOffset;
6862 wLock->LLength = tLength;
6863 wLock->lockp = NULL;
6864 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
6865 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6870 wLock = malloc(sizeof(smb_waitingLock_t));
6872 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6875 wLock->LOffset = LOffset;
6876 wLock->LLength = LLength;
6877 wLock->lockp = lockp;
6878 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
6879 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6882 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
6890 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
6897 /* Since something went wrong with the lock number i, we now
6898 have to go ahead and release any locks acquired before the
6899 failure. All locks before lock number i (of which there
6900 are i of them) have either been successful or are waiting.
6901 Either case requires calling cm_Unlock(). */
6903 /* And purge the waiting lock */
6904 if(wlRequest != NULL) {
6905 smb_waitingLock_t * wl;
6906 smb_waitingLock_t * wlNext;
6909 for(wl = wlRequest->locks; wl; wl = wlNext) {
6911 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
6913 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, 0, userp, &req);
6916 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
6918 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
6921 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
6926 smb_ReleaseVC(wlRequest->vcp);
6927 cm_ReleaseSCache(wlRequest->scp);
6928 smb_FreePacket(wlRequest->inp);
6929 smb_FreePacket(wlRequest->outp);
6938 if (wlRequest != NULL) {
6940 lock_ObtainWrite(&smb_globalLock);
6941 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
6943 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
6944 lock_ReleaseWrite(&smb_globalLock);
6946 /* don't send reply immediately */
6947 outp->flags |= SMB_PACKETFLAG_NOSEND;
6950 smb_SetSMBDataLength(outp, 0);
6954 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
6957 lock_ReleaseWrite(&scp->rw);
6958 cm_ReleaseSCache(scp);
6959 cm_ReleaseUser(userp);
6960 smb_ReleaseFID(fidp);
6961 if (!smb_vc_hold_required)
6967 /* SMB_COM_QUERY_INFORMATION2 */
6968 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6974 afs_uint32 searchTime;
6981 fid = smb_GetSMBParm(inp, 0);
6982 fid = smb_ChainFID(fid, inp);
6984 fidp = smb_FindFID(vcp, fid, 0);
6986 osi_Log2(smb_logp, "V3GetAttributes Unknown SMB Fid vcp 0x%p fid %d",
6988 return CM_ERROR_BADFD;
6990 lock_ObtainMutex(&fidp->mx);
6991 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6992 lock_ReleaseMutex(&fidp->mx);
6993 smb_CloseFID(vcp, fidp, NULL, 0);
6994 smb_ReleaseFID(fidp);
6995 return CM_ERROR_NOSUCHFILE;
6998 if (fidp->flags & SMB_FID_IOCTL) {
6999 lock_ReleaseMutex(&fidp->mx);
7000 smb_ReleaseFID(fidp);
7001 return CM_ERROR_BADFD;
7004 osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
7006 lock_ReleaseMutex(&fidp->mx);
7008 userp = smb_GetUserFromVCP(vcp, inp);
7011 /* otherwise, stat the file */
7012 lock_ObtainWrite(&scp->rw);
7013 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7014 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7018 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7020 lock_ConvertWToR(&scp->rw);
7023 /* decode times. We need a search time, but the response to this
7024 * call provides the date first, not the time, as returned in the
7025 * searchTime variable. So we take the high-order bits first.
7027 cm_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
7028 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
7029 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
7030 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
7031 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
7032 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
7033 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
7035 /* now handle file size and allocation size */
7036 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
7037 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
7038 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
7039 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
7041 /* file attribute */
7042 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
7044 /* and finalize stuff */
7045 smb_SetSMBDataLength(outp, 0);
7050 lock_ReleaseRead(&scp->rw);
7052 lock_ReleaseWrite(&scp->rw);
7053 cm_ReleaseSCache(scp);
7054 cm_ReleaseUser(userp);
7055 smb_ReleaseFID(fidp);
7059 /* SMB_COM_SET_INFORMATION2 */
7060 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7066 afs_uint32 searchTime;
7074 fid = smb_GetSMBParm(inp, 0);
7075 fid = smb_ChainFID(fid, inp);
7077 fidp = smb_FindFID(vcp, fid, 0);
7079 osi_Log2(smb_logp, "V3SetAttributes Unknown SMB Fid vcp 0x%p fid %d",
7081 return CM_ERROR_BADFD;
7083 lock_ObtainMutex(&fidp->mx);
7084 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7085 lock_ReleaseMutex(&fidp->mx);
7086 smb_CloseFID(vcp, fidp, NULL, 0);
7087 smb_ReleaseFID(fidp);
7088 return CM_ERROR_NOSUCHFILE;
7091 if (fidp->flags & SMB_FID_IOCTL) {
7092 lock_ReleaseMutex(&fidp->mx);
7093 smb_ReleaseFID(fidp);
7094 return CM_ERROR_BADFD;
7097 osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
7099 lock_ReleaseMutex(&fidp->mx);
7101 userp = smb_GetUserFromVCP(vcp, inp);
7103 /* now prepare to call cm_setattr. This message only sets various times,
7104 * and AFS only implements mtime, and we'll set the mtime if that's
7105 * requested. The others we'll ignore.
7107 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
7109 if (searchTime != 0) {
7110 cm_UnixTimeFromSearchTime(&unixTime, searchTime);
7112 if ( unixTime != -1 ) {
7113 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
7114 attrs.clientModTime = unixTime;
7115 code = cm_SetAttr(scp, &attrs, userp, &req);
7117 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
7119 osi_Log1(smb_logp, "**cm_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
7125 cm_ReleaseSCache(scp);
7126 cm_ReleaseUser(userp);
7127 smb_ReleaseFID(fidp);
7131 /* SMB_COM_WRITE_ANDX */
7132 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7135 long count, written = 0, total_written = 0;
7139 smb_t *smbp = (smb_t*) inp;
7144 int inDataBlockCount;
7146 fd = smb_GetSMBParm(inp, 2);
7147 count = smb_GetSMBParm(inp, 10);
7149 offset.HighPart = 0;
7150 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7152 if (*inp->wctp == 14) {
7153 /* we have a request with 64-bit file offsets */
7154 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7157 op = inp->data + smb_GetSMBParm(inp, 11);
7158 inDataBlockCount = count;
7160 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
7161 fd, offset.HighPart, offset.LowPart, count);
7163 fd = smb_ChainFID(fd, inp);
7164 fidp = smb_FindFID(vcp, fd, 0);
7166 osi_Log2(smb_logp, "smb_ReceiveV3WriteX Unknown SMB Fid vcp 0x%p fid %d",
7168 return CM_ERROR_BADFD;
7170 lock_ObtainMutex(&fidp->mx);
7171 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7172 lock_ReleaseMutex(&fidp->mx);
7173 smb_CloseFID(vcp, fidp, NULL, 0);
7174 smb_ReleaseFID(fidp);
7175 return CM_ERROR_NOSUCHFILE;
7178 if (fidp->flags & SMB_FID_IOCTL) {
7179 lock_ReleaseMutex(&fidp->mx);
7180 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
7181 smb_ReleaseFID(fidp);
7185 if (fidp->flags & SMB_FID_RPC) {
7186 lock_ReleaseMutex(&fidp->mx);
7187 code = smb_RPCV3Write(fidp, vcp, inp, outp);
7188 smb_ReleaseFID(fidp);
7193 lock_ReleaseMutex(&fidp->mx);
7194 smb_ReleaseFID(fidp);
7195 return CM_ERROR_BADFDOP;
7200 lock_ReleaseMutex(&fidp->mx);
7202 userp = smb_GetUserFromVCP(vcp, inp);
7204 /* special case: 0 bytes transferred means there is no data
7205 transferred. A slight departure from SMB_COM_WRITE where this
7206 means that we are supposed to truncate the file at this
7211 LARGE_INTEGER LOffset;
7212 LARGE_INTEGER LLength;
7215 key = cm_GenerateKey(vcp->vcID, pid, fd);
7217 LOffset.HighPart = offset.HighPart;
7218 LOffset.LowPart = offset.LowPart;
7219 LLength.HighPart = 0;
7220 LLength.LowPart = count;
7222 lock_ObtainWrite(&scp->rw);
7223 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7224 lock_ReleaseWrite(&scp->rw);
7231 * Work around bug in NT client
7233 * When copying a file, the NT client should first copy the data,
7234 * then copy the last write time. But sometimes the NT client does
7235 * these in the wrong order, so the data copies would inadvertently
7236 * cause the last write time to be overwritten. We try to detect this,
7237 * and don't set client mod time if we think that would go against the
7240 lock_ObtainMutex(&fidp->mx);
7241 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7242 lock_ObtainWrite(&fidp->scp->rw);
7243 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7244 scp->clientModTime = time(NULL);
7245 lock_ReleaseWrite(&fidp->scp->rw);
7247 lock_ReleaseMutex(&fidp->mx);
7250 while ( code == 0 && count > 0 ) {
7251 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7252 if (code == 0 && written == 0)
7253 code = CM_ERROR_PARTIALWRITE;
7255 offset = LargeIntegerAdd(offset,
7256 ConvertLongToLargeInteger(written));
7258 total_written += written;
7262 /* slots 0 and 1 are reserved for request chaining and will be
7263 filled in when we return. */
7264 smb_SetSMBParm(outp, 2, total_written);
7265 smb_SetSMBParm(outp, 3, 0); /* reserved */
7266 smb_SetSMBParm(outp, 4, 0); /* reserved */
7267 smb_SetSMBParm(outp, 5, 0); /* reserved */
7268 smb_SetSMBDataLength(outp, 0);
7272 cm_ReleaseSCache(scp);
7273 cm_ReleaseUser(userp);
7274 smb_ReleaseFID(fidp);
7279 /* SMB_COM_READ_ANDX */
7280 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7284 long finalCount = 0;
7288 smb_t *smbp = (smb_t*) inp;
7295 fd = smb_GetSMBParm(inp, 2); /* File ID */
7296 count = smb_GetSMBParm(inp, 5); /* MaxCount */
7297 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7299 if (*inp->wctp == 12) {
7300 /* a request with 64-bit offsets */
7301 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
7303 if (LargeIntegerLessThanZero(offset)) {
7304 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
7305 offset.HighPart, offset.LowPart);
7306 return CM_ERROR_BADSMB;
7309 offset.HighPart = 0;
7312 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
7313 fd, offset.HighPart, offset.LowPart, count);
7315 fd = smb_ChainFID(fd, inp);
7316 fidp = smb_FindFID(vcp, fd, 0);
7318 osi_Log2(smb_logp, "smb_ReceiveV3Read Unknown SMB Fid vcp 0x%p fid %d",
7320 return CM_ERROR_BADFD;
7323 lock_ObtainMutex(&fidp->mx);
7325 if (fidp->flags & SMB_FID_IOCTL) {
7326 lock_ReleaseMutex(&fidp->mx);
7328 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
7329 smb_ReleaseFID(fidp);
7333 if (fidp->flags & SMB_FID_RPC) {
7334 lock_ReleaseMutex(&fidp->mx);
7336 code = smb_RPCV3Read(fidp, vcp, inp, outp);
7337 smb_ReleaseFID(fidp);
7341 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7342 lock_ReleaseMutex(&fidp->mx);
7343 smb_CloseFID(vcp, fidp, NULL, 0);
7344 smb_ReleaseFID(fidp);
7345 return CM_ERROR_NOSUCHFILE;
7349 lock_ReleaseMutex(&fidp->mx);
7350 smb_ReleaseFID(fidp);
7351 return CM_ERROR_BADFDOP;
7357 lock_ReleaseMutex(&fidp->mx);
7360 key = cm_GenerateKey(vcp->vcID, pid, fd);
7362 LARGE_INTEGER LOffset, LLength;
7364 LOffset.HighPart = offset.HighPart;
7365 LOffset.LowPart = offset.LowPart;
7366 LLength.HighPart = 0;
7367 LLength.LowPart = count;
7369 lock_ObtainWrite(&scp->rw);
7370 code = cm_LockCheckRead(scp, LOffset, LLength, key);
7371 lock_ReleaseWrite(&scp->rw);
7373 cm_ReleaseSCache(scp);
7376 smb_ReleaseFID(fidp);
7380 /* set inp->fid so that later read calls in same msg can find fid */
7383 userp = smb_GetUserFromVCP(vcp, inp);
7385 /* 0 and 1 are reserved for request chaining, were setup by our caller,
7386 * and will be further filled in after we return.
7388 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
7389 smb_SetSMBParm(outp, 3, 0); /* resvd */
7390 smb_SetSMBParm(outp, 4, 0); /* resvd */
7391 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
7392 /* fill in #6 when we have all the parameters' space reserved */
7393 smb_SetSMBParm(outp, 7, 0); /* resv'd */
7394 smb_SetSMBParm(outp, 8, 0); /* resv'd */
7395 smb_SetSMBParm(outp, 9, 0); /* resv'd */
7396 smb_SetSMBParm(outp, 10, 0); /* resv'd */
7397 smb_SetSMBParm(outp, 11, 0); /* reserved */
7399 /* get op ptr after putting in the parms, since otherwise we don't
7400 * know where the data really is.
7402 op = smb_GetSMBData(outp, NULL);
7404 /* now fill in offset from start of SMB header to first data byte (to op) */
7405 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
7407 /* set the packet data length the count of the # of bytes */
7408 smb_SetSMBDataLength(outp, count);
7410 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7412 /* fix some things up */
7413 smb_SetSMBParm(outp, 5, finalCount);
7414 smb_SetSMBDataLength(outp, finalCount);
7416 cm_ReleaseUser(userp);
7417 smb_ReleaseFID(fidp);
7422 * Values for createDisp, copied from NTDDK.H
7424 #define FILE_SUPERSEDE 0 // (???)
7425 #define FILE_OPEN 1 // (open)
7426 #define FILE_CREATE 2 // (exclusive)
7427 #define FILE_OPEN_IF 3 // (non-exclusive)
7428 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
7429 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
7432 #define REQUEST_OPLOCK 2
7433 #define REQUEST_BATCH_OPLOCK 4
7434 #define OPEN_DIRECTORY 8
7435 #define EXTENDED_RESPONSE_REQUIRED 0x10
7437 /* CreateOptions field. */
7438 #define FILE_DIRECTORY_FILE 0x0001
7439 #define FILE_WRITE_THROUGH 0x0002
7440 #define FILE_SEQUENTIAL_ONLY 0x0004
7441 #define FILE_NON_DIRECTORY_FILE 0x0040
7442 #define FILE_NO_EA_KNOWLEDGE 0x0200
7443 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
7444 #define FILE_RANDOM_ACCESS 0x0800
7445 #define FILE_DELETE_ON_CLOSE 0x1000
7446 #define FILE_OPEN_BY_FILE_ID 0x2000
7447 #define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000
7448 #define FILE_NO_COMPRESSION 0x00008000
7449 #define FILE_RESERVE_OPFILTER 0x00100000
7450 #define FILE_OPEN_REPARSE_POINT 0x00200000
7451 #define FILE_OPEN_NO_RECALL 0x00400000
7452 #define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000
7454 /* SMB_COM_NT_CREATE_ANDX */
7455 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7457 clientchar_t *pathp, *realPathp;
7461 cm_scache_t *dscp; /* parent dir */
7462 cm_scache_t *scp; /* file to create or open */
7463 cm_scache_t *targetScp; /* if scp is a symlink */
7465 clientchar_t *lastNamep;
7466 clientchar_t *treeStartp;
7467 unsigned short nameLength;
7469 unsigned int requestOpLock;
7470 unsigned int requestBatchOpLock;
7471 unsigned int mustBeDir;
7472 unsigned int extendedRespRequired;
7473 unsigned int treeCreate;
7475 unsigned int desiredAccess;
7476 unsigned int extAttributes;
7477 unsigned int createDisp;
7478 unsigned int createOptions;
7479 unsigned int shareAccess;
7480 unsigned short baseFid;
7481 smb_fid_t *baseFidp;
7483 cm_scache_t *baseDirp;
7484 unsigned short openAction;
7489 clientchar_t *tidPathp;
7494 int checkDoneRequired = 0;
7495 cm_lock_data_t *ldp = NULL;
7496 BOOL is_rpc = FALSE;
7497 BOOL is_ipc = FALSE;
7501 /* This code is very long and has a lot of if-then-else clauses
7502 * scp and dscp get reused frequently and we need to ensure that
7503 * we don't lose a reference. Start by ensuring that they are NULL.
7510 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
7511 flags = smb_GetSMBOffsetParm(inp, 3, 1)
7512 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
7513 requestOpLock = flags & REQUEST_OPLOCK;
7514 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7515 mustBeDir = flags & OPEN_DIRECTORY;
7516 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7519 * Why all of a sudden 32-bit FID?
7520 * We will reject all bits higher than 16.
7522 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
7523 return CM_ERROR_INVAL;
7524 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
7525 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
7526 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
7527 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
7528 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
7529 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
7530 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
7531 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
7532 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
7533 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
7534 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
7536 /* mustBeDir is never set; createOptions directory bit seems to be
7539 if (createOptions & FILE_DIRECTORY_FILE)
7541 else if (createOptions & FILE_NON_DIRECTORY_FILE)
7546 pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
7547 NULL, SMB_STRF_ANSIPATH);
7549 /* Sometimes path is not null-terminated, so we make a copy. */
7550 realPathp = malloc(nameLength+sizeof(clientchar_t));
7551 memcpy(realPathp, pathp, nameLength+sizeof(clientchar_t));
7552 realPathp[nameLength/sizeof(clientchar_t)] = 0;
7554 spacep = inp->spacep;
7555 /* smb_StripLastComponent will strip "::$DATA" if present */
7556 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
7558 osi_Log1(smb_logp,"NTCreateX for [%S]",osi_LogSaveClientString(smb_logp,realPathp));
7559 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
7560 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%S]", shareAccess, flags, osi_LogSaveClientString(smb_logp,(lastNamep?lastNamep:_C("null"))));
7564 baseDirp = cm_RootSCachep(cm_rootUserp, &req);
7565 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7566 if (code == CM_ERROR_TIDIPC) {
7567 /* Attempt to use a TID allocated for IPC. The client
7568 * is probably looking for DCE RPC end points which we
7569 * don't support OR it could be looking to make a DFS
7572 osi_Log0(smb_logp, "NTCreateX received IPC TID");
7577 osi_Log1(smb_logp, "NTCreateX tidPathp=[%S]", (tidPathp==NULL)?_C("null"): osi_LogSaveClientString(smb_logp,tidPathp));
7581 ((is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)) ||
7583 /* special case magic file name for receiving IOCTL requests
7584 * (since IOCTL calls themselves aren't getting through).
7586 cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0)) {
7588 unsigned short file_type = 0;
7589 unsigned short device_state = 0;
7591 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7594 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
7595 osi_Log1(smb_logp, "NTCreateX Setting up RPC on fid[%d]", fidp->fid);
7597 osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
7598 smb_ReleaseFID(fidp);
7603 smb_SetupIoctlFid(fidp, spacep);
7604 osi_Log1(smb_logp, "NTCreateX Setting up IOCTL on fid[%d]", fidp->fid);
7607 /* set inp->fid so that later read calls in same msg can find fid */
7608 inp->fid = fidp->fid;
7612 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7613 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7614 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
7616 memset(&ft, 0, sizeof(ft));
7617 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7618 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7619 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7620 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7621 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
7622 sz.HighPart = 0x7fff; sz.LowPart = 0;
7623 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
7624 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
7625 smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++; /* filetype */
7626 smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++; /* dev state */
7627 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
7628 smb_SetSMBDataLength(outp, 0);
7630 /* clean up fid reference */
7631 smb_ReleaseFID(fidp);
7638 osi_Log0(smb_logp, "NTCreateX rejecting IPC TID");
7640 return CM_ERROR_BADFD;
7644 if (!cm_IsValidClientString(realPathp)) {
7646 clientchar_t * hexp;
7648 hexp = cm_GetRawCharsAlloc(realPathp, -1);
7649 osi_Log1(smb_logp, "NTCreateX rejecting invalid name. [%S]",
7650 osi_LogSaveClientString(smb_logp, hexp));
7654 osi_Log0(smb_logp, "NTCreateX rejecting invalid name");
7657 return CM_ERROR_BADNTFILENAME;
7660 userp = smb_GetUserFromVCP(vcp, inp);
7662 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
7664 return CM_ERROR_INVAL;
7667 if (baseFidp != 0) {
7668 baseFidp = smb_FindFID(vcp, baseFid, 0);
7670 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
7671 cm_ReleaseUser(userp);
7673 return CM_ERROR_INVAL;
7676 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7678 smb_CloseFID(vcp, baseFidp, NULL, 0);
7679 smb_ReleaseFID(baseFidp);
7680 cm_ReleaseUser(userp);
7681 return CM_ERROR_NOSUCHPATH;
7684 baseDirp = baseFidp->scp;
7688 /* compute open mode */
7690 if (desiredAccess & DELETE)
7691 fidflags |= SMB_FID_OPENDELETE;
7692 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
7693 fidflags |= SMB_FID_OPENREAD_LISTDIR;
7694 if (desiredAccess & AFS_ACCESS_WRITE)
7695 fidflags |= SMB_FID_OPENWRITE;
7696 if (createOptions & FILE_DELETE_ON_CLOSE)
7697 fidflags |= SMB_FID_DELONCLOSE;
7698 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7699 fidflags |= SMB_FID_SEQUENTIAL;
7700 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7701 fidflags |= SMB_FID_RANDOM;
7702 if (createOptions & FILE_OPEN_REPARSE_POINT)
7703 osi_Log0(smb_logp, "NTCreateX Open Reparse Point");
7704 if (smb_IsExecutableFileName(lastNamep))
7705 fidflags |= SMB_FID_EXECUTABLE;
7707 /* and the share mode */
7708 if (shareAccess & FILE_SHARE_READ)
7709 fidflags |= SMB_FID_SHARE_READ;
7710 if (shareAccess & FILE_SHARE_WRITE)
7711 fidflags |= SMB_FID_SHARE_WRITE;
7713 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
7716 /* For an exclusive create, we want to do a case sensitive match for the last component. */
7717 if ( createDisp == FILE_CREATE ||
7718 createDisp == FILE_OVERWRITE ||
7719 createDisp == FILE_OVERWRITE_IF) {
7720 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7721 userp, tidPathp, &req, &dscp);
7724 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7725 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7727 cm_ReleaseSCache(dscp);
7728 cm_ReleaseUser(userp);
7731 smb_ReleaseFID(baseFidp);
7732 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7733 return CM_ERROR_PATH_NOT_COVERED;
7735 return CM_ERROR_NOSUCHPATH;
7737 #endif /* DFS_SUPPORT */
7738 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7740 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7741 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7742 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7743 if (code == 0 && realDirFlag == 1) {
7744 cm_ReleaseSCache(scp);
7745 cm_ReleaseSCache(dscp);
7746 cm_ReleaseUser(userp);
7749 smb_ReleaseFID(baseFidp);
7750 return CM_ERROR_EXISTS;
7753 /* we have both scp and dscp */
7756 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7757 userp, tidPathp, &req, &scp);
7759 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7760 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7761 cm_ReleaseSCache(scp);
7762 cm_ReleaseUser(userp);
7765 smb_ReleaseFID(baseFidp);
7766 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7767 return CM_ERROR_PATH_NOT_COVERED;
7769 return CM_ERROR_NOSUCHPATH;
7771 #endif /* DFS_SUPPORT */
7772 /* we might have scp but not dscp */
7776 code != CM_ERROR_NOSUCHFILE &&
7777 code != CM_ERROR_NOSUCHPATH &&
7778 code != CM_ERROR_BPLUS_NOMATCH) {
7779 cm_ReleaseUser(userp);
7782 smb_ReleaseFID(baseFidp);
7789 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7790 /* look up parent directory */
7791 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
7792 * the immediate parent. We have to work our way up realPathp until we hit something that we
7796 /* we might or might not have scp */
7802 code = cm_NameI(baseDirp, spacep->wdata,
7803 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7804 userp, tidPathp, &req, &dscp);
7807 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7808 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7811 cm_ReleaseSCache(scp);
7812 cm_ReleaseSCache(dscp);
7813 cm_ReleaseUser(userp);
7816 smb_ReleaseFID(baseFidp);
7817 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7818 return CM_ERROR_PATH_NOT_COVERED;
7820 return CM_ERROR_NOSUCHPATH;
7822 #endif /* DFS_SUPPORT */
7825 (code == CM_ERROR_NOSUCHFILE ||
7826 code == CM_ERROR_NOSUCHPATH ||
7827 code == CM_ERROR_BPLUS_NOMATCH) &&
7828 (tp = cm_ClientStrRChr(spacep->wdata, '\\')) &&
7829 (createDisp == FILE_CREATE) &&
7830 (realDirFlag == 1)) {
7833 treeStartp = realPathp + (tp - spacep->wdata);
7835 if (*tp && !smb_IsLegalFilename(tp)) {
7836 cm_ReleaseUser(userp);
7838 smb_ReleaseFID(baseFidp);
7841 cm_ReleaseSCache(scp);
7842 return CM_ERROR_BADNTFILENAME;
7846 } while (dscp == NULL && code == 0);
7850 /* we might have scp and we might have dscp */
7853 smb_ReleaseFID(baseFidp);
7856 osi_Log0(smb_logp,"NTCreateX parent not found");
7858 cm_ReleaseSCache(scp);
7860 cm_ReleaseSCache(dscp);
7861 cm_ReleaseUser(userp);
7866 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
7867 /* A file exists where we want a directory. */
7869 cm_ReleaseSCache(scp);
7870 cm_ReleaseSCache(dscp);
7871 cm_ReleaseUser(userp);
7873 return CM_ERROR_EXISTS;
7877 lastNamep = realPathp;
7881 if (!smb_IsLegalFilename(lastNamep)) {
7883 cm_ReleaseSCache(scp);
7885 cm_ReleaseSCache(dscp);
7886 cm_ReleaseUser(userp);
7888 return CM_ERROR_BADNTFILENAME;
7891 if (!foundscp && !treeCreate) {
7892 if ( createDisp == FILE_CREATE ||
7893 createDisp == FILE_OVERWRITE ||
7894 createDisp == FILE_OVERWRITE_IF)
7896 code = cm_Lookup(dscp, lastNamep,
7897 CM_FLAG_FOLLOW, userp, &req, &scp);
7899 code = cm_Lookup(dscp, lastNamep,
7900 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7903 if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
7905 cm_ReleaseSCache(dscp);
7906 cm_ReleaseUser(userp);
7911 /* we have scp and dscp */
7913 /* we have scp but not dscp */
7915 smb_ReleaseFID(baseFidp);
7918 /* if we get here, if code is 0, the file exists and is represented by
7919 * scp. Otherwise, we have to create it. The dir may be represented
7920 * by dscp, or we may have found the file directly. If code is non-zero,
7925 * open the file itself
7926 * allocate the fidp early so the smb fid can be used by cm_CheckNTOpen()
7928 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7929 osi_assertx(fidp, "null smb_fid_t");
7931 /* save a reference to the user */
7933 fidp->userp = userp;
7935 if (code == 0 && !treeCreate) {
7936 code = cm_CheckNTOpen(scp, desiredAccess, shareAccess, createDisp, 0, fidp->fid, userp, &req, &ldp);
7938 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7940 cm_ReleaseSCache(dscp);
7942 cm_ReleaseSCache(scp);
7943 cm_ReleaseUser(userp);
7944 smb_CloseFID(vcp, fidp, NULL, 0);
7945 smb_ReleaseFID(fidp);
7949 checkDoneRequired = 1;
7951 if (createDisp == FILE_CREATE) {
7952 /* oops, file shouldn't be there */
7953 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7955 cm_ReleaseSCache(dscp);
7957 cm_ReleaseSCache(scp);
7958 cm_ReleaseUser(userp);
7959 smb_CloseFID(vcp, fidp, NULL, 0);
7960 smb_ReleaseFID(fidp);
7962 return CM_ERROR_EXISTS;
7965 if ( createDisp == FILE_OVERWRITE ||
7966 createDisp == FILE_OVERWRITE_IF) {
7968 setAttr.mask = CM_ATTRMASK_LENGTH;
7969 setAttr.length.LowPart = 0;
7970 setAttr.length.HighPart = 0;
7971 /* now watch for a symlink */
7973 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7975 osi_assertx(dscp != NULL, "null cm_scache_t");
7976 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7978 /* we have a more accurate file to use (the
7979 * target of the symbolic link). Otherwise,
7980 * we'll just use the symlink anyway.
7982 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7984 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7985 cm_ReleaseSCache(scp);
7987 code = cm_CheckNTOpen(scp, desiredAccess, shareAccess, createDisp, 0, fidp->fid, userp, &req, &ldp);
7989 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7991 cm_ReleaseSCache(dscp);
7993 cm_ReleaseSCache(scp);
7994 cm_ReleaseUser(userp);
7995 smb_CloseFID(vcp, fidp, NULL, 0);
7996 smb_ReleaseFID(fidp);
8002 code = cm_SetAttr(scp, &setAttr, userp, &req);
8003 openAction = 3; /* truncated existing file */
8006 openAction = 1; /* found existing file */
8008 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
8009 /* don't create if not found */
8011 cm_ReleaseSCache(dscp);
8013 cm_ReleaseSCache(scp);
8014 cm_ReleaseUser(userp);
8015 smb_CloseFID(vcp, fidp, NULL, 0);
8016 smb_ReleaseFID(fidp);
8018 return CM_ERROR_NOSUCHFILE;
8019 } else if (realDirFlag == 0 || realDirFlag == -1) {
8020 osi_assertx(dscp != NULL, "null cm_scache_t");
8021 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %S",
8022 osi_LogSaveClientString(smb_logp, lastNamep));
8023 openAction = 2; /* created file */
8024 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8025 setAttr.clientModTime = time(NULL);
8026 smb_SetInitialModeBitsForFile(extAttributes, &setAttr);
8028 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
8031 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8032 smb_NotifyChange(FILE_ACTION_ADDED,
8033 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8034 dscp, lastNamep, NULL, TRUE);
8035 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
8036 /* Not an exclusive create, and someone else tried
8037 * creating it already, then we open it anyway. We
8038 * don't bother retrying after this, since if this next
8039 * fails, that means that the file was deleted after we
8040 * started this call.
8042 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8045 if (createDisp == FILE_OVERWRITE_IF) {
8046 setAttr.mask = CM_ATTRMASK_LENGTH;
8047 setAttr.length.LowPart = 0;
8048 setAttr.length.HighPart = 0;
8050 /* now watch for a symlink */
8052 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8054 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8056 /* we have a more accurate file to use (the
8057 * target of the symbolic link). Otherwise,
8058 * we'll just use the symlink anyway.
8060 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8062 cm_ReleaseSCache(scp);
8066 code = cm_SetAttr(scp, &setAttr, userp, &req);
8068 } /* lookup succeeded */
8071 clientchar_t *tp, *pp;
8072 clientchar_t *cp; /* This component */
8073 int clen = 0; /* length of component */
8074 cm_scache_t *tscp1, *tscp2;
8077 /* create directory */
8079 treeStartp = lastNamep;
8080 osi_assertx(dscp != NULL, "null cm_scache_t");
8081 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%S]",
8082 osi_LogSaveClientString(smb_logp, treeStartp));
8083 openAction = 2; /* created directory */
8085 /* if the request is to create the root directory
8086 * it will appear as a directory name of the nul-string
8087 * and a code of CM_ERROR_NOSUCHFILE
8089 if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
8090 code = CM_ERROR_EXISTS;
8092 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8093 setAttr.clientModTime = time(NULL);
8094 smb_SetInitialModeBitsForDir(extAttributes, &setAttr);
8099 cm_HoldSCache(tscp1);
8103 tp = cm_ClientStrChr(pp, '\\');
8105 cm_ClientStrCpy(cp, lengthof(spacep->wdata) - (cp - spacep->wdata), pp);
8106 clen = (int)cm_ClientStrLen(cp);
8107 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
8109 clen = (int)(tp - pp);
8110 cm_ClientStrCpyN(cp, lengthof(spacep->wdata) - (cp - spacep->wdata),
8118 continue; /* the supplied path can't have consecutive slashes either , but */
8120 /* cp is the next component to be created. */
8121 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req, NULL);
8122 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
8123 smb_NotifyChange(FILE_ACTION_ADDED,
8124 FILE_NOTIFY_CHANGE_DIR_NAME,
8125 tscp1, cp, NULL, TRUE);
8127 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
8128 /* Not an exclusive create, and someone else tried
8129 * creating it already, then we open it anyway. We
8130 * don't bother retrying after this, since if this next
8131 * fails, that means that the file was deleted after we
8132 * started this call.
8134 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
8135 userp, &req, &tscp2);
8140 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
8141 cm_ReleaseSCache(tscp1);
8142 tscp1 = tscp2; /* Newly created directory will be next parent */
8143 /* the hold is transfered to tscp1 from tscp2 */
8148 cm_ReleaseSCache(dscp);
8151 cm_ReleaseSCache(scp);
8154 * if we get here and code == 0, then scp is the last directory created, and dscp is the
8160 /* something went wrong creating or truncating the file */
8161 if (checkDoneRequired)
8162 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8164 cm_ReleaseSCache(scp);
8166 cm_ReleaseSCache(dscp);
8167 cm_ReleaseUser(userp);
8168 smb_CloseFID(vcp, fidp, NULL, 0);
8169 smb_ReleaseFID(fidp);
8174 /* make sure we have file vs. dir right (only applies for single component case) */
8175 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
8176 /* now watch for a symlink */
8178 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8179 cm_scache_t * targetScp = 0;
8180 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8182 /* we have a more accurate file to use (the
8183 * target of the symbolic link). Otherwise,
8184 * we'll just use the symlink anyway.
8186 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
8187 if (checkDoneRequired) {
8188 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8189 checkDoneRequired = 0;
8191 cm_ReleaseSCache(scp);
8196 if (scp->fileType != CM_SCACHETYPE_FILE) {
8197 if (checkDoneRequired)
8198 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8200 cm_ReleaseSCache(dscp);
8201 cm_ReleaseSCache(scp);
8202 cm_ReleaseUser(userp);
8203 smb_CloseFID(vcp, fidp, NULL, 0);
8204 smb_ReleaseFID(fidp);
8206 return CM_ERROR_ISDIR;
8210 /* (only applies to single component case) */
8211 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8212 if (checkDoneRequired)
8213 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8214 cm_ReleaseSCache(scp);
8216 cm_ReleaseSCache(dscp);
8217 cm_ReleaseUser(userp);
8218 smb_CloseFID(vcp, fidp, NULL, 0);
8219 smb_ReleaseFID(fidp);
8221 return CM_ERROR_NOTDIR;
8224 /* If we are restricting sharing, we should do so with a suitable
8226 if (scp->fileType == CM_SCACHETYPE_FILE &&
8227 !(fidflags & SMB_FID_SHARE_WRITE)) {
8229 LARGE_INTEGER LOffset, LLength;
8232 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8233 LOffset.LowPart = SMB_FID_QLOCK_LOW;
8234 LLength.HighPart = 0;
8235 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8237 /* If we are not opening the file for writing, then we don't
8238 try to get an exclusive lock. No one else should be able to
8239 get an exclusive lock on the file anyway, although someone
8240 else can get a shared lock. */
8241 if ((fidflags & SMB_FID_SHARE_READ) ||
8242 !(fidflags & SMB_FID_OPENWRITE)) {
8243 sLockType = LOCKING_ANDX_SHARED_LOCK;
8248 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8250 lock_ObtainWrite(&scp->rw);
8251 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8252 lock_ReleaseWrite(&scp->rw);
8255 if (checkDoneRequired)
8256 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8257 cm_ReleaseSCache(scp);
8259 cm_ReleaseSCache(dscp);
8260 cm_ReleaseUser(userp);
8261 smb_CloseFID(vcp, fidp, NULL, 0);
8262 smb_ReleaseFID(fidp);
8264 return CM_ERROR_SHARING_VIOLATION;
8268 /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
8269 if (checkDoneRequired) {
8270 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8271 checkDoneRequired = 0;
8274 lock_ObtainMutex(&fidp->mx);
8275 /* save a pointer to the vnode */
8276 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
8277 lock_ObtainWrite(&scp->rw);
8278 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8279 lock_ReleaseWrite(&scp->rw);
8280 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
8282 fidp->flags = fidflags;
8284 /* remember if the file was newly created */
8286 fidp->flags |= SMB_FID_CREATED;
8288 /* save parent dir and pathname for delete or change notification */
8289 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8290 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
8291 fidp->flags |= SMB_FID_NTOPEN;
8292 fidp->NTopen_dscp = dscp;
8294 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
8296 fidp->NTopen_wholepathp = realPathp;
8297 lock_ReleaseMutex(&fidp->mx);
8299 /* we don't need this any longer */
8301 cm_ReleaseSCache(dscp);
8305 cm_Open(scp, 0, userp);
8307 /* set inp->fid so that later read calls in same msg can find fid */
8308 inp->fid = fidp->fid;
8310 lock_ObtainRead(&scp->rw);
8313 * Always send the standard response. Sending the extended
8314 * response results in the Explorer Shell being unable to
8315 * access directories at random times.
8317 if (1 /*!extendedRespRequired */) {
8320 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
8321 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
8322 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
8323 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8324 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8325 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8326 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8327 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8328 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
8330 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8331 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8332 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
8333 smb_SetSMBParm(outp, parmSlot, NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS);
8334 parmSlot++; /* dev state */
8335 smb_SetSMBParmByte(outp, parmSlot,
8336 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8337 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8338 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
8339 smb_SetSMBDataLength(outp, 0);
8343 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
8344 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
8345 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
8346 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8347 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8348 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8349 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8350 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8351 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
8353 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8354 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8355 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
8356 smb_SetSMBParm(outp, parmSlot, NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS);
8357 parmSlot++; /* dev state */
8358 smb_SetSMBParmByte(outp, parmSlot,
8359 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8360 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8361 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
8362 /* Setting the GUID results in a failure with cygwin */
8363 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8364 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8365 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8366 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8367 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8368 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8369 /* Maxmimal access rights */
8370 smb_SetSMBParmLong(outp, parmSlot, 0x001f01ff); parmSlot += 2;
8371 /* Guest access rights */
8372 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8373 smb_SetSMBDataLength(outp, 0);
8376 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
8377 LargeIntegerGreaterThanZero(scp->length) &&
8378 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
8381 lock_ReleaseRead(&scp->rw);
8384 cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
8385 scp->length.LowPart, scp->length.HighPart,
8389 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %S", fidp->fid,
8390 osi_LogSaveClientString(smb_logp, realPathp));
8392 cm_ReleaseUser(userp);
8393 smb_ReleaseFID(fidp);
8395 /* Can't free realPathp if we get here since
8396 fidp->NTopen_wholepathp is pointing there */
8398 /* leave scp held since we put it in fidp->scp */
8403 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
8404 * Instead, ultimately, would like to use a subroutine for common code.
8407 /* NT_TRANSACT_CREATE (SMB_COM_NT_TRANSACT) */
8408 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8410 clientchar_t *pathp, *realPathp;
8414 cm_scache_t *dscp; /* parent dir */
8415 cm_scache_t *scp; /* file to create or open */
8416 cm_scache_t *targetScp; /* if scp is a symlink */
8418 clientchar_t *lastNamep;
8419 unsigned long nameLength;
8421 unsigned int requestOpLock;
8422 unsigned int requestBatchOpLock;
8423 unsigned int mustBeDir;
8424 unsigned int extendedRespRequired;
8426 unsigned int desiredAccess;
8427 unsigned int allocSize;
8428 unsigned int shareAccess;
8429 unsigned int extAttributes;
8430 unsigned int createDisp;
8433 unsigned int impLevel;
8434 unsigned int secFlags;
8435 unsigned int createOptions;
8436 unsigned short baseFid;
8437 smb_fid_t *baseFidp;
8439 cm_scache_t *baseDirp;
8440 unsigned short openAction;
8444 clientchar_t *tidPathp;
8446 int parmOffset, dataOffset;
8453 cm_lock_data_t *ldp = NULL;
8454 int checkDoneRequired = 0;
8461 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8462 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8463 parmp = inp->data + parmOffset;
8464 lparmp = (ULONG *) parmp;
8467 requestOpLock = flags & REQUEST_OPLOCK;
8468 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
8469 mustBeDir = flags & OPEN_DIRECTORY;
8470 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
8473 * Why all of a sudden 32-bit FID?
8474 * We will reject all bits higher than 16.
8476 if (lparmp[1] & 0xFFFF0000)
8477 return CM_ERROR_INVAL;
8478 baseFid = (unsigned short)lparmp[1];
8479 desiredAccess = lparmp[2];
8480 allocSize = lparmp[3];
8481 extAttributes = lparmp[5];
8482 shareAccess = lparmp[6];
8483 createDisp = lparmp[7];
8484 createOptions = lparmp[8];
8487 nameLength = lparmp[11]; /* spec says chars but appears to be bytes */
8488 impLevel = lparmp[12];
8489 secFlags = lparmp[13];
8491 /* mustBeDir is never set; createOptions directory bit seems to be
8494 if (createOptions & FILE_DIRECTORY_FILE)
8496 else if (createOptions & FILE_NON_DIRECTORY_FILE)
8501 pathp = smb_ParseStringCb(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
8502 nameLength, NULL, SMB_STRF_ANSIPATH);
8503 /* Sometimes path is not nul-terminated, so we make a copy. */
8504 realPathp = malloc(nameLength+sizeof(clientchar_t));
8505 memcpy(realPathp, pathp, nameLength);
8506 realPathp[nameLength/sizeof(clientchar_t)] = 0;
8507 spacep = cm_GetSpace();
8508 /* smb_StripLastComponent will strip "::$DATA" if present */
8509 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
8511 osi_Log1(smb_logp,"NTTranCreate %S",osi_LogSaveStringW(smb_logp,realPathp));
8512 osi_Log4(smb_logp,"... da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
8513 osi_Log4(smb_logp,"... co[%x],sdl[%x],eal[%x],as[%x],flags[%x]",createOptions,sdLen,eaLen,allocSize);
8514 osi_Log3(smb_logp,"... imp[%x],sec[%x],flags[%x]", impLevel, secFlags, flags);
8516 if ( realDirFlag == 1 &&
8517 ( createDisp == FILE_SUPERSEDE ||
8518 createDisp == FILE_OVERWRITE ||
8519 createDisp == FILE_OVERWRITE_IF))
8521 osi_Log0(smb_logp, "NTTranCreate rejecting invalid readDirFlag and createDisp combination");
8522 cm_FreeSpace(spacep);
8524 return CM_ERROR_INVAL;
8528 * Nothing here to handle SMB_IOCTL_FILENAME.
8529 * Will add it if necessary.
8532 if (!cm_IsValidClientString(realPathp)) {
8534 clientchar_t * hexp;
8536 hexp = cm_GetRawCharsAlloc(realPathp, -1);
8537 osi_Log1(smb_logp, "NTTranCreate rejecting invalid name. [%S]",
8538 osi_LogSaveClientString(smb_logp, hexp));
8542 osi_Log0(smb_logp, "NTTranCreate rejecting invalid name.");
8544 cm_FreeSpace(spacep);
8546 return CM_ERROR_BADNTFILENAME;
8549 userp = smb_GetUserFromVCP(vcp, inp);
8551 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
8552 cm_FreeSpace(spacep);
8554 return CM_ERROR_INVAL;
8559 baseDirp = cm_RootSCachep(cm_rootUserp, &req);
8560 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8561 if (code == CM_ERROR_TIDIPC) {
8562 /* Attempt to use a TID allocated for IPC. The client
8563 * is probably looking for DCE RPC end points which we
8564 * don't support OR it could be looking to make a DFS
8567 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
8569 cm_FreeSpace(spacep);
8571 cm_ReleaseUser(userp);
8572 return CM_ERROR_NOSUCHPATH;
8576 baseFidp = smb_FindFID(vcp, baseFid, 0);
8578 osi_Log2(smb_logp, "NTTranCreate Unknown SMB Fid vcp 0x%p fid %d",
8580 cm_FreeSpace(spacep);
8582 cm_ReleaseUser(userp);
8583 return CM_ERROR_BADFD;
8586 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8587 cm_FreeSpace(spacep);
8589 cm_ReleaseUser(userp);
8590 smb_CloseFID(vcp, baseFidp, NULL, 0);
8591 smb_ReleaseFID(baseFidp);
8592 return CM_ERROR_NOSUCHPATH;
8595 baseDirp = baseFidp->scp;
8599 /* compute open mode */
8601 if (desiredAccess & DELETE)
8602 fidflags |= SMB_FID_OPENDELETE;
8603 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
8604 fidflags |= SMB_FID_OPENREAD_LISTDIR;
8605 if (desiredAccess & AFS_ACCESS_WRITE)
8606 fidflags |= SMB_FID_OPENWRITE;
8607 if (createOptions & FILE_DELETE_ON_CLOSE)
8608 fidflags |= SMB_FID_DELONCLOSE;
8609 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
8610 fidflags |= SMB_FID_SEQUENTIAL;
8611 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
8612 fidflags |= SMB_FID_RANDOM;
8613 if (createOptions & FILE_OPEN_REPARSE_POINT)
8614 osi_Log0(smb_logp, "NTTranCreate Open Reparse Point");
8615 if (smb_IsExecutableFileName(lastNamep))
8616 fidflags |= SMB_FID_EXECUTABLE;
8618 /* And the share mode */
8619 if (shareAccess & FILE_SHARE_READ)
8620 fidflags |= SMB_FID_SHARE_READ;
8621 if (shareAccess & FILE_SHARE_WRITE)
8622 fidflags |= SMB_FID_SHARE_WRITE;
8627 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8628 userp, tidPathp, &req, &dscp);
8631 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8632 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8633 cm_ReleaseSCache(dscp);
8634 cm_ReleaseUser(userp);
8635 cm_FreeSpace(spacep);
8638 smb_ReleaseFID(baseFidp);
8639 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8640 return CM_ERROR_PATH_NOT_COVERED;
8642 return CM_ERROR_NOSUCHPATH;
8644 #endif /* DFS_SUPPORT */
8645 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
8647 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
8649 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
8650 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
8651 if (code == 0 && realDirFlag == 1 &&
8652 (createDisp == FILE_OPEN ||
8653 createDisp == FILE_OVERWRITE ||
8654 createDisp == FILE_OVERWRITE_IF)) {
8655 cm_ReleaseSCache(scp);
8656 cm_ReleaseSCache(dscp);
8657 cm_ReleaseUser(userp);
8658 cm_FreeSpace(spacep);
8661 smb_ReleaseFID(baseFidp);
8662 return CM_ERROR_EXISTS;
8666 cm_ReleaseUser(userp);
8668 smb_ReleaseFID(baseFidp);
8669 cm_FreeSpace(spacep);
8671 return CM_ERROR_NOSUCHPATH;
8677 if (code == CM_ERROR_NOSUCHFILE ||
8678 code == CM_ERROR_NOSUCHPATH ||
8679 code == CM_ERROR_BPLUS_NOMATCH ||
8680 (code == 0 && (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)))) {
8683 cm_FreeSpace(spacep);
8686 smb_ReleaseFID(baseFidp);
8689 cm_ReleaseSCache(dscp);
8690 cm_ReleaseUser(userp);
8696 lastNamep = realPathp;
8700 if (!smb_IsLegalFilename(lastNamep)) {
8701 cm_ReleaseSCache(dscp);
8702 cm_ReleaseUser(userp);
8704 return CM_ERROR_BADNTFILENAME;
8708 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF || createDisp == FILE_OPEN_IF) {
8709 code = cm_Lookup(dscp, lastNamep,
8710 CM_FLAG_FOLLOW, userp, &req, &scp);
8712 code = cm_Lookup(dscp, lastNamep,
8713 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8716 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8717 cm_ReleaseSCache(dscp);
8718 cm_ReleaseUser(userp);
8725 smb_ReleaseFID(baseFidp);
8726 cm_FreeSpace(spacep);
8729 /* if we get here, if code is 0, the file exists and is represented by
8730 * scp. Otherwise, we have to create it. The dir may be represented
8731 * by dscp, or we may have found the file directly. If code is non-zero,
8735 code = cm_CheckNTOpen(scp, desiredAccess, shareAccess, createDisp, 0, fidp->fid, userp, &req, &ldp);
8737 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8738 cm_ReleaseSCache(dscp);
8739 cm_ReleaseSCache(scp);
8740 cm_ReleaseUser(userp);
8744 checkDoneRequired = 1;
8746 if (createDisp == FILE_CREATE) {
8747 /* oops, file shouldn't be there */
8748 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8749 cm_ReleaseSCache(dscp);
8750 cm_ReleaseSCache(scp);
8751 cm_ReleaseUser(userp);
8753 return CM_ERROR_EXISTS;
8756 if (createDisp == FILE_OVERWRITE ||
8757 createDisp == FILE_OVERWRITE_IF) {
8758 setAttr.mask = CM_ATTRMASK_LENGTH;
8759 setAttr.length.LowPart = 0;
8760 setAttr.length.HighPart = 0;
8762 /* now watch for a symlink */
8764 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8766 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8768 /* we have a more accurate file to use (the
8769 * target of the symbolic link). Otherwise,
8770 * we'll just use the symlink anyway.
8772 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8774 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8775 cm_ReleaseSCache(scp);
8777 code = cm_CheckNTOpen(scp, desiredAccess, shareAccess, createDisp, 0, fidp->fid, userp, &req, &ldp);
8779 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8780 cm_ReleaseSCache(dscp);
8782 cm_ReleaseSCache(scp);
8783 cm_ReleaseUser(userp);
8789 code = cm_SetAttr(scp, &setAttr, userp, &req);
8790 openAction = 3; /* truncated existing file */
8792 else openAction = 1; /* found existing file */
8794 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
8795 /* don't create if not found */
8796 cm_ReleaseSCache(dscp);
8797 cm_ReleaseUser(userp);
8799 return CM_ERROR_NOSUCHFILE;
8801 else if (realDirFlag == 0 || realDirFlag == -1) {
8802 /* createDisp: FILE_SUPERSEDE, FILE_CREATE, FILE_OPEN_IF, FILE_OVERWRITE_IF */
8803 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %S",
8804 osi_LogSaveClientString(smb_logp, lastNamep));
8805 openAction = 2; /* created file */
8806 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8807 setAttr.clientModTime = time(NULL);
8808 smb_SetInitialModeBitsForFile(extAttributes, &setAttr);
8810 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8814 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8815 smb_NotifyChange(FILE_ACTION_ADDED,
8816 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8817 dscp, lastNamep, NULL, TRUE);
8818 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
8819 /* Not an exclusive create, and someone else tried
8820 * creating it already, then we open it anyway. We
8821 * don't bother retrying after this, since if this next
8822 * fails, that means that the file was deleted after we
8823 * started this call.
8825 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8828 if (createDisp == FILE_OVERWRITE_IF) {
8829 setAttr.mask = CM_ATTRMASK_LENGTH;
8830 setAttr.length.LowPart = 0;
8831 setAttr.length.HighPart = 0;
8833 /* now watch for a symlink */
8835 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8837 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8839 /* we have a more accurate file to use (the
8840 * target of the symbolic link). Otherwise,
8841 * we'll just use the symlink anyway.
8843 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8845 cm_ReleaseSCache(scp);
8849 code = cm_SetAttr(scp, &setAttr, userp, &req);
8851 } /* lookup succeeded */
8854 /* create directory; createDisp: FILE_CREATE, FILE_OPEN_IF */
8856 "smb_ReceiveNTTranCreate creating directory %S",
8857 osi_LogSaveClientString(smb_logp, lastNamep));
8858 openAction = 2; /* created directory */
8859 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8860 setAttr.clientModTime = time(NULL);
8861 smb_SetInitialModeBitsForDir(extAttributes, &setAttr);
8863 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8864 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8865 smb_NotifyChange(FILE_ACTION_ADDED,
8866 FILE_NOTIFY_CHANGE_DIR_NAME,
8867 dscp, lastNamep, NULL, TRUE);
8869 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
8870 /* Not an exclusive create, and someone else tried
8871 * creating it already, then we open it anyway. We
8872 * don't bother retrying after this, since if this next
8873 * fails, that means that the file was deleted after we
8874 * started this call.
8876 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8882 /* something went wrong creating or truncating the file */
8883 if (checkDoneRequired)
8884 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8886 cm_ReleaseSCache(scp);
8887 cm_ReleaseUser(userp);
8892 /* make sure we have file vs. dir right */
8893 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
8894 /* now watch for a symlink */
8896 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8898 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8900 /* we have a more accurate file to use (the
8901 * target of the symbolic link). Otherwise,
8902 * we'll just use the symlink anyway.
8904 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8906 if (checkDoneRequired) {
8907 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8908 checkDoneRequired = 0;
8910 cm_ReleaseSCache(scp);
8915 if (scp->fileType != CM_SCACHETYPE_FILE) {
8916 if (checkDoneRequired)
8917 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8918 cm_ReleaseSCache(scp);
8919 cm_ReleaseUser(userp);
8921 return CM_ERROR_ISDIR;
8925 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8926 if (checkDoneRequired)
8927 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8928 cm_ReleaseSCache(scp);
8929 cm_ReleaseUser(userp);
8931 return CM_ERROR_NOTDIR;
8934 /* open the file itself */
8935 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8936 osi_assertx(fidp, "null smb_fid_t");
8938 /* save a reference to the user */
8940 fidp->userp = userp;
8942 /* If we are restricting sharing, we should do so with a suitable
8944 if (scp->fileType == CM_SCACHETYPE_FILE &&
8945 !(fidflags & SMB_FID_SHARE_WRITE)) {
8947 LARGE_INTEGER LOffset, LLength;
8950 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8951 LOffset.LowPart = SMB_FID_QLOCK_LOW;
8952 LLength.HighPart = 0;
8953 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8955 /* Similar to what we do in handling NTCreateX. We get a
8956 shared lock if we are only opening the file for reading. */
8957 if ((fidflags & SMB_FID_SHARE_READ) ||
8958 !(fidflags & SMB_FID_OPENWRITE)) {
8959 sLockType = LOCKING_ANDX_SHARED_LOCK;
8964 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8966 lock_ObtainWrite(&scp->rw);
8967 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8968 lock_ReleaseWrite(&scp->rw);
8971 if (checkDoneRequired)
8972 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8973 cm_ReleaseSCache(scp);
8974 cm_ReleaseUser(userp);
8975 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
8976 smb_CloseFID(vcp, fidp, NULL, 0);
8977 smb_ReleaseFID(fidp);
8979 return CM_ERROR_SHARING_VIOLATION;
8983 /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
8984 if (checkDoneRequired) {
8985 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8986 checkDoneRequired = 0;
8989 lock_ObtainMutex(&fidp->mx);
8990 /* save a pointer to the vnode */
8992 lock_ObtainWrite(&scp->rw);
8993 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8994 lock_ReleaseWrite(&scp->rw);
8995 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
8997 fidp->flags = fidflags;
8999 /* remember if the file was newly created */
9001 fidp->flags |= SMB_FID_CREATED;
9003 /* save parent dir and pathname for deletion or change notification */
9004 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
9005 fidp->flags |= SMB_FID_NTOPEN;
9006 fidp->NTopen_dscp = dscp;
9007 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
9009 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
9011 fidp->NTopen_wholepathp = realPathp;
9012 lock_ReleaseMutex(&fidp->mx);
9014 /* we don't need this any longer */
9016 cm_ReleaseSCache(dscp);
9018 cm_Open(scp, 0, userp);
9020 /* set inp->fid so that later read calls in same msg can find fid */
9021 inp->fid = fidp->fid;
9023 /* check whether we are required to send an extended response */
9024 if (!extendedRespRequired) {
9026 parmOffset = 8*4 + 39;
9027 parmOffset += 1; /* pad to 4 */
9028 dataOffset = parmOffset + 70;
9032 /* Total Parameter Count */
9033 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
9034 /* Total Data Count */
9035 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9036 /* Parameter Count */
9037 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
9038 /* Parameter Offset */
9039 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
9040 /* Parameter Displacement */
9041 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9043 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9045 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
9046 /* Data Displacement */
9047 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9048 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
9049 smb_SetSMBDataLength(outp, 70);
9051 lock_ObtainRead(&scp->rw);
9052 outData = smb_GetSMBData(outp, NULL);
9053 outData++; /* round to get to parmOffset */
9054 *outData = 0; outData++; /* oplock */
9055 *outData = 0; outData++; /* reserved */
9056 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
9057 *((ULONG *)outData) = openAction; outData += 4;
9058 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
9059 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
9060 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
9061 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
9062 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
9063 *((FILETIME *)outData) = ft; outData += 8; /* change time */
9064 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
9065 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
9066 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
9067 *((USHORT *)outData) = 0; outData += 2; /* filetype */
9068 *((USHORT *)outData) = NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS;
9069 outData += 2; /* dev state */
9070 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
9071 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
9072 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
9073 outData += 2; /* is a dir? */
9076 parmOffset = 8*4 + 39;
9077 parmOffset += 1; /* pad to 4 */
9078 dataOffset = parmOffset + 104;
9082 /* Total Parameter Count */
9083 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
9084 /* Total Data Count */
9085 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9086 /* Parameter Count */
9087 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
9088 /* Parameter Offset */
9089 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
9090 /* Parameter Displacement */
9091 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9093 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9095 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
9096 /* Data Displacement */
9097 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9098 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
9099 smb_SetSMBDataLength(outp, 105);
9101 lock_ObtainRead(&scp->rw);
9102 outData = smb_GetSMBData(outp, NULL);
9103 outData++; /* round to get to parmOffset */
9104 *outData = 0; outData++; /* oplock */
9105 *outData = 1; outData++; /* response type */
9106 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
9107 *((ULONG *)outData) = openAction; outData += 4;
9108 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
9109 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
9110 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
9111 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
9112 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
9113 *((FILETIME *)outData) = ft; outData += 8; /* change time */
9114 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
9115 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
9116 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
9117 *((USHORT *)outData) = 0; outData += 2; /* filetype */
9118 *((USHORT *)outData) = NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS;
9119 outData += 2; /* dev state */
9120 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
9121 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
9122 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
9123 outData += 1; /* is a dir? */
9124 /* Setting the GUID results in failures with cygwin */
9125 memset(outData,0,24); outData += 24; /* GUID */
9126 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
9127 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
9130 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
9131 LargeIntegerGreaterThanZero(scp->length) &&
9132 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
9135 lock_ReleaseRead(&scp->rw);
9138 cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
9139 scp->length.LowPart, scp->length.HighPart,
9142 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
9144 cm_ReleaseUser(userp);
9145 smb_ReleaseFID(fidp);
9147 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
9148 /* leave scp held since we put it in fidp->scp */
9152 /* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
9153 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
9156 smb_packet_t *savedPacketp;
9158 USHORT fid, watchtree;
9162 filter = smb_GetSMBParm(inp, 19) |
9163 (smb_GetSMBParm(inp, 20) << 16);
9164 fid = smb_GetSMBParm(inp, 21);
9165 watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
9167 fidp = smb_FindFID(vcp, fid, 0);
9169 osi_Log2(smb_logp, "NotifyChange Unknown SMB Fid vcp 0x%p fid %d",
9171 return CM_ERROR_BADFD;
9174 lock_ObtainMutex(&fidp->mx);
9175 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
9176 lock_ReleaseMutex(&fidp->mx);
9177 smb_CloseFID(vcp, fidp, NULL, 0);
9178 smb_ReleaseFID(fidp);
9179 return CM_ERROR_NOSUCHFILE;
9183 lock_ReleaseMutex(&fidp->mx);
9185 /* Create a copy of the Directory Watch Packet to use when sending the
9186 * notification if in the future a matching change is detected.
9188 savedPacketp = smb_CopyPacket(inp);
9189 if (vcp != savedPacketp->vcp) {
9191 if (savedPacketp->vcp)
9192 smb_ReleaseVC(savedPacketp->vcp);
9193 savedPacketp->vcp = vcp;
9196 /* Add the watch to the list of events to send notifications for */
9197 lock_ObtainMutex(&smb_Dir_Watch_Lock);
9198 savedPacketp->nextp = smb_Directory_Watches;
9199 smb_Directory_Watches = savedPacketp;
9200 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9202 osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%S\"",
9203 fidp, scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp));
9204 osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
9205 filter, fid, watchtree);
9206 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
9207 osi_Log0(smb_logp, " Notify Change File Name");
9208 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
9209 osi_Log0(smb_logp, " Notify Change Directory Name");
9210 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
9211 osi_Log0(smb_logp, " Notify Change Attributes");
9212 if (filter & FILE_NOTIFY_CHANGE_SIZE)
9213 osi_Log0(smb_logp, " Notify Change Size");
9214 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
9215 osi_Log0(smb_logp, " Notify Change Last Write");
9216 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
9217 osi_Log0(smb_logp, " Notify Change Last Access");
9218 if (filter & FILE_NOTIFY_CHANGE_CREATION)
9219 osi_Log0(smb_logp, " Notify Change Creation");
9220 if (filter & FILE_NOTIFY_CHANGE_EA)
9221 osi_Log0(smb_logp, " Notify Change Extended Attributes");
9222 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
9223 osi_Log0(smb_logp, " Notify Change Security");
9224 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
9225 osi_Log0(smb_logp, " Notify Change Stream Name");
9226 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
9227 osi_Log0(smb_logp, " Notify Change Stream Size");
9228 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
9229 osi_Log0(smb_logp, " Notify Change Stream Write");
9231 lock_ObtainWrite(&scp->rw);
9233 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
9235 scp->flags |= CM_SCACHEFLAG_WATCHED;
9236 lock_ReleaseWrite(&scp->rw);
9237 cm_ReleaseSCache(scp);
9238 smb_ReleaseFID(fidp);
9240 outp->flags |= SMB_PACKETFLAG_NOSEND;
9244 unsigned char nullSecurityDesc[] = {
9245 0x01, /* security descriptor revision */
9246 0x00, /* reserved, should be zero */
9247 0x04, 0x80, /* security descriptor control;
9248 * 0x0004 : null-DACL present - everyone has full access
9249 * 0x8000 : relative format */
9250 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
9251 0x20, 0x00, 0x00, 0x00, /* offset of group SID */
9252 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
9253 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
9254 0x01, 0x01, 0x00, 0x00, /* "everyone SID" owner SID */
9255 0x00, 0x00, 0x00, 0x01,
9256 0x00, 0x00, 0x00, 0x00,
9257 0x01, 0x01, 0x00, 0x00, /* "everyone SID" owner SID */
9258 0x00, 0x00, 0x00, 0x01,
9259 0x00, 0x00, 0x00, 0x00
9262 /* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
9263 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9265 int parmOffset, parmCount, dataOffset, dataCount;
9266 int totalParmCount, totalDataCount;
9268 int maxData, maxParm;
9269 int inTotalParm, inTotalData;
9271 int inParmOffset, inDataOffset;
9277 ULONG securityInformation;
9283 * For details on the meanings of the various
9284 * SMB_COM_TRANSACTION fields, see sections 2.2.4.33
9285 * of http://msdn.microsoft.com/en-us/library/ee442092%28PROT.13%29.aspx
9288 inTotalParm = smb_GetSMBOffsetParm(inp, 1, 1)
9289 | (smb_GetSMBOffsetParm(inp, 2, 1) << 16);
9291 inTotalData = smb_GetSMBOffsetParm(inp, 3, 1)
9292 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
9294 maxParm = smb_GetSMBOffsetParm(inp, 5, 1)
9295 | (smb_GetSMBOffsetParm(inp, 6, 1) << 16);
9297 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
9298 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
9300 inParm = smb_GetSMBOffsetParm(inp, 9, 1)
9301 | (smb_GetSMBOffsetParm(inp, 10, 1) << 16);
9303 inParmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
9304 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
9306 inData = smb_GetSMBOffsetParm(inp, 13, 1)
9307 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
9309 inDataOffset = smb_GetSMBOffsetParm(inp, 15, 1)
9310 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
9312 parmp = inp->data + inParmOffset;
9313 sparmp = (USHORT *) parmp;
9314 lparmp = (ULONG *) parmp;
9317 securityInformation = lparmp[1];
9319 fidp = smb_FindFID(vcp, fid, 0);
9321 osi_Log2(smb_logp, "smb_ReceiveNTTranQuerySecurityDesc Unknown SMB Fid vcp 0x%p fid %d",
9323 return CM_ERROR_BADFD;
9326 lock_ObtainMutex(&fidp->mx);
9327 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
9328 lock_ReleaseMutex(&fidp->mx);
9329 smb_CloseFID(vcp, fidp, NULL, 0);
9330 smb_ReleaseFID(fidp);
9331 return CM_ERROR_NOSUCHFILE;
9333 lock_ReleaseMutex(&fidp->mx);
9335 osi_Log4(smb_logp,"smb_ReceiveNTTranQuerySecurityDesc fidp 0x%p scp 0x%p file \"%S\" Info=0x%x",
9336 fidp, fidp->scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp),
9337 securityInformation);
9339 smb_ReleaseFID(fidp);
9341 if ( securityInformation & ~(OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION) )
9343 code = CM_ERROR_BAD_LEVEL;
9347 dwLength = sizeof( nullSecurityDesc);
9349 totalDataCount = dwLength;
9352 if (maxData >= totalDataCount) {
9353 dataCount = totalDataCount;
9354 parmCount = min(totalParmCount, maxParm);
9355 } else if (maxParm >= totalParmCount) {
9356 totalDataCount = dataCount = 0;
9357 parmCount = totalParmCount;
9359 totalDataCount = dataCount = 0;
9360 totalParmCount = parmCount = 0;
9364 parmOffset = 8*4 + 39;
9365 parmOffset += 1; /* pad to 4 */
9367 dataOffset = parmOffset + parmCount;
9371 /* Total Parameter Count */
9372 smb_SetSMBParmLong(outp, parmSlot, totalParmCount); parmSlot += 2;
9373 /* Total Data Count */
9374 smb_SetSMBParmLong(outp, parmSlot, totalDataCount); parmSlot += 2;
9375 /* Parameter Count */
9376 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
9377 /* Parameter Offset */
9378 smb_SetSMBParmLong(outp, parmSlot, parmCount ? parmOffset : 0); parmSlot += 2;
9379 /* Parameter Displacement */
9380 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9382 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
9384 smb_SetSMBParmLong(outp, parmSlot, dataCount ? dataOffset : 0); parmSlot += 2;
9385 /* Data Displacement */
9386 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9388 smb_SetSMBParmByte(outp, parmSlot, 0);
9390 if (parmCount == totalParmCount && dwLength == dataCount) {
9391 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
9394 outData = smb_GetSMBData(outp, NULL);
9395 outData++; /* round to get to dataOffset */
9397 *((ULONG *)outData) = dataCount; outData += 4; /* SD Length (4 bytes) */
9398 memcpy(outData, nullSecurityDesc, dataCount);
9399 outData += dataCount;
9402 } else if (parmCount >= 4) {
9403 smb_SetSMBDataLength(outp, 1 + parmCount);
9406 outData = smb_GetSMBData(outp, NULL);
9407 outData++; /* round to get to dataOffset */
9409 *((ULONG *)outData) = dwLength; outData += 4; /* SD Length (4 bytes) */
9410 code = CM_ERROR_BUFFERTOOSMALL;
9412 smb_SetSMBDataLength(outp, 0);
9413 code = CM_ERROR_BUFFER_OVERFLOW;
9420 /* SMB_COM_NT_TRANSACT
9422 SMB_COM_NT_TRANSACT_SECONDARY should also be handled here.
9424 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9426 unsigned short function;
9428 function = smb_GetSMBParm(inp, 18);
9430 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
9432 /* We can handle long names */
9433 if (vcp->flags & SMB_VCFLAG_USENT)
9434 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
9437 case 1: /* NT_TRANSACT_CREATE */
9438 return smb_ReceiveNTTranCreate(vcp, inp, outp);
9439 case 2: /* NT_TRANSACT_IOCTL */
9440 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
9442 case 3: /* NT_TRANSACT_SET_SECURITY_DESC */
9443 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
9445 case 4: /* NT_TRANSACT_NOTIFY_CHANGE */
9446 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
9447 case 5: /* NT_TRANSACT_RENAME */
9448 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
9450 case 6: /* NT_TRANSACT_QUERY_SECURITY_DESC */
9451 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
9453 osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
9456 osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
9459 return CM_ERROR_BADOP;
9463 * smb_NotifyChange -- find relevant change notification messages and
9466 * If we don't know the file name (i.e. a callback break), filename is
9467 * NULL, and we return a zero-length list.
9469 * At present there is not a single call to smb_NotifyChange that
9470 * has the isDirectParent parameter set to FALSE.
9472 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
9473 cm_scache_t *dscp, clientchar_t *filename, clientchar_t *otherFilename,
9474 BOOL isDirectParent)
9476 smb_packet_t *watch, *lastWatch, *nextWatch;
9477 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen = 0;
9478 char *outData, *oldOutData;
9482 BOOL twoEntries = FALSE;
9483 ULONG otherNameLen, oldParmCount = 0;
9487 /* Get ready for rename within directory */
9488 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
9490 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
9493 osi_Log4(smb_logp,"in smb_NotifyChange for file [%S] dscp [%p] notification 0x%x parent %d",
9494 osi_LogSaveClientString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
9496 osi_Log0(smb_logp," FILE_ACTION_NONE");
9497 if (action == FILE_ACTION_ADDED)
9498 osi_Log0(smb_logp," FILE_ACTION_ADDED");
9499 if (action == FILE_ACTION_REMOVED)
9500 osi_Log0(smb_logp," FILE_ACTION_REMOVED");
9501 if (action == FILE_ACTION_MODIFIED)
9502 osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
9503 if (action == FILE_ACTION_RENAMED_OLD_NAME)
9504 osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
9505 if (action == FILE_ACTION_RENAMED_NEW_NAME)
9506 osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
9508 lock_ObtainMutex(&smb_Dir_Watch_Lock);
9509 watch = smb_Directory_Watches;
9511 filter = smb_GetSMBParm(watch, 19)
9512 | (smb_GetSMBParm(watch, 20) << 16);
9513 fid = smb_GetSMBParm(watch, 21);
9514 wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
9516 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
9517 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
9520 * Strange hack - bug in NT Client and NT Server that we must emulate?
9522 if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
9523 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
9525 fidp = smb_FindFID(watch->vcp, fid, 0);
9527 osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
9529 watch = watch->nextp;
9533 if (fidp->scp != dscp ||
9534 fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
9535 (filter & notifyFilter) == 0 ||
9536 (!isDirectParent && !wtree))
9538 osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
9540 watch = watch->nextp;
9541 smb_ReleaseFID(fidp);
9546 "Sending Change Notification for fid %d filter 0x%x wtree %d file %S",
9547 fid, filter, wtree, osi_LogSaveClientString(smb_logp, filename));
9548 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
9549 osi_Log0(smb_logp, " Notify Change File Name");
9550 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
9551 osi_Log0(smb_logp, " Notify Change Directory Name");
9552 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
9553 osi_Log0(smb_logp, " Notify Change Attributes");
9554 if (filter & FILE_NOTIFY_CHANGE_SIZE)
9555 osi_Log0(smb_logp, " Notify Change Size");
9556 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
9557 osi_Log0(smb_logp, " Notify Change Last Write");
9558 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
9559 osi_Log0(smb_logp, " Notify Change Last Access");
9560 if (filter & FILE_NOTIFY_CHANGE_CREATION)
9561 osi_Log0(smb_logp, " Notify Change Creation");
9562 if (filter & FILE_NOTIFY_CHANGE_EA)
9563 osi_Log0(smb_logp, " Notify Change Extended Attributes");
9564 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
9565 osi_Log0(smb_logp, " Notify Change Security");
9566 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
9567 osi_Log0(smb_logp, " Notify Change Stream Name");
9568 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
9569 osi_Log0(smb_logp, " Notify Change Stream Size");
9570 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
9571 osi_Log0(smb_logp, " Notify Change Stream Write");
9573 /* A watch can only be notified once. Remove it from the list */
9574 nextWatch = watch->nextp;
9575 if (watch == smb_Directory_Watches)
9576 smb_Directory_Watches = nextWatch;
9578 lastWatch->nextp = nextWatch;
9580 /* Turn off WATCHED flag in dscp */
9581 lock_ObtainWrite(&dscp->rw);
9583 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
9585 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
9586 lock_ReleaseWrite(&dscp->rw);
9588 /* Convert to response packet */
9589 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
9590 #ifdef SEND_CANONICAL_PATHNAMES
9591 ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
9593 ((smb_t *) watch)->wct = 0;
9596 if (filename == NULL) {
9599 nameLen = (ULONG)cm_ClientStrLen(filename);
9600 parmCount = 3*4 + nameLen*2;
9601 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
9603 otherNameLen = (ULONG)cm_ClientStrLen(otherFilename);
9604 oldParmCount = parmCount;
9605 parmCount += 3*4 + otherNameLen*2;
9606 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
9608 if (maxLen < parmCount)
9609 parmCount = 0; /* not enough room */
9611 parmOffset = 8*4 + 39;
9612 parmOffset += 1; /* pad to 4 */
9613 dataOffset = parmOffset + parmCount;
9617 /* Total Parameter Count */
9618 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
9619 /* Total Data Count */
9620 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9621 /* Parameter Count */
9622 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
9623 /* Parameter Offset */
9624 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
9625 /* Parameter Displacement */
9626 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9628 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9630 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
9631 /* Data Displacement */
9632 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9633 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
9634 smb_SetSMBDataLength(watch, parmCount + 1);
9636 if (parmCount != 0) {
9637 outData = smb_GetSMBData(watch, NULL);
9638 outData++; /* round to get to parmOffset */
9639 oldOutData = outData;
9640 *((DWORD *)outData) = oldParmCount; outData += 4;
9641 /* Next Entry Offset */
9642 *((DWORD *)outData) = action; outData += 4;
9644 *((DWORD *)outData) = nameLen*2; outData += 4;
9645 /* File Name Length */
9647 smb_UnparseString(watch, outData, filename, NULL, 0);
9651 outData = oldOutData + oldParmCount;
9652 *((DWORD *)outData) = 0; outData += 4;
9653 /* Next Entry Offset */
9654 *((DWORD *)outData) = otherAction; outData += 4;
9656 *((DWORD *)outData) = otherNameLen*2;
9657 outData += 4; /* File Name Length */
9658 smb_UnparseString(watch, outData, otherFilename, NULL, 0);
9663 * If filename is null, we don't know the cause of the
9664 * change notification. We return zero data (see above),
9665 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
9666 * (= 0x010C). We set the error code here by hand, without
9667 * modifying wct and bcc.
9669 if (filename == NULL) {
9670 ((smb_t *) watch)->rcls = 0x0C;
9671 ((smb_t *) watch)->reh = 0x01;
9672 ((smb_t *) watch)->errLow = 0;
9673 ((smb_t *) watch)->errHigh = 0;
9674 /* Set NT Status codes flag */
9675 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9678 smb_SendPacket(watch->vcp, watch);
9679 smb_FreePacket(watch);
9681 smb_ReleaseFID(fidp);
9684 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9687 /* SMB_COM_NT_CANCEL */
9688 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9690 unsigned char *replyWctp;
9691 smb_packet_t *watch, *lastWatch;
9692 USHORT fid, watchtree;
9696 osi_Log0(smb_logp, "SMB3 receive NT cancel");
9698 lock_ObtainMutex(&smb_Dir_Watch_Lock);
9699 watch = smb_Directory_Watches;
9701 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
9702 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
9703 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
9704 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
9705 if (watch == smb_Directory_Watches)
9706 smb_Directory_Watches = watch->nextp;
9708 lastWatch->nextp = watch->nextp;
9709 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9711 /* Turn off WATCHED flag in scp */
9712 fid = smb_GetSMBParm(watch, 21);
9713 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
9715 if (vcp != watch->vcp)
9716 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
9719 fidp = smb_FindFID(vcp, fid, 0);
9721 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %S",
9723 (fidp ? osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp) :_C("")));
9726 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
9728 lock_ObtainWrite(&scp->rw);
9730 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
9732 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
9733 lock_ReleaseWrite(&scp->rw);
9735 smb_ReleaseFID(fidp);
9737 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
9740 /* assume STATUS32; return 0xC0000120 (CANCELED) */
9741 replyWctp = watch->wctp;
9745 ((smb_t *)watch)->rcls = 0x20;
9746 ((smb_t *)watch)->reh = 0x1;
9747 ((smb_t *)watch)->errLow = 0;
9748 ((smb_t *)watch)->errHigh = 0xC0;
9749 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9750 smb_SendPacket(vcp, watch);
9751 smb_FreePacket(watch);
9755 watch = watch->nextp;
9757 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9763 * NT rename also does hard links.
9766 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
9767 #define RENAME_FLAG_HARD_LINK 0x103
9768 #define RENAME_FLAG_RENAME 0x104
9769 #define RENAME_FLAG_COPY 0x105
9771 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9773 clientchar_t *oldPathp, *newPathp;
9779 attrs = smb_GetSMBParm(inp, 0);
9780 rename_type = smb_GetSMBParm(inp, 1);
9782 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
9783 osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
9784 return CM_ERROR_NOACCESS;
9787 tp = smb_GetSMBData(inp, NULL);
9788 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
9790 return CM_ERROR_BADSMB;
9791 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
9793 return CM_ERROR_BADSMB;
9795 osi_Log3(smb_logp, "NTRename for [%S]->[%S] type [%s]",
9796 osi_LogSaveClientString(smb_logp, oldPathp),
9797 osi_LogSaveClientString(smb_logp, newPathp),
9798 ((rename_type==RENAME_FLAG_RENAME)?"rename":(rename_type==RENAME_FLAG_HARD_LINK)?"hardlink":"other"));
9800 if (rename_type == RENAME_FLAG_RENAME) {
9801 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
9802 } else if (rename_type == RENAME_FLAG_HARD_LINK) { /* RENAME_FLAG_HARD_LINK */
9803 code = smb_Link(vcp,inp,oldPathp,newPathp);
9805 code = CM_ERROR_BADOP;
9811 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock", LOCK_HIERARCHY_SMB_DIRWATCH);
9814 cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
9816 smb_username_t *unp;
9819 unp = smb_FindUserByName(usern, machine, flags);
9821 lock_ObtainMutex(&unp->mx);
9822 unp->userp = cm_NewUser();
9823 lock_ReleaseMutex(&unp->mx);
9824 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9826 osi_Log2(smb_logp,"smb_FindCMUserByName Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9830 smb_ReleaseUsername(unp);
9834 cm_user_t *smb_FindCMUserBySID(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
9836 smb_username_t *unp;
9839 unp = smb_FindUserByName(usern, machine, flags);
9841 lock_ObtainMutex(&unp->mx);
9842 unp->flags |= SMB_USERNAMEFLAG_SID;
9843 unp->userp = cm_NewUser();
9844 lock_ReleaseMutex(&unp->mx);
9845 osi_Log2(smb_logp,"smb_FindCMUserBySID New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9847 osi_Log2(smb_logp,"smb_FindCMUserBySID Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9851 smb_ReleaseUsername(unp);