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>
35 extern osi_hyper_t hzero;
37 smb_packet_t *smb_Directory_Watches = NULL;
38 osi_mutex_t smb_Dir_Watch_Lock;
40 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
42 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
44 /* protected by the smb_globalLock */
45 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
47 const clientchar_t **smb_ExecutableExtensions = NULL;
49 /* retrieve a held reference to a user structure corresponding to an incoming
51 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
56 uidp = smb_FindUID(vcp, inp->uid, 0);
60 up = smb_GetUserFromUID(uidp);
68 * Return boolean specifying if the path name is thought to be an
69 * executable file. For now .exe or .dll.
71 afs_uint32 smb_IsExecutableFileName(const clientchar_t *name)
75 if ( smb_ExecutableExtensions == NULL || name == NULL)
78 len = (int)cm_ClientStrLen(name);
80 for ( i=0; smb_ExecutableExtensions[i]; i++) {
81 j = len - (int)cm_ClientStrLen(smb_ExecutableExtensions[i]);
82 if (cm_ClientStrCmpI(smb_ExecutableExtensions[i], &name[j]) == 0)
90 * Return extended attributes.
91 * Right now, we aren't using any of the "new" bits, so this looks exactly
92 * like smb_Attributes() (see smb.c).
94 unsigned long smb_ExtAttributes(cm_scache_t *scp)
98 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
99 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
100 scp->fileType == CM_SCACHETYPE_INVALID)
102 attrs = SMB_ATTR_DIRECTORY;
103 #ifdef SPECIAL_FOLDERS
104 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
105 #endif /* SPECIAL_FOLDERS */
106 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
107 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
108 } else if (scp->fid.vnode & 0x1)
109 attrs = SMB_ATTR_DIRECTORY;
114 * We used to mark a file RO if it was in an RO volume, but that
115 * turns out to be impolitic in NT. See defect 10007.
118 if ((scp->unixModeBits & 0200) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
119 attrs |= SMB_ATTR_READONLY; /* Read-only */
121 if ((scp->unixModeBits & 0200) == 0)
122 attrs |= SMB_ATTR_READONLY; /* Read-only */
126 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
131 int smb_V3IsStarMask(clientchar_t *maskp)
135 while (tc = *maskp++)
136 if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
141 void OutputDebugF(clientchar_t * format, ...) {
143 clientchar_t vbuffer[1024];
145 va_start( args, format );
146 cm_ClientStrPrintfV(vbuffer, lengthof(vbuffer), format, args);
147 osi_Log1(smb_logp, "%S", osi_LogSaveClientString(smb_logp, vbuffer));
150 void OutputDebugHexDump(unsigned char * buffer, int len) {
153 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
155 OutputDebugF(_C("Hexdump length [%d]"),len);
157 for (i=0;i<len;i++) {
160 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
162 StringCchPrintfA(buf, lengthof(buf), "%5x", i);
163 memset(buf+5,' ',80);
168 j = j*3 + 7 + ((j>7)?1:0);
171 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
174 j = j + 56 + ((j>7)?1:0);
176 buf[j] = (k>32 && k<127)?k:'.';
179 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
183 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
185 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
186 SECURITY_STATUS status, istatus;
187 CredHandle creds = {0,0};
189 SecBufferDesc secOut;
197 OutputDebugF(_C("Negotiating Extended Security"));
199 status = AcquireCredentialsHandle( NULL,
200 SMB_EXT_SEC_PACKAGE_NAME,
209 if (status != SEC_E_OK) {
210 /* Really bad. We return an empty security blob */
211 OutputDebugF(_C("AcquireCredentialsHandle failed with %lX"), status);
216 secOut.pBuffers = &secTok;
217 secOut.ulVersion = SECBUFFER_VERSION;
219 secTok.BufferType = SECBUFFER_TOKEN;
221 secTok.pvBuffer = NULL;
223 ctx.dwLower = ctx.dwUpper = 0;
225 status = AcceptSecurityContext( &creds,
228 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
229 SECURITY_NETWORK_DREP,
236 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
237 OutputDebugF(_C("Completing token..."));
238 istatus = CompleteAuthToken(&ctx, &secOut);
239 if ( istatus != SEC_E_OK )
240 OutputDebugF(_C("Token completion failed: %x"), istatus);
243 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
244 if (secTok.pvBuffer) {
245 *secBlobLength = secTok.cbBuffer;
246 *secBlob = malloc( secTok.cbBuffer );
247 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
250 if ( status != SEC_E_OK )
251 OutputDebugF(_C("AcceptSecurityContext status != CONTINUE %lX"), status);
254 /* Discard partial security context */
255 DeleteSecurityContext(&ctx);
257 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
259 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
260 FreeCredentialsHandle(&creds);
266 struct smb_ext_context {
273 long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern,
274 char * secBlobIn, int secBlobInLength,
275 char ** secBlobOut, int * secBlobOutLength) {
276 SECURITY_STATUS status, istatus;
280 SecBufferDesc secBufIn;
282 SecBufferDesc secBufOut;
285 struct smb_ext_context * secCtx = NULL;
286 struct smb_ext_context * newSecCtx = NULL;
287 void * assembledBlob = NULL;
288 int assembledBlobLength = 0;
291 OutputDebugF(_C("In smb_AuthenticateUserExt"));
294 *secBlobOutLength = 0;
296 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
297 secCtx = vcp->secCtx;
298 lock_ObtainMutex(&vcp->mx);
299 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
301 lock_ReleaseMutex(&vcp->mx);
305 OutputDebugF(_C("Received incoming token:"));
306 OutputDebugHexDump(secBlobIn,secBlobInLength);
310 OutputDebugF(_C("Continuing with existing context."));
311 creds = secCtx->creds;
314 if (secCtx->partialToken) {
315 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
316 assembledBlob = malloc(assembledBlobLength);
317 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
318 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
321 status = AcquireCredentialsHandle( NULL,
322 SMB_EXT_SEC_PACKAGE_NAME,
331 if (status != SEC_E_OK) {
332 OutputDebugF(_C("Can't acquire Credentials handle [%lX]"), status);
333 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
341 secBufIn.cBuffers = 1;
342 secBufIn.pBuffers = &secTokIn;
343 secBufIn.ulVersion = SECBUFFER_VERSION;
345 secTokIn.BufferType = SECBUFFER_TOKEN;
347 secTokIn.cbBuffer = assembledBlobLength;
348 secTokIn.pvBuffer = assembledBlob;
350 secTokIn.cbBuffer = secBlobInLength;
351 secTokIn.pvBuffer = secBlobIn;
354 secBufOut.cBuffers = 1;
355 secBufOut.pBuffers = &secTokOut;
356 secBufOut.ulVersion = SECBUFFER_VERSION;
358 secTokOut.BufferType = SECBUFFER_TOKEN;
359 secTokOut.cbBuffer = 0;
360 secTokOut.pvBuffer = NULL;
362 status = AcceptSecurityContext( &creds,
363 ((secCtx)?&ctx:NULL),
365 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
366 SECURITY_NETWORK_DREP,
373 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
374 OutputDebugF(_C("Completing token..."));
375 istatus = CompleteAuthToken(&ctx, &secBufOut);
376 if ( istatus != SEC_E_OK )
377 OutputDebugF(_C("Token completion failed: %lX"), istatus);
380 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
381 OutputDebugF(_C("Continue needed"));
383 newSecCtx = malloc(sizeof(*newSecCtx));
385 newSecCtx->creds = creds;
386 newSecCtx->ctx = ctx;
387 newSecCtx->partialToken = NULL;
388 newSecCtx->partialTokenLen = 0;
390 lock_ObtainMutex( &vcp->mx );
391 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
392 vcp->secCtx = newSecCtx;
393 lock_ReleaseMutex( &vcp->mx );
395 code = CM_ERROR_GSSCONTINUE;
398 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
399 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
400 secTokOut.pvBuffer) {
401 OutputDebugF(_C("Need to send token back to client"));
403 *secBlobOutLength = secTokOut.cbBuffer;
404 *secBlobOut = malloc(secTokOut.cbBuffer);
405 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
407 OutputDebugF(_C("Outgoing token:"));
408 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
409 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
410 OutputDebugF(_C("Incomplete message"));
412 newSecCtx = malloc(sizeof(*newSecCtx));
414 newSecCtx->creds = creds;
415 newSecCtx->ctx = ctx;
416 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
417 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
418 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
420 lock_ObtainMutex( &vcp->mx );
421 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
422 vcp->secCtx = newSecCtx;
423 lock_ReleaseMutex( &vcp->mx );
425 code = CM_ERROR_GSSCONTINUE;
428 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
430 SecPkgContext_NamesW names;
432 OutputDebugF(_C("Authentication completed"));
433 OutputDebugF(_C("Returned flags : [%lX]"), flags);
435 if (!QueryContextAttributesW(&ctx, SECPKG_ATTR_NAMES, &names)) {
436 OutputDebugF(_C("Received name [%s]"), names.sUserName);
437 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, names.sUserName);
438 cm_ClientStrLwr(usern); /* in tandem with smb_GetNormalizedUsername */
439 FreeContextBuffer(names.sUserName);
441 /* Force the user to retry if the context is invalid */
442 OutputDebugF(_C("QueryContextAttributes Names failed [%x]"), GetLastError());
443 code = CM_ERROR_BADPASSWORD;
447 case SEC_E_INVALID_TOKEN:
448 OutputDebugF(_C("Returning bad password :: INVALID_TOKEN"));
450 case SEC_E_INVALID_HANDLE:
451 OutputDebugF(_C("Returning bad password :: INVALID_HANDLE"));
453 case SEC_E_LOGON_DENIED:
454 OutputDebugF(_C("Returning bad password :: LOGON_DENIED"));
456 case SEC_E_UNKNOWN_CREDENTIALS:
457 OutputDebugF(_C("Returning bad password :: UNKNOWN_CREDENTIALS"));
459 case SEC_E_NO_CREDENTIALS:
460 OutputDebugF(_C("Returning bad password :: NO_CREDENTIALS"));
462 case SEC_E_CONTEXT_EXPIRED:
463 OutputDebugF(_C("Returning bad password :: CONTEXT_EXPIRED"));
465 case SEC_E_INCOMPLETE_CREDENTIALS:
466 OutputDebugF(_C("Returning bad password :: INCOMPLETE_CREDENTIALS"));
468 case SEC_E_WRONG_PRINCIPAL:
469 OutputDebugF(_C("Returning bad password :: WRONG_PRINCIPAL"));
471 case SEC_E_TIME_SKEW:
472 OutputDebugF(_C("Returning bad password :: TIME_SKEW"));
475 OutputDebugF(_C("Returning bad password :: Status == %lX"), status);
477 code = CM_ERROR_BADPASSWORD;
481 if (secCtx->partialToken) free(secCtx->partialToken);
489 if (secTokOut.pvBuffer)
490 FreeContextBuffer(secTokOut.pvBuffer);
492 if (code != CM_ERROR_GSSCONTINUE) {
493 DeleteSecurityContext(&ctx);
494 FreeCredentialsHandle(&creds);
502 #define P_RESP_LEN 128
504 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
505 So put stuff in a struct. */
506 struct Lm20AuthBlob {
507 MSV1_0_LM20_LOGON lmlogon;
508 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
509 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
510 WCHAR accountNameW[P_LEN];
511 WCHAR primaryDomainW[P_LEN];
512 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
513 TOKEN_GROUPS tgroups;
514 TOKEN_SOURCE tsource;
517 long smb_AuthenticateUserLM(smb_vc_t *vcp, clientchar_t * accountName, clientchar_t * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
520 struct Lm20AuthBlob lmAuth;
521 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
522 QUOTA_LIMITS quotaLimits;
524 ULONG lmprofilepSize;
528 OutputDebugF(_C("In smb_AuthenticateUser for user [%s] domain [%s]"), accountName, primaryDomain);
529 OutputDebugF(_C("ciPwdLength is %d and csPwdLength is %d"), ciPwdLength, csPwdLength);
531 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
532 OutputDebugF(_C("ciPwdLength or csPwdLength is too long"));
533 return CM_ERROR_BADPASSWORD;
536 memset(&lmAuth,0,sizeof(lmAuth));
538 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
540 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
541 cm_ClientStringToUtf16(primaryDomain, -1, lmAuth.primaryDomainW, P_LEN);
542 lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
543 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
545 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
546 cm_ClientStringToUtf16(accountName, -1, lmAuth.accountNameW, P_LEN);
547 lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
548 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
550 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
551 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
552 size = MAX_COMPUTERNAME_LENGTH + 1;
553 GetComputerNameW(lmAuth.workstationW, &size);
554 lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
556 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
558 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
559 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
560 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
561 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
563 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
564 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
565 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
566 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
568 lmAuth.lmlogon.ParameterControl = 0;
570 lmAuth.tgroups.GroupCount = 0;
571 lmAuth.tgroups.Groups[0].Sid = NULL;
572 lmAuth.tgroups.Groups[0].Attributes = 0;
575 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
577 lmAuth.tsource.SourceIdentifier.HighPart = 0;
579 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
580 StringCchCopyA(lmAuth.tsource.SourceName, lengthof(lmAuth.tsource.SourceName),
581 "OpenAFS"); /* 8 char limit */
583 nts = LsaLogonUser( smb_lsaHandle,
598 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
599 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
602 OutputDebugF(_C("Return from LsaLogonUser is 0x%lX"), nts);
603 OutputDebugF(_C("Extended status is 0x%lX"), ntsEx);
605 if (nts == ERROR_SUCCESS) {
607 LsaFreeReturnBuffer(lmprofilep);
608 CloseHandle(lmToken);
612 if (nts == 0xC000015BL)
613 return CM_ERROR_BADLOGONTYPE;
614 else /* our catchall is a bad password though we could be more specific */
615 return CM_ERROR_BADPASSWORD;
619 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
620 long smb_GetNormalizedUsername(clientchar_t * usern, const clientchar_t * accountName, const clientchar_t * domainName)
622 clientchar_t * atsign;
623 const clientchar_t * domain;
625 /* check if we have sane input */
626 if ((cm_ClientStrLen(accountName) + cm_ClientStrLen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
629 /* we could get : [accountName][domainName]
635 atsign = cm_ClientStrChr(accountName, '@');
637 if (atsign) /* [user@domain][] -> [user@domain][domain] */
642 /* if for some reason the client doesn't know what domain to use,
643 it will either return an empty string or a '?' */
644 if (!domain[0] || domain[0] == '?')
645 /* Empty domains and empty usernames are usually sent from tokenless contexts.
646 This way such logins will get an empty username (easy to check). I don't know
647 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
648 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, accountName);
650 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
651 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, domain);
652 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, _C("\\"));
654 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
656 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
659 cm_ClientStrLwr(usern);
664 /* When using SMB auth, all SMB sessions have to pass through here
665 * first to authenticate the user.
667 * Caveat: If not using SMB auth, the protocol does not require
668 * sending a session setup packet, which means that we can't rely on a
669 * UID in subsequent packets. Though in practice we get one anyway.
671 /* SMB_COM_SESSION_SETUP_ANDX */
672 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
676 unsigned short newUid;
677 unsigned long caps = 0;
679 clientchar_t *s1 = _C(" ");
681 clientchar_t usern[SMB_MAX_USERNAME_LENGTH];
682 char *secBlobOut = NULL;
683 int secBlobOutLength = 0;
684 int maxBufferSize = 0;
688 /* Check for bad conns */
689 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
690 return CM_ERROR_REMOTECONN;
693 maxBufferSize = smb_GetSMBParm(inp, 2);
694 maxMpxCount = smb_GetSMBParm(inp, 3);
695 vcNumber = smb_GetSMBParm(inp, 4);
697 osi_Log3(smb_logp, "SESSION_SETUP_ANDX with MaxBufferSize=%d, MaxMpxCount=%d, VCNumber=%d",
698 maxBufferSize, maxMpxCount, vcNumber);
700 if (maxMpxCount > smb_maxMpxRequests) {
701 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_MPX_COUNT, maxMpxCount, smb_maxMpxRequests);
702 osi_Log2(smb_logp, "MaxMpxCount for client is too large (Client=%d, Server=%d)",
703 maxMpxCount, smb_maxMpxRequests);
706 if (maxBufferSize < SMB_PACKETSIZE) {
707 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_BUFFER_SIZE, maxBufferSize, SMB_PACKETSIZE);
708 osi_Log2(smb_logp, "MaxBufferSize for client is too small (Client=%d, Server=%d)",
709 maxBufferSize, SMB_PACKETSIZE);
713 osi_Log0(smb_logp, "Resetting all VCs");
714 smb_MarkAllVCsDead(vcp);
717 if (vcp->flags & SMB_VCFLAG_USENT) {
718 if (smb_authType == SMB_AUTH_EXTENDED) {
719 /* extended authentication */
723 OutputDebugF(_C("NT Session Setup: Extended"));
725 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
726 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
729 secBlobInLength = smb_GetSMBParm(inp, 7);
730 secBlobIn = smb_GetSMBData(inp, NULL);
732 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
734 if (code == CM_ERROR_GSSCONTINUE) {
737 smb_SetSMBParm(outp, 2, 0);
738 smb_SetSMBParm(outp, 3, secBlobOutLength);
740 tp = smb_GetSMBData(outp, NULL);
741 if (secBlobOutLength) {
742 memcpy(tp, secBlobOut, secBlobOutLength);
744 tp += secBlobOutLength;
745 cb_data += secBlobOutLength;
747 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
748 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
749 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
751 smb_SetSMBDataLength(outp, cb_data);
754 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
756 unsigned ciPwdLength, csPwdLength;
758 clientchar_t *accountName;
759 clientchar_t *primaryDomain;
762 if (smb_authType == SMB_AUTH_NTLM)
763 OutputDebugF(_C("NT Session Setup: NTLM"));
765 OutputDebugF(_C("NT Session Setup: None"));
767 /* TODO: parse for extended auth as well */
768 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
769 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
771 tp = smb_GetSMBData(inp, &datalen);
773 OutputDebugF(_C("Session packet data size [%d]"),datalen);
780 accountName = smb_ParseString(inp, tp, &tp, 0);
781 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
783 OutputDebugF(_C("Account Name: %s"),accountName);
784 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
785 OutputDebugF(_C("Case Sensitive Password: %s"),
786 csPwd && csPwd[0] ? _C("yes") : _C("no"));
787 OutputDebugF(_C("Case Insensitive Password: %s"),
788 ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
790 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
791 /* shouldn't happen */
792 code = CM_ERROR_BADSMB;
793 goto after_read_packet;
796 /* capabilities are only valid for first session packet */
797 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
798 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
801 if (smb_authType == SMB_AUTH_NTLM) {
802 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
804 OutputDebugF(_C("LM authentication failed [%d]"), code);
806 OutputDebugF(_C("LM authentication succeeded"));
810 unsigned ciPwdLength;
812 clientchar_t *accountName;
813 clientchar_t *primaryDomain;
815 switch ( smb_authType ) {
816 case SMB_AUTH_EXTENDED:
817 OutputDebugF(_C("V3 Session Setup: Extended"));
820 OutputDebugF(_C("V3 Session Setup: NTLM"));
823 OutputDebugF(_C("V3 Session Setup: None"));
825 ciPwdLength = smb_GetSMBParm(inp, 7);
826 tp = smb_GetSMBData(inp, NULL);
830 accountName = smb_ParseString(inp, tp, &tp, 0);
831 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
833 OutputDebugF(_C("Account Name: %s"),accountName);
834 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
835 OutputDebugF(_C("Case Insensitive Password: %s"), ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
837 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
838 /* shouldn't happen */
839 code = CM_ERROR_BADSMB;
840 goto after_read_packet;
843 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
846 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
847 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
849 OutputDebugF(_C("LM authentication failed [%d]"), code);
851 OutputDebugF(_C("LM authentication succeeded"));
856 /* note down that we received a session setup X and set the capabilities flag */
857 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
858 lock_ObtainMutex(&vcp->mx);
859 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
860 /* for the moment we can only deal with NTSTATUS */
861 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
862 vcp->flags |= SMB_VCFLAG_STATUS32;
866 if ((caps & NTNEGOTIATE_CAPABILITY_UNICODE) && smb_UseUnicode) {
867 vcp->flags |= SMB_VCFLAG_USEUNICODE;
870 lock_ReleaseMutex(&vcp->mx);
873 /* code would be non-zero if there was an authentication failure.
874 Ideally we would like to invalidate the uid for this session or break
875 early to avoid accidently stealing someone else's tokens. */
881 OutputDebugF(_C("Received username=[%s]"), usern);
883 /* On Windows 2000, this function appears to be called more often than
884 it is expected to be called. This resulted in multiple smb_user_t
885 records existing all for the same user session which results in all
886 of the users tokens disappearing.
888 To avoid this problem, we look for an existing smb_user_t record
889 based on the users name, and use that one if we find it.
892 uidp = smb_FindUserByNameThisSession(vcp, usern);
893 if (uidp) { /* already there, so don't create a new one */
895 newUid = uidp->userID;
896 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
897 vcp->lana,vcp->lsn,newUid);
898 smb_ReleaseUID(uidp);
903 /* do a global search for the username/machine name pair */
904 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
905 lock_ObtainMutex(&unp->mx);
906 if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
907 /* clear the afslogon flag so that the tickets can now
908 * be freed when the refCount returns to zero.
910 unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
912 lock_ReleaseMutex(&unp->mx);
914 /* Create a new UID and cm_user_t structure */
917 userp = cm_NewUser();
918 cm_HoldUserVCRef(userp);
919 lock_ObtainMutex(&vcp->mx);
920 if (!vcp->uidCounter)
921 vcp->uidCounter++; /* handle unlikely wraparounds */
922 newUid = (cm_ClientStrLen(usern)==0)?0:vcp->uidCounter++;
923 lock_ReleaseMutex(&vcp->mx);
925 /* Create a new smb_user_t structure and connect them up */
926 lock_ObtainMutex(&unp->mx);
928 lock_ReleaseMutex(&unp->mx);
930 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
932 lock_ObtainMutex(&uidp->mx);
934 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
935 lock_ReleaseMutex(&uidp->mx);
936 smb_ReleaseUID(uidp);
940 /* Return UID to the client */
941 ((smb_t *)outp)->uid = newUid;
942 /* Also to the next chained message */
943 ((smb_t *)inp)->uid = newUid;
945 osi_Log3(smb_logp, "SMB3 session setup name %S creating ID %d%S",
946 osi_LogSaveClientString(smb_logp, usern), newUid,
947 osi_LogSaveClientString(smb_logp, s1));
949 smb_SetSMBParm(outp, 2, 0);
951 if (vcp->flags & SMB_VCFLAG_USENT) {
952 if (smb_authType == SMB_AUTH_EXTENDED) {
955 smb_SetSMBParm(outp, 3, secBlobOutLength);
957 tp = smb_GetSMBData(outp, NULL);
958 if (secBlobOutLength) {
959 memcpy(tp, secBlobOut, secBlobOutLength);
961 tp += secBlobOutLength;
962 cb_data += secBlobOutLength;
965 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
966 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
967 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
969 smb_SetSMBDataLength(outp, cb_data);
971 smb_SetSMBDataLength(outp, 0);
974 if (smb_authType == SMB_AUTH_EXTENDED) {
977 tp = smb_GetSMBData(outp, NULL);
979 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
980 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
981 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
983 smb_SetSMBDataLength(outp, cb_data);
985 smb_SetSMBDataLength(outp, 0);
992 /* SMB_COM_LOGOFF_ANDX */
993 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
997 /* find the tree and free it */
998 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1000 smb_username_t * unp;
1002 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %S", uidp->userID,
1003 osi_LogSaveClientString(smb_logp, (uidp->unp) ? uidp->unp->name: _C(" ")));
1005 lock_ObtainMutex(&uidp->mx);
1006 uidp->flags |= SMB_USERFLAG_DELETE;
1008 * it doesn't get deleted right away
1009 * because the vcp points to it
1012 lock_ReleaseMutex(&uidp->mx);
1015 /* we can't do this. we get logoff messages prior to a session
1016 * disconnect even though it doesn't mean the user is logging out.
1017 * we need to create a new pioctl and EventLogoff handler to set
1018 * SMB_USERNAMEFLAG_LOGOFF.
1020 if (unp && smb_LogoffTokenTransfer) {
1021 lock_ObtainMutex(&unp->mx);
1022 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
1023 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
1024 lock_ReleaseMutex(&unp->mx);
1028 smb_ReleaseUID(uidp);
1031 osi_Log0(smb_logp, "SMB3 user logoffX");
1033 smb_SetSMBDataLength(outp, 0);
1037 #define SMB_SUPPORT_SEARCH_BITS 0x0001
1038 #define SMB_SHARE_IS_IN_DFS 0x0002
1040 /* SMB_COM_TREE_CONNECT_ANDX */
1041 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1044 smb_user_t *uidp = NULL;
1045 unsigned short newTid;
1046 clientchar_t shareName[AFSPATHMAX];
1047 clientchar_t *sharePath;
1050 clientchar_t *slashp;
1051 clientchar_t *pathp;
1052 clientchar_t *passwordp;
1053 clientchar_t *servicep;
1054 cm_user_t *userp = NULL;
1057 osi_Log0(smb_logp, "SMB3 receive tree connect");
1059 /* parse input parameters */
1060 tp = smb_GetSMBData(inp, NULL);
1061 passwordp = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1062 pathp = smb_ParseString(inp, tp, &tp, SMB_STRF_ANSIPATH);
1063 servicep = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1065 slashp = cm_ClientStrRChr(pathp, '\\');
1067 return CM_ERROR_BADSMB;
1069 cm_ClientStrCpy(shareName, lengthof(shareName), slashp+1);
1071 osi_Log3(smb_logp, "Tree connect pathp[%S] shareName[%S] service[%S]",
1072 osi_LogSaveClientString(smb_logp, pathp),
1073 osi_LogSaveClientString(smb_logp, shareName),
1074 osi_LogSaveClientString(smb_logp, servicep));
1076 if (cm_ClientStrCmp(servicep, _C("IPC")) == 0 ||
1077 cm_ClientStrCmp(shareName, _C("IPC$")) == 0) {
1079 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1082 return CM_ERROR_NOIPC;
1086 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1088 userp = smb_GetUserFromUID(uidp);
1090 lock_ObtainMutex(&vcp->mx);
1091 newTid = vcp->tidCounter++;
1092 lock_ReleaseMutex(&vcp->mx);
1094 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1097 if (!cm_ClientStrCmp(shareName, _C("*.")))
1098 cm_ClientStrCpy(shareName, lengthof(shareName), _C("all"));
1099 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1102 smb_ReleaseUID(uidp);
1103 smb_ReleaseTID(tidp, FALSE);
1104 return CM_ERROR_BADSHARENAME;
1107 if (vcp->flags & SMB_VCFLAG_USENT)
1109 int policy = smb_FindShareCSCPolicy(shareName);
1112 DWORD dwAdvertiseDFS = 0, dwSize = sizeof(DWORD);
1114 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1115 0, KEY_QUERY_VALUE, &parmKey);
1116 if (code == ERROR_SUCCESS) {
1117 code = RegQueryValueEx(parmKey, "AdvertiseDFS", NULL, NULL,
1118 (BYTE *)&dwAdvertiseDFS, &dwSize);
1119 if (code != ERROR_SUCCESS)
1121 RegCloseKey (parmKey);
1123 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1124 (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
1128 smb_SetSMBParm(outp, 2, 0);
1132 smb_ReleaseUID(uidp);
1134 lock_ObtainMutex(&tidp->mx);
1135 tidp->userp = userp;
1136 tidp->pathname = sharePath;
1138 tidp->flags |= SMB_TIDFLAG_IPC;
1139 lock_ReleaseMutex(&tidp->mx);
1140 smb_ReleaseTID(tidp, FALSE);
1142 ((smb_t *)outp)->tid = newTid;
1143 ((smb_t *)inp)->tid = newTid;
1144 tp = smb_GetSMBData(outp, NULL);
1148 tp = smb_UnparseString(outp, tp, _C("A:"), &cb_data, SMB_STRF_FORCEASCII);
1149 tp = smb_UnparseString(outp, tp, _C("AFS"), &cb_data, 0);
1150 smb_SetSMBDataLength(outp, cb_data);
1154 tp = smb_UnparseString(outp, tp, _C("IPC"), &cb_data, SMB_STRF_FORCEASCII);
1155 smb_SetSMBDataLength(outp, cb_data);
1158 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1162 /* must be called with global tran lock held */
1163 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1165 smb_tran2Packet_t *tp;
1168 smbp = (smb_t *) inp->data;
1169 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1170 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1176 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1177 int totalParms, int totalData)
1179 smb_tran2Packet_t *tp;
1182 smbp = (smb_t *) inp->data;
1183 tp = malloc(sizeof(*tp));
1184 memset(tp, 0, sizeof(*tp));
1187 tp->curData = tp->curParms = 0;
1188 tp->totalData = totalData;
1189 tp->totalParms = totalParms;
1190 tp->tid = smbp->tid;
1191 tp->mid = smbp->mid;
1192 tp->uid = smbp->uid;
1193 tp->pid = smbp->pid;
1194 tp->res[0] = smbp->res[0];
1195 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1196 if (totalParms != 0)
1197 tp->parmsp = malloc(totalParms);
1199 tp->datap = malloc(totalData);
1200 if (smbp->com == 0x25 || smbp->com == 0x26)
1203 tp->opcode = smb_GetSMBParm(inp, 14);
1206 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1208 if (WANTS_UNICODE(inp) && (vcp->flags & SMB_VCFLAG_USEUNICODE))
1209 tp->flags |= SMB_TRAN2PFLAG_USEUNICODE;
1214 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1215 smb_tran2Packet_t *inp, smb_packet_t *outp,
1216 int totalParms, int totalData)
1218 smb_tran2Packet_t *tp;
1219 unsigned short parmOffset;
1220 unsigned short dataOffset;
1221 unsigned short dataAlign;
1223 tp = malloc(sizeof(*tp));
1224 memset(tp, 0, sizeof(*tp));
1227 tp->curData = tp->curParms = 0;
1228 tp->totalData = totalData;
1229 tp->totalParms = totalParms;
1230 tp->oldTotalParms = totalParms;
1235 tp->res[0] = inp->res[0];
1236 tp->opcode = inp->opcode;
1240 * We calculate where the parameters and data will start.
1241 * This calculation must parallel the calculation in
1242 * smb_SendTran2Packet.
1245 parmOffset = 10*2 + 35;
1246 parmOffset++; /* round to even */
1247 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1249 dataOffset = parmOffset + totalParms;
1250 dataAlign = dataOffset & 2; /* quad-align */
1251 dataOffset += dataAlign;
1252 tp->datap = outp->data + dataOffset;
1257 /* free a tran2 packet */
1258 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1261 smb_ReleaseVC(t2p->vcp);
1264 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1274 while (t2p->stringsp) {
1278 t2p->stringsp = ns->nextp;
1284 clientchar_t *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
1285 char ** chainpp, int flags)
1290 if (!(p->flags & SMB_TRAN2PFLAG_USEUNICODE))
1291 flags |= SMB_STRF_FORCEASCII;
1294 cb = p->totalParms - (inp - (char *)p->parmsp);
1295 if (inp < (char *) p->parmsp ||
1296 inp >= ((char *) p->parmsp) + p->totalParms) {
1297 #ifdef DEBUG_UNICODE
1303 return smb_ParseStringBuf((unsigned char *) p->parmsp, &p->stringsp,
1304 inp, &cb, chainpp, flags);
1307 /* called with a VC, an input packet to respond to, and an error code.
1308 * sends an error response.
1310 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1311 smb_packet_t *tp, long code)
1314 unsigned short errCode;
1315 unsigned char errClass;
1316 unsigned long NTStatus;
1318 if (vcp->flags & SMB_VCFLAG_STATUS32)
1319 smb_MapNTError(code, &NTStatus);
1321 smb_MapCoreError(code, vcp, &errCode, &errClass);
1323 smb_FormatResponsePacket(vcp, NULL, tp);
1324 smbp = (smb_t *) tp;
1326 /* We can handle long names */
1327 if (vcp->flags & SMB_VCFLAG_USENT)
1328 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1330 /* now copy important fields from the tran 2 packet */
1331 smbp->com = t2p->com;
1332 smbp->tid = t2p->tid;
1333 smbp->mid = t2p->mid;
1334 smbp->pid = t2p->pid;
1335 smbp->uid = t2p->uid;
1336 smbp->res[0] = t2p->res[0];
1337 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1338 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1339 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1340 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1341 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1342 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1345 smbp->rcls = errClass;
1346 smbp->errLow = (unsigned char) (errCode & 0xff);
1347 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1351 smb_SendPacket(vcp, tp);
1354 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1357 unsigned short parmOffset;
1358 unsigned short dataOffset;
1359 unsigned short totalLength;
1360 unsigned short dataAlign;
1363 smb_FormatResponsePacket(vcp, NULL, tp);
1364 smbp = (smb_t *) tp;
1366 /* We can handle long names */
1367 if (vcp->flags & SMB_VCFLAG_USENT)
1368 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1370 /* now copy important fields from the tran 2 packet */
1371 smbp->com = t2p->com;
1372 smbp->tid = t2p->tid;
1373 smbp->mid = t2p->mid;
1374 smbp->pid = t2p->pid;
1375 smbp->uid = t2p->uid;
1376 smbp->res[0] = t2p->res[0];
1378 if (t2p->error_code) {
1379 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1380 unsigned long NTStatus;
1382 smb_MapNTError(t2p->error_code, &NTStatus);
1384 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1385 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1386 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1387 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1388 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1391 unsigned short errCode;
1392 unsigned char errClass;
1394 smb_MapCoreError(t2p->error_code, vcp, &errCode, &errClass);
1396 smbp->rcls = errClass;
1397 smbp->errLow = (unsigned char) (errCode & 0xff);
1398 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1402 totalLength = 1 + t2p->totalData + t2p->totalParms;
1404 /* now add the core parameters (tran2 info) to the packet */
1405 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1406 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1407 smb_SetSMBParm(tp, 2, 0); /* reserved */
1408 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1409 parmOffset = 10*2 + 35; /* parm offset in packet */
1410 parmOffset++; /* round to even */
1411 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1412 * hdr, bcc and wct */
1413 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1414 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1415 dataOffset = parmOffset + t2p->oldTotalParms;
1416 dataAlign = dataOffset & 2; /* quad-align */
1417 dataOffset += dataAlign;
1418 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1419 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1420 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1423 datap = smb_GetSMBData(tp, NULL);
1424 *datap++ = 0; /* we rounded to even */
1426 totalLength += dataAlign;
1427 smb_SetSMBDataLength(tp, totalLength);
1429 /* next, send the datagram */
1430 smb_SendPacket(vcp, tp);
1433 /* TRANS_SET_NMPIPE_STATE */
1434 long smb_nmpipeSetState(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1438 int pipeState = 0x0100; /* default */
1439 smb_tran2Packet_t *outp = NULL;
1442 if (p->totalParms > 0)
1443 pipeState = p->parmsp[0];
1445 osi_Log2(smb_logp, "smb_nmpipeSetState for fd[%d] with state[0x%x]", fd, pipeState);
1447 fidp = smb_FindFID(vcp, fd, 0);
1449 osi_Log2(smb_logp, "smb_nmpipeSetState Unknown SMB Fid vcp 0x%p fid %d",
1451 return CM_ERROR_BADFD;
1453 lock_ObtainMutex(&fidp->mx);
1454 if (pipeState & 0x8000)
1455 fidp->flags |= SMB_FID_BLOCKINGPIPE;
1456 if (pipeState & 0x0100)
1457 fidp->flags |= SMB_FID_MESSAGEMODEPIPE;
1458 lock_ReleaseMutex(&fidp->mx);
1460 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 0);
1461 smb_SendTran2Packet(vcp, outp, op);
1462 smb_FreeTran2Packet(outp);
1464 smb_ReleaseFID(fidp);
1469 long smb_nmpipeTransact(smb_vc_t * vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1479 osi_Log3(smb_logp, "smb_nmpipeTransact for fd[%d] %d bytes in, %d max bytes out",
1480 fd, p->totalData, p->maxReturnData);
1482 fidp = smb_FindFID(vcp, fd, 0);
1484 osi_Log2(smb_logp, "smb_nmpipeTransact Unknown SMB Fid vcp 0x%p fid %d",
1486 return CM_ERROR_BADFD;
1488 lock_ObtainMutex(&fidp->mx);
1489 if (fidp->flags & SMB_FID_RPC) {
1492 lock_ReleaseMutex(&fidp->mx);
1495 code = smb_RPCNmpipeTransact(fidp, vcp, p, op);
1496 smb_ReleaseFID(fidp);
1498 /* We only deal with RPC pipes */
1499 osi_Log2(smb_logp, "smb_nmpipeTransact Not a RPC vcp 0x%p fid %d",
1501 code = CM_ERROR_BADFD;
1508 /* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
1509 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1511 smb_tran2Packet_t *asp;
1524 /* We sometimes see 0 word count. What to do? */
1525 if (*inp->wctp == 0) {
1526 osi_Log0(smb_logp, "Transaction2 word count = 0");
1527 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1529 smb_SetSMBDataLength(outp, 0);
1530 smb_SendPacket(vcp, outp);
1534 totalParms = smb_GetSMBParm(inp, 0);
1535 totalData = smb_GetSMBParm(inp, 1);
1537 firstPacket = (inp->inCom == 0x25);
1539 /* find the packet we're reassembling */
1540 lock_ObtainWrite(&smb_globalLock);
1541 asp = smb_FindTran2Packet(vcp, inp);
1543 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1545 lock_ReleaseWrite(&smb_globalLock);
1547 /* now merge in this latest packet; start by looking up offsets */
1549 parmDisp = dataDisp = 0;
1550 parmOffset = smb_GetSMBParm(inp, 10);
1551 dataOffset = smb_GetSMBParm(inp, 12);
1552 parmCount = smb_GetSMBParm(inp, 9);
1553 dataCount = smb_GetSMBParm(inp, 11);
1554 asp->setupCount = smb_GetSMBParmByte(inp, 13);
1555 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1556 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1558 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1559 totalData, dataCount, asp->maxReturnData);
1561 if (asp->setupCount == 2) {
1562 clientchar_t * pname;
1564 asp->pipeCommand = smb_GetSMBParm(inp, 14);
1565 asp->pipeParam = smb_GetSMBParm(inp, 15);
1566 pname = smb_ParseString(inp, inp->wctp + 35, NULL, 0);
1568 asp->name = cm_ClientStrDup(pname);
1571 osi_Log2(smb_logp, " Named Pipe command id [%d] with name [%S]",
1572 asp->pipeCommand, osi_LogSaveClientString(smb_logp, asp->name));
1576 parmDisp = smb_GetSMBParm(inp, 4);
1577 parmOffset = smb_GetSMBParm(inp, 3);
1578 dataDisp = smb_GetSMBParm(inp, 7);
1579 dataOffset = smb_GetSMBParm(inp, 6);
1580 parmCount = smb_GetSMBParm(inp, 2);
1581 dataCount = smb_GetSMBParm(inp, 5);
1583 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1584 parmCount, dataCount);
1587 /* now copy the parms and data */
1588 if ( asp->totalParms > 0 && parmCount != 0 )
1590 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1592 if ( asp->totalData > 0 && dataCount != 0 ) {
1593 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1596 /* account for new bytes */
1597 asp->curData += dataCount;
1598 asp->curParms += parmCount;
1600 /* finally, if we're done, remove the packet from the queue and dispatch it */
1601 if (((asp->totalParms > 0 && asp->curParms > 0)
1602 || asp->setupCount == 2) &&
1603 asp->totalData <= asp->curData &&
1604 asp->totalParms <= asp->curParms) {
1606 /* we've received it all */
1607 lock_ObtainWrite(&smb_globalLock);
1608 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1609 lock_ReleaseWrite(&smb_globalLock);
1611 switch(asp->setupCount) {
1614 rapOp = asp->parmsp[0];
1616 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES &&
1617 smb_rapDispatchTable[rapOp].procp) {
1619 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",
1620 myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1622 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1624 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",
1625 code,vcp,vcp->lana,vcp->lsn);
1628 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]",
1629 rapOp, vcp, vcp->lana, vcp->lsn);
1631 code = CM_ERROR_BADOP;
1637 { /* Named pipe operation */
1638 osi_Log2(smb_logp, "Named Pipe: %s with name [%S]",
1639 myCrt_NmpipeDispatch(asp->pipeCommand),
1640 osi_LogSaveClientString(smb_logp, asp->name));
1642 code = CM_ERROR_BADOP;
1644 switch (asp->pipeCommand) {
1645 case SMB_TRANS_SET_NMPIPE_STATE:
1646 code = smb_nmpipeSetState(vcp, asp, outp);
1649 case SMB_TRANS_RAW_READ_NMPIPE:
1652 case SMB_TRANS_QUERY_NMPIPE_STATE:
1655 case SMB_TRANS_QUERY_NMPIPE_INFO:
1658 case SMB_TRANS_PEEK_NMPIPE:
1661 case SMB_TRANS_TRANSACT_NMPIPE:
1662 code = smb_nmpipeTransact(vcp, asp, outp);
1665 case SMB_TRANS_RAW_WRITE_NMPIPE:
1668 case SMB_TRANS_READ_NMPIPE:
1671 case SMB_TRANS_WRITE_NMPIPE:
1674 case SMB_TRANS_WAIT_NMPIPE:
1677 case SMB_TRANS_CALL_NMPIPE:
1684 code = CM_ERROR_BADOP;
1687 /* if an error is returned, we're supposed to send an error packet,
1688 * otherwise the dispatched function already did the data sending.
1689 * We give dispatched proc the responsibility since it knows how much
1690 * space to allocate.
1693 smb_SendTran2Error(vcp, asp, outp, code);
1696 /* free the input tran 2 packet */
1697 smb_FreeTran2Packet(asp);
1699 else if (firstPacket) {
1700 /* the first packet in a multi-packet request, we need to send an
1701 * ack to get more data.
1703 smb_SetSMBDataLength(outp, 0);
1704 smb_SendPacket(vcp, outp);
1710 /* ANSI versions. */
1712 #pragma pack(push, 1)
1714 typedef struct smb_rap_share_info_0 {
1715 BYTE shi0_netname[13];
1716 } smb_rap_share_info_0_t;
1718 typedef struct smb_rap_share_info_1 {
1719 BYTE shi1_netname[13];
1722 DWORD shi1_remark; /* char *shi1_remark; data offset */
1723 } smb_rap_share_info_1_t;
1725 typedef struct smb_rap_share_info_2 {
1726 BYTE shi2_netname[13];
1729 DWORD shi2_remark; /* char *shi2_remark; data offset */
1730 WORD shi2_permissions;
1732 WORD shi2_current_uses;
1733 DWORD shi2_path; /* char *shi2_path; data offset */
1734 WORD shi2_passwd[9];
1736 } smb_rap_share_info_2_t;
1738 #define SMB_RAP_MAX_SHARES 512
1740 typedef struct smb_rap_share_list {
1743 smb_rap_share_info_0_t * shares;
1744 } smb_rap_share_list_t;
1748 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1749 smb_rap_share_list_t * sp;
1751 if (dep->name[0] == '.' && (!dep->name[1] || (dep->name[1] == '.' && !dep->name[2])))
1752 return 0; /* skip over '.' and '..' */
1754 sp = (smb_rap_share_list_t *) vrockp;
1756 strncpy(sp->shares[sp->cShare].shi0_netname, dep->name, 12);
1757 sp->shares[sp->cShare].shi0_netname[12] = 0;
1761 if (sp->cShare >= sp->maxShares)
1762 return CM_ERROR_STOPNOW;
1767 /* RAP NetShareEnumRequest */
1768 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1770 smb_tran2Packet_t *outp;
1771 unsigned short * tp;
1775 int outParmsTotal; /* total parameter bytes */
1776 int outDataTotal; /* total data bytes */
1779 DWORD allSubmount = 0;
1781 DWORD nRegShares = 0;
1782 DWORD nSharesRet = 0;
1784 HKEY hkSubmount = NULL;
1785 smb_rap_share_info_1_t * shares;
1788 clientchar_t thisShare[AFSPATHMAX];
1792 smb_rap_share_list_t rootShares;
1796 cm_scache_t *rootScp;
1798 tp = p->parmsp + 1; /* skip over function number (always 0) */
1801 clientchar_t * cdescp;
1803 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1804 if (cm_ClientStrCmp(cdescp, _C("WrLeh")))
1805 return CM_ERROR_INVAL;
1806 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1807 if (cm_ClientStrCmp(cdescp, _C("B13BWz")))
1808 return CM_ERROR_INVAL;
1814 if (infoLevel != 1) {
1815 return CM_ERROR_INVAL;
1818 /* We are supposed to use the same ASCII data structure even if
1819 Unicode is negotiated, which ultimately means that the share
1820 names that we return must be at most 13 characters in length,
1821 including the NULL terminator.
1823 The RAP specification states that shares with names longer than
1824 12 characters should not be included in the enumeration.
1825 However, since we support prefix cell references and since many
1826 cell names are going to exceed 12 characters, we lie and send
1827 the first 12 characters.
1830 /* first figure out how many shares there are */
1831 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1832 KEY_QUERY_VALUE, &hkParam);
1833 if (rv == ERROR_SUCCESS) {
1834 len = sizeof(allSubmount);
1835 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1836 (BYTE *) &allSubmount, &len);
1837 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1840 RegCloseKey (hkParam);
1843 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1844 0, KEY_QUERY_VALUE, &hkSubmount);
1845 if (rv == ERROR_SUCCESS) {
1846 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1847 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1848 if (rv != ERROR_SUCCESS)
1854 /* fetch the root shares */
1855 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1856 rootShares.cShare = 0;
1857 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1861 userp = smb_GetTran2User(vcp,p);
1863 thyper.HighPart = 0;
1866 rootScp = cm_RootSCachep(userp, &req);
1867 cm_HoldSCache(rootScp);
1868 cm_ApplyDir(rootScp, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1869 cm_ReleaseSCache(rootScp);
1871 cm_ReleaseUser(userp);
1873 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1875 #define REMARK_LEN 1
1876 outParmsTotal = 8; /* 4 dwords */
1877 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1878 if(outDataTotal > bufsize) {
1879 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1880 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1883 nSharesRet = nShares;
1886 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1888 /* now for the submounts */
1889 shares = (smb_rap_share_info_1_t *) outp->datap;
1890 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1892 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1895 StringCchCopyA(shares[cshare].shi1_netname,
1896 lengthof(shares[cshare].shi1_netname), "all" );
1897 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1898 /* type and pad are zero already */
1904 for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
1905 len = sizeof(thisShare);
1906 rv = RegEnumValueW(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
1907 if (rv == ERROR_SUCCESS &&
1908 cm_ClientStrLen(thisShare) &&
1909 (!allSubmount || cm_ClientStrCmpI(thisShare,_C("all")))) {
1910 cm_ClientStringToUtf8(thisShare, -1, shares[cshare].shi1_netname,
1911 lengthof( shares[cshare].shi1_netname ));
1912 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1913 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1918 nShares--; /* uncount key */
1921 RegCloseKey(hkSubmount);
1924 nonrootShares = cshare;
1926 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1927 /* in case there are collisions with submounts, submounts have
1929 for (j=0; j < nonrootShares; j++)
1930 if (!cm_stricmp_utf8(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1933 if (j < nonrootShares) {
1934 nShares--; /* uncount */
1938 StringCchCopyA(shares[cshare].shi1_netname, lengthof(shares[cshare].shi1_netname),
1939 rootShares.shares[i].shi0_netname);
1940 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1945 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1946 outp->parmsp[1] = 0;
1947 outp->parmsp[2] = cshare;
1948 outp->parmsp[3] = nShares;
1950 outp->totalData = (int)(cstrp - outp->datap);
1951 outp->totalParms = outParmsTotal;
1953 smb_SendTran2Packet(vcp, outp, op);
1954 smb_FreeTran2Packet(outp);
1956 free(rootShares.shares);
1961 /* RAP NetShareGetInfo */
1962 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1964 smb_tran2Packet_t *outp;
1965 unsigned short * tp;
1966 clientchar_t * shareName;
1967 BOOL shareFound = FALSE;
1968 unsigned short infoLevel;
1969 unsigned short bufsize;
1978 cm_scache_t *scp = NULL;
1984 tp = p->parmsp + 1; /* skip over function number (always 1) */
1987 clientchar_t * cdescp;
1989 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1990 if (cm_ClientStrCmp(cdescp, _C("zWrLh")))
1992 return CM_ERROR_INVAL;
1994 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1995 if (cm_ClientStrCmp(cdescp, _C("B13")) &&
1996 cm_ClientStrCmp(cdescp, _C("B13BWz")) &&
1997 cm_ClientStrCmp(cdescp, _C("B13BWzWWWzB9B")))
1999 return CM_ERROR_INVAL;
2001 shareName = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2009 totalData = sizeof(smb_rap_share_info_0_t);
2010 else if(infoLevel == SMB_INFO_STANDARD)
2011 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
2012 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
2013 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
2015 return CM_ERROR_INVAL;
2017 if(!cm_ClientStrCmpI(shareName, _C("all")) || !cm_ClientStrCmp(shareName,_C("*."))) {
2018 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
2019 KEY_QUERY_VALUE, &hkParam);
2020 if (rv == ERROR_SUCCESS) {
2021 len = sizeof(allSubmount);
2022 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
2023 (BYTE *) &allSubmount, &len);
2024 if (rv != ERROR_SUCCESS || allSubmount != 0) {
2027 RegCloseKey (hkParam);
2034 userp = smb_GetTran2User(vcp, p);
2036 osi_Log1(smb_logp,"ReceiveRAPNetShareGetInfo unable to resolve user [%d]", p->uid);
2037 return CM_ERROR_BADSMB;
2039 code = cm_NameI(cm_RootSCachep(userp, &req), shareName,
2040 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
2041 userp, NULL, &req, &scp);
2043 cm_ReleaseSCache(scp);
2046 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
2047 KEY_QUERY_VALUE, &hkSubmount);
2048 if (rv == ERROR_SUCCESS) {
2049 rv = RegQueryValueExW(hkSubmount, shareName, NULL, NULL, NULL, NULL);
2050 if (rv == ERROR_SUCCESS) {
2053 RegCloseKey(hkSubmount);
2059 return CM_ERROR_BADSHARENAME;
2061 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
2062 memset(outp->datap, 0, totalData);
2064 outp->parmsp[0] = 0;
2065 outp->parmsp[1] = 0;
2066 outp->parmsp[2] = totalData;
2068 if (infoLevel == 0) {
2069 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
2070 cm_ClientStringToUtf8(shareName, -1, info->shi0_netname,
2071 lengthof(info->shi0_netname));
2072 } else if(infoLevel == SMB_INFO_STANDARD) {
2073 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
2074 cm_ClientStringToUtf8(shareName, -1, info->shi1_netname, lengthof(info->shi1_netname));
2075 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
2076 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
2077 /* type and pad are already zero */
2078 } else { /* infoLevel==2 */
2079 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
2080 cm_ClientStringToUtf8(shareName, -1, info->shi2_netname, lengthof(info->shi2_netname));
2081 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
2082 info->shi2_permissions = ACCESS_ALL;
2083 info->shi2_max_uses = (unsigned short) -1;
2084 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
2087 outp->totalData = totalData;
2088 outp->totalParms = totalParam;
2090 smb_SendTran2Packet(vcp, outp, op);
2091 smb_FreeTran2Packet(outp);
2096 #pragma pack(push, 1)
2098 typedef struct smb_rap_wksta_info_10 {
2099 DWORD wki10_computername; /*char *wki10_computername;*/
2100 DWORD wki10_username; /* char *wki10_username; */
2101 DWORD wki10_langroup; /* char *wki10_langroup;*/
2102 BYTE wki10_ver_major;
2103 BYTE wki10_ver_minor;
2104 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
2105 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
2106 } smb_rap_wksta_info_10_t;
2110 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2112 smb_tran2Packet_t *outp;
2116 unsigned short * tp;
2119 smb_rap_wksta_info_10_t * info;
2123 tp = p->parmsp + 1; /* Skip over function number */
2126 clientchar_t * cdescp;
2128 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2129 SMB_STRF_FORCEASCII);
2130 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2131 return CM_ERROR_INVAL;
2133 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2134 SMB_STRF_FORCEASCII);
2135 if (cm_ClientStrCmp(cdescp, _C("zzzBBzz")))
2136 return CM_ERROR_INVAL;
2142 if (infoLevel != 10) {
2143 return CM_ERROR_INVAL;
2149 totalData = sizeof(*info) + /* info */
2150 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
2151 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
2152 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
2153 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
2154 1; /* wki10_oth_domains (null)*/
2156 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2158 memset(outp->parmsp,0,totalParams);
2159 memset(outp->datap,0,totalData);
2161 info = (smb_rap_wksta_info_10_t *) outp->datap;
2162 cstrp = (char *) (info + 1);
2164 info->wki10_computername = (DWORD) (cstrp - outp->datap);
2165 StringCbCopyA(cstrp, totalData, smb_localNamep);
2166 cstrp += strlen(cstrp) + 1;
2168 info->wki10_username = (DWORD) (cstrp - outp->datap);
2169 uidp = smb_FindUID(vcp, p->uid, 0);
2171 lock_ObtainMutex(&uidp->mx);
2172 if(uidp->unp && uidp->unp->name)
2173 cm_ClientStringToUtf8(uidp->unp->name, -1,
2174 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2175 lock_ReleaseMutex(&uidp->mx);
2176 smb_ReleaseUID(uidp);
2178 cstrp += strlen(cstrp) + 1;
2180 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
2181 StringCbCopyA(cstrp, totalData - (cstrp - outp->datap)*sizeof(char), "WORKGROUP");
2182 cstrp += strlen(cstrp) + 1;
2184 /* TODO: Not sure what values these should take, but these work */
2185 info->wki10_ver_major = 5;
2186 info->wki10_ver_minor = 1;
2188 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
2189 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
2190 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2191 cstrp += strlen(cstrp) + 1;
2193 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
2194 cstrp ++; /* no other domains */
2196 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
2197 outp->parmsp[2] = outp->totalData;
2198 outp->totalParms = totalParams;
2200 smb_SendTran2Packet(vcp,outp,op);
2201 smb_FreeTran2Packet(outp);
2206 #pragma pack(push, 1)
2208 typedef struct smb_rap_server_info_0 {
2210 } smb_rap_server_info_0_t;
2212 typedef struct smb_rap_server_info_1 {
2214 BYTE sv1_version_major;
2215 BYTE sv1_version_minor;
2217 DWORD sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
2218 } smb_rap_server_info_1_t;
2222 char smb_ServerComment[] = "OpenAFS Client";
2223 int smb_ServerCommentLen = sizeof(smb_ServerComment);
2225 #define SMB_SV_TYPE_SERVER 0x00000002L
2226 #define SMB_SV_TYPE_NT 0x00001000L
2227 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
2229 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2231 smb_tran2Packet_t *outp;
2235 unsigned short * tp;
2238 smb_rap_server_info_0_t * info0;
2239 smb_rap_server_info_1_t * info1;
2242 tp = p->parmsp + 1; /* Skip over function number */
2245 clientchar_t * cdescp;
2247 cdescp = smb_ParseStringT2Parm(p, (unsigned char *) tp, (char **) &tp,
2248 SMB_STRF_FORCEASCII);
2249 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2250 return CM_ERROR_INVAL;
2251 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2252 SMB_STRF_FORCEASCII);
2253 if (cm_ClientStrCmp(cdescp, _C("B16")) ||
2254 cm_ClientStrCmp(cdescp, _C("B16BBDz")))
2255 return CM_ERROR_INVAL;
2261 if (infoLevel != 0 && infoLevel != 1) {
2262 return CM_ERROR_INVAL;
2268 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
2269 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
2271 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2273 memset(outp->parmsp,0,totalParams);
2274 memset(outp->datap,0,totalData);
2276 if (infoLevel == 0) {
2277 info0 = (smb_rap_server_info_0_t *) outp->datap;
2278 cstrp = (char *) (info0 + 1);
2279 StringCchCopyA(info0->sv0_name, lengthof(info0->sv0_name), "AFS");
2280 } else { /* infoLevel == SMB_INFO_STANDARD */
2281 info1 = (smb_rap_server_info_1_t *) outp->datap;
2282 cstrp = (char *) (info1 + 1);
2283 StringCchCopyA(info1->sv1_name, lengthof(info1->sv1_name), "AFS");
2286 SMB_SV_TYPE_SERVER |
2288 SMB_SV_TYPE_SERVER_NT;
2290 info1->sv1_version_major = 5;
2291 info1->sv1_version_minor = 1;
2292 info1->sv1_comment_or_master_browser = (DWORD) (cstrp - outp->datap);
2294 StringCbCopyA(cstrp, smb_ServerCommentLen, smb_ServerComment);
2296 cstrp += smb_ServerCommentLen / sizeof(char);
2299 totalData = (DWORD)(cstrp - outp->datap);
2300 outp->totalData = min(bufsize,totalData); /* actual data size */
2301 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
2302 outp->parmsp[2] = totalData;
2303 outp->totalParms = totalParams;
2305 smb_SendTran2Packet(vcp,outp,op);
2306 smb_FreeTran2Packet(outp);
2311 /* SMB_COM_TRANSACTION2 and SMB_COM_TRANSACTION2_SECONDARY */
2312 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2314 smb_tran2Packet_t *asp;
2325 DWORD oldTime, newTime;
2327 /* We sometimes see 0 word count. What to do? */
2328 if (*inp->wctp == 0) {
2329 osi_Log0(smb_logp, "Transaction2 word count = 0");
2330 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
2332 smb_SetSMBDataLength(outp, 0);
2333 smb_SendPacket(vcp, outp);
2337 totalParms = smb_GetSMBParm(inp, 0);
2338 totalData = smb_GetSMBParm(inp, 1);
2340 firstPacket = (inp->inCom == 0x32);
2342 /* find the packet we're reassembling */
2343 lock_ObtainWrite(&smb_globalLock);
2344 asp = smb_FindTran2Packet(vcp, inp);
2346 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
2348 lock_ReleaseWrite(&smb_globalLock);
2350 /* now merge in this latest packet; start by looking up offsets */
2352 parmDisp = dataDisp = 0;
2353 parmOffset = smb_GetSMBParm(inp, 10);
2354 dataOffset = smb_GetSMBParm(inp, 12);
2355 parmCount = smb_GetSMBParm(inp, 9);
2356 dataCount = smb_GetSMBParm(inp, 11);
2357 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2358 asp->maxReturnData = smb_GetSMBParm(inp, 3);
2360 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2361 totalData, dataCount, asp->maxReturnData);
2364 parmDisp = smb_GetSMBParm(inp, 4);
2365 parmOffset = smb_GetSMBParm(inp, 3);
2366 dataDisp = smb_GetSMBParm(inp, 7);
2367 dataOffset = smb_GetSMBParm(inp, 6);
2368 parmCount = smb_GetSMBParm(inp, 2);
2369 dataCount = smb_GetSMBParm(inp, 5);
2371 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2372 parmCount, dataCount);
2375 /* now copy the parms and data */
2376 if ( asp->totalParms > 0 && parmCount != 0 )
2378 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2380 if ( asp->totalData > 0 && dataCount != 0 ) {
2381 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2384 /* account for new bytes */
2385 asp->curData += dataCount;
2386 asp->curParms += parmCount;
2388 /* finally, if we're done, remove the packet from the queue and dispatch it */
2389 if (asp->totalParms > 0 &&
2390 asp->curParms > 0 &&
2391 asp->totalData <= asp->curData &&
2392 asp->totalParms <= asp->curParms) {
2393 /* we've received it all */
2394 lock_ObtainWrite(&smb_globalLock);
2395 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2396 lock_ReleaseWrite(&smb_globalLock);
2398 oldTime = GetTickCount();
2400 /* now dispatch it */
2401 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2402 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2403 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2406 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2407 code = CM_ERROR_BADOP;
2410 /* if an error is returned, we're supposed to send an error packet,
2411 * otherwise the dispatched function already did the data sending.
2412 * We give dispatched proc the responsibility since it knows how much
2413 * space to allocate.
2416 smb_SendTran2Error(vcp, asp, outp, code);
2419 newTime = GetTickCount();
2420 if (newTime - oldTime > 45000) {
2423 clientchar_t *treepath = NULL; /* do not free */
2424 clientchar_t *pathname = NULL;
2425 cm_fid_t afid = {0,0,0,0,0};
2427 uidp = smb_FindUID(vcp, asp->uid, 0);
2428 smb_LookupTIDPath(vcp, asp->tid, &treepath);
2429 fidp = smb_FindFID(vcp, inp->fid, 0);
2432 lock_ObtainMutex(&fidp->mx);
2433 if (fidp->NTopen_pathp)
2434 pathname = fidp->NTopen_pathp;
2436 afid = fidp->scp->fid;
2438 if (inp->stringsp->wdata)
2439 pathname = inp->stringsp->wdata;
2442 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)",
2443 myCrt_2Dispatch(asp->opcode), newTime - oldTime,
2444 asp->uid, uidp ? uidp->unp->name : NULL,
2445 asp->pid, asp->mid, asp->tid,
2448 afid.cell, afid.volume, afid.vnode, afid.unique);
2451 lock_ReleaseMutex(&fidp->mx);
2454 smb_ReleaseUID(uidp);
2456 smb_ReleaseFID(fidp);
2459 /* free the input tran 2 packet */
2460 smb_FreeTran2Packet(asp);
2462 else if (firstPacket) {
2463 /* the first packet in a multi-packet request, we need to send an
2464 * ack to get more data.
2466 smb_SetSMBDataLength(outp, 0);
2467 smb_SendPacket(vcp, outp);
2474 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2476 clientchar_t *pathp;
2477 smb_tran2Packet_t *outp;
2482 cm_scache_t *dscp; /* dir we're dealing with */
2483 cm_scache_t *scp; /* file we're creating */
2487 clientchar_t *lastNamep;
2494 int parmSlot; /* which parm we're dealing with */
2495 long returnEALength;
2496 clientchar_t *tidPathp;
2499 BOOL is_rpc = FALSE;
2500 BOOL is_ipc = FALSE;
2506 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2507 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2509 openFun = p->parmsp[6]; /* open function */
2510 excl = ((openFun & 3) == 0);
2511 trunc = ((openFun & 3) == 2); /* truncate it */
2512 openMode = (p->parmsp[1] & 0x7);
2513 openAction = 0; /* tracks what we did */
2515 attributes = p->parmsp[3];
2516 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2518 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
2521 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2523 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2524 if (code == CM_ERROR_TIDIPC) {
2526 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2529 spacep = cm_GetSpace();
2530 /* smb_StripLastComponent will strip "::$DATA" if present */
2531 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2535 /* special case magic file name for receiving IOCTL requests
2536 * (since IOCTL calls themselves aren't getting through).
2538 (cm_ClientStrCmpI(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
2540 /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional)*/
2541 (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
2543 unsigned short file_type = 0;
2544 unsigned short device_state = 0;
2546 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2549 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
2550 osi_Log2(smb_logp, "smb_ReceiveTran2Open Creating RPC Fid [%d] code [%d]",
2553 smb_ReleaseFID(fidp);
2554 smb_FreeTran2Packet(outp);
2555 osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
2559 smb_SetupIoctlFid(fidp, spacep);
2560 osi_Log1(smb_logp, "smb_ReceiveTran2Open Creating IOCTL Fid [%d]", fidp->fid);
2563 /* copy out remainder of the parms */
2565 outp->parmsp[parmSlot++] = fidp->fid;
2567 outp->parmsp[parmSlot++] = 0; /* attrs */
2568 outp->parmsp[parmSlot++] = 0; /* mod time */
2569 outp->parmsp[parmSlot++] = 0;
2570 outp->parmsp[parmSlot++] = 0; /* len */
2571 outp->parmsp[parmSlot++] = 0x7fff;
2572 outp->parmsp[parmSlot++] = openMode;
2573 outp->parmsp[parmSlot++] = file_type;
2574 outp->parmsp[parmSlot++] = device_state;
2576 /* and the final "always present" stuff */
2577 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2578 /* next write out the "unique" ID */
2579 outp->parmsp[parmSlot++] = 0x1234;
2580 outp->parmsp[parmSlot++] = 0x5678;
2581 outp->parmsp[parmSlot++] = 0;
2582 if (returnEALength) {
2583 outp->parmsp[parmSlot++] = 0;
2584 outp->parmsp[parmSlot++] = 0;
2587 outp->totalData = 0;
2588 outp->totalParms = parmSlot * 2;
2590 smb_SendTran2Packet(vcp, outp, op);
2592 smb_FreeTran2Packet(outp);
2594 /* and clean up fid reference */
2595 smb_ReleaseFID(fidp);
2601 osi_Log1(smb_logp, "Tran2Open rejecting IPC TID vcp %p", vcp);
2602 smb_FreeTran2Packet(outp);
2603 return CM_ERROR_BADFD;
2607 if (!cm_IsValidClientString(pathp)) {
2609 clientchar_t * hexp;
2611 hexp = cm_GetRawCharsAlloc(pathp, -1);
2612 osi_Log1(smb_logp, "Tran2Open rejecting invalid name. [%S]",
2613 osi_LogSaveClientString(smb_logp, hexp));
2617 osi_Log0(smb_logp, "Tran2Open rejecting invalid name");
2619 smb_FreeTran2Packet(outp);
2620 return CM_ERROR_BADNTFILENAME;
2623 #ifdef DEBUG_VERBOSE
2625 char *hexp, *asciip;
2626 asciip = (lastNamep ? lastNamep : pathp);
2627 hexp = osi_HexifyString( asciip );
2628 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2633 userp = smb_GetTran2User(vcp, p);
2634 /* In the off chance that userp is NULL, we log and abandon */
2636 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2637 smb_FreeTran2Packet(outp);
2638 return CM_ERROR_BADSMB;
2642 code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
2643 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2644 userp, tidPathp, &req, &scp);
2646 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
2647 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2648 userp, tidPathp, &req, &dscp);
2649 cm_FreeSpace(spacep);
2652 cm_ReleaseUser(userp);
2653 smb_FreeTran2Packet(outp);
2658 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2659 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2660 (clientchar_t*) spacep->data);
2661 cm_ReleaseSCache(dscp);
2662 cm_ReleaseUser(userp);
2663 smb_FreeTran2Packet(outp);
2664 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2665 return CM_ERROR_PATH_NOT_COVERED;
2667 return CM_ERROR_NOSUCHPATH;
2669 #endif /* DFS_SUPPORT */
2671 /* otherwise, scp points to the parent directory. Do a lookup,
2672 * and truncate the file if we find it, otherwise we create the
2679 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2681 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2682 cm_ReleaseSCache(dscp);
2683 cm_ReleaseUser(userp);
2684 smb_FreeTran2Packet(outp);
2688 /* macintosh is expensive to program for it */
2689 cm_FreeSpace(spacep);
2692 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2693 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2694 cm_ReleaseSCache(scp);
2695 cm_ReleaseUser(userp);
2696 smb_FreeTran2Packet(outp);
2697 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2698 return CM_ERROR_PATH_NOT_COVERED;
2700 return CM_ERROR_NOSUCHPATH;
2702 #endif /* DFS_SUPPORT */
2705 /* if we get here, if code is 0, the file exists and is represented by
2706 * scp. Otherwise, we have to create it.
2709 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2712 cm_ReleaseSCache(dscp);
2713 cm_ReleaseSCache(scp);
2714 cm_ReleaseUser(userp);
2715 smb_FreeTran2Packet(outp);
2720 /* oops, file shouldn't be there */
2722 cm_ReleaseSCache(dscp);
2723 cm_ReleaseSCache(scp);
2724 cm_ReleaseUser(userp);
2725 smb_FreeTran2Packet(outp);
2726 return CM_ERROR_EXISTS;
2730 setAttr.mask = CM_ATTRMASK_LENGTH;
2731 setAttr.length.LowPart = 0;
2732 setAttr.length.HighPart = 0;
2733 code = cm_SetAttr(scp, &setAttr, userp, &req);
2734 openAction = 3; /* truncated existing file */
2737 openAction = 1; /* found existing file */
2739 else if (!(openFun & 0x10)) {
2740 /* don't create if not found */
2742 cm_ReleaseSCache(dscp);
2743 osi_assertx(scp == NULL, "null cm_scache_t");
2744 cm_ReleaseUser(userp);
2745 smb_FreeTran2Packet(outp);
2746 return CM_ERROR_NOSUCHFILE;
2749 osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2750 openAction = 2; /* created file */
2751 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2752 cm_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2753 smb_SetInitialModeBitsForFile(attributes, &setAttr);
2755 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2759 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2760 smb_NotifyChange(FILE_ACTION_ADDED,
2761 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2762 dscp, lastNamep, NULL, TRUE);
2763 } else if (!excl && code == CM_ERROR_EXISTS) {
2764 /* not an exclusive create, and someone else tried
2765 * creating it already, then we open it anyway. We
2766 * don't bother retrying after this, since if this next
2767 * fails, that means that the file was deleted after we
2768 * started this call.
2770 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2774 setAttr.mask = CM_ATTRMASK_LENGTH;
2775 setAttr.length.LowPart = 0;
2776 setAttr.length.HighPart = 0;
2777 code = cm_SetAttr(scp, &setAttr, userp,
2780 } /* lookup succeeded */
2784 /* we don't need this any longer */
2786 cm_ReleaseSCache(dscp);
2789 /* something went wrong creating or truncating the file */
2791 cm_ReleaseSCache(scp);
2792 cm_ReleaseUser(userp);
2793 smb_FreeTran2Packet(outp);
2797 /* make sure we're about to open a file */
2798 if (scp->fileType != CM_SCACHETYPE_FILE) {
2800 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2801 cm_scache_t * targetScp = 0;
2802 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2804 /* we have a more accurate file to use (the
2805 * target of the symbolic link). Otherwise,
2806 * we'll just use the symlink anyway.
2808 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2810 cm_ReleaseSCache(scp);
2814 if (scp->fileType != CM_SCACHETYPE_FILE) {
2815 cm_ReleaseSCache(scp);
2816 cm_ReleaseUser(userp);
2817 smb_FreeTran2Packet(outp);
2818 return CM_ERROR_ISDIR;
2822 /* now all we have to do is open the file itself */
2823 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2824 osi_assertx(fidp, "null smb_fid_t");
2827 lock_ObtainMutex(&fidp->mx);
2828 /* save a pointer to the vnode */
2829 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2831 lock_ObtainWrite(&scp->rw);
2832 scp->flags |= CM_SCACHEFLAG_SMB_FID;
2833 lock_ReleaseWrite(&scp->rw);
2836 fidp->userp = userp;
2838 /* compute open mode */
2840 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
2841 if (openMode == 1 || openMode == 2)
2842 fidp->flags |= SMB_FID_OPENWRITE;
2844 /* remember that the file was newly created */
2846 fidp->flags |= SMB_FID_CREATED;
2848 lock_ReleaseMutex(&fidp->mx);
2850 smb_ReleaseFID(fidp);
2852 cm_Open(scp, 0, userp);
2854 /* copy out remainder of the parms */
2856 outp->parmsp[parmSlot++] = fidp->fid;
2857 lock_ObtainRead(&scp->rw);
2859 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2860 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2861 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2862 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2863 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2864 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2865 outp->parmsp[parmSlot++] = openMode;
2866 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2867 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2869 /* and the final "always present" stuff */
2870 outp->parmsp[parmSlot++] = openAction;
2871 /* next write out the "unique" ID */
2872 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2873 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2874 outp->parmsp[parmSlot++] = 0;
2875 if (returnEALength) {
2876 outp->parmsp[parmSlot++] = 0;
2877 outp->parmsp[parmSlot++] = 0;
2879 lock_ReleaseRead(&scp->rw);
2880 outp->totalData = 0; /* total # of data bytes */
2881 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2883 smb_SendTran2Packet(vcp, outp, op);
2885 smb_FreeTran2Packet(outp);
2887 cm_ReleaseUser(userp);
2888 /* leave scp held since we put it in fidp->scp */
2892 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2895 unsigned short infolevel;
2897 infolevel = p->parmsp[0];
2899 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2901 return CM_ERROR_BAD_LEVEL;
2904 /* TRANS2_QUERY_FS_INFORMATION */
2905 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2907 smb_tran2Packet_t *outp;
2908 smb_tran2QFSInfo_t qi;
2912 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2914 switch (p->parmsp[0]) {
2915 case SMB_INFO_ALLOCATION:
2917 responseSize = sizeof(qi.u.allocInfo);
2919 qi.u.allocInfo.FSID = 0;
2920 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2921 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2922 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2923 qi.u.allocInfo.bytesPerSector = 1024;
2926 case SMB_INFO_VOLUME:
2928 qi.u.volumeInfo.vsn = 1234; /* Volume serial number */
2929 qi.u.volumeInfo.vnCount = 3; /* Number of characters in label (AFS\0)*/
2931 /* we're supposed to pad it out with zeroes to the end */
2932 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2933 smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
2935 responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
2938 case SMB_QUERY_FS_VOLUME_INFO:
2939 /* FS volume info */
2940 responseSize = sizeof(qi.u.FSvolumeInfo);
2943 FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
2944 memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
2947 qi.u.FSvolumeInfo.vsn = 1234;
2948 qi.u.FSvolumeInfo.vnCount = 6; /* This is always in Unicode */
2949 memset(&qi.u.FSvolumeInfo.label, 0, sizeof(qi.u.FSvolumeInfo.label));
2950 memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
2953 case SMB_QUERY_FS_SIZE_INFO:
2955 responseSize = sizeof(qi.u.FSsizeInfo);
2957 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2958 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2959 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2960 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2961 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2962 qi.u.FSsizeInfo.bytesPerSector = 1024;
2965 case SMB_QUERY_FS_DEVICE_INFO:
2966 /* FS device info */
2967 responseSize = sizeof(qi.u.FSdeviceInfo);
2969 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2970 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2973 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2974 /* FS attribute info */
2976 /* attributes, defined in WINNT.H:
2977 * FILE_CASE_SENSITIVE_SEARCH 0x1
2978 * FILE_CASE_PRESERVED_NAMES 0x2
2979 * FILE_UNICODE_ON_DISK 0x4
2980 * FILE_VOLUME_QUOTAS 0x10
2981 * <no name defined> 0x4000
2982 * If bit 0x4000 is not set, Windows 95 thinks
2983 * we can't handle long (non-8.3) names,
2984 * despite our protestations to the contrary.
2986 qi.u.FSattributeInfo.attributes = 0x4003;
2987 /* The maxCompLength is supposed to be in bytes */
2989 qi.u.FSattributeInfo.attributes |= 0x04;
2991 qi.u.FSattributeInfo.maxCompLength = 255;
2992 smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
2993 qi.u.FSattributeInfo.FSnameLength = sz;
2996 sizeof(qi.u.FSattributeInfo.attributes) +
2997 sizeof(qi.u.FSattributeInfo.maxCompLength) +
2998 sizeof(qi.u.FSattributeInfo.FSnameLength) +
3003 case SMB_INFO_UNIX: /* CIFS Unix Info */
3004 case SMB_INFO_MACOS: /* Mac FS Info */
3006 return CM_ERROR_BADOP;
3009 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
3011 /* copy out return data, and set corresponding sizes */
3012 outp->totalParms = 0;
3013 outp->totalData = responseSize;
3014 memcpy(outp->datap, &qi, responseSize);
3016 /* send and free the packets */
3017 smb_SendTran2Packet(vcp, outp, op);
3018 smb_FreeTran2Packet(outp);
3023 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3025 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
3026 return CM_ERROR_BADOP;
3029 struct smb_ShortNameRock {
3030 clientchar_t *maskp;
3032 clientchar_t *shortName;
3033 size_t shortNameLen;
3036 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
3039 struct smb_ShortNameRock *rockp;
3040 normchar_t normName[MAX_PATH];
3041 clientchar_t *shortNameEnd;
3045 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t)) == 0) {
3046 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
3047 osi_LogSaveString(smb_logp, dep->name));
3051 /* compare both names and vnodes, though probably just comparing vnodes
3052 * would be safe enough.
3054 if (cm_NormStrCmpI(normName, rockp->maskp) != 0)
3056 if (ntohl(dep->fid.vnode) != rockp->vnode)
3059 /* This is the entry */
3060 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
3061 rockp->shortNameLen = shortNameEnd - rockp->shortName;
3063 return CM_ERROR_STOPNOW;
3066 long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
3067 clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
3069 struct smb_ShortNameRock rock;
3070 clientchar_t *lastNamep;
3073 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
3077 spacep = cm_GetSpace();
3078 /* smb_StripLastComponent will strip "::$DATA" if present */
3079 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
3081 code = cm_NameI(cm_RootSCachep(userp, reqp), spacep->wdata,
3082 caseFold, userp, tidPathp,
3084 cm_FreeSpace(spacep);
3089 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3090 cm_ReleaseSCache(dscp);
3091 cm_ReleaseUser(userp);
3095 return CM_ERROR_PATH_NOT_COVERED;
3097 #endif /* DFS_SUPPORT */
3099 if (!lastNamep) lastNamep = pathp;
3102 thyper.HighPart = 0;
3103 rock.shortName = shortName;
3105 rock.maskp = lastNamep;
3106 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
3108 cm_ReleaseSCache(dscp);
3111 return CM_ERROR_NOSUCHFILE;
3112 if (code == CM_ERROR_STOPNOW) {
3113 *shortNameLenp = rock.shortNameLen;
3119 /* TRANS2_QUERY_PATH_INFORMATION */
3120 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3122 smb_tran2Packet_t *outp;
3125 unsigned short infoLevel;
3126 smb_tran2QPathInfo_t qpi;
3128 unsigned short attributes;
3129 unsigned long extAttributes;
3130 clientchar_t shortName[13];
3134 cm_scache_t *scp, *dscp;
3135 int scp_rw_held = 0;
3138 clientchar_t *pathp;
3139 clientchar_t *tidPathp;
3140 clientchar_t *lastComp;
3145 infoLevel = p->parmsp[0];
3146 if (infoLevel == SMB_INFO_IS_NAME_VALID)
3148 else if (infoLevel == SMB_INFO_STANDARD)
3149 responseSize = sizeof(qpi.u.QPstandardInfo);
3150 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
3151 responseSize = sizeof(qpi.u.QPeaSizeInfo);
3152 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3153 responseSize = sizeof(qpi.u.QPfileBasicInfo);
3154 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3155 responseSize = sizeof(qpi.u.QPfileStandardInfo);
3156 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3157 responseSize = sizeof(qpi.u.QPfileEaInfo);
3158 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3159 responseSize = sizeof(qpi.u.QPfileNameInfo);
3160 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
3161 responseSize = sizeof(qpi.u.QPfileAllInfo);
3162 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
3163 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
3164 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO)
3165 responseSize = sizeof(qpi.u.QPfileStreamInfo);
3167 osi_Log2(smb_logp, "Bad Tran2QPathInfo op 0x%x infolevel 0x%x",
3168 p->opcode, infoLevel);
3169 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3172 memset(&qpi, 0, sizeof(qpi));
3174 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3175 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path \"%S\"", infoLevel,
3176 osi_LogSaveClientString(smb_logp, pathp));
3178 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3180 if (infoLevel > 0x100)
3181 outp->totalParms = 2;
3183 outp->totalParms = 0;
3185 /* now, if we're at infoLevel 6, we're only being asked to check
3186 * the syntax, so we just OK things now. In particular, we're *not*
3187 * being asked to verify anything about the state of any parent dirs.
3189 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
3190 smb_SendTran2Packet(vcp, outp, opx);
3191 smb_FreeTran2Packet(outp);
3195 userp = smb_GetTran2User(vcp, p);
3197 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
3198 smb_FreeTran2Packet(outp);
3199 return CM_ERROR_BADSMB;
3202 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3204 osi_Log1(smb_logp, "ReceiveTran2QPathInfo tid path lookup failure 0x%x", code);
3205 cm_ReleaseUser(userp);
3206 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
3207 smb_FreeTran2Packet(outp);
3211 osi_Log1(smb_logp, "T2 QPathInfo tidPathp \"%S\"",
3212 osi_LogSaveClientString(smb_logp, tidPathp));
3215 * XXX Strange hack XXX
3217 * As of Patch 7 (13 January 98), we are having the following problem:
3218 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3219 * requests to look up "desktop.ini" in all the subdirectories.
3220 * This can cause zillions of timeouts looking up non-existent cells
3221 * and volumes, especially in the top-level directory.
3223 * We have not found any way to avoid this or work around it except
3224 * to explicitly ignore the requests for mount points that haven't
3225 * yet been evaluated and for directories that haven't yet been
3228 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3229 spacep = cm_GetSpace();
3230 /* smb_StripLastComponent will strip "::$DATA" if present */
3231 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3232 #ifndef SPECIAL_FOLDERS
3233 /* Make sure that lastComp is not NULL */
3235 if (cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
3236 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
3240 userp, tidPathp, &req, &dscp);
3243 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3244 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3246 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3247 code = CM_ERROR_PATH_NOT_COVERED;
3249 code = CM_ERROR_NOSUCHPATH;
3251 #endif /* DFS_SUPPORT */
3252 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3253 code = CM_ERROR_NOSUCHFILE;
3254 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3255 cm_buf_t *bp = buf_Find(dscp, &hzero);
3261 code = CM_ERROR_NOSUCHFILE;
3263 cm_ReleaseSCache(dscp);
3265 cm_FreeSpace(spacep);
3266 cm_ReleaseUser(userp);
3267 smb_SendTran2Error(vcp, p, opx, code);
3268 smb_FreeTran2Packet(outp);
3274 #endif /* SPECIAL_FOLDERS */
3276 cm_FreeSpace(spacep);
3279 /* now do namei and stat, and copy out the info */
3280 code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
3281 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3284 cm_ReleaseUser(userp);
3285 smb_SendTran2Error(vcp, p, opx, code);
3286 smb_FreeTran2Packet(outp);
3291 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3292 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3293 cm_ReleaseSCache(scp);
3294 cm_ReleaseUser(userp);
3295 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3296 code = CM_ERROR_PATH_NOT_COVERED;
3298 code = CM_ERROR_NOSUCHPATH;
3299 smb_SendTran2Error(vcp, p, opx, code);
3300 smb_FreeTran2Packet(outp);
3303 #endif /* DFS_SUPPORT */
3305 lock_ObtainWrite(&scp->rw);
3307 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3308 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3312 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3314 lock_ConvertWToR(&scp->rw);
3319 /* now we have the status in the cache entry, and everything is locked.
3320 * Marshall the output data.
3322 /* for info level 108, figure out short name */
3323 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3324 code = cm_GetShortName(pathp, userp, &req,
3325 tidPathp, scp->fid.vnode, shortName,
3331 smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
3332 qpi.u.QPfileAltNameInfo.fileNameLength = len;
3333 responseSize = sizeof(unsigned long) + len;
3335 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3336 smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3337 qpi.u.QPfileNameInfo.fileNameLength = len;
3338 responseSize = sizeof(unsigned long) + len;
3340 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3341 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3342 qpi.u.QPstandardInfo.creationDateTime = dosTime;
3343 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3344 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3345 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3346 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3347 attributes = smb_Attributes(scp);
3348 qpi.u.QPstandardInfo.attributes = attributes;
3349 qpi.u.QPstandardInfo.eaSize = 0;
3351 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3352 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3353 qpi.u.QPfileBasicInfo.creationTime = ft;
3354 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3355 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3356 qpi.u.QPfileBasicInfo.changeTime = ft;
3357 extAttributes = smb_ExtAttributes(scp);
3358 qpi.u.QPfileBasicInfo.attributes = extAttributes;
3359 qpi.u.QPfileBasicInfo.reserved = 0;
3361 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3364 lock_ReleaseRead(&scp->rw);
3366 fidp = smb_FindFIDByScache(vcp, scp);
3368 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3369 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3370 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3371 qpi.u.QPfileStandardInfo.directory =
3372 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3373 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3374 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3375 qpi.u.QPfileStandardInfo.reserved = 0;
3378 lock_ObtainMutex(&fidp->mx);
3379 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3380 lock_ReleaseMutex(&fidp->mx);
3381 smb_ReleaseFID(fidp);
3383 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3385 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3386 qpi.u.QPfileEaInfo.eaSize = 0;
3388 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3391 lock_ReleaseRead(&scp->rw);
3393 fidp = smb_FindFIDByScache(vcp, scp);
3395 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3396 qpi.u.QPfileAllInfo.creationTime = ft;
3397 qpi.u.QPfileAllInfo.lastAccessTime = ft;
3398 qpi.u.QPfileAllInfo.lastWriteTime = ft;
3399 qpi.u.QPfileAllInfo.changeTime = ft;
3400 extAttributes = smb_ExtAttributes(scp);
3401 qpi.u.QPfileAllInfo.attributes = extAttributes;
3402 qpi.u.QPfileAllInfo.allocationSize = scp->length;
3403 qpi.u.QPfileAllInfo.endOfFile = scp->length;
3404 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3405 qpi.u.QPfileAllInfo.deletePending = 0;
3406 qpi.u.QPfileAllInfo.directory =
3407 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3408 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3409 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3410 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.vnode;
3411 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.unique;
3412 qpi.u.QPfileAllInfo.eaSize = 0;
3413 qpi.u.QPfileAllInfo.accessFlags = 0;
3415 lock_ObtainMutex(&fidp->mx);
3416 if (fidp->flags & SMB_FID_OPENDELETE)
3417 qpi.u.QPfileAllInfo.accessFlags |= DELETE;
3418 if (fidp->flags & SMB_FID_OPENREAD_LISTDIR)
3419 qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_READ|AFS_ACCESS_EXECUTE;
3420 if (fidp->flags & SMB_FID_OPENWRITE)
3421 qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_WRITE;
3422 if (fidp->flags & SMB_FID_DELONCLOSE)
3423 qpi.u.QPfileAllInfo.deletePending = 1;
3424 lock_ReleaseMutex(&fidp->mx);
3425 smb_ReleaseFID(fidp);
3427 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.cell;
3428 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.volume;
3429 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3430 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3431 qpi.u.QPfileAllInfo.mode = 0;
3432 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3434 smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3435 qpi.u.QPfileAllInfo.fileNameLength = len;
3436 responseSize -= (sizeof(qpi.u.QPfileAllInfo.fileName) - len);
3438 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO) {
3440 /* For now we have no streams */
3441 qpi.u.QPfileStreamInfo.nextEntryOffset = 0;
3442 if (scp->fileType == CM_SCACHETYPE_FILE) {
3443 qpi.u.QPfileStreamInfo.streamSize = scp->length;
3444 qpi.u.QPfileStreamInfo.streamAllocationSize = scp->length;
3445 smb_UnparseString(opx, qpi.u.QPfileStreamInfo.fileName, L"::$DATA", &len, SMB_STRF_IGNORENUL);
3446 qpi.u.QPfileStreamInfo.streamNameLength = len;
3447 responseSize -= (sizeof(qpi.u.QPfileStreamInfo.fileName) - len);
3449 qpi.u.QPfileStreamInfo.streamSize.QuadPart = 0;
3450 qpi.u.QPfileStreamInfo.streamAllocationSize.QuadPart = 0;
3451 smb_UnparseString(opx, qpi.u.QPfileStreamInfo.fileName, L"", &len, SMB_STRF_IGNORENUL);
3452 qpi.u.QPfileStreamInfo.streamNameLength = 0;
3456 outp->totalData = responseSize;
3458 /* send and free the packets */
3460 switch (scp_rw_held) {
3462 lock_ReleaseRead(&scp->rw);
3465 lock_ReleaseWrite(&scp->rw);
3469 cm_ReleaseSCache(scp);
3470 cm_ReleaseUser(userp);
3472 memcpy(outp->datap, &qpi, responseSize);
3473 smb_SendTran2Packet(vcp, outp, opx);
3475 smb_SendTran2Error(vcp, p, opx, code);
3477 smb_FreeTran2Packet(outp);
3482 /* TRANS2_SET_PATH_INFORMATION */
3483 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3486 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
3487 return CM_ERROR_BADOP;
3490 unsigned short infoLevel;
3491 clientchar_t * pathp;
3492 smb_tran2Packet_t *outp;
3493 smb_tran2QPathInfo_t *spi;
3495 cm_scache_t *scp, *dscp;
3498 clientchar_t *tidPathp;
3499 clientchar_t *lastComp;
3503 infoLevel = p->parmsp[0];
3504 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
3505 if (infoLevel != SMB_INFO_STANDARD &&
3506 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
3507 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
3508 osi_Log2(smb_logp, "Bad Tran2SetPathInfo op 0x%x infolevel 0x%x",
3509 p->opcode, infoLevel);
3510 smb_SendTran2Error(vcp, p, opx,
3511 infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3515 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3517 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
3518 osi_LogSaveClientString(smb_logp, pathp));
3520 userp = smb_GetTran2User(vcp, p);
3522 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3523 code = CM_ERROR_BADSMB;
3527 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3528 if (code == CM_ERROR_TIDIPC) {
3529 /* Attempt to use a TID allocated for IPC. The client
3530 * is probably looking for DCE RPC end points which we
3531 * don't support OR it could be looking to make a DFS
3534 osi_Log0(smb_logp, "Tran2Open received IPC TID");
3535 cm_ReleaseUser(userp);
3536 return CM_ERROR_NOSUCHPATH;
3540 * XXX Strange hack XXX
3542 * As of Patch 7 (13 January 98), we are having the following problem:
3543 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3544 * requests to look up "desktop.ini" in all the subdirectories.
3545 * This can cause zillions of timeouts looking up non-existent cells
3546 * and volumes, especially in the top-level directory.
3548 * We have not found any way to avoid this or work around it except
3549 * to explicitly ignore the requests for mount points that haven't
3550 * yet been evaluated and for directories that haven't yet been
3553 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3554 spacep = cm_GetSpace();
3555 /* smb_StripLastComponent will strip "::$DATA" if present */
3556 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3557 #ifndef SPECIAL_FOLDERS
3558 /* Make sure that lastComp is not NULL */
3560 if (cm_ClientStrCmpI(lastComp, _C("\\desktop.ini")) == 0) {
3561 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
3565 userp, tidPathp, &req, &dscp);
3568 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3569 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3571 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3572 code = CM_ERROR_PATH_NOT_COVERED;
3574 code = CM_ERROR_NOSUCHPATH;
3576 #endif /* DFS_SUPPORT */
3577 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3578 code = CM_ERROR_NOSUCHFILE;
3579 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3580 cm_buf_t *bp = buf_Find(dscp, &hzero);
3586 code = CM_ERROR_NOSUCHFILE;
3588 cm_ReleaseSCache(dscp);
3590 cm_FreeSpace(spacep);
3591 cm_ReleaseUser(userp);
3592 smb_SendTran2Error(vcp, p, opx, code);
3598 #endif /* SPECIAL_FOLDERS */