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));
149 void OutputDebugHexDump(unsigned char * buffer, int len) {
152 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
154 OutputDebugF(_C("Hexdump length [%d]"),len);
156 for (i=0;i<len;i++) {
159 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
161 StringCchPrintfA(buf, lengthof(buf), "%5x", i);
162 memset(buf+5,' ',80);
167 j = j*3 + 7 + ((j>7)?1:0);
170 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
173 j = j + 56 + ((j>7)?1:0);
175 buf[j] = (k>32 && k<127)?k:'.';
178 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
182 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
184 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
185 SECURITY_STATUS status, istatus;
186 CredHandle creds = {0,0};
188 SecBufferDesc secOut;
196 OutputDebugF(_C("Negotiating Extended Security"));
198 status = AcquireCredentialsHandle( NULL,
199 SMB_EXT_SEC_PACKAGE_NAME,
208 if (status != SEC_E_OK) {
209 /* Really bad. We return an empty security blob */
210 OutputDebugF(_C("AcquireCredentialsHandle failed with %lX"), status);
215 secOut.pBuffers = &secTok;
216 secOut.ulVersion = SECBUFFER_VERSION;
218 secTok.BufferType = SECBUFFER_TOKEN;
220 secTok.pvBuffer = NULL;
222 ctx.dwLower = ctx.dwUpper = 0;
224 status = AcceptSecurityContext( &creds,
227 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
228 SECURITY_NETWORK_DREP,
235 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
236 OutputDebugF(_C("Completing token..."));
237 istatus = CompleteAuthToken(&ctx, &secOut);
238 if ( istatus != SEC_E_OK )
239 OutputDebugF(_C("Token completion failed: %x"), istatus);
242 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
243 if (secTok.pvBuffer) {
244 *secBlobLength = secTok.cbBuffer;
245 *secBlob = malloc( secTok.cbBuffer );
246 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
249 if ( status != SEC_E_OK )
250 OutputDebugF(_C("AcceptSecurityContext status != CONTINUE %lX"), status);
253 /* Discard partial security context */
254 DeleteSecurityContext(&ctx);
256 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
258 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
259 FreeCredentialsHandle(&creds);
265 struct smb_ext_context {
272 long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern,
273 char * secBlobIn, int secBlobInLength,
274 char ** secBlobOut, int * secBlobOutLength) {
275 SECURITY_STATUS status, istatus;
279 SecBufferDesc secBufIn;
281 SecBufferDesc secBufOut;
284 struct smb_ext_context * secCtx = NULL;
285 struct smb_ext_context * newSecCtx = NULL;
286 void * assembledBlob = NULL;
287 int assembledBlobLength = 0;
290 OutputDebugF(_C("In smb_AuthenticateUserExt"));
293 *secBlobOutLength = 0;
295 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
296 secCtx = vcp->secCtx;
297 lock_ObtainMutex(&vcp->mx);
298 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
300 lock_ReleaseMutex(&vcp->mx);
304 OutputDebugF(_C("Received incoming token:"));
305 OutputDebugHexDump(secBlobIn,secBlobInLength);
309 OutputDebugF(_C("Continuing with existing context."));
310 creds = secCtx->creds;
313 if (secCtx->partialToken) {
314 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
315 assembledBlob = malloc(assembledBlobLength);
316 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
317 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
320 status = AcquireCredentialsHandle( NULL,
321 SMB_EXT_SEC_PACKAGE_NAME,
330 if (status != SEC_E_OK) {
331 OutputDebugF(_C("Can't acquire Credentials handle [%lX]"), status);
332 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
340 secBufIn.cBuffers = 1;
341 secBufIn.pBuffers = &secTokIn;
342 secBufIn.ulVersion = SECBUFFER_VERSION;
344 secTokIn.BufferType = SECBUFFER_TOKEN;
346 secTokIn.cbBuffer = assembledBlobLength;
347 secTokIn.pvBuffer = assembledBlob;
349 secTokIn.cbBuffer = secBlobInLength;
350 secTokIn.pvBuffer = secBlobIn;
353 secBufOut.cBuffers = 1;
354 secBufOut.pBuffers = &secTokOut;
355 secBufOut.ulVersion = SECBUFFER_VERSION;
357 secTokOut.BufferType = SECBUFFER_TOKEN;
358 secTokOut.cbBuffer = 0;
359 secTokOut.pvBuffer = NULL;
361 status = AcceptSecurityContext( &creds,
362 ((secCtx)?&ctx:NULL),
364 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
365 SECURITY_NETWORK_DREP,
372 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
373 OutputDebugF(_C("Completing token..."));
374 istatus = CompleteAuthToken(&ctx, &secBufOut);
375 if ( istatus != SEC_E_OK )
376 OutputDebugF(_C("Token completion failed: %lX"), istatus);
379 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
380 OutputDebugF(_C("Continue needed"));
382 newSecCtx = malloc(sizeof(*newSecCtx));
384 newSecCtx->creds = creds;
385 newSecCtx->ctx = ctx;
386 newSecCtx->partialToken = NULL;
387 newSecCtx->partialTokenLen = 0;
389 lock_ObtainMutex( &vcp->mx );
390 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
391 vcp->secCtx = newSecCtx;
392 lock_ReleaseMutex( &vcp->mx );
394 code = CM_ERROR_GSSCONTINUE;
397 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
398 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
399 secTokOut.pvBuffer) {
400 OutputDebugF(_C("Need to send token back to client"));
402 *secBlobOutLength = secTokOut.cbBuffer;
403 *secBlobOut = malloc(secTokOut.cbBuffer);
404 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
406 OutputDebugF(_C("Outgoing token:"));
407 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
408 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
409 OutputDebugF(_C("Incomplete message"));
411 newSecCtx = malloc(sizeof(*newSecCtx));
413 newSecCtx->creds = creds;
414 newSecCtx->ctx = ctx;
415 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
416 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
417 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
419 lock_ObtainMutex( &vcp->mx );
420 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
421 vcp->secCtx = newSecCtx;
422 lock_ReleaseMutex( &vcp->mx );
424 code = CM_ERROR_GSSCONTINUE;
427 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
429 SecPkgContext_NamesW names;
431 OutputDebugF(_C("Authentication completed"));
432 OutputDebugF(_C("Returned flags : [%lX]"), flags);
434 if (!QueryContextAttributesW(&ctx, SECPKG_ATTR_NAMES, &names)) {
435 OutputDebugF(_C("Received name [%s]"), names.sUserName);
436 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, names.sUserName);
437 cm_ClientStrLwr(usern); /* in tandem with smb_GetNormalizedUsername */
438 FreeContextBuffer(names.sUserName);
440 /* Force the user to retry if the context is invalid */
441 OutputDebugF(_C("QueryContextAttributes Names failed [%x]"), GetLastError());
442 code = CM_ERROR_BADPASSWORD;
446 case SEC_E_INVALID_TOKEN:
447 OutputDebugF(_C("Returning bad password :: INVALID_TOKEN"));
449 case SEC_E_INVALID_HANDLE:
450 OutputDebugF(_C("Returning bad password :: INVALID_HANDLE"));
452 case SEC_E_LOGON_DENIED:
453 OutputDebugF(_C("Returning bad password :: LOGON_DENIED"));
455 case SEC_E_UNKNOWN_CREDENTIALS:
456 OutputDebugF(_C("Returning bad password :: UNKNOWN_CREDENTIALS"));
458 case SEC_E_NO_CREDENTIALS:
459 OutputDebugF(_C("Returning bad password :: NO_CREDENTIALS"));
461 case SEC_E_CONTEXT_EXPIRED:
462 OutputDebugF(_C("Returning bad password :: CONTEXT_EXPIRED"));
464 case SEC_E_INCOMPLETE_CREDENTIALS:
465 OutputDebugF(_C("Returning bad password :: INCOMPLETE_CREDENTIALS"));
467 case SEC_E_WRONG_PRINCIPAL:
468 OutputDebugF(_C("Returning bad password :: WRONG_PRINCIPAL"));
470 case SEC_E_TIME_SKEW:
471 OutputDebugF(_C("Returning bad password :: TIME_SKEW"));
474 OutputDebugF(_C("Returning bad password :: Status == %lX"), status);
476 code = CM_ERROR_BADPASSWORD;
480 if (secCtx->partialToken) free(secCtx->partialToken);
488 if (secTokOut.pvBuffer)
489 FreeContextBuffer(secTokOut.pvBuffer);
491 if (code != CM_ERROR_GSSCONTINUE) {
492 DeleteSecurityContext(&ctx);
493 FreeCredentialsHandle(&creds);
501 #define P_RESP_LEN 128
503 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
504 So put stuff in a struct. */
505 struct Lm20AuthBlob {
506 MSV1_0_LM20_LOGON lmlogon;
507 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
508 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
509 WCHAR accountNameW[P_LEN];
510 WCHAR primaryDomainW[P_LEN];
511 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
512 TOKEN_GROUPS tgroups;
513 TOKEN_SOURCE tsource;
516 long smb_AuthenticateUserLM(smb_vc_t *vcp, clientchar_t * accountName, clientchar_t * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
519 struct Lm20AuthBlob lmAuth;
520 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
521 QUOTA_LIMITS quotaLimits;
523 ULONG lmprofilepSize;
527 OutputDebugF(_C("In smb_AuthenticateUser for user [%s] domain [%s]"), accountName, primaryDomain);
528 OutputDebugF(_C("ciPwdLength is %d and csPwdLength is %d"), ciPwdLength, csPwdLength);
530 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
531 OutputDebugF(_C("ciPwdLength or csPwdLength is too long"));
532 return CM_ERROR_BADPASSWORD;
535 memset(&lmAuth,0,sizeof(lmAuth));
537 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
539 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
540 cm_ClientStringToUtf16(primaryDomain, -1, lmAuth.primaryDomainW, P_LEN);
541 lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
542 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
544 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
545 cm_ClientStringToUtf16(accountName, -1, lmAuth.accountNameW, P_LEN);
546 lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
547 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
549 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
550 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
551 size = MAX_COMPUTERNAME_LENGTH + 1;
552 GetComputerNameW(lmAuth.workstationW, &size);
553 lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
555 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
557 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
558 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
559 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
560 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
562 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
563 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
564 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
565 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
567 lmAuth.lmlogon.ParameterControl = 0;
569 lmAuth.tgroups.GroupCount = 0;
570 lmAuth.tgroups.Groups[0].Sid = NULL;
571 lmAuth.tgroups.Groups[0].Attributes = 0;
574 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
576 lmAuth.tsource.SourceIdentifier.HighPart = 0;
578 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
579 StringCchCopyA(lmAuth.tsource.SourceName, lengthof(lmAuth.tsource.SourceName),
580 "OpenAFS"); /* 8 char limit */
582 nts = LsaLogonUser( smb_lsaHandle,
597 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
598 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
601 OutputDebugF(_C("Return from LsaLogonUser is 0x%lX"), nts);
602 OutputDebugF(_C("Extended status is 0x%lX"), ntsEx);
604 if (nts == ERROR_SUCCESS) {
606 LsaFreeReturnBuffer(lmprofilep);
607 CloseHandle(lmToken);
611 if (nts == 0xC000015BL)
612 return CM_ERROR_BADLOGONTYPE;
613 else /* our catchall is a bad password though we could be more specific */
614 return CM_ERROR_BADPASSWORD;
618 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
619 long smb_GetNormalizedUsername(clientchar_t * usern, const clientchar_t * accountName, const clientchar_t * domainName)
621 clientchar_t * atsign;
622 const clientchar_t * domain;
624 /* check if we have sane input */
625 if ((cm_ClientStrLen(accountName) + cm_ClientStrLen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
628 /* we could get : [accountName][domainName]
634 atsign = cm_ClientStrChr(accountName, '@');
636 if (atsign) /* [user@domain][] -> [user@domain][domain] */
641 /* if for some reason the client doesn't know what domain to use,
642 it will either return an empty string or a '?' */
643 if (!domain[0] || domain[0] == '?')
644 /* Empty domains and empty usernames are usually sent from tokenless contexts.
645 This way such logins will get an empty username (easy to check). I don't know
646 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
647 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, accountName);
649 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
650 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, domain);
651 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, _C("\\"));
653 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
655 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
658 cm_ClientStrLwr(usern);
663 /* When using SMB auth, all SMB sessions have to pass through here
664 * first to authenticate the user.
666 * Caveat: If not using SMB auth, the protocol does not require
667 * sending a session setup packet, which means that we can't rely on a
668 * UID in subsequent packets. Though in practice we get one anyway.
670 /* SMB_COM_SESSION_SETUP_ANDX */
671 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
675 unsigned short newUid;
676 unsigned long caps = 0;
678 clientchar_t *s1 = _C(" ");
680 clientchar_t usern[SMB_MAX_USERNAME_LENGTH];
681 char *secBlobOut = NULL;
682 int secBlobOutLength = 0;
683 int maxBufferSize = 0;
687 /* Check for bad conns */
688 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
689 return CM_ERROR_REMOTECONN;
692 maxBufferSize = smb_GetSMBParm(inp, 2);
693 maxMpxCount = smb_GetSMBParm(inp, 3);
694 vcNumber = smb_GetSMBParm(inp, 4);
696 osi_Log3(smb_logp, "SESSION_SETUP_ANDX with MaxBufferSize=%d, MaxMpxCount=%d, VCNumber=%d",
697 maxBufferSize, maxMpxCount, vcNumber);
699 if (maxMpxCount > smb_maxMpxRequests) {
700 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_MPX_COUNT, maxMpxCount, smb_maxMpxRequests);
701 osi_Log2(smb_logp, "MaxMpxCount for client is too large (Client=%d, Server=%d)",
702 maxMpxCount, smb_maxMpxRequests);
705 if (maxBufferSize < SMB_PACKETSIZE) {
706 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_BUFFER_SIZE, maxBufferSize, SMB_PACKETSIZE);
707 osi_Log2(smb_logp, "MaxBufferSize for client is too small (Client=%d, Server=%d)",
708 maxBufferSize, SMB_PACKETSIZE);
712 osi_Log0(smb_logp, "Resetting all VCs");
713 smb_MarkAllVCsDead(vcp);
716 if (vcp->flags & SMB_VCFLAG_USENT) {
717 if (smb_authType == SMB_AUTH_EXTENDED) {
718 /* extended authentication */
722 OutputDebugF(_C("NT Session Setup: Extended"));
724 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
725 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
728 secBlobInLength = smb_GetSMBParm(inp, 7);
729 secBlobIn = smb_GetSMBData(inp, NULL);
731 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
733 if (code == CM_ERROR_GSSCONTINUE) {
736 smb_SetSMBParm(outp, 2, 0);
737 smb_SetSMBParm(outp, 3, secBlobOutLength);
739 tp = smb_GetSMBData(outp, NULL);
740 if (secBlobOutLength) {
741 memcpy(tp, secBlobOut, secBlobOutLength);
743 tp += secBlobOutLength;
744 cb_data += secBlobOutLength;
746 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
747 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
748 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
750 smb_SetSMBDataLength(outp, cb_data);
753 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
755 unsigned ciPwdLength, csPwdLength;
757 clientchar_t *accountName;
758 clientchar_t *primaryDomain;
761 if (smb_authType == SMB_AUTH_NTLM)
762 OutputDebugF(_C("NT Session Setup: NTLM"));
764 OutputDebugF(_C("NT Session Setup: None"));
766 /* TODO: parse for extended auth as well */
767 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
768 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
770 tp = smb_GetSMBData(inp, &datalen);
772 OutputDebugF(_C("Session packet data size [%d]"),datalen);
779 accountName = smb_ParseString(inp, tp, &tp, 0);
780 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
782 OutputDebugF(_C("Account Name: %s"),accountName);
783 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
784 OutputDebugF(_C("Case Sensitive Password: %s"),
785 csPwd && csPwd[0] ? _C("yes") : _C("no"));
786 OutputDebugF(_C("Case Insensitive Password: %s"),
787 ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
789 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
790 /* shouldn't happen */
791 code = CM_ERROR_BADSMB;
792 goto after_read_packet;
795 /* capabilities are only valid for first session packet */
796 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
797 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
800 if (smb_authType == SMB_AUTH_NTLM) {
801 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
803 OutputDebugF(_C("LM authentication failed [%d]"), code);
805 OutputDebugF(_C("LM authentication succeeded"));
809 unsigned ciPwdLength;
811 clientchar_t *accountName;
812 clientchar_t *primaryDomain;
814 switch ( smb_authType ) {
815 case SMB_AUTH_EXTENDED:
816 OutputDebugF(_C("V3 Session Setup: Extended"));
819 OutputDebugF(_C("V3 Session Setup: NTLM"));
822 OutputDebugF(_C("V3 Session Setup: None"));
824 ciPwdLength = smb_GetSMBParm(inp, 7);
825 tp = smb_GetSMBData(inp, NULL);
829 accountName = smb_ParseString(inp, tp, &tp, 0);
830 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
832 OutputDebugF(_C("Account Name: %s"),accountName);
833 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
834 OutputDebugF(_C("Case Insensitive Password: %s"), ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
836 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
837 /* shouldn't happen */
838 code = CM_ERROR_BADSMB;
839 goto after_read_packet;
842 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
845 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
846 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
848 OutputDebugF(_C("LM authentication failed [%d]"), code);
850 OutputDebugF(_C("LM authentication succeeded"));
855 /* note down that we received a session setup X and set the capabilities flag */
856 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
857 lock_ObtainMutex(&vcp->mx);
858 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
859 /* for the moment we can only deal with NTSTATUS */
860 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
861 vcp->flags |= SMB_VCFLAG_STATUS32;
865 if ((caps & NTNEGOTIATE_CAPABILITY_UNICODE) && smb_UseUnicode) {
866 vcp->flags |= SMB_VCFLAG_USEUNICODE;
869 lock_ReleaseMutex(&vcp->mx);
872 /* code would be non-zero if there was an authentication failure.
873 Ideally we would like to invalidate the uid for this session or break
874 early to avoid accidently stealing someone else's tokens. */
880 OutputDebugF(_C("Received username=[%s]"), usern);
882 /* On Windows 2000, this function appears to be called more often than
883 it is expected to be called. This resulted in multiple smb_user_t
884 records existing all for the same user session which results in all
885 of the users tokens disappearing.
887 To avoid this problem, we look for an existing smb_user_t record
888 based on the users name, and use that one if we find it.
891 uidp = smb_FindUserByNameThisSession(vcp, usern);
892 if (uidp) { /* already there, so don't create a new one */
894 newUid = uidp->userID;
895 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
896 vcp->lana,vcp->lsn,newUid);
897 smb_ReleaseUID(uidp);
902 /* do a global search for the username/machine name pair */
903 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
904 lock_ObtainMutex(&unp->mx);
905 if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
906 /* clear the afslogon flag so that the tickets can now
907 * be freed when the refCount returns to zero.
909 unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
911 lock_ReleaseMutex(&unp->mx);
913 /* Create a new UID and cm_user_t structure */
916 userp = cm_NewUser();
917 cm_HoldUserVCRef(userp);
918 lock_ObtainMutex(&vcp->mx);
919 if (!vcp->uidCounter)
920 vcp->uidCounter++; /* handle unlikely wraparounds */
921 newUid = (cm_ClientStrLen(usern)==0)?0:vcp->uidCounter++;
922 lock_ReleaseMutex(&vcp->mx);
924 /* Create a new smb_user_t structure and connect them up */
925 lock_ObtainMutex(&unp->mx);
927 lock_ReleaseMutex(&unp->mx);
929 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
931 lock_ObtainMutex(&uidp->mx);
933 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
934 lock_ReleaseMutex(&uidp->mx);
935 smb_ReleaseUID(uidp);
939 /* Return UID to the client */
940 ((smb_t *)outp)->uid = newUid;
941 /* Also to the next chained message */
942 ((smb_t *)inp)->uid = newUid;
944 osi_Log3(smb_logp, "SMB3 session setup name %S creating ID %d%S",
945 osi_LogSaveClientString(smb_logp, usern), newUid,
946 osi_LogSaveClientString(smb_logp, s1));
948 smb_SetSMBParm(outp, 2, 0);
950 if (vcp->flags & SMB_VCFLAG_USENT) {
951 if (smb_authType == SMB_AUTH_EXTENDED) {
954 smb_SetSMBParm(outp, 3, secBlobOutLength);
956 tp = smb_GetSMBData(outp, NULL);
957 if (secBlobOutLength) {
958 memcpy(tp, secBlobOut, secBlobOutLength);
960 tp += secBlobOutLength;
961 cb_data += secBlobOutLength;
964 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
965 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
966 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
968 smb_SetSMBDataLength(outp, cb_data);
970 smb_SetSMBDataLength(outp, 0);
973 if (smb_authType == SMB_AUTH_EXTENDED) {
976 tp = smb_GetSMBData(outp, NULL);
978 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
979 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
980 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
982 smb_SetSMBDataLength(outp, cb_data);
984 smb_SetSMBDataLength(outp, 0);
991 /* SMB_COM_LOGOFF_ANDX */
992 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
996 /* find the tree and free it */
997 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
999 smb_username_t * unp;
1001 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %S", uidp->userID,
1002 osi_LogSaveClientString(smb_logp, (uidp->unp) ? uidp->unp->name: _C(" ")));
1004 lock_ObtainMutex(&uidp->mx);
1005 uidp->flags |= SMB_USERFLAG_DELETE;
1007 * it doesn't get deleted right away
1008 * because the vcp points to it
1011 lock_ReleaseMutex(&uidp->mx);
1014 /* we can't do this. we get logoff messages prior to a session
1015 * disconnect even though it doesn't mean the user is logging out.
1016 * we need to create a new pioctl and EventLogoff handler to set
1017 * SMB_USERNAMEFLAG_LOGOFF.
1019 if (unp && smb_LogoffTokenTransfer) {
1020 lock_ObtainMutex(&unp->mx);
1021 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
1022 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
1023 lock_ReleaseMutex(&unp->mx);
1027 smb_ReleaseUID(uidp);
1030 osi_Log0(smb_logp, "SMB3 user logoffX");
1032 smb_SetSMBDataLength(outp, 0);
1036 #define SMB_SUPPORT_SEARCH_BITS 0x0001
1037 #define SMB_SHARE_IS_IN_DFS 0x0002
1039 /* SMB_COM_TREE_CONNECT_ANDX */
1040 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1043 smb_user_t *uidp = NULL;
1044 unsigned short newTid;
1045 clientchar_t shareName[AFSPATHMAX];
1046 clientchar_t *sharePath;
1049 clientchar_t *slashp;
1050 clientchar_t *pathp;
1051 clientchar_t *passwordp;
1052 clientchar_t *servicep;
1053 cm_user_t *userp = NULL;
1056 osi_Log0(smb_logp, "SMB3 receive tree connect");
1058 /* parse input parameters */
1059 tp = smb_GetSMBData(inp, NULL);
1060 passwordp = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1061 pathp = smb_ParseString(inp, tp, &tp, SMB_STRF_ANSIPATH);
1062 servicep = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1064 slashp = cm_ClientStrRChr(pathp, '\\');
1066 return CM_ERROR_BADSMB;
1068 cm_ClientStrCpy(shareName, lengthof(shareName), slashp+1);
1070 osi_Log3(smb_logp, "Tree connect pathp[%S] shareName[%S] service[%S]",
1071 osi_LogSaveClientString(smb_logp, pathp),
1072 osi_LogSaveClientString(smb_logp, shareName),
1073 osi_LogSaveClientString(smb_logp, servicep));
1075 if (cm_ClientStrCmp(servicep, _C("IPC")) == 0 ||
1076 cm_ClientStrCmp(shareName, _C("IPC$")) == 0) {
1078 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1081 return CM_ERROR_NOIPC;
1085 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1087 userp = smb_GetUserFromUID(uidp);
1089 lock_ObtainMutex(&vcp->mx);
1090 newTid = vcp->tidCounter++;
1091 lock_ReleaseMutex(&vcp->mx);
1093 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1096 if (!cm_ClientStrCmp(shareName, _C("*.")))
1097 cm_ClientStrCpy(shareName, lengthof(shareName), _C("all"));
1098 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1101 smb_ReleaseUID(uidp);
1102 smb_ReleaseTID(tidp, FALSE);
1103 return CM_ERROR_BADSHARENAME;
1106 if (vcp->flags & SMB_VCFLAG_USENT)
1108 int policy = smb_FindShareCSCPolicy(shareName);
1111 DWORD dwAdvertiseDFS = 0, dwSize = sizeof(DWORD);
1113 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1114 0, KEY_QUERY_VALUE, &parmKey);
1115 if (code == ERROR_SUCCESS) {
1116 code = RegQueryValueEx(parmKey, "AdvertiseDFS", NULL, NULL,
1117 (BYTE *)&dwAdvertiseDFS, &dwSize);
1118 if (code != ERROR_SUCCESS)
1120 RegCloseKey (parmKey);
1122 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1123 (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
1127 smb_SetSMBParm(outp, 2, 0);
1131 smb_ReleaseUID(uidp);
1133 lock_ObtainMutex(&tidp->mx);
1134 tidp->userp = userp;
1135 tidp->pathname = sharePath;
1137 tidp->flags |= SMB_TIDFLAG_IPC;
1138 lock_ReleaseMutex(&tidp->mx);
1139 smb_ReleaseTID(tidp, FALSE);
1141 ((smb_t *)outp)->tid = newTid;
1142 ((smb_t *)inp)->tid = newTid;
1143 tp = smb_GetSMBData(outp, NULL);
1147 tp = smb_UnparseString(outp, tp, _C("A:"), &cb_data, SMB_STRF_FORCEASCII);
1148 tp = smb_UnparseString(outp, tp, _C("AFS"), &cb_data, 0);
1149 smb_SetSMBDataLength(outp, cb_data);
1153 tp = smb_UnparseString(outp, tp, _C("IPC"), &cb_data, SMB_STRF_FORCEASCII);
1154 smb_SetSMBDataLength(outp, cb_data);
1157 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1161 /* must be called with global tran lock held */
1162 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1164 smb_tran2Packet_t *tp;
1167 smbp = (smb_t *) inp->data;
1168 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1169 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1175 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1176 int totalParms, int totalData)
1178 smb_tran2Packet_t *tp;
1181 smbp = (smb_t *) inp->data;
1182 tp = malloc(sizeof(*tp));
1183 memset(tp, 0, sizeof(*tp));
1186 tp->curData = tp->curParms = 0;
1187 tp->totalData = totalData;
1188 tp->totalParms = totalParms;
1189 tp->tid = smbp->tid;
1190 tp->mid = smbp->mid;
1191 tp->uid = smbp->uid;
1192 tp->pid = smbp->pid;
1193 tp->res[0] = smbp->res[0];
1194 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1195 if (totalParms != 0)
1196 tp->parmsp = malloc(totalParms);
1198 tp->datap = malloc(totalData);
1199 if (smbp->com == 0x25 || smbp->com == 0x26)
1202 tp->opcode = smb_GetSMBParm(inp, 14);
1205 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1207 if (WANTS_UNICODE(inp) && (vcp->flags & SMB_VCFLAG_USEUNICODE))
1208 tp->flags |= SMB_TRAN2PFLAG_USEUNICODE;
1213 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1214 smb_tran2Packet_t *inp, smb_packet_t *outp,
1215 int totalParms, int totalData)
1217 smb_tran2Packet_t *tp;
1218 unsigned short parmOffset;
1219 unsigned short dataOffset;
1220 unsigned short dataAlign;
1222 tp = malloc(sizeof(*tp));
1223 memset(tp, 0, sizeof(*tp));
1226 tp->curData = tp->curParms = 0;
1227 tp->totalData = totalData;
1228 tp->totalParms = totalParms;
1229 tp->oldTotalParms = totalParms;
1234 tp->res[0] = inp->res[0];
1235 tp->opcode = inp->opcode;
1239 * We calculate where the parameters and data will start.
1240 * This calculation must parallel the calculation in
1241 * smb_SendTran2Packet.
1244 parmOffset = 10*2 + 35;
1245 parmOffset++; /* round to even */
1246 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1248 dataOffset = parmOffset + totalParms;
1249 dataAlign = dataOffset & 2; /* quad-align */
1250 dataOffset += dataAlign;
1251 tp->datap = outp->data + dataOffset;
1256 /* free a tran2 packet */
1257 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1260 smb_ReleaseVC(t2p->vcp);
1263 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1273 while (t2p->stringsp) {
1277 t2p->stringsp = ns->nextp;
1283 clientchar_t *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
1284 char ** chainpp, int flags)
1289 if (!(p->flags & SMB_TRAN2PFLAG_USEUNICODE))
1290 flags |= SMB_STRF_FORCEASCII;
1293 cb = p->totalParms - (inp - (char *)p->parmsp);
1294 if (inp < (char *) p->parmsp ||
1295 inp >= ((char *) p->parmsp) + p->totalParms) {
1296 #ifdef DEBUG_UNICODE
1302 return smb_ParseStringBuf((unsigned char *) p->parmsp, &p->stringsp,
1303 inp, &cb, chainpp, flags);
1306 /* called with a VC, an input packet to respond to, and an error code.
1307 * sends an error response.
1309 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1310 smb_packet_t *tp, long code)
1313 unsigned short errCode;
1314 unsigned char errClass;
1315 unsigned long NTStatus;
1317 if (vcp->flags & SMB_VCFLAG_STATUS32)
1318 smb_MapNTError(code, &NTStatus);
1320 smb_MapCoreError(code, vcp, &errCode, &errClass);
1322 smb_FormatResponsePacket(vcp, NULL, tp);
1323 smbp = (smb_t *) tp;
1325 /* We can handle long names */
1326 if (vcp->flags & SMB_VCFLAG_USENT)
1327 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1329 /* now copy important fields from the tran 2 packet */
1330 smbp->com = t2p->com;
1331 smbp->tid = t2p->tid;
1332 smbp->mid = t2p->mid;
1333 smbp->pid = t2p->pid;
1334 smbp->uid = t2p->uid;
1335 smbp->res[0] = t2p->res[0];
1336 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1337 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1338 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1339 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1340 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1341 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1344 smbp->rcls = errClass;
1345 smbp->errLow = (unsigned char) (errCode & 0xff);
1346 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1350 smb_SendPacket(vcp, tp);
1353 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1356 unsigned short parmOffset;
1357 unsigned short dataOffset;
1358 unsigned short totalLength;
1359 unsigned short dataAlign;
1362 smb_FormatResponsePacket(vcp, NULL, tp);
1363 smbp = (smb_t *) tp;
1365 /* We can handle long names */
1366 if (vcp->flags & SMB_VCFLAG_USENT)
1367 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1369 /* now copy important fields from the tran 2 packet */
1370 smbp->com = t2p->com;
1371 smbp->tid = t2p->tid;
1372 smbp->mid = t2p->mid;
1373 smbp->pid = t2p->pid;
1374 smbp->uid = t2p->uid;
1375 smbp->res[0] = t2p->res[0];
1377 if (t2p->error_code) {
1378 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1379 unsigned long NTStatus;
1381 smb_MapNTError(t2p->error_code, &NTStatus);
1383 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1384 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1385 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1386 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1387 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1390 unsigned short errCode;
1391 unsigned char errClass;
1393 smb_MapCoreError(t2p->error_code, vcp, &errCode, &errClass);
1395 smbp->rcls = errClass;
1396 smbp->errLow = (unsigned char) (errCode & 0xff);
1397 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1401 totalLength = 1 + t2p->totalData + t2p->totalParms;
1403 /* now add the core parameters (tran2 info) to the packet */
1404 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1405 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1406 smb_SetSMBParm(tp, 2, 0); /* reserved */
1407 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1408 parmOffset = 10*2 + 35; /* parm offset in packet */
1409 parmOffset++; /* round to even */
1410 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1411 * hdr, bcc and wct */
1412 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1413 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1414 dataOffset = parmOffset + t2p->oldTotalParms;
1415 dataAlign = dataOffset & 2; /* quad-align */
1416 dataOffset += dataAlign;
1417 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1418 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1419 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1422 datap = smb_GetSMBData(tp, NULL);
1423 *datap++ = 0; /* we rounded to even */
1425 totalLength += dataAlign;
1426 smb_SetSMBDataLength(tp, totalLength);
1428 /* next, send the datagram */
1429 smb_SendPacket(vcp, tp);
1432 /* TRANS_SET_NMPIPE_STATE */
1433 long smb_nmpipeSetState(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1437 int pipeState = 0x0100; /* default */
1438 smb_tran2Packet_t *outp = NULL;
1441 if (p->totalParms > 0)
1442 pipeState = p->parmsp[0];
1444 osi_Log2(smb_logp, "smb_nmpipeSetState for fd[%d] with state[0x%x]", fd, pipeState);
1446 fidp = smb_FindFID(vcp, fd, 0);
1448 return CM_ERROR_BADFD;
1450 lock_ObtainMutex(&fidp->mx);
1451 if (pipeState & 0x8000)
1452 fidp->flags |= SMB_FID_BLOCKINGPIPE;
1453 if (pipeState & 0x0100)
1454 fidp->flags |= SMB_FID_MESSAGEMODEPIPE;
1455 lock_ReleaseMutex(&fidp->mx);
1457 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 0);
1458 smb_SendTran2Packet(vcp, outp, op);
1459 smb_FreeTran2Packet(outp);
1461 smb_ReleaseFID(fidp);
1466 long smb_nmpipeTransact(smb_vc_t * vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1476 osi_Log3(smb_logp, "smb_nmpipeTransact for fd[%d] %d bytes in, %d max bytes out",
1477 fd, p->totalData, p->maxReturnData);
1479 fidp = smb_FindFID(vcp, fd, 0);
1481 return CM_ERROR_BADFD;
1483 lock_ObtainMutex(&fidp->mx);
1484 if (fidp->flags & SMB_FID_RPC) {
1487 lock_ReleaseMutex(&fidp->mx);
1490 code = smb_RPCNmpipeTransact(fidp, vcp, p, op);
1491 smb_ReleaseFID(fidp);
1493 /* We only deal with RPC pipes */
1494 code = CM_ERROR_BADFD;
1501 /* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
1502 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1504 smb_tran2Packet_t *asp;
1517 /* We sometimes see 0 word count. What to do? */
1518 if (*inp->wctp == 0) {
1519 osi_Log0(smb_logp, "Transaction2 word count = 0");
1520 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1522 smb_SetSMBDataLength(outp, 0);
1523 smb_SendPacket(vcp, outp);
1527 totalParms = smb_GetSMBParm(inp, 0);
1528 totalData = smb_GetSMBParm(inp, 1);
1530 firstPacket = (inp->inCom == 0x25);
1532 /* find the packet we're reassembling */
1533 lock_ObtainWrite(&smb_globalLock);
1534 asp = smb_FindTran2Packet(vcp, inp);
1536 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1538 lock_ReleaseWrite(&smb_globalLock);
1540 /* now merge in this latest packet; start by looking up offsets */
1542 parmDisp = dataDisp = 0;
1543 parmOffset = smb_GetSMBParm(inp, 10);
1544 dataOffset = smb_GetSMBParm(inp, 12);
1545 parmCount = smb_GetSMBParm(inp, 9);
1546 dataCount = smb_GetSMBParm(inp, 11);
1547 asp->setupCount = smb_GetSMBParmByte(inp, 13);
1548 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1549 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1551 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1552 totalData, dataCount, asp->maxReturnData);
1554 if (asp->setupCount == 2) {
1555 clientchar_t * pname;
1557 asp->pipeCommand = smb_GetSMBParm(inp, 14);
1558 asp->pipeParam = smb_GetSMBParm(inp, 15);
1559 pname = smb_ParseString(inp, inp->wctp + 35, NULL, 0);
1561 asp->name = cm_ClientStrDup(pname);
1564 osi_Log2(smb_logp, " Named Pipe command id [%d] with name [%S]",
1565 asp->pipeCommand, osi_LogSaveClientString(smb_logp, asp->name));
1569 parmDisp = smb_GetSMBParm(inp, 4);
1570 parmOffset = smb_GetSMBParm(inp, 3);
1571 dataDisp = smb_GetSMBParm(inp, 7);
1572 dataOffset = smb_GetSMBParm(inp, 6);
1573 parmCount = smb_GetSMBParm(inp, 2);
1574 dataCount = smb_GetSMBParm(inp, 5);
1576 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1577 parmCount, dataCount);
1580 /* now copy the parms and data */
1581 if ( asp->totalParms > 0 && parmCount != 0 )
1583 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1585 if ( asp->totalData > 0 && dataCount != 0 ) {
1586 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1589 /* account for new bytes */
1590 asp->curData += dataCount;
1591 asp->curParms += parmCount;
1593 /* finally, if we're done, remove the packet from the queue and dispatch it */
1594 if (((asp->totalParms > 0 && asp->curParms > 0)
1595 || asp->setupCount == 2) &&
1596 asp->totalData <= asp->curData &&
1597 asp->totalParms <= asp->curParms) {
1599 /* we've received it all */
1600 lock_ObtainWrite(&smb_globalLock);
1601 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1602 lock_ReleaseWrite(&smb_globalLock);
1604 switch(asp->setupCount) {
1607 rapOp = asp->parmsp[0];
1609 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES &&
1610 smb_rapDispatchTable[rapOp].procp) {
1612 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",
1613 myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1615 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1617 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",
1618 code,vcp,vcp->lana,vcp->lsn);
1621 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]",
1622 rapOp, vcp, vcp->lana, vcp->lsn);
1624 code = CM_ERROR_BADOP;
1630 { /* Named pipe operation */
1631 osi_Log2(smb_logp, "Named Pipe: %s with name [%S]",
1632 myCrt_NmpipeDispatch(asp->pipeCommand),
1633 osi_LogSaveClientString(smb_logp, asp->name));
1635 code = CM_ERROR_BADOP;
1637 switch (asp->pipeCommand) {
1638 case SMB_TRANS_SET_NMPIPE_STATE:
1639 code = smb_nmpipeSetState(vcp, asp, outp);
1642 case SMB_TRANS_RAW_READ_NMPIPE:
1645 case SMB_TRANS_QUERY_NMPIPE_STATE:
1648 case SMB_TRANS_QUERY_NMPIPE_INFO:
1651 case SMB_TRANS_PEEK_NMPIPE:
1654 case SMB_TRANS_TRANSACT_NMPIPE:
1655 code = smb_nmpipeTransact(vcp, asp, outp);
1658 case SMB_TRANS_RAW_WRITE_NMPIPE:
1661 case SMB_TRANS_READ_NMPIPE:
1664 case SMB_TRANS_WRITE_NMPIPE:
1667 case SMB_TRANS_WAIT_NMPIPE:
1670 case SMB_TRANS_CALL_NMPIPE:
1677 code = CM_ERROR_BADOP;
1680 /* if an error is returned, we're supposed to send an error packet,
1681 * otherwise the dispatched function already did the data sending.
1682 * We give dispatched proc the responsibility since it knows how much
1683 * space to allocate.
1686 smb_SendTran2Error(vcp, asp, outp, code);
1689 /* free the input tran 2 packet */
1690 smb_FreeTran2Packet(asp);
1692 else if (firstPacket) {
1693 /* the first packet in a multi-packet request, we need to send an
1694 * ack to get more data.
1696 smb_SetSMBDataLength(outp, 0);
1697 smb_SendPacket(vcp, outp);
1703 /* ANSI versions. */
1705 #pragma pack(push, 1)
1707 typedef struct smb_rap_share_info_0 {
1708 BYTE shi0_netname[13];
1709 } smb_rap_share_info_0_t;
1711 typedef struct smb_rap_share_info_1 {
1712 BYTE shi1_netname[13];
1715 DWORD shi1_remark; /* char *shi1_remark; data offset */
1716 } smb_rap_share_info_1_t;
1718 typedef struct smb_rap_share_info_2 {
1719 BYTE shi2_netname[13];
1722 DWORD shi2_remark; /* char *shi2_remark; data offset */
1723 WORD shi2_permissions;
1725 WORD shi2_current_uses;
1726 DWORD shi2_path; /* char *shi2_path; data offset */
1727 WORD shi2_passwd[9];
1729 } smb_rap_share_info_2_t;
1731 #define SMB_RAP_MAX_SHARES 512
1733 typedef struct smb_rap_share_list {
1736 smb_rap_share_info_0_t * shares;
1737 } smb_rap_share_list_t;
1741 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1742 smb_rap_share_list_t * sp;
1744 if (dep->name[0] == '.' && (!dep->name[1] || (dep->name[1] == '.' && !dep->name[2])))
1745 return 0; /* skip over '.' and '..' */
1747 sp = (smb_rap_share_list_t *) vrockp;
1749 strncpy(sp->shares[sp->cShare].shi0_netname, dep->name, 12);
1750 sp->shares[sp->cShare].shi0_netname[12] = 0;
1754 if (sp->cShare >= sp->maxShares)
1755 return CM_ERROR_STOPNOW;
1760 /* RAP NetShareEnumRequest */
1761 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1763 smb_tran2Packet_t *outp;
1764 unsigned short * tp;
1768 int outParmsTotal; /* total parameter bytes */
1769 int outDataTotal; /* total data bytes */
1772 DWORD allSubmount = 0;
1774 DWORD nRegShares = 0;
1775 DWORD nSharesRet = 0;
1777 HKEY hkSubmount = NULL;
1778 smb_rap_share_info_1_t * shares;
1781 clientchar_t thisShare[AFSPATHMAX];
1785 smb_rap_share_list_t rootShares;
1790 tp = p->parmsp + 1; /* skip over function number (always 0) */
1793 clientchar_t * cdescp;
1795 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1796 if (cm_ClientStrCmp(cdescp, _C("WrLeh")))
1797 return CM_ERROR_INVAL;
1798 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1799 if (cm_ClientStrCmp(cdescp, _C("B13BWz")))
1800 return CM_ERROR_INVAL;
1806 if (infoLevel != 1) {
1807 return CM_ERROR_INVAL;
1810 /* We are supposed to use the same ASCII data structure even if
1811 Unicode is negotiated, which ultimately means that the share
1812 names that we return must be at most 13 characters in length,
1813 including the NULL terminator.
1815 The RAP specification states that shares with names longer than
1816 12 characters should not be included in the enumeration.
1817 However, since we support prefix cell references and since many
1818 cell names are going to exceed 12 characters, we lie and send
1819 the first 12 characters.
1822 /* first figure out how many shares there are */
1823 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1824 KEY_QUERY_VALUE, &hkParam);
1825 if (rv == ERROR_SUCCESS) {
1826 len = sizeof(allSubmount);
1827 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1828 (BYTE *) &allSubmount, &len);
1829 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1832 RegCloseKey (hkParam);
1835 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1836 0, KEY_QUERY_VALUE, &hkSubmount);
1837 if (rv == ERROR_SUCCESS) {
1838 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1839 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1840 if (rv != ERROR_SUCCESS)
1846 /* fetch the root shares */
1847 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1848 rootShares.cShare = 0;
1849 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1853 userp = smb_GetTran2User(vcp,p);
1855 thyper.HighPart = 0;
1858 cm_HoldSCache(cm_data.rootSCachep);
1859 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1860 cm_ReleaseSCache(cm_data.rootSCachep);
1862 cm_ReleaseUser(userp);
1864 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1866 #define REMARK_LEN 1
1867 outParmsTotal = 8; /* 4 dwords */
1868 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1869 if(outDataTotal > bufsize) {
1870 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1871 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1874 nSharesRet = nShares;
1877 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1879 /* now for the submounts */
1880 shares = (smb_rap_share_info_1_t *) outp->datap;
1881 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1883 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1886 StringCchCopyA(shares[cshare].shi1_netname,
1887 lengthof(shares[cshare].shi1_netname), "all" );
1888 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1889 /* type and pad are zero already */
1895 for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
1896 len = sizeof(thisShare);
1897 rv = RegEnumValueW(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
1898 if (rv == ERROR_SUCCESS &&
1899 cm_ClientStrLen(thisShare) &&
1900 (!allSubmount || cm_ClientStrCmpI(thisShare,_C("all")))) {
1901 cm_ClientStringToUtf8(thisShare, -1, shares[cshare].shi1_netname,
1902 lengthof( shares[cshare].shi1_netname ));
1903 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1904 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1909 nShares--; /* uncount key */
1912 RegCloseKey(hkSubmount);
1915 nonrootShares = cshare;
1917 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1918 /* in case there are collisions with submounts, submounts have
1920 for (j=0; j < nonrootShares; j++)
1921 if (!cm_stricmp_utf8(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1924 if (j < nonrootShares) {
1925 nShares--; /* uncount */
1929 StringCchCopyA(shares[cshare].shi1_netname, lengthof(shares[cshare].shi1_netname),
1930 rootShares.shares[i].shi0_netname);
1931 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1936 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1937 outp->parmsp[1] = 0;
1938 outp->parmsp[2] = cshare;
1939 outp->parmsp[3] = nShares;
1941 outp->totalData = (int)(cstrp - outp->datap);
1942 outp->totalParms = outParmsTotal;
1944 smb_SendTran2Packet(vcp, outp, op);
1945 smb_FreeTran2Packet(outp);
1947 free(rootShares.shares);
1952 /* RAP NetShareGetInfo */
1953 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1955 smb_tran2Packet_t *outp;
1956 unsigned short * tp;
1957 clientchar_t * shareName;
1958 BOOL shareFound = FALSE;
1959 unsigned short infoLevel;
1960 unsigned short bufsize;
1969 cm_scache_t *scp = NULL;
1975 tp = p->parmsp + 1; /* skip over function number (always 1) */
1978 clientchar_t * cdescp;
1980 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1981 if (cm_ClientStrCmp(cdescp, _C("zWrLh")))
1983 return CM_ERROR_INVAL;
1985 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1986 if (cm_ClientStrCmp(cdescp, _C("B13")) &&
1987 cm_ClientStrCmp(cdescp, _C("B13BWz")) &&
1988 cm_ClientStrCmp(cdescp, _C("B13BWzWWWzB9B")))
1990 return CM_ERROR_INVAL;
1992 shareName = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2000 totalData = sizeof(smb_rap_share_info_0_t);
2001 else if(infoLevel == SMB_INFO_STANDARD)
2002 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
2003 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
2004 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
2006 return CM_ERROR_INVAL;
2008 if(!cm_ClientStrCmpI(shareName, _C("all")) || !cm_ClientStrCmp(shareName,_C("*."))) {
2009 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
2010 KEY_QUERY_VALUE, &hkParam);
2011 if (rv == ERROR_SUCCESS) {
2012 len = sizeof(allSubmount);
2013 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
2014 (BYTE *) &allSubmount, &len);
2015 if (rv != ERROR_SUCCESS || allSubmount != 0) {
2018 RegCloseKey (hkParam);
2025 userp = smb_GetTran2User(vcp, p);
2027 osi_Log1(smb_logp,"ReceiveRAPNetShareGetInfo unable to resolve user [%d]", p->uid);
2028 return CM_ERROR_BADSMB;
2030 code = cm_NameI(cm_data.rootSCachep, shareName,
2031 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
2032 userp, NULL, &req, &scp);
2034 cm_ReleaseSCache(scp);
2037 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
2038 KEY_QUERY_VALUE, &hkSubmount);
2039 if (rv == ERROR_SUCCESS) {
2040 rv = RegQueryValueExW(hkSubmount, shareName, NULL, NULL, NULL, NULL);
2041 if (rv == ERROR_SUCCESS) {
2044 RegCloseKey(hkSubmount);
2050 return CM_ERROR_BADSHARENAME;
2052 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
2053 memset(outp->datap, 0, totalData);
2055 outp->parmsp[0] = 0;
2056 outp->parmsp[1] = 0;
2057 outp->parmsp[2] = totalData;
2059 if (infoLevel == 0) {
2060 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
2061 cm_ClientStringToUtf8(shareName, -1, info->shi0_netname,
2062 lengthof(info->shi0_netname));
2063 } else if(infoLevel == SMB_INFO_STANDARD) {
2064 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
2065 cm_ClientStringToUtf8(shareName, -1, info->shi1_netname, lengthof(info->shi1_netname));
2066 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
2067 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
2068 /* type and pad are already zero */
2069 } else { /* infoLevel==2 */
2070 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
2071 cm_ClientStringToUtf8(shareName, -1, info->shi2_netname, lengthof(info->shi2_netname));
2072 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
2073 info->shi2_permissions = ACCESS_ALL;
2074 info->shi2_max_uses = (unsigned short) -1;
2075 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
2078 outp->totalData = totalData;
2079 outp->totalParms = totalParam;
2081 smb_SendTran2Packet(vcp, outp, op);
2082 smb_FreeTran2Packet(outp);
2087 #pragma pack(push, 1)
2089 typedef struct smb_rap_wksta_info_10 {
2090 DWORD wki10_computername; /*char *wki10_computername;*/
2091 DWORD wki10_username; /* char *wki10_username; */
2092 DWORD wki10_langroup; /* char *wki10_langroup;*/
2093 BYTE wki10_ver_major;
2094 BYTE wki10_ver_minor;
2095 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
2096 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
2097 } smb_rap_wksta_info_10_t;
2101 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2103 smb_tran2Packet_t *outp;
2107 unsigned short * tp;
2110 smb_rap_wksta_info_10_t * info;
2114 tp = p->parmsp + 1; /* Skip over function number */
2117 clientchar_t * cdescp;
2119 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2120 SMB_STRF_FORCEASCII);
2121 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2122 return CM_ERROR_INVAL;
2124 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2125 SMB_STRF_FORCEASCII);
2126 if (cm_ClientStrCmp(cdescp, _C("zzzBBzz")))
2127 return CM_ERROR_INVAL;
2133 if (infoLevel != 10) {
2134 return CM_ERROR_INVAL;
2140 totalData = sizeof(*info) + /* info */
2141 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
2142 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
2143 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
2144 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
2145 1; /* wki10_oth_domains (null)*/
2147 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2149 memset(outp->parmsp,0,totalParams);
2150 memset(outp->datap,0,totalData);
2152 info = (smb_rap_wksta_info_10_t *) outp->datap;
2153 cstrp = (char *) (info + 1);
2155 info->wki10_computername = (DWORD) (cstrp - outp->datap);
2156 StringCbCopyA(cstrp, totalData, smb_localNamep);
2157 cstrp += strlen(cstrp) + 1;
2159 info->wki10_username = (DWORD) (cstrp - outp->datap);
2160 uidp = smb_FindUID(vcp, p->uid, 0);
2162 lock_ObtainMutex(&uidp->mx);
2163 if(uidp->unp && uidp->unp->name)
2164 cm_ClientStringToUtf8(uidp->unp->name, -1,
2165 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2166 lock_ReleaseMutex(&uidp->mx);
2167 smb_ReleaseUID(uidp);
2169 cstrp += strlen(cstrp) + 1;
2171 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
2172 StringCbCopyA(cstrp, totalData - (cstrp - outp->datap)*sizeof(char), "WORKGROUP");
2173 cstrp += strlen(cstrp) + 1;
2175 /* TODO: Not sure what values these should take, but these work */
2176 info->wki10_ver_major = 5;
2177 info->wki10_ver_minor = 1;
2179 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
2180 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
2181 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2182 cstrp += strlen(cstrp) + 1;
2184 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
2185 cstrp ++; /* no other domains */
2187 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
2188 outp->parmsp[2] = outp->totalData;
2189 outp->totalParms = totalParams;
2191 smb_SendTran2Packet(vcp,outp,op);
2192 smb_FreeTran2Packet(outp);
2197 #pragma pack(push, 1)
2199 typedef struct smb_rap_server_info_0 {
2201 } smb_rap_server_info_0_t;
2203 typedef struct smb_rap_server_info_1 {
2205 BYTE sv1_version_major;
2206 BYTE sv1_version_minor;
2208 DWORD sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
2209 } smb_rap_server_info_1_t;
2213 char smb_ServerComment[] = "OpenAFS Client";
2214 int smb_ServerCommentLen = sizeof(smb_ServerComment);
2216 #define SMB_SV_TYPE_SERVER 0x00000002L
2217 #define SMB_SV_TYPE_NT 0x00001000L
2218 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
2220 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2222 smb_tran2Packet_t *outp;
2226 unsigned short * tp;
2229 smb_rap_server_info_0_t * info0;
2230 smb_rap_server_info_1_t * info1;
2233 tp = p->parmsp + 1; /* Skip over function number */
2236 clientchar_t * cdescp;
2238 cdescp = smb_ParseStringT2Parm(p, (unsigned char *) tp, (char **) &tp,
2239 SMB_STRF_FORCEASCII);
2240 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2241 return CM_ERROR_INVAL;
2242 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2243 SMB_STRF_FORCEASCII);
2244 if (cm_ClientStrCmp(cdescp, _C("B16")) ||
2245 cm_ClientStrCmp(cdescp, _C("B16BBDz")))
2246 return CM_ERROR_INVAL;
2252 if (infoLevel != 0 && infoLevel != 1) {
2253 return CM_ERROR_INVAL;
2259 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
2260 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
2262 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2264 memset(outp->parmsp,0,totalParams);
2265 memset(outp->datap,0,totalData);
2267 if (infoLevel == 0) {
2268 info0 = (smb_rap_server_info_0_t *) outp->datap;
2269 cstrp = (char *) (info0 + 1);
2270 StringCchCopyA(info0->sv0_name, lengthof(info0->sv0_name), "AFS");
2271 } else { /* infoLevel == SMB_INFO_STANDARD */
2272 info1 = (smb_rap_server_info_1_t *) outp->datap;
2273 cstrp = (char *) (info1 + 1);
2274 StringCchCopyA(info1->sv1_name, lengthof(info1->sv1_name), "AFS");
2277 SMB_SV_TYPE_SERVER |
2279 SMB_SV_TYPE_SERVER_NT;
2281 info1->sv1_version_major = 5;
2282 info1->sv1_version_minor = 1;
2283 info1->sv1_comment_or_master_browser = (DWORD) (cstrp - outp->datap);
2285 StringCbCopyA(cstrp, smb_ServerCommentLen, smb_ServerComment);
2287 cstrp += smb_ServerCommentLen / sizeof(char);
2290 totalData = (DWORD)(cstrp - outp->datap);
2291 outp->totalData = min(bufsize,totalData); /* actual data size */
2292 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
2293 outp->parmsp[2] = totalData;
2294 outp->totalParms = totalParams;
2296 smb_SendTran2Packet(vcp,outp,op);
2297 smb_FreeTran2Packet(outp);
2302 /* SMB_COM_TRANSACTION2 and SMB_COM_TRANSACTION2_SECONDARY */
2303 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2305 smb_tran2Packet_t *asp;
2316 DWORD oldTime, newTime;
2318 /* We sometimes see 0 word count. What to do? */
2319 if (*inp->wctp == 0) {
2320 osi_Log0(smb_logp, "Transaction2 word count = 0");
2321 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
2323 smb_SetSMBDataLength(outp, 0);
2324 smb_SendPacket(vcp, outp);
2328 totalParms = smb_GetSMBParm(inp, 0);
2329 totalData = smb_GetSMBParm(inp, 1);
2331 firstPacket = (inp->inCom == 0x32);
2333 /* find the packet we're reassembling */
2334 lock_ObtainWrite(&smb_globalLock);
2335 asp = smb_FindTran2Packet(vcp, inp);
2337 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
2339 lock_ReleaseWrite(&smb_globalLock);
2341 /* now merge in this latest packet; start by looking up offsets */
2343 parmDisp = dataDisp = 0;
2344 parmOffset = smb_GetSMBParm(inp, 10);
2345 dataOffset = smb_GetSMBParm(inp, 12);
2346 parmCount = smb_GetSMBParm(inp, 9);
2347 dataCount = smb_GetSMBParm(inp, 11);
2348 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2349 asp->maxReturnData = smb_GetSMBParm(inp, 3);
2351 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2352 totalData, dataCount, asp->maxReturnData);
2355 parmDisp = smb_GetSMBParm(inp, 4);
2356 parmOffset = smb_GetSMBParm(inp, 3);
2357 dataDisp = smb_GetSMBParm(inp, 7);
2358 dataOffset = smb_GetSMBParm(inp, 6);
2359 parmCount = smb_GetSMBParm(inp, 2);
2360 dataCount = smb_GetSMBParm(inp, 5);
2362 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2363 parmCount, dataCount);
2366 /* now copy the parms and data */
2367 if ( asp->totalParms > 0 && parmCount != 0 )
2369 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2371 if ( asp->totalData > 0 && dataCount != 0 ) {
2372 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2375 /* account for new bytes */
2376 asp->curData += dataCount;
2377 asp->curParms += parmCount;
2379 /* finally, if we're done, remove the packet from the queue and dispatch it */
2380 if (asp->totalParms > 0 &&
2381 asp->curParms > 0 &&
2382 asp->totalData <= asp->curData &&
2383 asp->totalParms <= asp->curParms) {
2384 /* we've received it all */
2385 lock_ObtainWrite(&smb_globalLock);
2386 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2387 lock_ReleaseWrite(&smb_globalLock);
2389 oldTime = GetTickCount();
2391 /* now dispatch it */
2392 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2393 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2394 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2397 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2398 code = CM_ERROR_BADOP;
2401 /* if an error is returned, we're supposed to send an error packet,
2402 * otherwise the dispatched function already did the data sending.
2403 * We give dispatched proc the responsibility since it knows how much
2404 * space to allocate.
2407 smb_SendTran2Error(vcp, asp, outp, code);
2410 newTime = GetTickCount();
2411 if (newTime - oldTime > 45000) {
2414 clientchar_t *treepath = NULL; /* do not free */
2415 clientchar_t *pathname = NULL;
2416 cm_fid_t afid = {0,0,0,0,0};
2418 uidp = smb_FindUID(vcp, asp->uid, 0);
2419 smb_LookupTIDPath(vcp, asp->tid, &treepath);
2420 fidp = smb_FindFID(vcp, inp->fid, 0);
2423 lock_ObtainMutex(&fidp->mx);
2424 if (fidp->NTopen_pathp)
2425 pathname = fidp->NTopen_pathp;
2427 afid = fidp->scp->fid;
2429 if (inp->stringsp->wdata)
2430 pathname = inp->stringsp->wdata;
2433 afsi_log("Request %s duration %d ms user 0x%x \"%S\" pid 0x%x mid 0x%x tid 0x%x \"%S\" path? \"%S\" afid (%d.%d.%d.%d)",
2434 myCrt_2Dispatch(asp->opcode), newTime - oldTime,
2435 asp->uid, uidp ? uidp->unp->name : NULL,
2436 asp->pid, asp->mid, asp->tid,
2439 afid.cell, afid.volume, afid.vnode, afid.unique);
2442 lock_ReleaseMutex(&fidp->mx);
2445 smb_ReleaseUID(uidp);
2447 smb_ReleaseFID(fidp);
2450 /* free the input tran 2 packet */
2451 smb_FreeTran2Packet(asp);
2453 else if (firstPacket) {
2454 /* the first packet in a multi-packet request, we need to send an
2455 * ack to get more data.
2457 smb_SetSMBDataLength(outp, 0);
2458 smb_SendPacket(vcp, outp);
2465 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2467 clientchar_t *pathp;
2468 smb_tran2Packet_t *outp;
2473 cm_scache_t *dscp; /* dir we're dealing with */
2474 cm_scache_t *scp; /* file we're creating */
2476 int initialModeBits;
2479 clientchar_t *lastNamep;
2486 int parmSlot; /* which parm we're dealing with */
2487 long returnEALength;
2488 clientchar_t *tidPathp;
2491 BOOL is_rpc = FALSE;
2497 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2498 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2500 openFun = p->parmsp[6]; /* open function */
2501 excl = ((openFun & 3) == 0);
2502 trunc = ((openFun & 3) == 2); /* truncate it */
2503 openMode = (p->parmsp[1] & 0x7);
2504 openAction = 0; /* tracks what we did */
2506 attributes = p->parmsp[3];
2507 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2509 /* compute initial mode bits based on read-only flag in attributes */
2510 initialModeBits = 0666;
2511 if (attributes & SMB_ATTR_READONLY)
2512 initialModeBits &= ~0222;
2514 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
2517 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2519 spacep = cm_GetSpace();
2520 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2522 /* The 'is_rpc' assignment to TRUE is intentional */
2524 (cm_ClientStrCmpI(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
2525 ((cm_ClientStrCmpI(lastNamep, _C("\\srvsvc")) == 0 ||
2526 cm_ClientStrCmpI(lastNamep, _C("\\wkssvc")) == 0 ||
2527 cm_ClientStrCmpI(lastNamep, _C("\\ipc$")) == 0) && (is_rpc = TRUE)))) {
2529 unsigned short file_type = 0;
2530 unsigned short device_state = 0;
2532 /* special case magic file name for receiving IOCTL requests
2533 * (since IOCTL calls themselves aren't getting through).
2535 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2538 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
2539 osi_Log2(smb_logp, "smb_ReceiveTran2Open Creating RPC Fid [%d] code [%d]",
2542 smb_SetupIoctlFid(fidp, spacep);
2543 osi_Log1(smb_logp, "smb_ReceiveTran2Open Creating IOCTL Fid [%d]", fidp->fid);
2546 /* copy out remainder of the parms */
2548 outp->parmsp[parmSlot++] = fidp->fid;
2550 outp->parmsp[parmSlot++] = 0; /* attrs */
2551 outp->parmsp[parmSlot++] = 0; /* mod time */
2552 outp->parmsp[parmSlot++] = 0;
2553 outp->parmsp[parmSlot++] = 0; /* len */
2554 outp->parmsp[parmSlot++] = 0x7fff;
2555 outp->parmsp[parmSlot++] = openMode;
2556 outp->parmsp[parmSlot++] = file_type;
2557 outp->parmsp[parmSlot++] = device_state;
2559 /* and the final "always present" stuff */
2560 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2561 /* next write out the "unique" ID */
2562 outp->parmsp[parmSlot++] = 0x1234;
2563 outp->parmsp[parmSlot++] = 0x5678;
2564 outp->parmsp[parmSlot++] = 0;
2565 if (returnEALength) {
2566 outp->parmsp[parmSlot++] = 0;
2567 outp->parmsp[parmSlot++] = 0;
2570 outp->totalData = 0;
2571 outp->totalParms = parmSlot * 2;
2573 smb_SendTran2Packet(vcp, outp, op);
2575 smb_FreeTran2Packet(outp);
2577 /* and clean up fid reference */
2578 smb_ReleaseFID(fidp);
2582 if (!cm_IsValidClientString(pathp)) {
2584 clientchar_t * hexp;
2586 hexp = cm_GetRawCharsAlloc(pathp, -1);
2587 osi_Log1(smb_logp, "Tran2Open rejecting invalid name. [%S]",
2588 osi_LogSaveClientString(smb_logp, hexp));
2592 osi_Log0(smb_logp, "Tran2Open rejecting invalid name");
2594 smb_FreeTran2Packet(outp);
2595 return CM_ERROR_BADNTFILENAME;
2598 #ifdef DEBUG_VERBOSE
2600 char *hexp, *asciip;
2601 asciip = (lastNamep ? lastNamep : pathp);
2602 hexp = osi_HexifyString( asciip );
2603 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2608 userp = smb_GetTran2User(vcp, p);
2609 /* In the off chance that userp is NULL, we log and abandon */
2611 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2612 smb_FreeTran2Packet(outp);
2613 return CM_ERROR_BADSMB;
2616 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2617 if (code == CM_ERROR_TIDIPC) {
2618 /* Attempt to use a TID allocated for IPC. The client
2619 * is probably looking for DCE RPC end points which we
2620 * don't support OR it could be looking to make a DFS
2623 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2625 cm_ReleaseUser(userp);
2626 smb_FreeTran2Packet(outp);
2627 return CM_ERROR_NOSUCHPATH;
2632 code = cm_NameI(cm_data.rootSCachep, pathp,
2633 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2634 userp, tidPathp, &req, &scp);
2636 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2637 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2638 userp, tidPathp, &req, &dscp);
2639 cm_FreeSpace(spacep);
2642 cm_ReleaseUser(userp);
2643 smb_FreeTran2Packet(outp);
2648 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2649 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2650 (clientchar_t*) spacep->data);
2651 cm_ReleaseSCache(dscp);
2652 cm_ReleaseUser(userp);
2653 smb_FreeTran2Packet(outp);
2654 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2655 return CM_ERROR_PATH_NOT_COVERED;
2657 return CM_ERROR_NOSUCHPATH;
2659 #endif /* DFS_SUPPORT */
2661 /* otherwise, scp points to the parent directory. Do a lookup,
2662 * and truncate the file if we find it, otherwise we create the
2669 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2671 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2672 cm_ReleaseSCache(dscp);
2673 cm_ReleaseUser(userp);
2674 smb_FreeTran2Packet(outp);
2679 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2680 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2681 cm_ReleaseSCache(scp);
2682 cm_ReleaseUser(userp);
2683 smb_FreeTran2Packet(outp);
2684 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2685 return CM_ERROR_PATH_NOT_COVERED;
2687 return CM_ERROR_NOSUCHPATH;
2689 #endif /* DFS_SUPPORT */
2691 /* macintosh is expensive to program for it */
2692 cm_FreeSpace(spacep);
2695 /* if we get here, if code is 0, the file exists and is represented by
2696 * scp. Otherwise, we have to create it.
2699 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2702 cm_ReleaseSCache(dscp);
2703 cm_ReleaseSCache(scp);
2704 cm_ReleaseUser(userp);
2705 smb_FreeTran2Packet(outp);
2710 /* oops, file shouldn't be there */
2712 cm_ReleaseSCache(dscp);
2713 cm_ReleaseSCache(scp);
2714 cm_ReleaseUser(userp);
2715 smb_FreeTran2Packet(outp);
2716 return CM_ERROR_EXISTS;
2720 setAttr.mask = CM_ATTRMASK_LENGTH;
2721 setAttr.length.LowPart = 0;
2722 setAttr.length.HighPart = 0;
2723 code = cm_SetAttr(scp, &setAttr, userp, &req);
2724 openAction = 3; /* truncated existing file */
2727 openAction = 1; /* found existing file */
2729 else if (!(openFun & 0x10)) {
2730 /* don't create if not found */
2732 cm_ReleaseSCache(dscp);
2733 osi_assertx(scp == NULL, "null cm_scache_t");
2734 cm_ReleaseUser(userp);
2735 smb_FreeTran2Packet(outp);
2736 return CM_ERROR_NOSUCHFILE;
2739 osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2740 openAction = 2; /* created file */
2741 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2742 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2743 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2747 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2748 smb_NotifyChange(FILE_ACTION_ADDED,
2749 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2750 dscp, lastNamep, NULL, TRUE);
2751 } else if (!excl && code == CM_ERROR_EXISTS) {
2752 /* not an exclusive create, and someone else tried
2753 * creating it already, then we open it anyway. We
2754 * don't bother retrying after this, since if this next
2755 * fails, that means that the file was deleted after we
2756 * started this call.
2758 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2762 setAttr.mask = CM_ATTRMASK_LENGTH;
2763 setAttr.length.LowPart = 0;
2764 setAttr.length.HighPart = 0;
2765 code = cm_SetAttr(scp, &setAttr, userp,
2768 } /* lookup succeeded */
2772 /* we don't need this any longer */
2774 cm_ReleaseSCache(dscp);
2777 /* something went wrong creating or truncating the file */
2779 cm_ReleaseSCache(scp);
2780 cm_ReleaseUser(userp);
2781 smb_FreeTran2Packet(outp);
2785 /* make sure we're about to open a file */
2786 if (scp->fileType != CM_SCACHETYPE_FILE) {
2788 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2789 cm_scache_t * targetScp = 0;
2790 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2792 /* we have a more accurate file to use (the
2793 * target of the symbolic link). Otherwise,
2794 * we'll just use the symlink anyway.
2796 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2798 cm_ReleaseSCache(scp);
2802 if (scp->fileType != CM_SCACHETYPE_FILE) {
2803 cm_ReleaseSCache(scp);
2804 cm_ReleaseUser(userp);
2805 smb_FreeTran2Packet(outp);
2806 return CM_ERROR_ISDIR;
2810 /* now all we have to do is open the file itself */
2811 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2812 osi_assertx(fidp, "null smb_fid_t");
2815 lock_ObtainMutex(&fidp->mx);
2816 /* save a pointer to the vnode */
2817 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2819 lock_ObtainWrite(&scp->rw);
2820 scp->flags |= CM_SCACHEFLAG_SMB_FID;
2821 lock_ReleaseWrite(&scp->rw);
2824 fidp->userp = userp;
2826 /* compute open mode */
2828 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
2829 if (openMode == 1 || openMode == 2)
2830 fidp->flags |= SMB_FID_OPENWRITE;
2832 /* remember that the file was newly created */
2834 fidp->flags |= SMB_FID_CREATED;
2836 lock_ReleaseMutex(&fidp->mx);
2838 smb_ReleaseFID(fidp);
2840 cm_Open(scp, 0, userp);
2842 /* copy out remainder of the parms */
2844 outp->parmsp[parmSlot++] = fidp->fid;
2845 lock_ObtainRead(&scp->rw);
2847 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2848 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2849 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2850 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2851 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2852 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2853 outp->parmsp[parmSlot++] = openMode;
2854 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2855 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2857 /* and the final "always present" stuff */
2858 outp->parmsp[parmSlot++] = openAction;
2859 /* next write out the "unique" ID */
2860 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2861 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2862 outp->parmsp[parmSlot++] = 0;
2863 if (returnEALength) {
2864 outp->parmsp[parmSlot++] = 0;
2865 outp->parmsp[parmSlot++] = 0;
2867 lock_ReleaseRead(&scp->rw);
2868 outp->totalData = 0; /* total # of data bytes */
2869 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2871 smb_SendTran2Packet(vcp, outp, op);
2873 smb_FreeTran2Packet(outp);
2875 cm_ReleaseUser(userp);
2876 /* leave scp held since we put it in fidp->scp */
2880 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2883 unsigned short infolevel;
2885 infolevel = p->parmsp[0];
2887 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2889 return CM_ERROR_BAD_LEVEL;
2892 /* TRANS2_QUERY_FS_INFORMATION */
2893 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2895 smb_tran2Packet_t *outp;
2896 smb_tran2QFSInfo_t qi;
2900 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2902 switch (p->parmsp[0]) {
2903 case SMB_INFO_ALLOCATION:
2905 responseSize = sizeof(qi.u.allocInfo);
2907 qi.u.allocInfo.FSID = 0;
2908 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2909 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2910 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2911 qi.u.allocInfo.bytesPerSector = 1024;
2914 case SMB_INFO_VOLUME:
2916 qi.u.volumeInfo.vsn = 1234; /* Volume serial number */
2917 qi.u.volumeInfo.vnCount = 3; /* Number of characters in label (AFS\0)*/
2919 /* we're supposed to pad it out with zeroes to the end */
2920 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2921 smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
2923 responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
2926 case SMB_QUERY_FS_VOLUME_INFO:
2927 /* FS volume info */
2928 responseSize = sizeof(qi.u.FSvolumeInfo);
2931 FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
2932 memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
2935 qi.u.FSvolumeInfo.vsn = 1234;
2936 qi.u.FSvolumeInfo.vnCount = 6; /* This is always in Unicode */
2937 memset(&qi.u.FSvolumeInfo.label, 0, sizeof(qi.u.FSvolumeInfo.label));
2938 memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
2941 case SMB_QUERY_FS_SIZE_INFO:
2943 responseSize = sizeof(qi.u.FSsizeInfo);
2945 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2946 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2947 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2948 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2949 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2950 qi.u.FSsizeInfo.bytesPerSector = 1024;
2953 case SMB_QUERY_FS_DEVICE_INFO:
2954 /* FS device info */
2955 responseSize = sizeof(qi.u.FSdeviceInfo);
2957 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2958 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2961 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2962 /* FS attribute info */
2964 /* attributes, defined in WINNT.H:
2965 * FILE_CASE_SENSITIVE_SEARCH 0x1
2966 * FILE_CASE_PRESERVED_NAMES 0x2
2967 * FILE_UNICODE_ON_DISK 0x4
2968 * FILE_VOLUME_QUOTAS 0x10
2969 * <no name defined> 0x4000
2970 * If bit 0x4000 is not set, Windows 95 thinks
2971 * we can't handle long (non-8.3) names,
2972 * despite our protestations to the contrary.
2974 qi.u.FSattributeInfo.attributes = 0x4003;
2975 /* The maxCompLength is supposed to be in bytes */
2977 qi.u.FSattributeInfo.attributes |= 0x04;
2979 qi.u.FSattributeInfo.maxCompLength = 255;
2980 smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
2981 qi.u.FSattributeInfo.FSnameLength = sz;
2984 sizeof(qi.u.FSattributeInfo.attributes) +
2985 sizeof(qi.u.FSattributeInfo.maxCompLength) +
2986 sizeof(qi.u.FSattributeInfo.FSnameLength) +
2991 case SMB_INFO_UNIX: /* CIFS Unix Info */
2992 case SMB_INFO_MACOS: /* Mac FS Info */
2994 return CM_ERROR_BADOP;
2997 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2999 /* copy out return data, and set corresponding sizes */
3000 outp->totalParms = 0;
3001 outp->totalData = responseSize;
3002 memcpy(outp->datap, &qi, responseSize);
3004 /* send and free the packets */
3005 smb_SendTran2Packet(vcp, outp, op);
3006 smb_FreeTran2Packet(outp);
3011 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3013 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
3014 return CM_ERROR_BADOP;
3017 struct smb_ShortNameRock {
3018 clientchar_t *maskp;
3020 clientchar_t *shortName;
3021 size_t shortNameLen;
3024 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
3027 struct smb_ShortNameRock *rockp;
3028 normchar_t normName[MAX_PATH];
3029 clientchar_t *shortNameEnd;
3033 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t)) == 0) {
3034 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
3035 osi_LogSaveString(smb_logp, dep->name));
3039 /* compare both names and vnodes, though probably just comparing vnodes
3040 * would be safe enough.
3042 if (cm_NormStrCmpI(normName, rockp->maskp) != 0)
3044 if (ntohl(dep->fid.vnode) != rockp->vnode)
3047 /* This is the entry */
3048 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
3049 rockp->shortNameLen = shortNameEnd - rockp->shortName;
3051 return CM_ERROR_STOPNOW;
3054 long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
3055 clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
3057 struct smb_ShortNameRock rock;
3058 clientchar_t *lastNamep;
3061 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
3065 spacep = cm_GetSpace();
3066 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
3068 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3069 caseFold, userp, tidPathp,
3071 cm_FreeSpace(spacep);
3076 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3077 cm_ReleaseSCache(dscp);
3078 cm_ReleaseUser(userp);
3082 return CM_ERROR_PATH_NOT_COVERED;
3084 #endif /* DFS_SUPPORT */
3086 if (!lastNamep) lastNamep = pathp;
3089 thyper.HighPart = 0;
3090 rock.shortName = shortName;
3092 rock.maskp = lastNamep;
3093 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
3095 cm_ReleaseSCache(dscp);
3098 return CM_ERROR_NOSUCHFILE;
3099 if (code == CM_ERROR_STOPNOW) {
3100 *shortNameLenp = rock.shortNameLen;
3106 /* TRANS2_QUERY_PATH_INFORMATION */
3107 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3109 smb_tran2Packet_t *outp;
3112 unsigned short infoLevel;
3113 smb_tran2QPathInfo_t qpi;
3115 unsigned short attributes;
3116 unsigned long extAttributes;
3117 clientchar_t shortName[13];
3121 cm_scache_t *scp, *dscp;
3122 int scp_rw_held = 0;
3125 clientchar_t *pathp;
3126 clientchar_t *tidPathp;
3127 clientchar_t *lastComp;
3132 infoLevel = p->parmsp[0];
3133 if (infoLevel == SMB_INFO_IS_NAME_VALID)
3135 else if (infoLevel == SMB_INFO_STANDARD)
3136 responseSize = sizeof(qpi.u.QPstandardInfo);
3137 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
3138 responseSize = sizeof(qpi.u.QPeaSizeInfo);
3139 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3140 responseSize = sizeof(qpi.u.QPfileBasicInfo);
3141 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3142 responseSize = sizeof(qpi.u.QPfileStandardInfo);
3143 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3144 responseSize = sizeof(qpi.u.QPfileEaInfo);
3145 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3146 responseSize = sizeof(qpi.u.QPfileNameInfo);
3147 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
3148 responseSize = sizeof(qpi.u.QPfileAllInfo);
3149 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
3150 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
3152 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3153 p->opcode, infoLevel);
3154 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3158 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3159 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %S", infoLevel,
3160 osi_LogSaveClientString(smb_logp, pathp));
3162 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3164 if (infoLevel > 0x100)
3165 outp->totalParms = 2;
3167 outp->totalParms = 0;
3168 outp->totalData = responseSize;
3170 /* now, if we're at infoLevel 6, we're only being asked to check
3171 * the syntax, so we just OK things now. In particular, we're *not*
3172 * being asked to verify anything about the state of any parent dirs.
3174 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
3175 smb_SendTran2Packet(vcp, outp, opx);
3176 smb_FreeTran2Packet(outp);
3180 userp = smb_GetTran2User(vcp, p);
3182 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
3183 smb_FreeTran2Packet(outp);
3184 return CM_ERROR_BADSMB;
3187 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3189 cm_ReleaseUser(userp);
3190 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
3191 smb_FreeTran2Packet(outp);
3196 * XXX Strange hack XXX
3198 * As of Patch 7 (13 January 98), we are having the following problem:
3199 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3200 * requests to look up "desktop.ini" in all the subdirectories.
3201 * This can cause zillions of timeouts looking up non-existent cells
3202 * and volumes, especially in the top-level directory.
3204 * We have not found any way to avoid this or work around it except
3205 * to explicitly ignore the requests for mount points that haven't
3206 * yet been evaluated and for directories that haven't yet been
3209 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3210 spacep = cm_GetSpace();
3211 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3212 #ifndef SPECIAL_FOLDERS
3213 /* Make sure that lastComp is not NULL */
3215 if (cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
3216 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3220 userp, tidPathp, &req, &dscp);
3223 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3224 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3226 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3227 code = CM_ERROR_PATH_NOT_COVERED;
3229 code = CM_ERROR_NOSUCHPATH;
3231 #endif /* DFS_SUPPORT */
3232 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3233 code = CM_ERROR_NOSUCHFILE;
3234 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3235 cm_buf_t *bp = buf_Find(dscp, &hzero);
3241 code = CM_ERROR_NOSUCHFILE;
3243 cm_ReleaseSCache(dscp);
3245 cm_FreeSpace(spacep);
3246 cm_ReleaseUser(userp);
3247 smb_SendTran2Error(vcp, p, opx, code);
3248 smb_FreeTran2Packet(outp);
3254 #endif /* SPECIAL_FOLDERS */
3256 cm_FreeSpace(spacep);
3259 /* now do namei and stat, and copy out the info */
3260 code = cm_NameI(cm_data.rootSCachep, pathp,
3261 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3264 cm_ReleaseUser(userp);
3265 smb_SendTran2Error(vcp, p, opx, code);
3266 smb_FreeTran2Packet(outp);
3271 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3272 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3273 cm_ReleaseSCache(scp);
3274 cm_ReleaseUser(userp);
3275 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3276 code = CM_ERROR_PATH_NOT_COVERED;
3278 code = CM_ERROR_NOSUCHPATH;
3279 smb_SendTran2Error(vcp, p, opx, code);
3280 smb_FreeTran2Packet(outp);
3283 #endif /* DFS_SUPPORT */
3285 lock_ObtainWrite(&scp->rw);
3287 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3288 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3292 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3294 lock_ConvertWToR(&scp->rw);
3299 /* now we have the status in the cache entry, and everything is locked.
3300 * Marshall the output data.
3302 /* for info level 108, figure out short name */
3303 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3304 code = cm_GetShortName(pathp, userp, &req,
3305 tidPathp, scp->fid.vnode, shortName,
3311 smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
3312 qpi.u.QPfileAltNameInfo.fileNameLength = len;
3316 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3317 smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3318 qpi.u.QPfileNameInfo.fileNameLength = len;
3322 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3323 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3324 qpi.u.QPstandardInfo.creationDateTime = dosTime;
3325 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3326 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3327 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3328 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3329 attributes = smb_Attributes(scp);
3330 qpi.u.QPstandardInfo.attributes = attributes;
3331 qpi.u.QPstandardInfo.eaSize = 0;
3333 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3334 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3335 qpi.u.QPfileBasicInfo.creationTime = ft;
3336 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3337 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3338 qpi.u.QPfileBasicInfo.changeTime = ft;
3339 extAttributes = smb_ExtAttributes(scp);
3340 qpi.u.QPfileBasicInfo.attributes = extAttributes;
3341 qpi.u.QPfileBasicInfo.reserved = 0;
3343 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3346 lock_ReleaseRead(&scp->rw);
3348 fidp = smb_FindFIDByScache(vcp, scp);
3350 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3351 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3352 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3353 qpi.u.QPfileStandardInfo.directory =
3354 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3355 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3356 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3357 qpi.u.QPfileStandardInfo.reserved = 0;
3360 lock_ObtainMutex(&fidp->mx);
3361 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3362 lock_ReleaseMutex(&fidp->mx);
3363 smb_ReleaseFID(fidp);
3365 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3367 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3368 qpi.u.QPfileEaInfo.eaSize = 0;
3370 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3371 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3372 qpi.u.QPfileAllInfo.creationTime = ft;
3373 qpi.u.QPfileAllInfo.lastAccessTime = ft;
3374 qpi.u.QPfileAllInfo.lastWriteTime = ft;
3375 qpi.u.QPfileAllInfo.changeTime = ft;
3376 extAttributes = smb_ExtAttributes(scp);
3377 qpi.u.QPfileAllInfo.attributes = extAttributes;
3378 qpi.u.QPfileAllInfo.allocationSize = scp->length;
3379 qpi.u.QPfileAllInfo.endOfFile = scp->length;
3380 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3381 qpi.u.QPfileAllInfo.deletePending = 0;
3382 qpi.u.QPfileAllInfo.directory =
3383 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3384 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3385 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3386 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
3387 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
3388 qpi.u.QPfileAllInfo.eaSize = 0;
3389 qpi.u.QPfileAllInfo.accessFlags = 0;
3390 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
3391 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
3392 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3393 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3394 qpi.u.QPfileAllInfo.mode = 0;
3395 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3397 smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3398 qpi.u.QPfileAllInfo.fileNameLength = len;
3401 /* send and free the packets */
3403 switch (scp_rw_held) {
3405 lock_ReleaseRead(&scp->rw);
3408 lock_ReleaseWrite(&scp->rw);
3412 cm_ReleaseSCache(scp);
3413 cm_ReleaseUser(userp);
3415 memcpy(outp->datap, &qpi, responseSize);
3416 smb_SendTran2Packet(vcp, outp, opx);
3418 smb_SendTran2Error(vcp, p, opx, code);
3420 smb_FreeTran2Packet(outp);
3425 /* TRANS2_SET_PATH_INFORMATION */
3426 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3429 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
3430 return CM_ERROR_BADOP;
3433 unsigned short infoLevel;
3434 clientchar_t * pathp;
3435 smb_tran2Packet_t *outp;
3436 smb_tran2QPathInfo_t *spi;
3438 cm_scache_t *scp, *dscp;
3441 clientchar_t *tidPathp;
3442 clientchar_t *lastComp;
3446 infoLevel = p->parmsp[0];
3447 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
3448 if (infoLevel != SMB_INFO_STANDARD &&
3449 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
3450 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
3451 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3452 p->opcode, infoLevel);
3453 smb_SendTran2Error(vcp, p, opx,
3454 infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3458 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3460 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
3461 osi_LogSaveClientString(smb_logp, pathp));
3463 userp = smb_GetTran2User(vcp, p);
3465 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3466 code = CM_ERROR_BADSMB;
3470 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3471 if (code == CM_ERROR_TIDIPC) {
3472 /* Attempt to use a TID allocated for IPC. The client
3473 * is probably looking for DCE RPC end points which we
3474 * don't support OR it could be looking to make a DFS
3477 osi_Log0(smb_logp, "Tran2Open received IPC TID");
3478 cm_ReleaseUser(userp);
3479 return CM_ERROR_NOSUCHPATH;
3483 * XXX Strange hack XXX
3485 * As of Patch 7 (13 January 98), we are having the following problem:
3486 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3487 * requests to look up "desktop.ini" in all the subdirectories.
3488 * This can cause zillions of timeouts looking up non-existent cells
3489 * and volumes, especially in the top-level directory.
3491 * We have not found any way to avoid this or work around it except
3492 * to explicitly ignore the requests for mount points that haven't
3493 * yet been evaluated and for directories that haven't yet been
3496 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3497 spacep = cm_GetSpace();
3498 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3499 #ifndef SPECIAL_FOLDERS
3500 /* Make sure that lastComp is not NULL */
3502 if (cm_ClientStrCmpI(lastComp, _C("\\desktop.ini")) == 0) {
3503 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3507 userp, tidPathp, &req, &dscp);
3510 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3511 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3513 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3514 code = CM_ERROR_PATH_NOT_COVERED;
3516 code = CM_ERROR_NOSUCHPATH;
3518 #endif /* DFS_SUPPORT */
3519 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3520 code = CM_ERROR_NOSUCHFILE;
3521 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3522 cm_buf_t *bp = buf_Find(dscp, &hzero);
3528 code = CM_ERROR_NOSUCHFILE;
3530 cm_ReleaseSCache(dscp);
3532 cm_FreeSpace(spacep);
3533 cm_ReleaseUser(userp);
3534 smb_SendTran2Error(vcp, p, opx, code);
3540 #endif /* SPECIAL_FOLDERS */
3542 cm_FreeSpace(spacep);
3545 /* now do namei and stat, and copy out the info */
3546 code = cm_NameI(cm_data.rootSCachep, pathp,
3547 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3549 cm_ReleaseUser(userp);
3550 smb_SendTran2Error(vcp, p, opx, code);
3554 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3556 outp->totalParms = 2;
3557 outp->totalData = 0;
3559 spi = (smb_tran2QPathInfo_t *)p->datap;
3560 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3563 /* lock the vnode with a callback; we need the current status
3564 * to determine what the new status is, in some cases.
3566 lock_ObtainWrite(&scp->rw);
3567 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3568 CM_SCACHESYNC_GETSTATUS
3569 | CM_SCACHESYNC_NEEDCALLBACK);
3571 lock_ReleaseWrite(&scp->rw);
3574 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3576 /* prepare for setattr call */
3577 attr.mask = CM_ATTRMASK_LENGTH;
3578 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3579 attr.length.HighPart = 0;
3581 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3582 smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3583 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3586 if (spi->u.QPstandardInfo.attributes != 0) {
3587 if ((scp->unixModeBits & 0222)
3588 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3589 /* make a writable file read-only */
3590 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3591 attr.unixModeBits = scp->unixModeBits & ~0222;
3593 else if ((scp->unixModeBits & 0222) == 0
3594 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3595 /* make a read-only file writable */
3596 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3597 attr.unixModeBits = scp->unixModeBits | 0222;
3600 lock_ReleaseRead(&scp->rw);
3604 code = cm_SetAttr(scp, &attr, userp, &req);
3608 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3609 /* we don't support EAs */
3610 code = CM_ERROR_EAS_NOT_SUPPORTED;
3614 cm_ReleaseSCache(scp);
3615 cm_ReleaseUser(userp);
3617 smb_SendTran2Packet(vcp, outp, opx);
3619 smb_SendTran2Error(vcp, p, opx, code);
3620 smb_FreeTran2Packet(outp);
3626 /* TRANS2_QUERY_FILE_INFORMATION */
3627 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3629 smb_tran2Packet_t *outp;
3631 unsigned long attributes;
3632 unsigned short infoLevel;
3639 smb_tran2QFileInfo_t qfi;
3647 fidp = smb_FindFID(vcp, fid, 0);
3650 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3654 lock_ObtainMutex(&fidp->mx);
3655 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3656 lock_ReleaseMutex(&fidp->mx);
3657 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3658 smb_CloseFID(vcp, fidp, NULL, 0);
3659 smb_ReleaseFID(fidp);
3662 lock_ReleaseMutex(&fidp->mx);
3664 infoLevel = p->parmsp[1];
3665 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3666 responseSize = sizeof(qfi.u.QFbasicInfo);
3667 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3668 responseSize = sizeof(qfi.u.QFstandardInfo);
3669 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3670 responseSize = sizeof(qfi.u.QFeaInfo);
3671 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3672 responseSize = sizeof(qfi.u.QFfileNameInfo);
3674 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3675 p->opcode, infoLevel);
3676 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3677 smb_ReleaseFID(fidp);
3680 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3682 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3684 if (infoLevel > 0x100)
3685 outp->totalParms = 2;
3687 outp->totalParms = 0;
3688 outp->totalData = responseSize;
3690 userp = smb_GetTran2User(vcp, p);
3692 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3693 code = CM_ERROR_BADSMB;
3697 lock_ObtainMutex(&fidp->mx);
3698 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3700 osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3702 lock_ReleaseMutex(&fidp->mx);
3703 lock_ObtainWrite(&scp->rw);
3704 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3705 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3709 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3711 lock_ConvertWToR(&scp->rw);
3714 /* now we have the status in the cache entry, and everything is locked.
3715 * Marshall the output data.
3717 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3718 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3719 qfi.u.QFbasicInfo.creationTime = ft;
3720 qfi.u.QFbasicInfo.lastAccessTime = ft;
3721 qfi.u.QFbasicInfo.lastWriteTime = ft;
3722 qfi.u.QFbasicInfo.lastChangeTime = ft;
3723 attributes = smb_ExtAttributes(scp);
3724 qfi.u.QFbasicInfo.attributes = attributes;
3726 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3727 qfi.u.QFstandardInfo.allocationSize = scp->length;
3728 qfi.u.QFstandardInfo.endOfFile = scp->length;
3729 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3730 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3731 qfi.u.QFstandardInfo.directory =
3732 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3733 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3734 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3736 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3737 qfi.u.QFeaInfo.eaSize = 0;
3739 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3743 lock_ReleaseRead(&scp->rw);
3744 lock_ObtainMutex(&fidp->mx);
3745 lock_ObtainRead(&scp->rw);
3746 if (fidp->NTopen_wholepathp)
3747 name = fidp->NTopen_wholepathp;
3749 name = _C("\\"); /* probably can't happen */
3750 lock_ReleaseMutex(&fidp->mx);
3752 smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, SMB_STRF_IGNORENUL);
3753 outp->totalData = len + 4; /* this is actually what we want to return */
3754 qfi.u.QFfileNameInfo.fileNameLength = len;
3757 /* send and free the packets */
3760 lock_ReleaseRead(&scp->rw);
3762 lock_ReleaseWrite(&scp->rw);
3763 cm_ReleaseSCache(scp);
3764 cm_ReleaseUser(userp);
3765 smb_ReleaseFID(fidp);
3767 memcpy(outp->datap, &qfi, responseSize);
3768 smb_SendTran2Packet(vcp, outp, opx);
3770 smb_SendTran2Error(vcp, p, opx, code);
3772 smb_FreeTran2Packet(outp);
3778 /* TRANS2_SET_FILE_INFORMATION */
3779 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3784 unsigned short infoLevel;
3785 smb_tran2Packet_t *outp;
3786 cm_user_t *userp = NULL;
3787 cm_scache_t *scp = NULL;
3793 fidp = smb_FindFID(vcp, fid, 0);
3796 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3800 infoLevel = p->parmsp[1];
3801 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3802 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3803 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3804 p->opcode, infoLevel);
3805 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3806 smb_ReleaseFID(fidp);
3810 lock_ObtainMutex(&fidp->mx);
3811 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3812 lock_ReleaseMutex(&fidp->mx);
3813 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3814 smb_CloseFID(vcp, fidp, NULL, 0);
3815 smb_ReleaseFID(fidp);
3819 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
3820 !(fidp->flags & SMB_FID_OPENDELETE)) {
3821 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3822 fidp, fidp->scp, fidp->flags);
3823 lock_ReleaseMutex(&fidp->mx);
3824 smb_ReleaseFID(fidp);
3825 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3828 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3829 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3830 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3831 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3832 fidp, fidp->scp, fidp->flags);
3833 lock_ReleaseMutex(&fidp->mx);
3834 smb_ReleaseFID(fidp);
3835 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3840 osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3842 lock_ReleaseMutex(&fidp->mx);
3844 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3846 outp->totalParms = 2;
3847 outp->totalData = 0;
3849 userp = smb_GetTran2User(vcp, p);
3851 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3852 code = CM_ERROR_BADSMB;
3856 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3858 unsigned int attribute;
3860 smb_tran2QFileInfo_t *sfi;
3862 sfi = (smb_tran2QFileInfo_t *)p->datap;
3864 /* lock the vnode with a callback; we need the current status
3865 * to determine what the new status is, in some cases.
3867 lock_ObtainWrite(&scp->rw);
3868 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3869 CM_SCACHESYNC_GETSTATUS
3870 | CM_SCACHESYNC_NEEDCALLBACK);
3872 lock_ReleaseWrite(&scp->rw);
3876 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3878 lock_ReleaseWrite(&scp->rw);
3879 lock_ObtainMutex(&fidp->mx);
3880 lock_ObtainRead(&scp->rw);
3882 /* prepare for setattr call */
3885 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3886 /* when called as result of move a b, lastMod is (-1, -1).
3887 * If the check for -1 is not present, timestamp
3888 * of the resulting file will be 1969 (-1)
3890 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3891 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3892 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3893 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3894 fidp->flags |= SMB_FID_MTIMESETDONE;
3897 attribute = sfi->u.QFbasicInfo.attributes;
3898 if (attribute != 0) {
3899 if ((scp->unixModeBits & 0222)
3900 && (attribute & SMB_ATTR_READONLY) != 0) {
3901 /* make a writable file read-only */
3902 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3903 attr.unixModeBits = scp->unixModeBits & ~0222;
3905 else if ((scp->unixModeBits & 0222) == 0
3906 && (attribute & SMB_ATTR_READONLY) == 0) {
3907 /* make a read-only file writable */
3908 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3909 attr.unixModeBits = scp->unixModeBits | 0222;
3912 lock_ReleaseRead(&scp->rw);
3913 lock_ReleaseMutex(&fidp->mx);
3917 code = cm_SetAttr(scp, &attr, userp, &req);
3921 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3922 int delflag = *((char *)(p->datap));
3923 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
3924 delflag, fidp, scp);
3925 if (*((char *)(p->datap))) { /* File is Deleted */
3926 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3929 lock_ObtainMutex(&fidp->mx);
3930 fidp->flags |= SMB_FID_DELONCLOSE;
3931 lock_ReleaseMutex(&fidp->mx);
3933 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
3939 lock_ObtainMutex(&fidp->mx);
3940 fidp->flags &= ~SMB_FID_DELONCLOSE;
3941 lock_ReleaseMutex(&fidp->mx);
3944 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3945 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3946 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3949 attr.mask = CM_ATTRMASK_LENGTH;
3950 attr.length.LowPart = size.LowPart;
3951 attr.length.HighPart = size.HighPart;
3952 code = cm_SetAttr(scp, &attr, userp, &req);
3956 cm_ReleaseSCache(scp);
3957 cm_ReleaseUser(userp);
3958 smb_ReleaseFID(fidp);
3960 smb_SendTran2Packet(vcp, outp, opx);
3962 smb_SendTran2Error(vcp, p, opx, code);
3963 smb_FreeTran2Packet(outp);
3970 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3972 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3973 return CM_ERROR_BADOP;
3978 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3980 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3981 return CM_ERROR_BADOP;
3984 /* TRANS2_FIND_NOTIFY_FIRST */
3986 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3988 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3989 return CM_ERROR_BADOP;
3992 /* TRANS2_FIND_NOTIFY_NEXT */
3994 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3996 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3997 return CM_ERROR_BADOP;
4000 /* TRANS2_CREATE_DIRECTORY */
4002 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4004 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
4005 return CM_ERROR_BADOP;
4008 /* TRANS2_SESSION_SETUP */
4010 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4012 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
4013 return CM_ERROR_BADOP;
4016 struct smb_v2_referral {
4018 USHORT ReferralFlags;
4021 USHORT DfsPathOffset;
4022 USHORT DfsAlternativePathOffset;
4023 USHORT NetworkAddressOffset;
4026 /* TRANS2_GET_DFS_REFERRAL */
4028 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
4030 /* This is a UNICODE only request (bit15 of Flags2) */
4031 /* The TID must be IPC$ */
4033 /* The documentation for the Flags response field is contradictory */
4035 /* Use Version 1 Referral Element Format */
4036 /* ServerType = 0; indicates the next server should be queried for the file */
4037 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
4038 /* Node = UnicodeString of UNC path of the next share name */
4041 int maxReferralLevel = 0;
4042 clientchar_t requestFileName[1024] = _C("");
4043 clientchar_t referralPath[1024] = _C("");
4044 smb_tran2Packet_t *outp = 0;
4045 cm_user_t *userp = 0;
4046 cm_scache_t *scp = 0;
4047 cm_scache_t *dscp = 0;
4049 CPINFO CodePageInfo;
4050 int i, nbnLen, reqLen, refLen;
4055 maxReferralLevel = p->parmsp[0];
4057 GetCPInfo(CP_ACP, &CodePageInfo);
4058 cm_Utf16ToClientString(&p->parmsp[1], -1, requestFileName, lengthof(requestFileName));
4060 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%S]",
4061 maxReferralLevel, osi_LogSaveClientString(smb_logp, requestFileName));
4063 nbnLen = (int)cm_ClientStrLen(cm_NetbiosNameC);
4064 reqLen = (int)cm_ClientStrLen(requestFileName);
4066 if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
4067 !cm_ClientStrCmpNI(cm_NetbiosNameC, &requestFileName[1], nbnLen) &&
4068 requestFileName[nbnLen+1] == '\\')
4072 if (!cm_ClientStrCmpNI(_C("all"), &requestFileName[nbnLen+2], 3) ||
4073 !cm_ClientStrCmpNI(_C("*."), &requestFileName[nbnLen+2], 2)) {
4075 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4078 userp = smb_GetTran2User(vcp, p);
4080 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
4081 code = CM_ERROR_BADSMB;
4086 * We have a requested path. Check to see if it is something
4089 * But be careful because the name that we might be searching
4090 * for might be a known name with the final character stripped
4093 code = cm_NameI(cm_data.rootSCachep, &requestFileName[nbnLen+2],
4094 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
4095 userp, NULL, &req, &scp);
4099 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4101 } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
4102 clientchar_t temp[1024];
4103 clientchar_t pathName[1024];
4104 clientchar_t *lastComponent;
4106 * we have a msdfs link somewhere in the path
4107 * we should figure out where in the path the link is.
4110 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%S]", requestFileName);
4112 cm_ClientStrCpy(temp, lengthof(temp), &requestFileName[nbnLen+2]);
4116 cm_ReleaseSCache(dscp);
4120 cm_ReleaseSCache(scp);
4123 smb_StripLastComponent(pathName, &lastComponent, temp);
4125 code = cm_NameI(cm_data.rootSCachep, pathName,
4126 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4127 userp, NULL, &req, &dscp);
4129 code = cm_NameI(dscp, ++lastComponent,
4131 userp, NULL, &req, &scp);
4132 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK)
4135 } while (code == CM_ERROR_PATH_NOT_COVERED);
4137 /* scp should now be the DfsLink we are looking for */
4139 /* figure out how much of the input path was used */
4140 reqLen = (int)(nbnLen+2 + cm_ClientStrLen(pathName) + 1 + cm_ClientStrLen(lastComponent));
4142 cm_FsStringToClientString(&scp->mountPointStringp[strlen("msdfs:")], -1,
4143 referralPath, lengthof(referralPath));
4144 refLen = (int)cm_ClientStrLen(referralPath);
4148 clientchar_t shareName[MAX_PATH + 1];
4149 clientchar_t *p, *q;
4150 /* we may have a sharename that is a volume reference */
4152 for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
4158 if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
4159 code = cm_NameI(cm_data.rootSCachep, _C(""),
4160 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
4161 userp, p, &req, &scp);
4166 cm_ClientStrCpy(referralPath, lengthof(referralPath),
4177 struct smb_v2_referral * v2ref;
4178 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (refLen + 8));
4180 sp = (USHORT *)outp->datap;
4182 sp[idx++] = reqLen; /* path consumed */
4183 sp[idx++] = 1; /* number of referrals */
4184 sp[idx++] = 0x03; /* flags */
4185 #ifdef DFS_VERSION_1
4186 sp[idx++] = 1; /* Version Number */
4187 sp[idx++] = refLen + 4; /* Referral Size */
4188 sp[idx++] = 1; /* Type = SMB Server */
4189 sp[idx++] = 0; /* Do not strip path consumed */
4190 for ( i=0;i<=refLen; i++ )
4191 sp[i+idx] = referralPath[i];
4192 #else /* DFS_VERSION_2 */
4193 sp[idx++] = 2; /* Version Number */
4194 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
4195 idx += (sizeof(struct smb_v2_referral) / 2);
4196 v2ref = (struct smb_v2_referral *) &sp[5];
4197 v2ref->ServerType = 1; /* SMB Server */
4198 v2ref->ReferralFlags = 0x03;
4199 v2ref->Proximity = 0; /* closest */
4200 v2ref->TimeToLive = 3600; /* seconds */
4201 v2ref->DfsPathOffset = idx * 2;
4202 v2ref->DfsAlternativePathOffset = idx * 2;
4203 v2ref->NetworkAddressOffset = 0;
4204 for ( i=0;i<=refLen; i++ )
4205 sp[i+idx] = referralPath[i];
4209 code = CM_ERROR_NOSUCHPATH;
4214 cm_ReleaseSCache(dscp);
4216 cm_ReleaseSCache(scp);
4218 cm_ReleaseUser(userp);
4220 smb_SendTran2Packet(vcp, outp, op);
4222 smb_SendTran2Error(vcp, p, op, code);
4224 smb_FreeTran2Packet(outp);
4227 #else /* DFS_SUPPORT */
4228 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
4229 return CM_ERROR_NOSUCHDEVICE;
4230 #endif /* DFS_SUPPORT */
4233 /* TRANS2_REPORT_DFS_INCONSISTENCY */
4235 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4237 /* This is a UNICODE only request (bit15 of Flags2) */