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