3 * Copyright 2000, International Business Machines Corporation and others.
6 * This software has been released under the terms of the IBM Public
7 * License. For details, see the LICENSE file in the top-level source
8 * directory or online at http://www.openafs.org/dl/license10.html
11 #include <afsconfig.h>
12 #include <afs/param.h>
19 #pragma warning(disable: 4005)
21 #define SECURITY_WIN32
34 #include <WINNT\afsreg.h>
40 extern osi_hyper_t hzero;
42 smb_packet_t *smb_Directory_Watches = NULL;
43 osi_mutex_t smb_Dir_Watch_Lock;
45 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
47 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
49 /* protected by the smb_globalLock */
50 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
52 const clientchar_t **smb_ExecutableExtensions = NULL;
54 /* retrieve a held reference to a user structure corresponding to an incoming
56 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
61 uidp = smb_FindUID(vcp, inp->uid, 0);
65 up = smb_GetUserFromUID(uidp);
73 * Return boolean specifying if the path name is thought to be an
74 * executable file. For now .exe or .dll.
76 afs_uint32 smb_IsExecutableFileName(const clientchar_t *name)
80 if ( smb_ExecutableExtensions == NULL || name == NULL)
83 len = (int)cm_ClientStrLen(name);
85 for ( i=0; smb_ExecutableExtensions[i]; i++) {
86 j = len - (int)cm_ClientStrLen(smb_ExecutableExtensions[i]);
87 if (cm_ClientStrCmpI(smb_ExecutableExtensions[i], &name[j]) == 0)
95 * Return extended attributes.
96 * Right now, we aren't using any of the "new" bits, so this looks exactly
97 * like smb_Attributes() (see smb.c).
99 unsigned long smb_ExtAttributes(cm_scache_t *scp)
103 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
104 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
105 scp->fileType == CM_SCACHETYPE_INVALID)
107 attrs = SMB_ATTR_DIRECTORY;
108 #ifdef SPECIAL_FOLDERS
109 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
110 #endif /* SPECIAL_FOLDERS */
111 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
112 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
113 } else if (scp->fid.vnode & 0x1)
114 attrs = SMB_ATTR_DIRECTORY;
119 * We used to mark a file RO if it was in an RO volume, but that
120 * turns out to be impolitic in NT. See defect 10007.
123 if ((scp->unixModeBits & 0200) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
124 attrs |= SMB_ATTR_READONLY; /* Read-only */
126 if ((scp->unixModeBits & 0200) == 0)
127 attrs |= SMB_ATTR_READONLY; /* Read-only */
131 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
136 int smb_V3IsStarMask(clientchar_t *maskp)
140 while (tc = *maskp++)
141 if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
146 void OutputDebugF(clientchar_t * format, ...) {
148 clientchar_t vbuffer[1024];
150 va_start( args, format );
151 cm_ClientStrPrintfV(vbuffer, lengthof(vbuffer), format, args);
152 osi_Log1(smb_logp, "%S", osi_LogSaveClientString(smb_logp, vbuffer));
155 void OutputDebugHexDump(unsigned char * buffer, int len) {
158 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
160 OutputDebugF(_C("Hexdump length [%d]"),len);
162 for (i=0;i<len;i++) {
165 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
167 StringCchPrintfA(buf, lengthof(buf), "%5x", i);
168 memset(buf+5,' ',80);
173 j = j*3 + 7 + ((j>7)?1:0);
176 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
179 j = j + 56 + ((j>7)?1:0);
181 buf[j] = (k>32 && k<127)?k:'.';
184 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
188 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
190 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
191 SECURITY_STATUS status, istatus;
192 CredHandle creds = {0,0};
194 SecBufferDesc secOut;
202 OutputDebugF(_C("Negotiating Extended Security"));
204 status = AcquireCredentialsHandle( NULL,
205 SMB_EXT_SEC_PACKAGE_NAME,
214 if (status != SEC_E_OK) {
215 /* Really bad. We return an empty security blob */
216 OutputDebugF(_C("AcquireCredentialsHandle failed with %lX"), status);
221 secOut.pBuffers = &secTok;
222 secOut.ulVersion = SECBUFFER_VERSION;
224 secTok.BufferType = SECBUFFER_TOKEN;
226 secTok.pvBuffer = NULL;
228 ctx.dwLower = ctx.dwUpper = 0;
230 status = AcceptSecurityContext( &creds,
233 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
234 SECURITY_NETWORK_DREP,
241 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
242 OutputDebugF(_C("Completing token..."));
243 istatus = CompleteAuthToken(&ctx, &secOut);
244 if ( istatus != SEC_E_OK )
245 OutputDebugF(_C("Token completion failed: %x"), istatus);
248 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
249 if (secTok.pvBuffer) {
250 *secBlobLength = secTok.cbBuffer;
251 *secBlob = malloc( secTok.cbBuffer );
252 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
255 if ( status != SEC_E_OK )
256 OutputDebugF(_C("AcceptSecurityContext status != CONTINUE %lX"), status);
259 /* Discard partial security context */
260 DeleteSecurityContext(&ctx);
262 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
264 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
265 FreeCredentialsHandle(&creds);
272 smb_GetLogonSID(HANDLE hToken, PSID *ppsid)
274 BOOL bSuccess = FALSE;
277 PTOKEN_GROUPS ptg = NULL;
279 // Verify the parameter passed in is not NULL.
283 // Get required buffer size and allocate the TOKEN_GROUPS buffer.
285 if (!GetTokenInformation( hToken, // handle to the access token
286 TokenGroups, // get information about the token's groups
287 (LPVOID) ptg, // pointer to TOKEN_GROUPS buffer
289 &dwLength // receives required buffer size
292 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
295 ptg = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(),
296 HEAP_ZERO_MEMORY, dwLength);
302 // Get the token group information from the access token.
304 if (!GetTokenInformation( hToken, // handle to the access token
305 TokenGroups, // get information about the token's groups
306 (LPVOID) ptg, // pointer to TOKEN_GROUPS buffer
307 dwLength, // size of buffer
308 &dwLength // receives required buffer size
314 // Loop through the groups to find the logon SID.
315 for (dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++) {
316 if ((ptg->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID)
318 // Found the logon SID; make a copy of it.
320 dwLength = GetLengthSid(ptg->Groups[dwIndex].Sid);
321 *ppsid = (PSID) HeapAlloc(GetProcessHeap(),
322 HEAP_ZERO_MEMORY, dwLength);
325 if (!CopySid(dwLength, *ppsid, ptg->Groups[dwIndex].Sid))
327 HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
337 // Free the buffer for the token groups.
339 HeapFree(GetProcessHeap(), 0, (LPVOID)ptg);
345 smb_GetUserSID(HANDLE hToken, PSID *ppsid)
347 BOOL bSuccess = FALSE;
349 PTOKEN_USER ptu = NULL;
351 // Verify the parameter passed in is not NULL.
355 // Get required buffer size and allocate the TOKEN_USER buffer.
357 if (!GetTokenInformation( hToken, // handle to the access token
358 TokenUser, // get information about the token's user
359 (LPVOID) ptu, // pointer to TOKEN_USER buffer
361 &dwLength // receives required buffer size
364 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
367 ptu = (PTOKEN_USER)HeapAlloc(GetProcessHeap(),
368 HEAP_ZERO_MEMORY, dwLength);
374 // Get the token group information from the access token.
376 if (!GetTokenInformation( hToken, // handle to the access token
377 TokenUser, // get information about the token's user
378 (LPVOID) ptu, // pointer to TOKEN_USER buffer
379 dwLength, // size of buffer
380 &dwLength // receives required buffer size
386 // Found the user SID; make a copy of it.
387 dwLength = GetLengthSid(ptu->User.Sid);
388 *ppsid = (PSID) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
391 if (!CopySid(dwLength, *ppsid, ptu->User.Sid))
393 HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
400 // Free the buffer for the token groups.
402 HeapFree(GetProcessHeap(), 0, (LPVOID)ptu);
408 smb_FreeSID (PSID psid)
410 HeapFree(GetProcessHeap(), 0, (LPVOID)psid);
414 struct smb_ext_context {
421 long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern,
422 char * secBlobIn, int secBlobInLength,
423 char ** secBlobOut, int * secBlobOutLength,
424 wchar_t **secSidString) {
425 SECURITY_STATUS status, istatus;
429 SecBufferDesc secBufIn;
431 SecBufferDesc secBufOut;
434 struct smb_ext_context * secCtx = NULL;
435 struct smb_ext_context * newSecCtx = NULL;
436 void * assembledBlob = NULL;
437 int assembledBlobLength = 0;
440 OutputDebugF(_C("In smb_AuthenticateUserExt"));
443 *secBlobOutLength = 0;
444 *secSidString = NULL;
446 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
447 secCtx = vcp->secCtx;
448 lock_ObtainMutex(&vcp->mx);
449 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
451 lock_ReleaseMutex(&vcp->mx);
455 OutputDebugF(_C("Received incoming token:"));
456 OutputDebugHexDump(secBlobIn,secBlobInLength);
460 OutputDebugF(_C("Continuing with existing context."));
461 creds = secCtx->creds;
464 if (secCtx->partialToken) {
465 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
466 assembledBlob = malloc(assembledBlobLength);
467 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
468 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
471 status = AcquireCredentialsHandle( NULL,
472 SMB_EXT_SEC_PACKAGE_NAME,
481 if (status != SEC_E_OK) {
482 OutputDebugF(_C("Can't acquire Credentials handle [%lX]"), status);
483 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
491 secBufIn.cBuffers = 1;
492 secBufIn.pBuffers = &secTokIn;
493 secBufIn.ulVersion = SECBUFFER_VERSION;
495 secTokIn.BufferType = SECBUFFER_TOKEN;
497 secTokIn.cbBuffer = assembledBlobLength;
498 secTokIn.pvBuffer = assembledBlob;
500 secTokIn.cbBuffer = secBlobInLength;
501 secTokIn.pvBuffer = secBlobIn;
504 secBufOut.cBuffers = 1;
505 secBufOut.pBuffers = &secTokOut;
506 secBufOut.ulVersion = SECBUFFER_VERSION;
508 secTokOut.BufferType = SECBUFFER_TOKEN;
509 secTokOut.cbBuffer = 0;
510 secTokOut.pvBuffer = NULL;
512 status = AcceptSecurityContext( &creds,
513 ((secCtx)?&ctx:NULL),
515 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
516 SECURITY_NETWORK_DREP,
523 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
524 OutputDebugF(_C("Completing token..."));
525 istatus = CompleteAuthToken(&ctx, &secBufOut);
526 if ( istatus != SEC_E_OK )
527 OutputDebugF(_C("Token completion failed: %lX"), istatus);
530 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
531 OutputDebugF(_C("Continue needed"));
533 newSecCtx = malloc(sizeof(*newSecCtx));
535 newSecCtx->creds = creds;
536 newSecCtx->ctx = ctx;
537 newSecCtx->partialToken = NULL;
538 newSecCtx->partialTokenLen = 0;
540 lock_ObtainMutex( &vcp->mx );
541 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
542 vcp->secCtx = newSecCtx;
543 lock_ReleaseMutex( &vcp->mx );
545 code = CM_ERROR_GSSCONTINUE;
548 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
549 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
550 secTokOut.pvBuffer) {
551 OutputDebugF(_C("Need to send token back to client"));
553 *secBlobOutLength = secTokOut.cbBuffer;
554 *secBlobOut = malloc(secTokOut.cbBuffer);
555 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
557 OutputDebugF(_C("Outgoing token:"));
558 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
559 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
560 OutputDebugF(_C("Incomplete message"));
562 newSecCtx = malloc(sizeof(*newSecCtx));
564 newSecCtx->creds = creds;
565 newSecCtx->ctx = ctx;
566 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
567 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
568 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
570 lock_ObtainMutex( &vcp->mx );
571 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
572 vcp->secCtx = newSecCtx;
573 lock_ReleaseMutex( &vcp->mx );
575 code = CM_ERROR_GSSCONTINUE;
578 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
581 SecPkgContext_NamesW names;
583 OutputDebugF(_C("Authentication completed"));
584 OutputDebugF(_C("Returned flags : [%lX]"), flags);
586 if (!QueryContextAttributesW(&ctx, SECPKG_ATTR_NAMES, &names)) {
587 OutputDebugF(_C("Received name [%s]"), names.sUserName);
588 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, names.sUserName);
589 cm_ClientStrLwr(usern); /* in tandem with smb_GetNormalizedUsername */
590 FreeContextBuffer(names.sUserName);
592 /* Force the user to retry if the context is invalid */
593 OutputDebugF(_C("QueryContextAttributes Names failed [%x]"), GetLastError());
594 code = CM_ERROR_BADPASSWORD;
597 /* Obtain the user's SID */
598 if (code == 0 && !QuerySecurityContextToken(((secCtx)?&ctx:NULL), &hToken)) {
600 OutputDebugF(_C("Received hToken"));
602 if (smb_GetUserSID(hToken, &pSid))
603 ConvertSidToStringSidW(pSid, secSidString);
609 OutputDebugF(_C("QueryContextToken failed [%x]"), GetLastError());
613 case SEC_E_INVALID_TOKEN:
614 OutputDebugF(_C("Returning bad password :: INVALID_TOKEN"));
616 case SEC_E_INVALID_HANDLE:
617 OutputDebugF(_C("Returning bad password :: INVALID_HANDLE"));
619 case SEC_E_LOGON_DENIED:
620 OutputDebugF(_C("Returning bad password :: LOGON_DENIED"));
622 case SEC_E_UNKNOWN_CREDENTIALS:
623 OutputDebugF(_C("Returning bad password :: UNKNOWN_CREDENTIALS"));
625 case SEC_E_NO_CREDENTIALS:
626 OutputDebugF(_C("Returning bad password :: NO_CREDENTIALS"));
628 case SEC_E_CONTEXT_EXPIRED:
629 OutputDebugF(_C("Returning bad password :: CONTEXT_EXPIRED"));
631 case SEC_E_INCOMPLETE_CREDENTIALS:
632 OutputDebugF(_C("Returning bad password :: INCOMPLETE_CREDENTIALS"));
634 case SEC_E_WRONG_PRINCIPAL:
635 OutputDebugF(_C("Returning bad password :: WRONG_PRINCIPAL"));
637 case SEC_E_TIME_SKEW:
638 OutputDebugF(_C("Returning bad password :: TIME_SKEW"));
641 OutputDebugF(_C("Returning bad password :: Status == %lX"), status);
643 code = CM_ERROR_BADPASSWORD;
647 if (secCtx->partialToken) free(secCtx->partialToken);
655 if (secTokOut.pvBuffer)
656 FreeContextBuffer(secTokOut.pvBuffer);
658 if (code != CM_ERROR_GSSCONTINUE) {
659 DeleteSecurityContext(&ctx);
660 FreeCredentialsHandle(&creds);
668 #define P_RESP_LEN 128
670 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
671 So put stuff in a struct. */
672 struct Lm20AuthBlob {
673 MSV1_0_LM20_LOGON lmlogon;
674 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
675 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
676 WCHAR accountNameW[P_LEN];
677 WCHAR primaryDomainW[P_LEN];
678 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
679 TOKEN_GROUPS tgroups;
680 TOKEN_SOURCE tsource;
683 long smb_AuthenticateUserLM(smb_vc_t *vcp, clientchar_t * accountName, clientchar_t * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
686 struct Lm20AuthBlob lmAuth;
687 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
688 QUOTA_LIMITS quotaLimits;
690 ULONG lmprofilepSize;
694 OutputDebugF(_C("In smb_AuthenticateUser for user [%s] domain [%s]"), accountName, primaryDomain);
695 OutputDebugF(_C("ciPwdLength is %d and csPwdLength is %d"), ciPwdLength, csPwdLength);
697 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
698 OutputDebugF(_C("ciPwdLength or csPwdLength is too long"));
699 return CM_ERROR_BADPASSWORD;
702 memset(&lmAuth,0,sizeof(lmAuth));
704 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
706 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
707 cm_ClientStringToUtf16(primaryDomain, -1, lmAuth.primaryDomainW, P_LEN);
708 lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
709 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
711 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
712 cm_ClientStringToUtf16(accountName, -1, lmAuth.accountNameW, P_LEN);
713 lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
714 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
716 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
717 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
718 size = MAX_COMPUTERNAME_LENGTH + 1;
719 GetComputerNameW(lmAuth.workstationW, &size);
720 lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
722 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
724 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
725 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
726 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
727 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
729 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
730 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
731 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
732 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
734 lmAuth.lmlogon.ParameterControl = 0;
736 lmAuth.tgroups.GroupCount = 0;
737 lmAuth.tgroups.Groups[0].Sid = NULL;
738 lmAuth.tgroups.Groups[0].Attributes = 0;
741 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
743 lmAuth.tsource.SourceIdentifier.HighPart = 0;
745 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
746 StringCchCopyA(lmAuth.tsource.SourceName, lengthof(lmAuth.tsource.SourceName),
747 "OpenAFS"); /* 8 char limit */
749 nts = LsaLogonUser( smb_lsaHandle,
764 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
765 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
768 OutputDebugF(_C("Return from LsaLogonUser is 0x%lX"), nts);
769 OutputDebugF(_C("Extended status is 0x%lX"), ntsEx);
771 if (nts == ERROR_SUCCESS) {
773 LsaFreeReturnBuffer(lmprofilep);
774 CloseHandle(lmToken);
778 if (nts == 0xC000015BL)
779 return CM_ERROR_BADLOGONTYPE;
780 else /* our catchall is a bad password though we could be more specific */
781 return CM_ERROR_BADPASSWORD;
785 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
786 long smb_GetNormalizedUsername(clientchar_t * usern, const clientchar_t * accountName, const clientchar_t * domainName)
788 clientchar_t * atsign;
789 const clientchar_t * domain;
791 /* check if we have sane input */
792 if ((cm_ClientStrLen(accountName) + cm_ClientStrLen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
795 /* we could get : [accountName][domainName]
801 atsign = cm_ClientStrChr(accountName, '@');
803 if (atsign) /* [user@domain][] -> [user@domain][domain] */
808 /* if for some reason the client doesn't know what domain to use,
809 it will either return an empty string or a '?' */
810 if (!domain[0] || domain[0] == '?')
811 /* Empty domains and empty usernames are usually sent from tokenless contexts.
812 This way such logins will get an empty username (easy to check). I don't know
813 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
814 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, accountName);
816 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
817 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, domain);
818 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, _C("\\"));
820 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
822 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
825 cm_ClientStrLwr(usern);
830 /* When using SMB auth, all SMB sessions have to pass through here
831 * first to authenticate the user.
833 * Caveat: If not using SMB auth, the protocol does not require
834 * sending a session setup packet, which means that we can't rely on a
835 * UID in subsequent packets. Though in practice we get one anyway.
837 /* SMB_COM_SESSION_SETUP_ANDX */
838 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
842 unsigned short newUid;
843 unsigned long caps = 0;
845 clientchar_t *s1 = _C(" ");
847 clientchar_t usern[SMB_MAX_USERNAME_LENGTH];
849 char *secBlobOut = NULL;
850 int secBlobOutLength = 0;
851 wchar_t *secSidString = 0;
852 int maxBufferSize = 0;
856 /* Check for bad conns */
857 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
858 return CM_ERROR_REMOTECONN;
861 maxBufferSize = smb_GetSMBParm(inp, 2);
862 maxMpxCount = smb_GetSMBParm(inp, 3);
863 vcNumber = smb_GetSMBParm(inp, 4);
865 osi_Log3(smb_logp, "SESSION_SETUP_ANDX with MaxBufferSize=%d, MaxMpxCount=%d, VCNumber=%d",
866 maxBufferSize, maxMpxCount, vcNumber);
868 if (maxMpxCount > smb_maxMpxRequests) {
869 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_MPX_COUNT, maxMpxCount, smb_maxMpxRequests);
870 osi_Log2(smb_logp, "MaxMpxCount for client is too large (Client=%d, Server=%d)",
871 maxMpxCount, smb_maxMpxRequests);
874 if (maxBufferSize < SMB_PACKETSIZE) {
875 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_BUFFER_SIZE, maxBufferSize, SMB_PACKETSIZE);
876 osi_Log2(smb_logp, "MaxBufferSize for client is too small (Client=%d, Server=%d)",
877 maxBufferSize, SMB_PACKETSIZE);
881 osi_Log0(smb_logp, "Resetting all VCs");
882 smb_MarkAllVCsDead(vcp);
885 if (vcp->flags & SMB_VCFLAG_USENT) {
886 if (smb_authType == SMB_AUTH_EXTENDED) {
887 /* extended authentication */
891 OutputDebugF(_C("NT Session Setup: Extended"));
893 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
894 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
897 secBlobInLength = smb_GetSMBParm(inp, 7);
898 secBlobIn = smb_GetSMBData(inp, NULL);
900 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength, &secSidString);
902 if (code == CM_ERROR_GSSCONTINUE) {
905 smb_SetSMBParm(outp, 2, 0);
906 smb_SetSMBParm(outp, 3, secBlobOutLength);
908 tp = smb_GetSMBData(outp, NULL);
909 if (secBlobOutLength) {
910 memcpy(tp, secBlobOut, secBlobOutLength);
912 tp += secBlobOutLength;
913 cb_data += secBlobOutLength;
915 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
916 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
917 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
919 smb_SetSMBDataLength(outp, cb_data);
922 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
924 unsigned ciPwdLength, csPwdLength;
926 clientchar_t *accountName;
927 clientchar_t *primaryDomain;
930 if (smb_authType == SMB_AUTH_NTLM)
931 OutputDebugF(_C("NT Session Setup: NTLM"));
933 OutputDebugF(_C("NT Session Setup: None"));
935 /* TODO: parse for extended auth as well */
936 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
937 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
939 tp = smb_GetSMBData(inp, &datalen);
941 OutputDebugF(_C("Session packet data size [%d]"),datalen);
948 accountName = smb_ParseString(inp, tp, &tp, 0);
949 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
951 OutputDebugF(_C("Account Name: %s"),accountName);
952 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
953 OutputDebugF(_C("Case Sensitive Password: %s"),
954 csPwd && csPwd[0] ? _C("yes") : _C("no"));
955 OutputDebugF(_C("Case Insensitive Password: %s"),
956 ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
958 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
959 /* shouldn't happen */
960 code = CM_ERROR_BADSMB;
961 goto after_read_packet;
964 /* capabilities are only valid for first session packet */
965 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
966 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
969 if (smb_authType == SMB_AUTH_NTLM) {
970 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
972 OutputDebugF(_C("LM authentication failed [%d]"), code);
974 OutputDebugF(_C("LM authentication succeeded"));
978 unsigned ciPwdLength;
980 clientchar_t *accountName;
981 clientchar_t *primaryDomain;
983 switch ( smb_authType ) {
984 case SMB_AUTH_EXTENDED:
985 OutputDebugF(_C("V3 Session Setup: Extended"));
988 OutputDebugF(_C("V3 Session Setup: NTLM"));
991 OutputDebugF(_C("V3 Session Setup: None"));
993 ciPwdLength = smb_GetSMBParm(inp, 7);
994 tp = smb_GetSMBData(inp, NULL);
998 accountName = smb_ParseString(inp, tp, &tp, 0);
999 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
1001 OutputDebugF(_C("Account Name: %s"),accountName);
1002 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
1003 OutputDebugF(_C("Case Insensitive Password: %s"), ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
1005 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
1006 /* shouldn't happen */
1007 code = CM_ERROR_BADSMB;
1008 goto after_read_packet;
1011 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
1014 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
1015 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
1017 OutputDebugF(_C("LM authentication failed [%d]"), code);
1019 OutputDebugF(_C("LM authentication succeeded"));
1024 /* note down that we received a session setup X and set the capabilities flag */
1025 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
1026 lock_ObtainMutex(&vcp->mx);
1027 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
1028 /* for the moment we can only deal with NTSTATUS */
1029 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
1030 vcp->flags |= SMB_VCFLAG_STATUS32;
1034 if ((caps & NTNEGOTIATE_CAPABILITY_UNICODE) && smb_UseUnicode) {
1035 vcp->flags |= SMB_VCFLAG_USEUNICODE;
1038 lock_ReleaseMutex(&vcp->mx);
1041 /* code would be non-zero if there was an authentication failure.
1042 Ideally we would like to invalidate the uid for this session or break
1043 early to avoid accidently stealing someone else's tokens. */
1047 LocalFree(secSidString);
1052 * If the SidString for the user could be obtained, use that
1056 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, secSidString);
1060 OutputDebugF(_C("Received username=[%s]"), usern);
1062 /* On Windows 2000, this function appears to be called more often than
1063 it is expected to be called. This resulted in multiple smb_user_t
1064 records existing all for the same user session which results in all
1065 of the users tokens disappearing.
1067 To avoid this problem, we look for an existing smb_user_t record
1068 based on the users name, and use that one if we find it.
1071 uidp = smb_FindUserByNameThisSession(vcp, usern);
1072 if (uidp) { /* already there, so don't create a new one */
1074 newUid = uidp->userID;
1075 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
1076 vcp->lana,vcp->lsn,newUid);
1077 smb_ReleaseUID(uidp);
1082 /* do a global search for the username/machine name pair */
1083 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
1084 lock_ObtainMutex(&unp->mx);
1085 if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
1086 /* clear the afslogon flag so that the tickets can now
1087 * be freed when the refCount returns to zero.
1089 unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
1091 unp->flags |= SMB_USERNAMEFLAG_SID;
1094 unp->flags |= SMB_USERNAMEFLAG_SID;
1095 lock_ReleaseMutex(&unp->mx);
1097 /* Create a new UID and cm_user_t structure */
1100 userp = cm_NewUser();
1101 cm_HoldUserVCRef(userp);
1102 lock_ObtainMutex(&vcp->mx);
1103 if (!vcp->uidCounter)
1104 vcp->uidCounter++; /* handle unlikely wraparounds */
1105 newUid = (cm_ClientStrLen(usern)==0)?0:vcp->uidCounter++;
1106 lock_ReleaseMutex(&vcp->mx);
1108 /* Create a new smb_user_t structure and connect them up */
1109 lock_ObtainMutex(&unp->mx);
1111 lock_ReleaseMutex(&unp->mx);
1113 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
1115 lock_ObtainMutex(&uidp->mx);
1117 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
1118 lock_ReleaseMutex(&uidp->mx);
1119 smb_ReleaseUID(uidp);
1123 /* Return UID to the client */
1124 ((smb_t *)outp)->uid = newUid;
1125 /* Also to the next chained message */
1126 ((smb_t *)inp)->uid = newUid;
1128 osi_Log3(smb_logp, "SMB3 session setup name %S creating ID %d%S",
1129 osi_LogSaveClientString(smb_logp, usern), newUid,
1130 osi_LogSaveClientString(smb_logp, s1));
1132 smb_SetSMBParm(outp, 2, 0);
1134 if (vcp->flags & SMB_VCFLAG_USENT) {
1135 if (smb_authType == SMB_AUTH_EXTENDED) {
1138 smb_SetSMBParm(outp, 3, secBlobOutLength);
1140 tp = smb_GetSMBData(outp, NULL);
1141 if (secBlobOutLength) {
1142 memcpy(tp, secBlobOut, secBlobOutLength);
1144 tp += secBlobOutLength;
1145 cb_data += secBlobOutLength;
1148 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
1149 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
1150 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
1152 smb_SetSMBDataLength(outp, cb_data);
1154 smb_SetSMBDataLength(outp, 0);
1157 if (smb_authType == SMB_AUTH_EXTENDED) {
1160 tp = smb_GetSMBData(outp, NULL);
1162 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
1163 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
1164 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
1166 smb_SetSMBDataLength(outp, cb_data);
1168 smb_SetSMBDataLength(outp, 0);
1173 LocalFree(secSidString);
1177 /* SMB_COM_LOGOFF_ANDX */
1178 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1182 /* find the tree and free it */
1183 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1185 smb_username_t * unp;
1187 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %S", uidp->userID,
1188 osi_LogSaveClientString(smb_logp, (uidp->unp) ? uidp->unp->name: _C(" ")));
1190 lock_ObtainMutex(&uidp->mx);
1191 uidp->flags |= SMB_USERFLAG_DELETE;
1193 * it doesn't get deleted right away
1194 * because the vcp points to it
1197 lock_ReleaseMutex(&uidp->mx);
1200 /* we can't do this. we get logoff messages prior to a session
1201 * disconnect even though it doesn't mean the user is logging out.
1202 * we need to create a new pioctl and EventLogoff handler to set
1203 * SMB_USERNAMEFLAG_LOGOFF.
1205 if (unp && smb_LogoffTokenTransfer) {
1206 lock_ObtainMutex(&unp->mx);
1207 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
1208 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
1209 lock_ReleaseMutex(&unp->mx);
1213 smb_ReleaseUID(uidp);
1216 osi_Log0(smb_logp, "SMB3 user logoffX");
1218 smb_SetSMBDataLength(outp, 0);
1222 #define SMB_SUPPORT_SEARCH_BITS 0x0001
1223 #define SMB_SHARE_IS_IN_DFS 0x0002
1225 /* SMB_COM_TREE_CONNECT_ANDX */
1226 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1229 smb_user_t *uidp = NULL;
1230 unsigned short newTid;
1231 clientchar_t shareName[AFSPATHMAX];
1232 clientchar_t *sharePath;
1235 clientchar_t *slashp;
1236 clientchar_t *pathp;
1237 clientchar_t *passwordp;
1238 clientchar_t *servicep;
1239 cm_user_t *userp = NULL;
1242 osi_Log0(smb_logp, "SMB3 receive tree connect");
1244 /* parse input parameters */
1245 tp = smb_GetSMBData(inp, NULL);
1246 passwordp = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1247 pathp = smb_ParseString(inp, tp, &tp, SMB_STRF_ANSIPATH);
1248 servicep = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1250 slashp = cm_ClientStrRChr(pathp, '\\');
1252 return CM_ERROR_BADSMB;
1254 cm_ClientStrCpy(shareName, lengthof(shareName), slashp+1);
1256 osi_Log3(smb_logp, "Tree connect pathp[%S] shareName[%S] service[%S]",
1257 osi_LogSaveClientString(smb_logp, pathp),
1258 osi_LogSaveClientString(smb_logp, shareName),
1259 osi_LogSaveClientString(smb_logp, servicep));
1261 if (cm_ClientStrCmp(servicep, _C("IPC")) == 0 ||
1262 cm_ClientStrCmp(shareName, _C("IPC$")) == 0) {
1264 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1267 return CM_ERROR_NOIPC;
1271 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1273 userp = smb_GetUserFromUID(uidp);
1275 lock_ObtainMutex(&vcp->mx);
1276 newTid = vcp->tidCounter++;
1277 lock_ReleaseMutex(&vcp->mx);
1279 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1282 if (!cm_ClientStrCmp(shareName, _C("*.")))
1283 cm_ClientStrCpy(shareName, lengthof(shareName), _C("all"));
1284 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1287 smb_ReleaseUID(uidp);
1288 smb_ReleaseTID(tidp, FALSE);
1289 return CM_ERROR_BADSHARENAME;
1292 if (vcp->flags & SMB_VCFLAG_USENT)
1294 int policy = smb_FindShareCSCPolicy(shareName);
1297 DWORD dwAdvertiseDFS = 0, dwSize = sizeof(DWORD);
1299 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1300 0, KEY_QUERY_VALUE, &parmKey);
1301 if (code == ERROR_SUCCESS) {
1302 code = RegQueryValueEx(parmKey, "AdvertiseDFS", NULL, NULL,
1303 (BYTE *)&dwAdvertiseDFS, &dwSize);
1304 if (code != ERROR_SUCCESS)
1306 RegCloseKey (parmKey);
1308 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1309 (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
1313 smb_SetSMBParm(outp, 2, 0);
1317 smb_ReleaseUID(uidp);
1319 lock_ObtainMutex(&tidp->mx);
1320 tidp->userp = userp;
1321 tidp->pathname = sharePath;
1323 tidp->flags |= SMB_TIDFLAG_IPC;
1324 lock_ReleaseMutex(&tidp->mx);
1325 smb_ReleaseTID(tidp, FALSE);
1327 ((smb_t *)outp)->tid = newTid;
1328 ((smb_t *)inp)->tid = newTid;
1329 tp = smb_GetSMBData(outp, NULL);
1333 tp = smb_UnparseString(outp, tp, _C("A:"), &cb_data, SMB_STRF_FORCEASCII);
1334 tp = smb_UnparseString(outp, tp, _C("AFS"), &cb_data, 0);
1335 smb_SetSMBDataLength(outp, cb_data);
1339 tp = smb_UnparseString(outp, tp, _C("IPC"), &cb_data, SMB_STRF_FORCEASCII);
1340 smb_SetSMBDataLength(outp, cb_data);
1343 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1347 /* must be called with global tran lock held */
1348 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1350 smb_tran2Packet_t *tp;
1353 smbp = (smb_t *) inp->data;
1354 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1355 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1361 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1362 int totalParms, int totalData)
1364 smb_tran2Packet_t *tp;
1367 smbp = (smb_t *) inp->data;
1368 tp = malloc(sizeof(*tp));
1369 memset(tp, 0, sizeof(*tp));
1372 tp->curData = tp->curParms = 0;
1373 tp->totalData = totalData;
1374 tp->totalParms = totalParms;
1375 tp->tid = smbp->tid;
1376 tp->mid = smbp->mid;
1377 tp->uid = smbp->uid;
1378 tp->pid = smbp->pid;
1379 tp->res[0] = smbp->res[0];
1380 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1381 if (totalParms != 0)
1382 tp->parmsp = malloc(totalParms);
1384 tp->datap = malloc(totalData);
1385 if (smbp->com == 0x25 || smbp->com == 0x26)
1388 tp->opcode = smb_GetSMBParm(inp, 14);
1391 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1393 if (WANTS_UNICODE(inp) && (vcp->flags & SMB_VCFLAG_USEUNICODE))
1394 tp->flags |= SMB_TRAN2PFLAG_USEUNICODE;
1399 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1400 smb_tran2Packet_t *inp, smb_packet_t *outp,
1401 int totalParms, int totalData)
1403 smb_tran2Packet_t *tp;
1404 unsigned short parmOffset;
1405 unsigned short dataOffset;
1406 unsigned short dataAlign;
1408 tp = malloc(sizeof(*tp));
1409 memset(tp, 0, sizeof(*tp));
1412 tp->curData = tp->curParms = 0;
1413 tp->totalData = totalData;
1414 tp->totalParms = totalParms;
1415 tp->oldTotalParms = totalParms;
1420 tp->res[0] = inp->res[0];
1421 tp->opcode = inp->opcode;
1425 * We calculate where the parameters and data will start.
1426 * This calculation must parallel the calculation in
1427 * smb_SendTran2Packet.
1430 parmOffset = 10*2 + 35;
1431 parmOffset++; /* round to even */
1432 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1434 dataOffset = parmOffset + totalParms;
1435 dataAlign = dataOffset & 2; /* quad-align */
1436 dataOffset += dataAlign;
1437 tp->datap = outp->data + dataOffset;
1442 /* free a tran2 packet */
1443 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1446 smb_ReleaseVC(t2p->vcp);
1449 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1459 while (t2p->stringsp) {
1463 t2p->stringsp = ns->nextp;
1469 clientchar_t *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
1470 char ** chainpp, int flags)
1475 if (!(p->flags & SMB_TRAN2PFLAG_USEUNICODE))
1476 flags |= SMB_STRF_FORCEASCII;
1479 cb = p->totalParms - (inp - (char *)p->parmsp);
1480 if (inp < (char *) p->parmsp ||
1481 inp >= ((char *) p->parmsp) + p->totalParms) {
1482 #ifdef DEBUG_UNICODE
1488 return smb_ParseStringBuf((unsigned char *) p->parmsp, &p->stringsp,
1489 inp, &cb, chainpp, flags);
1492 /* called with a VC, an input packet to respond to, and an error code.
1493 * sends an error response.
1495 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1496 smb_packet_t *tp, long code)
1499 unsigned short errCode;
1500 unsigned char errClass;
1501 unsigned long NTStatus;
1503 if (vcp->flags & SMB_VCFLAG_STATUS32)
1504 smb_MapNTError(code, &NTStatus, FALSE);
1506 smb_MapCoreError(code, vcp, &errCode, &errClass);
1508 smb_FormatResponsePacket(vcp, NULL, tp);
1509 smbp = (smb_t *) tp;
1511 /* We can handle long names */
1512 if (vcp->flags & SMB_VCFLAG_USENT)
1513 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1515 /* now copy important fields from the tran 2 packet */
1516 smbp->com = t2p->com;
1517 smbp->tid = t2p->tid;
1518 smbp->mid = t2p->mid;
1519 smbp->pid = t2p->pid;
1520 smbp->uid = t2p->uid;
1521 smbp->res[0] = t2p->res[0];
1522 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1523 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1524 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1525 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1526 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1527 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1530 smbp->rcls = errClass;
1531 smbp->errLow = (unsigned char) (errCode & 0xff);
1532 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1536 smb_SendPacket(vcp, tp);
1539 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1542 unsigned short parmOffset;
1543 unsigned short dataOffset;
1544 unsigned short totalLength;
1545 unsigned short dataAlign;
1548 smb_FormatResponsePacket(vcp, NULL, tp);
1549 smbp = (smb_t *) tp;
1551 /* We can handle long names */
1552 if (vcp->flags & SMB_VCFLAG_USENT)
1553 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1555 /* now copy important fields from the tran 2 packet */
1556 smbp->com = t2p->com;
1557 smbp->tid = t2p->tid;
1558 smbp->mid = t2p->mid;
1559 smbp->pid = t2p->pid;
1560 smbp->uid = t2p->uid;
1561 smbp->res[0] = t2p->res[0];
1563 if (t2p->error_code) {
1564 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1565 unsigned long NTStatus;
1567 smb_MapNTError(t2p->error_code, &NTStatus, FALSE);
1569 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1570 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1571 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1572 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1573 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1576 unsigned short errCode;
1577 unsigned char errClass;
1579 smb_MapCoreError(t2p->error_code, vcp, &errCode, &errClass);
1581 smbp->rcls = errClass;
1582 smbp->errLow = (unsigned char) (errCode & 0xff);
1583 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1587 totalLength = 1 + t2p->totalData + t2p->totalParms;
1589 /* now add the core parameters (tran2 info) to the packet */
1590 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1591 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1592 smb_SetSMBParm(tp, 2, 0); /* reserved */
1593 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1594 parmOffset = 10*2 + 35; /* parm offset in packet */
1595 parmOffset++; /* round to even */
1596 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1597 * hdr, bcc and wct */
1598 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1599 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1600 dataOffset = parmOffset + t2p->oldTotalParms;
1601 dataAlign = dataOffset & 2; /* quad-align */
1602 dataOffset += dataAlign;
1603 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1604 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1605 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1608 datap = smb_GetSMBData(tp, NULL);
1609 *datap++ = 0; /* we rounded to even */
1611 totalLength += dataAlign;
1612 smb_SetSMBDataLength(tp, totalLength);
1614 /* next, send the datagram */
1615 smb_SendPacket(vcp, tp);
1618 /* TRANS_SET_NMPIPE_STATE */
1619 long smb_nmpipeSetState(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1623 int pipeState = 0x0100; /* default */
1624 smb_tran2Packet_t *outp = NULL;
1627 if (p->totalParms > 0)
1628 pipeState = p->parmsp[0];
1630 osi_Log2(smb_logp, "smb_nmpipeSetState for fd[%d] with state[0x%x]", fd, pipeState);
1632 fidp = smb_FindFID(vcp, fd, 0);
1634 osi_Log2(smb_logp, "smb_nmpipeSetState Unknown SMB Fid vcp 0x%p fid %d",
1636 return CM_ERROR_BADFD;
1638 lock_ObtainMutex(&fidp->mx);
1639 if (pipeState & 0x8000)
1640 fidp->flags |= SMB_FID_BLOCKINGPIPE;
1641 if (pipeState & 0x0100)
1642 fidp->flags |= SMB_FID_MESSAGEMODEPIPE;
1643 lock_ReleaseMutex(&fidp->mx);
1645 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 0);
1646 smb_SendTran2Packet(vcp, outp, op);
1647 smb_FreeTran2Packet(outp);
1649 smb_ReleaseFID(fidp);
1654 long smb_nmpipeTransact(smb_vc_t * vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1664 osi_Log3(smb_logp, "smb_nmpipeTransact for fd[%d] %d bytes in, %d max bytes out",
1665 fd, p->totalData, p->maxReturnData);
1667 fidp = smb_FindFID(vcp, fd, 0);
1669 osi_Log2(smb_logp, "smb_nmpipeTransact Unknown SMB Fid vcp 0x%p fid %d",
1671 return CM_ERROR_BADFD;
1673 lock_ObtainMutex(&fidp->mx);
1674 if (fidp->flags & SMB_FID_RPC) {
1677 lock_ReleaseMutex(&fidp->mx);
1680 code = smb_RPCNmpipeTransact(fidp, vcp, p, op);
1681 smb_ReleaseFID(fidp);
1683 /* We only deal with RPC pipes */
1684 osi_Log2(smb_logp, "smb_nmpipeTransact Not a RPC vcp 0x%p fid %d",
1686 code = CM_ERROR_BADFD;
1693 /* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
1694 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1696 smb_tran2Packet_t *asp;
1709 /* We sometimes see 0 word count. What to do? */
1710 if (*inp->wctp == 0) {
1711 osi_Log0(smb_logp, "Transaction2 word count = 0");
1712 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1714 smb_SetSMBDataLength(outp, 0);
1715 smb_SendPacket(vcp, outp);
1719 totalParms = smb_GetSMBParm(inp, 0);
1720 totalData = smb_GetSMBParm(inp, 1);
1722 firstPacket = (inp->inCom == 0x25);
1724 /* find the packet we're reassembling */
1725 lock_ObtainWrite(&smb_globalLock);
1726 asp = smb_FindTran2Packet(vcp, inp);
1728 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1730 lock_ReleaseWrite(&smb_globalLock);
1732 /* now merge in this latest packet; start by looking up offsets */
1734 parmDisp = dataDisp = 0;
1735 parmOffset = smb_GetSMBParm(inp, 10);
1736 dataOffset = smb_GetSMBParm(inp, 12);
1737 parmCount = smb_GetSMBParm(inp, 9);
1738 dataCount = smb_GetSMBParm(inp, 11);
1739 asp->setupCount = smb_GetSMBParmByte(inp, 13);
1740 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1741 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1743 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1744 totalData, dataCount, asp->maxReturnData);
1746 if (asp->setupCount == 2) {
1747 clientchar_t * pname;
1749 asp->pipeCommand = smb_GetSMBParm(inp, 14);
1750 asp->pipeParam = smb_GetSMBParm(inp, 15);
1751 pname = smb_ParseString(inp, inp->wctp + 35, NULL, 0);
1753 asp->name = cm_ClientStrDup(pname);
1756 osi_Log2(smb_logp, " Named Pipe command id [%d] with name [%S]",
1757 asp->pipeCommand, osi_LogSaveClientString(smb_logp, asp->name));
1761 parmDisp = smb_GetSMBParm(inp, 4);
1762 parmOffset = smb_GetSMBParm(inp, 3);
1763 dataDisp = smb_GetSMBParm(inp, 7);
1764 dataOffset = smb_GetSMBParm(inp, 6);
1765 parmCount = smb_GetSMBParm(inp, 2);
1766 dataCount = smb_GetSMBParm(inp, 5);
1768 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1769 parmCount, dataCount);
1772 /* now copy the parms and data */
1773 if ( asp->totalParms > 0 && parmCount != 0 )
1775 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1777 if ( asp->totalData > 0 && dataCount != 0 ) {
1778 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1781 /* account for new bytes */
1782 asp->curData += dataCount;
1783 asp->curParms += parmCount;
1785 /* finally, if we're done, remove the packet from the queue and dispatch it */
1786 if (((asp->totalParms > 0 && asp->curParms > 0)
1787 || asp->setupCount == 2) &&
1788 asp->totalData <= asp->curData &&
1789 asp->totalParms <= asp->curParms) {
1791 /* we've received it all */
1792 lock_ObtainWrite(&smb_globalLock);
1793 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1794 lock_ReleaseWrite(&smb_globalLock);
1796 switch(asp->setupCount) {
1799 rapOp = asp->parmsp[0];
1801 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES &&
1802 smb_rapDispatchTable[rapOp].procp) {
1804 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",
1805 myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1807 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1809 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",
1810 code,vcp,vcp->lana,vcp->lsn);
1813 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]",
1814 rapOp, vcp, vcp->lana, vcp->lsn);
1816 code = CM_ERROR_BADOP;
1822 { /* Named pipe operation */
1823 osi_Log2(smb_logp, "Named Pipe: %s with name [%S]",
1824 myCrt_NmpipeDispatch(asp->pipeCommand),
1825 osi_LogSaveClientString(smb_logp, asp->name));
1827 code = CM_ERROR_BADOP;
1829 switch (asp->pipeCommand) {
1830 case SMB_TRANS_SET_NMPIPE_STATE:
1831 code = smb_nmpipeSetState(vcp, asp, outp);
1834 case SMB_TRANS_RAW_READ_NMPIPE:
1837 case SMB_TRANS_QUERY_NMPIPE_STATE:
1840 case SMB_TRANS_QUERY_NMPIPE_INFO:
1843 case SMB_TRANS_PEEK_NMPIPE:
1846 case SMB_TRANS_TRANSACT_NMPIPE:
1847 code = smb_nmpipeTransact(vcp, asp, outp);
1850 case SMB_TRANS_RAW_WRITE_NMPIPE:
1853 case SMB_TRANS_READ_NMPIPE:
1856 case SMB_TRANS_WRITE_NMPIPE:
1859 case SMB_TRANS_WAIT_NMPIPE:
1862 case SMB_TRANS_CALL_NMPIPE:
1869 code = CM_ERROR_BADOP;
1872 /* if an error is returned, we're supposed to send an error packet,
1873 * otherwise the dispatched function already did the data sending.
1874 * We give dispatched proc the responsibility since it knows how much
1875 * space to allocate.
1878 smb_SendTran2Error(vcp, asp, outp, code);
1881 /* free the input tran 2 packet */
1882 smb_FreeTran2Packet(asp);
1884 else if (firstPacket) {
1885 /* the first packet in a multi-packet request, we need to send an
1886 * ack to get more data.
1888 smb_SetSMBDataLength(outp, 0);
1889 smb_SendPacket(vcp, outp);
1895 /* ANSI versions. */
1897 #pragma pack(push, 1)
1899 typedef struct smb_rap_share_info_0 {
1900 BYTE shi0_netname[13];
1901 } smb_rap_share_info_0_t;
1903 typedef struct smb_rap_share_info_1 {
1904 BYTE shi1_netname[13];
1907 DWORD shi1_remark; /* char *shi1_remark; data offset */
1908 } smb_rap_share_info_1_t;
1910 typedef struct smb_rap_share_info_2 {
1911 BYTE shi2_netname[13];
1914 DWORD shi2_remark; /* char *shi2_remark; data offset */
1915 WORD shi2_permissions;
1917 WORD shi2_current_uses;
1918 DWORD shi2_path; /* char *shi2_path; data offset */
1919 WORD shi2_passwd[9];
1921 } smb_rap_share_info_2_t;
1923 #define SMB_RAP_MAX_SHARES 512
1925 typedef struct smb_rap_share_list {
1928 smb_rap_share_info_0_t * shares;
1929 } smb_rap_share_list_t;
1933 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1934 smb_rap_share_list_t * sp;
1936 if (dep->name[0] == '.' && (!dep->name[1] || (dep->name[1] == '.' && !dep->name[2])))
1937 return 0; /* skip over '.' and '..' */
1939 sp = (smb_rap_share_list_t *) vrockp;
1941 strncpy(sp->shares[sp->cShare].shi0_netname, dep->name, 12);
1942 sp->shares[sp->cShare].shi0_netname[12] = 0;
1946 if (sp->cShare >= sp->maxShares)
1947 return CM_ERROR_STOPNOW;
1952 /* RAP NetShareEnumRequest */
1953 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1955 smb_tran2Packet_t *outp;
1956 unsigned short * tp;
1960 int outParmsTotal; /* total parameter bytes */
1961 int outDataTotal; /* total data bytes */
1964 DWORD allSubmount = 0;
1966 DWORD nRegShares = 0;
1967 DWORD nSharesRet = 0;
1969 HKEY hkSubmount = NULL;
1970 smb_rap_share_info_1_t * shares;
1973 clientchar_t thisShare[AFSPATHMAX];
1977 smb_rap_share_list_t rootShares;
1981 cm_scache_t *rootScp;
1983 tp = p->parmsp + 1; /* skip over function number (always 0) */
1986 clientchar_t * cdescp;
1988 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1989 if (cm_ClientStrCmp(cdescp, _C("WrLeh")))
1990 return CM_ERROR_INVAL;
1991 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1992 if (cm_ClientStrCmp(cdescp, _C("B13BWz")))
1993 return CM_ERROR_INVAL;
1999 if (infoLevel != 1) {
2000 return CM_ERROR_INVAL;
2003 /* We are supposed to use the same ASCII data structure even if
2004 Unicode is negotiated, which ultimately means that the share
2005 names that we return must be at most 13 characters in length,
2006 including the NULL terminator.
2008 The RAP specification states that shares with names longer than
2009 12 characters should not be included in the enumeration.
2010 However, since we support prefix cell references and since many
2011 cell names are going to exceed 12 characters, we lie and send
2012 the first 12 characters.
2015 /* first figure out how many shares there are */
2016 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
2017 KEY_QUERY_VALUE, &hkParam);
2018 if (rv == ERROR_SUCCESS) {
2019 len = sizeof(allSubmount);
2020 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
2021 (BYTE *) &allSubmount, &len);
2022 if (rv != ERROR_SUCCESS || allSubmount != 0) {
2025 RegCloseKey (hkParam);
2028 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
2029 0, KEY_QUERY_VALUE, &hkSubmount);
2030 if (rv == ERROR_SUCCESS) {
2031 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
2032 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
2033 if (rv != ERROR_SUCCESS)
2039 /* fetch the root shares */
2040 rootShares.maxShares = SMB_RAP_MAX_SHARES;
2041 rootShares.cShare = 0;
2042 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
2046 userp = smb_GetTran2User(vcp,p);
2048 thyper.HighPart = 0;
2051 rootScp = cm_RootSCachep(userp, &req);
2052 cm_HoldSCache(rootScp);
2053 cm_ApplyDir(rootScp, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
2054 cm_ReleaseSCache(rootScp);
2056 cm_ReleaseUser(userp);
2058 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
2060 #define REMARK_LEN 1
2061 outParmsTotal = 8; /* 4 dwords */
2062 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
2063 if(outDataTotal > bufsize) {
2064 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
2065 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
2068 nSharesRet = nShares;
2071 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
2073 /* now for the submounts */
2074 shares = (smb_rap_share_info_1_t *) outp->datap;
2075 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
2077 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
2080 StringCchCopyA(shares[cshare].shi1_netname,
2081 lengthof(shares[cshare].shi1_netname), "all" );
2082 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
2083 /* type and pad are zero already */
2089 for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
2090 len = sizeof(thisShare);
2091 rv = RegEnumValueW(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
2092 if (rv == ERROR_SUCCESS &&
2093 cm_ClientStrLen(thisShare) &&
2094 (!allSubmount || cm_ClientStrCmpI(thisShare,_C("all")))) {
2095 cm_ClientStringToUtf8(thisShare, -1, shares[cshare].shi1_netname,
2096 lengthof( shares[cshare].shi1_netname ));
2097 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
2098 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
2103 nShares--; /* uncount key */
2106 RegCloseKey(hkSubmount);
2109 nonrootShares = cshare;
2111 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
2112 /* in case there are collisions with submounts, submounts have
2114 for (j=0; j < nonrootShares; j++)
2115 if (!cm_stricmp_utf8(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
2118 if (j < nonrootShares) {
2119 nShares--; /* uncount */
2123 StringCchCopyA(shares[cshare].shi1_netname, lengthof(shares[cshare].shi1_netname),
2124 rootShares.shares[i].shi0_netname);
2125 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
2130 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
2131 outp->parmsp[1] = 0;
2132 outp->parmsp[2] = cshare;
2133 outp->parmsp[3] = nShares;
2135 outp->totalData = (int)(cstrp - outp->datap);
2136 outp->totalParms = outParmsTotal;
2138 smb_SendTran2Packet(vcp, outp, op);
2139 smb_FreeTran2Packet(outp);
2141 free(rootShares.shares);
2146 /* RAP NetShareGetInfo */
2147 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2149 smb_tran2Packet_t *outp;
2150 unsigned short * tp;
2151 clientchar_t * shareName;
2152 BOOL shareFound = FALSE;
2153 unsigned short infoLevel;
2154 unsigned short bufsize;
2163 cm_scache_t *scp = NULL;
2169 tp = p->parmsp + 1; /* skip over function number (always 1) */
2172 clientchar_t * cdescp;
2174 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2175 if (cm_ClientStrCmp(cdescp, _C("zWrLh")))
2177 return CM_ERROR_INVAL;
2179 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2180 if (cm_ClientStrCmp(cdescp, _C("B13")) &&
2181 cm_ClientStrCmp(cdescp, _C("B13BWz")) &&
2182 cm_ClientStrCmp(cdescp, _C("B13BWzWWWzB9B")))
2184 return CM_ERROR_INVAL;
2186 shareName = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2194 totalData = sizeof(smb_rap_share_info_0_t);
2195 else if(infoLevel == SMB_INFO_STANDARD)
2196 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
2197 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
2198 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
2200 return CM_ERROR_INVAL;
2202 if(!cm_ClientStrCmpI(shareName, _C("all")) || !cm_ClientStrCmp(shareName,_C("*."))) {
2203 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
2204 KEY_QUERY_VALUE, &hkParam);
2205 if (rv == ERROR_SUCCESS) {
2206 len = sizeof(allSubmount);
2207 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
2208 (BYTE *) &allSubmount, &len);
2209 if (rv != ERROR_SUCCESS || allSubmount != 0) {
2212 RegCloseKey (hkParam);
2219 userp = smb_GetTran2User(vcp, p);
2221 osi_Log1(smb_logp,"ReceiveRAPNetShareGetInfo unable to resolve user [%d]", p->uid);
2222 return CM_ERROR_BADSMB;
2224 code = cm_NameI(cm_RootSCachep(userp, &req), shareName,
2225 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
2226 userp, NULL, &req, &scp);
2228 cm_ReleaseSCache(scp);
2231 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
2232 KEY_QUERY_VALUE, &hkSubmount);
2233 if (rv == ERROR_SUCCESS) {
2234 rv = RegQueryValueExW(hkSubmount, shareName, NULL, NULL, NULL, NULL);
2235 if (rv == ERROR_SUCCESS) {
2238 RegCloseKey(hkSubmount);
2244 return CM_ERROR_BADSHARENAME;
2246 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
2247 memset(outp->datap, 0, totalData);
2249 outp->parmsp[0] = 0;
2250 outp->parmsp[1] = 0;
2251 outp->parmsp[2] = totalData;
2253 if (infoLevel == 0) {
2254 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
2255 cm_ClientStringToUtf8(shareName, -1, info->shi0_netname,
2256 lengthof(info->shi0_netname));
2257 } else if(infoLevel == SMB_INFO_STANDARD) {
2258 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
2259 cm_ClientStringToUtf8(shareName, -1, info->shi1_netname, lengthof(info->shi1_netname));
2260 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
2261 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
2262 /* type and pad are already zero */
2263 } else { /* infoLevel==2 */
2264 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
2265 cm_ClientStringToUtf8(shareName, -1, info->shi2_netname, lengthof(info->shi2_netname));
2266 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
2267 info->shi2_permissions = ACCESS_ALL;
2268 info->shi2_max_uses = (unsigned short) -1;
2269 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
2272 outp->totalData = totalData;
2273 outp->totalParms = totalParam;
2275 smb_SendTran2Packet(vcp, outp, op);
2276 smb_FreeTran2Packet(outp);
2281 #pragma pack(push, 1)
2283 typedef struct smb_rap_wksta_info_10 {
2284 DWORD wki10_computername; /*char *wki10_computername;*/
2285 DWORD wki10_username; /* char *wki10_username; */
2286 DWORD wki10_langroup; /* char *wki10_langroup;*/
2287 BYTE wki10_ver_major;
2288 BYTE wki10_ver_minor;
2289 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
2290 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
2291 } smb_rap_wksta_info_10_t;
2295 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2297 smb_tran2Packet_t *outp;
2301 unsigned short * tp;
2304 smb_rap_wksta_info_10_t * info;
2308 tp = p->parmsp + 1; /* Skip over function number */
2311 clientchar_t * cdescp;
2313 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2314 SMB_STRF_FORCEASCII);
2315 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2316 return CM_ERROR_INVAL;
2318 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2319 SMB_STRF_FORCEASCII);
2320 if (cm_ClientStrCmp(cdescp, _C("zzzBBzz")))
2321 return CM_ERROR_INVAL;
2327 if (infoLevel != 10) {
2328 return CM_ERROR_INVAL;
2334 totalData = sizeof(*info) + /* info */
2335 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
2336 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
2337 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
2338 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
2339 1; /* wki10_oth_domains (null)*/
2341 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2343 memset(outp->parmsp,0,totalParams);
2344 memset(outp->datap,0,totalData);
2346 info = (smb_rap_wksta_info_10_t *) outp->datap;
2347 cstrp = (char *) (info + 1);
2349 info->wki10_computername = (DWORD) (cstrp - outp->datap);
2350 StringCbCopyA(cstrp, totalData, smb_localNamep);
2351 cstrp += strlen(cstrp) + 1;
2353 info->wki10_username = (DWORD) (cstrp - outp->datap);
2354 uidp = smb_FindUID(vcp, p->uid, 0);
2356 lock_ObtainMutex(&uidp->mx);
2357 if(uidp->unp && uidp->unp->name)
2358 cm_ClientStringToUtf8(uidp->unp->name, -1,
2359 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2360 lock_ReleaseMutex(&uidp->mx);
2361 smb_ReleaseUID(uidp);
2363 cstrp += strlen(cstrp) + 1;
2365 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
2366 StringCbCopyA(cstrp, totalData - (cstrp - outp->datap)*sizeof(char), "WORKGROUP");
2367 cstrp += strlen(cstrp) + 1;
2369 /* TODO: Not sure what values these should take, but these work */
2370 info->wki10_ver_major = 5;
2371 info->wki10_ver_minor = 1;
2373 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
2374 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
2375 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2376 cstrp += strlen(cstrp) + 1;
2378 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
2379 cstrp ++; /* no other domains */
2381 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
2382 outp->parmsp[2] = outp->totalData;
2383 outp->totalParms = totalParams;
2385 smb_SendTran2Packet(vcp,outp,op);
2386 smb_FreeTran2Packet(outp);
2391 #pragma pack(push, 1)
2393 typedef struct smb_rap_server_info_0 {
2395 } smb_rap_server_info_0_t;
2397 typedef struct smb_rap_server_info_1 {
2399 BYTE sv1_version_major;
2400 BYTE sv1_version_minor;
2402 DWORD sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
2403 } smb_rap_server_info_1_t;
2407 char smb_ServerComment[] = "OpenAFS Client";
2408 int smb_ServerCommentLen = sizeof(smb_ServerComment);
2410 #define SMB_SV_TYPE_SERVER 0x00000002L
2411 #define SMB_SV_TYPE_NT 0x00001000L
2412 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
2414 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2416 smb_tran2Packet_t *outp;
2420 unsigned short * tp;
2423 smb_rap_server_info_0_t * info0;
2424 smb_rap_server_info_1_t * info1;
2427 tp = p->parmsp + 1; /* Skip over function number */
2430 clientchar_t * cdescp;
2432 cdescp = smb_ParseStringT2Parm(p, (unsigned char *) tp, (char **) &tp,
2433 SMB_STRF_FORCEASCII);
2434 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2435 return CM_ERROR_INVAL;
2436 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2437 SMB_STRF_FORCEASCII);
2438 if (cm_ClientStrCmp(cdescp, _C("B16")) ||
2439 cm_ClientStrCmp(cdescp, _C("B16BBDz")))
2440 return CM_ERROR_INVAL;
2446 if (infoLevel != 0 && infoLevel != 1) {
2447 return CM_ERROR_INVAL;
2453 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
2454 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
2456 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2458 memset(outp->parmsp,0,totalParams);
2459 memset(outp->datap,0,totalData);
2461 if (infoLevel == 0) {
2462 info0 = (smb_rap_server_info_0_t *) outp->datap;
2463 cstrp = (char *) (info0 + 1);
2464 StringCchCopyA(info0->sv0_name, lengthof(info0->sv0_name), "AFS");
2465 } else { /* infoLevel == SMB_INFO_STANDARD */
2466 info1 = (smb_rap_server_info_1_t *) outp->datap;
2467 cstrp = (char *) (info1 + 1);
2468 StringCchCopyA(info1->sv1_name, lengthof(info1->sv1_name), "AFS");
2471 SMB_SV_TYPE_SERVER |
2473 SMB_SV_TYPE_SERVER_NT;
2475 info1->sv1_version_major = 5;
2476 info1->sv1_version_minor = 1;
2477 info1->sv1_comment_or_master_browser = (DWORD) (cstrp - outp->datap);
2479 StringCbCopyA(cstrp, smb_ServerCommentLen, smb_ServerComment);
2481 cstrp += smb_ServerCommentLen / sizeof(char);
2484 totalData = (DWORD)(cstrp - outp->datap);
2485 outp->totalData = min(bufsize,totalData); /* actual data size */
2486 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
2487 outp->parmsp[2] = totalData;
2488 outp->totalParms = totalParams;
2490 smb_SendTran2Packet(vcp,outp,op);
2491 smb_FreeTran2Packet(outp);
2496 /* SMB_COM_TRANSACTION2 and SMB_COM_TRANSACTION2_SECONDARY */
2497 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2499 smb_tran2Packet_t *asp;
2510 DWORD oldTime, newTime;
2512 /* We sometimes see 0 word count. What to do? */
2513 if (*inp->wctp == 0) {
2514 osi_Log0(smb_logp, "Transaction2 word count = 0");
2515 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
2517 smb_SetSMBDataLength(outp, 0);
2518 smb_SendPacket(vcp, outp);
2522 totalParms = smb_GetSMBParm(inp, 0);
2523 totalData = smb_GetSMBParm(inp, 1);
2525 firstPacket = (inp->inCom == 0x32);
2527 /* find the packet we're reassembling */
2528 lock_ObtainWrite(&smb_globalLock);
2529 asp = smb_FindTran2Packet(vcp, inp);
2531 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
2533 lock_ReleaseWrite(&smb_globalLock);
2535 /* now merge in this latest packet; start by looking up offsets */
2537 parmDisp = dataDisp = 0;
2538 parmOffset = smb_GetSMBParm(inp, 10);
2539 dataOffset = smb_GetSMBParm(inp, 12);
2540 parmCount = smb_GetSMBParm(inp, 9);
2541 dataCount = smb_GetSMBParm(inp, 11);
2542 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2543 asp->maxReturnData = smb_GetSMBParm(inp, 3);
2545 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2546 totalData, dataCount, asp->maxReturnData);
2549 parmDisp = smb_GetSMBParm(inp, 4);
2550 parmOffset = smb_GetSMBParm(inp, 3);
2551 dataDisp = smb_GetSMBParm(inp, 7);
2552 dataOffset = smb_GetSMBParm(inp, 6);
2553 parmCount = smb_GetSMBParm(inp, 2);
2554 dataCount = smb_GetSMBParm(inp, 5);
2556 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2557 parmCount, dataCount);
2560 /* now copy the parms and data */
2561 if ( asp->totalParms > 0 && parmCount != 0 )
2563 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2565 if ( asp->totalData > 0 && dataCount != 0 ) {
2566 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2569 /* account for new bytes */
2570 asp->curData += dataCount;
2571 asp->curParms += parmCount;
2573 /* finally, if we're done, remove the packet from the queue and dispatch it */
2574 if (asp->totalParms > 0 &&
2575 asp->curParms > 0 &&
2576 asp->totalData <= asp->curData &&
2577 asp->totalParms <= asp->curParms) {
2578 /* we've received it all */
2579 lock_ObtainWrite(&smb_globalLock);
2580 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2581 lock_ReleaseWrite(&smb_globalLock);
2583 oldTime = GetTickCount();
2585 /* now dispatch it */
2586 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2587 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2588 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2591 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2592 code = CM_ERROR_BADOP;
2595 /* if an error is returned, we're supposed to send an error packet,
2596 * otherwise the dispatched function already did the data sending.
2597 * We give dispatched proc the responsibility since it knows how much
2598 * space to allocate.
2601 smb_SendTran2Error(vcp, asp, outp, code);
2604 newTime = GetTickCount();
2605 if (newTime - oldTime > 45000) {
2608 clientchar_t *treepath = NULL; /* do not free */
2609 clientchar_t *pathname = NULL;
2610 cm_fid_t afid = {0,0,0,0,0};
2612 uidp = smb_FindUID(vcp, asp->uid, 0);
2613 smb_LookupTIDPath(vcp, asp->tid, &treepath);
2614 fidp = smb_FindFID(vcp, inp->fid, 0);
2617 lock_ObtainMutex(&fidp->mx);
2618 if (fidp->NTopen_pathp)
2619 pathname = fidp->NTopen_pathp;
2621 afid = fidp->scp->fid;
2623 if (inp->stringsp->wdata)
2624 pathname = inp->stringsp->wdata;
2627 afsi_log("Request %s duration %d ms user 0x%x \"%S\" pid 0x%x mid 0x%x tid 0x%x \"%S\" path? \"%S\" afid (%d.%d.%d.%d)",
2628 myCrt_2Dispatch(asp->opcode), newTime - oldTime,
2629 asp->uid, uidp ? uidp->unp->name : NULL,
2630 asp->pid, asp->mid, asp->tid,
2633 afid.cell, afid.volume, afid.vnode, afid.unique);
2636 lock_ReleaseMutex(&fidp->mx);
2639 smb_ReleaseUID(uidp);
2641 smb_ReleaseFID(fidp);
2644 /* free the input tran 2 packet */
2645 smb_FreeTran2Packet(asp);
2647 else if (firstPacket) {
2648 /* the first packet in a multi-packet request, we need to send an
2649 * ack to get more data.
2651 smb_SetSMBDataLength(outp, 0);
2652 smb_SendPacket(vcp, outp);
2659 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2661 clientchar_t *pathp;
2662 smb_tran2Packet_t *outp;
2667 cm_scache_t *dscp; /* dir we're dealing with */
2668 cm_scache_t *scp; /* file we're creating */
2672 clientchar_t *lastNamep;
2679 int parmSlot; /* which parm we're dealing with */
2680 long returnEALength;
2681 clientchar_t *tidPathp;
2684 BOOL is_rpc = FALSE;
2685 BOOL is_ipc = FALSE;
2691 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2692 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2694 openFun = p->parmsp[6]; /* open function */
2695 excl = ((openFun & 3) == 0);
2696 trunc = ((openFun & 3) == 2); /* truncate it */
2697 openMode = (p->parmsp[1] & 0x7);
2698 openAction = 0; /* tracks what we did */
2700 attributes = p->parmsp[3];
2701 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2703 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
2706 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2708 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2709 if (code == CM_ERROR_TIDIPC) {
2711 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2714 spacep = cm_GetSpace();
2715 /* smb_StripLastComponent will strip "::$DATA" if present */
2716 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2720 /* special case magic file name for receiving IOCTL requests
2721 * (since IOCTL calls themselves aren't getting through).
2723 (cm_ClientStrCmpI(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
2725 /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional)*/
2726 (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
2728 unsigned short file_type = 0;
2729 unsigned short device_state = 0;
2731 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2734 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
2735 osi_Log2(smb_logp, "smb_ReceiveTran2Open Creating RPC Fid [%d] code [%d]",
2738 smb_ReleaseFID(fidp);
2739 smb_FreeTran2Packet(outp);
2740 osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
2744 smb_SetupIoctlFid(fidp, spacep);
2745 osi_Log1(smb_logp, "smb_ReceiveTran2Open Creating IOCTL Fid [%d]", fidp->fid);
2748 /* copy out remainder of the parms */
2750 outp->parmsp[parmSlot++] = fidp->fid;
2752 outp->parmsp[parmSlot++] = 0; /* attrs */
2753 outp->parmsp[parmSlot++] = 0; /* mod time */
2754 outp->parmsp[parmSlot++] = 0;
2755 outp->parmsp[parmSlot++] = 0; /* len */
2756 outp->parmsp[parmSlot++] = 0x7fff;
2757 outp->parmsp[parmSlot++] = openMode;
2758 outp->parmsp[parmSlot++] = file_type;
2759 outp->parmsp[parmSlot++] = device_state;
2761 /* and the final "always present" stuff */
2762 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2763 /* next write out the "unique" ID */
2764 outp->parmsp[parmSlot++] = 0x1234;
2765 outp->parmsp[parmSlot++] = 0x5678;
2766 outp->parmsp[parmSlot++] = 0;
2767 if (returnEALength) {
2768 outp->parmsp[parmSlot++] = 0;
2769 outp->parmsp[parmSlot++] = 0;
2772 outp->totalData = 0;
2773 outp->totalParms = parmSlot * 2;
2775 smb_SendTran2Packet(vcp, outp, op);
2777 smb_FreeTran2Packet(outp);
2779 /* and clean up fid reference */
2780 smb_ReleaseFID(fidp);
2786 osi_Log1(smb_logp, "Tran2Open rejecting IPC TID vcp %p", vcp);
2787 smb_FreeTran2Packet(outp);
2788 return CM_ERROR_BADFD;
2792 if (!cm_IsValidClientString(pathp)) {
2794 clientchar_t * hexp;
2796 hexp = cm_GetRawCharsAlloc(pathp, -1);
2797 osi_Log1(smb_logp, "Tran2Open rejecting invalid name. [%S]",
2798 osi_LogSaveClientString(smb_logp, hexp));
2802 osi_Log0(smb_logp, "Tran2Open rejecting invalid name");
2804 smb_FreeTran2Packet(outp);
2805 return CM_ERROR_BADNTFILENAME;
2808 #ifdef DEBUG_VERBOSE
2810 char *hexp, *asciip;
2811 asciip = (lastNamep ? lastNamep : pathp);
2812 hexp = osi_HexifyString( asciip );
2813 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2818 userp = smb_GetTran2User(vcp, p);
2819 /* In the off chance that userp is NULL, we log and abandon */
2821 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2822 smb_FreeTran2Packet(outp);
2823 return CM_ERROR_BADSMB;
2827 code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
2828 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2829 userp, tidPathp, &req, &scp);
2831 if (code == CM_ERROR_NOSUCHFILE ||
2832 code == CM_ERROR_NOSUCHPATH ||
2833 code == CM_ERROR_BPLUS_NOMATCH)
2834 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
2835 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2836 userp, tidPathp, &req, &dscp);
2837 cm_FreeSpace(spacep);
2840 cm_ReleaseUser(userp);
2841 smb_FreeTran2Packet(outp);
2846 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2847 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2848 (clientchar_t*) spacep->data);
2849 cm_ReleaseSCache(dscp);
2850 cm_ReleaseUser(userp);
2851 smb_FreeTran2Packet(outp);
2852 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2853 return CM_ERROR_PATH_NOT_COVERED;
2855 return CM_ERROR_NOSUCHPATH;
2857 #endif /* DFS_SUPPORT */
2859 /* otherwise, scp points to the parent directory. Do a lookup,
2860 * and truncate the file if we find it, otherwise we create the
2867 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2869 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2870 cm_ReleaseSCache(dscp);
2871 cm_ReleaseUser(userp);
2872 smb_FreeTran2Packet(outp);
2876 /* macintosh is expensive to program for it */
2877 cm_FreeSpace(spacep);
2880 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2881 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2882 cm_ReleaseSCache(scp);
2883 cm_ReleaseUser(userp);
2884 smb_FreeTran2Packet(outp);
2885 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2886 return CM_ERROR_PATH_NOT_COVERED;
2888 return CM_ERROR_NOSUCHPATH;
2890 #endif /* DFS_SUPPORT */
2893 /* if we get here, if code is 0, the file exists and is represented by
2894 * scp. Otherwise, we have to create it.
2897 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2900 cm_ReleaseSCache(dscp);
2901 cm_ReleaseSCache(scp);
2902 cm_ReleaseUser(userp);
2903 smb_FreeTran2Packet(outp);
2908 /* oops, file shouldn't be there */
2910 cm_ReleaseSCache(dscp);
2911 cm_ReleaseSCache(scp);
2912 cm_ReleaseUser(userp);
2913 smb_FreeTran2Packet(outp);
2914 return CM_ERROR_EXISTS;
2918 setAttr.mask = CM_ATTRMASK_LENGTH;
2919 setAttr.length.LowPart = 0;
2920 setAttr.length.HighPart = 0;
2921 code = cm_SetAttr(scp, &setAttr, userp, &req);
2922 openAction = 3; /* truncated existing file */
2925 openAction = 1; /* found existing file */
2927 else if (!(openFun & 0x10)) {
2928 /* don't create if not found */
2930 cm_ReleaseSCache(dscp);
2931 osi_assertx(scp == NULL, "null cm_scache_t");
2932 cm_ReleaseUser(userp);
2933 smb_FreeTran2Packet(outp);
2934 return CM_ERROR_NOSUCHFILE;
2937 osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2938 openAction = 2; /* created file */
2939 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2940 cm_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2941 smb_SetInitialModeBitsForFile(attributes, &setAttr);
2943 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2947 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2948 smb_NotifyChange(FILE_ACTION_ADDED,
2949 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2950 dscp, lastNamep, NULL, TRUE);
2951 } else if (!excl && code == CM_ERROR_EXISTS) {
2952 /* not an exclusive create, and someone else tried
2953 * creating it already, then we open it anyway. We
2954 * don't bother retrying after this, since if this next
2955 * fails, that means that the file was deleted after we
2956 * started this call.
2958 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2962 setAttr.mask = CM_ATTRMASK_LENGTH;
2963 setAttr.length.LowPart = 0;
2964 setAttr.length.HighPart = 0;
2965 code = cm_SetAttr(scp, &setAttr, userp,
2968 } /* lookup succeeded */
2972 /* we don't need this any longer */
2974 cm_ReleaseSCache(dscp);
2977 /* something went wrong creating or truncating the file */
2979 cm_ReleaseSCache(scp);
2980 cm_ReleaseUser(userp);
2981 smb_FreeTran2Packet(outp);
2985 /* make sure we're about to open a file */
2986 if (scp->fileType != CM_SCACHETYPE_FILE) {
2988 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2989 cm_scache_t * targetScp = 0;
2990 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2992 /* we have a more accurate file to use (the
2993 * target of the symbolic link). Otherwise,
2994 * we'll just use the symlink anyway.
2996 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2998 cm_ReleaseSCache(scp);
3002 if (scp->fileType != CM_SCACHETYPE_FILE) {
3003 cm_ReleaseSCache(scp);
3004 cm_ReleaseUser(userp);
3005 smb_FreeTran2Packet(outp);
3006 return CM_ERROR_ISDIR;
3010 /* now all we have to do is open the file itself */
3011 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3012 osi_assertx(fidp, "null smb_fid_t");
3015 lock_ObtainMutex(&fidp->mx);
3016 /* save a pointer to the vnode */
3017 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
3019 lock_ObtainWrite(&scp->rw);
3020 scp->flags |= CM_SCACHEFLAG_SMB_FID;
3021 lock_ReleaseWrite(&scp->rw);
3024 fidp->userp = userp;
3026 /* compute open mode */
3028 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
3029 if (openMode == 1 || openMode == 2)
3030 fidp->flags |= SMB_FID_OPENWRITE;
3032 /* remember that the file was newly created */
3034 fidp->flags |= SMB_FID_CREATED;
3036 lock_ReleaseMutex(&fidp->mx);
3038 smb_ReleaseFID(fidp);
3040 cm_Open(scp, 0, userp);
3042 /* copy out remainder of the parms */
3044 outp->parmsp[parmSlot++] = fidp->fid;
3045 lock_ObtainRead(&scp->rw);
3047 outp->parmsp[parmSlot++] = smb_Attributes(scp);
3048 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3049 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
3050 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
3051 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
3052 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
3053 outp->parmsp[parmSlot++] = openMode;
3054 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
3055 outp->parmsp[parmSlot++] = 0; /* IPC junk */
3057 /* and the final "always present" stuff */
3058 outp->parmsp[parmSlot++] = openAction;
3059 /* next write out the "unique" ID */
3060 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
3061 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
3062 outp->parmsp[parmSlot++] = 0;
3063 if (returnEALength) {
3064 outp->parmsp[parmSlot++] = 0;
3065 outp->parmsp[parmSlot++] = 0;
3067 lock_ReleaseRead(&scp->rw);
3068 outp->totalData = 0; /* total # of data bytes */
3069 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
3071 smb_SendTran2Packet(vcp, outp, op);
3073 smb_FreeTran2Packet(outp);
3075 cm_ReleaseUser(userp);
3076 /* leave scp held since we put it in fidp->scp */
3080 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3083 unsigned short infolevel;
3085 infolevel = p->parmsp[0];
3087 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
3089 return CM_ERROR_BAD_LEVEL;
3092 /* TRANS2_QUERY_FS_INFORMATION */
3093 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3095 smb_tran2Packet_t *outp;
3096 smb_tran2QFSInfo_t qi;
3100 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
3102 switch (p->parmsp[0]) {
3103 case SMB_INFO_ALLOCATION:
3105 responseSize = sizeof(qi.u.allocInfo);
3107 qi.u.allocInfo.FSID = 0;
3108 qi.u.allocInfo.sectorsPerAllocUnit = 1;
3109 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
3110 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
3111 qi.u.allocInfo.bytesPerSector = 1024;
3114 case SMB_INFO_VOLUME:
3116 qi.u.volumeInfo.vsn = 1234; /* Volume serial number */
3117 qi.u.volumeInfo.vnCount = 3; /* Number of characters in label (AFS\0)*/
3119 /* we're supposed to pad it out with zeroes to the end */
3120 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
3121 smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
3123 responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
3126 case SMB_QUERY_FS_VOLUME_INFO:
3127 /* FS volume info */
3128 responseSize = sizeof(qi.u.FSvolumeInfo);
3131 FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
3132 memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
3135 qi.u.FSvolumeInfo.vsn = 1234;
3136 qi.u.FSvolumeInfo.vnCount = 6; /* This is always in Unicode */
3137 memset(&qi.u.FSvolumeInfo.label, 0, sizeof(qi.u.FSvolumeInfo.label));
3138 memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
3141 case SMB_QUERY_FS_SIZE_INFO:
3143 responseSize = sizeof(qi.u.FSsizeInfo);
3145 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
3146 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
3147 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
3148 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
3149 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
3150 qi.u.FSsizeInfo.bytesPerSector = 1024;
3153 case SMB_QUERY_FS_DEVICE_INFO:
3154 /* FS device info */
3155 responseSize = sizeof(qi.u.FSdeviceInfo);
3157 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
3158 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
3161 case SMB_QUERY_FS_ATTRIBUTE_INFO:
3162 /* FS attribute info */
3164 /* attributes, defined in WINNT.H:
3165 * FILE_CASE_SENSITIVE_SEARCH 0x1
3166 * FILE_CASE_PRESERVED_NAMES 0x2
3167 * FILE_UNICODE_ON_DISK 0x4
3168 * FILE_VOLUME_QUOTAS 0x10
3169 * <no name defined> 0x4000
3170 * If bit 0x4000 is not set, Windows 95 thinks
3171 * we can't handle long (non-8.3) names,
3172 * despite our protestations to the contrary.
3174 qi.u.FSattributeInfo.attributes = 0x4003;
3175 /* The maxCompLength is supposed to be in bytes */
3177 qi.u.FSattributeInfo.attributes |= 0x04;
3179 qi.u.FSattributeInfo.maxCompLength = 255;
3180 smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
3181 qi.u.FSattributeInfo.FSnameLength = sz;
3184 sizeof(qi.u.FSattributeInfo.attributes) +
3185 sizeof(qi.u.FSattributeInfo.maxCompLength) +
3186 sizeof(qi.u.FSattributeInfo.FSnameLength) +
3191 case SMB_INFO_UNIX: /* CIFS Unix Info */
3192 case SMB_INFO_MACOS: /* Mac FS Info */
3194 return CM_ERROR_BADOP;
3197 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
3199 /* copy out return data, and set corresponding sizes */
3200 outp->totalParms = 0;
3201 outp->totalData = responseSize;
3202 memcpy(outp->datap, &qi, responseSize);
3204 /* send and free the packets */
3205 smb_SendTran2Packet(vcp, outp, op);
3206 smb_FreeTran2Packet(outp);
3211 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3213 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
3214 return CM_ERROR_BADOP;
3217 struct smb_ShortNameRock {
3218 clientchar_t *maskp;
3220 clientchar_t *shortName;
3221 size_t shortNameLen;
3224 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
3227 struct smb_ShortNameRock *rockp;
3228 normchar_t normName[MAX_PATH];
3229 clientchar_t *shortNameEnd;
3233 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t)) == 0) {
3234 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
3235 osi_LogSaveString(smb_logp, dep->name));
3239 /* compare both names and vnodes, though probably just comparing vnodes
3240 * would be safe enough.
3242 if (cm_NormStrCmpI(normName, rockp->maskp) != 0)
3244 if (ntohl(dep->fid.vnode) != rockp->vnode)
3247 /* This is the entry */
3248 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
3249 rockp->shortNameLen = shortNameEnd - rockp->shortName;
3251 return CM_ERROR_STOPNOW;
3254 long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
3255 clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
3257 struct smb_ShortNameRock rock;
3258 clientchar_t *lastNamep;
3261 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
3265 spacep = cm_GetSpace();
3266 /* smb_StripLastComponent will strip "::$DATA" if present */
3267 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
3269 code = cm_NameI(cm_RootSCachep(userp, reqp), spacep->wdata,
3270 caseFold, userp, tidPathp,
3272 cm_FreeSpace(spacep);
3277 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3278 cm_ReleaseSCache(dscp);
3279 cm_ReleaseUser(userp);
3283 return CM_ERROR_PATH_NOT_COVERED;
3285 #endif /* DFS_SUPPORT */
3287 if (!lastNamep) lastNamep = pathp;
3290 thyper.HighPart = 0;
3291 rock.shortName = shortName;
3293 rock.maskp = lastNamep;
3294 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
3296 cm_ReleaseSCache(dscp);
3299 return CM_ERROR_NOSUCHFILE;
3300 if (code == CM_ERROR_STOPNOW) {
3301 *shortNameLenp = rock.shortNameLen;
3307 /* TRANS2_QUERY_PATH_INFORMATION */
3308 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3310 smb_tran2Packet_t *outp;
3313 unsigned short infoLevel;
3314 smb_tran2QPathInfo_t qpi;
3316 unsigned short attributes;
3317 unsigned long extAttributes;
3318 clientchar_t shortName[13];
3322 cm_scache_t *scp, *dscp;
3323 int scp_rw_held = 0;
3326 clientchar_t *pathp;
3327 clientchar_t *tidPathp;
3328 clientchar_t *lastComp;
3333 infoLevel = p->parmsp[0];
3334 if (infoLevel == SMB_INFO_IS_NAME_VALID)
3336 else if (infoLevel == SMB_INFO_STANDARD)
3337 responseSize = sizeof(qpi.u.QPstandardInfo);
3338 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
3339 responseSize = sizeof(qpi.u.QPeaSizeInfo);
3340 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3341 responseSize = sizeof(qpi.u.QPfileBasicInfo);
3342 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3343 responseSize = sizeof(qpi.u.QPfileStandardInfo);
3344 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3345 responseSize = sizeof(qpi.u.QPfileEaInfo);
3346 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3347 responseSize = sizeof(qpi.u.QPfileNameInfo);
3348 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
3349 responseSize = sizeof(qpi.u.QPfileAllInfo);
3350 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
3351 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
3352 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO)
3353 responseSize = sizeof(qpi.u.QPfileStreamInfo);
3355 osi_Log2(smb_logp, "Bad Tran2QPathInfo op 0x%x infolevel 0x%x",
3356 p->opcode, infoLevel);
3357 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3360 memset(&qpi, 0, sizeof(qpi));
3362 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3363 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path \"%S\"", infoLevel,
3364 osi_LogSaveClientString(smb_logp, pathp));
3366 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3368 if (infoLevel > 0x100)
3369 outp->totalParms = 2;
3371 outp->totalParms = 0;
3373 /* now, if we're at infoLevel 6, we're only being asked to check
3374 * the syntax, so we just OK things now. In particular, we're *not*
3375 * being asked to verify anything about the state of any parent dirs.
3377 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
3378 smb_SendTran2Packet(vcp, outp, opx);
3379 smb_FreeTran2Packet(outp);
3383 userp = smb_GetTran2User(vcp, p);
3385 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
3386 smb_FreeTran2Packet(outp);
3387 return CM_ERROR_BADSMB;
3390 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3392 osi_Log1(smb_logp, "ReceiveTran2QPathInfo tid path lookup failure 0x%x", code);
3393 cm_ReleaseUser(userp);
3394 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
3395 smb_FreeTran2Packet(outp);
3399 osi_Log1(smb_logp, "T2 QPathInfo tidPathp \"%S\"",
3400 osi_LogSaveClientString(smb_logp, tidPathp));
3403 * If the query is regarding the special _._AFS_IOCTL_._ file
3404 * a reply must be sent even though the file doesn't exist.
3406 if (cm_ClientStrCmpI(pathp, CM_IOCTL_FILENAME_NOSLASH_W) == 0)
3408 /* for info level 108, figure out short name */
3409 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3410 smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, L"_IOCTL_.AFS", &len, SMB_STRF_IGNORENUL);
3411 qpi.u.QPfileAltNameInfo.fileNameLength = len;
3412 responseSize = sizeof(unsigned long) + len;
3414 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3415 smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, CM_IOCTL_FILENAME_NOSLASH_W, &len, SMB_STRF_IGNORENUL);
3416 qpi.u.QPfileNameInfo.fileNameLength = len;
3417 responseSize = sizeof(unsigned long) + len;
3419 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3420 cm_SearchTimeFromUnixTime(&dosTime, 0);
3421 qpi.u.QPstandardInfo.creationDateTime = dosTime;
3422 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3423 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3424 qpi.u.QPstandardInfo.dataSize = 0;
3425 qpi.u.QPstandardInfo.allocationSize = 0;
3426 qpi.u.QPstandardInfo.attributes = SMB_ATTR_SYSTEM | SMB_ATTR_HIDDEN;
3427 qpi.u.QPstandardInfo.eaSize = 0;
3429 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3430 cm_LargeSearchTimeFromUnixTime(&ft, 0);
3431 qpi.u.QPfileBasicInfo.creationTime = ft;
3432 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3433 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3434 qpi.u.QPfileBasicInfo.changeTime = ft;
3435 qpi.u.QPfileBasicInfo.attributes = SMB_ATTR_SYSTEM | SMB_ATTR_HIDDEN;
3436 qpi.u.QPfileBasicInfo.reserved = 0;
3438 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3439 qpi.u.QPfileStandardInfo.allocationSize.QuadPart = 0;
3440 qpi.u.QPfileStandardInfo.endOfFile.QuadPart = 0;
3441 qpi.u.QPfileStandardInfo.numberOfLinks = 1;
3442 qpi.u.QPfileStandardInfo.directory = 0;
3443 qpi.u.QPfileStandardInfo.reserved = 0;
3444 qpi.u.QPfileStandardInfo.deletePending = 0;
3446 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3447 qpi.u.QPfileEaInfo.eaSize = 0;
3449 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3450 cm_LargeSearchTimeFromUnixTime(&ft, 0);
3451 qpi.u.QPfileAllInfo.creationTime = ft;
3452 qpi.u.QPfileAllInfo.lastAccessTime = ft;
3453 qpi.u.QPfileAllInfo.lastWriteTime = ft;
3454 qpi.u.QPfileAllInfo.changeTime = ft;
3455 qpi.u.QPfileAllInfo.attributes = SMB_ATTR_SYSTEM | SMB_ATTR_HIDDEN;
3456 qpi.u.QPfileAllInfo.allocationSize.QuadPart = 0;
3457 qpi.u.QPfileAllInfo.endOfFile.QuadPart = 0;
3458 qpi.u.QPfileAllInfo.numberOfLinks = 1;
3459 qpi.u.QPfileAllInfo.deletePending = 0;
3460 qpi.u.QPfileAllInfo.directory = 0;
3461 qpi.u.QPfileAllInfo.indexNumber.HighPart = 0;
3462 qpi.u.QPfileAllInfo.indexNumber.LowPart = 0;
3463 qpi.u.QPfileAllInfo.eaSize = 0;
3464 qpi.u.QPfileAllInfo.accessFlags = 0;
3465 qpi.u.QPfileAllInfo.indexNumber2.HighPart = 0;
3466 qpi.u.QPfileAllInfo.indexNumber2.LowPart = 0;
3467 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3468 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3469 qpi.u.QPfileAllInfo.mode = 0;
3470 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3472 smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, CM_IOCTL_FILENAME_NOSLASH_W, &len, SMB_STRF_IGNORENUL);
3473 qpi.u.QPfileAllInfo.fileNameLength = len;
3474 responseSize -= (sizeof(qpi.u.QPfileAllInfo.fileName) - len);
3476 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO) {
3478 /* For now we have no streams */
3479 qpi.u.QPfileStreamInfo.nextEntryOffset = 0;
3480 qpi.u.QPfileStreamInfo.streamSize.QuadPart = 0;
3481 qpi.u.QPfileStreamInfo.streamAllocationSize.QuadPart = 0;
3482 smb_UnparseString(opx, qpi.u.QPfileStreamInfo.fileName, L"::$DATA", &len, SMB_STRF_IGNORENUL);
3483 qpi.u.QPfileStreamInfo.streamNameLength = len;
3484 responseSize -= (sizeof(qpi.u.QPfileStreamInfo.fileName) - len);
3487 outp->totalData = responseSize;
3488 goto done_afs_ioctl;
3492 * XXX Strange hack XXX
3494 * As of Patch 7 (13 January 98), we are having the following problem:
3495 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3496 * requests to look up "desktop.ini" in all the subdirectories.
3497 * This can cause zillions of timeouts looking up non-existent cells
3498 * and volumes, especially in the top-level directory.
3500 * We have not found any way to avoid this or work around it except
3501 * to explicitly ignore the requests for mount points that haven't
3502 * yet been evaluated and for directories that haven't yet been
3505 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3506 spacep = cm_GetSpace();
3507 /* smb_StripLastComponent will strip "::$DATA" if present */
3508 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3509 #ifndef SPECIAL_FOLDERS
3510 /* Make sure that lastComp is not NULL */
3512 if (cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
3513 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
3517 userp, tidPathp, &req, &dscp);
3520 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3521 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3523 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3524 code = CM_ERROR_PATH_NOT_COVERED;
3526 code = CM_ERROR_NOSUCHPATH;
3528 #endif /* DFS_SUPPORT */
3529 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3530 code = CM_ERROR_NOSUCHFILE;
3531 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3532 cm_buf_t *bp = buf_Find(&dscp->fid, &hzero);
3538 code = CM_ERROR_NOSUCHFILE;
3540 cm_ReleaseSCache(dscp);
3542 cm_FreeSpace(spacep);
3543 cm_ReleaseUser(userp);
3544 smb_SendTran2Error(vcp, p, opx, code);
3545 smb_FreeTran2Packet(outp);
3551 #endif /* SPECIAL_FOLDERS */
3553 cm_FreeSpace(spacep);
3557 code == CM_ERROR_NOSUCHFILE ||
3558 code == CM_ERROR_NOSUCHPATH ||
3559 code == CM_ERROR_BPLUS_NOMATCH) {
3560 /* now do namei and stat, and copy out the info */
3561 code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
3562 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3566 cm_ReleaseUser(userp);
3567 smb_SendTran2Error(vcp, p, opx, code);
3568 smb_FreeTran2Packet(outp);
3573 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3574 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3575 cm_ReleaseSCache(scp);
3576 cm_ReleaseUser(userp);
3577 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3578 code = CM_ERROR_PATH_NOT_COVERED;
3580 code = CM_ERROR_NOSUCHPATH;
3581 smb_SendTran2Error(vcp, p, opx, code);
3582 smb_FreeTran2Packet(outp);
3585 #endif /* DFS_SUPPORT */
3587 lock_ObtainWrite(&scp->rw);
3589 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3590 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3594 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3596 lock_ConvertWToR(&scp->rw);
3601 /* now we have the status in the cache entry, and everything is locked.
3602 * Marshall the output data.
3604 /* for info level 108, figure out short name */
3605 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3606 code = cm_GetShortName(pathp, userp, &req,
3607 tidPathp, scp->fid.vnode, shortName,
3613 smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);