2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
15 #pragma warning(disable: 4005)
17 #define SECURITY_WIN32
30 #include <WINNT\afsreg.h>
36 extern osi_hyper_t hzero;
38 smb_packet_t *smb_Directory_Watches = NULL;
39 osi_mutex_t smb_Dir_Watch_Lock;
41 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
43 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
45 /* protected by the smb_globalLock */
46 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
48 const clientchar_t **smb_ExecutableExtensions = NULL;
50 /* retrieve a held reference to a user structure corresponding to an incoming
52 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
57 uidp = smb_FindUID(vcp, inp->uid, 0);
61 up = smb_GetUserFromUID(uidp);
69 * Return boolean specifying if the path name is thought to be an
70 * executable file. For now .exe or .dll.
72 afs_uint32 smb_IsExecutableFileName(const clientchar_t *name)
76 if ( smb_ExecutableExtensions == NULL || name == NULL)
79 len = (int)cm_ClientStrLen(name);
81 for ( i=0; smb_ExecutableExtensions[i]; i++) {
82 j = len - (int)cm_ClientStrLen(smb_ExecutableExtensions[i]);
83 if (cm_ClientStrCmpI(smb_ExecutableExtensions[i], &name[j]) == 0)
91 * Return extended attributes.
92 * Right now, we aren't using any of the "new" bits, so this looks exactly
93 * like smb_Attributes() (see smb.c).
95 unsigned long smb_ExtAttributes(cm_scache_t *scp)
99 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
100 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
101 scp->fileType == CM_SCACHETYPE_INVALID)
103 attrs = SMB_ATTR_DIRECTORY;
104 #ifdef SPECIAL_FOLDERS
105 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
106 #endif /* SPECIAL_FOLDERS */
107 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
108 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
109 } else if (scp->fid.vnode & 0x1)
110 attrs = SMB_ATTR_DIRECTORY;
115 * We used to mark a file RO if it was in an RO volume, but that
116 * turns out to be impolitic in NT. See defect 10007.
119 if ((scp->unixModeBits & 0200) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
120 attrs |= SMB_ATTR_READONLY; /* Read-only */
122 if ((scp->unixModeBits & 0200) == 0)
123 attrs |= SMB_ATTR_READONLY; /* Read-only */
127 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
132 int smb_V3IsStarMask(clientchar_t *maskp)
136 while (tc = *maskp++)
137 if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
142 void OutputDebugF(clientchar_t * format, ...) {
144 clientchar_t vbuffer[1024];
146 va_start( args, format );
147 cm_ClientStrPrintfV(vbuffer, lengthof(vbuffer), format, args);
148 osi_Log1(smb_logp, "%S", osi_LogSaveClientString(smb_logp, vbuffer));
151 void OutputDebugHexDump(unsigned char * buffer, int len) {
154 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
156 OutputDebugF(_C("Hexdump length [%d]"),len);
158 for (i=0;i<len;i++) {
161 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
163 StringCchPrintfA(buf, lengthof(buf), "%5x", i);
164 memset(buf+5,' ',80);
169 j = j*3 + 7 + ((j>7)?1:0);
172 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
175 j = j + 56 + ((j>7)?1:0);
177 buf[j] = (k>32 && k<127)?k:'.';
180 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
184 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
186 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
187 SECURITY_STATUS status, istatus;
188 CredHandle creds = {0,0};
190 SecBufferDesc secOut;
198 OutputDebugF(_C("Negotiating Extended Security"));
200 status = AcquireCredentialsHandle( NULL,
201 SMB_EXT_SEC_PACKAGE_NAME,
210 if (status != SEC_E_OK) {
211 /* Really bad. We return an empty security blob */
212 OutputDebugF(_C("AcquireCredentialsHandle failed with %lX"), status);
217 secOut.pBuffers = &secTok;
218 secOut.ulVersion = SECBUFFER_VERSION;
220 secTok.BufferType = SECBUFFER_TOKEN;
222 secTok.pvBuffer = NULL;
224 ctx.dwLower = ctx.dwUpper = 0;
226 status = AcceptSecurityContext( &creds,
229 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
230 SECURITY_NETWORK_DREP,
237 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
238 OutputDebugF(_C("Completing token..."));
239 istatus = CompleteAuthToken(&ctx, &secOut);
240 if ( istatus != SEC_E_OK )
241 OutputDebugF(_C("Token completion failed: %x"), istatus);
244 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
245 if (secTok.pvBuffer) {
246 *secBlobLength = secTok.cbBuffer;
247 *secBlob = malloc( secTok.cbBuffer );
248 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
251 if ( status != SEC_E_OK )
252 OutputDebugF(_C("AcceptSecurityContext status != CONTINUE %lX"), status);
255 /* Discard partial security context */
256 DeleteSecurityContext(&ctx);
258 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
260 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
261 FreeCredentialsHandle(&creds);
268 smb_GetLogonSID(HANDLE hToken, PSID *ppsid)
270 BOOL bSuccess = FALSE;
273 PTOKEN_GROUPS ptg = NULL;
275 // Verify the parameter passed in is not NULL.
279 // Get required buffer size and allocate the TOKEN_GROUPS buffer.
281 if (!GetTokenInformation( hToken, // handle to the access token
282 TokenGroups, // get information about the token's groups
283 (LPVOID) ptg, // pointer to TOKEN_GROUPS buffer
285 &dwLength // receives required buffer size
288 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
291 ptg = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(),
292 HEAP_ZERO_MEMORY, dwLength);
298 // Get the token group information from the access token.
300 if (!GetTokenInformation( hToken, // handle to the access token
301 TokenGroups, // get information about the token's groups
302 (LPVOID) ptg, // pointer to TOKEN_GROUPS buffer
303 dwLength, // size of buffer
304 &dwLength // receives required buffer size
310 // Loop through the groups to find the logon SID.
311 for (dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++) {
312 if ((ptg->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID)
314 // Found the logon SID; make a copy of it.
316 dwLength = GetLengthSid(ptg->Groups[dwIndex].Sid);
317 *ppsid = (PSID) HeapAlloc(GetProcessHeap(),
318 HEAP_ZERO_MEMORY, dwLength);
321 if (!CopySid(dwLength, *ppsid, ptg->Groups[dwIndex].Sid))
323 HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
333 // Free the buffer for the token groups.
335 HeapFree(GetProcessHeap(), 0, (LPVOID)ptg);
341 smb_GetUserSID(HANDLE hToken, PSID *ppsid)
343 BOOL bSuccess = FALSE;
345 PTOKEN_USER ptu = NULL;
347 // Verify the parameter passed in is not NULL.
351 // Get required buffer size and allocate the TOKEN_USER buffer.
353 if (!GetTokenInformation( hToken, // handle to the access token
354 TokenUser, // get information about the token's user
355 (LPVOID) ptu, // pointer to TOKEN_USER buffer
357 &dwLength // receives required buffer size
360 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
363 ptu = (PTOKEN_USER)HeapAlloc(GetProcessHeap(),
364 HEAP_ZERO_MEMORY, dwLength);
370 // Get the token group information from the access token.
372 if (!GetTokenInformation( hToken, // handle to the access token
373 TokenUser, // get information about the token's user
374 (LPVOID) ptu, // pointer to TOKEN_USER buffer
375 dwLength, // size of buffer
376 &dwLength // receives required buffer size
382 // Found the user SID; make a copy of it.
383 dwLength = GetLengthSid(ptu->User.Sid);
384 *ppsid = (PSID) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
387 if (!CopySid(dwLength, *ppsid, ptu->User.Sid))
389 HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
396 // Free the buffer for the token groups.
398 HeapFree(GetProcessHeap(), 0, (LPVOID)ptu);
404 smb_FreeSID (PSID psid)
406 HeapFree(GetProcessHeap(), 0, (LPVOID)psid);
410 struct smb_ext_context {
417 long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern,
418 char * secBlobIn, int secBlobInLength,
419 char ** secBlobOut, int * secBlobOutLength,
420 wchar_t **secSidString) {
421 SECURITY_STATUS status, istatus;
425 SecBufferDesc secBufIn;
427 SecBufferDesc secBufOut;
430 struct smb_ext_context * secCtx = NULL;
431 struct smb_ext_context * newSecCtx = NULL;
432 void * assembledBlob = NULL;
433 int assembledBlobLength = 0;
436 OutputDebugF(_C("In smb_AuthenticateUserExt"));
439 *secBlobOutLength = 0;
440 *secSidString = NULL;
442 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
443 secCtx = vcp->secCtx;
444 lock_ObtainMutex(&vcp->mx);
445 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
447 lock_ReleaseMutex(&vcp->mx);
451 OutputDebugF(_C("Received incoming token:"));
452 OutputDebugHexDump(secBlobIn,secBlobInLength);
456 OutputDebugF(_C("Continuing with existing context."));
457 creds = secCtx->creds;
460 if (secCtx->partialToken) {
461 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
462 assembledBlob = malloc(assembledBlobLength);
463 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
464 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
467 status = AcquireCredentialsHandle( NULL,
468 SMB_EXT_SEC_PACKAGE_NAME,
477 if (status != SEC_E_OK) {
478 OutputDebugF(_C("Can't acquire Credentials handle [%lX]"), status);
479 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
487 secBufIn.cBuffers = 1;
488 secBufIn.pBuffers = &secTokIn;
489 secBufIn.ulVersion = SECBUFFER_VERSION;
491 secTokIn.BufferType = SECBUFFER_TOKEN;
493 secTokIn.cbBuffer = assembledBlobLength;
494 secTokIn.pvBuffer = assembledBlob;
496 secTokIn.cbBuffer = secBlobInLength;
497 secTokIn.pvBuffer = secBlobIn;
500 secBufOut.cBuffers = 1;
501 secBufOut.pBuffers = &secTokOut;
502 secBufOut.ulVersion = SECBUFFER_VERSION;
504 secTokOut.BufferType = SECBUFFER_TOKEN;
505 secTokOut.cbBuffer = 0;
506 secTokOut.pvBuffer = NULL;
508 status = AcceptSecurityContext( &creds,
509 ((secCtx)?&ctx:NULL),
511 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
512 SECURITY_NETWORK_DREP,
519 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
520 OutputDebugF(_C("Completing token..."));
521 istatus = CompleteAuthToken(&ctx, &secBufOut);
522 if ( istatus != SEC_E_OK )
523 OutputDebugF(_C("Token completion failed: %lX"), istatus);
526 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
527 OutputDebugF(_C("Continue needed"));
529 newSecCtx = malloc(sizeof(*newSecCtx));
531 newSecCtx->creds = creds;
532 newSecCtx->ctx = ctx;
533 newSecCtx->partialToken = NULL;
534 newSecCtx->partialTokenLen = 0;
536 lock_ObtainMutex( &vcp->mx );
537 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
538 vcp->secCtx = newSecCtx;
539 lock_ReleaseMutex( &vcp->mx );
541 code = CM_ERROR_GSSCONTINUE;
544 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
545 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
546 secTokOut.pvBuffer) {
547 OutputDebugF(_C("Need to send token back to client"));
549 *secBlobOutLength = secTokOut.cbBuffer;
550 *secBlobOut = malloc(secTokOut.cbBuffer);
551 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
553 OutputDebugF(_C("Outgoing token:"));
554 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
555 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
556 OutputDebugF(_C("Incomplete message"));
558 newSecCtx = malloc(sizeof(*newSecCtx));
560 newSecCtx->creds = creds;
561 newSecCtx->ctx = ctx;
562 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
563 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
564 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
566 lock_ObtainMutex( &vcp->mx );
567 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
568 vcp->secCtx = newSecCtx;
569 lock_ReleaseMutex( &vcp->mx );
571 code = CM_ERROR_GSSCONTINUE;
574 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
577 SecPkgContext_NamesW names;
579 OutputDebugF(_C("Authentication completed"));
580 OutputDebugF(_C("Returned flags : [%lX]"), flags);
582 if (!QueryContextAttributesW(&ctx, SECPKG_ATTR_NAMES, &names)) {
583 OutputDebugF(_C("Received name [%s]"), names.sUserName);
584 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, names.sUserName);
585 cm_ClientStrLwr(usern); /* in tandem with smb_GetNormalizedUsername */
586 FreeContextBuffer(names.sUserName);
588 /* Force the user to retry if the context is invalid */
589 OutputDebugF(_C("QueryContextAttributes Names failed [%x]"), GetLastError());
590 code = CM_ERROR_BADPASSWORD;
593 /* Obtain the user's SID */
594 if (code == 0 && !QuerySecurityContextToken(((secCtx)?&ctx:NULL), &hToken)) {
596 OutputDebugF(_C("Received hToken"));
598 if (smb_GetUserSID(hToken, &pSid))
599 ConvertSidToStringSidW(pSid, secSidString);
605 OutputDebugF(_C("QueryContextToken failed [%x]"), GetLastError());
609 case SEC_E_INVALID_TOKEN:
610 OutputDebugF(_C("Returning bad password :: INVALID_TOKEN"));
612 case SEC_E_INVALID_HANDLE:
613 OutputDebugF(_C("Returning bad password :: INVALID_HANDLE"));
615 case SEC_E_LOGON_DENIED:
616 OutputDebugF(_C("Returning bad password :: LOGON_DENIED"));
618 case SEC_E_UNKNOWN_CREDENTIALS:
619 OutputDebugF(_C("Returning bad password :: UNKNOWN_CREDENTIALS"));
621 case SEC_E_NO_CREDENTIALS:
622 OutputDebugF(_C("Returning bad password :: NO_CREDENTIALS"));
624 case SEC_E_CONTEXT_EXPIRED:
625 OutputDebugF(_C("Returning bad password :: CONTEXT_EXPIRED"));
627 case SEC_E_INCOMPLETE_CREDENTIALS:
628 OutputDebugF(_C("Returning bad password :: INCOMPLETE_CREDENTIALS"));
630 case SEC_E_WRONG_PRINCIPAL:
631 OutputDebugF(_C("Returning bad password :: WRONG_PRINCIPAL"));
633 case SEC_E_TIME_SKEW:
634 OutputDebugF(_C("Returning bad password :: TIME_SKEW"));
637 OutputDebugF(_C("Returning bad password :: Status == %lX"), status);
639 code = CM_ERROR_BADPASSWORD;
643 if (secCtx->partialToken) free(secCtx->partialToken);
651 if (secTokOut.pvBuffer)
652 FreeContextBuffer(secTokOut.pvBuffer);
654 if (code != CM_ERROR_GSSCONTINUE) {
655 DeleteSecurityContext(&ctx);
656 FreeCredentialsHandle(&creds);
664 #define P_RESP_LEN 128
666 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
667 So put stuff in a struct. */
668 struct Lm20AuthBlob {
669 MSV1_0_LM20_LOGON lmlogon;
670 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
671 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
672 WCHAR accountNameW[P_LEN];
673 WCHAR primaryDomainW[P_LEN];
674 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
675 TOKEN_GROUPS tgroups;
676 TOKEN_SOURCE tsource;
679 long smb_AuthenticateUserLM(smb_vc_t *vcp, clientchar_t * accountName, clientchar_t * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
682 struct Lm20AuthBlob lmAuth;
683 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
684 QUOTA_LIMITS quotaLimits;
686 ULONG lmprofilepSize;
690 OutputDebugF(_C("In smb_AuthenticateUser for user [%s] domain [%s]"), accountName, primaryDomain);
691 OutputDebugF(_C("ciPwdLength is %d and csPwdLength is %d"), ciPwdLength, csPwdLength);
693 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
694 OutputDebugF(_C("ciPwdLength or csPwdLength is too long"));
695 return CM_ERROR_BADPASSWORD;
698 memset(&lmAuth,0,sizeof(lmAuth));
700 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
702 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
703 cm_ClientStringToUtf16(primaryDomain, -1, lmAuth.primaryDomainW, P_LEN);
704 lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
705 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
707 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
708 cm_ClientStringToUtf16(accountName, -1, lmAuth.accountNameW, P_LEN);
709 lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
710 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
712 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
713 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
714 size = MAX_COMPUTERNAME_LENGTH + 1;
715 GetComputerNameW(lmAuth.workstationW, &size);
716 lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
718 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
720 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
721 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
722 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
723 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
725 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
726 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
727 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
728 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
730 lmAuth.lmlogon.ParameterControl = 0;
732 lmAuth.tgroups.GroupCount = 0;
733 lmAuth.tgroups.Groups[0].Sid = NULL;
734 lmAuth.tgroups.Groups[0].Attributes = 0;
737 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
739 lmAuth.tsource.SourceIdentifier.HighPart = 0;
741 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
742 StringCchCopyA(lmAuth.tsource.SourceName, lengthof(lmAuth.tsource.SourceName),
743 "OpenAFS"); /* 8 char limit */
745 nts = LsaLogonUser( smb_lsaHandle,
760 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
761 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
764 OutputDebugF(_C("Return from LsaLogonUser is 0x%lX"), nts);
765 OutputDebugF(_C("Extended status is 0x%lX"), ntsEx);
767 if (nts == ERROR_SUCCESS) {
769 LsaFreeReturnBuffer(lmprofilep);
770 CloseHandle(lmToken);
774 if (nts == 0xC000015BL)
775 return CM_ERROR_BADLOGONTYPE;
776 else /* our catchall is a bad password though we could be more specific */
777 return CM_ERROR_BADPASSWORD;
781 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
782 long smb_GetNormalizedUsername(clientchar_t * usern, const clientchar_t * accountName, const clientchar_t * domainName)
784 clientchar_t * atsign;
785 const clientchar_t * domain;
787 /* check if we have sane input */
788 if ((cm_ClientStrLen(accountName) + cm_ClientStrLen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
791 /* we could get : [accountName][domainName]
797 atsign = cm_ClientStrChr(accountName, '@');
799 if (atsign) /* [user@domain][] -> [user@domain][domain] */
804 /* if for some reason the client doesn't know what domain to use,
805 it will either return an empty string or a '?' */
806 if (!domain[0] || domain[0] == '?')
807 /* Empty domains and empty usernames are usually sent from tokenless contexts.
808 This way such logins will get an empty username (easy to check). I don't know
809 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
810 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, accountName);
812 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
813 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, domain);
814 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, _C("\\"));
816 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
818 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
821 cm_ClientStrLwr(usern);
826 /* When using SMB auth, all SMB sessions have to pass through here
827 * first to authenticate the user.
829 * Caveat: If not using SMB auth, the protocol does not require
830 * sending a session setup packet, which means that we can't rely on a
831 * UID in subsequent packets. Though in practice we get one anyway.
833 /* SMB_COM_SESSION_SETUP_ANDX */
834 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
838 unsigned short newUid;
839 unsigned long caps = 0;
841 clientchar_t *s1 = _C(" ");
843 clientchar_t usern[SMB_MAX_USERNAME_LENGTH];
845 char *secBlobOut = NULL;
846 int secBlobOutLength = 0;
847 wchar_t *secSidString = 0;
848 int maxBufferSize = 0;
852 /* Check for bad conns */
853 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
854 return CM_ERROR_REMOTECONN;
857 maxBufferSize = smb_GetSMBParm(inp, 2);
858 maxMpxCount = smb_GetSMBParm(inp, 3);
859 vcNumber = smb_GetSMBParm(inp, 4);
861 osi_Log3(smb_logp, "SESSION_SETUP_ANDX with MaxBufferSize=%d, MaxMpxCount=%d, VCNumber=%d",
862 maxBufferSize, maxMpxCount, vcNumber);
864 if (maxMpxCount > smb_maxMpxRequests) {
865 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_MPX_COUNT, maxMpxCount, smb_maxMpxRequests);
866 osi_Log2(smb_logp, "MaxMpxCount for client is too large (Client=%d, Server=%d)",
867 maxMpxCount, smb_maxMpxRequests);
870 if (maxBufferSize < SMB_PACKETSIZE) {
871 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_BUFFER_SIZE, maxBufferSize, SMB_PACKETSIZE);
872 osi_Log2(smb_logp, "MaxBufferSize for client is too small (Client=%d, Server=%d)",
873 maxBufferSize, SMB_PACKETSIZE);
877 osi_Log0(smb_logp, "Resetting all VCs");
878 smb_MarkAllVCsDead(vcp);
881 if (vcp->flags & SMB_VCFLAG_USENT) {
882 if (smb_authType == SMB_AUTH_EXTENDED) {
883 /* extended authentication */
887 OutputDebugF(_C("NT Session Setup: Extended"));
889 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
890 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
893 secBlobInLength = smb_GetSMBParm(inp, 7);
894 secBlobIn = smb_GetSMBData(inp, NULL);
896 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength, &secSidString);
898 if (code == CM_ERROR_GSSCONTINUE) {
901 smb_SetSMBParm(outp, 2, 0);
902 smb_SetSMBParm(outp, 3, secBlobOutLength);
904 tp = smb_GetSMBData(outp, NULL);
905 if (secBlobOutLength) {
906 memcpy(tp, secBlobOut, secBlobOutLength);
908 tp += secBlobOutLength;
909 cb_data += secBlobOutLength;
911 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
912 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
913 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
915 smb_SetSMBDataLength(outp, cb_data);
918 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
920 unsigned ciPwdLength, csPwdLength;
922 clientchar_t *accountName;
923 clientchar_t *primaryDomain;
926 if (smb_authType == SMB_AUTH_NTLM)
927 OutputDebugF(_C("NT Session Setup: NTLM"));
929 OutputDebugF(_C("NT Session Setup: None"));
931 /* TODO: parse for extended auth as well */
932 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
933 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
935 tp = smb_GetSMBData(inp, &datalen);
937 OutputDebugF(_C("Session packet data size [%d]"),datalen);
944 accountName = smb_ParseString(inp, tp, &tp, 0);
945 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
947 OutputDebugF(_C("Account Name: %s"),accountName);
948 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
949 OutputDebugF(_C("Case Sensitive Password: %s"),
950 csPwd && csPwd[0] ? _C("yes") : _C("no"));
951 OutputDebugF(_C("Case Insensitive Password: %s"),
952 ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
954 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
955 /* shouldn't happen */
956 code = CM_ERROR_BADSMB;
957 goto after_read_packet;
960 /* capabilities are only valid for first session packet */
961 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
962 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
965 if (smb_authType == SMB_AUTH_NTLM) {
966 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
968 OutputDebugF(_C("LM authentication failed [%d]"), code);
970 OutputDebugF(_C("LM authentication succeeded"));
974 unsigned ciPwdLength;
976 clientchar_t *accountName;
977 clientchar_t *primaryDomain;
979 switch ( smb_authType ) {
980 case SMB_AUTH_EXTENDED:
981 OutputDebugF(_C("V3 Session Setup: Extended"));
984 OutputDebugF(_C("V3 Session Setup: NTLM"));
987 OutputDebugF(_C("V3 Session Setup: None"));
989 ciPwdLength = smb_GetSMBParm(inp, 7);
990 tp = smb_GetSMBData(inp, NULL);
994 accountName = smb_ParseString(inp, tp, &tp, 0);
995 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
997 OutputDebugF(_C("Account Name: %s"),accountName);
998 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
999 OutputDebugF(_C("Case Insensitive Password: %s"), ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
1001 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
1002 /* shouldn't happen */
1003 code = CM_ERROR_BADSMB;
1004 goto after_read_packet;
1007 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
1010 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
1011 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
1013 OutputDebugF(_C("LM authentication failed [%d]"), code);
1015 OutputDebugF(_C("LM authentication succeeded"));
1020 /* note down that we received a session setup X and set the capabilities flag */
1021 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
1022 lock_ObtainMutex(&vcp->mx);
1023 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
1024 /* for the moment we can only deal with NTSTATUS */
1025 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
1026 vcp->flags |= SMB_VCFLAG_STATUS32;
1030 if ((caps & NTNEGOTIATE_CAPABILITY_UNICODE) && smb_UseUnicode) {
1031 vcp->flags |= SMB_VCFLAG_USEUNICODE;
1034 lock_ReleaseMutex(&vcp->mx);
1037 /* code would be non-zero if there was an authentication failure.
1038 Ideally we would like to invalidate the uid for this session or break
1039 early to avoid accidently stealing someone else's tokens. */
1043 LocalFree(secSidString);
1048 * If the SidString for the user could be obtained, use that
1052 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, secSidString);
1056 OutputDebugF(_C("Received username=[%s]"), usern);
1058 /* On Windows 2000, this function appears to be called more often than
1059 it is expected to be called. This resulted in multiple smb_user_t
1060 records existing all for the same user session which results in all
1061 of the users tokens disappearing.
1063 To avoid this problem, we look for an existing smb_user_t record
1064 based on the users name, and use that one if we find it.
1067 uidp = smb_FindUserByNameThisSession(vcp, usern);
1068 if (uidp) { /* already there, so don't create a new one */
1070 newUid = uidp->userID;
1071 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
1072 vcp->lana,vcp->lsn,newUid);
1073 smb_ReleaseUID(uidp);
1078 /* do a global search for the username/machine name pair */
1079 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
1080 lock_ObtainMutex(&unp->mx);
1081 if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
1082 /* clear the afslogon flag so that the tickets can now
1083 * be freed when the refCount returns to zero.
1085 unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
1088 unp->flags |= SMB_USERNAMEFLAG_SID;
1089 lock_ReleaseMutex(&unp->mx);
1091 /* Create a new UID and cm_user_t structure */
1094 userp = cm_NewUser();
1095 cm_HoldUserVCRef(userp);
1096 lock_ObtainMutex(&vcp->mx);
1097 if (!vcp->uidCounter)
1098 vcp->uidCounter++; /* handle unlikely wraparounds */
1099 newUid = (cm_ClientStrLen(usern)==0)?0:vcp->uidCounter++;
1100 lock_ReleaseMutex(&vcp->mx);
1102 /* Create a new smb_user_t structure and connect them up */
1103 lock_ObtainMutex(&unp->mx);
1105 lock_ReleaseMutex(&unp->mx);
1107 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
1109 lock_ObtainMutex(&uidp->mx);
1111 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
1112 lock_ReleaseMutex(&uidp->mx);
1113 smb_ReleaseUID(uidp);
1117 /* Return UID to the client */
1118 ((smb_t *)outp)->uid = newUid;
1119 /* Also to the next chained message */
1120 ((smb_t *)inp)->uid = newUid;
1122 osi_Log3(smb_logp, "SMB3 session setup name %S creating ID %d%S",
1123 osi_LogSaveClientString(smb_logp, usern), newUid,
1124 osi_LogSaveClientString(smb_logp, s1));
1126 smb_SetSMBParm(outp, 2, 0);
1128 if (vcp->flags & SMB_VCFLAG_USENT) {
1129 if (smb_authType == SMB_AUTH_EXTENDED) {
1132 smb_SetSMBParm(outp, 3, secBlobOutLength);
1134 tp = smb_GetSMBData(outp, NULL);
1135 if (secBlobOutLength) {
1136 memcpy(tp, secBlobOut, secBlobOutLength);
1138 tp += secBlobOutLength;
1139 cb_data += secBlobOutLength;
1142 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
1143 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
1144 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
1146 smb_SetSMBDataLength(outp, cb_data);
1148 smb_SetSMBDataLength(outp, 0);
1151 if (smb_authType == SMB_AUTH_EXTENDED) {
1154 tp = smb_GetSMBData(outp, NULL);
1156 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
1157 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
1158 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
1160 smb_SetSMBDataLength(outp, cb_data);
1162 smb_SetSMBDataLength(outp, 0);
1167 LocalFree(secSidString);
1171 /* SMB_COM_LOGOFF_ANDX */
1172 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1176 /* find the tree and free it */
1177 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1179 smb_username_t * unp;
1181 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %S", uidp->userID,
1182 osi_LogSaveClientString(smb_logp, (uidp->unp) ? uidp->unp->name: _C(" ")));
1184 lock_ObtainMutex(&uidp->mx);
1185 uidp->flags |= SMB_USERFLAG_DELETE;
1187 * it doesn't get deleted right away
1188 * because the vcp points to it
1191 lock_ReleaseMutex(&uidp->mx);
1194 /* we can't do this. we get logoff messages prior to a session
1195 * disconnect even though it doesn't mean the user is logging out.
1196 * we need to create a new pioctl and EventLogoff handler to set
1197 * SMB_USERNAMEFLAG_LOGOFF.
1199 if (unp && smb_LogoffTokenTransfer) {
1200 lock_ObtainMutex(&unp->mx);
1201 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
1202 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
1203 lock_ReleaseMutex(&unp->mx);
1207 smb_ReleaseUID(uidp);
1210 osi_Log0(smb_logp, "SMB3 user logoffX");
1212 smb_SetSMBDataLength(outp, 0);
1216 #define SMB_SUPPORT_SEARCH_BITS 0x0001
1217 #define SMB_SHARE_IS_IN_DFS 0x0002
1219 /* SMB_COM_TREE_CONNECT_ANDX */
1220 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1223 smb_user_t *uidp = NULL;
1224 unsigned short newTid;
1225 clientchar_t shareName[AFSPATHMAX];
1226 clientchar_t *sharePath;
1229 clientchar_t *slashp;
1230 clientchar_t *pathp;
1231 clientchar_t *passwordp;
1232 clientchar_t *servicep;
1233 cm_user_t *userp = NULL;
1236 osi_Log0(smb_logp, "SMB3 receive tree connect");
1238 /* parse input parameters */
1239 tp = smb_GetSMBData(inp, NULL);
1240 passwordp = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1241 pathp = smb_ParseString(inp, tp, &tp, SMB_STRF_ANSIPATH);
1242 servicep = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1244 slashp = cm_ClientStrRChr(pathp, '\\');
1246 return CM_ERROR_BADSMB;
1248 cm_ClientStrCpy(shareName, lengthof(shareName), slashp+1);
1250 osi_Log3(smb_logp, "Tree connect pathp[%S] shareName[%S] service[%S]",
1251 osi_LogSaveClientString(smb_logp, pathp),
1252 osi_LogSaveClientString(smb_logp, shareName),
1253 osi_LogSaveClientString(smb_logp, servicep));
1255 if (cm_ClientStrCmp(servicep, _C("IPC")) == 0 ||
1256 cm_ClientStrCmp(shareName, _C("IPC$")) == 0) {
1258 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1261 return CM_ERROR_NOIPC;
1265 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1267 userp = smb_GetUserFromUID(uidp);
1269 lock_ObtainMutex(&vcp->mx);
1270 newTid = vcp->tidCounter++;
1271 lock_ReleaseMutex(&vcp->mx);
1273 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1276 if (!cm_ClientStrCmp(shareName, _C("*.")))
1277 cm_ClientStrCpy(shareName, lengthof(shareName), _C("all"));
1278 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1281 smb_ReleaseUID(uidp);
1282 smb_ReleaseTID(tidp, FALSE);
1283 return CM_ERROR_BADSHARENAME;
1286 if (vcp->flags & SMB_VCFLAG_USENT)
1288 int policy = smb_FindShareCSCPolicy(shareName);
1291 DWORD dwAdvertiseDFS = 0, dwSize = sizeof(DWORD);
1293 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1294 0, KEY_QUERY_VALUE, &parmKey);
1295 if (code == ERROR_SUCCESS) {
1296 code = RegQueryValueEx(parmKey, "AdvertiseDFS", NULL, NULL,
1297 (BYTE *)&dwAdvertiseDFS, &dwSize);
1298 if (code != ERROR_SUCCESS)
1300 RegCloseKey (parmKey);
1302 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1303 (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
1307 smb_SetSMBParm(outp, 2, 0);
1311 smb_ReleaseUID(uidp);
1313 lock_ObtainMutex(&tidp->mx);
1314 tidp->userp = userp;
1315 tidp->pathname = sharePath;
1317 tidp->flags |= SMB_TIDFLAG_IPC;
1318 lock_ReleaseMutex(&tidp->mx);
1319 smb_ReleaseTID(tidp, FALSE);
1321 ((smb_t *)outp)->tid = newTid;
1322 ((smb_t *)inp)->tid = newTid;
1323 tp = smb_GetSMBData(outp, NULL);
1327 tp = smb_UnparseString(outp, tp, _C("A:"), &cb_data, SMB_STRF_FORCEASCII);
1328 tp = smb_UnparseString(outp, tp, _C("AFS"), &cb_data, 0);
1329 smb_SetSMBDataLength(outp, cb_data);
1333 tp = smb_UnparseString(outp, tp, _C("IPC"), &cb_data, SMB_STRF_FORCEASCII);
1334 smb_SetSMBDataLength(outp, cb_data);
1337 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1341 /* must be called with global tran lock held */
1342 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1344 smb_tran2Packet_t *tp;
1347 smbp = (smb_t *) inp->data;
1348 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1349 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1355 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1356 int totalParms, int totalData)
1358 smb_tran2Packet_t *tp;
1361 smbp = (smb_t *) inp->data;
1362 tp = malloc(sizeof(*tp));
1363 memset(tp, 0, sizeof(*tp));
1366 tp->curData = tp->curParms = 0;
1367 tp->totalData = totalData;
1368 tp->totalParms = totalParms;
1369 tp->tid = smbp->tid;
1370 tp->mid = smbp->mid;
1371 tp->uid = smbp->uid;
1372 tp->pid = smbp->pid;
1373 tp->res[0] = smbp->res[0];
1374 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1375 if (totalParms != 0)
1376 tp->parmsp = malloc(totalParms);
1378 tp->datap = malloc(totalData);
1379 if (smbp->com == 0x25 || smbp->com == 0x26)
1382 tp->opcode = smb_GetSMBParm(inp, 14);
1385 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1387 if (WANTS_UNICODE(inp) && (vcp->flags & SMB_VCFLAG_USEUNICODE))
1388 tp->flags |= SMB_TRAN2PFLAG_USEUNICODE;
1393 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1394 smb_tran2Packet_t *inp, smb_packet_t *outp,
1395 int totalParms, int totalData)
1397 smb_tran2Packet_t *tp;
1398 unsigned short parmOffset;
1399 unsigned short dataOffset;
1400 unsigned short dataAlign;
1402 tp = malloc(sizeof(*tp));
1403 memset(tp, 0, sizeof(*tp));
1406 tp->curData = tp->curParms = 0;
1407 tp->totalData = totalData;
1408 tp->totalParms = totalParms;
1409 tp->oldTotalParms = totalParms;
1414 tp->res[0] = inp->res[0];
1415 tp->opcode = inp->opcode;
1419 * We calculate where the parameters and data will start.
1420 * This calculation must parallel the calculation in
1421 * smb_SendTran2Packet.
1424 parmOffset = 10*2 + 35;
1425 parmOffset++; /* round to even */
1426 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1428 dataOffset = parmOffset + totalParms;
1429 dataAlign = dataOffset & 2; /* quad-align */
1430 dataOffset += dataAlign;
1431 tp->datap = outp->data + dataOffset;
1436 /* free a tran2 packet */
1437 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1440 smb_ReleaseVC(t2p->vcp);
1443 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1453 while (t2p->stringsp) {
1457 t2p->stringsp = ns->nextp;
1463 clientchar_t *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
1464 char ** chainpp, int flags)
1469 if (!(p->flags & SMB_TRAN2PFLAG_USEUNICODE))
1470 flags |= SMB_STRF_FORCEASCII;
1473 cb = p->totalParms - (inp - (char *)p->parmsp);
1474 if (inp < (char *) p->parmsp ||
1475 inp >= ((char *) p->parmsp) + p->totalParms) {
1476 #ifdef DEBUG_UNICODE
1482 return smb_ParseStringBuf((unsigned char *) p->parmsp, &p->stringsp,
1483 inp, &cb, chainpp, flags);
1486 /* called with a VC, an input packet to respond to, and an error code.
1487 * sends an error response.
1489 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1490 smb_packet_t *tp, long code)
1493 unsigned short errCode;
1494 unsigned char errClass;
1495 unsigned long NTStatus;
1497 if (vcp->flags & SMB_VCFLAG_STATUS32)
1498 smb_MapNTError(code, &NTStatus);
1500 smb_MapCoreError(code, vcp, &errCode, &errClass);
1502 smb_FormatResponsePacket(vcp, NULL, tp);
1503 smbp = (smb_t *) tp;
1505 /* We can handle long names */
1506 if (vcp->flags & SMB_VCFLAG_USENT)
1507 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1509 /* now copy important fields from the tran 2 packet */
1510 smbp->com = t2p->com;
1511 smbp->tid = t2p->tid;
1512 smbp->mid = t2p->mid;
1513 smbp->pid = t2p->pid;
1514 smbp->uid = t2p->uid;
1515 smbp->res[0] = t2p->res[0];
1516 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1517 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1518 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1519 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1520 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1521 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1524 smbp->rcls = errClass;
1525 smbp->errLow = (unsigned char) (errCode & 0xff);
1526 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1530 smb_SendPacket(vcp, tp);
1533 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1536 unsigned short parmOffset;
1537 unsigned short dataOffset;
1538 unsigned short totalLength;
1539 unsigned short dataAlign;
1542 smb_FormatResponsePacket(vcp, NULL, tp);
1543 smbp = (smb_t *) tp;
1545 /* We can handle long names */
1546 if (vcp->flags & SMB_VCFLAG_USENT)
1547 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1549 /* now copy important fields from the tran 2 packet */
1550 smbp->com = t2p->com;
1551 smbp->tid = t2p->tid;
1552 smbp->mid = t2p->mid;
1553 smbp->pid = t2p->pid;
1554 smbp->uid = t2p->uid;
1555 smbp->res[0] = t2p->res[0];
1557 if (t2p->error_code) {
1558 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1559 unsigned long NTStatus;
1561 smb_MapNTError(t2p->error_code, &NTStatus);
1563 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1564 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1565 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1566 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1567 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1570 unsigned short errCode;
1571 unsigned char errClass;
1573 smb_MapCoreError(t2p->error_code, vcp, &errCode, &errClass);
1575 smbp->rcls = errClass;
1576 smbp->errLow = (unsigned char) (errCode & 0xff);
1577 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1581 totalLength = 1 + t2p->totalData + t2p->totalParms;
1583 /* now add the core parameters (tran2 info) to the packet */
1584 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1585 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1586 smb_SetSMBParm(tp, 2, 0); /* reserved */
1587 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1588 parmOffset = 10*2 + 35; /* parm offset in packet */
1589 parmOffset++; /* round to even */
1590 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1591 * hdr, bcc and wct */
1592 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1593 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1594 dataOffset = parmOffset + t2p->oldTotalParms;
1595 dataAlign = dataOffset & 2; /* quad-align */
1596 dataOffset += dataAlign;
1597 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1598 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1599 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1602 datap = smb_GetSMBData(tp, NULL);
1603 *datap++ = 0; /* we rounded to even */
1605 totalLength += dataAlign;
1606 smb_SetSMBDataLength(tp, totalLength);
1608 /* next, send the datagram */
1609 smb_SendPacket(vcp, tp);
1612 /* TRANS_SET_NMPIPE_STATE */
1613 long smb_nmpipeSetState(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1617 int pipeState = 0x0100; /* default */
1618 smb_tran2Packet_t *outp = NULL;
1621 if (p->totalParms > 0)
1622 pipeState = p->parmsp[0];
1624 osi_Log2(smb_logp, "smb_nmpipeSetState for fd[%d] with state[0x%x]", fd, pipeState);
1626 fidp = smb_FindFID(vcp, fd, 0);
1628 osi_Log2(smb_logp, "smb_nmpipeSetState Unknown SMB Fid vcp 0x%p fid %d",
1630 return CM_ERROR_BADFD;
1632 lock_ObtainMutex(&fidp->mx);
1633 if (pipeState & 0x8000)
1634 fidp->flags |= SMB_FID_BLOCKINGPIPE;
1635 if (pipeState & 0x0100)
1636 fidp->flags |= SMB_FID_MESSAGEMODEPIPE;
1637 lock_ReleaseMutex(&fidp->mx);
1639 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 0);
1640 smb_SendTran2Packet(vcp, outp, op);
1641 smb_FreeTran2Packet(outp);
1643 smb_ReleaseFID(fidp);
1648 long smb_nmpipeTransact(smb_vc_t * vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1658 osi_Log3(smb_logp, "smb_nmpipeTransact for fd[%d] %d bytes in, %d max bytes out",
1659 fd, p->totalData, p->maxReturnData);
1661 fidp = smb_FindFID(vcp, fd, 0);
1663 osi_Log2(smb_logp, "smb_nmpipeTransact Unknown SMB Fid vcp 0x%p fid %d",
1665 return CM_ERROR_BADFD;
1667 lock_ObtainMutex(&fidp->mx);
1668 if (fidp->flags & SMB_FID_RPC) {
1671 lock_ReleaseMutex(&fidp->mx);
1674 code = smb_RPCNmpipeTransact(fidp, vcp, p, op);
1675 smb_ReleaseFID(fidp);
1677 /* We only deal with RPC pipes */
1678 osi_Log2(smb_logp, "smb_nmpipeTransact Not a RPC vcp 0x%p fid %d",
1680 code = CM_ERROR_BADFD;
1687 /* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
1688 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1690 smb_tran2Packet_t *asp;
1703 /* We sometimes see 0 word count. What to do? */
1704 if (*inp->wctp == 0) {
1705 osi_Log0(smb_logp, "Transaction2 word count = 0");
1706 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1708 smb_SetSMBDataLength(outp, 0);
1709 smb_SendPacket(vcp, outp);
1713 totalParms = smb_GetSMBParm(inp, 0);
1714 totalData = smb_GetSMBParm(inp, 1);
1716 firstPacket = (inp->inCom == 0x25);
1718 /* find the packet we're reassembling */
1719 lock_ObtainWrite(&smb_globalLock);
1720 asp = smb_FindTran2Packet(vcp, inp);
1722 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1724 lock_ReleaseWrite(&smb_globalLock);
1726 /* now merge in this latest packet; start by looking up offsets */
1728 parmDisp = dataDisp = 0;
1729 parmOffset = smb_GetSMBParm(inp, 10);
1730 dataOffset = smb_GetSMBParm(inp, 12);
1731 parmCount = smb_GetSMBParm(inp, 9);
1732 dataCount = smb_GetSMBParm(inp, 11);
1733 asp->setupCount = smb_GetSMBParmByte(inp, 13);
1734 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1735 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1737 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1738 totalData, dataCount, asp->maxReturnData);
1740 if (asp->setupCount == 2) {
1741 clientchar_t * pname;
1743 asp->pipeCommand = smb_GetSMBParm(inp, 14);
1744 asp->pipeParam = smb_GetSMBParm(inp, 15);
1745 pname = smb_ParseString(inp, inp->wctp + 35, NULL, 0);
1747 asp->name = cm_ClientStrDup(pname);
1750 osi_Log2(smb_logp, " Named Pipe command id [%d] with name [%S]",
1751 asp->pipeCommand, osi_LogSaveClientString(smb_logp, asp->name));
1755 parmDisp = smb_GetSMBParm(inp, 4);
1756 parmOffset = smb_GetSMBParm(inp, 3);
1757 dataDisp = smb_GetSMBParm(inp, 7);
1758 dataOffset = smb_GetSMBParm(inp, 6);
1759 parmCount = smb_GetSMBParm(inp, 2);
1760 dataCount = smb_GetSMBParm(inp, 5);
1762 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1763 parmCount, dataCount);
1766 /* now copy the parms and data */
1767 if ( asp->totalParms > 0 && parmCount != 0 )
1769 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1771 if ( asp->totalData > 0 && dataCount != 0 ) {
1772 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1775 /* account for new bytes */
1776 asp->curData += dataCount;
1777 asp->curParms += parmCount;
1779 /* finally, if we're done, remove the packet from the queue and dispatch it */
1780 if (((asp->totalParms > 0 && asp->curParms > 0)
1781 || asp->setupCount == 2) &&
1782 asp->totalData <= asp->curData &&
1783 asp->totalParms <= asp->curParms) {
1785 /* we've received it all */
1786 lock_ObtainWrite(&smb_globalLock);
1787 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1788 lock_ReleaseWrite(&smb_globalLock);
1790 switch(asp->setupCount) {
1793 rapOp = asp->parmsp[0];
1795 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES &&
1796 smb_rapDispatchTable[rapOp].procp) {
1798 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",
1799 myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1801 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1803 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",
1804 code,vcp,vcp->lana,vcp->lsn);
1807 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]",
1808 rapOp, vcp, vcp->lana, vcp->lsn);
1810 code = CM_ERROR_BADOP;
1816 { /* Named pipe operation */
1817 osi_Log2(smb_logp, "Named Pipe: %s with name [%S]",
1818 myCrt_NmpipeDispatch(asp->pipeCommand),
1819 osi_LogSaveClientString(smb_logp, asp->name));
1821 code = CM_ERROR_BADOP;
1823 switch (asp->pipeCommand) {
1824 case SMB_TRANS_SET_NMPIPE_STATE:
1825 code = smb_nmpipeSetState(vcp, asp, outp);
1828 case SMB_TRANS_RAW_READ_NMPIPE:
1831 case SMB_TRANS_QUERY_NMPIPE_STATE:
1834 case SMB_TRANS_QUERY_NMPIPE_INFO:
1837 case SMB_TRANS_PEEK_NMPIPE:
1840 case SMB_TRANS_TRANSACT_NMPIPE:
1841 code = smb_nmpipeTransact(vcp, asp, outp);
1844 case SMB_TRANS_RAW_WRITE_NMPIPE:
1847 case SMB_TRANS_READ_NMPIPE:
1850 case SMB_TRANS_WRITE_NMPIPE:
1853 case SMB_TRANS_WAIT_NMPIPE:
1856 case SMB_TRANS_CALL_NMPIPE:
1863 code = CM_ERROR_BADOP;
1866 /* if an error is returned, we're supposed to send an error packet,
1867 * otherwise the dispatched function already did the data sending.
1868 * We give dispatched proc the responsibility since it knows how much
1869 * space to allocate.
1872 smb_SendTran2Error(vcp, asp, outp, code);
1875 /* free the input tran 2 packet */
1876 smb_FreeTran2Packet(asp);
1878 else if (firstPacket) {
1879 /* the first packet in a multi-packet request, we need to send an
1880 * ack to get more data.
1882 smb_SetSMBDataLength(outp, 0);
1883 smb_SendPacket(vcp, outp);
1889 /* ANSI versions. */
1891 #pragma pack(push, 1)
1893 typedef struct smb_rap_share_info_0 {
1894 BYTE shi0_netname[13];
1895 } smb_rap_share_info_0_t;
1897 typedef struct smb_rap_share_info_1 {
1898 BYTE shi1_netname[13];
1901 DWORD shi1_remark; /* char *shi1_remark; data offset */
1902 } smb_rap_share_info_1_t;
1904 typedef struct smb_rap_share_info_2 {
1905 BYTE shi2_netname[13];
1908 DWORD shi2_remark; /* char *shi2_remark; data offset */
1909 WORD shi2_permissions;
1911 WORD shi2_current_uses;
1912 DWORD shi2_path; /* char *shi2_path; data offset */
1913 WORD shi2_passwd[9];
1915 } smb_rap_share_info_2_t;
1917 #define SMB_RAP_MAX_SHARES 512
1919 typedef struct smb_rap_share_list {
1922 smb_rap_share_info_0_t * shares;
1923 } smb_rap_share_list_t;
1927 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1928 smb_rap_share_list_t * sp;
1930 if (dep->name[0] == '.' && (!dep->name[1] || (dep->name[1] == '.' && !dep->name[2])))
1931 return 0; /* skip over '.' and '..' */
1933 sp = (smb_rap_share_list_t *) vrockp;
1935 strncpy(sp->shares[sp->cShare].shi0_netname, dep->name, 12);
1936 sp->shares[sp->cShare].shi0_netname[12] = 0;
1940 if (sp->cShare >= sp->maxShares)
1941 return CM_ERROR_STOPNOW;
1946 /* RAP NetShareEnumRequest */
1947 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1949 smb_tran2Packet_t *outp;
1950 unsigned short * tp;
1954 int outParmsTotal; /* total parameter bytes */
1955 int outDataTotal; /* total data bytes */
1958 DWORD allSubmount = 0;
1960 DWORD nRegShares = 0;
1961 DWORD nSharesRet = 0;
1963 HKEY hkSubmount = NULL;
1964 smb_rap_share_info_1_t * shares;
1967 clientchar_t thisShare[AFSPATHMAX];
1971 smb_rap_share_list_t rootShares;
1975 cm_scache_t *rootScp;
1977 tp = p->parmsp + 1; /* skip over function number (always 0) */
1980 clientchar_t * cdescp;
1982 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1983 if (cm_ClientStrCmp(cdescp, _C("WrLeh")))
1984 return CM_ERROR_INVAL;
1985 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1986 if (cm_ClientStrCmp(cdescp, _C("B13BWz")))
1987 return CM_ERROR_INVAL;
1993 if (infoLevel != 1) {
1994 return CM_ERROR_INVAL;
1997 /* We are supposed to use the same ASCII data structure even if
1998 Unicode is negotiated, which ultimately means that the share
1999 names that we return must be at most 13 characters in length,
2000 including the NULL terminator.
2002 The RAP specification states that shares with names longer than
2003 12 characters should not be included in the enumeration.
2004 However, since we support prefix cell references and since many
2005 cell names are going to exceed 12 characters, we lie and send
2006 the first 12 characters.
2009 /* first figure out how many shares there are */
2010 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
2011 KEY_QUERY_VALUE, &hkParam);
2012 if (rv == ERROR_SUCCESS) {
2013 len = sizeof(allSubmount);
2014 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
2015 (BYTE *) &allSubmount, &len);
2016 if (rv != ERROR_SUCCESS || allSubmount != 0) {
2019 RegCloseKey (hkParam);
2022 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
2023 0, KEY_QUERY_VALUE, &hkSubmount);
2024 if (rv == ERROR_SUCCESS) {
2025 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
2026 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
2027 if (rv != ERROR_SUCCESS)
2033 /* fetch the root shares */
2034 rootShares.maxShares = SMB_RAP_MAX_SHARES;
2035 rootShares.cShare = 0;
2036 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
2040 userp = smb_GetTran2User(vcp,p);
2042 thyper.HighPart = 0;
2045 rootScp = cm_RootSCachep(userp, &req);
2046 cm_HoldSCache(rootScp);
2047 cm_ApplyDir(rootScp, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
2048 cm_ReleaseSCache(rootScp);
2050 cm_ReleaseUser(userp);
2052 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
2054 #define REMARK_LEN 1
2055 outParmsTotal = 8; /* 4 dwords */
2056 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
2057 if(outDataTotal > bufsize) {
2058 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
2059 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
2062 nSharesRet = nShares;
2065 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
2067 /* now for the submounts */
2068 shares = (smb_rap_share_info_1_t *) outp->datap;
2069 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
2071 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
2074 StringCchCopyA(shares[cshare].shi1_netname,
2075 lengthof(shares[cshare].shi1_netname), "all" );
2076 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
2077 /* type and pad are zero already */
2083 for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
2084 len = sizeof(thisShare);
2085 rv = RegEnumValueW(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
2086 if (rv == ERROR_SUCCESS &&
2087 cm_ClientStrLen(thisShare) &&
2088 (!allSubmount || cm_ClientStrCmpI(thisShare,_C("all")))) {
2089 cm_ClientStringToUtf8(thisShare, -1, shares[cshare].shi1_netname,
2090 lengthof( shares[cshare].shi1_netname ));
2091 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
2092 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
2097 nShares--; /* uncount key */
2100 RegCloseKey(hkSubmount);
2103 nonrootShares = cshare;
2105 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
2106 /* in case there are collisions with submounts, submounts have
2108 for (j=0; j < nonrootShares; j++)
2109 if (!cm_stricmp_utf8(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
2112 if (j < nonrootShares) {
2113 nShares--; /* uncount */
2117 StringCchCopyA(shares[cshare].shi1_netname, lengthof(shares[cshare].shi1_netname),
2118 rootShares.shares[i].shi0_netname);
2119 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
2124 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
2125 outp->parmsp[1] = 0;
2126 outp->parmsp[2] = cshare;
2127 outp->parmsp[3] = nShares;
2129 outp->totalData = (int)(cstrp - outp->datap);
2130 outp->totalParms = outParmsTotal;
2132 smb_SendTran2Packet(vcp, outp, op);
2133 smb_FreeTran2Packet(outp);
2135 free(rootShares.shares);
2140 /* RAP NetShareGetInfo */
2141 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2143 smb_tran2Packet_t *outp;
2144 unsigned short * tp;
2145 clientchar_t * shareName;
2146 BOOL shareFound = FALSE;
2147 unsigned short infoLevel;
2148 unsigned short bufsize;
2157 cm_scache_t *scp = NULL;
2163 tp = p->parmsp + 1; /* skip over function number (always 1) */
2166 clientchar_t * cdescp;
2168 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2169 if (cm_ClientStrCmp(cdescp, _C("zWrLh")))
2171 return CM_ERROR_INVAL;
2173 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2174 if (cm_ClientStrCmp(cdescp, _C("B13")) &&
2175 cm_ClientStrCmp(cdescp, _C("B13BWz")) &&
2176 cm_ClientStrCmp(cdescp, _C("B13BWzWWWzB9B")))
2178 return CM_ERROR_INVAL;
2180 shareName = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2188 totalData = sizeof(smb_rap_share_info_0_t);
2189 else if(infoLevel == SMB_INFO_STANDARD)
2190 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
2191 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
2192 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
2194 return CM_ERROR_INVAL;
2196 if(!cm_ClientStrCmpI(shareName, _C("all")) || !cm_ClientStrCmp(shareName,_C("*."))) {
2197 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
2198 KEY_QUERY_VALUE, &hkParam);
2199 if (rv == ERROR_SUCCESS) {
2200 len = sizeof(allSubmount);
2201 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
2202 (BYTE *) &allSubmount, &len);
2203 if (rv != ERROR_SUCCESS || allSubmount != 0) {
2206 RegCloseKey (hkParam);
2213 userp = smb_GetTran2User(vcp, p);
2215 osi_Log1(smb_logp,"ReceiveRAPNetShareGetInfo unable to resolve user [%d]", p->uid);
2216 return CM_ERROR_BADSMB;
2218 code = cm_NameI(cm_RootSCachep(userp, &req), shareName,
2219 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
2220 userp, NULL, &req, &scp);
2222 cm_ReleaseSCache(scp);
2225 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
2226 KEY_QUERY_VALUE, &hkSubmount);
2227 if (rv == ERROR_SUCCESS) {
2228 rv = RegQueryValueExW(hkSubmount, shareName, NULL, NULL, NULL, NULL);
2229 if (rv == ERROR_SUCCESS) {
2232 RegCloseKey(hkSubmount);
2238 return CM_ERROR_BADSHARENAME;
2240 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
2241 memset(outp->datap, 0, totalData);
2243 outp->parmsp[0] = 0;
2244 outp->parmsp[1] = 0;
2245 outp->parmsp[2] = totalData;
2247 if (infoLevel == 0) {
2248 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
2249 cm_ClientStringToUtf8(shareName, -1, info->shi0_netname,
2250 lengthof(info->shi0_netname));
2251 } else if(infoLevel == SMB_INFO_STANDARD) {
2252 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
2253 cm_ClientStringToUtf8(shareName, -1, info->shi1_netname, lengthof(info->shi1_netname));
2254 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
2255 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
2256 /* type and pad are already zero */
2257 } else { /* infoLevel==2 */
2258 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
2259 cm_ClientStringToUtf8(shareName, -1, info->shi2_netname, lengthof(info->shi2_netname));
2260 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
2261 info->shi2_permissions = ACCESS_ALL;
2262 info->shi2_max_uses = (unsigned short) -1;
2263 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
2266 outp->totalData = totalData;
2267 outp->totalParms = totalParam;
2269 smb_SendTran2Packet(vcp, outp, op);
2270 smb_FreeTran2Packet(outp);
2275 #pragma pack(push, 1)
2277 typedef struct smb_rap_wksta_info_10 {
2278 DWORD wki10_computername; /*char *wki10_computername;*/
2279 DWORD wki10_username; /* char *wki10_username; */
2280 DWORD wki10_langroup; /* char *wki10_langroup;*/
2281 BYTE wki10_ver_major;
2282 BYTE wki10_ver_minor;
2283 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
2284 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
2285 } smb_rap_wksta_info_10_t;
2289 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2291 smb_tran2Packet_t *outp;
2295 unsigned short * tp;
2298 smb_rap_wksta_info_10_t * info;
2302 tp = p->parmsp + 1; /* Skip over function number */
2305 clientchar_t * cdescp;
2307 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2308 SMB_STRF_FORCEASCII);
2309 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2310 return CM_ERROR_INVAL;
2312 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2313 SMB_STRF_FORCEASCII);
2314 if (cm_ClientStrCmp(cdescp, _C("zzzBBzz")))
2315 return CM_ERROR_INVAL;
2321 if (infoLevel != 10) {
2322 return CM_ERROR_INVAL;
2328 totalData = sizeof(*info) + /* info */
2329 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
2330 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
2331 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
2332 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
2333 1; /* wki10_oth_domains (null)*/
2335 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2337 memset(outp->parmsp,0,totalParams);
2338 memset(outp->datap,0,totalData);
2340 info = (smb_rap_wksta_info_10_t *) outp->datap;
2341 cstrp = (char *) (info + 1);
2343 info->wki10_computername = (DWORD) (cstrp - outp->datap);
2344 StringCbCopyA(cstrp, totalData, smb_localNamep);
2345 cstrp += strlen(cstrp) + 1;
2347 info->wki10_username = (DWORD) (cstrp - outp->datap);
2348 uidp = smb_FindUID(vcp, p->uid, 0);
2350 lock_ObtainMutex(&uidp->mx);
2351 if(uidp->unp && uidp->unp->name)
2352 cm_ClientStringToUtf8(uidp->unp->name, -1,
2353 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2354 lock_ReleaseMutex(&uidp->mx);
2355 smb_ReleaseUID(uidp);
2357 cstrp += strlen(cstrp) + 1;
2359 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
2360 StringCbCopyA(cstrp, totalData - (cstrp - outp->datap)*sizeof(char), "WORKGROUP");
2361 cstrp += strlen(cstrp) + 1;
2363 /* TODO: Not sure what values these should take, but these work */
2364 info->wki10_ver_major = 5;
2365 info->wki10_ver_minor = 1;
2367 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
2368 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
2369 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2370 cstrp += strlen(cstrp) + 1;
2372 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
2373 cstrp ++; /* no other domains */
2375 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
2376 outp->parmsp[2] = outp->totalData;
2377 outp->totalParms = totalParams;
2379 smb_SendTran2Packet(vcp,outp,op);
2380 smb_FreeTran2Packet(outp);
2385 #pragma pack(push, 1)
2387 typedef struct smb_rap_server_info_0 {
2389 } smb_rap_server_info_0_t;
2391 typedef struct smb_rap_server_info_1 {
2393 BYTE sv1_version_major;
2394 BYTE sv1_version_minor;
2396 DWORD sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
2397 } smb_rap_server_info_1_t;
2401 char smb_ServerComment[] = "OpenAFS Client";
2402 int smb_ServerCommentLen = sizeof(smb_ServerComment);
2404 #define SMB_SV_TYPE_SERVER 0x00000002L
2405 #define SMB_SV_TYPE_NT 0x00001000L
2406 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
2408 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2410 smb_tran2Packet_t *outp;
2414 unsigned short * tp;
2417 smb_rap_server_info_0_t * info0;
2418 smb_rap_server_info_1_t * info1;
2421 tp = p->parmsp + 1; /* Skip over function number */
2424 clientchar_t * cdescp;
2426 cdescp = smb_ParseStringT2Parm(p, (unsigned char *) tp, (char **) &tp,
2427 SMB_STRF_FORCEASCII);
2428 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2429 return CM_ERROR_INVAL;
2430 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2431 SMB_STRF_FORCEASCII);
2432 if (cm_ClientStrCmp(cdescp, _C("B16")) ||
2433 cm_ClientStrCmp(cdescp, _C("B16BBDz")))
2434 return CM_ERROR_INVAL;
2440 if (infoLevel != 0 && infoLevel != 1) {
2441 return CM_ERROR_INVAL;
2447 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
2448 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
2450 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2452 memset(outp->parmsp,0,totalParams);
2453 memset(outp->datap,0,totalData);
2455 if (infoLevel == 0) {
2456 info0 = (smb_rap_server_info_0_t *) outp->datap;
2457 cstrp = (char *) (info0 + 1);
2458 StringCchCopyA(info0->sv0_name, lengthof(info0->sv0_name), "AFS");
2459 } else { /* infoLevel == SMB_INFO_STANDARD */
2460 info1 = (smb_rap_server_info_1_t *) outp->datap;
2461 cstrp = (char *) (info1 + 1);
2462 StringCchCopyA(info1->sv1_name, lengthof(info1->sv1_name), "AFS");
2465 SMB_SV_TYPE_SERVER |
2467 SMB_SV_TYPE_SERVER_NT;
2469 info1->sv1_version_major = 5;
2470 info1->sv1_version_minor = 1;
2471 info1->sv1_comment_or_master_browser = (DWORD) (cstrp - outp->datap);
2473 StringCbCopyA(cstrp, smb_ServerCommentLen, smb_ServerComment);
2475 cstrp += smb_ServerCommentLen / sizeof(char);
2478 totalData = (DWORD)(cstrp - outp->datap);
2479 outp->totalData = min(bufsize,totalData); /* actual data size */
2480 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
2481 outp->parmsp[2] = totalData;
2482 outp->totalParms = totalParams;
2484 smb_SendTran2Packet(vcp,outp,op);
2485 smb_FreeTran2Packet(outp);
2490 /* SMB_COM_TRANSACTION2 and SMB_COM_TRANSACTION2_SECONDARY */
2491 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2493 smb_tran2Packet_t *asp;
2504 DWORD oldTime, newTime;
2506 /* We sometimes see 0 word count. What to do? */
2507 if (*inp->wctp == 0) {
2508 osi_Log0(smb_logp, "Transaction2 word count = 0");
2509 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
2511 smb_SetSMBDataLength(outp, 0);
2512 smb_SendPacket(vcp, outp);
2516 totalParms = smb_GetSMBParm(inp, 0);
2517 totalData = smb_GetSMBParm(inp, 1);
2519 firstPacket = (inp->inCom == 0x32);
2521 /* find the packet we're reassembling */
2522 lock_ObtainWrite(&smb_globalLock);
2523 asp = smb_FindTran2Packet(vcp, inp);
2525 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
2527 lock_ReleaseWrite(&smb_globalLock);
2529 /* now merge in this latest packet; start by looking up offsets */
2531 parmDisp = dataDisp = 0;
2532 parmOffset = smb_GetSMBParm(inp, 10);
2533 dataOffset = smb_GetSMBParm(inp, 12);
2534 parmCount = smb_GetSMBParm(inp, 9);
2535 dataCount = smb_GetSMBParm(inp, 11);
2536 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2537 asp->maxReturnData = smb_GetSMBParm(inp, 3);
2539 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2540 totalData, dataCount, asp->maxReturnData);
2543 parmDisp = smb_GetSMBParm(inp, 4);
2544 parmOffset = smb_GetSMBParm(inp, 3);
2545 dataDisp = smb_GetSMBParm(inp, 7);
2546 dataOffset = smb_GetSMBParm(inp, 6);
2547 parmCount = smb_GetSMBParm(inp, 2);
2548 dataCount = smb_GetSMBParm(inp, 5);
2550 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2551 parmCount, dataCount);
2554 /* now copy the parms and data */
2555 if ( asp->totalParms > 0 && parmCount != 0 )
2557 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2559 if ( asp->totalData > 0 && dataCount != 0 ) {
2560 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2563 /* account for new bytes */
2564 asp->curData += dataCount;
2565 asp->curParms += parmCount;
2567 /* finally, if we're done, remove the packet from the queue and dispatch it */
2568 if (asp->totalParms > 0 &&
2569 asp->curParms > 0 &&
2570 asp->totalData <= asp->curData &&
2571 asp->totalParms <= asp->curParms) {
2572 /* we've received it all */
2573 lock_ObtainWrite(&smb_globalLock);
2574 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2575 lock_ReleaseWrite(&smb_globalLock);
2577 oldTime = GetTickCount();
2579 /* now dispatch it */
2580 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2581 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2582 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2585 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2586 code = CM_ERROR_BADOP;
2589 /* if an error is returned, we're supposed to send an error packet,
2590 * otherwise the dispatched function already did the data sending.
2591 * We give dispatched proc the responsibility since it knows how much
2592 * space to allocate.
2595 smb_SendTran2Error(vcp, asp, outp, code);
2598 newTime = GetTickCount();
2599 if (newTime - oldTime > 45000) {
2602 clientchar_t *treepath = NULL; /* do not free */
2603 clientchar_t *pathname = NULL;
2604 cm_fid_t afid = {0,0,0,0,0};
2606 uidp = smb_FindUID(vcp, asp->uid, 0);
2607 smb_LookupTIDPath(vcp, asp->tid, &treepath);
2608 fidp = smb_FindFID(vcp, inp->fid, 0);
2611 lock_ObtainMutex(&fidp->mx);
2612 if (fidp->NTopen_pathp)
2613 pathname = fidp->NTopen_pathp;
2615 afid = fidp->scp->fid;
2617 if (inp->stringsp->wdata)
2618 pathname = inp->stringsp->wdata;
2621 afsi_log("Request %s duration %d ms user 0x%x \"%S\" pid 0x%x mid 0x%x tid 0x%x \"%S\" path? \"%S\" afid (%d.%d.%d.%d)",
2622 myCrt_2Dispatch(asp->opcode), newTime - oldTime,
2623 asp->uid, uidp ? uidp->unp->name : NULL,
2624 asp->pid, asp->mid, asp->tid,
2627 afid.cell, afid.volume, afid.vnode, afid.unique);
2630 lock_ReleaseMutex(&fidp->mx);
2633 smb_ReleaseUID(uidp);
2635 smb_ReleaseFID(fidp);
2638 /* free the input tran 2 packet */
2639 smb_FreeTran2Packet(asp);
2641 else if (firstPacket) {
2642 /* the first packet in a multi-packet request, we need to send an
2643 * ack to get more data.
2645 smb_SetSMBDataLength(outp, 0);
2646 smb_SendPacket(vcp, outp);
2653 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2655 clientchar_t *pathp;
2656 smb_tran2Packet_t *outp;
2661 cm_scache_t *dscp; /* dir we're dealing with */
2662 cm_scache_t *scp; /* file we're creating */
2666 clientchar_t *lastNamep;
2673 int parmSlot; /* which parm we're dealing with */
2674 long returnEALength;
2675 clientchar_t *tidPathp;
2678 BOOL is_rpc = FALSE;
2679 BOOL is_ipc = FALSE;
2685 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2686 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2688 openFun = p->parmsp[6]; /* open function */
2689 excl = ((openFun & 3) == 0);
2690 trunc = ((openFun & 3) == 2); /* truncate it */
2691 openMode = (p->parmsp[1] & 0x7);
2692 openAction = 0; /* tracks what we did */
2694 attributes = p->parmsp[3];
2695 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2697 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
2700 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2702 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2703 if (code == CM_ERROR_TIDIPC) {
2705 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2708 spacep = cm_GetSpace();
2709 /* smb_StripLastComponent will strip "::$DATA" if present */
2710 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2714 /* special case magic file name for receiving IOCTL requests
2715 * (since IOCTL calls themselves aren't getting through).
2717 (cm_ClientStrCmpI(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
2719 /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional)*/
2720 (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
2722 unsigned short file_type = 0;
2723 unsigned short device_state = 0;
2725 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2728 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
2729 osi_Log2(smb_logp, "smb_ReceiveTran2Open Creating RPC Fid [%d] code [%d]",
2732 smb_ReleaseFID(fidp);
2733 smb_FreeTran2Packet(outp);
2734 osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
2738 smb_SetupIoctlFid(fidp, spacep);
2739 osi_Log1(smb_logp, "smb_ReceiveTran2Open Creating IOCTL Fid [%d]", fidp->fid);
2742 /* copy out remainder of the parms */
2744 outp->parmsp[parmSlot++] = fidp->fid;
2746 outp->parmsp[parmSlot++] = 0; /* attrs */
2747 outp->parmsp[parmSlot++] = 0; /* mod time */
2748 outp->parmsp[parmSlot++] = 0;
2749 outp->parmsp[parmSlot++] = 0; /* len */
2750 outp->parmsp[parmSlot++] = 0x7fff;
2751 outp->parmsp[parmSlot++] = openMode;
2752 outp->parmsp[parmSlot++] = file_type;
2753 outp->parmsp[parmSlot++] = device_state;
2755 /* and the final "always present" stuff */
2756 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2757 /* next write out the "unique" ID */
2758 outp->parmsp[parmSlot++] = 0x1234;
2759 outp->parmsp[parmSlot++] = 0x5678;
2760 outp->parmsp[parmSlot++] = 0;
2761 if (returnEALength) {
2762 outp->parmsp[parmSlot++] = 0;
2763 outp->parmsp[parmSlot++] = 0;
2766 outp->totalData = 0;
2767 outp->totalParms = parmSlot * 2;
2769 smb_SendTran2Packet(vcp, outp, op);
2771 smb_FreeTran2Packet(outp);
2773 /* and clean up fid reference */
2774 smb_ReleaseFID(fidp);
2780 osi_Log1(smb_logp, "Tran2Open rejecting IPC TID vcp %p", vcp);
2781 smb_FreeTran2Packet(outp);
2782 return CM_ERROR_BADFD;
2786 if (!cm_IsValidClientString(pathp)) {
2788 clientchar_t * hexp;
2790 hexp = cm_GetRawCharsAlloc(pathp, -1);
2791 osi_Log1(smb_logp, "Tran2Open rejecting invalid name. [%S]",
2792 osi_LogSaveClientString(smb_logp, hexp));
2796 osi_Log0(smb_logp, "Tran2Open rejecting invalid name");
2798 smb_FreeTran2Packet(outp);
2799 return CM_ERROR_BADNTFILENAME;
2802 #ifdef DEBUG_VERBOSE
2804 char *hexp, *asciip;
2805 asciip = (lastNamep ? lastNamep : pathp);
2806 hexp = osi_HexifyString( asciip );
2807 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2812 userp = smb_GetTran2User(vcp, p);
2813 /* In the off chance that userp is NULL, we log and abandon */
2815 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2816 smb_FreeTran2Packet(outp);
2817 return CM_ERROR_BADSMB;
2821 code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
2822 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2823 userp, tidPathp, &req, &scp);
2825 if (code == CM_ERROR_NOSUCHFILE ||
2826 code == CM_ERROR_NOSUCHPATH ||
2827 code == CM_ERROR_BPLUS_NOMATCH)
2828 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
2829 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2830 userp, tidPathp, &req, &dscp);
2831 cm_FreeSpace(spacep);
2834 cm_ReleaseUser(userp);
2835 smb_FreeTran2Packet(outp);
2840 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2841 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2842 (clientchar_t*) spacep->data);
2843 cm_ReleaseSCache(dscp);
2844 cm_ReleaseUser(userp);
2845 smb_FreeTran2Packet(outp);
2846 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2847 return CM_ERROR_PATH_NOT_COVERED;
2849 return CM_ERROR_NOSUCHPATH;
2851 #endif /* DFS_SUPPORT */
2853 /* otherwise, scp points to the parent directory. Do a lookup,
2854 * and truncate the file if we find it, otherwise we create the
2861 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2863 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2864 cm_ReleaseSCache(dscp);
2865 cm_ReleaseUser(userp);
2866 smb_FreeTran2Packet(outp);
2870 /* macintosh is expensive to program for it */
2871 cm_FreeSpace(spacep);
2874 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2875 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2876 cm_ReleaseSCache(scp);
2877 cm_ReleaseUser(userp);
2878 smb_FreeTran2Packet(outp);
2879 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2880 return CM_ERROR_PATH_NOT_COVERED;
2882 return CM_ERROR_NOSUCHPATH;
2884 #endif /* DFS_SUPPORT */
2887 /* if we get here, if code is 0, the file exists and is represented by
2888 * scp. Otherwise, we have to create it.
2891 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2894 cm_ReleaseSCache(dscp);
2895 cm_ReleaseSCache(scp);
2896 cm_ReleaseUser(userp);
2897 smb_FreeTran2Packet(outp);
2902 /* oops, file shouldn't be there */
2904 cm_ReleaseSCache(dscp);
2905 cm_ReleaseSCache(scp);
2906 cm_ReleaseUser(userp);
2907 smb_FreeTran2Packet(outp);
2908 return CM_ERROR_EXISTS;
2912 setAttr.mask = CM_ATTRMASK_LENGTH;
2913 setAttr.length.LowPart = 0;
2914 setAttr.length.HighPart = 0;
2915 code = cm_SetAttr(scp, &setAttr, userp, &req);
2916 openAction = 3; /* truncated existing file */
2919 openAction = 1; /* found existing file */
2921 else if (!(openFun & 0x10)) {
2922 /* don't create if not found */
2924 cm_ReleaseSCache(dscp);
2925 osi_assertx(scp == NULL, "null cm_scache_t");
2926 cm_ReleaseUser(userp);
2927 smb_FreeTran2Packet(outp);
2928 return CM_ERROR_NOSUCHFILE;
2931 osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2932 openAction = 2; /* created file */
2933 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2934 cm_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2935 smb_SetInitialModeBitsForFile(attributes, &setAttr);
2937 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2941 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2942 smb_NotifyChange(FILE_ACTION_ADDED,
2943 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2944 dscp, lastNamep, NULL, TRUE);
2945 } else if (!excl && code == CM_ERROR_EXISTS) {
2946 /* not an exclusive create, and someone else tried
2947 * creating it already, then we open it anyway. We
2948 * don't bother retrying after this, since if this next
2949 * fails, that means that the file was deleted after we
2950 * started this call.
2952 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2956 setAttr.mask = CM_ATTRMASK_LENGTH;
2957 setAttr.length.LowPart = 0;
2958 setAttr.length.HighPart = 0;
2959 code = cm_SetAttr(scp, &setAttr, userp,
2962 } /* lookup succeeded */
2966 /* we don't need this any longer */
2968 cm_ReleaseSCache(dscp);
2971 /* something went wrong creating or truncating the file */
2973 cm_ReleaseSCache(scp);
2974 cm_ReleaseUser(userp);
2975 smb_FreeTran2Packet(outp);
2979 /* make sure we're about to open a file */
2980 if (scp->fileType != CM_SCACHETYPE_FILE) {
2982 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2983 cm_scache_t * targetScp = 0;
2984 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2986 /* we have a more accurate file to use (the
2987 * target of the symbolic link). Otherwise,
2988 * we'll just use the symlink anyway.
2990 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2992 cm_ReleaseSCache(scp);
2996 if (scp->fileType != CM_SCACHETYPE_FILE) {
2997 cm_ReleaseSCache(scp);
2998 cm_ReleaseUser(userp);
2999 smb_FreeTran2Packet(outp);
3000 return CM_ERROR_ISDIR;
3004 /* now all we have to do is open the file itself */
3005 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3006 osi_assertx(fidp, "null smb_fid_t");
3009 lock_ObtainMutex(&fidp->mx);
3010 /* save a pointer to the vnode */
3011 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
3013 lock_ObtainWrite(&scp->rw);
3014 scp->flags |= CM_SCACHEFLAG_SMB_FID;
3015 lock_ReleaseWrite(&scp->rw);
3018 fidp->userp = userp;
3020 /* compute open mode */
3022 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
3023 if (openMode == 1 || openMode == 2)
3024 fidp->flags |= SMB_FID_OPENWRITE;
3026 /* remember that the file was newly created */
3028 fidp->flags |= SMB_FID_CREATED;
3030 lock_ReleaseMutex(&fidp->mx);
3032 smb_ReleaseFID(fidp);
3034 cm_Open(scp, 0, userp);
3036 /* copy out remainder of the parms */
3038 outp->parmsp[parmSlot++] = fidp->fid;
3039 lock_ObtainRead(&scp->rw);
3041 outp->parmsp[parmSlot++] = smb_Attributes(scp);
3042 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3043 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
3044 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
3045 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
3046 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
3047 outp->parmsp[parmSlot++] = openMode;
3048 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
3049 outp->parmsp[parmSlot++] = 0; /* IPC junk */
3051 /* and the final "always present" stuff */
3052 outp->parmsp[parmSlot++] = openAction;
3053 /* next write out the "unique" ID */
3054 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
3055 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
3056 outp->parmsp[parmSlot++] = 0;
3057 if (returnEALength) {
3058 outp->parmsp[parmSlot++] = 0;
3059 outp->parmsp[parmSlot++] = 0;
3061 lock_ReleaseRead(&scp->rw);
3062 outp->totalData = 0; /* total # of data bytes */
3063 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
3065 smb_SendTran2Packet(vcp, outp, op);
3067 smb_FreeTran2Packet(outp);
3069 cm_ReleaseUser(userp);
3070 /* leave scp held since we put it in fidp->scp */
3074 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3077 unsigned short infolevel;
3079 infolevel = p->parmsp[0];
3081 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
3083 return CM_ERROR_BAD_LEVEL;
3086 /* TRANS2_QUERY_FS_INFORMATION */
3087 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3089 smb_tran2Packet_t *outp;
3090 smb_tran2QFSInfo_t qi;
3094 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
3096 switch (p->parmsp[0]) {
3097 case SMB_INFO_ALLOCATION:
3099 responseSize = sizeof(qi.u.allocInfo);
3101 qi.u.allocInfo.FSID = 0;
3102 qi.u.allocInfo.sectorsPerAllocUnit = 1;
3103 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
3104 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
3105 qi.u.allocInfo.bytesPerSector = 1024;
3108 case SMB_INFO_VOLUME:
3110 qi.u.volumeInfo.vsn = 1234; /* Volume serial number */
3111 qi.u.volumeInfo.vnCount = 3; /* Number of characters in label (AFS\0)*/
3113 /* we're supposed to pad it out with zeroes to the end */
3114 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
3115 smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
3117 responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
3120 case SMB_QUERY_FS_VOLUME_INFO:
3121 /* FS volume info */
3122 responseSize = sizeof(qi.u.FSvolumeInfo);
3125 FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
3126 memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
3129 qi.u.FSvolumeInfo.vsn = 1234;
3130 qi.u.FSvolumeInfo.vnCount = 6; /* This is always in Unicode */
3131 memset(&qi.u.FSvolumeInfo.label, 0, sizeof(qi.u.FSvolumeInfo.label));
3132 memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
3135 case SMB_QUERY_FS_SIZE_INFO:
3137 responseSize = sizeof(qi.u.FSsizeInfo);
3139 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
3140 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
3141 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
3142 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
3143 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
3144 qi.u.FSsizeInfo.bytesPerSector = 1024;
3147 case SMB_QUERY_FS_DEVICE_INFO:
3148 /* FS device info */
3149 responseSize = sizeof(qi.u.FSdeviceInfo);
3151 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
3152 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
3155 case SMB_QUERY_FS_ATTRIBUTE_INFO:
3156 /* FS attribute info */
3158 /* attributes, defined in WINNT.H:
3159 * FILE_CASE_SENSITIVE_SEARCH 0x1
3160 * FILE_CASE_PRESERVED_NAMES 0x2
3161 * FILE_UNICODE_ON_DISK 0x4
3162 * FILE_VOLUME_QUOTAS 0x10
3163 * <no name defined> 0x4000
3164 * If bit 0x4000 is not set, Windows 95 thinks
3165 * we can't handle long (non-8.3) names,
3166 * despite our protestations to the contrary.
3168 qi.u.FSattributeInfo.attributes = 0x4003;
3169 /* The maxCompLength is supposed to be in bytes */
3171 qi.u.FSattributeInfo.attributes |= 0x04;
3173 qi.u.FSattributeInfo.maxCompLength = 255;
3174 smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
3175 qi.u.FSattributeInfo.FSnameLength = sz;
3178 sizeof(qi.u.FSattributeInfo.attributes) +
3179 sizeof(qi.u.FSattributeInfo.maxCompLength) +
3180 sizeof(qi.u.FSattributeInfo.FSnameLength) +
3185 case SMB_INFO_UNIX: /* CIFS Unix Info */
3186 case SMB_INFO_MACOS: /* Mac FS Info */
3188 return CM_ERROR_BADOP;
3191 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
3193 /* copy out return data, and set corresponding sizes */
3194 outp->totalParms = 0;
3195 outp->totalData = responseSize;
3196 memcpy(outp->datap, &qi, responseSize);
3198 /* send and free the packets */
3199 smb_SendTran2Packet(vcp, outp, op);
3200 smb_FreeTran2Packet(outp);
3205 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3207 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
3208 return CM_ERROR_BADOP;
3211 struct smb_ShortNameRock {
3212 clientchar_t *maskp;
3214 clientchar_t *shortName;
3215 size_t shortNameLen;
3218 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
3221 struct smb_ShortNameRock *rockp;
3222 normchar_t normName[MAX_PATH];
3223 clientchar_t *shortNameEnd;
3227 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t)) == 0) {
3228 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
3229 osi_LogSaveString(smb_logp, dep->name));
3233 /* compare both names and vnodes, though probably just comparing vnodes
3234 * would be safe enough.
3236 if (cm_NormStrCmpI(normName, rockp->maskp) != 0)
3238 if (ntohl(dep->fid.vnode) != rockp->vnode)
3241 /* This is the entry */
3242 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
3243 rockp->shortNameLen = shortNameEnd - rockp->shortName;
3245 return CM_ERROR_STOPNOW;
3248 long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
3249 clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
3251 struct smb_ShortNameRock rock;
3252 clientchar_t *lastNamep;
3255 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
3259 spacep = cm_GetSpace();
3260 /* smb_StripLastComponent will strip "::$DATA" if present */
3261 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
3263 code = cm_NameI(cm_RootSCachep(userp, reqp), spacep->wdata,
3264 caseFold, userp, tidPathp,
3266 cm_FreeSpace(spacep);
3271 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3272 cm_ReleaseSCache(dscp);
3273 cm_ReleaseUser(userp);
3277 return CM_ERROR_PATH_NOT_COVERED;
3279 #endif /* DFS_SUPPORT */
3281 if (!lastNamep) lastNamep = pathp;
3284 thyper.HighPart = 0;
3285 rock.shortName = shortName;
3287 rock.maskp = lastNamep;
3288 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
3290 cm_ReleaseSCache(dscp);
3293 return CM_ERROR_NOSUCHFILE;
3294 if (code == CM_ERROR_STOPNOW) {
3295 *shortNameLenp = rock.shortNameLen;
3301 /* TRANS2_QUERY_PATH_INFORMATION */
3302 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3304 smb_tran2Packet_t *outp;
3307 unsigned short infoLevel;
3308 smb_tran2QPathInfo_t qpi;
3310 unsigned short attributes;
3311 unsigned long extAttributes;
3312 clientchar_t shortName[13];
3316 cm_scache_t *scp, *dscp;
3317 int scp_rw_held = 0;
3320 clientchar_t *pathp;
3321 clientchar_t *tidPathp;
3322 clientchar_t *lastComp;
3327 infoLevel = p->parmsp[0];
3328 if (infoLevel == SMB_INFO_IS_NAME_VALID)
3330 else if (infoLevel == SMB_INFO_STANDARD)
3331 responseSize = sizeof(qpi.u.QPstandardInfo);
3332 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
3333 responseSize = sizeof(qpi.u.QPeaSizeInfo);
3334 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3335 responseSize = sizeof(qpi.u.QPfileBasicInfo);
3336 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3337 responseSize = sizeof(qpi.u.QPfileStandardInfo);
3338 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3339 responseSize = sizeof(qpi.u.QPfileEaInfo);
3340 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3341 responseSize = sizeof(qpi.u.QPfileNameInfo);
3342 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
3343 responseSize = sizeof(qpi.u.QPfileAllInfo);
3344 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
3345 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
3346 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO)
3347 responseSize = sizeof(qpi.u.QPfileStreamInfo);
3349 osi_Log2(smb_logp, "Bad Tran2QPathInfo op 0x%x infolevel 0x%x",
3350 p->opcode, infoLevel);
3351 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3354 memset(&qpi, 0, sizeof(qpi));
3356 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3357 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path \"%S\"", infoLevel,
3358 osi_LogSaveClientString(smb_logp, pathp));
3360 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3362 if (infoLevel > 0x100)
3363 outp->totalParms = 2;
3365 outp->totalParms = 0;
3367 /* now, if we're at infoLevel 6, we're only being asked to check
3368 * the syntax, so we just OK things now. In particular, we're *not*
3369 * being asked to verify anything about the state of any parent dirs.
3371 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
3372 smb_SendTran2Packet(vcp, outp, opx);
3373 smb_FreeTran2Packet(outp);
3377 userp = smb_GetTran2User(vcp, p);
3379 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
3380 smb_FreeTran2Packet(outp);
3381 return CM_ERROR_BADSMB;
3384 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3386 osi_Log1(smb_logp, "ReceiveTran2QPathInfo tid path lookup failure 0x%x", code);
3387 cm_ReleaseUser(userp);
3388 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
3389 smb_FreeTran2Packet(outp);
3393 osi_Log1(smb_logp, "T2 QPathInfo tidPathp \"%S\"",
3394 osi_LogSaveClientString(smb_logp, tidPathp));
3397 * XXX Strange hack XXX
3399 * As of Patch 7 (13 January 98), we are having the following problem:
3400 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3401 * requests to look up "desktop.ini" in all the subdirectories.
3402 * This can cause zillions of timeouts looking up non-existent cells
3403 * and volumes, especially in the top-level directory.
3405 * We have not found any way to avoid this or work around it except
3406 * to explicitly ignore the requests for mount points that haven't
3407 * yet been evaluated and for directories that haven't yet been
3410 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3411 spacep = cm_GetSpace();
3412 /* smb_StripLastComponent will strip "::$DATA" if present */
3413 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3414 #ifndef SPECIAL_FOLDERS
3415 /* Make sure that lastComp is not NULL */
3417 if (cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
3418 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
3422 userp, tidPathp, &req, &dscp);
3425 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3426 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3428 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3429 code = CM_ERROR_PATH_NOT_COVERED;
3431 code = CM_ERROR_NOSUCHPATH;
3433 #endif /* DFS_SUPPORT */
3434 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3435 code = CM_ERROR_NOSUCHFILE;
3436 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3437 cm_buf_t *bp = buf_Find(dscp, &hzero);
3443 code = CM_ERROR_NOSUCHFILE;
3445 cm_ReleaseSCache(dscp);
3447 cm_FreeSpace(spacep);
3448 cm_ReleaseUser(userp);
3449 smb_SendTran2Error(vcp, p, opx, code);
3450 smb_FreeTran2Packet(outp);
3456 #endif /* SPECIAL_FOLDERS */
3458 cm_FreeSpace(spacep);
3462 code == CM_ERROR_NOSUCHFILE ||
3463 code == CM_ERROR_NOSUCHPATH ||
3464 code == CM_ERROR_BPLUS_NOMATCH) {
3465 /* now do namei and stat, and copy out the info */
3466 code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
3467 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3471 cm_ReleaseUser(userp);
3472 smb_SendTran2Error(vcp, p, opx, code);
3473 smb_FreeTran2Packet(outp);
3478 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3479 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3480 cm_ReleaseSCache(scp);
3481 cm_ReleaseUser(userp);
3482 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3483 code = CM_ERROR_PATH_NOT_COVERED;
3485 code = CM_ERROR_NOSUCHPATH;
3486 smb_SendTran2Error(vcp, p, opx, code);
3487 smb_FreeTran2Packet(outp);
3490 #endif /* DFS_SUPPORT */
3492 lock_ObtainWrite(&scp->rw);
3494 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3495 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3499 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3501 lock_ConvertWToR(&scp->rw);
3506 /* now we have the status in the cache entry, and everything is locked.
3507 * Marshall the output data.
3509 /* for info level 108, figure out short name */
3510 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3511 code = cm_GetShortName(pathp, userp, &req,
3512 tidPathp, scp->fid.vnode, shortName,
3518 smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
3519 qpi.u.QPfileAltNameInfo.fileNameLength = len;
3520 responseSize = sizeof(unsigned long) + len;
3522 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3523 smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3524 qpi.u.QPfileNameInfo.fileNameLength = len;
3525 responseSize = sizeof(unsigned long) + len;
3527 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3528 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3529 qpi.u.QPstandardInfo.creationDateTime = dosTime;
3530 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3531 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3532 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3533 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3534 attributes = smb_Attributes(scp);
3535 qpi.u.QPstandardInfo.attributes = attributes;
3536 qpi.u.QPstandardInfo.eaSize = 0;
3538 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3539 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3540 qpi.u.QPfileBasicInfo.creationTime = ft;
3541 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3542 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3543 qpi.u.QPfileBasicInfo.changeTime = ft;
3544 extAttributes = smb_ExtAttributes(scp);
3545 qpi.u.QPfileBasicInfo.attributes = extAttributes;
3546 qpi.u.QPfileBasicInfo.reserved = 0;
3548 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3551 lock_ReleaseRead(&scp->rw);
3553 fidp = smb_FindFIDByScache(vcp, scp);
3555 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3556 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3557 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3558 qpi.u.QPfileStandardInfo.directory =
3559 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3560 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3561 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3562 qpi.u.QPfileStandardInfo.reserved = 0;
3565 lock_ObtainMutex(&fidp->mx);
3566 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3567 lock_ReleaseMutex(&fidp->mx);
3568 smb_ReleaseFID(fidp);
3570 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3572 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3573 qpi.u.QPfileEaInfo.eaSize = 0;
3575 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3578 lock_ReleaseRead(&scp->rw);
3580 fidp = smb_FindFIDByScache(vcp, scp);
3582 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3583 qpi.u.QPfileAllInfo.creationTime = ft;
3584 qpi.u.QPfileAllInfo.lastAccessTime = ft;
3585 qpi.u.QPfileAllInfo.lastWriteTime = ft;
3586 qpi.u.QPfileAllInfo.changeTime = ft;
3587 extAttributes = smb_ExtAttributes(scp);
3588 qpi.u.QPfileAllInfo.attributes = extAttributes;
3589 qpi.u.QPfileAllInfo.allocationSize = scp->length;
3590 qpi.u.QPfileAllInfo.endOfFile = scp->length;
3591 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3592 qpi.u.QPfileAllInfo.deletePending = 0;
3593 qpi.u.QPfileAllInfo.directory =
3594 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3595 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3596 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3597 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.vnode;
3598 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.unique;
3599 qpi.u.QPfileAllInfo.eaSize = 0;
3600 qpi.u.QPfileAllInfo.accessFlags = 0;
3602 lock_ObtainMutex(&fidp->mx);
3603 if (fidp->flags & SMB_FID_OPENDELETE)