2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
15 #pragma warning(disable: 4005)
17 #define SECURITY_WIN32
29 #include <WINNT\afsreg.h>
34 extern osi_hyper_t hzero;
36 smb_packet_t *smb_Directory_Watches = NULL;
37 osi_mutex_t smb_Dir_Watch_Lock;
39 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
41 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
43 /* protected by the smb_globalLock */
44 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
46 const clientchar_t **smb_ExecutableExtensions = NULL;
48 /* retrieve a held reference to a user structure corresponding to an incoming
50 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
55 uidp = smb_FindUID(vcp, inp->uid, 0);
59 up = smb_GetUserFromUID(uidp);
67 * Return boolean specifying if the path name is thought to be an
68 * executable file. For now .exe or .dll.
70 afs_uint32 smb_IsExecutableFileName(const clientchar_t *name)
74 if ( smb_ExecutableExtensions == NULL || name == NULL)
77 len = (int)cm_ClientStrLen(name);
79 for ( i=0; smb_ExecutableExtensions[i]; i++) {
80 j = len - (int)cm_ClientStrLen(smb_ExecutableExtensions[i]);
81 if (cm_ClientStrCmpI(smb_ExecutableExtensions[i], &name[j]) == 0)
89 * Return extended attributes.
90 * Right now, we aren't using any of the "new" bits, so this looks exactly
91 * like smb_Attributes() (see smb.c).
93 unsigned long smb_ExtAttributes(cm_scache_t *scp)
97 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
98 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
99 scp->fileType == CM_SCACHETYPE_INVALID)
101 attrs = SMB_ATTR_DIRECTORY;
102 #ifdef SPECIAL_FOLDERS
103 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
104 #endif /* SPECIAL_FOLDERS */
105 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
106 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
107 } else if (scp->fid.vnode & 0x1)
108 attrs = SMB_ATTR_DIRECTORY;
113 * We used to mark a file RO if it was in an RO volume, but that
114 * turns out to be impolitic in NT. See defect 10007.
117 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
118 attrs |= SMB_ATTR_READONLY; /* Read-only */
120 if ((scp->unixModeBits & 0222) == 0)
121 attrs |= SMB_ATTR_READONLY; /* Read-only */
125 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
130 int smb_V3IsStarMask(clientchar_t *maskp)
134 while (tc = *maskp++)
135 if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
140 void OutputDebugF(clientchar_t * format, ...) {
142 clientchar_t vbuffer[1024];
144 va_start( args, format );
145 cm_ClientStrPrintfV(vbuffer, lengthof(vbuffer), format, args);
146 osi_Log1(smb_logp, "%S", osi_LogSaveClientString(smb_logp, vbuffer));
147 cm_ClientStrCat(vbuffer, lengthof(vbuffer), _C("\n"));
148 OutputDebugStringW(vbuffer);
151 void OutputDebugHexDump(unsigned char * buffer, int len) {
154 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
156 OutputDebugF(_C("Hexdump length [%d]"),len);
158 for (i=0;i<len;i++) {
161 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
162 StringCchCatA(buf, lengthof(buf), "\r\n");
163 OutputDebugString(buf);
165 StringCchPrintfA(buf, lengthof(buf), "%5x", i);
166 memset(buf+5,' ',80);
171 j = j*3 + 7 + ((j>7)?1:0);
174 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
177 j = j + 56 + ((j>7)?1:0);
179 buf[j] = (k>32 && k<127)?k:'.';
182 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
183 StringCchCatA(buf, lengthof(buf), "\r\n");
184 OutputDebugString(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);
271 struct smb_ext_context {
278 long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern,
279 char * secBlobIn, int secBlobInLength,
280 char ** secBlobOut, int * secBlobOutLength) {
281 SECURITY_STATUS status, istatus;
285 SecBufferDesc secBufIn;
287 SecBufferDesc secBufOut;
290 struct smb_ext_context * secCtx = NULL;
291 struct smb_ext_context * newSecCtx = NULL;
292 void * assembledBlob = NULL;
293 int assembledBlobLength = 0;
296 OutputDebugF(_C("In smb_AuthenticateUserExt"));
299 *secBlobOutLength = 0;
301 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
302 secCtx = vcp->secCtx;
303 lock_ObtainMutex(&vcp->mx);
304 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
306 lock_ReleaseMutex(&vcp->mx);
310 OutputDebugF(_C("Received incoming token:"));
311 OutputDebugHexDump(secBlobIn,secBlobInLength);
315 OutputDebugF(_C("Continuing with existing context."));
316 creds = secCtx->creds;
319 if (secCtx->partialToken) {
320 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
321 assembledBlob = malloc(assembledBlobLength);
322 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
323 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
326 status = AcquireCredentialsHandle( NULL,
327 SMB_EXT_SEC_PACKAGE_NAME,
336 if (status != SEC_E_OK) {
337 OutputDebugF(_C("Can't acquire Credentials handle [%lX]"), status);
338 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
346 secBufIn.cBuffers = 1;
347 secBufIn.pBuffers = &secTokIn;
348 secBufIn.ulVersion = SECBUFFER_VERSION;
350 secTokIn.BufferType = SECBUFFER_TOKEN;
352 secTokIn.cbBuffer = assembledBlobLength;
353 secTokIn.pvBuffer = assembledBlob;
355 secTokIn.cbBuffer = secBlobInLength;
356 secTokIn.pvBuffer = secBlobIn;
359 secBufOut.cBuffers = 1;
360 secBufOut.pBuffers = &secTokOut;
361 secBufOut.ulVersion = SECBUFFER_VERSION;
363 secTokOut.BufferType = SECBUFFER_TOKEN;
364 secTokOut.cbBuffer = 0;
365 secTokOut.pvBuffer = NULL;
367 status = AcceptSecurityContext( &creds,
368 ((secCtx)?&ctx:NULL),
370 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
371 SECURITY_NETWORK_DREP,
378 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
379 OutputDebugF(_C("Completing token..."));
380 istatus = CompleteAuthToken(&ctx, &secBufOut);
381 if ( istatus != SEC_E_OK )
382 OutputDebugF(_C("Token completion failed: %lX"), istatus);
385 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
386 OutputDebugF(_C("Continue needed"));
388 newSecCtx = malloc(sizeof(*newSecCtx));
390 newSecCtx->creds = creds;
391 newSecCtx->ctx = ctx;
392 newSecCtx->partialToken = NULL;
393 newSecCtx->partialTokenLen = 0;
395 lock_ObtainMutex( &vcp->mx );
396 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
397 vcp->secCtx = newSecCtx;
398 lock_ReleaseMutex( &vcp->mx );
400 code = CM_ERROR_GSSCONTINUE;
403 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
404 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
405 secTokOut.pvBuffer) {
406 OutputDebugF(_C("Need to send token back to client"));
408 *secBlobOutLength = secTokOut.cbBuffer;
409 *secBlobOut = malloc(secTokOut.cbBuffer);
410 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
412 OutputDebugF(_C("Outgoing token:"));
413 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
414 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
415 OutputDebugF(_C("Incomplete message"));
417 newSecCtx = malloc(sizeof(*newSecCtx));
419 newSecCtx->creds = creds;
420 newSecCtx->ctx = ctx;
421 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
422 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
423 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
425 lock_ObtainMutex( &vcp->mx );
426 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
427 vcp->secCtx = newSecCtx;
428 lock_ReleaseMutex( &vcp->mx );
430 code = CM_ERROR_GSSCONTINUE;
433 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
435 SecPkgContext_NamesW names;
437 OutputDebugF(_C("Authentication completed"));
438 OutputDebugF(_C("Returned flags : [%lX]"), flags);
440 if (!QueryContextAttributesW(&ctx, SECPKG_ATTR_NAMES, &names)) {
441 OutputDebugF(_C("Received name [%s]"), names.sUserName);
442 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, names.sUserName);
443 cm_ClientStrLwr(usern); /* in tandem with smb_GetNormalizedUsername */
444 FreeContextBuffer(names.sUserName);
446 /* Force the user to retry if the context is invalid */
447 OutputDebugF(_C("QueryContextAttributes Names failed [%x]"), GetLastError());
448 code = CM_ERROR_BADPASSWORD;
452 case SEC_E_INVALID_TOKEN:
453 OutputDebugF(_C("Returning bad password :: INVALID_TOKEN"));
455 case SEC_E_INVALID_HANDLE:
456 OutputDebugF(_C("Returning bad password :: INVALID_HANDLE"));
458 case SEC_E_LOGON_DENIED:
459 OutputDebugF(_C("Returning bad password :: LOGON_DENIED"));
461 case SEC_E_UNKNOWN_CREDENTIALS:
462 OutputDebugF(_C("Returning bad password :: UNKNOWN_CREDENTIALS"));
464 case SEC_E_NO_CREDENTIALS:
465 OutputDebugF(_C("Returning bad password :: NO_CREDENTIALS"));
467 case SEC_E_CONTEXT_EXPIRED:
468 OutputDebugF(_C("Returning bad password :: CONTEXT_EXPIRED"));
470 case SEC_E_INCOMPLETE_CREDENTIALS:
471 OutputDebugF(_C("Returning bad password :: INCOMPLETE_CREDENTIALS"));
473 case SEC_E_WRONG_PRINCIPAL:
474 OutputDebugF(_C("Returning bad password :: WRONG_PRINCIPAL"));
476 case SEC_E_TIME_SKEW:
477 OutputDebugF(_C("Returning bad password :: TIME_SKEW"));
480 OutputDebugF(_C("Returning bad password :: Status == %lX"), status);
482 code = CM_ERROR_BADPASSWORD;
486 if (secCtx->partialToken) free(secCtx->partialToken);
494 if (secTokOut.pvBuffer)
495 FreeContextBuffer(secTokOut.pvBuffer);
497 if (code != CM_ERROR_GSSCONTINUE) {
498 DeleteSecurityContext(&ctx);
499 FreeCredentialsHandle(&creds);
507 #define P_RESP_LEN 128
509 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
510 So put stuff in a struct. */
511 struct Lm20AuthBlob {
512 MSV1_0_LM20_LOGON lmlogon;
513 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
514 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
515 WCHAR accountNameW[P_LEN];
516 WCHAR primaryDomainW[P_LEN];
517 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
518 TOKEN_GROUPS tgroups;
519 TOKEN_SOURCE tsource;
522 long smb_AuthenticateUserLM(smb_vc_t *vcp, clientchar_t * accountName, clientchar_t * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
525 struct Lm20AuthBlob lmAuth;
526 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
527 QUOTA_LIMITS quotaLimits;
529 ULONG lmprofilepSize;
533 OutputDebugF(_C("In smb_AuthenticateUser for user [%s] domain [%s]"), accountName, primaryDomain);
534 OutputDebugF(_C("ciPwdLength is %d and csPwdLength is %d"), ciPwdLength, csPwdLength);
536 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
537 OutputDebugF(_C("ciPwdLength or csPwdLength is too long"));
538 return CM_ERROR_BADPASSWORD;
541 memset(&lmAuth,0,sizeof(lmAuth));
543 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
545 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
546 cm_ClientStringToUtf16(primaryDomain, -1, lmAuth.primaryDomainW, P_LEN);
547 lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
548 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
550 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
551 cm_ClientStringToUtf16(accountName, -1, lmAuth.accountNameW, P_LEN);
552 lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
553 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
555 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
556 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
557 size = MAX_COMPUTERNAME_LENGTH + 1;
558 GetComputerNameW(lmAuth.workstationW, &size);
559 lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
561 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
563 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
564 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
565 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
566 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
568 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
569 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
570 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
571 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
573 lmAuth.lmlogon.ParameterControl = 0;
575 lmAuth.tgroups.GroupCount = 0;
576 lmAuth.tgroups.Groups[0].Sid = NULL;
577 lmAuth.tgroups.Groups[0].Attributes = 0;
580 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
582 lmAuth.tsource.SourceIdentifier.HighPart = 0;
584 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
585 StringCchCopyA(lmAuth.tsource.SourceName, lengthof(lmAuth.tsource.SourceName),
586 "OpenAFS"); /* 8 char limit */
588 nts = LsaLogonUser( smb_lsaHandle,
603 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
604 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
607 OutputDebugF(_C("Return from LsaLogonUser is 0x%lX"), nts);
608 OutputDebugF(_C("Extended status is 0x%lX"), ntsEx);
610 if (nts == ERROR_SUCCESS) {
612 LsaFreeReturnBuffer(lmprofilep);
613 CloseHandle(lmToken);
617 if (nts == 0xC000015BL)
618 return CM_ERROR_BADLOGONTYPE;
619 else /* our catchall is a bad password though we could be more specific */
620 return CM_ERROR_BADPASSWORD;
624 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
625 long smb_GetNormalizedUsername(clientchar_t * usern, const clientchar_t * accountName, const clientchar_t * domainName)
627 clientchar_t * atsign;
628 const clientchar_t * domain;
630 /* check if we have sane input */
631 if ((cm_ClientStrLen(accountName) + cm_ClientStrLen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
634 /* we could get : [accountName][domainName]
640 atsign = cm_ClientStrChr(accountName, '@');
642 if (atsign) /* [user@domain][] -> [user@domain][domain] */
647 /* if for some reason the client doesn't know what domain to use,
648 it will either return an empty string or a '?' */
649 if (!domain[0] || domain[0] == '?')
650 /* Empty domains and empty usernames are usually sent from tokenless contexts.
651 This way such logins will get an empty username (easy to check). I don't know
652 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
653 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, accountName);
655 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
656 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, domain);
657 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, _C("\\"));
659 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
661 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
664 cm_ClientStrLwr(usern);
669 /* When using SMB auth, all SMB sessions have to pass through here
670 * first to authenticate the user.
672 * Caveat: If not using SMB auth, the protocol does not require
673 * sending a session setup packet, which means that we can't rely on a
674 * UID in subsequent packets. Though in practice we get one anyway.
676 /* SMB_COM_SESSION_SETUP_ANDX */
677 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
681 unsigned short newUid;
682 unsigned long caps = 0;
684 clientchar_t *s1 = _C(" ");
686 clientchar_t usern[SMB_MAX_USERNAME_LENGTH];
687 char *secBlobOut = NULL;
688 int secBlobOutLength = 0;
690 /* Check for bad conns */
691 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
692 return CM_ERROR_REMOTECONN;
694 if (vcp->flags & SMB_VCFLAG_USENT) {
695 if (smb_authType == SMB_AUTH_EXTENDED) {
696 /* extended authentication */
700 OutputDebugF(_C("NT Session Setup: Extended"));
702 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
703 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
706 secBlobInLength = smb_GetSMBParm(inp, 7);
707 secBlobIn = smb_GetSMBData(inp, NULL);
709 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
711 if (code == CM_ERROR_GSSCONTINUE) {
714 smb_SetSMBParm(outp, 2, 0);
715 smb_SetSMBParm(outp, 3, secBlobOutLength);
717 tp = smb_GetSMBData(outp, NULL);
718 if (secBlobOutLength) {
719 memcpy(tp, secBlobOut, secBlobOutLength);
721 tp += secBlobOutLength;
722 cb_data += secBlobOutLength;
724 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
725 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
726 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
728 smb_SetSMBDataLength(outp, cb_data);
731 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
733 unsigned ciPwdLength, csPwdLength;
735 clientchar_t *accountName;
736 clientchar_t *primaryDomain;
739 if (smb_authType == SMB_AUTH_NTLM)
740 OutputDebugF(_C("NT Session Setup: NTLM"));
742 OutputDebugF(_C("NT Session Setup: None"));
744 /* TODO: parse for extended auth as well */
745 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
746 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
748 tp = smb_GetSMBData(inp, &datalen);
750 OutputDebugF(_C("Session packet data size [%d]"),datalen);
757 accountName = smb_ParseString(inp, tp, &tp, 0);
758 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
760 OutputDebugF(_C("Account Name: %s"),accountName);
761 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
762 OutputDebugF(_C("Case Sensitive Password: %s"),
763 csPwd && csPwd[0] ? _C("yes") : _C("no"));
764 OutputDebugF(_C("Case Insensitive Password: %s"),
765 ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
767 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
768 /* shouldn't happen */
769 code = CM_ERROR_BADSMB;
770 goto after_read_packet;
773 /* capabilities are only valid for first session packet */
774 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
775 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
778 if (smb_authType == SMB_AUTH_NTLM) {
779 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
781 OutputDebugF(_C("LM authentication failed [%d]"), code);
783 OutputDebugF(_C("LM authentication succeeded"));
787 unsigned ciPwdLength;
789 clientchar_t *accountName;
790 clientchar_t *primaryDomain;
792 switch ( smb_authType ) {
793 case SMB_AUTH_EXTENDED:
794 OutputDebugF(_C("V3 Session Setup: Extended"));
797 OutputDebugF(_C("V3 Session Setup: NTLM"));
800 OutputDebugF(_C("V3 Session Setup: None"));
802 ciPwdLength = smb_GetSMBParm(inp, 7);
803 tp = smb_GetSMBData(inp, NULL);
807 accountName = smb_ParseString(inp, tp, &tp, 0);
808 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
810 OutputDebugF(_C("Account Name: %s"),accountName);
811 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
812 OutputDebugF(_C("Case Insensitive Password: %s"), ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
814 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
815 /* shouldn't happen */
816 code = CM_ERROR_BADSMB;
817 goto after_read_packet;
820 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
823 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
824 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
826 OutputDebugF(_C("LM authentication failed [%d]"), code);
828 OutputDebugF(_C("LM authentication succeeded"));
833 /* note down that we received a session setup X and set the capabilities flag */
834 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
835 lock_ObtainMutex(&vcp->mx);
836 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
837 /* for the moment we can only deal with NTSTATUS */
838 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
839 vcp->flags |= SMB_VCFLAG_STATUS32;
843 if ((caps & NTNEGOTIATE_CAPABILITY_UNICODE) && smb_UseUnicode) {
844 vcp->flags |= SMB_VCFLAG_USEUNICODE;
847 lock_ReleaseMutex(&vcp->mx);
850 /* code would be non-zero if there was an authentication failure.
851 Ideally we would like to invalidate the uid for this session or break
852 early to avoid accidently stealing someone else's tokens. */
858 OutputDebugF(_C("Received username=[%s]"), usern);
860 /* On Windows 2000, this function appears to be called more often than
861 it is expected to be called. This resulted in multiple smb_user_t
862 records existing all for the same user session which results in all
863 of the users tokens disappearing.
865 To avoid this problem, we look for an existing smb_user_t record
866 based on the users name, and use that one if we find it.
869 uidp = smb_FindUserByNameThisSession(vcp, usern);
870 if (uidp) { /* already there, so don't create a new one */
872 newUid = uidp->userID;
873 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
874 vcp->lana,vcp->lsn,newUid);
875 smb_ReleaseUID(uidp);
880 /* do a global search for the username/machine name pair */
881 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
882 lock_ObtainMutex(&unp->mx);
883 if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
884 /* clear the afslogon flag so that the tickets can now
885 * be freed when the refCount returns to zero.
887 unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
889 lock_ReleaseMutex(&unp->mx);
891 /* Create a new UID and cm_user_t structure */
894 userp = cm_NewUser();
895 cm_HoldUserVCRef(userp);
896 lock_ObtainMutex(&vcp->mx);
897 if (!vcp->uidCounter)
898 vcp->uidCounter++; /* handle unlikely wraparounds */
899 newUid = (cm_ClientStrLen(usern)==0)?0:vcp->uidCounter++;
900 lock_ReleaseMutex(&vcp->mx);
902 /* Create a new smb_user_t structure and connect them up */
903 lock_ObtainMutex(&unp->mx);
905 lock_ReleaseMutex(&unp->mx);
907 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
909 lock_ObtainMutex(&uidp->mx);
911 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
912 lock_ReleaseMutex(&uidp->mx);
913 smb_ReleaseUID(uidp);
917 /* Return UID to the client */
918 ((smb_t *)outp)->uid = newUid;
919 /* Also to the next chained message */
920 ((smb_t *)inp)->uid = newUid;
922 osi_Log3(smb_logp, "SMB3 session setup name %S creating ID %d%S",
923 osi_LogSaveClientString(smb_logp, usern), newUid,
924 osi_LogSaveClientString(smb_logp, s1));
926 smb_SetSMBParm(outp, 2, 0);
928 if (vcp->flags & SMB_VCFLAG_USENT) {
929 if (smb_authType == SMB_AUTH_EXTENDED) {
932 smb_SetSMBParm(outp, 3, secBlobOutLength);
934 tp = smb_GetSMBData(outp, NULL);
935 if (secBlobOutLength) {
936 memcpy(tp, secBlobOut, secBlobOutLength);
938 tp += secBlobOutLength;
939 cb_data += secBlobOutLength;
942 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
943 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
944 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
946 smb_SetSMBDataLength(outp, cb_data);
948 smb_SetSMBDataLength(outp, 0);
951 if (smb_authType == SMB_AUTH_EXTENDED) {
954 tp = smb_GetSMBData(outp, NULL);
956 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
957 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
958 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
960 smb_SetSMBDataLength(outp, cb_data);
962 smb_SetSMBDataLength(outp, 0);
969 /* SMB_COM_LOGOFF_ANDX */
970 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
974 /* find the tree and free it */
975 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
977 smb_username_t * unp;
979 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %S", uidp->userID,
980 osi_LogSaveClientString(smb_logp, (uidp->unp) ? uidp->unp->name: _C(" ")));
982 lock_ObtainMutex(&uidp->mx);
983 uidp->flags |= SMB_USERFLAG_DELETE;
985 * it doesn't get deleted right away
986 * because the vcp points to it
989 lock_ReleaseMutex(&uidp->mx);
992 /* we can't do this. we get logoff messages prior to a session
993 * disconnect even though it doesn't mean the user is logging out.
994 * we need to create a new pioctl and EventLogoff handler to set
995 * SMB_USERNAMEFLAG_LOGOFF.
997 if (unp && smb_LogoffTokenTransfer) {
998 lock_ObtainMutex(&unp->mx);
999 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
1000 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
1001 lock_ReleaseMutex(&unp->mx);
1005 smb_ReleaseUID(uidp);
1008 osi_Log0(smb_logp, "SMB3 user logoffX");
1010 smb_SetSMBDataLength(outp, 0);
1014 #define SMB_SUPPORT_SEARCH_BITS 0x0001
1015 #define SMB_SHARE_IS_IN_DFS 0x0002
1017 /* SMB_COM_TREE_CONNECT_ANDX */
1018 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1021 smb_user_t *uidp = NULL;
1022 unsigned short newTid;
1023 clientchar_t shareName[AFSPATHMAX];
1024 clientchar_t *sharePath;
1027 clientchar_t *slashp;
1028 clientchar_t *pathp;
1029 clientchar_t *passwordp;
1030 clientchar_t *servicep;
1031 cm_user_t *userp = NULL;
1034 osi_Log0(smb_logp, "SMB3 receive tree connect");
1036 /* parse input parameters */
1037 tp = smb_GetSMBData(inp, NULL);
1038 passwordp = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1039 pathp = smb_ParseString(inp, tp, &tp, SMB_STRF_ANSIPATH);
1040 servicep = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1042 slashp = cm_ClientStrRChr(pathp, '\\');
1044 return CM_ERROR_BADSMB;
1046 cm_ClientStrCpy(shareName, lengthof(shareName), slashp+1);
1048 osi_Log3(smb_logp, "Tree connect pathp[%S] shareName[%S] service[%S]",
1049 osi_LogSaveClientString(smb_logp, pathp),
1050 osi_LogSaveClientString(smb_logp, shareName),
1051 osi_LogSaveClientString(smb_logp, servicep));
1053 if (cm_ClientStrCmp(servicep, _C("IPC")) == 0 ||
1054 cm_ClientStrCmp(shareName, _C("IPC$")) == 0) {
1056 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1059 return CM_ERROR_NOIPC;
1063 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1065 userp = smb_GetUserFromUID(uidp);
1067 lock_ObtainMutex(&vcp->mx);
1068 newTid = vcp->tidCounter++;
1069 lock_ReleaseMutex(&vcp->mx);
1071 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1074 if (!cm_ClientStrCmp(shareName, _C("*.")))
1075 cm_ClientStrCpy(shareName, lengthof(shareName), _C("all"));
1076 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1079 smb_ReleaseUID(uidp);
1080 smb_ReleaseTID(tidp, FALSE);
1081 return CM_ERROR_BADSHARENAME;
1084 if (vcp->flags & SMB_VCFLAG_USENT)
1086 int policy = smb_FindShareCSCPolicy(shareName);
1089 DWORD dwAdvertiseDFS = 0, dwSize = sizeof(DWORD);
1091 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1092 0, KEY_QUERY_VALUE, &parmKey);
1093 if (code == ERROR_SUCCESS) {
1094 code = RegQueryValueEx(parmKey, "AdvertiseDFS", NULL, NULL,
1095 (BYTE *)&dwAdvertiseDFS, &dwSize);
1096 if (code != ERROR_SUCCESS)
1098 RegCloseKey (parmKey);
1100 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1101 (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
1105 smb_SetSMBParm(outp, 2, 0);
1109 smb_ReleaseUID(uidp);
1111 lock_ObtainMutex(&tidp->mx);
1112 tidp->userp = userp;
1113 tidp->pathname = sharePath;
1115 tidp->flags |= SMB_TIDFLAG_IPC;
1116 lock_ReleaseMutex(&tidp->mx);
1117 smb_ReleaseTID(tidp, FALSE);
1119 ((smb_t *)outp)->tid = newTid;
1120 ((smb_t *)inp)->tid = newTid;
1121 tp = smb_GetSMBData(outp, NULL);
1125 tp = smb_UnparseString(outp, tp, _C("A:"), &cb_data, SMB_STRF_FORCEASCII);
1126 tp = smb_UnparseString(outp, tp, _C("AFS"), &cb_data, 0);
1127 smb_SetSMBDataLength(outp, cb_data);
1131 tp = smb_UnparseString(outp, tp, _C("IPC"), &cb_data, SMB_STRF_FORCEASCII);
1132 smb_SetSMBDataLength(outp, cb_data);
1135 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1139 /* must be called with global tran lock held */
1140 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1142 smb_tran2Packet_t *tp;
1145 smbp = (smb_t *) inp->data;
1146 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1147 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1153 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1154 int totalParms, int totalData)
1156 smb_tran2Packet_t *tp;
1159 smbp = (smb_t *) inp->data;
1160 tp = malloc(sizeof(*tp));
1161 memset(tp, 0, sizeof(*tp));
1164 tp->curData = tp->curParms = 0;
1165 tp->totalData = totalData;
1166 tp->totalParms = totalParms;
1167 tp->tid = smbp->tid;
1168 tp->mid = smbp->mid;
1169 tp->uid = smbp->uid;
1170 tp->pid = smbp->pid;
1171 tp->res[0] = smbp->res[0];
1172 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1173 if (totalParms != 0)
1174 tp->parmsp = malloc(totalParms);
1176 tp->datap = malloc(totalData);
1177 if (smbp->com == 0x25 || smbp->com == 0x26)
1180 tp->opcode = smb_GetSMBParm(inp, 14);
1183 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1185 if (WANTS_UNICODE(inp) && (vcp->flags & SMB_VCFLAG_USEUNICODE))
1186 tp->flags |= SMB_TRAN2PFLAG_USEUNICODE;
1191 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1192 smb_tran2Packet_t *inp, smb_packet_t *outp,
1193 int totalParms, int totalData)
1195 smb_tran2Packet_t *tp;
1196 unsigned short parmOffset;
1197 unsigned short dataOffset;
1198 unsigned short dataAlign;
1200 tp = malloc(sizeof(*tp));
1201 memset(tp, 0, sizeof(*tp));
1204 tp->curData = tp->curParms = 0;
1205 tp->totalData = totalData;
1206 tp->totalParms = totalParms;
1207 tp->oldTotalParms = totalParms;
1212 tp->res[0] = inp->res[0];
1213 tp->opcode = inp->opcode;
1217 * We calculate where the parameters and data will start.
1218 * This calculation must parallel the calculation in
1219 * smb_SendTran2Packet.
1222 parmOffset = 10*2 + 35;
1223 parmOffset++; /* round to even */
1224 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1226 dataOffset = parmOffset + totalParms;
1227 dataAlign = dataOffset & 2; /* quad-align */
1228 dataOffset += dataAlign;
1229 tp->datap = outp->data + dataOffset;
1234 /* free a tran2 packet */
1235 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1238 smb_ReleaseVC(t2p->vcp);
1241 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1247 while (t2p->stringsp) {
1251 t2p->stringsp = ns->nextp;
1257 clientchar_t *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
1258 char ** chainpp, int flags)
1263 if (!(p->flags & SMB_TRAN2PFLAG_USEUNICODE))
1264 flags |= SMB_STRF_FORCEASCII;
1267 cb = p->totalParms - (inp - (char *)p->parmsp);
1268 if (inp < (char *) p->parmsp ||
1269 inp >= ((char *) p->parmsp) + p->totalParms) {
1270 #ifdef DEBUG_UNICODE
1276 return smb_ParseStringBuf((unsigned char *) p->parmsp, &p->stringsp,
1277 inp, &cb, chainpp, flags);
1280 /* called with a VC, an input packet to respond to, and an error code.
1281 * sends an error response.
1283 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1284 smb_packet_t *tp, long code)
1287 unsigned short errCode;
1288 unsigned char errClass;
1289 unsigned long NTStatus;
1291 if (vcp->flags & SMB_VCFLAG_STATUS32)
1292 smb_MapNTError(code, &NTStatus);
1294 smb_MapCoreError(code, vcp, &errCode, &errClass);
1296 smb_FormatResponsePacket(vcp, NULL, tp);
1297 smbp = (smb_t *) tp;
1299 /* We can handle long names */
1300 if (vcp->flags & SMB_VCFLAG_USENT)
1301 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1303 /* now copy important fields from the tran 2 packet */
1304 smbp->com = t2p->com;
1305 smbp->tid = t2p->tid;
1306 smbp->mid = t2p->mid;
1307 smbp->pid = t2p->pid;
1308 smbp->uid = t2p->uid;
1309 smbp->res[0] = t2p->res[0];
1310 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1311 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1312 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1313 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1314 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1315 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1318 smbp->rcls = errClass;
1319 smbp->errLow = (unsigned char) (errCode & 0xff);
1320 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1324 smb_SendPacket(vcp, tp);
1327 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1330 unsigned short parmOffset;
1331 unsigned short dataOffset;
1332 unsigned short totalLength;
1333 unsigned short dataAlign;
1336 smb_FormatResponsePacket(vcp, NULL, tp);
1337 smbp = (smb_t *) tp;
1339 /* We can handle long names */
1340 if (vcp->flags & SMB_VCFLAG_USENT)
1341 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1343 /* now copy important fields from the tran 2 packet */
1344 smbp->com = t2p->com;
1345 smbp->tid = t2p->tid;
1346 smbp->mid = t2p->mid;
1347 smbp->pid = t2p->pid;
1348 smbp->uid = t2p->uid;
1349 smbp->res[0] = t2p->res[0];
1351 totalLength = 1 + t2p->totalData + t2p->totalParms;
1353 /* now add the core parameters (tran2 info) to the packet */
1354 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1355 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1356 smb_SetSMBParm(tp, 2, 0); /* reserved */
1357 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1358 parmOffset = 10*2 + 35; /* parm offset in packet */
1359 parmOffset++; /* round to even */
1360 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1361 * hdr, bcc and wct */
1362 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1363 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1364 dataOffset = parmOffset + t2p->oldTotalParms;
1365 dataAlign = dataOffset & 2; /* quad-align */
1366 dataOffset += dataAlign;
1367 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1368 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1369 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1372 datap = smb_GetSMBData(tp, NULL);
1373 *datap++ = 0; /* we rounded to even */
1375 totalLength += dataAlign;
1376 smb_SetSMBDataLength(tp, totalLength);
1378 /* next, send the datagram */
1379 smb_SendPacket(vcp, tp);
1383 /* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
1384 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1386 smb_tran2Packet_t *asp;
1399 /* We sometimes see 0 word count. What to do? */
1400 if (*inp->wctp == 0) {
1401 osi_Log0(smb_logp, "Transaction2 word count = 0");
1402 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1404 smb_SetSMBDataLength(outp, 0);
1405 smb_SendPacket(vcp, outp);
1409 totalParms = smb_GetSMBParm(inp, 0);
1410 totalData = smb_GetSMBParm(inp, 1);
1412 firstPacket = (inp->inCom == 0x25);
1414 /* find the packet we're reassembling */
1415 lock_ObtainWrite(&smb_globalLock);
1416 asp = smb_FindTran2Packet(vcp, inp);
1418 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1420 lock_ReleaseWrite(&smb_globalLock);
1422 /* now merge in this latest packet; start by looking up offsets */
1424 parmDisp = dataDisp = 0;
1425 parmOffset = smb_GetSMBParm(inp, 10);
1426 dataOffset = smb_GetSMBParm(inp, 12);
1427 parmCount = smb_GetSMBParm(inp, 9);
1428 dataCount = smb_GetSMBParm(inp, 11);
1429 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1430 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1432 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1433 totalData, dataCount, asp->maxReturnData);
1436 parmDisp = smb_GetSMBParm(inp, 4);
1437 parmOffset = smb_GetSMBParm(inp, 3);
1438 dataDisp = smb_GetSMBParm(inp, 7);
1439 dataOffset = smb_GetSMBParm(inp, 6);
1440 parmCount = smb_GetSMBParm(inp, 2);
1441 dataCount = smb_GetSMBParm(inp, 5);
1443 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1444 parmCount, dataCount);
1447 /* now copy the parms and data */
1448 if ( asp->totalParms > 0 && parmCount != 0 )
1450 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1452 if ( asp->totalData > 0 && dataCount != 0 ) {
1453 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1456 /* account for new bytes */
1457 asp->curData += dataCount;
1458 asp->curParms += parmCount;
1460 /* finally, if we're done, remove the packet from the queue and dispatch it */
1461 if (asp->totalParms > 0 &&
1462 asp->curParms > 0 &&
1463 asp->totalData <= asp->curData &&
1464 asp->totalParms <= asp->curParms) {
1465 /* we've received it all */
1466 lock_ObtainWrite(&smb_globalLock);
1467 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1468 lock_ReleaseWrite(&smb_globalLock);
1470 /* now dispatch it */
1471 rapOp = asp->parmsp[0];
1473 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1474 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1475 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1476 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
1479 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1480 code = CM_ERROR_BADOP;
1483 /* if an error is returned, we're supposed to send an error packet,
1484 * otherwise the dispatched function already did the data sending.
1485 * We give dispatched proc the responsibility since it knows how much
1486 * space to allocate.
1489 smb_SendTran2Error(vcp, asp, outp, code);
1492 /* free the input tran 2 packet */
1493 smb_FreeTran2Packet(asp);
1495 else if (firstPacket) {
1496 /* the first packet in a multi-packet request, we need to send an
1497 * ack to get more data.
1499 smb_SetSMBDataLength(outp, 0);
1500 smb_SendPacket(vcp, outp);
1506 /* ANSI versions. */
1508 #pragma pack(push, 1)
1510 typedef struct smb_rap_share_info_0 {
1511 BYTE shi0_netname[13];
1512 } smb_rap_share_info_0_t;
1514 typedef struct smb_rap_share_info_1 {
1515 BYTE shi1_netname[13];
1518 DWORD shi1_remark; /* char *shi1_remark; data offset */
1519 } smb_rap_share_info_1_t;
1521 typedef struct smb_rap_share_info_2 {
1522 BYTE shi2_netname[13];
1525 DWORD shi2_remark; /* char *shi2_remark; data offset */
1526 WORD shi2_permissions;
1528 WORD shi2_current_uses;
1529 DWORD shi2_path; /* char *shi2_path; data offset */
1530 WORD shi2_passwd[9];
1532 } smb_rap_share_info_2_t;
1534 #define SMB_RAP_MAX_SHARES 512
1536 typedef struct smb_rap_share_list {
1539 smb_rap_share_info_0_t * shares;
1540 } smb_rap_share_list_t;
1544 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1545 smb_rap_share_list_t * sp;
1547 if (dep->name[0] == '.' && (!dep->name[1] || (dep->name[1] == '.' && !dep->name[2])))
1548 return 0; /* skip over '.' and '..' */
1550 sp = (smb_rap_share_list_t *) vrockp;
1552 strncpy(sp->shares[sp->cShare].shi0_netname, dep->name, 12);
1553 sp->shares[sp->cShare].shi0_netname[12] = 0;
1557 if (sp->cShare >= sp->maxShares)
1558 return CM_ERROR_STOPNOW;
1563 /* RAP NetShareEnumRequest */
1564 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1566 smb_tran2Packet_t *outp;
1567 unsigned short * tp;
1571 int outParmsTotal; /* total parameter bytes */
1572 int outDataTotal; /* total data bytes */
1575 DWORD allSubmount = 0;
1577 DWORD nRegShares = 0;
1578 DWORD nSharesRet = 0;
1580 HKEY hkSubmount = NULL;
1581 smb_rap_share_info_1_t * shares;
1584 clientchar_t thisShare[AFSPATHMAX];
1588 smb_rap_share_list_t rootShares;
1593 tp = p->parmsp + 1; /* skip over function number (always 0) */
1596 clientchar_t * cdescp;
1598 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1599 if (cm_ClientStrCmp(cdescp, _C("WrLeh")))
1600 return CM_ERROR_INVAL;
1601 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1602 if (cm_ClientStrCmp(cdescp, _C("B13BWz")))
1603 return CM_ERROR_INVAL;
1609 if (infoLevel != 1) {
1610 return CM_ERROR_INVAL;
1613 /* We are supposed to use the same ASCII data structure even if
1614 Unicode is negotiated, which ultimately means that the share
1615 names that we return must be at most 13 characters in length,
1616 including the NULL terminator.
1618 The RAP specification states that shares with names longer than
1619 12 characters should not be included in the enumeration.
1620 However, since we support prefix cell references and since many
1621 cell names are going to exceed 12 characters, we lie and send
1622 the first 12 characters.
1625 /* first figure out how many shares there are */
1626 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1627 KEY_QUERY_VALUE, &hkParam);
1628 if (rv == ERROR_SUCCESS) {
1629 len = sizeof(allSubmount);
1630 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1631 (BYTE *) &allSubmount, &len);
1632 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1635 RegCloseKey (hkParam);
1638 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1639 0, KEY_QUERY_VALUE, &hkSubmount);
1640 if (rv == ERROR_SUCCESS) {
1641 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1642 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1643 if (rv != ERROR_SUCCESS)
1649 /* fetch the root shares */
1650 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1651 rootShares.cShare = 0;
1652 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1656 userp = smb_GetTran2User(vcp,p);
1658 thyper.HighPart = 0;
1661 cm_HoldSCache(cm_data.rootSCachep);
1662 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1663 cm_ReleaseSCache(cm_data.rootSCachep);
1665 cm_ReleaseUser(userp);
1667 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1669 #define REMARK_LEN 1
1670 outParmsTotal = 8; /* 4 dwords */
1671 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1672 if(outDataTotal > bufsize) {
1673 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1674 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1677 nSharesRet = nShares;
1680 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1682 /* now for the submounts */
1683 shares = (smb_rap_share_info_1_t *) outp->datap;
1684 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1686 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1689 StringCchCopyA(shares[cshare].shi1_netname,
1690 lengthof(shares[cshare].shi1_netname), "all" );
1691 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1692 /* type and pad are zero already */
1698 for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
1699 len = sizeof(thisShare);
1700 rv = RegEnumValueW(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
1701 if (rv == ERROR_SUCCESS &&
1702 cm_ClientStrLen(thisShare) &&
1703 (!allSubmount || cm_ClientStrCmpI(thisShare,_C("all")))) {
1704 cm_ClientStringToUtf8(thisShare, -1, shares[cshare].shi1_netname,
1705 lengthof( shares[cshare].shi1_netname ));
1706 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1707 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1712 nShares--; /* uncount key */
1715 RegCloseKey(hkSubmount);
1718 nonrootShares = cshare;
1720 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1721 /* in case there are collisions with submounts, submounts have
1723 for (j=0; j < nonrootShares; j++)
1724 if (!cm_stricmp_utf8(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1727 if (j < nonrootShares) {
1728 nShares--; /* uncount */
1732 StringCchCopyA(shares[cshare].shi1_netname, lengthof(shares[cshare].shi1_netname),
1733 rootShares.shares[i].shi0_netname);
1734 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1739 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1740 outp->parmsp[1] = 0;
1741 outp->parmsp[2] = cshare;
1742 outp->parmsp[3] = nShares;
1744 outp->totalData = (int)(cstrp - outp->datap);
1745 outp->totalParms = outParmsTotal;
1747 smb_SendTran2Packet(vcp, outp, op);
1748 smb_FreeTran2Packet(outp);
1750 free(rootShares.shares);
1755 /* RAP NetShareGetInfo */
1756 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1758 smb_tran2Packet_t *outp;
1759 unsigned short * tp;
1760 clientchar_t * shareName;
1761 BOOL shareFound = FALSE;
1762 unsigned short infoLevel;
1763 unsigned short bufsize;
1772 cm_scache_t *scp = NULL;
1778 tp = p->parmsp + 1; /* skip over function number (always 1) */
1781 clientchar_t * cdescp;
1783 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1784 if (cm_ClientStrCmp(cdescp, _C("zWrLh")))
1786 return CM_ERROR_INVAL;
1788 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1789 if (cm_ClientStrCmp(cdescp, _C("B13")) &&
1790 cm_ClientStrCmp(cdescp, _C("B13BWz")) &&
1791 cm_ClientStrCmp(cdescp, _C("B13BWzWWWzB9B")))
1793 return CM_ERROR_INVAL;
1795 shareName = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1803 totalData = sizeof(smb_rap_share_info_0_t);
1804 else if(infoLevel == SMB_INFO_STANDARD)
1805 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1806 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1807 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1809 return CM_ERROR_INVAL;
1811 if(!cm_ClientStrCmpI(shareName, _C("all")) || !cm_ClientStrCmp(shareName,_C("*."))) {
1812 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1813 KEY_QUERY_VALUE, &hkParam);
1814 if (rv == ERROR_SUCCESS) {
1815 len = sizeof(allSubmount);
1816 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1817 (BYTE *) &allSubmount, &len);
1818 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1821 RegCloseKey (hkParam);
1828 userp = smb_GetTran2User(vcp, p);
1830 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
1831 return CM_ERROR_BADSMB;
1833 code = cm_NameI(cm_data.rootSCachep, shareName,
1834 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
1835 userp, NULL, &req, &scp);
1837 cm_ReleaseSCache(scp);
1840 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1841 KEY_QUERY_VALUE, &hkSubmount);
1842 if (rv == ERROR_SUCCESS) {
1843 rv = RegQueryValueExW(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1844 if (rv == ERROR_SUCCESS) {
1847 RegCloseKey(hkSubmount);
1853 return CM_ERROR_BADSHARENAME;
1855 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1856 memset(outp->datap, 0, totalData);
1858 outp->parmsp[0] = 0;
1859 outp->parmsp[1] = 0;
1860 outp->parmsp[2] = totalData;
1862 if (infoLevel == 0) {
1863 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1864 cm_ClientStringToUtf8(shareName, -1, info->shi0_netname,
1865 lengthof(info->shi0_netname));
1866 } else if(infoLevel == SMB_INFO_STANDARD) {
1867 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1868 cm_ClientStringToUtf8(shareName, -1, info->shi1_netname, lengthof(info->shi1_netname));
1869 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1870 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1871 /* type and pad are already zero */
1872 } else { /* infoLevel==2 */
1873 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1874 cm_ClientStringToUtf8(shareName, -1, info->shi2_netname, lengthof(info->shi2_netname));
1875 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1876 info->shi2_permissions = ACCESS_ALL;
1877 info->shi2_max_uses = (unsigned short) -1;
1878 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
1881 outp->totalData = totalData;
1882 outp->totalParms = totalParam;
1884 smb_SendTran2Packet(vcp, outp, op);
1885 smb_FreeTran2Packet(outp);
1890 #pragma pack(push, 1)
1892 typedef struct smb_rap_wksta_info_10 {
1893 DWORD wki10_computername; /*char *wki10_computername;*/
1894 DWORD wki10_username; /* char *wki10_username; */
1895 DWORD wki10_langroup; /* char *wki10_langroup;*/
1896 BYTE wki10_ver_major;
1897 BYTE wki10_ver_minor;
1898 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1899 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1900 } smb_rap_wksta_info_10_t;
1904 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1906 smb_tran2Packet_t *outp;
1910 unsigned short * tp;
1913 smb_rap_wksta_info_10_t * info;
1917 tp = p->parmsp + 1; /* Skip over function number */
1920 clientchar_t * cdescp;
1922 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
1923 SMB_STRF_FORCEASCII);
1924 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
1925 return CM_ERROR_INVAL;
1927 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
1928 SMB_STRF_FORCEASCII);
1929 if (cm_ClientStrCmp(cdescp, _C("zzzBBzz")))
1930 return CM_ERROR_INVAL;
1936 if (infoLevel != 10) {
1937 return CM_ERROR_INVAL;
1943 totalData = sizeof(*info) + /* info */
1944 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1945 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1946 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1947 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1948 1; /* wki10_oth_domains (null)*/
1950 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1952 memset(outp->parmsp,0,totalParams);
1953 memset(outp->datap,0,totalData);
1955 info = (smb_rap_wksta_info_10_t *) outp->datap;
1956 cstrp = (char *) (info + 1);
1958 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1959 StringCbCopyA(cstrp, totalData, smb_localNamep);
1960 cstrp += strlen(cstrp) + 1;
1962 info->wki10_username = (DWORD) (cstrp - outp->datap);
1963 uidp = smb_FindUID(vcp, p->uid, 0);
1965 lock_ObtainMutex(&uidp->mx);
1966 if(uidp->unp && uidp->unp->name)
1967 cm_ClientStringToUtf8(uidp->unp->name, -1,
1968 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
1969 lock_ReleaseMutex(&uidp->mx);
1970 smb_ReleaseUID(uidp);
1972 cstrp += strlen(cstrp) + 1;
1974 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1975 StringCbCopyA(cstrp, totalData - (cstrp - outp->datap)*sizeof(char), "WORKGROUP");
1976 cstrp += strlen(cstrp) + 1;
1978 /* TODO: Not sure what values these should take, but these work */
1979 info->wki10_ver_major = 5;
1980 info->wki10_ver_minor = 1;
1982 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1983 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
1984 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
1985 cstrp += strlen(cstrp) + 1;
1987 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1988 cstrp ++; /* no other domains */
1990 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1991 outp->parmsp[2] = outp->totalData;
1992 outp->totalParms = totalParams;
1994 smb_SendTran2Packet(vcp,outp,op);
1995 smb_FreeTran2Packet(outp);
2000 #pragma pack(push, 1)
2002 typedef struct smb_rap_server_info_0 {
2004 } smb_rap_server_info_0_t;
2006 typedef struct smb_rap_server_info_1 {
2008 BYTE sv1_version_major;
2009 BYTE sv1_version_minor;
2011 DWORD sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
2012 } smb_rap_server_info_1_t;
2016 char smb_ServerComment[] = "OpenAFS Client";
2017 int smb_ServerCommentLen = sizeof(smb_ServerComment);
2019 #define SMB_SV_TYPE_SERVER 0x00000002L
2020 #define SMB_SV_TYPE_NT 0x00001000L
2021 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
2023 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2025 smb_tran2Packet_t *outp;
2029 unsigned short * tp;
2032 smb_rap_server_info_0_t * info0;
2033 smb_rap_server_info_1_t * info1;
2036 tp = p->parmsp + 1; /* Skip over function number */
2039 clientchar_t * cdescp;
2041 cdescp = smb_ParseStringT2Parm(p, (unsigned char *) tp, (char **) &tp,
2042 SMB_STRF_FORCEASCII);
2043 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2044 return CM_ERROR_INVAL;
2045 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2046 SMB_STRF_FORCEASCII);
2047 if (cm_ClientStrCmp(cdescp, _C("B16")) ||
2048 cm_ClientStrCmp(cdescp, _C("B16BBDz")))
2049 return CM_ERROR_INVAL;
2055 if (infoLevel != 0 && infoLevel != 1) {
2056 return CM_ERROR_INVAL;
2062 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
2063 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
2065 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2067 memset(outp->parmsp,0,totalParams);
2068 memset(outp->datap,0,totalData);
2070 if (infoLevel == 0) {
2071 info0 = (smb_rap_server_info_0_t *) outp->datap;
2072 cstrp = (char *) (info0 + 1);
2073 StringCchCopyA(info0->sv0_name, lengthof(info0->sv0_name), "AFS");
2074 } else { /* infoLevel == SMB_INFO_STANDARD */
2075 info1 = (smb_rap_server_info_1_t *) outp->datap;
2076 cstrp = (char *) (info1 + 1);
2077 StringCchCopyA(info1->sv1_name, lengthof(info1->sv1_name), "AFS");
2080 SMB_SV_TYPE_SERVER |
2082 SMB_SV_TYPE_SERVER_NT;
2084 info1->sv1_version_major = 5;
2085 info1->sv1_version_minor = 1;
2086 info1->sv1_comment_or_master_browser = (DWORD) (cstrp - outp->datap);
2088 StringCbCopyA(cstrp, smb_ServerCommentLen, smb_ServerComment);
2090 cstrp += smb_ServerCommentLen / sizeof(char);
2093 totalData = (DWORD)(cstrp - outp->datap);
2094 outp->totalData = min(bufsize,totalData); /* actual data size */
2095 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
2096 outp->parmsp[2] = totalData;
2097 outp->totalParms = totalParams;
2099 smb_SendTran2Packet(vcp,outp,op);
2100 smb_FreeTran2Packet(outp);
2105 /* SMB_COM_TRANSACTION2 and SMB_COM_TRANSACTION2_SECONDARY */
2106 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2108 smb_tran2Packet_t *asp;
2119 DWORD oldTime, newTime;
2121 /* We sometimes see 0 word count. What to do? */
2122 if (*inp->wctp == 0) {
2123 osi_Log0(smb_logp, "Transaction2 word count = 0");
2124 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
2126 smb_SetSMBDataLength(outp, 0);
2127 smb_SendPacket(vcp, outp);
2131 totalParms = smb_GetSMBParm(inp, 0);
2132 totalData = smb_GetSMBParm(inp, 1);
2134 firstPacket = (inp->inCom == 0x32);
2136 /* find the packet we're reassembling */
2137 lock_ObtainWrite(&smb_globalLock);
2138 asp = smb_FindTran2Packet(vcp, inp);
2140 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
2142 lock_ReleaseWrite(&smb_globalLock);
2144 /* now merge in this latest packet; start by looking up offsets */
2146 parmDisp = dataDisp = 0;
2147 parmOffset = smb_GetSMBParm(inp, 10);
2148 dataOffset = smb_GetSMBParm(inp, 12);
2149 parmCount = smb_GetSMBParm(inp, 9);
2150 dataCount = smb_GetSMBParm(inp, 11);
2151 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2152 asp->maxReturnData = smb_GetSMBParm(inp, 3);
2154 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2155 totalData, dataCount, asp->maxReturnData);
2158 parmDisp = smb_GetSMBParm(inp, 4);
2159 parmOffset = smb_GetSMBParm(inp, 3);
2160 dataDisp = smb_GetSMBParm(inp, 7);
2161 dataOffset = smb_GetSMBParm(inp, 6);
2162 parmCount = smb_GetSMBParm(inp, 2);
2163 dataCount = smb_GetSMBParm(inp, 5);
2165 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2166 parmCount, dataCount);
2169 /* now copy the parms and data */
2170 if ( asp->totalParms > 0 && parmCount != 0 )
2172 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2174 if ( asp->totalData > 0 && dataCount != 0 ) {
2175 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2178 /* account for new bytes */
2179 asp->curData += dataCount;
2180 asp->curParms += parmCount;
2182 /* finally, if we're done, remove the packet from the queue and dispatch it */
2183 if (asp->totalParms > 0 &&
2184 asp->curParms > 0 &&
2185 asp->totalData <= asp->curData &&
2186 asp->totalParms <= asp->curParms) {
2187 /* we've received it all */
2188 lock_ObtainWrite(&smb_globalLock);
2189 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2190 lock_ReleaseWrite(&smb_globalLock);
2192 oldTime = GetTickCount();
2194 /* now dispatch it */
2195 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2196 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2197 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2200 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2201 code = CM_ERROR_BADOP;
2204 /* if an error is returned, we're supposed to send an error packet,
2205 * otherwise the dispatched function already did the data sending.
2206 * We give dispatched proc the responsibility since it knows how much
2207 * space to allocate.
2210 smb_SendTran2Error(vcp, asp, outp, code);
2213 newTime = GetTickCount();
2214 if (newTime - oldTime > 45000) {
2217 clientchar_t *treepath = NULL; /* do not free */
2218 clientchar_t *pathname = NULL;
2219 cm_fid_t afid = {0,0,0,0,0};
2221 uidp = smb_FindUID(vcp, asp->uid, 0);
2222 smb_LookupTIDPath(vcp, asp->tid, &treepath);
2223 fidp = smb_FindFID(vcp, inp->fid, 0);
2225 if (fidp && fidp->NTopen_pathp)
2226 pathname = fidp->NTopen_pathp;
2227 else if (inp->stringsp->wdata)
2228 pathname = inp->stringsp->wdata;
2230 if (fidp && fidp->scp)
2231 afid = fidp->scp->fid;
2233 afsi_log("Request %s duration %d ms user %S tid \"%S\" path? \"%S\" afid (%d.%d.%d.%d)",
2234 myCrt_2Dispatch(asp->opcode), newTime - oldTime,
2235 uidp ? uidp->unp->name : NULL,
2238 afid.cell, afid.volume, afid.vnode, afid.unique);
2241 smb_ReleaseUID(uidp);
2243 smb_ReleaseFID(fidp);
2246 /* free the input tran 2 packet */
2247 smb_FreeTran2Packet(asp);
2249 else if (firstPacket) {
2250 /* the first packet in a multi-packet request, we need to send an
2251 * ack to get more data.
2253 smb_SetSMBDataLength(outp, 0);
2254 smb_SendPacket(vcp, outp);
2261 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2263 clientchar_t *pathp;
2264 smb_tran2Packet_t *outp;
2269 cm_scache_t *dscp; /* dir we're dealing with */
2270 cm_scache_t *scp; /* file we're creating */
2272 int initialModeBits;
2275 clientchar_t *lastNamep;
2282 int parmSlot; /* which parm we're dealing with */
2283 long returnEALength;
2284 clientchar_t *tidPathp;
2292 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2293 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2295 openFun = p->parmsp[6]; /* open function */
2296 excl = ((openFun & 3) == 0);
2297 trunc = ((openFun & 3) == 2); /* truncate it */
2298 openMode = (p->parmsp[1] & 0x7);
2299 openAction = 0; /* tracks what we did */
2301 attributes = p->parmsp[3];
2302 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2304 /* compute initial mode bits based on read-only flag in attributes */
2305 initialModeBits = 0666;
2306 if (attributes & SMB_ATTR_READONLY)
2307 initialModeBits &= ~0222;
2309 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
2312 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2314 spacep = cm_GetSpace();
2315 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2318 (cm_ClientStrCmpI(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
2319 cm_ClientStrCmpI(lastNamep, _C("\\srvsvc")) == 0 ||
2320 cm_ClientStrCmpI(lastNamep, _C("\\wkssvc")) == 0 ||
2321 cm_ClientStrCmpI(lastNamep, _C("\\ipc$")) == 0)) {
2322 /* special case magic file name for receiving IOCTL requests
2323 * (since IOCTL calls themselves aren't getting through).
2325 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2326 smb_SetupIoctlFid(fidp, spacep);
2328 /* copy out remainder of the parms */
2330 outp->parmsp[parmSlot++] = fidp->fid;
2332 outp->parmsp[parmSlot++] = 0; /* attrs */
2333 outp->parmsp[parmSlot++] = 0; /* mod time */
2334 outp->parmsp[parmSlot++] = 0;
2335 outp->parmsp[parmSlot++] = 0; /* len */
2336 outp->parmsp[parmSlot++] = 0x7fff;
2337 outp->parmsp[parmSlot++] = openMode;
2338 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2339 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2341 /* and the final "always present" stuff */
2342 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2343 /* next write out the "unique" ID */
2344 outp->parmsp[parmSlot++] = 0x1234;
2345 outp->parmsp[parmSlot++] = 0x5678;
2346 outp->parmsp[parmSlot++] = 0;
2347 if (returnEALength) {
2348 outp->parmsp[parmSlot++] = 0;
2349 outp->parmsp[parmSlot++] = 0;
2352 outp->totalData = 0;
2353 outp->totalParms = parmSlot * 2;
2355 smb_SendTran2Packet(vcp, outp, op);
2357 smb_FreeTran2Packet(outp);
2359 /* and clean up fid reference */
2360 smb_ReleaseFID(fidp);
2364 if (!cm_IsValidClientString(pathp)) {
2366 clientchar_t * hexp;
2368 hexp = cm_GetRawCharsAlloc(pathp, -1);
2369 osi_Log1(smb_logp, "Tran2Open rejecting invalid name. [%S]",
2370 osi_LogSaveClientString(smb_logp, hexp));
2374 osi_Log0(smb_logp, "Tran2Open rejecting invalid name");
2376 smb_FreeTran2Packet(outp);
2377 return CM_ERROR_BADNTFILENAME;
2380 #ifdef DEBUG_VERBOSE
2382 char *hexp, *asciip;
2383 asciip = (lastNamep ? lastNamep : pathp);
2384 hexp = osi_HexifyString( asciip );
2385 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2390 userp = smb_GetTran2User(vcp, p);
2391 /* In the off chance that userp is NULL, we log and abandon */
2393 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2394 smb_FreeTran2Packet(outp);
2395 return CM_ERROR_BADSMB;
2398 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2399 if (code == CM_ERROR_TIDIPC) {
2400 /* Attempt to use a TID allocated for IPC. The client
2401 * is probably looking for DCE RPC end points which we
2402 * don't support OR it could be looking to make a DFS
2405 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2407 cm_ReleaseUser(userp);
2408 smb_FreeTran2Packet(outp);
2409 return CM_ERROR_NOSUCHPATH;
2414 code = cm_NameI(cm_data.rootSCachep, pathp,
2415 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2416 userp, tidPathp, &req, &scp);
2418 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2419 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2420 userp, tidPathp, &req, &dscp);
2421 cm_FreeSpace(spacep);
2424 cm_ReleaseUser(userp);
2425 smb_FreeTran2Packet(outp);
2430 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2431 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2432 (clientchar_t*) spacep->data);
2433 cm_ReleaseSCache(dscp);
2434 cm_ReleaseUser(userp);
2435 smb_FreeTran2Packet(outp);
2436 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2437 return CM_ERROR_PATH_NOT_COVERED;
2439 return CM_ERROR_BADSHARENAME;
2441 #endif /* DFS_SUPPORT */
2443 /* otherwise, scp points to the parent directory. Do a lookup,
2444 * and truncate the file if we find it, otherwise we create the
2451 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2453 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2454 cm_ReleaseSCache(dscp);
2455 cm_ReleaseUser(userp);
2456 smb_FreeTran2Packet(outp);
2461 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2462 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2463 cm_ReleaseSCache(scp);
2464 cm_ReleaseUser(userp);
2465 smb_FreeTran2Packet(outp);
2466 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2467 return CM_ERROR_PATH_NOT_COVERED;
2469 return CM_ERROR_BADSHARENAME;
2471 #endif /* DFS_SUPPORT */
2473 /* macintosh is expensive to program for it */
2474 cm_FreeSpace(spacep);
2477 /* if we get here, if code is 0, the file exists and is represented by
2478 * scp. Otherwise, we have to create it.
2481 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2484 cm_ReleaseSCache(dscp);
2485 cm_ReleaseSCache(scp);
2486 cm_ReleaseUser(userp);
2487 smb_FreeTran2Packet(outp);
2492 /* oops, file shouldn't be there */
2494 cm_ReleaseSCache(dscp);
2495 cm_ReleaseSCache(scp);
2496 cm_ReleaseUser(userp);
2497 smb_FreeTran2Packet(outp);
2498 return CM_ERROR_EXISTS;
2502 setAttr.mask = CM_ATTRMASK_LENGTH;
2503 setAttr.length.LowPart = 0;
2504 setAttr.length.HighPart = 0;
2505 code = cm_SetAttr(scp, &setAttr, userp, &req);
2506 openAction = 3; /* truncated existing file */
2509 openAction = 1; /* found existing file */
2511 else if (!(openFun & 0x10)) {
2512 /* don't create if not found */
2514 cm_ReleaseSCache(dscp);
2515 osi_assertx(scp == NULL, "null cm_scache_t");
2516 cm_ReleaseUser(userp);
2517 smb_FreeTran2Packet(outp);
2518 return CM_ERROR_NOSUCHFILE;
2521 osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2522 openAction = 2; /* created file */
2523 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2524 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2525 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2529 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2530 smb_NotifyChange(FILE_ACTION_ADDED,
2531 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2532 dscp, lastNamep, NULL, TRUE);
2533 } else if (!excl && code == CM_ERROR_EXISTS) {
2534 /* not an exclusive create, and someone else tried
2535 * creating it already, then we open it anyway. We
2536 * don't bother retrying after this, since if this next
2537 * fails, that means that the file was deleted after we
2538 * started this call.
2540 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2544 setAttr.mask = CM_ATTRMASK_LENGTH;
2545 setAttr.length.LowPart = 0;
2546 setAttr.length.HighPart = 0;
2547 code = cm_SetAttr(scp, &setAttr, userp,
2550 } /* lookup succeeded */
2554 /* we don't need this any longer */
2556 cm_ReleaseSCache(dscp);
2559 /* something went wrong creating or truncating the file */
2561 cm_ReleaseSCache(scp);
2562 cm_ReleaseUser(userp);
2563 smb_FreeTran2Packet(outp);
2567 /* make sure we're about to open a file */
2568 if (scp->fileType != CM_SCACHETYPE_FILE) {
2570 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2571 cm_scache_t * targetScp = 0;
2572 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2574 /* we have a more accurate file to use (the
2575 * target of the symbolic link). Otherwise,
2576 * we'll just use the symlink anyway.
2578 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2580 cm_ReleaseSCache(scp);
2584 if (scp->fileType != CM_SCACHETYPE_FILE) {
2585 cm_ReleaseSCache(scp);
2586 cm_ReleaseUser(userp);
2587 smb_FreeTran2Packet(outp);
2588 return CM_ERROR_ISDIR;
2592 /* now all we have to do is open the file itself */
2593 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2594 osi_assertx(fidp, "null smb_fid_t");
2597 lock_ObtainMutex(&fidp->mx);
2598 /* save a pointer to the vnode */
2599 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2601 lock_ObtainWrite(&scp->rw);
2602 scp->flags |= CM_SCACHEFLAG_SMB_FID;
2603 lock_ReleaseWrite(&scp->rw);
2606 fidp->userp = userp;
2608 /* compute open mode */
2610 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
2611 if (openMode == 1 || openMode == 2)
2612 fidp->flags |= SMB_FID_OPENWRITE;
2614 /* remember that the file was newly created */
2616 fidp->flags |= SMB_FID_CREATED;
2618 lock_ReleaseMutex(&fidp->mx);
2620 smb_ReleaseFID(fidp);
2622 cm_Open(scp, 0, userp);
2624 /* copy out remainder of the parms */
2626 outp->parmsp[parmSlot++] = fidp->fid;
2627 lock_ObtainRead(&scp->rw);
2629 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2630 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2631 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2632 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2633 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2634 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2635 outp->parmsp[parmSlot++] = openMode;
2636 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2637 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2639 /* and the final "always present" stuff */
2640 outp->parmsp[parmSlot++] = openAction;
2641 /* next write out the "unique" ID */
2642 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2643 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2644 outp->parmsp[parmSlot++] = 0;
2645 if (returnEALength) {
2646 outp->parmsp[parmSlot++] = 0;
2647 outp->parmsp[parmSlot++] = 0;
2649 lock_ReleaseRead(&scp->rw);
2650 outp->totalData = 0; /* total # of data bytes */
2651 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2653 smb_SendTran2Packet(vcp, outp, op);
2655 smb_FreeTran2Packet(outp);
2657 cm_ReleaseUser(userp);
2658 /* leave scp held since we put it in fidp->scp */
2662 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2665 unsigned short infolevel;
2667 infolevel = p->parmsp[0];
2669 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2671 return CM_ERROR_BAD_LEVEL;
2674 /* TRANS2_QUERY_FS_INFORMATION */
2675 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2677 smb_tran2Packet_t *outp;
2678 smb_tran2QFSInfo_t qi;
2682 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2684 switch (p->parmsp[0]) {
2685 case SMB_INFO_ALLOCATION:
2687 responseSize = sizeof(qi.u.allocInfo);
2689 qi.u.allocInfo.FSID = 0;
2690 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2691 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2692 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2693 qi.u.allocInfo.bytesPerSector = 1024;
2696 case SMB_INFO_VOLUME:
2698 qi.u.volumeInfo.vsn = 1234; /* Volume serial number */
2699 qi.u.volumeInfo.vnCount = 3; /* Number of characters in label (AFS\0)*/
2701 /* we're supposed to pad it out with zeroes to the end */
2702 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2703 smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
2705 responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
2708 case SMB_QUERY_FS_VOLUME_INFO:
2709 /* FS volume info */
2710 responseSize = sizeof(qi.u.FSvolumeInfo);
2713 FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
2714 memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
2717 qi.u.FSvolumeInfo.vsn = 1234;
2718 qi.u.FSvolumeInfo.vnCount = 6; /* This is always in Unicode */
2719 memset(&qi.u.FSvolumeInfo.label, 0, sizeof(qi.u.FSvolumeInfo.label));
2720 memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
2723 case SMB_QUERY_FS_SIZE_INFO:
2725 responseSize = sizeof(qi.u.FSsizeInfo);
2727 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2728 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2729 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2730 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2731 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2732 qi.u.FSsizeInfo.bytesPerSector = 1024;
2735 case SMB_QUERY_FS_DEVICE_INFO:
2736 /* FS device info */
2737 responseSize = sizeof(qi.u.FSdeviceInfo);
2739 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2740 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2743 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2744 /* FS attribute info */
2746 /* attributes, defined in WINNT.H:
2747 * FILE_CASE_SENSITIVE_SEARCH 0x1
2748 * FILE_CASE_PRESERVED_NAMES 0x2
2749 * FILE_UNICODE_ON_DISK 0x4
2750 * FILE_VOLUME_QUOTAS 0x10
2751 * <no name defined> 0x4000
2752 * If bit 0x4000 is not set, Windows 95 thinks
2753 * we can't handle long (non-8.3) names,
2754 * despite our protestations to the contrary.
2756 qi.u.FSattributeInfo.attributes = 0x4003;
2757 /* The maxCompLength is supposed to be in bytes */
2759 qi.u.FSattributeInfo.attributes |= 0x04;
2761 qi.u.FSattributeInfo.maxCompLength = 255;
2762 smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
2763 qi.u.FSattributeInfo.FSnameLength = sz;
2766 sizeof(qi.u.FSattributeInfo.attributes) +
2767 sizeof(qi.u.FSattributeInfo.maxCompLength) +
2768 sizeof(qi.u.FSattributeInfo.FSnameLength) +
2773 case SMB_INFO_UNIX: /* CIFS Unix Info */
2774 case SMB_INFO_MACOS: /* Mac FS Info */
2776 return CM_ERROR_BADOP;
2779 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2781 /* copy out return data, and set corresponding sizes */
2782 outp->totalParms = 0;
2783 outp->totalData = responseSize;
2784 memcpy(outp->datap, &qi, responseSize);
2786 /* send and free the packets */
2787 smb_SendTran2Packet(vcp, outp, op);
2788 smb_FreeTran2Packet(outp);
2793 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2795 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2796 return CM_ERROR_BADOP;
2799 struct smb_ShortNameRock {
2800 clientchar_t *maskp;
2802 clientchar_t *shortName;
2803 size_t shortNameLen;
2806 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2809 struct smb_ShortNameRock *rockp;
2810 normchar_t normName[MAX_PATH];
2811 clientchar_t *shortNameEnd;
2815 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t)) == 0) {
2816 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
2817 osi_LogSaveString(smb_logp, dep->name));
2821 /* compare both names and vnodes, though probably just comparing vnodes
2822 * would be safe enough.
2824 if (cm_NormStrCmpI(normName, rockp->maskp) != 0)
2826 if (ntohl(dep->fid.vnode) != rockp->vnode)
2829 /* This is the entry */
2830 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2831 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2833 return CM_ERROR_STOPNOW;
2836 long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
2837 clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
2839 struct smb_ShortNameRock rock;
2840 clientchar_t *lastNamep;
2843 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2847 spacep = cm_GetSpace();
2848 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2850 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2851 caseFold, userp, tidPathp,
2853 cm_FreeSpace(spacep);
2858 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2859 cm_ReleaseSCache(dscp);
2860 cm_ReleaseUser(userp);
2864 return CM_ERROR_PATH_NOT_COVERED;
2866 #endif /* DFS_SUPPORT */
2868 if (!lastNamep) lastNamep = pathp;
2871 thyper.HighPart = 0;
2872 rock.shortName = shortName;
2874 rock.maskp = lastNamep;
2875 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2877 cm_ReleaseSCache(dscp);
2880 return CM_ERROR_NOSUCHFILE;
2881 if (code == CM_ERROR_STOPNOW) {
2882 *shortNameLenp = rock.shortNameLen;
2888 /* TRANS2_QUERY_PATH_INFORMATION */
2889 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2891 smb_tran2Packet_t *outp;
2894 unsigned short infoLevel;
2895 smb_tran2QPathInfo_t qpi;
2897 unsigned short attributes;
2898 unsigned long extAttributes;
2899 clientchar_t shortName[13];
2903 cm_scache_t *scp, *dscp;
2904 int scp_rw_held = 0;
2907 clientchar_t *pathp;
2908 clientchar_t *tidPathp;
2909 clientchar_t *lastComp;
2914 infoLevel = p->parmsp[0];
2915 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2917 else if (infoLevel == SMB_INFO_STANDARD)
2918 responseSize = sizeof(qpi.u.QPstandardInfo);
2919 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2920 responseSize = sizeof(qpi.u.QPeaSizeInfo);
2921 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2922 responseSize = sizeof(qpi.u.QPfileBasicInfo);
2923 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2924 responseSize = sizeof(qpi.u.QPfileStandardInfo);
2925 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2926 responseSize = sizeof(qpi.u.QPfileEaInfo);
2927 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2928 responseSize = sizeof(qpi.u.QPfileNameInfo);
2929 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
2930 responseSize = sizeof(qpi.u.QPfileAllInfo);
2931 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2932 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2934 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2935 p->opcode, infoLevel);
2936 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
2940 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
2941 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %S", infoLevel,
2942 osi_LogSaveClientString(smb_logp, pathp));
2944 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2946 if (infoLevel > 0x100)
2947 outp->totalParms = 2;
2949 outp->totalParms = 0;
2950 outp->totalData = responseSize;
2952 /* now, if we're at infoLevel 6, we're only being asked to check
2953 * the syntax, so we just OK things now. In particular, we're *not*
2954 * being asked to verify anything about the state of any parent dirs.
2956 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2957 smb_SendTran2Packet(vcp, outp, opx);
2958 smb_FreeTran2Packet(outp);
2962 userp = smb_GetTran2User(vcp, p);
2964 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2965 smb_FreeTran2Packet(outp);
2966 return CM_ERROR_BADSMB;
2969 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2971 cm_ReleaseUser(userp);
2972 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2973 smb_FreeTran2Packet(outp);
2978 * XXX Strange hack XXX
2980 * As of Patch 7 (13 January 98), we are having the following problem:
2981 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2982 * requests to look up "desktop.ini" in all the subdirectories.
2983 * This can cause zillions of timeouts looking up non-existent cells
2984 * and volumes, especially in the top-level directory.
2986 * We have not found any way to avoid this or work around it except
2987 * to explicitly ignore the requests for mount points that haven't
2988 * yet been evaluated and for directories that haven't yet been
2991 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2992 spacep = cm_GetSpace();
2993 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
2994 #ifndef SPECIAL_FOLDERS
2995 /* Make sure that lastComp is not NULL */
2997 if (cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
2998 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3002 userp, tidPathp, &req, &dscp);
3005 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3006 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3008 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3009 code = CM_ERROR_PATH_NOT_COVERED;
3011 code = CM_ERROR_BADSHARENAME;
3013 #endif /* DFS_SUPPORT */
3014 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3015 code = CM_ERROR_NOSUCHFILE;
3016 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3017 cm_buf_t *bp = buf_Find(dscp, &hzero);
3023 code = CM_ERROR_NOSUCHFILE;
3025 cm_ReleaseSCache(dscp);
3027 cm_FreeSpace(spacep);
3028 cm_ReleaseUser(userp);
3029 smb_SendTran2Error(vcp, p, opx, code);
3030 smb_FreeTran2Packet(outp);
3036 #endif /* SPECIAL_FOLDERS */
3038 cm_FreeSpace(spacep);
3041 /* now do namei and stat, and copy out the info */
3042 code = cm_NameI(cm_data.rootSCachep, pathp,
3043 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3046 cm_ReleaseUser(userp);
3047 smb_SendTran2Error(vcp, p, opx, code);
3048 smb_FreeTran2Packet(outp);
3053 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3054 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3055 cm_ReleaseSCache(scp);
3056 cm_ReleaseUser(userp);
3057 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3058 code = CM_ERROR_PATH_NOT_COVERED;
3060 code = CM_ERROR_BADSHARENAME;
3061 smb_SendTran2Error(vcp, p, opx, code);
3062 smb_FreeTran2Packet(outp);
3065 #endif /* DFS_SUPPORT */
3067 lock_ObtainWrite(&scp->rw);
3069 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3070 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3074 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3076 lock_ConvertWToR(&scp->rw);
3081 /* now we have the status in the cache entry, and everything is locked.
3082 * Marshall the output data.
3084 /* for info level 108, figure out short name */
3085 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3086 code = cm_GetShortName(pathp, userp, &req,
3087 tidPathp, scp->fid.vnode, shortName,
3093 smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
3094 qpi.u.QPfileAltNameInfo.fileNameLength = len;
3098 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3099 smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3100 qpi.u.QPfileNameInfo.fileNameLength = len;
3104 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3105 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3106 qpi.u.QPstandardInfo.creationDateTime = dosTime;
3107 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3108 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3109 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3110 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3111 attributes = smb_Attributes(scp);
3112 qpi.u.QPstandardInfo.attributes = attributes;
3113 qpi.u.QPstandardInfo.eaSize = 0;
3115 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3116 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3117 qpi.u.QPfileBasicInfo.creationTime = ft;
3118 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3119 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3120 qpi.u.QPfileBasicInfo.changeTime = ft;
3121 extAttributes = smb_ExtAttributes(scp);
3122 qpi.u.QPfileBasicInfo.attributes = extAttributes;
3123 qpi.u.QPfileBasicInfo.reserved = 0;
3125 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3128 lock_ReleaseRead(&scp->rw);
3130 fidp = smb_FindFIDByScache(vcp, scp);
3132 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3133 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3134 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3135 qpi.u.QPfileStandardInfo.directory =
3136 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3137 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3138 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3139 qpi.u.QPfileStandardInfo.reserved = 0;
3142 lock_ObtainMutex(&fidp->mx);
3143 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3144 lock_ReleaseMutex(&fidp->mx);
3145 smb_ReleaseFID(fidp);
3147 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3149 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3150 qpi.u.QPfileEaInfo.eaSize = 0;
3152 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3153 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3154 qpi.u.QPfileAllInfo.creationTime = ft;
3155 qpi.u.QPfileAllInfo.lastAccessTime = ft;
3156 qpi.u.QPfileAllInfo.lastWriteTime = ft;
3157 qpi.u.QPfileAllInfo.changeTime = ft;
3158 extAttributes = smb_ExtAttributes(scp);
3159 qpi.u.QPfileAllInfo.attributes = extAttributes;
3160 qpi.u.QPfileAllInfo.allocationSize = scp->length;
3161 qpi.u.QPfileAllInfo.endOfFile = scp->length;
3162 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3163 qpi.u.QPfileAllInfo.deletePending = 0;
3164 qpi.u.QPfileAllInfo.directory =
3165 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3166 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3167 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3168 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
3169 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
3170 qpi.u.QPfileAllInfo.eaSize = 0;
3171 qpi.u.QPfileAllInfo.accessFlags = 0;
3172 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
3173 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
3174 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3175 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3176 qpi.u.QPfileAllInfo.mode = 0;
3177 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3179 smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3180 qpi.u.QPfileAllInfo.fileNameLength = len;
3183 /* send and free the packets */
3185 switch (scp_rw_held) {
3187 lock_ReleaseRead(&scp->rw);
3190 lock_ReleaseWrite(&scp->rw);
3194 cm_ReleaseSCache(scp);
3195 cm_ReleaseUser(userp);
3197 memcpy(outp->datap, &qpi, responseSize);
3198 smb_SendTran2Packet(vcp, outp, opx);
3200 smb_SendTran2Error(vcp, p, opx, code);
3202 smb_FreeTran2Packet(outp);
3207 /* TRANS2_SET_PATH_INFORMATION */
3208 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3211 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
3212 return CM_ERROR_BADOP;
3216 unsigned short infoLevel;
3217 clientchar_t * pathp;
3218 smb_tran2Packet_t *outp;
3219 smb_tran2QPathInfo_t *spi;
3221 cm_scache_t *scp, *dscp;
3224 clientchar_t *tidPathp;
3225 clientchar_t *lastComp;
3229 infoLevel = p->parmsp[0];
3230 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
3231 if (infoLevel != SMB_INFO_STANDARD &&
3232 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
3233 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
3234 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3235 p->opcode, infoLevel);
3236 smb_SendTran2Error(vcp, p, opx,
3237 infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3241 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3243 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
3244 osi_LogSaveClientString(smb_logp, pathp));
3246 userp = smb_GetTran2User(vcp, p);
3248 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3249 code = CM_ERROR_BADSMB;
3253 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3254 if (code == CM_ERROR_TIDIPC) {
3255 /* Attempt to use a TID allocated for IPC. The client
3256 * is probably looking for DCE RPC end points which we
3257 * don't support OR it could be looking to make a DFS
3260 osi_Log0(smb_logp, "Tran2Open received IPC TID");
3261 cm_ReleaseUser(userp);
3262 return CM_ERROR_NOSUCHPATH;
3266 * XXX Strange hack XXX
3268 * As of Patch 7 (13 January 98), we are having the following problem:
3269 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3270 * requests to look up "desktop.ini" in all the subdirectories.
3271 * This can cause zillions of timeouts looking up non-existent cells
3272 * and volumes, especially in the top-level directory.
3274 * We have not found any way to avoid this or work around it except
3275 * to explicitly ignore the requests for mount points that haven't
3276 * yet been evaluated and for directories that haven't yet been
3279 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3280 spacep = cm_GetSpace();
3281 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3282 #ifndef SPECIAL_FOLDERS
3283 /* Make sure that lastComp is not NULL */
3285 if (cm_ClientStrCmpI(lastComp, _C("\\desktop.ini")) == 0) {
3286 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3290 userp, tidPathp, &req, &dscp);
3293 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3294 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3296 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3297 code = CM_ERROR_PATH_NOT_COVERED;
3299 code = CM_ERROR_BADSHARENAME;
3301 #endif /* DFS_SUPPORT */
3302 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3303 code = CM_ERROR_NOSUCHFILE;
3304 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3305 cm_buf_t *bp = buf_Find(dscp, &hzero);
3311 code = CM_ERROR_NOSUCHFILE;
3313 cm_ReleaseSCache(dscp);
3315 cm_FreeSpace(spacep);
3316 cm_ReleaseUser(userp);
3317 smb_SendTran2Error(vcp, p, opx, code);
3323 #endif /* SPECIAL_FOLDERS */
3325 cm_FreeSpace(spacep);
3328 /* now do namei and stat, and copy out the info */
3329 code = cm_NameI(cm_data.rootSCachep, pathp,
3330 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3332 cm_ReleaseUser(userp);
3333 smb_SendTran2Error(vcp, p, opx, code);
3337 fidp = smb_FindFIDByScache(vcp, scp);
3339 cm_ReleaseSCache(scp);
3340 cm_ReleaseUser(userp);
3341 smb_SendTran2Error(vcp, p, opx, code);
3345 lock_ObtainMutex(&fidp->mx);
3346 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
3347 lock_ReleaseMutex(&fidp->mx);
3348 cm_ReleaseSCache(scp);
3349 smb_ReleaseFID(fidp);
3350 cm_ReleaseUser(userp);
3351 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3354 lock_ReleaseMutex(&fidp->mx);
3356 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3358 outp->totalParms = 2;
3359 outp->totalData = 0;
3361 spi = (smb_tran2QPathInfo_t *)p->datap;
3362 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3365 /* lock the vnode with a callback; we need the current status
3366 * to determine what the new status is, in some cases.
3368 lock_ObtainWrite(&scp->rw);
3369 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3370 CM_SCACHESYNC_GETSTATUS
3371 | CM_SCACHESYNC_NEEDCALLBACK);
3373 lock_ReleaseWrite(&scp->rw);
3376 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3378 lock_ReleaseWrite(&scp->rw);
3379 lock_ObtainMutex(&fidp->mx);
3380 lock_ObtainRead(&scp->rw);
3382 /* prepare for setattr call */
3383 attr.mask = CM_ATTRMASK_LENGTH;
3384 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3385 attr.length.HighPart = 0;
3387 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3388 smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3389 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3390 fidp->flags |= SMB_FID_MTIMESETDONE;
3393 if (spi->u.QPstandardInfo.attributes != 0) {
3394 if ((scp->unixModeBits & 0222)
3395 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3396 /* make a writable file read-only */
3397 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3398 attr.unixModeBits = scp->unixModeBits & ~0222;
3400 else if ((scp->unixModeBits & 0222) == 0
3401 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3402 /* make a read-only file writable */
3403 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3404 attr.unixModeBits = scp->unixModeBits | 0222;
3407 lock_ReleaseRead(&scp->rw);
3408 lock_ReleaseMutex(&fidp->mx);
3412 code = cm_SetAttr(scp, &attr, userp, &req);
3416 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3417 /* we don't support EAs */
3418 code = CM_ERROR_EAS_NOT_SUPPORTED;
3422 cm_ReleaseSCache(scp);
3423 cm_ReleaseUser(userp);
3424 smb_ReleaseFID(fidp);
3426 smb_SendTran2Packet(vcp, outp, opx);
3428 smb_SendTran2Error(vcp, p, opx, code);
3429 smb_FreeTran2Packet(outp);
3435 /* TRANS2_QUERY_FILE_INFORMATION */
3436 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3438 smb_tran2Packet_t *outp;
3440 unsigned long attributes;
3441 unsigned short infoLevel;
3448 smb_tran2QFileInfo_t qfi;
3456 fidp = smb_FindFID(vcp, fid, 0);
3459 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3463 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3464 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3465 smb_CloseFID(vcp, fidp, NULL, 0);
3466 smb_ReleaseFID(fidp);
3470 infoLevel = p->parmsp[1];
3471 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3472 responseSize = sizeof(qfi.u.QFbasicInfo);
3473 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3474 responseSize = sizeof(qfi.u.QFstandardInfo);
3475 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3476 responseSize = sizeof(qfi.u.QFeaInfo);
3477 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3478 responseSize = sizeof(qfi.u.QFfileNameInfo);
3480 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3481 p->opcode, infoLevel);
3482 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3483 smb_ReleaseFID(fidp);
3486 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3488 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3490 if (infoLevel > 0x100)
3491 outp->totalParms = 2;
3493 outp->totalParms = 0;
3494 outp->totalData = responseSize;
3496 userp = smb_GetTran2User(vcp, p);
3498 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3499 code = CM_ERROR_BADSMB;
3503 lock_ObtainMutex(&fidp->mx);
3504 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3506 osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3508 lock_ReleaseMutex(&fidp->mx);
3509 lock_ObtainWrite(&scp->rw);
3510 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3511 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3515 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3517 lock_ConvertWToR(&scp->rw);
3520 /* now we have the status in the cache entry, and everything is locked.
3521 * Marshall the output data.
3523 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3524 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3525 qfi.u.QFbasicInfo.creationTime = ft;
3526 qfi.u.QFbasicInfo.lastAccessTime = ft;
3527 qfi.u.QFbasicInfo.lastWriteTime = ft;
3528 qfi.u.QFbasicInfo.lastChangeTime = ft;
3529 attributes = smb_ExtAttributes(scp);
3530 qfi.u.QFbasicInfo.attributes = attributes;
3532 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3533 qfi.u.QFstandardInfo.allocationSize = scp->length;
3534 qfi.u.QFstandardInfo.endOfFile = scp->length;
3535 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3536 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3537 qfi.u.QFstandardInfo.directory =
3538 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3539 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3540 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3542 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3543 qfi.u.QFeaInfo.eaSize = 0;
3545 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3549 lock_ReleaseRead(&scp->rw);
3550 lock_ObtainMutex(&fidp->mx);
3551 lock_ObtainRead(&scp->rw);
3552 if (fidp->NTopen_wholepathp)
3553 name = fidp->NTopen_wholepathp;
3555 name = _C("\\"); /* probably can't happen */
3556 lock_ReleaseMutex(&fidp->mx);
3558 smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, SMB_STRF_IGNORENUL);
3559 outp->totalData = len + 4; /* this is actually what we want to return */
3560 qfi.u.QFfileNameInfo.fileNameLength = len;
3563 /* send and free the packets */
3566 lock_ReleaseRead(&scp->rw);
3568 lock_ReleaseWrite(&scp->rw);
3569 cm_ReleaseSCache(scp);
3570 cm_ReleaseUser(userp);
3571 smb_ReleaseFID(fidp);
3573 memcpy(outp->datap, &qfi, responseSize);
3574 smb_SendTran2Packet(vcp, outp, opx);
3576 smb_SendTran2Error(vcp, p, opx, code);
3578 smb_FreeTran2Packet(outp);
3584 /* TRANS2_SET_FILE_INFORMATION */
3585 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3590 unsigned short infoLevel;
3591 smb_tran2Packet_t *outp;
3592 cm_user_t *userp = NULL;
3593 cm_scache_t *scp = NULL;
3599 fidp = smb_FindFID(vcp, fid, 0);
3602 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3606 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3607 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3608 smb_CloseFID(vcp, fidp, NULL, 0);
3609 smb_ReleaseFID(fidp);