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;
689 int maxBufferSize = 0;
693 /* Check for bad conns */
694 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
695 return CM_ERROR_REMOTECONN;
698 maxBufferSize = smb_GetSMBParm(inp, 2);
699 maxMpxCount = smb_GetSMBParm(inp, 3);
700 vcNumber = smb_GetSMBParm(inp, 4);
702 osi_Log3(smb_logp, "SESSION_SETUP_ANDX with MaxBufferSize=%d, MaxMpxCount=%d, VCNumber=%d",
703 maxBufferSize, maxMpxCount, vcNumber);
705 if (maxMpxCount > smb_maxMpxRequests) {
706 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_MPX_COUNT, maxMpxCount, smb_maxMpxRequests);
707 osi_Log2(smb_logp, "MaxMpxCount for client is too large (Client=%d, Server=%d)",
708 maxMpxCount, smb_maxMpxRequests);
711 if (maxBufferSize < SMB_PACKETSIZE) {
712 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_BUFFER_SIZE, maxBufferSize, SMB_PACKETSIZE);
713 osi_Log2(smb_logp, "MaxBufferSize for client is too small (Client=%d, Server=%d)",
714 maxBufferSize, SMB_PACKETSIZE);
718 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_RESET_ALL_VCS);
719 osi_Log0(smb_logp, "Resetting all VCs");
720 smb_MarkAllVCsDead(vcp);
723 if (vcp->flags & SMB_VCFLAG_USENT) {
724 if (smb_authType == SMB_AUTH_EXTENDED) {
725 /* extended authentication */
729 OutputDebugF(_C("NT Session Setup: Extended"));
731 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
732 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
735 secBlobInLength = smb_GetSMBParm(inp, 7);
736 secBlobIn = smb_GetSMBData(inp, NULL);
738 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
740 if (code == CM_ERROR_GSSCONTINUE) {
743 smb_SetSMBParm(outp, 2, 0);
744 smb_SetSMBParm(outp, 3, secBlobOutLength);
746 tp = smb_GetSMBData(outp, NULL);
747 if (secBlobOutLength) {
748 memcpy(tp, secBlobOut, secBlobOutLength);
750 tp += secBlobOutLength;
751 cb_data += secBlobOutLength;
753 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
754 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
755 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
757 smb_SetSMBDataLength(outp, cb_data);
760 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
762 unsigned ciPwdLength, csPwdLength;
764 clientchar_t *accountName;
765 clientchar_t *primaryDomain;
768 if (smb_authType == SMB_AUTH_NTLM)
769 OutputDebugF(_C("NT Session Setup: NTLM"));
771 OutputDebugF(_C("NT Session Setup: None"));
773 /* TODO: parse for extended auth as well */
774 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
775 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
777 tp = smb_GetSMBData(inp, &datalen);
779 OutputDebugF(_C("Session packet data size [%d]"),datalen);
786 accountName = smb_ParseString(inp, tp, &tp, 0);
787 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
789 OutputDebugF(_C("Account Name: %s"),accountName);
790 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
791 OutputDebugF(_C("Case Sensitive Password: %s"),
792 csPwd && csPwd[0] ? _C("yes") : _C("no"));
793 OutputDebugF(_C("Case Insensitive Password: %s"),
794 ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
796 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
797 /* shouldn't happen */
798 code = CM_ERROR_BADSMB;
799 goto after_read_packet;
802 /* capabilities are only valid for first session packet */
803 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
804 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
807 if (smb_authType == SMB_AUTH_NTLM) {
808 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
810 OutputDebugF(_C("LM authentication failed [%d]"), code);
812 OutputDebugF(_C("LM authentication succeeded"));
816 unsigned ciPwdLength;
818 clientchar_t *accountName;
819 clientchar_t *primaryDomain;
821 switch ( smb_authType ) {
822 case SMB_AUTH_EXTENDED:
823 OutputDebugF(_C("V3 Session Setup: Extended"));
826 OutputDebugF(_C("V3 Session Setup: NTLM"));
829 OutputDebugF(_C("V3 Session Setup: None"));
831 ciPwdLength = smb_GetSMBParm(inp, 7);
832 tp = smb_GetSMBData(inp, NULL);
836 accountName = smb_ParseString(inp, tp, &tp, 0);
837 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
839 OutputDebugF(_C("Account Name: %s"),accountName);
840 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
841 OutputDebugF(_C("Case Insensitive Password: %s"), ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
843 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
844 /* shouldn't happen */
845 code = CM_ERROR_BADSMB;
846 goto after_read_packet;
849 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
852 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
853 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
855 OutputDebugF(_C("LM authentication failed [%d]"), code);
857 OutputDebugF(_C("LM authentication succeeded"));
862 /* note down that we received a session setup X and set the capabilities flag */
863 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
864 lock_ObtainMutex(&vcp->mx);
865 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
866 /* for the moment we can only deal with NTSTATUS */
867 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
868 vcp->flags |= SMB_VCFLAG_STATUS32;
872 if ((caps & NTNEGOTIATE_CAPABILITY_UNICODE) && smb_UseUnicode) {
873 vcp->flags |= SMB_VCFLAG_USEUNICODE;
876 lock_ReleaseMutex(&vcp->mx);
879 /* code would be non-zero if there was an authentication failure.
880 Ideally we would like to invalidate the uid for this session or break
881 early to avoid accidently stealing someone else's tokens. */
887 OutputDebugF(_C("Received username=[%s]"), usern);
889 /* On Windows 2000, this function appears to be called more often than
890 it is expected to be called. This resulted in multiple smb_user_t
891 records existing all for the same user session which results in all
892 of the users tokens disappearing.
894 To avoid this problem, we look for an existing smb_user_t record
895 based on the users name, and use that one if we find it.
898 uidp = smb_FindUserByNameThisSession(vcp, usern);
899 if (uidp) { /* already there, so don't create a new one */
901 newUid = uidp->userID;
902 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
903 vcp->lana,vcp->lsn,newUid);
904 smb_ReleaseUID(uidp);
909 /* do a global search for the username/machine name pair */
910 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
911 lock_ObtainMutex(&unp->mx);
912 if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
913 /* clear the afslogon flag so that the tickets can now
914 * be freed when the refCount returns to zero.
916 unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
918 lock_ReleaseMutex(&unp->mx);
920 /* Create a new UID and cm_user_t structure */
923 userp = cm_NewUser();
924 cm_HoldUserVCRef(userp);
925 lock_ObtainMutex(&vcp->mx);
926 if (!vcp->uidCounter)
927 vcp->uidCounter++; /* handle unlikely wraparounds */
928 newUid = (cm_ClientStrLen(usern)==0)?0:vcp->uidCounter++;
929 lock_ReleaseMutex(&vcp->mx);
931 /* Create a new smb_user_t structure and connect them up */
932 lock_ObtainMutex(&unp->mx);
934 lock_ReleaseMutex(&unp->mx);
936 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
938 lock_ObtainMutex(&uidp->mx);
940 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
941 lock_ReleaseMutex(&uidp->mx);
942 smb_ReleaseUID(uidp);
946 /* Return UID to the client */
947 ((smb_t *)outp)->uid = newUid;
948 /* Also to the next chained message */
949 ((smb_t *)inp)->uid = newUid;
951 osi_Log3(smb_logp, "SMB3 session setup name %S creating ID %d%S",
952 osi_LogSaveClientString(smb_logp, usern), newUid,
953 osi_LogSaveClientString(smb_logp, s1));
955 smb_SetSMBParm(outp, 2, 0);
957 if (vcp->flags & SMB_VCFLAG_USENT) {
958 if (smb_authType == SMB_AUTH_EXTENDED) {
961 smb_SetSMBParm(outp, 3, secBlobOutLength);
963 tp = smb_GetSMBData(outp, NULL);
964 if (secBlobOutLength) {
965 memcpy(tp, secBlobOut, secBlobOutLength);
967 tp += secBlobOutLength;
968 cb_data += secBlobOutLength;
971 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
972 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
973 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
975 smb_SetSMBDataLength(outp, cb_data);
977 smb_SetSMBDataLength(outp, 0);
980 if (smb_authType == SMB_AUTH_EXTENDED) {
983 tp = smb_GetSMBData(outp, NULL);
985 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
986 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
987 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
989 smb_SetSMBDataLength(outp, cb_data);
991 smb_SetSMBDataLength(outp, 0);
998 /* SMB_COM_LOGOFF_ANDX */
999 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1003 /* find the tree and free it */
1004 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1006 smb_username_t * unp;
1008 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %S", uidp->userID,
1009 osi_LogSaveClientString(smb_logp, (uidp->unp) ? uidp->unp->name: _C(" ")));
1011 lock_ObtainMutex(&uidp->mx);
1012 uidp->flags |= SMB_USERFLAG_DELETE;
1014 * it doesn't get deleted right away
1015 * because the vcp points to it
1018 lock_ReleaseMutex(&uidp->mx);
1021 /* we can't do this. we get logoff messages prior to a session
1022 * disconnect even though it doesn't mean the user is logging out.
1023 * we need to create a new pioctl and EventLogoff handler to set
1024 * SMB_USERNAMEFLAG_LOGOFF.
1026 if (unp && smb_LogoffTokenTransfer) {
1027 lock_ObtainMutex(&unp->mx);
1028 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
1029 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
1030 lock_ReleaseMutex(&unp->mx);
1034 smb_ReleaseUID(uidp);
1037 osi_Log0(smb_logp, "SMB3 user logoffX");
1039 smb_SetSMBDataLength(outp, 0);
1043 #define SMB_SUPPORT_SEARCH_BITS 0x0001
1044 #define SMB_SHARE_IS_IN_DFS 0x0002
1046 /* SMB_COM_TREE_CONNECT_ANDX */
1047 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1050 smb_user_t *uidp = NULL;
1051 unsigned short newTid;
1052 clientchar_t shareName[AFSPATHMAX];
1053 clientchar_t *sharePath;
1056 clientchar_t *slashp;
1057 clientchar_t *pathp;
1058 clientchar_t *passwordp;
1059 clientchar_t *servicep;
1060 cm_user_t *userp = NULL;
1063 osi_Log0(smb_logp, "SMB3 receive tree connect");
1065 /* parse input parameters */
1066 tp = smb_GetSMBData(inp, NULL);
1067 passwordp = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1068 pathp = smb_ParseString(inp, tp, &tp, SMB_STRF_ANSIPATH);
1069 servicep = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1071 slashp = cm_ClientStrRChr(pathp, '\\');
1073 return CM_ERROR_BADSMB;
1075 cm_ClientStrCpy(shareName, lengthof(shareName), slashp+1);
1077 osi_Log3(smb_logp, "Tree connect pathp[%S] shareName[%S] service[%S]",
1078 osi_LogSaveClientString(smb_logp, pathp),
1079 osi_LogSaveClientString(smb_logp, shareName),
1080 osi_LogSaveClientString(smb_logp, servicep));
1082 if (cm_ClientStrCmp(servicep, _C("IPC")) == 0 ||
1083 cm_ClientStrCmp(shareName, _C("IPC$")) == 0) {
1085 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1088 return CM_ERROR_NOIPC;
1092 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1094 userp = smb_GetUserFromUID(uidp);
1096 lock_ObtainMutex(&vcp->mx);
1097 newTid = vcp->tidCounter++;
1098 lock_ReleaseMutex(&vcp->mx);
1100 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1103 if (!cm_ClientStrCmp(shareName, _C("*.")))
1104 cm_ClientStrCpy(shareName, lengthof(shareName), _C("all"));
1105 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1108 smb_ReleaseUID(uidp);
1109 smb_ReleaseTID(tidp, FALSE);
1110 return CM_ERROR_BADSHARENAME;
1113 if (vcp->flags & SMB_VCFLAG_USENT)
1115 int policy = smb_FindShareCSCPolicy(shareName);
1118 DWORD dwAdvertiseDFS = 0, dwSize = sizeof(DWORD);
1120 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1121 0, KEY_QUERY_VALUE, &parmKey);
1122 if (code == ERROR_SUCCESS) {
1123 code = RegQueryValueEx(parmKey, "AdvertiseDFS", NULL, NULL,
1124 (BYTE *)&dwAdvertiseDFS, &dwSize);
1125 if (code != ERROR_SUCCESS)
1127 RegCloseKey (parmKey);
1129 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1130 (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
1134 smb_SetSMBParm(outp, 2, 0);
1138 smb_ReleaseUID(uidp);
1140 lock_ObtainMutex(&tidp->mx);
1141 tidp->userp = userp;
1142 tidp->pathname = sharePath;
1144 tidp->flags |= SMB_TIDFLAG_IPC;
1145 lock_ReleaseMutex(&tidp->mx);
1146 smb_ReleaseTID(tidp, FALSE);
1148 ((smb_t *)outp)->tid = newTid;
1149 ((smb_t *)inp)->tid = newTid;
1150 tp = smb_GetSMBData(outp, NULL);
1154 tp = smb_UnparseString(outp, tp, _C("A:"), &cb_data, SMB_STRF_FORCEASCII);
1155 tp = smb_UnparseString(outp, tp, _C("AFS"), &cb_data, 0);
1156 smb_SetSMBDataLength(outp, cb_data);
1160 tp = smb_UnparseString(outp, tp, _C("IPC"), &cb_data, SMB_STRF_FORCEASCII);
1161 smb_SetSMBDataLength(outp, cb_data);
1164 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1168 /* must be called with global tran lock held */
1169 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1171 smb_tran2Packet_t *tp;
1174 smbp = (smb_t *) inp->data;
1175 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1176 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1182 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1183 int totalParms, int totalData)
1185 smb_tran2Packet_t *tp;
1188 smbp = (smb_t *) inp->data;
1189 tp = malloc(sizeof(*tp));
1190 memset(tp, 0, sizeof(*tp));
1193 tp->curData = tp->curParms = 0;
1194 tp->totalData = totalData;
1195 tp->totalParms = totalParms;
1196 tp->tid = smbp->tid;
1197 tp->mid = smbp->mid;
1198 tp->uid = smbp->uid;
1199 tp->pid = smbp->pid;
1200 tp->res[0] = smbp->res[0];
1201 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1202 if (totalParms != 0)
1203 tp->parmsp = malloc(totalParms);
1205 tp->datap = malloc(totalData);
1206 if (smbp->com == 0x25 || smbp->com == 0x26)
1209 tp->opcode = smb_GetSMBParm(inp, 14);
1212 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1214 if (WANTS_UNICODE(inp) && (vcp->flags & SMB_VCFLAG_USEUNICODE))
1215 tp->flags |= SMB_TRAN2PFLAG_USEUNICODE;
1220 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1221 smb_tran2Packet_t *inp, smb_packet_t *outp,
1222 int totalParms, int totalData)
1224 smb_tran2Packet_t *tp;
1225 unsigned short parmOffset;
1226 unsigned short dataOffset;
1227 unsigned short dataAlign;
1229 tp = malloc(sizeof(*tp));
1230 memset(tp, 0, sizeof(*tp));
1233 tp->curData = tp->curParms = 0;
1234 tp->totalData = totalData;
1235 tp->totalParms = totalParms;
1236 tp->oldTotalParms = totalParms;
1241 tp->res[0] = inp->res[0];
1242 tp->opcode = inp->opcode;
1246 * We calculate where the parameters and data will start.
1247 * This calculation must parallel the calculation in
1248 * smb_SendTran2Packet.
1251 parmOffset = 10*2 + 35;
1252 parmOffset++; /* round to even */
1253 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1255 dataOffset = parmOffset + totalParms;
1256 dataAlign = dataOffset & 2; /* quad-align */
1257 dataOffset += dataAlign;
1258 tp->datap = outp->data + dataOffset;
1263 /* free a tran2 packet */
1264 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1267 smb_ReleaseVC(t2p->vcp);
1270 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1276 while (t2p->stringsp) {
1280 t2p->stringsp = ns->nextp;
1286 clientchar_t *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
1287 char ** chainpp, int flags)
1292 if (!(p->flags & SMB_TRAN2PFLAG_USEUNICODE))
1293 flags |= SMB_STRF_FORCEASCII;
1296 cb = p->totalParms - (inp - (char *)p->parmsp);
1297 if (inp < (char *) p->parmsp ||
1298 inp >= ((char *) p->parmsp) + p->totalParms) {
1299 #ifdef DEBUG_UNICODE
1305 return smb_ParseStringBuf((unsigned char *) p->parmsp, &p->stringsp,
1306 inp, &cb, chainpp, flags);
1309 /* called with a VC, an input packet to respond to, and an error code.
1310 * sends an error response.
1312 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1313 smb_packet_t *tp, long code)
1316 unsigned short errCode;
1317 unsigned char errClass;
1318 unsigned long NTStatus;
1320 if (vcp->flags & SMB_VCFLAG_STATUS32)
1321 smb_MapNTError(code, &NTStatus);
1323 smb_MapCoreError(code, vcp, &errCode, &errClass);
1325 smb_FormatResponsePacket(vcp, NULL, tp);
1326 smbp = (smb_t *) tp;
1328 /* We can handle long names */
1329 if (vcp->flags & SMB_VCFLAG_USENT)
1330 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1332 /* now copy important fields from the tran 2 packet */
1333 smbp->com = t2p->com;
1334 smbp->tid = t2p->tid;
1335 smbp->mid = t2p->mid;
1336 smbp->pid = t2p->pid;
1337 smbp->uid = t2p->uid;
1338 smbp->res[0] = t2p->res[0];
1339 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1340 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1341 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1342 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1343 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1344 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1347 smbp->rcls = errClass;
1348 smbp->errLow = (unsigned char) (errCode & 0xff);
1349 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1353 smb_SendPacket(vcp, tp);
1356 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1359 unsigned short parmOffset;
1360 unsigned short dataOffset;
1361 unsigned short totalLength;
1362 unsigned short dataAlign;
1365 smb_FormatResponsePacket(vcp, NULL, tp);
1366 smbp = (smb_t *) tp;
1368 /* We can handle long names */
1369 if (vcp->flags & SMB_VCFLAG_USENT)
1370 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1372 /* now copy important fields from the tran 2 packet */
1373 smbp->com = t2p->com;
1374 smbp->tid = t2p->tid;
1375 smbp->mid = t2p->mid;
1376 smbp->pid = t2p->pid;
1377 smbp->uid = t2p->uid;
1378 smbp->res[0] = t2p->res[0];
1380 totalLength = 1 + t2p->totalData + t2p->totalParms;
1382 /* now add the core parameters (tran2 info) to the packet */
1383 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1384 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1385 smb_SetSMBParm(tp, 2, 0); /* reserved */
1386 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1387 parmOffset = 10*2 + 35; /* parm offset in packet */
1388 parmOffset++; /* round to even */
1389 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1390 * hdr, bcc and wct */
1391 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1392 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1393 dataOffset = parmOffset + t2p->oldTotalParms;
1394 dataAlign = dataOffset & 2; /* quad-align */
1395 dataOffset += dataAlign;
1396 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1397 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1398 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1401 datap = smb_GetSMBData(tp, NULL);
1402 *datap++ = 0; /* we rounded to even */
1404 totalLength += dataAlign;
1405 smb_SetSMBDataLength(tp, totalLength);
1407 /* next, send the datagram */
1408 smb_SendPacket(vcp, tp);
1412 /* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
1413 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1415 smb_tran2Packet_t *asp;
1428 /* We sometimes see 0 word count. What to do? */
1429 if (*inp->wctp == 0) {
1430 osi_Log0(smb_logp, "Transaction2 word count = 0");
1431 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1433 smb_SetSMBDataLength(outp, 0);
1434 smb_SendPacket(vcp, outp);
1438 totalParms = smb_GetSMBParm(inp, 0);
1439 totalData = smb_GetSMBParm(inp, 1);
1441 firstPacket = (inp->inCom == 0x25);
1443 /* find the packet we're reassembling */
1444 lock_ObtainWrite(&smb_globalLock);
1445 asp = smb_FindTran2Packet(vcp, inp);
1447 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1449 lock_ReleaseWrite(&smb_globalLock);
1451 /* now merge in this latest packet; start by looking up offsets */
1453 parmDisp = dataDisp = 0;
1454 parmOffset = smb_GetSMBParm(inp, 10);
1455 dataOffset = smb_GetSMBParm(inp, 12);
1456 parmCount = smb_GetSMBParm(inp, 9);
1457 dataCount = smb_GetSMBParm(inp, 11);
1458 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1459 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1461 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1462 totalData, dataCount, asp->maxReturnData);
1465 parmDisp = smb_GetSMBParm(inp, 4);
1466 parmOffset = smb_GetSMBParm(inp, 3);
1467 dataDisp = smb_GetSMBParm(inp, 7);
1468 dataOffset = smb_GetSMBParm(inp, 6);
1469 parmCount = smb_GetSMBParm(inp, 2);
1470 dataCount = smb_GetSMBParm(inp, 5);
1472 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1473 parmCount, dataCount);
1476 /* now copy the parms and data */
1477 if ( asp->totalParms > 0 && parmCount != 0 )
1479 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1481 if ( asp->totalData > 0 && dataCount != 0 ) {
1482 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1485 /* account for new bytes */
1486 asp->curData += dataCount;
1487 asp->curParms += parmCount;
1489 /* finally, if we're done, remove the packet from the queue and dispatch it */
1490 if (asp->totalParms > 0 &&
1491 asp->curParms > 0 &&
1492 asp->totalData <= asp->curData &&
1493 asp->totalParms <= asp->curParms) {
1494 /* we've received it all */
1495 lock_ObtainWrite(&smb_globalLock);
1496 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1497 lock_ReleaseWrite(&smb_globalLock);
1499 /* now dispatch it */
1500 rapOp = asp->parmsp[0];
1502 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1503 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1504 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1505 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
1508 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1509 code = CM_ERROR_BADOP;
1512 /* if an error is returned, we're supposed to send an error packet,
1513 * otherwise the dispatched function already did the data sending.
1514 * We give dispatched proc the responsibility since it knows how much
1515 * space to allocate.
1518 smb_SendTran2Error(vcp, asp, outp, code);
1521 /* free the input tran 2 packet */
1522 smb_FreeTran2Packet(asp);
1524 else if (firstPacket) {
1525 /* the first packet in a multi-packet request, we need to send an
1526 * ack to get more data.
1528 smb_SetSMBDataLength(outp, 0);
1529 smb_SendPacket(vcp, outp);
1535 /* ANSI versions. */
1537 #pragma pack(push, 1)
1539 typedef struct smb_rap_share_info_0 {
1540 BYTE shi0_netname[13];
1541 } smb_rap_share_info_0_t;
1543 typedef struct smb_rap_share_info_1 {
1544 BYTE shi1_netname[13];
1547 DWORD shi1_remark; /* char *shi1_remark; data offset */
1548 } smb_rap_share_info_1_t;
1550 typedef struct smb_rap_share_info_2 {
1551 BYTE shi2_netname[13];
1554 DWORD shi2_remark; /* char *shi2_remark; data offset */
1555 WORD shi2_permissions;
1557 WORD shi2_current_uses;
1558 DWORD shi2_path; /* char *shi2_path; data offset */
1559 WORD shi2_passwd[9];
1561 } smb_rap_share_info_2_t;
1563 #define SMB_RAP_MAX_SHARES 512
1565 typedef struct smb_rap_share_list {
1568 smb_rap_share_info_0_t * shares;
1569 } smb_rap_share_list_t;
1573 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1574 smb_rap_share_list_t * sp;
1576 if (dep->name[0] == '.' && (!dep->name[1] || (dep->name[1] == '.' && !dep->name[2])))
1577 return 0; /* skip over '.' and '..' */
1579 sp = (smb_rap_share_list_t *) vrockp;
1581 strncpy(sp->shares[sp->cShare].shi0_netname, dep->name, 12);
1582 sp->shares[sp->cShare].shi0_netname[12] = 0;
1586 if (sp->cShare >= sp->maxShares)
1587 return CM_ERROR_STOPNOW;
1592 /* RAP NetShareEnumRequest */
1593 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1595 smb_tran2Packet_t *outp;
1596 unsigned short * tp;
1600 int outParmsTotal; /* total parameter bytes */
1601 int outDataTotal; /* total data bytes */
1604 DWORD allSubmount = 0;
1606 DWORD nRegShares = 0;
1607 DWORD nSharesRet = 0;
1609 HKEY hkSubmount = NULL;
1610 smb_rap_share_info_1_t * shares;
1613 clientchar_t thisShare[AFSPATHMAX];
1617 smb_rap_share_list_t rootShares;
1622 tp = p->parmsp + 1; /* skip over function number (always 0) */
1625 clientchar_t * cdescp;
1627 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1628 if (cm_ClientStrCmp(cdescp, _C("WrLeh")))
1629 return CM_ERROR_INVAL;
1630 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1631 if (cm_ClientStrCmp(cdescp, _C("B13BWz")))
1632 return CM_ERROR_INVAL;
1638 if (infoLevel != 1) {
1639 return CM_ERROR_INVAL;
1642 /* We are supposed to use the same ASCII data structure even if
1643 Unicode is negotiated, which ultimately means that the share
1644 names that we return must be at most 13 characters in length,
1645 including the NULL terminator.
1647 The RAP specification states that shares with names longer than
1648 12 characters should not be included in the enumeration.
1649 However, since we support prefix cell references and since many
1650 cell names are going to exceed 12 characters, we lie and send
1651 the first 12 characters.
1654 /* first figure out how many shares there are */
1655 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1656 KEY_QUERY_VALUE, &hkParam);
1657 if (rv == ERROR_SUCCESS) {
1658 len = sizeof(allSubmount);
1659 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1660 (BYTE *) &allSubmount, &len);
1661 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1664 RegCloseKey (hkParam);
1667 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1668 0, KEY_QUERY_VALUE, &hkSubmount);
1669 if (rv == ERROR_SUCCESS) {
1670 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1671 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1672 if (rv != ERROR_SUCCESS)
1678 /* fetch the root shares */
1679 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1680 rootShares.cShare = 0;
1681 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1685 userp = smb_GetTran2User(vcp,p);
1687 thyper.HighPart = 0;
1690 cm_HoldSCache(cm_data.rootSCachep);
1691 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1692 cm_ReleaseSCache(cm_data.rootSCachep);
1694 cm_ReleaseUser(userp);
1696 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1698 #define REMARK_LEN 1
1699 outParmsTotal = 8; /* 4 dwords */
1700 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1701 if(outDataTotal > bufsize) {
1702 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1703 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1706 nSharesRet = nShares;
1709 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1711 /* now for the submounts */
1712 shares = (smb_rap_share_info_1_t *) outp->datap;
1713 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1715 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1718 StringCchCopyA(shares[cshare].shi1_netname,
1719 lengthof(shares[cshare].shi1_netname), "all" );
1720 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1721 /* type and pad are zero already */
1727 for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
1728 len = sizeof(thisShare);
1729 rv = RegEnumValueW(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
1730 if (rv == ERROR_SUCCESS &&
1731 cm_ClientStrLen(thisShare) &&
1732 (!allSubmount || cm_ClientStrCmpI(thisShare,_C("all")))) {
1733 cm_ClientStringToUtf8(thisShare, -1, shares[cshare].shi1_netname,
1734 lengthof( shares[cshare].shi1_netname ));
1735 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1736 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1741 nShares--; /* uncount key */
1744 RegCloseKey(hkSubmount);
1747 nonrootShares = cshare;
1749 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1750 /* in case there are collisions with submounts, submounts have
1752 for (j=0; j < nonrootShares; j++)
1753 if (!cm_stricmp_utf8(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1756 if (j < nonrootShares) {
1757 nShares--; /* uncount */
1761 StringCchCopyA(shares[cshare].shi1_netname, lengthof(shares[cshare].shi1_netname),
1762 rootShares.shares[i].shi0_netname);
1763 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1768 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1769 outp->parmsp[1] = 0;
1770 outp->parmsp[2] = cshare;
1771 outp->parmsp[3] = nShares;
1773 outp->totalData = (int)(cstrp - outp->datap);
1774 outp->totalParms = outParmsTotal;
1776 smb_SendTran2Packet(vcp, outp, op);
1777 smb_FreeTran2Packet(outp);
1779 free(rootShares.shares);
1784 /* RAP NetShareGetInfo */
1785 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1787 smb_tran2Packet_t *outp;
1788 unsigned short * tp;
1789 clientchar_t * shareName;
1790 BOOL shareFound = FALSE;
1791 unsigned short infoLevel;
1792 unsigned short bufsize;
1801 cm_scache_t *scp = NULL;
1807 tp = p->parmsp + 1; /* skip over function number (always 1) */
1810 clientchar_t * cdescp;
1812 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1813 if (cm_ClientStrCmp(cdescp, _C("zWrLh")))
1815 return CM_ERROR_INVAL;
1817 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1818 if (cm_ClientStrCmp(cdescp, _C("B13")) &&
1819 cm_ClientStrCmp(cdescp, _C("B13BWz")) &&
1820 cm_ClientStrCmp(cdescp, _C("B13BWzWWWzB9B")))
1822 return CM_ERROR_INVAL;
1824 shareName = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1832 totalData = sizeof(smb_rap_share_info_0_t);
1833 else if(infoLevel == SMB_INFO_STANDARD)
1834 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1835 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1836 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1838 return CM_ERROR_INVAL;
1840 if(!cm_ClientStrCmpI(shareName, _C("all")) || !cm_ClientStrCmp(shareName,_C("*."))) {
1841 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1842 KEY_QUERY_VALUE, &hkParam);
1843 if (rv == ERROR_SUCCESS) {
1844 len = sizeof(allSubmount);
1845 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1846 (BYTE *) &allSubmount, &len);
1847 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1850 RegCloseKey (hkParam);
1857 userp = smb_GetTran2User(vcp, p);
1859 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
1860 return CM_ERROR_BADSMB;
1862 code = cm_NameI(cm_data.rootSCachep, shareName,
1863 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
1864 userp, NULL, &req, &scp);
1866 cm_ReleaseSCache(scp);
1869 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1870 KEY_QUERY_VALUE, &hkSubmount);
1871 if (rv == ERROR_SUCCESS) {
1872 rv = RegQueryValueExW(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1873 if (rv == ERROR_SUCCESS) {
1876 RegCloseKey(hkSubmount);
1882 return CM_ERROR_BADSHARENAME;
1884 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1885 memset(outp->datap, 0, totalData);
1887 outp->parmsp[0] = 0;
1888 outp->parmsp[1] = 0;
1889 outp->parmsp[2] = totalData;
1891 if (infoLevel == 0) {
1892 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1893 cm_ClientStringToUtf8(shareName, -1, info->shi0_netname,
1894 lengthof(info->shi0_netname));
1895 } else if(infoLevel == SMB_INFO_STANDARD) {
1896 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1897 cm_ClientStringToUtf8(shareName, -1, info->shi1_netname, lengthof(info->shi1_netname));
1898 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1899 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1900 /* type and pad are already zero */
1901 } else { /* infoLevel==2 */
1902 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1903 cm_ClientStringToUtf8(shareName, -1, info->shi2_netname, lengthof(info->shi2_netname));
1904 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1905 info->shi2_permissions = ACCESS_ALL;
1906 info->shi2_max_uses = (unsigned short) -1;
1907 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
1910 outp->totalData = totalData;
1911 outp->totalParms = totalParam;
1913 smb_SendTran2Packet(vcp, outp, op);
1914 smb_FreeTran2Packet(outp);
1919 #pragma pack(push, 1)
1921 typedef struct smb_rap_wksta_info_10 {
1922 DWORD wki10_computername; /*char *wki10_computername;*/
1923 DWORD wki10_username; /* char *wki10_username; */
1924 DWORD wki10_langroup; /* char *wki10_langroup;*/
1925 BYTE wki10_ver_major;
1926 BYTE wki10_ver_minor;
1927 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1928 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1929 } smb_rap_wksta_info_10_t;
1933 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1935 smb_tran2Packet_t *outp;
1939 unsigned short * tp;
1942 smb_rap_wksta_info_10_t * info;
1946 tp = p->parmsp + 1; /* Skip over function number */
1949 clientchar_t * cdescp;
1951 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
1952 SMB_STRF_FORCEASCII);
1953 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
1954 return CM_ERROR_INVAL;
1956 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
1957 SMB_STRF_FORCEASCII);
1958 if (cm_ClientStrCmp(cdescp, _C("zzzBBzz")))
1959 return CM_ERROR_INVAL;
1965 if (infoLevel != 10) {
1966 return CM_ERROR_INVAL;
1972 totalData = sizeof(*info) + /* info */
1973 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1974 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1975 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1976 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1977 1; /* wki10_oth_domains (null)*/
1979 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1981 memset(outp->parmsp,0,totalParams);
1982 memset(outp->datap,0,totalData);
1984 info = (smb_rap_wksta_info_10_t *) outp->datap;
1985 cstrp = (char *) (info + 1);
1987 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1988 StringCbCopyA(cstrp, totalData, smb_localNamep);
1989 cstrp += strlen(cstrp) + 1;
1991 info->wki10_username = (DWORD) (cstrp - outp->datap);
1992 uidp = smb_FindUID(vcp, p->uid, 0);
1994 lock_ObtainMutex(&uidp->mx);
1995 if(uidp->unp && uidp->unp->name)
1996 cm_ClientStringToUtf8(uidp->unp->name, -1,
1997 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
1998 lock_ReleaseMutex(&uidp->mx);
1999 smb_ReleaseUID(uidp);
2001 cstrp += strlen(cstrp) + 1;
2003 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
2004 StringCbCopyA(cstrp, totalData - (cstrp - outp->datap)*sizeof(char), "WORKGROUP");
2005 cstrp += strlen(cstrp) + 1;
2007 /* TODO: Not sure what values these should take, but these work */
2008 info->wki10_ver_major = 5;
2009 info->wki10_ver_minor = 1;
2011 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
2012 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
2013 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2014 cstrp += strlen(cstrp) + 1;
2016 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
2017 cstrp ++; /* no other domains */
2019 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
2020 outp->parmsp[2] = outp->totalData;
2021 outp->totalParms = totalParams;
2023 smb_SendTran2Packet(vcp,outp,op);
2024 smb_FreeTran2Packet(outp);
2029 #pragma pack(push, 1)
2031 typedef struct smb_rap_server_info_0 {
2033 } smb_rap_server_info_0_t;
2035 typedef struct smb_rap_server_info_1 {
2037 BYTE sv1_version_major;
2038 BYTE sv1_version_minor;
2040 DWORD sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
2041 } smb_rap_server_info_1_t;
2045 char smb_ServerComment[] = "OpenAFS Client";
2046 int smb_ServerCommentLen = sizeof(smb_ServerComment);
2048 #define SMB_SV_TYPE_SERVER 0x00000002L
2049 #define SMB_SV_TYPE_NT 0x00001000L
2050 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
2052 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2054 smb_tran2Packet_t *outp;
2058 unsigned short * tp;
2061 smb_rap_server_info_0_t * info0;
2062 smb_rap_server_info_1_t * info1;
2065 tp = p->parmsp + 1; /* Skip over function number */
2068 clientchar_t * cdescp;
2070 cdescp = smb_ParseStringT2Parm(p, (unsigned char *) tp, (char **) &tp,
2071 SMB_STRF_FORCEASCII);
2072 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2073 return CM_ERROR_INVAL;
2074 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2075 SMB_STRF_FORCEASCII);
2076 if (cm_ClientStrCmp(cdescp, _C("B16")) ||
2077 cm_ClientStrCmp(cdescp, _C("B16BBDz")))
2078 return CM_ERROR_INVAL;
2084 if (infoLevel != 0 && infoLevel != 1) {
2085 return CM_ERROR_INVAL;
2091 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
2092 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
2094 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2096 memset(outp->parmsp,0,totalParams);
2097 memset(outp->datap,0,totalData);
2099 if (infoLevel == 0) {
2100 info0 = (smb_rap_server_info_0_t *) outp->datap;
2101 cstrp = (char *) (info0 + 1);
2102 StringCchCopyA(info0->sv0_name, lengthof(info0->sv0_name), "AFS");
2103 } else { /* infoLevel == SMB_INFO_STANDARD */
2104 info1 = (smb_rap_server_info_1_t *) outp->datap;
2105 cstrp = (char *) (info1 + 1);
2106 StringCchCopyA(info1->sv1_name, lengthof(info1->sv1_name), "AFS");
2109 SMB_SV_TYPE_SERVER |
2111 SMB_SV_TYPE_SERVER_NT;
2113 info1->sv1_version_major = 5;
2114 info1->sv1_version_minor = 1;
2115 info1->sv1_comment_or_master_browser = (DWORD) (cstrp - outp->datap);
2117 StringCbCopyA(cstrp, smb_ServerCommentLen, smb_ServerComment);
2119 cstrp += smb_ServerCommentLen / sizeof(char);
2122 totalData = (DWORD)(cstrp - outp->datap);
2123 outp->totalData = min(bufsize,totalData); /* actual data size */
2124 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
2125 outp->parmsp[2] = totalData;
2126 outp->totalParms = totalParams;
2128 smb_SendTran2Packet(vcp,outp,op);
2129 smb_FreeTran2Packet(outp);
2134 /* SMB_COM_TRANSACTION2 and SMB_COM_TRANSACTION2_SECONDARY */
2135 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2137 smb_tran2Packet_t *asp;
2148 DWORD oldTime, newTime;
2150 /* We sometimes see 0 word count. What to do? */
2151 if (*inp->wctp == 0) {
2152 osi_Log0(smb_logp, "Transaction2 word count = 0");
2153 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
2155 smb_SetSMBDataLength(outp, 0);
2156 smb_SendPacket(vcp, outp);
2160 totalParms = smb_GetSMBParm(inp, 0);
2161 totalData = smb_GetSMBParm(inp, 1);
2163 firstPacket = (inp->inCom == 0x32);
2165 /* find the packet we're reassembling */
2166 lock_ObtainWrite(&smb_globalLock);
2167 asp = smb_FindTran2Packet(vcp, inp);
2169 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
2171 lock_ReleaseWrite(&smb_globalLock);
2173 /* now merge in this latest packet; start by looking up offsets */
2175 parmDisp = dataDisp = 0;
2176 parmOffset = smb_GetSMBParm(inp, 10);
2177 dataOffset = smb_GetSMBParm(inp, 12);
2178 parmCount = smb_GetSMBParm(inp, 9);
2179 dataCount = smb_GetSMBParm(inp, 11);
2180 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2181 asp->maxReturnData = smb_GetSMBParm(inp, 3);
2183 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2184 totalData, dataCount, asp->maxReturnData);
2187 parmDisp = smb_GetSMBParm(inp, 4);
2188 parmOffset = smb_GetSMBParm(inp, 3);
2189 dataDisp = smb_GetSMBParm(inp, 7);
2190 dataOffset = smb_GetSMBParm(inp, 6);
2191 parmCount = smb_GetSMBParm(inp, 2);
2192 dataCount = smb_GetSMBParm(inp, 5);
2194 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2195 parmCount, dataCount);
2198 /* now copy the parms and data */
2199 if ( asp->totalParms > 0 && parmCount != 0 )
2201 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2203 if ( asp->totalData > 0 && dataCount != 0 ) {
2204 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2207 /* account for new bytes */
2208 asp->curData += dataCount;
2209 asp->curParms += parmCount;
2211 /* finally, if we're done, remove the packet from the queue and dispatch it */
2212 if (asp->totalParms > 0 &&
2213 asp->curParms > 0 &&
2214 asp->totalData <= asp->curData &&
2215 asp->totalParms <= asp->curParms) {
2216 /* we've received it all */
2217 lock_ObtainWrite(&smb_globalLock);
2218 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2219 lock_ReleaseWrite(&smb_globalLock);
2221 oldTime = GetTickCount();
2223 /* now dispatch it */
2224 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2225 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2226 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2229 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2230 code = CM_ERROR_BADOP;
2233 /* if an error is returned, we're supposed to send an error packet,
2234 * otherwise the dispatched function already did the data sending.
2235 * We give dispatched proc the responsibility since it knows how much
2236 * space to allocate.
2239 smb_SendTran2Error(vcp, asp, outp, code);
2242 newTime = GetTickCount();
2243 if (newTime - oldTime > 45000) {
2246 clientchar_t *treepath = NULL; /* do not free */
2247 clientchar_t *pathname = NULL;
2248 cm_fid_t afid = {0,0,0,0,0};
2250 uidp = smb_FindUID(vcp, asp->uid, 0);
2251 smb_LookupTIDPath(vcp, asp->tid, &treepath);
2252 fidp = smb_FindFID(vcp, inp->fid, 0);
2255 lock_ObtainMutex(&fidp->mx);
2256 if (fidp->NTopen_pathp)
2257 pathname = fidp->NTopen_pathp;
2259 afid = fidp->scp->fid;
2261 if (inp->stringsp->wdata)
2262 pathname = inp->stringsp->wdata;
2265 afsi_log("Request %s duration %d ms user %S tid \"%S\" path? \"%S\" afid (%d.%d.%d.%d)",
2266 myCrt_2Dispatch(asp->opcode), newTime - oldTime,
2267 uidp ? uidp->unp->name : NULL,
2270 afid.cell, afid.volume, afid.vnode, afid.unique);
2273 lock_ReleaseMutex(&fidp->mx);
2276 smb_ReleaseUID(uidp);
2278 smb_ReleaseFID(fidp);
2281 /* free the input tran 2 packet */
2282 smb_FreeTran2Packet(asp);
2284 else if (firstPacket) {
2285 /* the first packet in a multi-packet request, we need to send an
2286 * ack to get more data.
2288 smb_SetSMBDataLength(outp, 0);
2289 smb_SendPacket(vcp, outp);
2296 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2298 clientchar_t *pathp;
2299 smb_tran2Packet_t *outp;
2304 cm_scache_t *dscp; /* dir we're dealing with */
2305 cm_scache_t *scp; /* file we're creating */
2307 int initialModeBits;
2310 clientchar_t *lastNamep;
2317 int parmSlot; /* which parm we're dealing with */
2318 long returnEALength;
2319 clientchar_t *tidPathp;
2327 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2328 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2330 openFun = p->parmsp[6]; /* open function */
2331 excl = ((openFun & 3) == 0);
2332 trunc = ((openFun & 3) == 2); /* truncate it */
2333 openMode = (p->parmsp[1] & 0x7);
2334 openAction = 0; /* tracks what we did */
2336 attributes = p->parmsp[3];
2337 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2339 /* compute initial mode bits based on read-only flag in attributes */
2340 initialModeBits = 0666;
2341 if (attributes & SMB_ATTR_READONLY)
2342 initialModeBits &= ~0222;
2344 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
2347 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2349 spacep = cm_GetSpace();
2350 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2353 (cm_ClientStrCmpI(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
2354 cm_ClientStrCmpI(lastNamep, _C("\\srvsvc")) == 0 ||
2355 cm_ClientStrCmpI(lastNamep, _C("\\wkssvc")) == 0 ||
2356 cm_ClientStrCmpI(lastNamep, _C("\\ipc$")) == 0)) {
2357 /* special case magic file name for receiving IOCTL requests
2358 * (since IOCTL calls themselves aren't getting through).
2360 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2361 smb_SetupIoctlFid(fidp, spacep);
2363 /* copy out remainder of the parms */
2365 outp->parmsp[parmSlot++] = fidp->fid;
2367 outp->parmsp[parmSlot++] = 0; /* attrs */
2368 outp->parmsp[parmSlot++] = 0; /* mod time */
2369 outp->parmsp[parmSlot++] = 0;
2370 outp->parmsp[parmSlot++] = 0; /* len */
2371 outp->parmsp[parmSlot++] = 0x7fff;
2372 outp->parmsp[parmSlot++] = openMode;
2373 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2374 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2376 /* and the final "always present" stuff */
2377 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2378 /* next write out the "unique" ID */
2379 outp->parmsp[parmSlot++] = 0x1234;
2380 outp->parmsp[parmSlot++] = 0x5678;
2381 outp->parmsp[parmSlot++] = 0;
2382 if (returnEALength) {
2383 outp->parmsp[parmSlot++] = 0;
2384 outp->parmsp[parmSlot++] = 0;
2387 outp->totalData = 0;
2388 outp->totalParms = parmSlot * 2;
2390 smb_SendTran2Packet(vcp, outp, op);
2392 smb_FreeTran2Packet(outp);
2394 /* and clean up fid reference */
2395 smb_ReleaseFID(fidp);
2399 if (!cm_IsValidClientString(pathp)) {
2401 clientchar_t * hexp;
2403 hexp = cm_GetRawCharsAlloc(pathp, -1);
2404 osi_Log1(smb_logp, "Tran2Open rejecting invalid name. [%S]",
2405 osi_LogSaveClientString(smb_logp, hexp));
2409 osi_Log0(smb_logp, "Tran2Open rejecting invalid name");
2411 smb_FreeTran2Packet(outp);
2412 return CM_ERROR_BADNTFILENAME;
2415 #ifdef DEBUG_VERBOSE
2417 char *hexp, *asciip;
2418 asciip = (lastNamep ? lastNamep : pathp);
2419 hexp = osi_HexifyString( asciip );
2420 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2425 userp = smb_GetTran2User(vcp, p);
2426 /* In the off chance that userp is NULL, we log and abandon */
2428 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2429 smb_FreeTran2Packet(outp);
2430 return CM_ERROR_BADSMB;
2433 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2434 if (code == CM_ERROR_TIDIPC) {
2435 /* Attempt to use a TID allocated for IPC. The client
2436 * is probably looking for DCE RPC end points which we
2437 * don't support OR it could be looking to make a DFS
2440 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2442 cm_ReleaseUser(userp);
2443 smb_FreeTran2Packet(outp);
2444 return CM_ERROR_NOSUCHPATH;
2449 code = cm_NameI(cm_data.rootSCachep, pathp,
2450 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2451 userp, tidPathp, &req, &scp);
2453 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2454 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2455 userp, tidPathp, &req, &dscp);
2456 cm_FreeSpace(spacep);
2459 cm_ReleaseUser(userp);
2460 smb_FreeTran2Packet(outp);
2465 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2466 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2467 (clientchar_t*) spacep->data);
2468 cm_ReleaseSCache(dscp);
2469 cm_ReleaseUser(userp);
2470 smb_FreeTran2Packet(outp);
2471 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2472 return CM_ERROR_PATH_NOT_COVERED;
2474 return CM_ERROR_BADSHARENAME;
2476 #endif /* DFS_SUPPORT */
2478 /* otherwise, scp points to the parent directory. Do a lookup,
2479 * and truncate the file if we find it, otherwise we create the
2486 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2488 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2489 cm_ReleaseSCache(dscp);
2490 cm_ReleaseUser(userp);
2491 smb_FreeTran2Packet(outp);
2496 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2497 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2498 cm_ReleaseSCache(scp);
2499 cm_ReleaseUser(userp);
2500 smb_FreeTran2Packet(outp);
2501 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2502 return CM_ERROR_PATH_NOT_COVERED;
2504 return CM_ERROR_BADSHARENAME;
2506 #endif /* DFS_SUPPORT */
2508 /* macintosh is expensive to program for it */
2509 cm_FreeSpace(spacep);
2512 /* if we get here, if code is 0, the file exists and is represented by
2513 * scp. Otherwise, we have to create it.
2516 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2519 cm_ReleaseSCache(dscp);
2520 cm_ReleaseSCache(scp);
2521 cm_ReleaseUser(userp);
2522 smb_FreeTran2Packet(outp);
2527 /* oops, file shouldn't be there */
2529 cm_ReleaseSCache(dscp);
2530 cm_ReleaseSCache(scp);
2531 cm_ReleaseUser(userp);
2532 smb_FreeTran2Packet(outp);
2533 return CM_ERROR_EXISTS;
2537 setAttr.mask = CM_ATTRMASK_LENGTH;
2538 setAttr.length.LowPart = 0;
2539 setAttr.length.HighPart = 0;
2540 code = cm_SetAttr(scp, &setAttr, userp, &req);
2541 openAction = 3; /* truncated existing file */
2544 openAction = 1; /* found existing file */
2546 else if (!(openFun & 0x10)) {
2547 /* don't create if not found */
2549 cm_ReleaseSCache(dscp);
2550 osi_assertx(scp == NULL, "null cm_scache_t");
2551 cm_ReleaseUser(userp);
2552 smb_FreeTran2Packet(outp);
2553 return CM_ERROR_NOSUCHFILE;
2556 osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2557 openAction = 2; /* created file */
2558 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2559 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2560 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2564 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2565 smb_NotifyChange(FILE_ACTION_ADDED,
2566 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2567 dscp, lastNamep, NULL, TRUE);
2568 } else if (!excl && code == CM_ERROR_EXISTS) {
2569 /* not an exclusive create, and someone else tried
2570 * creating it already, then we open it anyway. We
2571 * don't bother retrying after this, since if this next
2572 * fails, that means that the file was deleted after we
2573 * started this call.
2575 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2579 setAttr.mask = CM_ATTRMASK_LENGTH;
2580 setAttr.length.LowPart = 0;
2581 setAttr.length.HighPart = 0;
2582 code = cm_SetAttr(scp, &setAttr, userp,
2585 } /* lookup succeeded */
2589 /* we don't need this any longer */
2591 cm_ReleaseSCache(dscp);
2594 /* something went wrong creating or truncating the file */
2596 cm_ReleaseSCache(scp);
2597 cm_ReleaseUser(userp);
2598 smb_FreeTran2Packet(outp);
2602 /* make sure we're about to open a file */
2603 if (scp->fileType != CM_SCACHETYPE_FILE) {
2605 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2606 cm_scache_t * targetScp = 0;
2607 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2609 /* we have a more accurate file to use (the
2610 * target of the symbolic link). Otherwise,
2611 * we'll just use the symlink anyway.
2613 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2615 cm_ReleaseSCache(scp);
2619 if (scp->fileType != CM_SCACHETYPE_FILE) {
2620 cm_ReleaseSCache(scp);
2621 cm_ReleaseUser(userp);
2622 smb_FreeTran2Packet(outp);
2623 return CM_ERROR_ISDIR;
2627 /* now all we have to do is open the file itself */
2628 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2629 osi_assertx(fidp, "null smb_fid_t");
2632 lock_ObtainMutex(&fidp->mx);
2633 /* save a pointer to the vnode */
2634 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2636 lock_ObtainWrite(&scp->rw);
2637 scp->flags |= CM_SCACHEFLAG_SMB_FID;
2638 lock_ReleaseWrite(&scp->rw);
2641 fidp->userp = userp;
2643 /* compute open mode */
2645 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
2646 if (openMode == 1 || openMode == 2)
2647 fidp->flags |= SMB_FID_OPENWRITE;
2649 /* remember that the file was newly created */
2651 fidp->flags |= SMB_FID_CREATED;
2653 lock_ReleaseMutex(&fidp->mx);
2655 smb_ReleaseFID(fidp);
2657 cm_Open(scp, 0, userp);
2659 /* copy out remainder of the parms */
2661 outp->parmsp[parmSlot++] = fidp->fid;
2662 lock_ObtainRead(&scp->rw);
2664 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2665 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2666 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2667 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2668 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2669 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2670 outp->parmsp[parmSlot++] = openMode;
2671 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2672 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2674 /* and the final "always present" stuff */
2675 outp->parmsp[parmSlot++] = openAction;
2676 /* next write out the "unique" ID */
2677 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2678 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2679 outp->parmsp[parmSlot++] = 0;
2680 if (returnEALength) {
2681 outp->parmsp[parmSlot++] = 0;
2682 outp->parmsp[parmSlot++] = 0;
2684 lock_ReleaseRead(&scp->rw);
2685 outp->totalData = 0; /* total # of data bytes */
2686 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2688 smb_SendTran2Packet(vcp, outp, op);
2690 smb_FreeTran2Packet(outp);
2692 cm_ReleaseUser(userp);
2693 /* leave scp held since we put it in fidp->scp */
2697 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2700 unsigned short infolevel;
2702 infolevel = p->parmsp[0];
2704 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2706 return CM_ERROR_BAD_LEVEL;
2709 /* TRANS2_QUERY_FS_INFORMATION */
2710 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2712 smb_tran2Packet_t *outp;
2713 smb_tran2QFSInfo_t qi;
2717 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2719 switch (p->parmsp[0]) {
2720 case SMB_INFO_ALLOCATION:
2722 responseSize = sizeof(qi.u.allocInfo);
2724 qi.u.allocInfo.FSID = 0;
2725 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2726 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2727 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2728 qi.u.allocInfo.bytesPerSector = 1024;
2731 case SMB_INFO_VOLUME:
2733 qi.u.volumeInfo.vsn = 1234; /* Volume serial number */
2734 qi.u.volumeInfo.vnCount = 3; /* Number of characters in label (AFS\0)*/
2736 /* we're supposed to pad it out with zeroes to the end */
2737 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2738 smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
2740 responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
2743 case SMB_QUERY_FS_VOLUME_INFO:
2744 /* FS volume info */
2745 responseSize = sizeof(qi.u.FSvolumeInfo);
2748 FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
2749 memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
2752 qi.u.FSvolumeInfo.vsn = 1234;
2753 qi.u.FSvolumeInfo.vnCount = 6; /* This is always in Unicode */
2754 memset(&qi.u.FSvolumeInfo.label, 0, sizeof(qi.u.FSvolumeInfo.label));
2755 memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
2758 case SMB_QUERY_FS_SIZE_INFO:
2760 responseSize = sizeof(qi.u.FSsizeInfo);
2762 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2763 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2764 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2765 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2766 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2767 qi.u.FSsizeInfo.bytesPerSector = 1024;
2770 case SMB_QUERY_FS_DEVICE_INFO:
2771 /* FS device info */
2772 responseSize = sizeof(qi.u.FSdeviceInfo);
2774 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2775 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2778 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2779 /* FS attribute info */
2781 /* attributes, defined in WINNT.H:
2782 * FILE_CASE_SENSITIVE_SEARCH 0x1
2783 * FILE_CASE_PRESERVED_NAMES 0x2
2784 * FILE_UNICODE_ON_DISK 0x4
2785 * FILE_VOLUME_QUOTAS 0x10
2786 * <no name defined> 0x4000
2787 * If bit 0x4000 is not set, Windows 95 thinks
2788 * we can't handle long (non-8.3) names,
2789 * despite our protestations to the contrary.
2791 qi.u.FSattributeInfo.attributes = 0x4003;
2792 /* The maxCompLength is supposed to be in bytes */
2794 qi.u.FSattributeInfo.attributes |= 0x04;
2796 qi.u.FSattributeInfo.maxCompLength = 255;
2797 smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
2798 qi.u.FSattributeInfo.FSnameLength = sz;
2801 sizeof(qi.u.FSattributeInfo.attributes) +
2802 sizeof(qi.u.FSattributeInfo.maxCompLength) +
2803 sizeof(qi.u.FSattributeInfo.FSnameLength) +
2808 case SMB_INFO_UNIX: /* CIFS Unix Info */
2809 case SMB_INFO_MACOS: /* Mac FS Info */
2811 return CM_ERROR_BADOP;
2814 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2816 /* copy out return data, and set corresponding sizes */
2817 outp->totalParms = 0;
2818 outp->totalData = responseSize;
2819 memcpy(outp->datap, &qi, responseSize);
2821 /* send and free the packets */
2822 smb_SendTran2Packet(vcp, outp, op);
2823 smb_FreeTran2Packet(outp);
2828 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2830 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2831 return CM_ERROR_BADOP;
2834 struct smb_ShortNameRock {
2835 clientchar_t *maskp;
2837 clientchar_t *shortName;
2838 size_t shortNameLen;
2841 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2844 struct smb_ShortNameRock *rockp;
2845 normchar_t normName[MAX_PATH];
2846 clientchar_t *shortNameEnd;
2850 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t)) == 0) {
2851 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
2852 osi_LogSaveString(smb_logp, dep->name));
2856 /* compare both names and vnodes, though probably just comparing vnodes
2857 * would be safe enough.
2859 if (cm_NormStrCmpI(normName, rockp->maskp) != 0)
2861 if (ntohl(dep->fid.vnode) != rockp->vnode)
2864 /* This is the entry */
2865 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2866 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2868 return CM_ERROR_STOPNOW;
2871 long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
2872 clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
2874 struct smb_ShortNameRock rock;
2875 clientchar_t *lastNamep;
2878 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2882 spacep = cm_GetSpace();
2883 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2885 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2886 caseFold, userp, tidPathp,
2888 cm_FreeSpace(spacep);
2893 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2894 cm_ReleaseSCache(dscp);
2895 cm_ReleaseUser(userp);
2899 return CM_ERROR_PATH_NOT_COVERED;
2901 #endif /* DFS_SUPPORT */
2903 if (!lastNamep) lastNamep = pathp;
2906 thyper.HighPart = 0;
2907 rock.shortName = shortName;
2909 rock.maskp = lastNamep;
2910 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2912 cm_ReleaseSCache(dscp);
2915 return CM_ERROR_NOSUCHFILE;
2916 if (code == CM_ERROR_STOPNOW) {
2917 *shortNameLenp = rock.shortNameLen;
2923 /* TRANS2_QUERY_PATH_INFORMATION */
2924 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2926 smb_tran2Packet_t *outp;
2929 unsigned short infoLevel;
2930 smb_tran2QPathInfo_t qpi;
2932 unsigned short attributes;
2933 unsigned long extAttributes;
2934 clientchar_t shortName[13];
2938 cm_scache_t *scp, *dscp;
2939 int scp_rw_held = 0;
2942 clientchar_t *pathp;
2943 clientchar_t *tidPathp;
2944 clientchar_t *lastComp;
2949 infoLevel = p->parmsp[0];
2950 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2952 else if (infoLevel == SMB_INFO_STANDARD)
2953 responseSize = sizeof(qpi.u.QPstandardInfo);
2954 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2955 responseSize = sizeof(qpi.u.QPeaSizeInfo);
2956 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2957 responseSize = sizeof(qpi.u.QPfileBasicInfo);
2958 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2959 responseSize = sizeof(qpi.u.QPfileStandardInfo);
2960 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2961 responseSize = sizeof(qpi.u.QPfileEaInfo);
2962 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2963 responseSize = sizeof(qpi.u.QPfileNameInfo);
2964 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
2965 responseSize = sizeof(qpi.u.QPfileAllInfo);
2966 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2967 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2969 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2970 p->opcode, infoLevel);
2971 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
2975 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
2976 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %S", infoLevel,
2977 osi_LogSaveClientString(smb_logp, pathp));
2979 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2981 if (infoLevel > 0x100)
2982 outp->totalParms = 2;
2984 outp->totalParms = 0;
2985 outp->totalData = responseSize;
2987 /* now, if we're at infoLevel 6, we're only being asked to check
2988 * the syntax, so we just OK things now. In particular, we're *not*
2989 * being asked to verify anything about the state of any parent dirs.
2991 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2992 smb_SendTran2Packet(vcp, outp, opx);
2993 smb_FreeTran2Packet(outp);
2997 userp = smb_GetTran2User(vcp, p);
2999 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
3000 smb_FreeTran2Packet(outp);
3001 return CM_ERROR_BADSMB;
3004 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3006 cm_ReleaseUser(userp);
3007 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
3008 smb_FreeTran2Packet(outp);
3013 * XXX Strange hack XXX
3015 * As of Patch 7 (13 January 98), we are having the following problem:
3016 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3017 * requests to look up "desktop.ini" in all the subdirectories.
3018 * This can cause zillions of timeouts looking up non-existent cells
3019 * and volumes, especially in the top-level directory.
3021 * We have not found any way to avoid this or work around it except
3022 * to explicitly ignore the requests for mount points that haven't
3023 * yet been evaluated and for directories that haven't yet been
3026 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3027 spacep = cm_GetSpace();
3028 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3029 #ifndef SPECIAL_FOLDERS
3030 /* Make sure that lastComp is not NULL */
3032 if (cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
3033 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3037 userp, tidPathp, &req, &dscp);
3040 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3041 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3043 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3044 code = CM_ERROR_PATH_NOT_COVERED;
3046 code = CM_ERROR_BADSHARENAME;
3048 #endif /* DFS_SUPPORT */
3049 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3050 code = CM_ERROR_NOSUCHFILE;
3051 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3052 cm_buf_t *bp = buf_Find(dscp, &hzero);
3058 code = CM_ERROR_NOSUCHFILE;
3060 cm_ReleaseSCache(dscp);
3062 cm_FreeSpace(spacep);
3063 cm_ReleaseUser(userp);
3064 smb_SendTran2Error(vcp, p, opx, code);
3065 smb_FreeTran2Packet(outp);
3071 #endif /* SPECIAL_FOLDERS */
3073 cm_FreeSpace(spacep);
3076 /* now do namei and stat, and copy out the info */
3077 code = cm_NameI(cm_data.rootSCachep, pathp,
3078 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3081 cm_ReleaseUser(userp);
3082 smb_SendTran2Error(vcp, p, opx, code);
3083 smb_FreeTran2Packet(outp);
3088 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3089 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3090 cm_ReleaseSCache(scp);
3091 cm_ReleaseUser(userp);
3092 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3093 code = CM_ERROR_PATH_NOT_COVERED;
3095 code = CM_ERROR_BADSHARENAME;
3096 smb_SendTran2Error(vcp, p, opx, code);
3097 smb_FreeTran2Packet(outp);
3100 #endif /* DFS_SUPPORT */
3102 lock_ObtainWrite(&scp->rw);
3104 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3105 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3109 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3111 lock_ConvertWToR(&scp->rw);
3116 /* now we have the status in the cache entry, and everything is locked.
3117 * Marshall the output data.
3119 /* for info level 108, figure out short name */
3120 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3121 code = cm_GetShortName(pathp, userp, &req,
3122 tidPathp, scp->fid.vnode, shortName,
3128 smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
3129 qpi.u.QPfileAltNameInfo.fileNameLength = len;
3133 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3134 smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3135 qpi.u.QPfileNameInfo.fileNameLength = len;
3139 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3140 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3141 qpi.u.QPstandardInfo.creationDateTime = dosTime;
3142 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3143 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3144 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3145 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3146 attributes = smb_Attributes(scp);
3147 qpi.u.QPstandardInfo.attributes = attributes;
3148 qpi.u.QPstandardInfo.eaSize = 0;
3150 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3151 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3152 qpi.u.QPfileBasicInfo.creationTime = ft;
3153 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3154 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3155 qpi.u.QPfileBasicInfo.changeTime = ft;
3156 extAttributes = smb_ExtAttributes(scp);
3157 qpi.u.QPfileBasicInfo.attributes = extAttributes;
3158 qpi.u.QPfileBasicInfo.reserved = 0;
3160 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3163 lock_ReleaseRead(&scp->rw);
3165 fidp = smb_FindFIDByScache(vcp, scp);
3167 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3168 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3169 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3170 qpi.u.QPfileStandardInfo.directory =
3171 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3172 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3173 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3174 qpi.u.QPfileStandardInfo.reserved = 0;
3177 lock_ObtainMutex(&fidp->mx);
3178 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3179 lock_ReleaseMutex(&fidp->mx);
3180 smb_ReleaseFID(fidp);
3182 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3184 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3185 qpi.u.QPfileEaInfo.eaSize = 0;
3187 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3188 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3189 qpi.u.QPfileAllInfo.creationTime = ft;
3190 qpi.u.QPfileAllInfo.lastAccessTime = ft;
3191 qpi.u.QPfileAllInfo.lastWriteTime = ft;
3192 qpi.u.QPfileAllInfo.changeTime = ft;
3193 extAttributes = smb_ExtAttributes(scp);
3194 qpi.u.QPfileAllInfo.attributes = extAttributes;
3195 qpi.u.QPfileAllInfo.allocationSize = scp->length;
3196 qpi.u.QPfileAllInfo.endOfFile = scp->length;
3197 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3198 qpi.u.QPfileAllInfo.deletePending = 0;
3199 qpi.u.QPfileAllInfo.directory =
3200 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3201 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3202 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3203 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
3204 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
3205 qpi.u.QPfileAllInfo.eaSize = 0;
3206 qpi.u.QPfileAllInfo.accessFlags = 0;
3207 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
3208 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
3209 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3210 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3211 qpi.u.QPfileAllInfo.mode = 0;
3212 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3214 smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3215 qpi.u.QPfileAllInfo.fileNameLength = len;
3218 /* send and free the packets */
3220 switch (scp_rw_held) {
3222 lock_ReleaseRead(&scp->rw);
3225 lock_ReleaseWrite(&scp->rw);
3229 cm_ReleaseSCache(scp);
3230 cm_ReleaseUser(userp);
3232 memcpy(outp->datap, &qpi, responseSize);
3233 smb_SendTran2Packet(vcp, outp, opx);
3235 smb_SendTran2Error(vcp, p, opx, code);
3237 smb_FreeTran2Packet(outp);
3242 /* TRANS2_SET_PATH_INFORMATION */
3243 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3246 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
3247 return CM_ERROR_BADOP;
3250 unsigned short infoLevel;
3251 clientchar_t * pathp;
3252 smb_tran2Packet_t *outp;
3253 smb_tran2QPathInfo_t *spi;
3255 cm_scache_t *scp, *dscp;
3258 clientchar_t *tidPathp;
3259 clientchar_t *lastComp;
3263 infoLevel = p->parmsp[0];
3264 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
3265 if (infoLevel != SMB_INFO_STANDARD &&
3266 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
3267 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
3268 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3269 p->opcode, infoLevel);
3270 smb_SendTran2Error(vcp, p, opx,
3271 infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3275 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3277 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
3278 osi_LogSaveClientString(smb_logp, pathp));
3280 userp = smb_GetTran2User(vcp, p);
3282 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3283 code = CM_ERROR_BADSMB;
3287 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3288 if (code == CM_ERROR_TIDIPC) {
3289 /* Attempt to use a TID allocated for IPC. The client
3290 * is probably looking for DCE RPC end points which we
3291 * don't support OR it could be looking to make a DFS
3294 osi_Log0(smb_logp, "Tran2Open received IPC TID");
3295 cm_ReleaseUser(userp);
3296 return CM_ERROR_NOSUCHPATH;
3300 * XXX Strange hack XXX
3302 * As of Patch 7 (13 January 98), we are having the following problem:
3303 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3304 * requests to look up "desktop.ini" in all the subdirectories.
3305 * This can cause zillions of timeouts looking up non-existent cells
3306 * and volumes, especially in the top-level directory.
3308 * We have not found any way to avoid this or work around it except
3309 * to explicitly ignore the requests for mount points that haven't
3310 * yet been evaluated and for directories that haven't yet been
3313 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3314 spacep = cm_GetSpace();
3315 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3316 #ifndef SPECIAL_FOLDERS
3317 /* Make sure that lastComp is not NULL */
3319 if (cm_ClientStrCmpI(lastComp, _C("\\desktop.ini")) == 0) {
3320 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3324 userp, tidPathp, &req, &dscp);
3327 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3328 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3330 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3331 code = CM_ERROR_PATH_NOT_COVERED;
3333 code = CM_ERROR_BADSHARENAME;
3335 #endif /* DFS_SUPPORT */
3336 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3337 code = CM_ERROR_NOSUCHFILE;
3338 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3339 cm_buf_t *bp = buf_Find(dscp, &hzero);
3345 code = CM_ERROR_NOSUCHFILE;
3347 cm_ReleaseSCache(dscp);
3349 cm_FreeSpace(spacep);
3350 cm_ReleaseUser(userp);
3351 smb_SendTran2Error(vcp, p, opx, code);
3357 #endif /* SPECIAL_FOLDERS */
3359 cm_FreeSpace(spacep);
3362 /* now do namei and stat, and copy out the info */
3363 code = cm_NameI(cm_data.rootSCachep, pathp,
3364 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3366 cm_ReleaseUser(userp);
3367 smb_SendTran2Error(vcp, p, opx, code);
3371 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3373 outp->totalParms = 2;
3374 outp->totalData = 0;
3376 spi = (smb_tran2QPathInfo_t *)p->datap;
3377 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3380 /* lock the vnode with a callback; we need the current status
3381 * to determine what the new status is, in some cases.
3383 lock_ObtainWrite(&scp->rw);
3384 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3385 CM_SCACHESYNC_GETSTATUS
3386 | CM_SCACHESYNC_NEEDCALLBACK);
3388 lock_ReleaseWrite(&scp->rw);
3391 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3393 /* prepare for setattr call */
3394 attr.mask = CM_ATTRMASK_LENGTH;
3395 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3396 attr.length.HighPart = 0;
3398 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3399 smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3400 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3403 if (spi->u.QPstandardInfo.attributes != 0) {
3404 if ((scp->unixModeBits & 0222)
3405 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3406 /* make a writable file read-only */
3407 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3408 attr.unixModeBits = scp->unixModeBits & ~0222;
3410 else if ((scp->unixModeBits & 0222) == 0
3411 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3412 /* make a read-only file writable */
3413 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3414 attr.unixModeBits = scp->unixModeBits | 0222;
3417 lock_ReleaseRead(&scp->rw);
3421 code = cm_SetAttr(scp, &attr, userp, &req);
3425 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3426 /* we don't support EAs */
3427 code = CM_ERROR_EAS_NOT_SUPPORTED;
3431 cm_ReleaseSCache(scp);
3432 cm_ReleaseUser(userp);
3434 smb_SendTran2Packet(vcp, outp, opx);
3436 smb_SendTran2Error(vcp, p, opx, code);
3437 smb_FreeTran2Packet(outp);
3443 /* TRANS2_QUERY_FILE_INFORMATION */
3444 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3446 smb_tran2Packet_t *outp;
3448 unsigned long attributes;
3449 unsigned short infoLevel;
3456 smb_tran2QFileInfo_t qfi;
3464 fidp = smb_FindFID(vcp, fid, 0);
3467 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3471 lock_ObtainMutex(&fidp->mx);
3472 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3473 lock_ReleaseMutex(&fidp->mx);
3474 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3475 smb_CloseFID(vcp, fidp, NULL, 0);
3476 smb_ReleaseFID(fidp);
3479 lock_ReleaseMutex(&fidp->mx);
3481 infoLevel = p->parmsp[1];
3482 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3483 responseSize = sizeof(qfi.u.QFbasicInfo);
3484 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3485 responseSize = sizeof(qfi.u.QFstandardInfo);
3486 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3487 responseSize = sizeof(qfi.u.QFeaInfo);
3488 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3489 responseSize = sizeof(qfi.u.QFfileNameInfo);
3491 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3492 p->opcode, infoLevel);
3493 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3494 smb_ReleaseFID(fidp);
3497 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3499 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3501 if (infoLevel > 0x100)
3502 outp->totalParms = 2;
3504 outp->totalParms = 0;
3505 outp->totalData = responseSize;
3507 userp = smb_GetTran2User(vcp, p);
3509 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3510 code = CM_ERROR_BADSMB;
3514 lock_ObtainMutex(&fidp->mx);
3515 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3517 osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3519 lock_ReleaseMutex(&fidp->mx);
3520 lock_ObtainWrite(&scp->rw);
3521 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3522 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3526 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3528 lock_ConvertWToR(&scp->rw);
3531 /* now we have the status in the cache entry, and everything is locked.
3532 * Marshall the output data.
3534 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3535 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3536 qfi.u.QFbasicInfo.creationTime = ft;
3537 qfi.u.QFbasicInfo.lastAccessTime = ft;
3538 qfi.u.QFbasicInfo.lastWriteTime = ft;
3539 qfi.u.QFbasicInfo.lastChangeTime = ft;
3540 attributes = smb_ExtAttributes(scp);
3541 qfi.u.QFbasicInfo.attributes = attributes;
3543 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3544 qfi.u.QFstandardInfo.allocationSize = scp->length;
3545 qfi.u.QFstandardInfo.endOfFile = scp->length;
3546 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3547 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3548 qfi.u.QFstandardInfo.directory =
3549 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3550 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3551 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3553 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3554 qfi.u.QFeaInfo.eaSize = 0;
3556 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3560 lock_ReleaseRead(&scp->rw);
3561 lock_ObtainMutex(&fidp->mx);
3562 lock_ObtainRead(&scp->rw);
3563 if (fidp->NTopen_wholepathp)
3564 name = fidp->NTopen_wholepathp;
3566 name = _C("\\"); /* probably can't happen */
3567 lock_ReleaseMutex(&fidp->mx);
3569 smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, SMB_STRF_IGNORENUL);
3570 outp->totalData = len + 4; /* this is actually what we want to return */
3571 qfi.u.QFfileNameInfo.fileNameLength = len;
3574 /* send and free the packets */
3577 lock_ReleaseRead(&scp->rw);
3579 lock_ReleaseWrite(&scp->rw);
3580 cm_ReleaseSCache(scp);
3581 cm_ReleaseUser(userp);
3582 smb_ReleaseFID(fidp);
3584 memcpy(outp->datap, &qfi, responseSize);
3585 smb_SendTran2Packet(vcp, outp, opx);
3587 smb_SendTran2Error(vcp, p, opx, code);
3589 smb_FreeTran2Packet(outp);
3595 /* TRANS2_SET_FILE_INFORMATION */
3596 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3601 unsigned short infoLevel;
3602 smb_tran2Packet_t *outp;
3603 cm_user_t *userp = NULL;
3604 cm_scache_t *scp = NULL;
3610 fidp = smb_FindFID(vcp, fid, 0);
3613 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3617 infoLevel = p->parmsp[1];
3618 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3619 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3620 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3621 p->opcode, infoLevel);
3622 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3623 smb_ReleaseFID(fidp);
3627 lock_ObtainMutex(&fidp->mx);
3628 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3629 lock_ReleaseMutex(&fidp->mx);
3630 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3631 smb_CloseFID(vcp, fidp, NULL, 0);
3632 smb_ReleaseFID(fidp);
3636 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
3637 !(fidp->flags & SMB_FID_OPENDELETE)) {
3638 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3639 fidp, fidp->scp, fidp->flags);
3640 lock_ReleaseMutex(&fidp->mx);
3641 smb_ReleaseFID(fidp);
3642 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3645 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3646 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3647 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3648 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3649 fidp, fidp->scp, fidp->flags);
3650 lock_ReleaseMutex(&fidp->mx);
3651 smb_ReleaseFID(fidp);
3652 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3657 osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3659 lock_ReleaseMutex(&fidp->mx);
3661 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3663 outp->totalParms = 2;
3664 outp->totalData = 0;
3666 userp = smb_GetTran2User(vcp, p);
3668 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3669 code = CM_ERROR_BADSMB;
3673 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3675 unsigned int attribute;
3677 smb_tran2QFileInfo_t *sfi;
3679 sfi = (smb_tran2QFileInfo_t *)p->datap;
3681 /* lock the vnode with a callback; we need the current status
3682 * to determine what the new status is, in some cases.
3684 lock_ObtainWrite(&scp->rw);
3685 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3686 CM_SCACHESYNC_GETSTATUS
3687 | CM_SCACHESYNC_NEEDCALLBACK);
3689 lock_ReleaseWrite(&scp->rw);
3693 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3695 lock_ReleaseWrite(&scp->rw);
3696 lock_ObtainMutex(&fidp->mx);
3697 lock_ObtainRead(&scp->rw);
3699 /* prepare for setattr call */
3702 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3703 /* when called as result of move a b, lastMod is (-1, -1).
3704 * If the check for -1 is not present, timestamp
3705 * of the resulting file will be 1969 (-1)
3707 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3708 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3709 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3710 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3711 fidp->flags |= SMB_FID_MTIMESETDONE;
3714 attribute = sfi->u.QFbasicInfo.attributes;
3715 if (attribute != 0) {
3716 if ((scp->unixModeBits & 0222)
3717 && (attribute & SMB_ATTR_READONLY) != 0) {
3718 /* make a writable file read-only */
3719 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3720 attr.unixModeBits = scp->unixModeBits & ~0222;
3722 else if ((scp->unixModeBits & 0222) == 0
3723 && (attribute & SMB_ATTR_READONLY) == 0) {
3724 /* make a read-only file writable */
3725 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3726 attr.unixModeBits = scp->unixModeBits | 0222;
3729 lock_ReleaseRead(&scp->rw);
3730 lock_ReleaseMutex(&fidp->mx);
3734 code = cm_SetAttr(scp, &attr, userp, &req);
3738 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3739 int delflag = *((char *)(p->datap));
3740 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
3741 delflag, fidp, scp);
3742 if (*((char *)(p->datap))) { /* File is Deleted */
3743 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3746 lock_ObtainMutex(&fidp->mx);
3747 fidp->flags |= SMB_FID_DELONCLOSE;
3748 lock_ReleaseMutex(&fidp->mx);
3750 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
3756 lock_ObtainMutex(&fidp->mx);
3757 fidp->flags &= ~SMB_FID_DELONCLOSE;
3758 lock_ReleaseMutex(&fidp->mx);
3761 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3762 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3763 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3766 attr.mask = CM_ATTRMASK_LENGTH;
3767 attr.length.LowPart = size.LowPart;
3768 attr.length.HighPart = size.HighPart;
3769 code = cm_SetAttr(scp, &attr, userp, &req);
3773 cm_ReleaseSCache(scp);
3774 cm_ReleaseUser(userp);
3775 smb_ReleaseFID(fidp);
3777 smb_SendTran2Packet(vcp, outp, opx);
3779 smb_SendTran2Error(vcp, p, opx, code);
3780 smb_FreeTran2Packet(outp);
3787 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3789 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3790 return CM_ERROR_BADOP;
3795 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3797 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3798 return CM_ERROR_BADOP;
3801 /* TRANS2_FIND_NOTIFY_FIRST */
3803 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3805 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3806 return CM_ERROR_BADOP;
3809 /* TRANS2_FIND_NOTIFY_NEXT */
3811 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3813 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3814 return CM_ERROR_BADOP;
3817 /* TRANS2_CREATE_DIRECTORY */
3819 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3821 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3822 return CM_ERROR_BADOP;
3825 /* TRANS2_SESSION_SETUP */
3827 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3829 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3830 return CM_ERROR_BADOP;
3833 struct smb_v2_referral {
3835 USHORT ReferralFlags;
3838 USHORT DfsPathOffset;
3839 USHORT DfsAlternativePathOffset;
3840 USHORT NetworkAddressOffset;
3843 /* TRANS2_GET_DFS_REFERRAL */
3845 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3847 /* This is a UNICODE only request (bit15 of Flags2) */
3848 /* The TID must be IPC$ */
3850 /* The documentation for the Flags response field is contradictory */
3852 /* Use Version 1 Referral Element Format */
3853 /* ServerType = 0; indicates the next server should be queried for the file */
3854 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3855 /* Node = UnicodeString of UNC path of the next share name */
3858 int maxReferralLevel = 0;
3859 clientchar_t requestFileName[1024] = _C("");
3860 clientchar_t referralPath[1024] = _C("");
3861 smb_tran2Packet_t *outp = 0;
3862 cm_user_t *userp = 0;
3863 cm_scache_t *scp = 0;
3864 cm_scache_t *dscp = 0;
3866 CPINFO CodePageInfo;
3867 int i, nbnLen, reqLen, refLen;
3872 maxReferralLevel = p->parmsp[0];
3874 GetCPInfo(CP_ACP, &CodePageInfo);
3875 cm_Utf16ToClientString(&p->parmsp[1], -1, requestFileName, lengthof(requestFileName));
3877 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%S]",
3878 maxReferralLevel, osi_LogSaveClientString(smb_logp, requestFileName));
3880 nbnLen = (int)cm_ClientStrLen(cm_NetbiosNameC);
3881 reqLen = (int)cm_ClientStrLen(requestFileName);
3883 if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
3884 !cm_ClientStrCmpNI(cm_NetbiosNameC, &requestFileName[1], nbnLen) &&
3885 requestFileName[nbnLen+1] == '\\')
3889 if (!cm_ClientStrCmpNI(_C("all"), &requestFileName[nbnLen+2], 3) ||
3890 !cm_ClientStrCmpNI(_C("*."), &requestFileName[nbnLen+2], 2)) {
3892 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
3895 userp = smb_GetTran2User(vcp, p);
3897 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3898 code = CM_ERROR_BADSMB;
3903 * We have a requested path. Check to see if it is something
3906 * But be careful because the name that we might be searching
3907 * for might be a known name with the final character stripped
3910 code = cm_NameI(cm_data.rootSCachep, &requestFileName[nbnLen+2],
3911 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
3912 userp, NULL, &req, &scp);
3916 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
3918 } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
3919 clientchar_t temp[1024];
3920 clientchar_t pathName[1024];
3921 clientchar_t *lastComponent;
3923 * we have a msdfs link somewhere in the path
3924 * we should figure out where in the path the link is.
3927 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%S]", requestFileName);
3929 cm_ClientStrCpy(temp, lengthof(temp), &requestFileName[nbnLen+2]);
3933 cm_ReleaseSCache(dscp);
3937 cm_ReleaseSCache(scp);
3940 smb_StripLastComponent(pathName, &lastComponent, temp);
3942 code = cm_NameI(cm_data.rootSCachep, pathName,
3943 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3944 userp, NULL, &req, &dscp);
3946 code = cm_NameI(dscp, ++lastComponent,
3948 userp, NULL, &req, &scp);
3949 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK)
3952 } while (code == CM_ERROR_PATH_NOT_COVERED);
3954 /* scp should now be the DfsLink we are looking for */
3956 /* figure out how much of the input path was used */
3957 reqLen = (int)(nbnLen+2 + cm_ClientStrLen(pathName) + 1 + cm_ClientStrLen(lastComponent));
3959 cm_FsStringToClientString(&scp->mountPointStringp[strlen("msdfs:")], -1,
3960 referralPath, lengthof(referralPath));
3961 refLen = (int)cm_ClientStrLen(referralPath);
3965 clientchar_t shareName[MAX_PATH + 1];
3966 clientchar_t *p, *q;
3967 /* we may have a sharename that is a volume reference */
3969 for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
3975 if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
3976 code = cm_NameI(cm_data.rootSCachep, _C(""),
3977 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
3978 userp, p, &req, &scp);
3983 cm_ClientStrCpy(referralPath, lengthof(referralPath),
3994 struct smb_v2_referral * v2ref;
3995 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (refLen + 8));
3997 sp = (USHORT *)outp->datap;
3999 sp[idx++] = reqLen; /* path consumed */
4000 sp[idx++] = 1; /* number of referrals */
4001 sp[idx++] = 0x03; /* flags */
4002 #ifdef DFS_VERSION_1
4003 sp[idx++] = 1; /* Version Number */
4004 sp[idx++] = refLen + 4; /* Referral Size */
4005 sp[idx++] = 1; /* Type = SMB Server */
4006 sp[idx++] = 0; /* Do not strip path consumed */
4007 for ( i=0;i<=refLen; i++ )
4008 sp[i+idx] = referralPath[i];
4009 #else /* DFS_VERSION_2 */
4010 sp[idx++] = 2; /* Version Number */
4011 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
4012 idx += (sizeof(struct smb_v2_referral) / 2);
4013 v2ref = (struct smb_v2_referral *) &sp[5];
4014 v2ref->ServerType = 1; /* SMB Server */
4015 v2ref->ReferralFlags = 0x03;
4016 v2ref->Proximity = 0; /* closest */
4017 v2ref->TimeToLive = 3600; /* seconds */
4018 v2ref->DfsPathOffset = idx * 2;
4019 v2ref->DfsAlternativePathOffset = idx * 2;
4020 v2ref->NetworkAddressOffset = 0;
4021 for ( i=0;i<=refLen; i++ )
4022 sp[i+idx] = referralPath[i];
4026 code = CM_ERROR_NOSUCHPATH;
4031 cm_ReleaseSCache(dscp);
4033 cm_ReleaseSCache(scp);
4035 cm_ReleaseUser(userp);
4037 smb_SendTran2Packet(vcp, outp, op);
4039 smb_SendTran2Error(vcp, p, op, code);
4041 smb_FreeTran2Packet(outp);
4044 #else /* DFS_SUPPORT */
4045 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
4046 return CM_ERROR_NOSUCHDEVICE;
4047 #endif /* DFS_SUPPORT */
4050 /* TRANS2_REPORT_DFS_INCONSISTENCY */
4052 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4054 /* This is a UNICODE only request (bit15 of Flags2) */
4056 /* There is nothing we can do about this operation. The client is going to
4057 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
4058 * Unfortunately, there is really nothing we can do about it other then log it
4059 * somewhere. Even then I don't think there is anything for us to do.
4060 * So let's return an error value.
4063 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
4064 return CM_ERROR_BADOP;
4068 smb_ApplyV3DirListPatches(cm_scache_t *dscp, smb_dirListPatch_t **dirPatchespp,
4069 clientchar_t * tidPathp, clientchar_t * relPathp,
4070 int infoLevel, cm_user_t *userp, cm_req_t *reqp)
4074 cm_scache_t *targetScp; /* target if scp is a symlink */
4077 unsigned short attr;
4078 unsigned long lattr;
4079 smb_dirListPatch_t *patchp;
4080 smb_dirListPatch_t *npatchp;
4082 afs_int32 mustFake = 0;
4083 clientchar_t path[AFSPATHMAX];
4085 code = cm_FindACLCache(dscp, userp, &rights);
4087 lock_ObtainWrite(&dscp->rw);
4088 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4089 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4091 cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4092 lock_ReleaseWrite(&dscp->rw);
4093 if (code == CM_ERROR_NOACCESS) {
4101 if (!mustFake) { /* Bulk Stat */
4103 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4105 memset(bsp, 0, sizeof(cm_bulkStat_t));
4107 for (patchp = *dirPatchespp, count=0;
4109 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4110 cm_scache_t *tscp = NULL;
4113 code = cm_GetSCache(&patchp->fid, &tscp, userp, reqp);
4115 if (lock_TryWrite(&tscp->rw)) {
4116 /* we have an entry that we can look at */
4117 #ifdef AFS_FREELANCE_CLIENT
4118 if (dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID && dscp->fid.volume == AFS_FAKE_ROOT_VOL_ID) {
4119 code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
4120 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4122 cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4124 lock_ReleaseWrite(&tscp->rw);
4125 cm_ReleaseSCache(tscp);
4128 #endif /* AFS_FREELANCE_CLIENT */
4129 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4130 /* we have a callback on it. Don't bother
4131 * fetching this stat entry, since we're happy
4132 * with the info we have.
4134 lock_ReleaseWrite(&tscp->rw);
4135 cm_ReleaseSCache(tscp);
4138 lock_ReleaseWrite(&tscp->rw);
4140 cm_ReleaseSCache(tscp);
4144 bsp->fids[i].Volume = patchp->fid.volume;
4145 bsp->fids[i].Vnode = patchp->fid.vnode;
4146 bsp->fids[i].Unique = patchp->fid.unique;
4148 if (bsp->counter == AFSCBMAX) {
4149 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4150 memset(bsp, 0, sizeof(cm_bulkStat_t));
4154 if (bsp->counter > 0)
4155 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4160 for( patchp = *dirPatchespp;
4162 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4163 cm_ClientStrPrintfN(path, lengthof(path),_C("%s\\%S"),
4164 relPathp ? relPathp : _C(""), patchp->dep->name);
4165 reqp->relPathp = path;
4166 reqp->tidPathp = tidPathp;
4168 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4169 reqp->relPathp = reqp->tidPathp = NULL;
4173 lock_ObtainWrite(&scp->rw);
4174 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4175 lock_ReleaseWrite(&scp->rw);
4177 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4178 errors in the client. */
4179 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4180 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4182 /* 1969-12-31 23:59:59 +00 */
4183 ft.dwHighDateTime = 0x19DB200;
4184 ft.dwLowDateTime = 0x5BB78980;
4186 /* copy to Creation Time */
4187 fa->creationTime = ft;
4188 fa->lastAccessTime = ft;
4189 fa->lastWriteTime = ft;
4190 fa->lastChangeTime = ft;
4192 switch (scp->fileType) {
4193 case CM_SCACHETYPE_DIRECTORY:
4194 case CM_SCACHETYPE_MOUNTPOINT:
4195 case CM_SCACHETYPE_INVALID:
4196 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4198 case CM_SCACHETYPE_SYMLINK:
4199 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4200 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4202 fa->extFileAttributes = SMB_ATTR_NORMAL;
4205 /* if we get here we either have a normal file
4206 * or we have a file for which we have never
4207 * received status info. In this case, we can
4208 * check the even/odd value of the entry's vnode.
4209 * odd means it is to be treated as a directory
4210 * and even means it is to be treated as a file.
4212 if (mustFake && (scp->fid.vnode & 0x1))
4213 fa->extFileAttributes = SMB_ATTR_DIRECT