3 * Copyright 2000, International Business Machines Corporation and others.
6 * This software has been released under the terms of the IBM Public
7 * License. For details, see the LICENSE file in the top-level source
8 * directory or online at http://www.openafs.org/dl/license10.html
11 #include <afsconfig.h>
12 #include <afs/param.h>
19 #pragma warning(disable: 4005)
21 #define SECURITY_WIN32
34 #include <WINNT\afsreg.h>
40 extern osi_hyper_t hzero;
42 smb_packet_t *smb_Directory_Watches = NULL;
43 osi_mutex_t smb_Dir_Watch_Lock;
45 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
47 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
49 /* protected by the smb_globalLock */
50 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
52 const clientchar_t **smb_ExecutableExtensions = NULL;
54 /* retrieve a held reference to a user structure corresponding to an incoming
56 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
61 uidp = smb_FindUID(vcp, inp->uid, 0);
65 up = smb_GetUserFromUID(uidp);
73 * Return boolean specifying if the path name is thought to be an
74 * executable file. For now .exe or .dll.
76 afs_uint32 smb_IsExecutableFileName(const clientchar_t *name)
80 if ( smb_ExecutableExtensions == NULL || name == NULL)
83 len = (int)cm_ClientStrLen(name);
85 for ( i=0; smb_ExecutableExtensions[i]; i++) {
86 j = len - (int)cm_ClientStrLen(smb_ExecutableExtensions[i]);
87 if (cm_ClientStrCmpI(smb_ExecutableExtensions[i], &name[j]) == 0)
95 * Return extended attributes.
96 * Right now, we aren't using any of the "new" bits, so this looks exactly
97 * like smb_Attributes() (see smb.c).
99 unsigned long smb_ExtAttributes(cm_scache_t *scp)
103 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
104 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
105 scp->fileType == CM_SCACHETYPE_INVALID)
107 attrs = SMB_ATTR_DIRECTORY;
108 #ifdef SPECIAL_FOLDERS
109 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
110 #endif /* SPECIAL_FOLDERS */
111 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
112 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
113 } else if (scp->fid.vnode & 0x1)
114 attrs = SMB_ATTR_DIRECTORY;
119 * We used to mark a file RO if it was in an RO volume, but that
120 * turns out to be impolitic in NT. See defect 10007.
123 if ((scp->unixModeBits & 0200) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
124 attrs |= SMB_ATTR_READONLY; /* Read-only */
126 if ((scp->unixModeBits & 0200) == 0)
127 attrs |= SMB_ATTR_READONLY; /* Read-only */
131 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
136 int smb_V3IsStarMask(clientchar_t *maskp)
140 while (tc = *maskp++)
141 if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
146 void OutputDebugF(clientchar_t * format, ...) {
148 clientchar_t vbuffer[1024];
150 va_start( args, format );
151 cm_ClientStrPrintfV(vbuffer, lengthof(vbuffer), format, args);
152 osi_Log1(smb_logp, "%S", osi_LogSaveClientString(smb_logp, vbuffer));
155 void OutputDebugHexDump(unsigned char * buffer, int len) {
158 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
160 OutputDebugF(_C("Hexdump length [%d]"),len);
162 for (i=0;i<len;i++) {
165 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
167 StringCchPrintfA(buf, lengthof(buf), "%5x", i);
168 memset(buf+5,' ',80);
173 j = j*3 + 7 + ((j>7)?1:0);
176 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
179 j = j + 56 + ((j>7)?1:0);
181 buf[j] = (k>32 && k<127)?k:'.';
184 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
188 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
190 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
191 SECURITY_STATUS status, istatus;
192 CredHandle creds = {0,0};
194 SecBufferDesc secOut;
202 OutputDebugF(_C("Negotiating Extended Security"));
204 status = AcquireCredentialsHandle( NULL,
205 SMB_EXT_SEC_PACKAGE_NAME,
214 if (status != SEC_E_OK) {
215 /* Really bad. We return an empty security blob */
216 OutputDebugF(_C("AcquireCredentialsHandle failed with %lX"), status);
221 secOut.pBuffers = &secTok;
222 secOut.ulVersion = SECBUFFER_VERSION;
224 secTok.BufferType = SECBUFFER_TOKEN;
226 secTok.pvBuffer = NULL;
228 ctx.dwLower = ctx.dwUpper = 0;
230 status = AcceptSecurityContext( &creds,
233 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
234 SECURITY_NETWORK_DREP,
241 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
242 OutputDebugF(_C("Completing token..."));
243 istatus = CompleteAuthToken(&ctx, &secOut);
244 if ( istatus != SEC_E_OK )
245 OutputDebugF(_C("Token completion failed: %x"), istatus);
248 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
249 if (secTok.pvBuffer) {
250 *secBlobLength = secTok.cbBuffer;
251 *secBlob = malloc( secTok.cbBuffer );
252 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
255 if ( status != SEC_E_OK )
256 OutputDebugF(_C("AcceptSecurityContext status != CONTINUE %lX"), status);
259 /* Discard partial security context */
260 DeleteSecurityContext(&ctx);
262 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
264 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
265 FreeCredentialsHandle(&creds);
272 smb_GetLogonSID(HANDLE hToken, PSID *ppsid)
274 BOOL bSuccess = FALSE;
277 PTOKEN_GROUPS ptg = NULL;
279 // Verify the parameter passed in is not NULL.
283 // Get required buffer size and allocate the TOKEN_GROUPS buffer.
285 if (!GetTokenInformation( hToken, // handle to the access token
286 TokenGroups, // get information about the token's groups
287 (LPVOID) ptg, // pointer to TOKEN_GROUPS buffer
289 &dwLength // receives required buffer size
292 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
295 ptg = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(),
296 HEAP_ZERO_MEMORY, dwLength);
302 // Get the token group information from the access token.
304 if (!GetTokenInformation( hToken, // handle to the access token
305 TokenGroups, // get information about the token's groups
306 (LPVOID) ptg, // pointer to TOKEN_GROUPS buffer
307 dwLength, // size of buffer
308 &dwLength // receives required buffer size
314 // Loop through the groups to find the logon SID.
315 for (dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++) {
316 if ((ptg->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID)
318 // Found the logon SID; make a copy of it.
320 dwLength = GetLengthSid(ptg->Groups[dwIndex].Sid);
321 *ppsid = (PSID) HeapAlloc(GetProcessHeap(),
322 HEAP_ZERO_MEMORY, dwLength);
325 if (!CopySid(dwLength, *ppsid, ptg->Groups[dwIndex].Sid))
327 HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
337 // Free the buffer for the token groups.
339 HeapFree(GetProcessHeap(), 0, (LPVOID)ptg);
345 smb_GetUserSID(HANDLE hToken, PSID *ppsid)
347 BOOL bSuccess = FALSE;
349 PTOKEN_USER ptu = NULL;
351 // Verify the parameter passed in is not NULL.
355 // Get required buffer size and allocate the TOKEN_USER buffer.
357 if (!GetTokenInformation( hToken, // handle to the access token
358 TokenUser, // get information about the token's user
359 (LPVOID) ptu, // pointer to TOKEN_USER buffer
361 &dwLength // receives required buffer size
364 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
367 ptu = (PTOKEN_USER)HeapAlloc(GetProcessHeap(),
368 HEAP_ZERO_MEMORY, dwLength);
374 // Get the token group information from the access token.
376 if (!GetTokenInformation( hToken, // handle to the access token
377 TokenUser, // get information about the token's user
378 (LPVOID) ptu, // pointer to TOKEN_USER buffer
379 dwLength, // size of buffer
380 &dwLength // receives required buffer size
386 // Found the user SID; make a copy of it.
387 dwLength = GetLengthSid(ptu->User.Sid);
388 *ppsid = (PSID) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
391 if (!CopySid(dwLength, *ppsid, ptu->User.Sid))
393 HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
400 // Free the buffer for the token groups.
402 HeapFree(GetProcessHeap(), 0, (LPVOID)ptu);
408 smb_FreeSID (PSID psid)
410 HeapFree(GetProcessHeap(), 0, (LPVOID)psid);
414 struct smb_ext_context {
421 long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern,
422 char * secBlobIn, int secBlobInLength,
423 char ** secBlobOut, int * secBlobOutLength,
424 wchar_t **secSidString) {
425 SECURITY_STATUS status, istatus;
429 SecBufferDesc secBufIn;
431 SecBufferDesc secBufOut;
434 struct smb_ext_context * secCtx = NULL;
435 struct smb_ext_context * newSecCtx = NULL;
436 void * assembledBlob = NULL;
437 int assembledBlobLength = 0;
440 OutputDebugF(_C("In smb_AuthenticateUserExt"));
443 *secBlobOutLength = 0;
444 *secSidString = NULL;
446 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
447 secCtx = vcp->secCtx;
448 lock_ObtainMutex(&vcp->mx);
449 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
451 lock_ReleaseMutex(&vcp->mx);
455 OutputDebugF(_C("Received incoming token:"));
456 OutputDebugHexDump(secBlobIn,secBlobInLength);
460 OutputDebugF(_C("Continuing with existing context."));
461 creds = secCtx->creds;
464 if (secCtx->partialToken) {
465 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
466 assembledBlob = malloc(assembledBlobLength);
467 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
468 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
471 status = AcquireCredentialsHandle( NULL,
472 SMB_EXT_SEC_PACKAGE_NAME,
481 if (status != SEC_E_OK) {
482 OutputDebugF(_C("Can't acquire Credentials handle [%lX]"), status);
483 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
491 secBufIn.cBuffers = 1;
492 secBufIn.pBuffers = &secTokIn;
493 secBufIn.ulVersion = SECBUFFER_VERSION;
495 secTokIn.BufferType = SECBUFFER_TOKEN;
497 secTokIn.cbBuffer = assembledBlobLength;
498 secTokIn.pvBuffer = assembledBlob;
500 secTokIn.cbBuffer = secBlobInLength;
501 secTokIn.pvBuffer = secBlobIn;
504 secBufOut.cBuffers = 1;
505 secBufOut.pBuffers = &secTokOut;
506 secBufOut.ulVersion = SECBUFFER_VERSION;
508 secTokOut.BufferType = SECBUFFER_TOKEN;
509 secTokOut.cbBuffer = 0;
510 secTokOut.pvBuffer = NULL;
512 status = AcceptSecurityContext( &creds,
513 ((secCtx)?&ctx:NULL),
515 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
516 SECURITY_NETWORK_DREP,
523 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
524 OutputDebugF(_C("Completing token..."));
525 istatus = CompleteAuthToken(&ctx, &secBufOut);
526 if ( istatus != SEC_E_OK )
527 OutputDebugF(_C("Token completion failed: %lX"), istatus);
530 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
531 OutputDebugF(_C("Continue needed"));
533 newSecCtx = malloc(sizeof(*newSecCtx));
535 newSecCtx->creds = creds;
536 newSecCtx->ctx = ctx;
537 newSecCtx->partialToken = NULL;
538 newSecCtx->partialTokenLen = 0;
540 lock_ObtainMutex( &vcp->mx );
541 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
542 vcp->secCtx = newSecCtx;
543 lock_ReleaseMutex( &vcp->mx );
545 code = CM_ERROR_GSSCONTINUE;
548 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
549 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
550 secTokOut.pvBuffer) {
551 OutputDebugF(_C("Need to send token back to client"));
553 *secBlobOutLength = secTokOut.cbBuffer;
554 *secBlobOut = malloc(secTokOut.cbBuffer);
555 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
557 OutputDebugF(_C("Outgoing token:"));
558 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
559 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
560 OutputDebugF(_C("Incomplete message"));
562 newSecCtx = malloc(sizeof(*newSecCtx));
564 newSecCtx->creds = creds;
565 newSecCtx->ctx = ctx;
566 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
567 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
568 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
570 lock_ObtainMutex( &vcp->mx );
571 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
572 vcp->secCtx = newSecCtx;
573 lock_ReleaseMutex( &vcp->mx );
575 code = CM_ERROR_GSSCONTINUE;
578 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
581 SecPkgContext_NamesW names;
583 OutputDebugF(_C("Authentication completed"));
584 OutputDebugF(_C("Returned flags : [%lX]"), flags);
586 if (!QueryContextAttributesW(&ctx, SECPKG_ATTR_NAMES, &names)) {
587 OutputDebugF(_C("Received name [%s]"), names.sUserName);
588 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, names.sUserName);
589 cm_ClientStrLwr(usern); /* in tandem with smb_GetNormalizedUsername */
590 FreeContextBuffer(names.sUserName);
592 /* Force the user to retry if the context is invalid */
593 OutputDebugF(_C("QueryContextAttributes Names failed [%x]"), GetLastError());
594 code = CM_ERROR_BADPASSWORD;
597 /* Obtain the user's SID */
598 if (code == 0 && !QuerySecurityContextToken(((secCtx)?&ctx:NULL), &hToken)) {
600 OutputDebugF(_C("Received hToken"));
602 if (smb_GetUserSID(hToken, &pSid))
603 ConvertSidToStringSidW(pSid, secSidString);
609 OutputDebugF(_C("QueryContextToken failed [%x]"), GetLastError());
613 case SEC_E_INVALID_TOKEN:
614 OutputDebugF(_C("Returning bad password :: INVALID_TOKEN"));
616 case SEC_E_INVALID_HANDLE:
617 OutputDebugF(_C("Returning bad password :: INVALID_HANDLE"));
619 case SEC_E_LOGON_DENIED:
620 OutputDebugF(_C("Returning bad password :: LOGON_DENIED"));
622 case SEC_E_UNKNOWN_CREDENTIALS:
623 OutputDebugF(_C("Returning bad password :: UNKNOWN_CREDENTIALS"));
625 case SEC_E_NO_CREDENTIALS:
626 OutputDebugF(_C("Returning bad password :: NO_CREDENTIALS"));
628 case SEC_E_CONTEXT_EXPIRED:
629 OutputDebugF(_C("Returning bad password :: CONTEXT_EXPIRED"));
631 case SEC_E_INCOMPLETE_CREDENTIALS:
632 OutputDebugF(_C("Returning bad password :: INCOMPLETE_CREDENTIALS"));
634 case SEC_E_WRONG_PRINCIPAL:
635 OutputDebugF(_C("Returning bad password :: WRONG_PRINCIPAL"));
637 case SEC_E_TIME_SKEW:
638 OutputDebugF(_C("Returning bad password :: TIME_SKEW"));
641 OutputDebugF(_C("Returning bad password :: Status == %lX"), status);
643 code = CM_ERROR_BADPASSWORD;
647 if (secCtx->partialToken) free(secCtx->partialToken);
655 if (secTokOut.pvBuffer)
656 FreeContextBuffer(secTokOut.pvBuffer);
658 if (code != CM_ERROR_GSSCONTINUE) {
659 DeleteSecurityContext(&ctx);
660 FreeCredentialsHandle(&creds);
668 #define P_RESP_LEN 128
670 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
671 So put stuff in a struct. */
672 struct Lm20AuthBlob {
673 MSV1_0_LM20_LOGON lmlogon;
674 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
675 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
676 WCHAR accountNameW[P_LEN];
677 WCHAR primaryDomainW[P_LEN];
678 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
679 TOKEN_GROUPS tgroups;
680 TOKEN_SOURCE tsource;
683 long smb_AuthenticateUserLM(smb_vc_t *vcp, clientchar_t * accountName, clientchar_t * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
686 struct Lm20AuthBlob lmAuth;
687 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
688 QUOTA_LIMITS quotaLimits;
690 ULONG lmprofilepSize;
694 OutputDebugF(_C("In smb_AuthenticateUser for user [%s] domain [%s]"), accountName, primaryDomain);
695 OutputDebugF(_C("ciPwdLength is %d and csPwdLength is %d"), ciPwdLength, csPwdLength);
697 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
698 OutputDebugF(_C("ciPwdLength or csPwdLength is too long"));
699 return CM_ERROR_BADPASSWORD;
702 memset(&lmAuth,0,sizeof(lmAuth));
704 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
706 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
707 cm_ClientStringToUtf16(primaryDomain, -1, lmAuth.primaryDomainW, P_LEN);
708 lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
709 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
711 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
712 cm_ClientStringToUtf16(accountName, -1, lmAuth.accountNameW, P_LEN);
713 lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
714 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
716 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
717 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
718 size = MAX_COMPUTERNAME_LENGTH + 1;
719 GetComputerNameW(lmAuth.workstationW, &size);
720 lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
722 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
724 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
725 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
726 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
727 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
729 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
730 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
731 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
732 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
734 lmAuth.lmlogon.ParameterControl = 0;
736 lmAuth.tgroups.GroupCount = 0;
737 lmAuth.tgroups.Groups[0].Sid = NULL;
738 lmAuth.tgroups.Groups[0].Attributes = 0;
741 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
743 lmAuth.tsource.SourceIdentifier.HighPart = 0;
745 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
746 StringCchCopyA(lmAuth.tsource.SourceName, lengthof(lmAuth.tsource.SourceName),
747 "OpenAFS"); /* 8 char limit */
749 nts = LsaLogonUser( smb_lsaHandle,
764 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
765 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
768 OutputDebugF(_C("Return from LsaLogonUser is 0x%lX"), nts);
769 OutputDebugF(_C("Extended status is 0x%lX"), ntsEx);
771 if (nts == ERROR_SUCCESS) {
773 LsaFreeReturnBuffer(lmprofilep);
774 CloseHandle(lmToken);
778 if (nts == 0xC000015BL)
779 return CM_ERROR_BADLOGONTYPE;
780 else /* our catchall is a bad password though we could be more specific */
781 return CM_ERROR_BADPASSWORD;
785 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
786 long smb_GetNormalizedUsername(clientchar_t * usern, const clientchar_t * accountName, const clientchar_t * domainName)
788 clientchar_t * atsign;
789 const clientchar_t * domain;
791 /* check if we have sane input */
792 if ((cm_ClientStrLen(accountName) + cm_ClientStrLen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
795 /* we could get : [accountName][domainName]
801 atsign = cm_ClientStrChr(accountName, '@');
803 if (atsign) /* [user@domain][] -> [user@domain][domain] */
808 /* if for some reason the client doesn't know what domain to use,
809 it will either return an empty string or a '?' */
810 if (!domain[0] || domain[0] == '?')
811 /* Empty domains and empty usernames are usually sent from tokenless contexts.
812 This way such logins will get an empty username (easy to check). I don't know
813 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
814 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, accountName);
816 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
817 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, domain);
818 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, _C("\\"));
820 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
822 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
825 cm_ClientStrLwr(usern);
830 /* When using SMB auth, all SMB sessions have to pass through here
831 * first to authenticate the user.
833 * Caveat: If not using SMB auth, the protocol does not require
834 * sending a session setup packet, which means that we can't rely on a
835 * UID in subsequent packets. Though in practice we get one anyway.
837 /* SMB_COM_SESSION_SETUP_ANDX */
838 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
842 unsigned short newUid;
843 unsigned long caps = 0;
845 clientchar_t *s1 = _C(" ");
847 clientchar_t usern[SMB_MAX_USERNAME_LENGTH];
849 char *secBlobOut = NULL;
850 int secBlobOutLength = 0;
851 wchar_t *secSidString = 0;
852 int maxBufferSize = 0;
856 /* Check for bad conns */
857 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
858 return CM_ERROR_REMOTECONN;
861 maxBufferSize = smb_GetSMBParm(inp, 2);
862 maxMpxCount = smb_GetSMBParm(inp, 3);
863 vcNumber = smb_GetSMBParm(inp, 4);
865 osi_Log3(smb_logp, "SESSION_SETUP_ANDX with MaxBufferSize=%d, MaxMpxCount=%d, VCNumber=%d",
866 maxBufferSize, maxMpxCount, vcNumber);
868 if (maxMpxCount > smb_maxMpxRequests) {
869 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_MPX_COUNT, maxMpxCount, smb_maxMpxRequests);
870 osi_Log2(smb_logp, "MaxMpxCount for client is too large (Client=%d, Server=%d)",
871 maxMpxCount, smb_maxMpxRequests);
874 if (maxBufferSize < SMB_PACKETSIZE) {
875 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_BUFFER_SIZE, maxBufferSize, SMB_PACKETSIZE);
876 osi_Log2(smb_logp, "MaxBufferSize for client is too small (Client=%d, Server=%d)",
877 maxBufferSize, SMB_PACKETSIZE);
881 osi_Log0(smb_logp, "Resetting all VCs");
882 smb_MarkAllVCsDead(vcp);
885 if (vcp->flags & SMB_VCFLAG_USENT) {
886 if (smb_authType == SMB_AUTH_EXTENDED) {
887 /* extended authentication */
891 OutputDebugF(_C("NT Session Setup: Extended"));
893 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
894 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
897 secBlobInLength = smb_GetSMBParm(inp, 7);
898 secBlobIn = smb_GetSMBData(inp, NULL);
900 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength, &secSidString);
902 if (code == CM_ERROR_GSSCONTINUE) {
905 smb_SetSMBParm(outp, 2, 0);
906 smb_SetSMBParm(outp, 3, secBlobOutLength);
908 tp = smb_GetSMBData(outp, NULL);
909 if (secBlobOutLength) {
910 memcpy(tp, secBlobOut, secBlobOutLength);
912 tp += secBlobOutLength;
913 cb_data += secBlobOutLength;
915 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
916 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
917 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
919 smb_SetSMBDataLength(outp, cb_data);
922 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
924 unsigned ciPwdLength, csPwdLength;
926 clientchar_t *accountName;
927 clientchar_t *primaryDomain;
930 if (smb_authType == SMB_AUTH_NTLM)
931 OutputDebugF(_C("NT Session Setup: NTLM"));
933 OutputDebugF(_C("NT Session Setup: None"));
935 /* TODO: parse for extended auth as well */
936 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
937 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
939 tp = smb_GetSMBData(inp, &datalen);
941 OutputDebugF(_C("Session packet data size [%d]"),datalen);
948 accountName = smb_ParseString(inp, tp, &tp, 0);
949 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
951 OutputDebugF(_C("Account Name: %s"),accountName);
952 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
953 OutputDebugF(_C("Case Sensitive Password: %s"),
954 csPwd && csPwd[0] ? _C("yes") : _C("no"));
955 OutputDebugF(_C("Case Insensitive Password: %s"),
956 ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
958 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
959 /* shouldn't happen */
960 code = CM_ERROR_BADSMB;
961 goto after_read_packet;
964 /* capabilities are only valid for first session packet */
965 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
966 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
969 if (smb_authType == SMB_AUTH_NTLM) {
970 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
972 OutputDebugF(_C("LM authentication failed [%d]"), code);
974 OutputDebugF(_C("LM authentication succeeded"));
978 unsigned ciPwdLength;
980 clientchar_t *accountName;
981 clientchar_t *primaryDomain;
983 switch ( smb_authType ) {
984 case SMB_AUTH_EXTENDED:
985 OutputDebugF(_C("V3 Session Setup: Extended"));
988 OutputDebugF(_C("V3 Session Setup: NTLM"));
991 OutputDebugF(_C("V3 Session Setup: None"));
993 ciPwdLength = smb_GetSMBParm(inp, 7);
994 tp = smb_GetSMBData(inp, NULL);
998 accountName = smb_ParseString(inp, tp, &tp, 0);
999 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
1001 OutputDebugF(_C("Account Name: %s"),accountName);
1002 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
1003 OutputDebugF(_C("Case Insensitive Password: %s"), ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
1005 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
1006 /* shouldn't happen */
1007 code = CM_ERROR_BADSMB;
1008 goto after_read_packet;
1011 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
1014 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
1015 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
1017 OutputDebugF(_C("LM authentication failed [%d]"), code);
1019 OutputDebugF(_C("LM authentication succeeded"));
1024 /* note down that we received a session setup X and set the capabilities flag */
1025 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
1026 lock_ObtainMutex(&vcp->mx);
1027 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
1028 /* for the moment we can only deal with NTSTATUS */
1029 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
1030 vcp->flags |= SMB_VCFLAG_STATUS32;
1034 if ((caps & NTNEGOTIATE_CAPABILITY_UNICODE) && smb_UseUnicode) {
1035 vcp->flags |= SMB_VCFLAG_USEUNICODE;
1038 lock_ReleaseMutex(&vcp->mx);
1041 /* code would be non-zero if there was an authentication failure.
1042 Ideally we would like to invalidate the uid for this session or break
1043 early to avoid accidently stealing someone else's tokens. */
1047 LocalFree(secSidString);
1052 * If the SidString for the user could be obtained, use that
1056 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, secSidString);
1060 OutputDebugF(_C("Received username=[%s]"), usern);
1062 /* On Windows 2000, this function appears to be called more often than
1063 it is expected to be called. This resulted in multiple smb_user_t
1064 records existing all for the same user session which results in all
1065 of the users tokens disappearing.
1067 To avoid this problem, we look for an existing smb_user_t record
1068 based on the users name, and use that one if we find it.
1071 uidp = smb_FindUserByNameThisSession(vcp, usern);
1072 if (uidp) { /* already there, so don't create a new one */
1074 newUid = uidp->userID;
1075 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
1076 vcp->lana,vcp->lsn,newUid);
1077 smb_ReleaseUID(uidp);
1082 /* do a global search for the username/machine name pair */
1083 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
1084 lock_ObtainMutex(&unp->mx);
1085 if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
1086 /* clear the afslogon flag so that the tickets can now
1087 * be freed when the refCount returns to zero.
1089 unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
1092 unp->flags |= SMB_USERNAMEFLAG_SID;
1093 lock_ReleaseMutex(&unp->mx);
1095 /* Create a new UID and cm_user_t structure */
1098 userp = cm_NewUser();
1099 cm_HoldUserVCRef(userp);
1100 lock_ObtainMutex(&vcp->mx);
1101 if (!vcp->uidCounter)
1102 vcp->uidCounter++; /* handle unlikely wraparounds */
1103 newUid = (cm_ClientStrLen(usern)==0)?0:vcp->uidCounter++;
1104 lock_ReleaseMutex(&vcp->mx);
1106 /* Create a new smb_user_t structure and connect them up */
1107 lock_ObtainMutex(&unp->mx);
1109 lock_ReleaseMutex(&unp->mx);
1111 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
1113 lock_ObtainMutex(&uidp->mx);
1115 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
1116 lock_ReleaseMutex(&uidp->mx);
1117 smb_ReleaseUID(uidp);
1121 /* Return UID to the client */
1122 ((smb_t *)outp)->uid = newUid;
1123 /* Also to the next chained message */
1124 ((smb_t *)inp)->uid = newUid;
1126 osi_Log3(smb_logp, "SMB3 session setup name %S creating ID %d%S",
1127 osi_LogSaveClientString(smb_logp, usern), newUid,
1128 osi_LogSaveClientString(smb_logp, s1));
1130 smb_SetSMBParm(outp, 2, 0);
1132 if (vcp->flags & SMB_VCFLAG_USENT) {
1133 if (smb_authType == SMB_AUTH_EXTENDED) {
1136 smb_SetSMBParm(outp, 3, secBlobOutLength);
1138 tp = smb_GetSMBData(outp, NULL);
1139 if (secBlobOutLength) {
1140 memcpy(tp, secBlobOut, secBlobOutLength);
1142 tp += secBlobOutLength;
1143 cb_data += secBlobOutLength;
1146 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
1147 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
1148 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
1150 smb_SetSMBDataLength(outp, cb_data);
1152 smb_SetSMBDataLength(outp, 0);
1155 if (smb_authType == SMB_AUTH_EXTENDED) {
1158 tp = smb_GetSMBData(outp, NULL);
1160 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
1161 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
1162 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
1164 smb_SetSMBDataLength(outp, cb_data);
1166 smb_SetSMBDataLength(outp, 0);
1171 LocalFree(secSidString);
1175 /* SMB_COM_LOGOFF_ANDX */
1176 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1180 /* find the tree and free it */
1181 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1183 smb_username_t * unp;
1185 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %S", uidp->userID,
1186 osi_LogSaveClientString(smb_logp, (uidp->unp) ? uidp->unp->name: _C(" ")));
1188 lock_ObtainMutex(&uidp->mx);
1189 uidp->flags |= SMB_USERFLAG_DELETE;
1191 * it doesn't get deleted right away
1192 * because the vcp points to it
1195 lock_ReleaseMutex(&uidp->mx);
1198 /* we can't do this. we get logoff messages prior to a session
1199 * disconnect even though it doesn't mean the user is logging out.
1200 * we need to create a new pioctl and EventLogoff handler to set
1201 * SMB_USERNAMEFLAG_LOGOFF.
1203 if (unp && smb_LogoffTokenTransfer) {
1204 lock_ObtainMutex(&unp->mx);
1205 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
1206 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
1207 lock_ReleaseMutex(&unp->mx);
1211 smb_ReleaseUID(uidp);
1214 osi_Log0(smb_logp, "SMB3 user logoffX");
1216 smb_SetSMBDataLength(outp, 0);
1220 #define SMB_SUPPORT_SEARCH_BITS 0x0001
1221 #define SMB_SHARE_IS_IN_DFS 0x0002
1223 /* SMB_COM_TREE_CONNECT_ANDX */
1224 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1227 smb_user_t *uidp = NULL;
1228 unsigned short newTid;
1229 clientchar_t shareName[AFSPATHMAX];
1230 clientchar_t *sharePath;
1233 clientchar_t *slashp;
1234 clientchar_t *pathp;
1235 clientchar_t *passwordp;
1236 clientchar_t *servicep;
1237 cm_user_t *userp = NULL;
1240 osi_Log0(smb_logp, "SMB3 receive tree connect");
1242 /* parse input parameters */
1243 tp = smb_GetSMBData(inp, NULL);
1244 passwordp = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1245 pathp = smb_ParseString(inp, tp, &tp, SMB_STRF_ANSIPATH);
1246 servicep = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1248 slashp = cm_ClientStrRChr(pathp, '\\');
1250 return CM_ERROR_BADSMB;
1252 cm_ClientStrCpy(shareName, lengthof(shareName), slashp+1);
1254 osi_Log3(smb_logp, "Tree connect pathp[%S] shareName[%S] service[%S]",
1255 osi_LogSaveClientString(smb_logp, pathp),
1256 osi_LogSaveClientString(smb_logp, shareName),
1257 osi_LogSaveClientString(smb_logp, servicep));
1259 if (cm_ClientStrCmp(servicep, _C("IPC")) == 0 ||
1260 cm_ClientStrCmp(shareName, _C("IPC$")) == 0) {
1262 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1265 return CM_ERROR_NOIPC;
1269 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1271 userp = smb_GetUserFromUID(uidp);
1273 lock_ObtainMutex(&vcp->mx);
1274 newTid = vcp->tidCounter++;
1275 lock_ReleaseMutex(&vcp->mx);
1277 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1280 if (!cm_ClientStrCmp(shareName, _C("*.")))
1281 cm_ClientStrCpy(shareName, lengthof(shareName), _C("all"));
1282 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1285 smb_ReleaseUID(uidp);
1286 smb_ReleaseTID(tidp, FALSE);
1287 return CM_ERROR_BADSHARENAME;
1290 if (vcp->flags & SMB_VCFLAG_USENT)
1292 int policy = smb_FindShareCSCPolicy(shareName);
1295 DWORD dwAdvertiseDFS = 0, dwSize = sizeof(DWORD);
1297 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1298 0, KEY_QUERY_VALUE, &parmKey);
1299 if (code == ERROR_SUCCESS) {
1300 code = RegQueryValueEx(parmKey, "AdvertiseDFS", NULL, NULL,
1301 (BYTE *)&dwAdvertiseDFS, &dwSize);
1302 if (code != ERROR_SUCCESS)
1304 RegCloseKey (parmKey);
1306 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1307 (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
1311 smb_SetSMBParm(outp, 2, 0);
1315 smb_ReleaseUID(uidp);
1317 lock_ObtainMutex(&tidp->mx);
1318 tidp->userp = userp;
1319 tidp->pathname = sharePath;
1321 tidp->flags |= SMB_TIDFLAG_IPC;
1322 lock_ReleaseMutex(&tidp->mx);
1323 smb_ReleaseTID(tidp, FALSE);
1325 ((smb_t *)outp)->tid = newTid;
1326 ((smb_t *)inp)->tid = newTid;
1327 tp = smb_GetSMBData(outp, NULL);
1331 tp = smb_UnparseString(outp, tp, _C("A:"), &cb_data, SMB_STRF_FORCEASCII);
1332 tp = smb_UnparseString(outp, tp, _C("AFS"), &cb_data, 0);
1333 smb_SetSMBDataLength(outp, cb_data);
1337 tp = smb_UnparseString(outp, tp, _C("IPC"), &cb_data, SMB_STRF_FORCEASCII);
1338 smb_SetSMBDataLength(outp, cb_data);
1341 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1345 /* must be called with global tran lock held */
1346 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1348 smb_tran2Packet_t *tp;
1351 smbp = (smb_t *) inp->data;
1352 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1353 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1359 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1360 int totalParms, int totalData)
1362 smb_tran2Packet_t *tp;
1365 smbp = (smb_t *) inp->data;
1366 tp = malloc(sizeof(*tp));
1367 memset(tp, 0, sizeof(*tp));
1370 tp->curData = tp->curParms = 0;
1371 tp->totalData = totalData;
1372 tp->totalParms = totalParms;
1373 tp->tid = smbp->tid;
1374 tp->mid = smbp->mid;
1375 tp->uid = smbp->uid;
1376 tp->pid = smbp->pid;
1377 tp->res[0] = smbp->res[0];
1378 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1379 if (totalParms != 0)
1380 tp->parmsp = malloc(totalParms);
1382 tp->datap = malloc(totalData);
1383 if (smbp->com == 0x25 || smbp->com == 0x26)
1386 tp->opcode = smb_GetSMBParm(inp, 14);
1389 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1391 if (WANTS_UNICODE(inp) && (vcp->flags & SMB_VCFLAG_USEUNICODE))
1392 tp->flags |= SMB_TRAN2PFLAG_USEUNICODE;
1397 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1398 smb_tran2Packet_t *inp, smb_packet_t *outp,
1399 int totalParms, int totalData)
1401 smb_tran2Packet_t *tp;
1402 unsigned short parmOffset;
1403 unsigned short dataOffset;
1404 unsigned short dataAlign;
1406 tp = malloc(sizeof(*tp));
1407 memset(tp, 0, sizeof(*tp));
1410 tp->curData = tp->curParms = 0;
1411 tp->totalData = totalData;
1412 tp->totalParms = totalParms;
1413 tp->oldTotalParms = totalParms;
1418 tp->res[0] = inp->res[0];
1419 tp->opcode = inp->opcode;
1423 * We calculate where the parameters and data will start.
1424 * This calculation must parallel the calculation in
1425 * smb_SendTran2Packet.
1428 parmOffset = 10*2 + 35;
1429 parmOffset++; /* round to even */
1430 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1432 dataOffset = parmOffset + totalParms;
1433 dataAlign = dataOffset & 2; /* quad-align */
1434 dataOffset += dataAlign;
1435 tp->datap = outp->data + dataOffset;
1440 /* free a tran2 packet */
1441 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1444 smb_ReleaseVC(t2p->vcp);
1447 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1457 while (t2p->stringsp) {
1461 t2p->stringsp = ns->nextp;
1467 clientchar_t *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
1468 char ** chainpp, int flags)
1473 if (!(p->flags & SMB_TRAN2PFLAG_USEUNICODE))
1474 flags |= SMB_STRF_FORCEASCII;
1477 cb = p->totalParms - (inp - (char *)p->parmsp);
1478 if (inp < (char *) p->parmsp ||
1479 inp >= ((char *) p->parmsp) + p->totalParms) {
1480 #ifdef DEBUG_UNICODE
1486 return smb_ParseStringBuf((unsigned char *) p->parmsp, &p->stringsp,
1487 inp, &cb, chainpp, flags);
1490 /* called with a VC, an input packet to respond to, and an error code.
1491 * sends an error response.
1493 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1494 smb_packet_t *tp, long code)
1497 unsigned short errCode;
1498 unsigned char errClass;
1499 unsigned long NTStatus;
1501 if (vcp->flags & SMB_VCFLAG_STATUS32)
1502 smb_MapNTError(code, &NTStatus);
1504 smb_MapCoreError(code, vcp, &errCode, &errClass);
1506 smb_FormatResponsePacket(vcp, NULL, tp);
1507 smbp = (smb_t *) tp;
1509 /* We can handle long names */
1510 if (vcp->flags & SMB_VCFLAG_USENT)
1511 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1513 /* now copy important fields from the tran 2 packet */
1514 smbp->com = t2p->com;
1515 smbp->tid = t2p->tid;
1516 smbp->mid = t2p->mid;
1517 smbp->pid = t2p->pid;
1518 smbp->uid = t2p->uid;
1519 smbp->res[0] = t2p->res[0];
1520 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1521 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1522 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1523 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1524 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1525 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1528 smbp->rcls = errClass;
1529 smbp->errLow = (unsigned char) (errCode & 0xff);
1530 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1534 smb_SendPacket(vcp, tp);
1537 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1540 unsigned short parmOffset;
1541 unsigned short dataOffset;
1542 unsigned short totalLength;
1543 unsigned short dataAlign;
1546 smb_FormatResponsePacket(vcp, NULL, tp);
1547 smbp = (smb_t *) tp;
1549 /* We can handle long names */
1550 if (vcp->flags & SMB_VCFLAG_USENT)
1551 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1553 /* now copy important fields from the tran 2 packet */
1554 smbp->com = t2p->com;
1555 smbp->tid = t2p->tid;
1556 smbp->mid = t2p->mid;
1557 smbp->pid = t2p->pid;
1558 smbp->uid = t2p->uid;
1559 smbp->res[0] = t2p->res[0];
1561 if (t2p->error_code) {
1562 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1563 unsigned long NTStatus;
1565 smb_MapNTError(t2p->error_code, &NTStatus);
1567 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1568 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1569 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1570 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1571 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1574 unsigned short errCode;
1575 unsigned char errClass;
1577 smb_MapCoreError(t2p->error_code, vcp, &errCode, &errClass);
1579 smbp->rcls = errClass;
1580 smbp->errLow = (unsigned char) (errCode & 0xff);
1581 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1585 totalLength = 1 + t2p->totalData + t2p->totalParms;
1587 /* now add the core parameters (tran2 info) to the packet */
1588 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1589 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1590 smb_SetSMBParm(tp, 2, 0); /* reserved */
1591 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1592 parmOffset = 10*2 + 35; /* parm offset in packet */
1593 parmOffset++; /* round to even */
1594 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1595 * hdr, bcc and wct */
1596 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1597 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1598 dataOffset = parmOffset + t2p->oldTotalParms;
1599 dataAlign = dataOffset & 2; /* quad-align */
1600 dataOffset += dataAlign;
1601 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1602 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1603 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1606 datap = smb_GetSMBData(tp, NULL);
1607 *datap++ = 0; /* we rounded to even */
1609 totalLength += dataAlign;
1610 smb_SetSMBDataLength(tp, totalLength);
1612 /* next, send the datagram */
1613 smb_SendPacket(vcp, tp);
1616 /* TRANS_SET_NMPIPE_STATE */
1617 long smb_nmpipeSetState(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1621 int pipeState = 0x0100; /* default */
1622 smb_tran2Packet_t *outp = NULL;
1625 if (p->totalParms > 0)
1626 pipeState = p->parmsp[0];
1628 osi_Log2(smb_logp, "smb_nmpipeSetState for fd[%d] with state[0x%x]", fd, pipeState);
1630 fidp = smb_FindFID(vcp, fd, 0);
1632 osi_Log2(smb_logp, "smb_nmpipeSetState Unknown SMB Fid vcp 0x%p fid %d",
1634 return CM_ERROR_BADFD;
1636 lock_ObtainMutex(&fidp->mx);
1637 if (pipeState & 0x8000)
1638 fidp->flags |= SMB_FID_BLOCKINGPIPE;
1639 if (pipeState & 0x0100)
1640 fidp->flags |= SMB_FID_MESSAGEMODEPIPE;
1641 lock_ReleaseMutex(&fidp->mx);
1643 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 0);
1644 smb_SendTran2Packet(vcp, outp, op);
1645 smb_FreeTran2Packet(outp);
1647 smb_ReleaseFID(fidp);
1652 long smb_nmpipeTransact(smb_vc_t * vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1662 osi_Log3(smb_logp, "smb_nmpipeTransact for fd[%d] %d bytes in, %d max bytes out",
1663 fd, p->totalData, p->maxReturnData);
1665 fidp = smb_FindFID(vcp, fd, 0);
1667 osi_Log2(smb_logp, "smb_nmpipeTransact Unknown SMB Fid vcp 0x%p fid %d",
1669 return CM_ERROR_BADFD;
1671 lock_ObtainMutex(&fidp->mx);
1672 if (fidp->flags & SMB_FID_RPC) {
1675 lock_ReleaseMutex(&fidp->mx);
1678 code = smb_RPCNmpipeTransact(fidp, vcp, p, op);
1679 smb_ReleaseFID(fidp);
1681 /* We only deal with RPC pipes */
1682 osi_Log2(smb_logp, "smb_nmpipeTransact Not a RPC vcp 0x%p fid %d",
1684 code = CM_ERROR_BADFD;
1691 /* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
1692 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1694 smb_tran2Packet_t *asp;
1707 /* We sometimes see 0 word count. What to do? */
1708 if (*inp->wctp == 0) {
1709 osi_Log0(smb_logp, "Transaction2 word count = 0");
1710 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1712 smb_SetSMBDataLength(outp, 0);
1713 smb_SendPacket(vcp, outp);
1717 totalParms = smb_GetSMBParm(inp, 0);
1718 totalData = smb_GetSMBParm(inp, 1);
1720 firstPacket = (inp->inCom == 0x25);
1722 /* find the packet we're reassembling */
1723 lock_ObtainWrite(&smb_globalLock);
1724 asp = smb_FindTran2Packet(vcp, inp);
1726 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1728 lock_ReleaseWrite(&smb_globalLock);
1730 /* now merge in this latest packet; start by looking up offsets */
1732 parmDisp = dataDisp = 0;
1733 parmOffset = smb_GetSMBParm(inp, 10);
1734 dataOffset = smb_GetSMBParm(inp, 12);
1735 parmCount = smb_GetSMBParm(inp, 9);
1736 dataCount = smb_GetSMBParm(inp, 11);
1737 asp->setupCount = smb_GetSMBParmByte(inp, 13);
1738 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1739 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1741 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1742 totalData, dataCount, asp->maxReturnData);
1744 if (asp->setupCount == 2) {
1745 clientchar_t * pname;
1747 asp->pipeCommand = smb_GetSMBParm(inp, 14);
1748 asp->pipeParam = smb_GetSMBParm(inp, 15);
1749 pname = smb_ParseString(inp, inp->wctp + 35, NULL, 0);
1751 asp->name = cm_ClientStrDup(pname);
1754 osi_Log2(smb_logp, " Named Pipe command id [%d] with name [%S]",
1755 asp->pipeCommand, osi_LogSaveClientString(smb_logp, asp->name));
1759 parmDisp = smb_GetSMBParm(inp, 4);
1760 parmOffset = smb_GetSMBParm(inp, 3);
1761 dataDisp = smb_GetSMBParm(inp, 7);
1762 dataOffset = smb_GetSMBParm(inp, 6);
1763 parmCount = smb_GetSMBParm(inp, 2);
1764 dataCount = smb_GetSMBParm(inp, 5);
1766 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1767 parmCount, dataCount);
1770 /* now copy the parms and data */
1771 if ( asp->totalParms > 0 && parmCount != 0 )
1773 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1775 if ( asp->totalData > 0 && dataCount != 0 ) {
1776 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1779 /* account for new bytes */
1780 asp->curData += dataCount;
1781 asp->curParms += parmCount;
1783 /* finally, if we're done, remove the packet from the queue and dispatch it */
1784 if (((asp->totalParms > 0 && asp->curParms > 0)
1785 || asp->setupCount == 2) &&
1786 asp->totalData <= asp->curData &&
1787 asp->totalParms <= asp->curParms) {
1789 /* we've received it all */
1790 lock_ObtainWrite(&smb_globalLock);
1791 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1792 lock_ReleaseWrite(&smb_globalLock);
1794 switch(asp->setupCount) {
1797 rapOp = asp->parmsp[0];
1799 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES &&
1800 smb_rapDispatchTable[rapOp].procp) {
1802 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",
1803 myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1805 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1807 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",
1808 code,vcp,vcp->lana,vcp->lsn);
1811 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]",
1812 rapOp, vcp, vcp->lana, vcp->lsn);
1814 code = CM_ERROR_BADOP;
1820 { /* Named pipe operation */
1821 osi_Log2(smb_logp, "Named Pipe: %s with name [%S]",
1822 myCrt_NmpipeDispatch(asp->pipeCommand),
1823 osi_LogSaveClientString(smb_logp, asp->name));
1825 code = CM_ERROR_BADOP;
1827 switch (asp->pipeCommand) {
1828 case SMB_TRANS_SET_NMPIPE_STATE:
1829 code = smb_nmpipeSetState(vcp, asp, outp);
1832 case SMB_TRANS_RAW_READ_NMPIPE:
1835 case SMB_TRANS_QUERY_NMPIPE_STATE:
1838 case SMB_TRANS_QUERY_NMPIPE_INFO:
1841 case SMB_TRANS_PEEK_NMPIPE:
1844 case SMB_TRANS_TRANSACT_NMPIPE:
1845 code = smb_nmpipeTransact(vcp, asp, outp);
1848 case SMB_TRANS_RAW_WRITE_NMPIPE:
1851 case SMB_TRANS_READ_NMPIPE:
1854 case SMB_TRANS_WRITE_NMPIPE:
1857 case SMB_TRANS_WAIT_NMPIPE:
1860 case SMB_TRANS_CALL_NMPIPE:
1867 code = CM_ERROR_BADOP;
1870 /* if an error is returned, we're supposed to send an error packet,
1871 * otherwise the dispatched function already did the data sending.
1872 * We give dispatched proc the responsibility since it knows how much
1873 * space to allocate.
1876 smb_SendTran2Error(vcp, asp, outp, code);
1879 /* free the input tran 2 packet */
1880 smb_FreeTran2Packet(asp);
1882 else if (firstPacket) {
1883 /* the first packet in a multi-packet request, we need to send an
1884 * ack to get more data.
1886 smb_SetSMBDataLength(outp, 0);
1887 smb_SendPacket(vcp, outp);
1893 /* ANSI versions. */
1895 #pragma pack(push, 1)
1897 typedef struct smb_rap_share_info_0 {
1898 BYTE shi0_netname[13];
1899 } smb_rap_share_info_0_t;
1901 typedef struct smb_rap_share_info_1 {
1902 BYTE shi1_netname[13];
1905 DWORD shi1_remark; /* char *shi1_remark; data offset */
1906 } smb_rap_share_info_1_t;
1908 typedef struct smb_rap_share_info_2 {
1909 BYTE shi2_netname[13];
1912 DWORD shi2_remark; /* char *shi2_remark; data offset */
1913 WORD shi2_permissions;
1915 WORD shi2_current_uses;
1916 DWORD shi2_path; /* char *shi2_path; data offset */
1917 WORD shi2_passwd[9];
1919 } smb_rap_share_info_2_t;
1921 #define SMB_RAP_MAX_SHARES 512
1923 typedef struct smb_rap_share_list {
1926 smb_rap_share_info_0_t * shares;
1927 } smb_rap_share_list_t;
1931 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1932 smb_rap_share_list_t * sp;
1934 if (dep->name[0] == '.' && (!dep->name[1] || (dep->name[1] == '.' && !dep->name[2])))
1935 return 0; /* skip over '.' and '..' */
1937 sp = (smb_rap_share_list_t *) vrockp;
1939 strncpy(sp->shares[sp->cShare].shi0_netname, dep->name, 12);
1940 sp->shares[sp->cShare].shi0_netname[12] = 0;
1944 if (sp->cShare >= sp->maxShares)
1945 return CM_ERROR_STOPNOW;
1950 /* RAP NetShareEnumRequest */
1951 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1953 smb_tran2Packet_t *outp;
1954 unsigned short * tp;
1958 int outParmsTotal; /* total parameter bytes */
1959 int outDataTotal; /* total data bytes */
1962 DWORD allSubmount = 0;
1964 DWORD nRegShares = 0;
1965 DWORD nSharesRet = 0;
1967 HKEY hkSubmount = NULL;
1968 smb_rap_share_info_1_t * shares;
1971 clientchar_t thisShare[AFSPATHMAX];
1975 smb_rap_share_list_t rootShares;
1979 cm_scache_t *rootScp;
1981 tp = p->parmsp + 1; /* skip over function number (always 0) */
1984 clientchar_t * cdescp;
1986 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1987 if (cm_ClientStrCmp(cdescp, _C("WrLeh")))
1988 return CM_ERROR_INVAL;
1989 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1990 if (cm_ClientStrCmp(cdescp, _C("B13BWz")))
1991 return CM_ERROR_INVAL;
1997 if (infoLevel != 1) {
1998 return CM_ERROR_INVAL;
2001 /* We are supposed to use the same ASCII data structure even if
2002 Unicode is negotiated, which ultimately means that the share
2003 names that we return must be at most 13 characters in length,
2004 including the NULL terminator.
2006 The RAP specification states that shares with names longer than
2007 12 characters should not be included in the enumeration.
2008 However, since we support prefix cell references and since many
2009 cell names are going to exceed 12 characters, we lie and send
2010 the first 12 characters.
2013 /* first figure out how many shares there are */
2014 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
2015 KEY_QUERY_VALUE, &hkParam);
2016 if (rv == ERROR_SUCCESS) {
2017 len = sizeof(allSubmount);
2018 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
2019 (BYTE *) &allSubmount, &len);
2020 if (rv != ERROR_SUCCESS || allSubmount != 0) {
2023 RegCloseKey (hkParam);
2026 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
2027 0, KEY_QUERY_VALUE, &hkSubmount);
2028 if (rv == ERROR_SUCCESS) {
2029 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
2030 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
2031 if (rv != ERROR_SUCCESS)
2037 /* fetch the root shares */
2038 rootShares.maxShares = SMB_RAP_MAX_SHARES;
2039 rootShares.cShare = 0;
2040 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
2044 userp = smb_GetTran2User(vcp,p);
2046 thyper.HighPart = 0;
2049 rootScp = cm_RootSCachep(userp, &req);
2050 cm_HoldSCache(rootScp);
2051 cm_ApplyDir(rootScp, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
2052 cm_ReleaseSCache(rootScp);
2054 cm_ReleaseUser(userp);
2056 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
2058 #define REMARK_LEN 1
2059 outParmsTotal = 8; /* 4 dwords */
2060 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
2061 if(outDataTotal > bufsize) {
2062 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
2063 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
2066 nSharesRet = nShares;
2069 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
2071 /* now for the submounts */
2072 shares = (smb_rap_share_info_1_t *) outp->datap;
2073 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
2075 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
2078 StringCchCopyA(shares[cshare].shi1_netname,
2079 lengthof(shares[cshare].shi1_netname), "all" );
2080 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
2081 /* type and pad are zero already */
2087 for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
2088 len = sizeof(thisShare);
2089 rv = RegEnumValueW(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
2090 if (rv == ERROR_SUCCESS &&
2091 cm_ClientStrLen(thisShare) &&
2092 (!allSubmount || cm_ClientStrCmpI(thisShare,_C("all")))) {
2093 cm_ClientStringToUtf8(thisShare, -1, shares[cshare].shi1_netname,
2094 lengthof( shares[cshare].shi1_netname ));
2095 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
2096 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
2101 nShares--; /* uncount key */
2104 RegCloseKey(hkSubmount);
2107 nonrootShares = cshare;
2109 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
2110 /* in case there are collisions with submounts, submounts have
2112 for (j=0; j < nonrootShares; j++)
2113 if (!cm_stricmp_utf8(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
2116 if (j < nonrootShares) {
2117 nShares--; /* uncount */
2121 StringCchCopyA(shares[cshare].shi1_netname, lengthof(shares[cshare].shi1_netname),
2122 rootShares.shares[i].shi0_netname);
2123 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
2128 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
2129 outp->parmsp[1] = 0;
2130 outp->parmsp[2] = cshare;
2131 outp->parmsp[3] = nShares;
2133 outp->totalData = (int)(cstrp - outp->datap);
2134 outp->totalParms = outParmsTotal;
2136 smb_SendTran2Packet(vcp, outp, op);
2137 smb_FreeTran2Packet(outp);
2139 free(rootShares.shares);
2144 /* RAP NetShareGetInfo */
2145 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2147 smb_tran2Packet_t *outp;
2148 unsigned short * tp;
2149 clientchar_t * shareName;
2150 BOOL shareFound = FALSE;
2151 unsigned short infoLevel;
2152 unsigned short bufsize;
2161 cm_scache_t *scp = NULL;
2167 tp = p->parmsp + 1; /* skip over function number (always 1) */
2170 clientchar_t * cdescp;
2172 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2173 if (cm_ClientStrCmp(cdescp, _C("zWrLh")))
2175 return CM_ERROR_INVAL;
2177 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2178 if (cm_ClientStrCmp(cdescp, _C("B13")) &&
2179 cm_ClientStrCmp(cdescp, _C("B13BWz")) &&
2180 cm_ClientStrCmp(cdescp, _C("B13BWzWWWzB9B")))
2182 return CM_ERROR_INVAL;
2184 shareName = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2192 totalData = sizeof(smb_rap_share_info_0_t);
2193 else if(infoLevel == SMB_INFO_STANDARD)
2194 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
2195 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
2196 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
2198 return CM_ERROR_INVAL;
2200 if(!cm_ClientStrCmpI(shareName, _C("all")) || !cm_ClientStrCmp(shareName,_C("*."))) {
2201 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
2202 KEY_QUERY_VALUE, &hkParam);
2203 if (rv == ERROR_SUCCESS) {
2204 len = sizeof(allSubmount);
2205 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
2206 (BYTE *) &allSubmount, &len);
2207 if (rv != ERROR_SUCCESS || allSubmount != 0) {
2210 RegCloseKey (hkParam);
2217 userp = smb_GetTran2User(vcp, p);
2219 osi_Log1(smb_logp,"ReceiveRAPNetShareGetInfo unable to resolve user [%d]", p->uid);
2220 return CM_ERROR_BADSMB;
2222 code = cm_NameI(cm_RootSCachep(userp, &req), shareName,
2223 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
2224 userp, NULL, &req, &scp);
2226 cm_ReleaseSCache(scp);
2229 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
2230 KEY_QUERY_VALUE, &hkSubmount);
2231 if (rv == ERROR_SUCCESS) {
2232 rv = RegQueryValueExW(hkSubmount, shareName, NULL, NULL, NULL, NULL);
2233 if (rv == ERROR_SUCCESS) {
2236 RegCloseKey(hkSubmount);
2242 return CM_ERROR_BADSHARENAME;
2244 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
2245 memset(outp->datap, 0, totalData);
2247 outp->parmsp[0] = 0;
2248 outp->parmsp[1] = 0;
2249 outp->parmsp[2] = totalData;
2251 if (infoLevel == 0) {
2252 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
2253 cm_ClientStringToUtf8(shareName, -1, info->shi0_netname,
2254 lengthof(info->shi0_netname));
2255 } else if(infoLevel == SMB_INFO_STANDARD) {
2256 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
2257 cm_ClientStringToUtf8(shareName, -1, info->shi1_netname, lengthof(info->shi1_netname));
2258 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
2259 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
2260 /* type and pad are already zero */
2261 } else { /* infoLevel==2 */
2262 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
2263 cm_ClientStringToUtf8(shareName, -1, info->shi2_netname, lengthof(info->shi2_netname));
2264 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
2265 info->shi2_permissions = ACCESS_ALL;
2266 info->shi2_max_uses = (unsigned short) -1;
2267 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
2270 outp->totalData = totalData;
2271 outp->totalParms = totalParam;
2273 smb_SendTran2Packet(vcp, outp, op);
2274 smb_FreeTran2Packet(outp);
2279 #pragma pack(push, 1)
2281 typedef struct smb_rap_wksta_info_10 {
2282 DWORD wki10_computername; /*char *wki10_computername;*/
2283 DWORD wki10_username; /* char *wki10_username; */
2284 DWORD wki10_langroup; /* char *wki10_langroup;*/
2285 BYTE wki10_ver_major;
2286 BYTE wki10_ver_minor;
2287 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
2288 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
2289 } smb_rap_wksta_info_10_t;
2293 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2295 smb_tran2Packet_t *outp;
2299 unsigned short * tp;
2302 smb_rap_wksta_info_10_t * info;
2306 tp = p->parmsp + 1; /* Skip over function number */
2309 clientchar_t * cdescp;
2311 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2312 SMB_STRF_FORCEASCII);
2313 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2314 return CM_ERROR_INVAL;
2316 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2317 SMB_STRF_FORCEASCII);
2318 if (cm_ClientStrCmp(cdescp, _C("zzzBBzz")))
2319 return CM_ERROR_INVAL;
2325 if (infoLevel != 10) {
2326 return CM_ERROR_INVAL;
2332 totalData = sizeof(*info) + /* info */
2333 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
2334 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
2335 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
2336 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
2337 1; /* wki10_oth_domains (null)*/
2339 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2341 memset(outp->parmsp,0,totalParams);
2342 memset(outp->datap,0,totalData);
2344 info = (smb_rap_wksta_info_10_t *) outp->datap;
2345 cstrp = (char *) (info + 1);
2347 info->wki10_computername = (DWORD) (cstrp - outp->datap);
2348 StringCbCopyA(cstrp, totalData, smb_localNamep);
2349 cstrp += strlen(cstrp) + 1;
2351 info->wki10_username = (DWORD) (cstrp - outp->datap);
2352 uidp = smb_FindUID(vcp, p->uid, 0);
2354 lock_ObtainMutex(&uidp->mx);
2355 if(uidp->unp && uidp->unp->name)
2356 cm_ClientStringToUtf8(uidp->unp->name, -1,
2357 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2358 lock_ReleaseMutex(&uidp->mx);
2359 smb_ReleaseUID(uidp);
2361 cstrp += strlen(cstrp) + 1;
2363 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
2364 StringCbCopyA(cstrp, totalData - (cstrp - outp->datap)*sizeof(char), "WORKGROUP");
2365 cstrp += strlen(cstrp) + 1;
2367 /* TODO: Not sure what values these should take, but these work */
2368 info->wki10_ver_major = 5;
2369 info->wki10_ver_minor = 1;
2371 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
2372 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
2373 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2374 cstrp += strlen(cstrp) + 1;
2376 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
2377 cstrp ++; /* no other domains */
2379 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
2380 outp->parmsp[2] = outp->totalData;
2381 outp->totalParms = totalParams;
2383 smb_SendTran2Packet(vcp,outp,op);
2384 smb_FreeTran2Packet(outp);
2389 #pragma pack(push, 1)
2391 typedef struct smb_rap_server_info_0 {
2393 } smb_rap_server_info_0_t;
2395 typedef struct smb_rap_server_info_1 {
2397 BYTE sv1_version_major;
2398 BYTE sv1_version_minor;
2400 DWORD sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
2401 } smb_rap_server_info_1_t;
2405 char smb_ServerComment[] = "OpenAFS Client";
2406 int smb_ServerCommentLen = sizeof(smb_ServerComment);
2408 #define SMB_SV_TYPE_SERVER 0x00000002L
2409 #define SMB_SV_TYPE_NT 0x00001000L
2410 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
2412 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2414 smb_tran2Packet_t *outp;
2418 unsigned short * tp;
2421 smb_rap_server_info_0_t * info0;
2422 smb_rap_server_info_1_t * info1;
2425 tp = p->parmsp + 1; /* Skip over function number */
2428 clientchar_t * cdescp;
2430 cdescp = smb_ParseStringT2Parm(p, (unsigned char *) tp, (char **) &tp,
2431 SMB_STRF_FORCEASCII);
2432 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2433 return CM_ERROR_INVAL;
2434 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2435 SMB_STRF_FORCEASCII);
2436 if (cm_ClientStrCmp(cdescp, _C("B16")) ||
2437 cm_ClientStrCmp(cdescp, _C("B16BBDz")))
2438 return CM_ERROR_INVAL;
2444 if (infoLevel != 0 && infoLevel != 1) {
2445 return CM_ERROR_INVAL;
2451 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
2452 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
2454 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2456 memset(outp->parmsp,0,totalParams);
2457 memset(outp->datap,0,totalData);
2459 if (infoLevel == 0) {
2460 info0 = (smb_rap_server_info_0_t *) outp->datap;
2461 cstrp = (char *) (info0 + 1);
2462 StringCchCopyA(info0->sv0_name, lengthof(info0->sv0_name), "AFS");
2463 } else { /* infoLevel == SMB_INFO_STANDARD */
2464 info1 = (smb_rap_server_info_1_t *) outp->datap;
2465 cstrp = (char *) (info1 + 1);
2466 StringCchCopyA(info1->sv1_name, lengthof(info1->sv1_name), "AFS");
2469 SMB_SV_TYPE_SERVER |
2471 SMB_SV_TYPE_SERVER_NT;
2473 info1->sv1_version_major = 5;
2474 info1->sv1_version_minor = 1;
2475 info1->sv1_comment_or_master_browser = (DWORD) (cstrp - outp->datap);
2477 StringCbCopyA(cstrp, smb_ServerCommentLen, smb_ServerComment);
2479 cstrp += smb_ServerCommentLen / sizeof(char);
2482 totalData = (DWORD)(cstrp - outp->datap);
2483 outp->totalData = min(bufsize,totalData); /* actual data size */
2484 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
2485 outp->parmsp[2] = totalData;
2486 outp->totalParms = totalParams;
2488 smb_SendTran2Packet(vcp,outp,op);
2489 smb_FreeTran2Packet(outp);
2494 /* SMB_COM_TRANSACTION2 and SMB_COM_TRANSACTION2_SECONDARY */
2495 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2497 smb_tran2Packet_t *asp;
2508 DWORD oldTime, newTime;
2510 /* We sometimes see 0 word count. What to do? */
2511 if (*inp->wctp == 0) {
2512 osi_Log0(smb_logp, "Transaction2 word count = 0");
2513 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
2515 smb_SetSMBDataLength(outp, 0);
2516 smb_SendPacket(vcp, outp);
2520 totalParms = smb_GetSMBParm(inp, 0);
2521 totalData = smb_GetSMBParm(inp, 1);
2523 firstPacket = (inp->inCom == 0x32);
2525 /* find the packet we're reassembling */
2526 lock_ObtainWrite(&smb_globalLock);
2527 asp = smb_FindTran2Packet(vcp, inp);
2529 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
2531 lock_ReleaseWrite(&smb_globalLock);
2533 /* now merge in this latest packet; start by looking up offsets */
2535 parmDisp = dataDisp = 0;
2536 parmOffset = smb_GetSMBParm(inp, 10);
2537 dataOffset = smb_GetSMBParm(inp, 12);
2538 parmCount = smb_GetSMBParm(inp, 9);
2539 dataCount = smb_GetSMBParm(inp, 11);
2540 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2541 asp->maxReturnData = smb_GetSMBParm(inp, 3);
2543 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2544 totalData, dataCount, asp->maxReturnData);
2547 parmDisp = smb_GetSMBParm(inp, 4);
2548 parmOffset = smb_GetSMBParm(inp, 3);
2549 dataDisp = smb_GetSMBParm(inp, 7);
2550 dataOffset = smb_GetSMBParm(inp, 6);
2551 parmCount = smb_GetSMBParm(inp, 2);
2552 dataCount = smb_GetSMBParm(inp, 5);
2554 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2555 parmCount, dataCount);
2558 /* now copy the parms and data */
2559 if ( asp->totalParms > 0 && parmCount != 0 )
2561 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2563 if ( asp->totalData > 0 && dataCount != 0 ) {
2564 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2567 /* account for new bytes */
2568 asp->curData += dataCount;
2569 asp->curParms += parmCount;
2571 /* finally, if we're done, remove the packet from the queue and dispatch it */
2572 if (asp->totalParms > 0 &&
2573 asp->curParms > 0 &&
2574 asp->totalData <= asp->curData &&
2575 asp->totalParms <= asp->curParms) {
2576 /* we've received it all */
2577 lock_ObtainWrite(&smb_globalLock);
2578 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2579 lock_ReleaseWrite(&smb_globalLock);
2581 oldTime = GetTickCount();
2583 /* now dispatch it */
2584 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2585 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2586 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2589 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2590 code = CM_ERROR_BADOP;
2593 /* if an error is returned, we're supposed to send an error packet,
2594 * otherwise the dispatched function already did the data sending.
2595 * We give dispatched proc the responsibility since it knows how much
2596 * space to allocate.
2599 smb_SendTran2Error(vcp, asp, outp, code);
2602 newTime = GetTickCount();
2603 if (newTime - oldTime > 45000) {
2606 clientchar_t *treepath = NULL; /* do not free */
2607 clientchar_t *pathname = NULL;
2608 cm_fid_t afid = {0,0,0,0,0};
2610 uidp = smb_FindUID(vcp, asp->uid, 0);
2611 smb_LookupTIDPath(vcp, asp->tid, &treepath);
2612 fidp = smb_FindFID(vcp, inp->fid, 0);
2615 lock_ObtainMutex(&fidp->mx);
2616 if (fidp->NTopen_pathp)
2617 pathname = fidp->NTopen_pathp;
2619 afid = fidp->scp->fid;
2621 if (inp->stringsp->wdata)
2622 pathname = inp->stringsp->wdata;
2625 afsi_log("Request %s duration %d ms user 0x%x \"%S\" pid 0x%x mid 0x%x tid 0x%x \"%S\" path? \"%S\" afid (%d.%d.%d.%d)",
2626 myCrt_2Dispatch(asp->opcode), newTime - oldTime,
2627 asp->uid, uidp ? uidp->unp->name : NULL,
2628 asp->pid, asp->mid, asp->tid,
2631 afid.cell, afid.volume, afid.vnode, afid.unique);
2634 lock_ReleaseMutex(&fidp->mx);
2637 smb_ReleaseUID(uidp);
2639 smb_ReleaseFID(fidp);
2642 /* free the input tran 2 packet */
2643 smb_FreeTran2Packet(asp);
2645 else if (firstPacket) {
2646 /* the first packet in a multi-packet request, we need to send an
2647 * ack to get more data.
2649 smb_SetSMBDataLength(outp, 0);
2650 smb_SendPacket(vcp, outp);
2657 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2659 clientchar_t *pathp;
2660 smb_tran2Packet_t *outp;
2665 cm_scache_t *dscp; /* dir we're dealing with */
2666 cm_scache_t *scp; /* file we're creating */
2670 clientchar_t *lastNamep;
2677 int parmSlot; /* which parm we're dealing with */
2678 long returnEALength;
2679 clientchar_t *tidPathp;
2682 BOOL is_rpc = FALSE;
2683 BOOL is_ipc = FALSE;
2689 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2690 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2692 openFun = p->parmsp[6]; /* open function */
2693 excl = ((openFun & 3) == 0);
2694 trunc = ((openFun & 3) == 2); /* truncate it */
2695 openMode = (p->parmsp[1] & 0x7);
2696 openAction = 0; /* tracks what we did */
2698 attributes = p->parmsp[3];
2699 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2701 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
2704 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2706 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2707 if (code == CM_ERROR_TIDIPC) {
2709 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2712 spacep = cm_GetSpace();
2713 /* smb_StripLastComponent will strip "::$DATA" if present */
2714 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2718 /* special case magic file name for receiving IOCTL requests
2719 * (since IOCTL calls themselves aren't getting through).
2721 (cm_ClientStrCmpI(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
2723 /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional)*/
2724 (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
2726 unsigned short file_type = 0;
2727 unsigned short device_state = 0;
2729 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2732 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
2733 osi_Log2(smb_logp, "smb_ReceiveTran2Open Creating RPC Fid [%d] code [%d]",
2736 smb_ReleaseFID(fidp);
2737 smb_FreeTran2Packet(outp);
2738 osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
2742 smb_SetupIoctlFid(fidp, spacep);
2743 osi_Log1(smb_logp, "smb_ReceiveTran2Open Creating IOCTL Fid [%d]", fidp->fid);
2746 /* copy out remainder of the parms */
2748 outp->parmsp[parmSlot++] = fidp->fid;
2750 outp->parmsp[parmSlot++] = 0; /* attrs */
2751 outp->parmsp[parmSlot++] = 0; /* mod time */
2752 outp->parmsp[parmSlot++] = 0;
2753 outp->parmsp[parmSlot++] = 0; /* len */
2754 outp->parmsp[parmSlot++] = 0x7fff;
2755 outp->parmsp[parmSlot++] = openMode;
2756 outp->parmsp[parmSlot++] = file_type;
2757 outp->parmsp[parmSlot++] = device_state;
2759 /* and the final "always present" stuff */
2760 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2761 /* next write out the "unique" ID */
2762 outp->parmsp[parmSlot++] = 0x1234;
2763 outp->parmsp[parmSlot++] = 0x5678;
2764 outp->parmsp[parmSlot++] = 0;
2765 if (returnEALength) {
2766 outp->parmsp[parmSlot++] = 0;
2767 outp->parmsp[parmSlot++] = 0;
2770 outp->totalData = 0;
2771 outp->totalParms = parmSlot * 2;
2773 smb_SendTran2Packet(vcp, outp, op);
2775 smb_FreeTran2Packet(outp);
2777 /* and clean up fid reference */
2778 smb_ReleaseFID(fidp);
2784 osi_Log1(smb_logp, "Tran2Open rejecting IPC TID vcp %p", vcp);
2785 smb_FreeTran2Packet(outp);
2786 return CM_ERROR_BADFD;
2790 if (!cm_IsValidClientString(pathp)) {
2792 clientchar_t * hexp;
2794 hexp = cm_GetRawCharsAlloc(pathp, -1);
2795 osi_Log1(smb_logp, "Tran2Open rejecting invalid name. [%S]",
2796 osi_LogSaveClientString(smb_logp, hexp));
2800 osi_Log0(smb_logp, "Tran2Open rejecting invalid name");
2802 smb_FreeTran2Packet(outp);
2803 return CM_ERROR_BADNTFILENAME;
2806 #ifdef DEBUG_VERBOSE
2808 char *hexp, *asciip;
2809 asciip = (lastNamep ? lastNamep : pathp);
2810 hexp = osi_HexifyString( asciip );
2811 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2816 userp = smb_GetTran2User(vcp, p);
2817 /* In the off chance that userp is NULL, we log and abandon */
2819 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2820 smb_FreeTran2Packet(outp);
2821 return CM_ERROR_BADSMB;
2825 code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
2826 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2827 userp, tidPathp, &req, &scp);
2829 if (code == CM_ERROR_NOSUCHFILE ||
2830 code == CM_ERROR_NOSUCHPATH ||
2831 code == CM_ERROR_BPLUS_NOMATCH)
2832 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
2833 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2834 userp, tidPathp, &req, &dscp);
2835 cm_FreeSpace(spacep);
2838 cm_ReleaseUser(userp);
2839 smb_FreeTran2Packet(outp);
2844 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2845 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2846 (clientchar_t*) spacep->data);
2847 cm_ReleaseSCache(dscp);
2848 cm_ReleaseUser(userp);
2849 smb_FreeTran2Packet(outp);
2850 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2851 return CM_ERROR_PATH_NOT_COVERED;
2853 return CM_ERROR_NOSUCHPATH;
2855 #endif /* DFS_SUPPORT */
2857 /* otherwise, scp points to the parent directory. Do a lookup,
2858 * and truncate the file if we find it, otherwise we create the
2865 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2867 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2868 cm_ReleaseSCache(dscp);
2869 cm_ReleaseUser(userp);
2870 smb_FreeTran2Packet(outp);
2874 /* macintosh is expensive to program for it */
2875 cm_FreeSpace(spacep);
2878 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2879 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2880 cm_ReleaseSCache(scp);
2881 cm_ReleaseUser(userp);
2882 smb_FreeTran2Packet(outp);
2883 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2884 return CM_ERROR_PATH_NOT_COVERED;
2886 return CM_ERROR_NOSUCHPATH;
2888 #endif /* DFS_SUPPORT */
2891 /* if we get here, if code is 0, the file exists and is represented by
2892 * scp. Otherwise, we have to create it.
2895 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2898 cm_ReleaseSCache(dscp);
2899 cm_ReleaseSCache(scp);
2900 cm_ReleaseUser(userp);
2901 smb_FreeTran2Packet(outp);
2906 /* oops, file shouldn't be there */
2908 cm_ReleaseSCache(dscp);
2909 cm_ReleaseSCache(scp);
2910 cm_ReleaseUser(userp);
2911 smb_FreeTran2Packet(outp);
2912 return CM_ERROR_EXISTS;
2916 setAttr.mask = CM_ATTRMASK_LENGTH;
2917 setAttr.length.LowPart = 0;
2918 setAttr.length.HighPart = 0;
2919 code = cm_SetAttr(scp, &setAttr, userp, &req);
2920 openAction = 3; /* truncated existing file */
2923 openAction = 1; /* found existing file */
2925 else if (!(openFun & 0x10)) {
2926 /* don't create if not found */
2928 cm_ReleaseSCache(dscp);
2929 osi_assertx(scp == NULL, "null cm_scache_t");
2930 cm_ReleaseUser(userp);
2931 smb_FreeTran2Packet(outp);
2932 return CM_ERROR_NOSUCHFILE;
2935 osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2936 openAction = 2; /* created file */
2937 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2938 cm_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2939 smb_SetInitialModeBitsForFile(attributes, &setAttr);
2941 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2945 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2946 smb_NotifyChange(FILE_ACTION_ADDED,
2947 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2948 dscp, lastNamep, NULL, TRUE);
2949 } else if (!excl && code == CM_ERROR_EXISTS) {
2950 /* not an exclusive create, and someone else tried
2951 * creating it already, then we open it anyway. We
2952 * don't bother retrying after this, since if this next
2953 * fails, that means that the file was deleted after we
2954 * started this call.
2956 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2960 setAttr.mask = CM_ATTRMASK_LENGTH;
2961 setAttr.length.LowPart = 0;
2962 setAttr.length.HighPart = 0;
2963 code = cm_SetAttr(scp, &setAttr, userp,
2966 } /* lookup succeeded */
2970 /* we don't need this any longer */
2972 cm_ReleaseSCache(dscp);
2975 /* something went wrong creating or truncating the file */
2977 cm_ReleaseSCache(scp);
2978 cm_ReleaseUser(userp);
2979 smb_FreeTran2Packet(outp);
2983 /* make sure we're about to open a file */
2984 if (scp->fileType != CM_SCACHETYPE_FILE) {
2986 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2987 cm_scache_t * targetScp = 0;
2988 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2990 /* we have a more accurate file to use (the
2991 * target of the symbolic link). Otherwise,
2992 * we'll just use the symlink anyway.
2994 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2996 cm_ReleaseSCache(scp);
3000 if (scp->fileType != CM_SCACHETYPE_FILE) {
3001 cm_ReleaseSCache(scp);
3002 cm_ReleaseUser(userp);
3003 smb_FreeTran2Packet(outp);
3004 return CM_ERROR_ISDIR;
3008 /* now all we have to do is open the file itself */
3009 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3010 osi_assertx(fidp, "null smb_fid_t");
3013 lock_ObtainMutex(&fidp->mx);
3014 /* save a pointer to the vnode */
3015 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
3017 lock_ObtainWrite(&scp->rw);
3018 scp->flags |= CM_SCACHEFLAG_SMB_FID;
3019 lock_ReleaseWrite(&scp->rw);
3022 fidp->userp = userp;
3024 /* compute open mode */
3026 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
3027 if (openMode == 1 || openMode == 2)
3028 fidp->flags |= SMB_FID_OPENWRITE;
3030 /* remember that the file was newly created */
3032 fidp->flags |= SMB_FID_CREATED;
3034 lock_ReleaseMutex(&fidp->mx);
3036 smb_ReleaseFID(fidp);
3038 cm_Open(scp, 0, userp);
3040 /* copy out remainder of the parms */
3042 outp->parmsp[parmSlot++] = fidp->fid;
3043 lock_ObtainRead(&scp->rw);
3045 outp->parmsp[parmSlot++] = smb_Attributes(scp);
3046 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3047 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
3048 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
3049 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
3050 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
3051 outp->parmsp[parmSlot++] = openMode;
3052 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
3053 outp->parmsp[parmSlot++] = 0; /* IPC junk */
3055 /* and the final "always present" stuff */
3056 outp->parmsp[parmSlot++] = openAction;
3057 /* next write out the "unique" ID */
3058 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
3059 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
3060 outp->parmsp[parmSlot++] = 0;
3061 if (returnEALength) {
3062 outp->parmsp[parmSlot++] = 0;
3063 outp->parmsp[parmSlot++] = 0;
3065 lock_ReleaseRead(&scp->rw);
3066 outp->totalData = 0; /* total # of data bytes */
3067 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
3069 smb_SendTran2Packet(vcp, outp, op);
3071 smb_FreeTran2Packet(outp);
3073 cm_ReleaseUser(userp);
3074 /* leave scp held since we put it in fidp->scp */
3078 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3081 unsigned short infolevel;
3083 infolevel = p->parmsp[0];
3085 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
3087 return CM_ERROR_BAD_LEVEL;
3090 /* TRANS2_QUERY_FS_INFORMATION */
3091 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3093 smb_tran2Packet_t *outp;
3094 smb_tran2QFSInfo_t qi;
3098 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
3100 switch (p->parmsp[0]) {
3101 case SMB_INFO_ALLOCATION:
3103 responseSize = sizeof(qi.u.allocInfo);
3105 qi.u.allocInfo.FSID = 0;
3106 qi.u.allocInfo.sectorsPerAllocUnit = 1;
3107 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
3108 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
3109 qi.u.allocInfo.bytesPerSector = 1024;
3112 case SMB_INFO_VOLUME:
3114 qi.u.volumeInfo.vsn = 1234; /* Volume serial number */
3115 qi.u.volumeInfo.vnCount = 3; /* Number of characters in label (AFS\0)*/
3117 /* we're supposed to pad it out with zeroes to the end */
3118 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
3119 smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
3121 responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
3124 case SMB_QUERY_FS_VOLUME_INFO:
3125 /* FS volume info */
3126 responseSize = sizeof(qi.u.FSvolumeInfo);
3129 FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
3130 memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
3133 qi.u.FSvolumeInfo.vsn = 1234;
3134 qi.u.FSvolumeInfo.vnCount = 6; /* This is always in Unicode */
3135 memset(&qi.u.FSvolumeInfo.label, 0, sizeof(qi.u.FSvolumeInfo.label));
3136 memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
3139 case SMB_QUERY_FS_SIZE_INFO:
3141 responseSize = sizeof(qi.u.FSsizeInfo);
3143 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
3144 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
3145 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
3146 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
3147 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
3148 qi.u.FSsizeInfo.bytesPerSector = 1024;
3151 case SMB_QUERY_FS_DEVICE_INFO:
3152 /* FS device info */
3153 responseSize = sizeof(qi.u.FSdeviceInfo);
3155 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
3156 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
3159 case SMB_QUERY_FS_ATTRIBUTE_INFO:
3160 /* FS attribute info */
3162 /* attributes, defined in WINNT.H:
3163 * FILE_CASE_SENSITIVE_SEARCH 0x1
3164 * FILE_CASE_PRESERVED_NAMES 0x2
3165 * FILE_UNICODE_ON_DISK 0x4
3166 * FILE_VOLUME_QUOTAS 0x10
3167 * <no name defined> 0x4000
3168 * If bit 0x4000 is not set, Windows 95 thinks
3169 * we can't handle long (non-8.3) names,
3170 * despite our protestations to the contrary.
3172 qi.u.FSattributeInfo.attributes = 0x4003;
3173 /* The maxCompLength is supposed to be in bytes */
3175 qi.u.FSattributeInfo.attributes |= 0x04;
3177 qi.u.FSattributeInfo.maxCompLength = 255;
3178 smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
3179 qi.u.FSattributeInfo.FSnameLength = sz;
3182 sizeof(qi.u.FSattributeInfo.attributes) +
3183 sizeof(qi.u.FSattributeInfo.maxCompLength) +
3184 sizeof(qi.u.FSattributeInfo.FSnameLength) +
3189 case SMB_INFO_UNIX: /* CIFS Unix Info */
3190 case SMB_INFO_MACOS: /* Mac FS Info */
3192 return CM_ERROR_BADOP;
3195 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
3197 /* copy out return data, and set corresponding sizes */
3198 outp->totalParms = 0;
3199 outp->totalData = responseSize;
3200 memcpy(outp->datap, &qi, responseSize);
3202 /* send and free the packets */
3203 smb_SendTran2Packet(vcp, outp, op);
3204 smb_FreeTran2Packet(outp);
3209 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3211 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
3212 return CM_ERROR_BADOP;
3215 struct smb_ShortNameRock {
3216 clientchar_t *maskp;
3218 clientchar_t *shortName;
3219 size_t shortNameLen;
3222 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
3225 struct smb_ShortNameRock *rockp;
3226 normchar_t normName[MAX_PATH];
3227 clientchar_t *shortNameEnd;
3231 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t)) == 0) {
3232 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
3233 osi_LogSaveString(smb_logp, dep->name));
3237 /* compare both names and vnodes, though probably just comparing vnodes
3238 * would be safe enough.
3240 if (cm_NormStrCmpI(normName, rockp->maskp) != 0)
3242 if (ntohl(dep->fid.vnode) != rockp->vnode)
3245 /* This is the entry */
3246 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
3247 rockp->shortNameLen = shortNameEnd - rockp->shortName;
3249 return CM_ERROR_STOPNOW;
3252 long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
3253 clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
3255 struct smb_ShortNameRock rock;
3256 clientchar_t *lastNamep;
3259 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
3263 spacep = cm_GetSpace();
3264 /* smb_StripLastComponent will strip "::$DATA" if present */
3265 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
3267 code = cm_NameI(cm_RootSCachep(userp, reqp), spacep->wdata,
3268 caseFold, userp, tidPathp,
3270 cm_FreeSpace(spacep);
3275 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3276 cm_ReleaseSCache(dscp);
3277 cm_ReleaseUser(userp);
3281 return CM_ERROR_PATH_NOT_COVERED;
3283 #endif /* DFS_SUPPORT */
3285 if (!lastNamep) lastNamep = pathp;
3288 thyper.HighPart = 0;
3289 rock.shortName = shortName;
3291 rock.maskp = lastNamep;
3292 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
3294 cm_ReleaseSCache(dscp);
3297 return CM_ERROR_NOSUCHFILE;
3298 if (code == CM_ERROR_STOPNOW) {
3299 *shortNameLenp = rock.shortNameLen;
3305 /* TRANS2_QUERY_PATH_INFORMATION */
3306 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3308 smb_tran2Packet_t *outp;
3311 unsigned short infoLevel;
3312 smb_tran2QPathInfo_t qpi;
3314 unsigned short attributes;
3315 unsigned long extAttributes;
3316 clientchar_t shortName[13];
3320 cm_scache_t *scp, *dscp;
3321 int scp_rw_held = 0;
3324 clientchar_t *pathp;
3325 clientchar_t *tidPathp;
3326 clientchar_t *lastComp;
3331 infoLevel = p->parmsp[0];
3332 if (infoLevel == SMB_INFO_IS_NAME_VALID)
3334 else if (infoLevel == SMB_INFO_STANDARD)
3335 responseSize = sizeof(qpi.u.QPstandardInfo);
3336 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
3337 responseSize = sizeof(qpi.u.QPeaSizeInfo);
3338 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3339 responseSize = sizeof(qpi.u.QPfileBasicInfo);
3340 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3341 responseSize = sizeof(qpi.u.QPfileStandardInfo);
3342 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3343 responseSize = sizeof(qpi.u.QPfileEaInfo);
3344 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3345 responseSize = sizeof(qpi.u.QPfileNameInfo);
3346 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
3347 responseSize = sizeof(qpi.u.QPfileAllInfo);
3348 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
3349 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
3350 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO)
3351 responseSize = sizeof(qpi.u.QPfileStreamInfo);
3353 osi_Log2(smb_logp, "Bad Tran2QPathInfo op 0x%x infolevel 0x%x",
3354 p->opcode, infoLevel);
3355 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3358 memset(&qpi, 0, sizeof(qpi));
3360 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3361 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path \"%S\"", infoLevel,
3362 osi_LogSaveClientString(smb_logp, pathp));
3364 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3366 if (infoLevel > 0x100)
3367 outp->totalParms = 2;
3369 outp->totalParms = 0;
3371 /* now, if we're at infoLevel 6, we're only being asked to check
3372 * the syntax, so we just OK things now. In particular, we're *not*
3373 * being asked to verify anything about the state of any parent dirs.
3375 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
3376 smb_SendTran2Packet(vcp, outp, opx);
3377 smb_FreeTran2Packet(outp);
3381 userp = smb_GetTran2User(vcp, p);
3383 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
3384 smb_FreeTran2Packet(outp);
3385 return CM_ERROR_BADSMB;
3388 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3390 osi_Log1(smb_logp, "ReceiveTran2QPathInfo tid path lookup failure 0x%x", code);
3391 cm_ReleaseUser(userp);
3392 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
3393 smb_FreeTran2Packet(outp);
3397 osi_Log1(smb_logp, "T2 QPathInfo tidPathp \"%S\"",
3398 osi_LogSaveClientString(smb_logp, tidPathp));
3401 * XXX Strange hack XXX
3403 * As of Patch 7 (13 January 98), we are having the following problem:
3404 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3405 * requests to look up "desktop.ini" in all the subdirectories.
3406 * This can cause zillions of timeouts looking up non-existent cells
3407 * and volumes, especially in the top-level directory.
3409 * We have not found any way to avoid this or work around it except
3410 * to explicitly ignore the requests for mount points that haven't
3411 * yet been evaluated and for directories that haven't yet been
3414 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3415 spacep = cm_GetSpace();
3416 /* smb_StripLastComponent will strip "::$DATA" if present */
3417 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3418 #ifndef SPECIAL_FOLDERS
3419 /* Make sure that lastComp is not NULL */
3421 if (cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
3422 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
3426 userp, tidPathp, &req, &dscp);
3429 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3430 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3432 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3433 code = CM_ERROR_PATH_NOT_COVERED;
3435 code = CM_ERROR_NOSUCHPATH;
3437 #endif /* DFS_SUPPORT */
3438 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3439 code = CM_ERROR_NOSUCHFILE;
3440 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3441 cm_buf_t *bp = buf_Find(dscp, &hzero);
3447 code = CM_ERROR_NOSUCHFILE;
3449 cm_ReleaseSCache(dscp);
3451 cm_FreeSpace(spacep);
3452 cm_ReleaseUser(userp);
3453 smb_SendTran2Error(vcp, p, opx, code);
3454 smb_FreeTran2Packet(outp);
3460 #endif /* SPECIAL_FOLDERS */
3462 cm_FreeSpace(spacep);
3466 code == CM_ERROR_NOSUCHFILE ||
3467 code == CM_ERROR_NOSUCHPATH ||
3468 code == CM_ERROR_BPLUS_NOMATCH) {
3469 /* now do namei and stat, and copy out the info */
3470 code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
3471 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3475 cm_ReleaseUser(userp);
3476 smb_SendTran2Error(vcp, p, opx, code);
3477 smb_FreeTran2Packet(outp);
3482 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3483 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3484 cm_ReleaseSCache(scp);
3485 cm_ReleaseUser(userp);
3486 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3487 code = CM_ERROR_PATH_NOT_COVERED;
3489 code = CM_ERROR_NOSUCHPATH;
3490 smb_SendTran2Error(vcp, p, opx, code);
3491 smb_FreeTran2Packet(outp);
3494 #endif /* DFS_SUPPORT */
3496 lock_ObtainWrite(&scp->rw);
3498 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3499 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3503 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3505 lock_ConvertWToR(&scp->rw);
3510 /* now we have the status in the cache entry, and everything is locked.
3511 * Marshall the output data.
3513 /* for info level 108, figure out short name */
3514 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3515 code = cm_GetShortName(pathp, userp, &req,
3516 tidPathp, scp->fid.vnode, shortName,
3522 smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
3523 qpi.u.QPfileAltNameInfo.fileNameLength = len;
3524 responseSize = sizeof(unsigned long) + len;
3526 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3527 smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3528 qpi.u.QPfileNameInfo.fileNameLength = len;
3529 responseSize = sizeof(unsigned long) + len;
3531 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3532 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3533 qpi.u.QPstandardInfo.creationDateTime = dosTime;
3534 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3535 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3536 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3537 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3538 attributes = smb_Attributes(scp);
3539 qpi.u.QPstandardInfo.attributes = attributes;
3540 qpi.u.QPstandardInfo.eaSize = 0;
3542 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3543 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3544 qpi.u.QPfileBasicInfo.creationTime = ft;
3545 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3546 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3547 qpi.u.QPfileBasicInfo.changeTime = ft;
3548 extAttributes = smb_ExtAttributes(scp);
3549 qpi.u.QPfileBasicInfo.attributes = extAttributes;
3550 qpi.u.QPfileBasicInfo.reserved = 0;
3552 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3555 lock_ReleaseRead(&scp->rw);
3557 fidp = smb_FindFIDByScache(vcp, scp);
3559 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3560 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3561 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3562 qpi.u.QPfileStandardInfo.directory =
3563 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3564 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3565 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3566 qpi.u.QPfileStandardInfo.reserved = 0;
3569 lock_ObtainMutex(&fidp->mx);
3570 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3571 lock_ReleaseMutex(&fidp->mx);
3572 smb_ReleaseFID(fidp);
3574 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3576 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3577 qpi.u.QPfileEaInfo.eaSize = 0;
3579 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3582 lock_ReleaseRead(&scp->rw);
3584 fidp = smb_FindFIDByScache(vcp, scp);
3586 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3587 qpi.u.QPfileAllInfo.creationTime = ft;
3588 qpi.u.QPfileAllInfo.lastAccessTime = ft;
3589 qpi.u.QPfileAllInfo.lastWriteTime = ft;
3590 qpi.u.QPfileAllInfo.changeTime = ft;
3591 extAttributes = smb_ExtAttributes(scp);
3592 qpi.u.QPfileAllInfo.attributes = extAttributes;
3593 qpi.u.QPfileAllInfo.allocationSize = scp->length;
3594 qpi.u.QPfileAllInfo.endOfFile = scp->length;
3595 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3596 qpi.u.QPfileAllInfo.deletePending = 0;
3597 qpi.u.QPfileAllInfo.directory =
3598 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3599 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3600 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3601 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.vnode;
3602 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.unique;
3603 qpi.u.QPfileAllInfo.eaSize = 0;
3604 qpi.u.QPfileAllInfo.accessFlags = 0;
3606 lock_ObtainMutex(&fidp->mx);
3607 if (fidp->flags & SMB_FID_OPENDELETE)
3608 qpi.u.QPfileAllInfo.accessFlags |= DELETE;
3609 if (fidp->flags & SMB_FID_OPENREAD_LISTDIR)
3610 qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_READ|AFS_ACCESS_EXECUTE;
3611 if (fidp->flags & SMB_FID_OPENWRITE)
3612 qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_WRITE;
3613 if (fidp->flags & SMB_FID_DELONCLOSE)
3614 qpi.u.QPfileAllInfo.deletePending = 1;