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>
33 extern osi_hyper_t hzero;
35 smb_packet_t *smb_Directory_Watches = NULL;
36 osi_mutex_t smb_Dir_Watch_Lock;
38 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
40 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
42 /* protected by the smb_globalLock */
43 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
45 const char **smb_ExecutableExtensions = NULL;
47 /* retrieve a held reference to a user structure corresponding to an incoming
49 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
54 uidp = smb_FindUID(vcp, inp->uid, 0);
58 up = smb_GetUserFromUID(uidp);
66 * Return boolean specifying if the path name is thought to be an
67 * executable file. For now .exe or .dll.
69 afs_uint32 smb_IsExecutableFileName(const char *name)
73 if ( smb_ExecutableExtensions == NULL || name == NULL)
78 for ( i=0; smb_ExecutableExtensions[i]; i++) {
79 j = len - strlen(smb_ExecutableExtensions[i]);
80 if (_stricmp(smb_ExecutableExtensions[i], &name[j]) == 0)
88 * Return extended attributes.
89 * Right now, we aren't using any of the "new" bits, so this looks exactly
90 * like smb_Attributes() (see smb.c).
92 unsigned long smb_ExtAttributes(cm_scache_t *scp)
96 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
97 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
98 scp->fileType == CM_SCACHETYPE_INVALID)
100 attrs = SMB_ATTR_DIRECTORY;
101 #ifdef SPECIAL_FOLDERS
102 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
103 #endif /* SPECIAL_FOLDERS */
104 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
105 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
109 * We used to mark a file RO if it was in an RO volume, but that
110 * turns out to be impolitic in NT. See defect 10007.
113 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
114 attrs |= SMB_ATTR_READONLY; /* Read-only */
116 if ((scp->unixModeBits & 0222) == 0)
117 attrs |= SMB_ATTR_READONLY; /* Read-only */
121 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
126 int smb_V3IsStarMask(char *maskp)
130 while (tc = *maskp++)
131 if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
136 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
139 /* skip over null-terminated string */
140 *chainpp = inp + strlen(inp) + 1;
145 void OutputDebugF(char * format, ...) {
150 va_start( args, format );
151 len = _vscprintf( format, args ) // _vscprintf doesn't count
152 + 3; // terminating '\0' + '\n'
153 buffer = malloc( len * sizeof(char) );
154 vsprintf( buffer, format, args );
155 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buffer));
156 strcat(buffer, "\n");
157 OutputDebugString(buffer);
161 void OutputDebugHexDump(unsigned char * buffer, int len) {
164 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
166 OutputDebugF("Hexdump length [%d]",len);
168 for (i=0;i<len;i++) {
171 osi_Log0(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
173 OutputDebugString(buf);
175 sprintf(buf,"%5x",i);
176 memset(buf+5,' ',80);
181 j = j*3 + 7 + ((j>7)?1:0);
184 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
187 j = j + 56 + ((j>7)?1:0);
189 buf[j] = (k>32 && k<127)?k:'.';
192 osi_Log0(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
194 OutputDebugString(buf);
198 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
200 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
201 SECURITY_STATUS status, istatus;
202 CredHandle creds = {0,0};
204 SecBufferDesc secOut;
212 OutputDebugF("Negotiating Extended Security");
214 status = AcquireCredentialsHandle( NULL,
215 SMB_EXT_SEC_PACKAGE_NAME,
224 if (status != SEC_E_OK) {
225 /* Really bad. We return an empty security blob */
226 OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
231 secOut.pBuffers = &secTok;
232 secOut.ulVersion = SECBUFFER_VERSION;
234 secTok.BufferType = SECBUFFER_TOKEN;
236 secTok.pvBuffer = NULL;
238 ctx.dwLower = ctx.dwUpper = 0;
240 status = AcceptSecurityContext( &creds,
243 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
244 SECURITY_NETWORK_DREP,
251 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
252 OutputDebugF("Completing token...");
253 istatus = CompleteAuthToken(&ctx, &secOut);
254 if ( istatus != SEC_E_OK )
255 OutputDebugF("Token completion failed: %x", istatus);
258 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
259 if (secTok.pvBuffer) {
260 *secBlobLength = secTok.cbBuffer;
261 *secBlob = malloc( secTok.cbBuffer );
262 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
265 if ( status != SEC_E_OK )
266 OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
269 /* Discard partial security context */
270 DeleteSecurityContext(&ctx);
272 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
274 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
275 FreeCredentialsHandle(&creds);
281 struct smb_ext_context {
288 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
289 SECURITY_STATUS status, istatus;
293 SecBufferDesc secBufIn;
295 SecBufferDesc secBufOut;
298 struct smb_ext_context * secCtx = NULL;
299 struct smb_ext_context * newSecCtx = NULL;
300 void * assembledBlob = NULL;
301 int assembledBlobLength = 0;
304 OutputDebugF("In smb_AuthenticateUserExt");
307 *secBlobOutLength = 0;
309 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
310 secCtx = vcp->secCtx;
311 lock_ObtainMutex(&vcp->mx);
312 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
314 lock_ReleaseMutex(&vcp->mx);
318 OutputDebugF("Received incoming token:");
319 OutputDebugHexDump(secBlobIn,secBlobInLength);
323 OutputDebugF("Continuing with existing context.");
324 creds = secCtx->creds;
327 if (secCtx->partialToken) {
328 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
329 assembledBlob = malloc(assembledBlobLength);
330 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
331 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
334 status = AcquireCredentialsHandle( NULL,
335 SMB_EXT_SEC_PACKAGE_NAME,
344 if (status != SEC_E_OK) {
345 OutputDebugF("Can't acquire Credentials handle [%lX]", status);
346 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
354 secBufIn.cBuffers = 1;
355 secBufIn.pBuffers = &secTokIn;
356 secBufIn.ulVersion = SECBUFFER_VERSION;
358 secTokIn.BufferType = SECBUFFER_TOKEN;
360 secTokIn.cbBuffer = assembledBlobLength;
361 secTokIn.pvBuffer = assembledBlob;
363 secTokIn.cbBuffer = secBlobInLength;
364 secTokIn.pvBuffer = secBlobIn;
367 secBufOut.cBuffers = 1;
368 secBufOut.pBuffers = &secTokOut;
369 secBufOut.ulVersion = SECBUFFER_VERSION;
371 secTokOut.BufferType = SECBUFFER_TOKEN;
372 secTokOut.cbBuffer = 0;
373 secTokOut.pvBuffer = NULL;
375 status = AcceptSecurityContext( &creds,
376 ((secCtx)?&ctx:NULL),
378 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
379 SECURITY_NETWORK_DREP,
386 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
387 OutputDebugF("Completing token...");
388 istatus = CompleteAuthToken(&ctx, &secBufOut);
389 if ( istatus != SEC_E_OK )
390 OutputDebugF("Token completion failed: %lX", istatus);
393 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
394 OutputDebugF("Continue needed");
396 newSecCtx = malloc(sizeof(*newSecCtx));
398 newSecCtx->creds = creds;
399 newSecCtx->ctx = ctx;
400 newSecCtx->partialToken = NULL;
401 newSecCtx->partialTokenLen = 0;
403 lock_ObtainMutex( &vcp->mx );
404 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
405 vcp->secCtx = newSecCtx;
406 lock_ReleaseMutex( &vcp->mx );
408 code = CM_ERROR_GSSCONTINUE;
411 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
412 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
413 secTokOut.pvBuffer) {
414 OutputDebugF("Need to send token back to client");
416 *secBlobOutLength = secTokOut.cbBuffer;
417 *secBlobOut = malloc(secTokOut.cbBuffer);
418 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
420 OutputDebugF("Outgoing token:");
421 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
422 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
423 OutputDebugF("Incomplete message");
425 newSecCtx = malloc(sizeof(*newSecCtx));
427 newSecCtx->creds = creds;
428 newSecCtx->ctx = ctx;
429 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
430 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
431 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
433 lock_ObtainMutex( &vcp->mx );
434 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
435 vcp->secCtx = newSecCtx;
436 lock_ReleaseMutex( &vcp->mx );
438 code = CM_ERROR_GSSCONTINUE;
441 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
443 SecPkgContext_Names names;
445 OutputDebugF("Authentication completed");
446 OutputDebugF("Returned flags : [%lX]", flags);
448 if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
449 OutputDebugF("Received name [%s]", names.sUserName);
450 strcpy(usern, names.sUserName);
451 strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
452 FreeContextBuffer(names.sUserName);
454 /* Force the user to retry if the context is invalid */
455 OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
456 code = CM_ERROR_BADPASSWORD;
460 case SEC_E_INVALID_TOKEN:
461 OutputDebugF("Returning bad password :: INVALID_TOKEN");
463 case SEC_E_INVALID_HANDLE:
464 OutputDebugF("Returning bad password :: INVALID_HANDLE");
466 case SEC_E_LOGON_DENIED:
467 OutputDebugF("Returning bad password :: LOGON_DENIED");
469 case SEC_E_UNKNOWN_CREDENTIALS:
470 OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
472 case SEC_E_NO_CREDENTIALS:
473 OutputDebugF("Returning bad password :: NO_CREDENTIALS");
475 case SEC_E_CONTEXT_EXPIRED:
476 OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
478 case SEC_E_INCOMPLETE_CREDENTIALS:
479 OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
481 case SEC_E_WRONG_PRINCIPAL:
482 OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
484 case SEC_E_TIME_SKEW:
485 OutputDebugF("Returning bad password :: TIME_SKEW");
488 OutputDebugF("Returning bad password :: Status == %lX", status);
490 code = CM_ERROR_BADPASSWORD;
494 if (secCtx->partialToken) free(secCtx->partialToken);
502 if (secTokOut.pvBuffer)
503 FreeContextBuffer(secTokOut.pvBuffer);
505 if (code != CM_ERROR_GSSCONTINUE) {
506 DeleteSecurityContext(&ctx);
507 FreeCredentialsHandle(&creds);
515 #define P_RESP_LEN 128
517 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
518 So put stuff in a struct. */
519 struct Lm20AuthBlob {
520 MSV1_0_LM20_LOGON lmlogon;
521 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
522 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
523 WCHAR accountNameW[P_LEN];
524 WCHAR primaryDomainW[P_LEN];
525 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
526 TOKEN_GROUPS tgroups;
527 TOKEN_SOURCE tsource;
530 long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
533 struct Lm20AuthBlob lmAuth;
534 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
535 QUOTA_LIMITS quotaLimits;
537 ULONG lmprofilepSize;
541 OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
542 OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
544 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
545 OutputDebugF("ciPwdLength or csPwdLength is too long");
546 return CM_ERROR_BADPASSWORD;
549 memset(&lmAuth,0,sizeof(lmAuth));
551 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
553 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
554 mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
555 lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
556 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
558 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
559 mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
560 lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
561 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
563 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
564 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
565 size = MAX_COMPUTERNAME_LENGTH + 1;
566 GetComputerNameW(lmAuth.workstationW, &size);
567 lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
569 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
571 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
572 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
573 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
574 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
576 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
577 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
578 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
579 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
581 lmAuth.lmlogon.ParameterControl = 0;
583 lmAuth.tgroups.GroupCount = 0;
584 lmAuth.tgroups.Groups[0].Sid = NULL;
585 lmAuth.tgroups.Groups[0].Attributes = 0;
587 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
588 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
589 strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
591 nts = LsaLogonUser( smb_lsaHandle,
606 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
607 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
610 OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
611 OutputDebugF("Extended status is 0x%lX", ntsEx);
613 if (nts == ERROR_SUCCESS) {
615 LsaFreeReturnBuffer(lmprofilep);
616 CloseHandle(lmToken);
620 if (nts == 0xC000015BL)
621 return CM_ERROR_BADLOGONTYPE;
622 else /* our catchall is a bad password though we could be more specific */
623 return CM_ERROR_BADPASSWORD;
627 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
628 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName)
633 /* check if we have sane input */
634 if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
637 /* we could get : [accountName][domainName]
643 atsign = strchr(accountName, '@');
645 if (atsign) /* [user@domain][] -> [user@domain][domain] */
650 /* if for some reason the client doesn't know what domain to use,
651 it will either return an empty string or a '?' */
652 if (!domain[0] || domain[0] == '?')
653 /* Empty domains and empty usernames are usually sent from tokenless contexts.
654 This way such logins will get an empty username (easy to check). I don't know
655 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
656 strcpy(usern,accountName);
658 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
659 strcpy(usern,domain);
662 strncat(usern,accountName,atsign - accountName);
664 strcat(usern,accountName);
672 /* When using SMB auth, all SMB sessions have to pass through here
673 * first to authenticate the user.
675 * Caveat: If not using SMB auth, the protocol does not require
676 * sending a session setup packet, which means that we can't rely on a
677 * UID in subsequent packets. Though in practice we get one anyway.
679 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
683 unsigned short newUid;
684 unsigned long caps = 0;
688 char usern[SMB_MAX_USERNAME_LENGTH];
689 char *secBlobOut = NULL;
690 int secBlobOutLength = 0;
692 /* Check for bad conns */
693 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
694 return CM_ERROR_REMOTECONN;
696 if (vcp->flags & SMB_VCFLAG_USENT) {
697 if (smb_authType == SMB_AUTH_EXTENDED) {
698 /* extended authentication */
702 OutputDebugF("NT Session Setup: Extended");
704 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
705 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
708 secBlobInLength = smb_GetSMBParm(inp, 7);
709 secBlobIn = smb_GetSMBData(inp, NULL);
711 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
713 if (code == CM_ERROR_GSSCONTINUE) {
714 smb_SetSMBParm(outp, 2, 0);
715 smb_SetSMBParm(outp, 3, secBlobOutLength);
716 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
717 tp = smb_GetSMBData(outp, NULL);
718 if (secBlobOutLength) {
719 memcpy(tp, secBlobOut, secBlobOutLength);
721 tp += secBlobOutLength;
723 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
724 tp += smb_ServerOSLength;
725 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
726 tp += smb_ServerLanManagerLength;
727 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
728 tp += smb_ServerDomainNameLength;
731 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
733 unsigned ciPwdLength, csPwdLength;
739 if (smb_authType == SMB_AUTH_NTLM)
740 OutputDebugF("NT Session Setup: NTLM");
742 OutputDebugF("NT Session Setup: None");
744 /* TODO: parse for extended auth as well */
745 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
746 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
748 tp = smb_GetSMBData(inp, &datalen);
750 OutputDebugF("Session packet data size [%d]",datalen);
757 accountName = smb_ParseString(tp, &tp);
758 primaryDomain = smb_ParseString(tp, NULL);
760 OutputDebugF("Account Name: %s",accountName);
761 OutputDebugF("Primary Domain: %s", primaryDomain);
762 OutputDebugF("Case Sensitive Password: %s", csPwd && csPwd[0] ? "yes" : "no");
763 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
765 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
766 /* shouldn't happen */
767 code = CM_ERROR_BADSMB;
768 goto after_read_packet;
771 /* capabilities are only valid for first session packet */
772 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
773 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
776 if (smb_authType == SMB_AUTH_NTLM) {
777 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
779 OutputDebugF("LM authentication failed [%d]", code);
781 OutputDebugF("LM authentication succeeded");
785 unsigned ciPwdLength;
790 switch ( smb_authType ) {
791 case SMB_AUTH_EXTENDED:
792 OutputDebugF("V3 Session Setup: Extended");
795 OutputDebugF("V3 Session Setup: NTLM");
798 OutputDebugF("V3 Session Setup: None");
800 ciPwdLength = smb_GetSMBParm(inp, 7);
801 tp = smb_GetSMBData(inp, NULL);
805 accountName = smb_ParseString(tp, &tp);
806 primaryDomain = smb_ParseString(tp, NULL);
808 OutputDebugF("Account Name: %s",accountName);
809 OutputDebugF("Primary Domain: %s", primaryDomain);
810 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
812 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
813 /* shouldn't happen */
814 code = CM_ERROR_BADSMB;
815 goto after_read_packet;
818 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
821 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
822 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
824 OutputDebugF("LM authentication failed [%d]", code);
826 OutputDebugF("LM authentication succeeded");
831 /* note down that we received a session setup X and set the capabilities flag */
832 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
833 lock_ObtainMutex(&vcp->mx);
834 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
835 /* for the moment we can only deal with NTSTATUS */
836 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
837 vcp->flags |= SMB_VCFLAG_STATUS32;
839 lock_ReleaseMutex(&vcp->mx);
842 /* code would be non-zero if there was an authentication failure.
843 Ideally we would like to invalidate the uid for this session or break
844 early to avoid accidently stealing someone else's tokens. */
850 OutputDebugF("Received username=[%s]", usern);
852 /* On Windows 2000, this function appears to be called more often than
853 it is expected to be called. This resulted in multiple smb_user_t
854 records existing all for the same user session which results in all
855 of the users tokens disappearing.
857 To avoid this problem, we look for an existing smb_user_t record
858 based on the users name, and use that one if we find it.
861 uidp = smb_FindUserByNameThisSession(vcp, usern);
862 if (uidp) { /* already there, so don't create a new one */
864 newUid = uidp->userID;
865 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
866 vcp->lana,vcp->lsn,newUid);
867 smb_ReleaseUID(uidp);
872 /* do a global search for the username/machine name pair */
873 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
874 lock_ObtainMutex(&unp->mx);
875 if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
876 /* clear the afslogon flag so that the tickets can now
877 * be freed when the refCount returns to zero.
879 unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
881 lock_ReleaseMutex(&unp->mx);
883 /* Create a new UID and cm_user_t structure */
886 userp = cm_NewUser();
887 cm_HoldUserVCRef(userp);
888 lock_ObtainMutex(&vcp->mx);
889 if (!vcp->uidCounter)
890 vcp->uidCounter++; /* handle unlikely wraparounds */
891 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
892 lock_ReleaseMutex(&vcp->mx);
894 /* Create a new smb_user_t structure and connect them up */
895 lock_ObtainMutex(&unp->mx);
897 lock_ReleaseMutex(&unp->mx);
899 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
901 lock_ObtainMutex(&uidp->mx);
903 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
904 lock_ReleaseMutex(&uidp->mx);
905 smb_ReleaseUID(uidp);
909 /* Return UID to the client */
910 ((smb_t *)outp)->uid = newUid;
911 /* Also to the next chained message */
912 ((smb_t *)inp)->uid = newUid;
914 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
915 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
917 smb_SetSMBParm(outp, 2, 0);
919 if (vcp->flags & SMB_VCFLAG_USENT) {
920 if (smb_authType == SMB_AUTH_EXTENDED) {
921 smb_SetSMBParm(outp, 3, secBlobOutLength);
922 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
923 tp = smb_GetSMBData(outp, NULL);
924 if (secBlobOutLength) {
925 memcpy(tp, secBlobOut, secBlobOutLength);
927 tp += secBlobOutLength;
929 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
930 tp += smb_ServerOSLength;
931 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
932 tp += smb_ServerLanManagerLength;
933 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
934 tp += smb_ServerDomainNameLength;
936 smb_SetSMBDataLength(outp, 0);
939 if (smb_authType == SMB_AUTH_EXTENDED) {
940 smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
941 tp = smb_GetSMBData(outp, NULL);
942 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
943 tp += smb_ServerOSLength;
944 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
945 tp += smb_ServerLanManagerLength;
946 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
947 tp += smb_ServerDomainNameLength;
949 smb_SetSMBDataLength(outp, 0);
956 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
960 /* find the tree and free it */
961 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
963 smb_username_t * unp;
965 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %s", uidp->userID,
966 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "));
968 lock_ObtainMutex(&uidp->mx);
969 uidp->flags |= SMB_USERFLAG_DELETE;
971 * it doesn't get deleted right away
972 * because the vcp points to it
975 lock_ReleaseMutex(&uidp->mx);
978 /* we can't do this. we get logoff messages prior to a session
979 * disconnect even though it doesn't mean the user is logging out.
980 * we need to create a new pioctl and EventLogoff handler to set
981 * SMB_USERNAMEFLAG_LOGOFF.
983 if (unp && smb_LogoffTokenTransfer) {
984 lock_ObtainMutex(&unp->mx);
985 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
986 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
987 lock_ReleaseMutex(&unp->mx);
991 smb_ReleaseUID(uidp);
994 osi_Log0(smb_logp, "SMB3 user logoffX");
996 smb_SetSMBDataLength(outp, 0);
1000 #define SMB_SUPPORT_SEARCH_BITS 0x0001
1001 #define SMB_SHARE_IS_IN_DFS 0x0002
1003 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1006 smb_user_t *uidp = NULL;
1007 unsigned short newTid;
1008 char shareName[AFSPATHMAX];
1015 cm_user_t *userp = NULL;
1018 osi_Log0(smb_logp, "SMB3 receive tree connect");
1020 /* parse input parameters */
1021 tp = smb_GetSMBData(inp, NULL);
1022 passwordp = smb_ParseString(tp, &tp);
1023 pathp = smb_ParseString(tp, &tp);
1024 if (smb_StoreAnsiFilenames)
1025 OemToChar(pathp,pathp);
1026 servicep = smb_ParseString(tp, &tp);
1028 tp = strrchr(pathp, '\\');
1030 return CM_ERROR_BADSMB;
1032 strcpy(shareName, tp+1);
1034 osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
1035 osi_LogSaveString(smb_logp, pathp),
1036 osi_LogSaveString(smb_logp, shareName));
1038 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
1040 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1043 return CM_ERROR_NOIPC;
1047 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1049 userp = smb_GetUserFromUID(uidp);
1051 lock_ObtainMutex(&vcp->mx);
1052 newTid = vcp->tidCounter++;
1053 lock_ReleaseMutex(&vcp->mx);
1055 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1058 if (!strcmp(shareName, "*."))
1059 strcpy(shareName, "all");
1060 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1063 smb_ReleaseUID(uidp);
1064 smb_ReleaseTID(tidp);
1065 return CM_ERROR_BADSHARENAME;
1068 if (vcp->flags & SMB_VCFLAG_USENT)
1070 int policy = smb_FindShareCSCPolicy(shareName);
1073 DWORD dwAdvertiseDFS = 0, dwSize = sizeof(DWORD);
1075 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1076 0, KEY_QUERY_VALUE, &parmKey);
1077 if (code == ERROR_SUCCESS) {
1078 code = RegQueryValueEx(parmKey, "AdvertiseDFS", NULL, NULL,
1079 (BYTE *)&dwAdvertiseDFS, &dwSize);
1080 if (code != ERROR_SUCCESS)
1082 RegCloseKey (parmKey);
1084 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1085 (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
1089 smb_SetSMBParm(outp, 2, 0);
1093 smb_ReleaseUID(uidp);
1095 lock_ObtainMutex(&tidp->mx);
1096 tidp->userp = userp;
1097 tidp->pathname = sharePath;
1099 tidp->flags |= SMB_TIDFLAG_IPC;
1100 lock_ReleaseMutex(&tidp->mx);
1101 smb_ReleaseTID(tidp);
1103 ((smb_t *)outp)->tid = newTid;
1104 ((smb_t *)inp)->tid = newTid;
1105 tp = smb_GetSMBData(outp, NULL);
1107 /* XXX - why is this a drive letter? */
1115 smb_SetSMBDataLength(outp, 7);
1118 smb_SetSMBDataLength(outp, 4);
1121 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1125 /* must be called with global tran lock held */
1126 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1128 smb_tran2Packet_t *tp;
1131 smbp = (smb_t *) inp->data;
1132 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1133 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1139 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1140 int totalParms, int totalData)
1142 smb_tran2Packet_t *tp;
1145 smbp = (smb_t *) inp->data;
1146 tp = malloc(sizeof(*tp));
1147 memset(tp, 0, sizeof(*tp));
1150 tp->curData = tp->curParms = 0;
1151 tp->totalData = totalData;
1152 tp->totalParms = totalParms;
1153 tp->tid = smbp->tid;
1154 tp->mid = smbp->mid;
1155 tp->uid = smbp->uid;
1156 tp->pid = smbp->pid;
1157 tp->res[0] = smbp->res[0];
1158 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1159 if (totalParms != 0)
1160 tp->parmsp = malloc(totalParms);
1162 tp->datap = malloc(totalData);
1163 if (smbp->com == 0x25 || smbp->com == 0x26)
1166 tp->opcode = smb_GetSMBParm(inp, 14);
1169 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1173 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1174 smb_tran2Packet_t *inp, smb_packet_t *outp,
1175 int totalParms, int totalData)
1177 smb_tran2Packet_t *tp;
1178 unsigned short parmOffset;
1179 unsigned short dataOffset;
1180 unsigned short dataAlign;
1182 tp = malloc(sizeof(*tp));
1183 memset(tp, 0, sizeof(*tp));
1186 tp->curData = tp->curParms = 0;
1187 tp->totalData = totalData;
1188 tp->totalParms = totalParms;
1189 tp->oldTotalParms = totalParms;
1194 tp->res[0] = inp->res[0];
1195 tp->opcode = inp->opcode;
1199 * We calculate where the parameters and data will start.
1200 * This calculation must parallel the calculation in
1201 * smb_SendTran2Packet.
1204 parmOffset = 10*2 + 35;
1205 parmOffset++; /* round to even */
1206 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1208 dataOffset = parmOffset + totalParms;
1209 dataAlign = dataOffset & 2; /* quad-align */
1210 dataOffset += dataAlign;
1211 tp->datap = outp->data + dataOffset;
1216 /* free a tran2 packet */
1217 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1220 smb_ReleaseVC(t2p->vcp);
1223 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1232 /* called with a VC, an input packet to respond to, and an error code.
1233 * sends an error response.
1235 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1236 smb_packet_t *tp, long code)
1239 unsigned short errCode;
1240 unsigned char errClass;
1241 unsigned long NTStatus;
1243 if (vcp->flags & SMB_VCFLAG_STATUS32)
1244 smb_MapNTError(code, &NTStatus);
1246 smb_MapCoreError(code, vcp, &errCode, &errClass);
1248 smb_FormatResponsePacket(vcp, NULL, tp);
1249 smbp = (smb_t *) tp;
1251 /* We can handle long names */
1252 if (vcp->flags & SMB_VCFLAG_USENT)
1253 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1255 /* now copy important fields from the tran 2 packet */
1256 smbp->com = t2p->com;
1257 smbp->tid = t2p->tid;
1258 smbp->mid = t2p->mid;
1259 smbp->pid = t2p->pid;
1260 smbp->uid = t2p->uid;
1261 smbp->res[0] = t2p->res[0];
1262 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1263 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1264 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1265 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1266 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1267 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1270 smbp->rcls = errClass;
1271 smbp->errLow = (unsigned char) (errCode & 0xff);
1272 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1276 smb_SendPacket(vcp, tp);
1279 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1282 unsigned short parmOffset;
1283 unsigned short dataOffset;
1284 unsigned short totalLength;
1285 unsigned short dataAlign;
1288 smb_FormatResponsePacket(vcp, NULL, tp);
1289 smbp = (smb_t *) tp;
1291 /* We can handle long names */
1292 if (vcp->flags & SMB_VCFLAG_USENT)
1293 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1295 /* now copy important fields from the tran 2 packet */
1296 smbp->com = t2p->com;
1297 smbp->tid = t2p->tid;
1298 smbp->mid = t2p->mid;
1299 smbp->pid = t2p->pid;
1300 smbp->uid = t2p->uid;
1301 smbp->res[0] = t2p->res[0];
1303 totalLength = 1 + t2p->totalData + t2p->totalParms;
1305 /* now add the core parameters (tran2 info) to the packet */
1306 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1307 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1308 smb_SetSMBParm(tp, 2, 0); /* reserved */
1309 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1310 parmOffset = 10*2 + 35; /* parm offset in packet */
1311 parmOffset++; /* round to even */
1312 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1313 * hdr, bcc and wct */
1314 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1315 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1316 dataOffset = parmOffset + t2p->oldTotalParms;
1317 dataAlign = dataOffset & 2; /* quad-align */
1318 dataOffset += dataAlign;
1319 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1320 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1321 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1324 datap = smb_GetSMBData(tp, NULL);
1325 *datap++ = 0; /* we rounded to even */
1327 totalLength += dataAlign;
1328 smb_SetSMBDataLength(tp, totalLength);
1330 /* next, send the datagram */
1331 smb_SendPacket(vcp, tp);
1334 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1336 smb_tran2Packet_t *asp;
1349 /* We sometimes see 0 word count. What to do? */
1350 if (*inp->wctp == 0) {
1351 osi_Log0(smb_logp, "Transaction2 word count = 0");
1352 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1354 smb_SetSMBDataLength(outp, 0);
1355 smb_SendPacket(vcp, outp);
1359 totalParms = smb_GetSMBParm(inp, 0);
1360 totalData = smb_GetSMBParm(inp, 1);
1362 firstPacket = (inp->inCom == 0x25);
1364 /* find the packet we're reassembling */
1365 lock_ObtainWrite(&smb_globalLock);
1366 asp = smb_FindTran2Packet(vcp, inp);
1368 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1370 lock_ReleaseWrite(&smb_globalLock);
1372 /* now merge in this latest packet; start by looking up offsets */
1374 parmDisp = dataDisp = 0;
1375 parmOffset = smb_GetSMBParm(inp, 10);
1376 dataOffset = smb_GetSMBParm(inp, 12);
1377 parmCount = smb_GetSMBParm(inp, 9);
1378 dataCount = smb_GetSMBParm(inp, 11);
1379 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1380 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1382 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1383 totalData, dataCount, asp->maxReturnData);
1386 parmDisp = smb_GetSMBParm(inp, 4);
1387 parmOffset = smb_GetSMBParm(inp, 3);
1388 dataDisp = smb_GetSMBParm(inp, 7);
1389 dataOffset = smb_GetSMBParm(inp, 6);
1390 parmCount = smb_GetSMBParm(inp, 2);
1391 dataCount = smb_GetSMBParm(inp, 5);
1393 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1394 parmCount, dataCount);
1397 /* now copy the parms and data */
1398 if ( asp->totalParms > 0 && parmCount != 0 )
1400 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1402 if ( asp->totalData > 0 && dataCount != 0 ) {
1403 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1406 /* account for new bytes */
1407 asp->curData += dataCount;
1408 asp->curParms += parmCount;
1410 /* finally, if we're done, remove the packet from the queue and dispatch it */
1411 if (asp->totalParms > 0 &&
1412 asp->curParms > 0 &&
1413 asp->totalData <= asp->curData &&
1414 asp->totalParms <= asp->curParms) {
1415 /* we've received it all */
1416 lock_ObtainWrite(&smb_globalLock);
1417 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1418 lock_ReleaseWrite(&smb_globalLock);
1420 /* now dispatch it */
1421 rapOp = asp->parmsp[0];
1423 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1424 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1425 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1426 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
1429 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1430 code = CM_ERROR_BADOP;
1433 /* if an error is returned, we're supposed to send an error packet,
1434 * otherwise the dispatched function already did the data sending.
1435 * We give dispatched proc the responsibility since it knows how much
1436 * space to allocate.
1439 smb_SendTran2Error(vcp, asp, outp, code);
1442 /* free the input tran 2 packet */
1443 smb_FreeTran2Packet(asp);
1445 else if (firstPacket) {
1446 /* the first packet in a multi-packet request, we need to send an
1447 * ack to get more data.
1449 smb_SetSMBDataLength(outp, 0);
1450 smb_SendPacket(vcp, outp);
1456 /* ANSI versions. The unicode versions support arbitrary length
1457 share names, but we don't support unicode yet. */
1459 typedef struct smb_rap_share_info_0 {
1460 char shi0_netname[13];
1461 } smb_rap_share_info_0_t;
1463 typedef struct smb_rap_share_info_1 {
1464 char shi1_netname[13];
1467 DWORD shi1_remark; /* char *shi1_remark; data offset */
1468 } smb_rap_share_info_1_t;
1470 typedef struct smb_rap_share_info_2 {
1471 char shi2_netname[13];
1473 unsigned short shi2_type;
1474 DWORD shi2_remark; /* char *shi2_remark; data offset */
1475 unsigned short shi2_permissions;
1476 unsigned short shi2_max_uses;
1477 unsigned short shi2_current_uses;
1478 DWORD shi2_path; /* char *shi2_path; data offset */
1479 unsigned short shi2_passwd[9];
1480 unsigned short shi2_pad2;
1481 } smb_rap_share_info_2_t;
1483 #define SMB_RAP_MAX_SHARES 512
1485 typedef struct smb_rap_share_list {
1488 smb_rap_share_info_0_t * shares;
1489 } smb_rap_share_list_t;
1491 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1492 smb_rap_share_list_t * sp;
1497 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1498 return 0; /* skip over '.' and '..' */
1500 sp = (smb_rap_share_list_t *) vrockp;
1502 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1503 sp->shares[sp->cShare].shi0_netname[12] = 0;
1507 if (sp->cShare >= sp->maxShares)
1508 return CM_ERROR_STOPNOW;
1513 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1515 smb_tran2Packet_t *outp;
1516 unsigned short * tp;
1520 int outParmsTotal; /* total parameter bytes */
1521 int outDataTotal; /* total data bytes */
1524 DWORD allSubmount = 0;
1526 DWORD nRegShares = 0;
1527 DWORD nSharesRet = 0;
1529 HKEY hkSubmount = NULL;
1530 smb_rap_share_info_1_t * shares;
1533 char thisShare[AFSPATHMAX];
1537 smb_rap_share_list_t rootShares;
1542 tp = p->parmsp + 1; /* skip over function number (always 0) */
1543 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1544 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1548 if (infoLevel != 1) {
1549 return CM_ERROR_INVAL;
1552 /* first figure out how many shares there are */
1553 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1554 KEY_QUERY_VALUE, &hkParam);
1555 if (rv == ERROR_SUCCESS) {
1556 len = sizeof(allSubmount);
1557 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1558 (BYTE *) &allSubmount, &len);
1559 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1562 RegCloseKey (hkParam);
1565 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1566 0, KEY_QUERY_VALUE, &hkSubmount);
1567 if (rv == ERROR_SUCCESS) {
1568 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1569 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1570 if (rv != ERROR_SUCCESS)
1576 /* fetch the root shares */
1577 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1578 rootShares.cShare = 0;
1579 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1583 userp = smb_GetTran2User(vcp,p);
1585 thyper.HighPart = 0;
1588 cm_HoldSCache(cm_data.rootSCachep);
1589 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1590 cm_ReleaseSCache(cm_data.rootSCachep);
1592 cm_ReleaseUser(userp);
1594 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1596 #define REMARK_LEN 1
1597 outParmsTotal = 8; /* 4 dwords */
1598 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1599 if(outDataTotal > bufsize) {
1600 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1601 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1604 nSharesRet = nShares;
1607 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1609 /* now for the submounts */
1610 shares = (smb_rap_share_info_1_t *) outp->datap;
1611 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1613 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1616 strcpy( shares[cshare].shi1_netname, "all" );
1617 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1618 /* type and pad are zero already */
1624 for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
1625 len = sizeof(thisShare);
1626 rv = RegEnumValue(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
1627 if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1628 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1629 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1630 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1635 nShares--; /* uncount key */
1638 RegCloseKey(hkSubmount);
1641 nonrootShares = cshare;
1643 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1644 /* in case there are collisions with submounts, submounts have higher priority */
1645 for (j=0; j < nonrootShares; j++)
1646 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1649 if (j < nonrootShares) {
1650 nShares--; /* uncount */
1654 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1655 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1660 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1661 outp->parmsp[1] = 0;
1662 outp->parmsp[2] = cshare;
1663 outp->parmsp[3] = nShares;
1665 outp->totalData = (int)(cstrp - outp->datap);
1666 outp->totalParms = outParmsTotal;
1668 smb_SendTran2Packet(vcp, outp, op);
1669 smb_FreeTran2Packet(outp);
1671 free(rootShares.shares);
1676 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1678 smb_tran2Packet_t *outp;
1679 unsigned short * tp;
1681 BOOL shareFound = FALSE;
1682 unsigned short infoLevel;
1683 unsigned short bufsize;
1693 tp = p->parmsp + 1; /* skip over function number (always 1) */
1694 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1695 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1696 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1703 totalData = sizeof(smb_rap_share_info_0_t);
1704 else if(infoLevel == SMB_INFO_STANDARD)
1705 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1706 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1707 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1709 return CM_ERROR_INVAL;
1711 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1713 if(!stricmp(shareName,"all") || !strcmp(shareName,"*.")) {
1714 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1715 KEY_QUERY_VALUE, &hkParam);
1716 if (rv == ERROR_SUCCESS) {
1717 len = sizeof(allSubmount);
1718 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1719 (BYTE *) &allSubmount, &len);
1720 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1723 RegCloseKey (hkParam);
1730 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1731 KEY_QUERY_VALUE, &hkSubmount);
1732 if (rv == ERROR_SUCCESS) {
1733 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1734 if (rv == ERROR_SUCCESS) {
1737 RegCloseKey(hkSubmount);
1742 smb_FreeTran2Packet(outp);
1743 return CM_ERROR_BADSHARENAME;
1746 memset(outp->datap, 0, totalData);
1748 outp->parmsp[0] = 0;
1749 outp->parmsp[1] = 0;
1750 outp->parmsp[2] = totalData;
1752 if (infoLevel == 0) {
1753 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1754 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1755 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1756 } else if(infoLevel == SMB_INFO_STANDARD) {
1757 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1758 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1759 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1760 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1761 /* type and pad are already zero */
1762 } else { /* infoLevel==2 */
1763 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1764 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1765 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1766 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1767 info->shi2_permissions = ACCESS_ALL;
1768 info->shi2_max_uses = (unsigned short) -1;
1769 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
1772 outp->totalData = totalData;
1773 outp->totalParms = totalParam;
1775 smb_SendTran2Packet(vcp, outp, op);
1776 smb_FreeTran2Packet(outp);
1781 typedef struct smb_rap_wksta_info_10 {
1782 DWORD wki10_computername; /*char *wki10_computername;*/
1783 DWORD wki10_username; /* char *wki10_username; */
1784 DWORD wki10_langroup; /* char *wki10_langroup;*/
1785 unsigned char wki10_ver_major;
1786 unsigned char wki10_ver_minor;
1787 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1788 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1789 } smb_rap_wksta_info_10_t;
1792 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1794 smb_tran2Packet_t *outp;
1798 unsigned short * tp;
1801 smb_rap_wksta_info_10_t * info;
1805 tp = p->parmsp + 1; /* Skip over function number */
1806 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1807 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1811 if (infoLevel != 10) {
1812 return CM_ERROR_INVAL;
1818 totalData = sizeof(*info) + /* info */
1819 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1820 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1821 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1822 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1823 1; /* wki10_oth_domains (null)*/
1825 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1827 memset(outp->parmsp,0,totalParams);
1828 memset(outp->datap,0,totalData);
1830 info = (smb_rap_wksta_info_10_t *) outp->datap;
1831 cstrp = (char *) (info + 1);
1833 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1834 strcpy(cstrp, smb_localNamep);
1835 cstrp += strlen(cstrp) + 1;
1837 info->wki10_username = (DWORD) (cstrp - outp->datap);
1838 uidp = smb_FindUID(vcp, p->uid, 0);
1840 lock_ObtainMutex(&uidp->mx);
1841 if(uidp->unp && uidp->unp->name)
1842 strcpy(cstrp, uidp->unp->name);
1843 lock_ReleaseMutex(&uidp->mx);
1844 smb_ReleaseUID(uidp);
1846 cstrp += strlen(cstrp) + 1;
1848 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1849 strcpy(cstrp, "WORKGROUP");
1850 cstrp += strlen(cstrp) + 1;
1852 /* TODO: Not sure what values these should take, but these work */
1853 info->wki10_ver_major = 5;
1854 info->wki10_ver_minor = 1;
1856 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1857 strcpy(cstrp, smb_ServerDomainName);
1858 cstrp += strlen(cstrp) + 1;
1860 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1861 cstrp ++; /* no other domains */
1863 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1864 outp->parmsp[2] = outp->totalData;
1865 outp->totalParms = totalParams;
1867 smb_SendTran2Packet(vcp,outp,op);
1868 smb_FreeTran2Packet(outp);
1873 typedef struct smb_rap_server_info_0 {
1875 } smb_rap_server_info_0_t;
1877 typedef struct smb_rap_server_info_1 {
1879 char sv1_version_major;
1880 char sv1_version_minor;
1881 unsigned long sv1_type;
1882 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1883 } smb_rap_server_info_1_t;
1885 char smb_ServerComment[] = "OpenAFS Client";
1886 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1888 #define SMB_SV_TYPE_SERVER 0x00000002L
1889 #define SMB_SV_TYPE_NT 0x00001000L
1890 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1892 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1894 smb_tran2Packet_t *outp;
1898 unsigned short * tp;
1901 smb_rap_server_info_0_t * info0;
1902 smb_rap_server_info_1_t * info1;
1905 tp = p->parmsp + 1; /* Skip over function number */
1906 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1907 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1911 if (infoLevel != 0 && infoLevel != 1) {
1912 return CM_ERROR_INVAL;
1918 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1919 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1921 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1923 memset(outp->parmsp,0,totalParams);
1924 memset(outp->datap,0,totalData);
1926 if (infoLevel == 0) {
1927 info0 = (smb_rap_server_info_0_t *) outp->datap;
1928 cstrp = (char *) (info0 + 1);
1929 strcpy(info0->sv0_name, "AFS");
1930 } else { /* infoLevel == SMB_INFO_STANDARD */
1931 info1 = (smb_rap_server_info_1_t *) outp->datap;
1932 cstrp = (char *) (info1 + 1);
1933 strcpy(info1->sv1_name, "AFS");
1936 SMB_SV_TYPE_SERVER |
1938 SMB_SV_TYPE_SERVER_NT;
1940 info1->sv1_version_major = 5;
1941 info1->sv1_version_minor = 1;
1942 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1944 strcpy(cstrp, smb_ServerComment);
1946 cstrp += smb_ServerCommentLen;
1949 totalData = (DWORD)(cstrp - outp->datap);
1950 outp->totalData = min(bufsize,totalData); /* actual data size */
1951 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1952 outp->parmsp[2] = totalData;
1953 outp->totalParms = totalParams;
1955 smb_SendTran2Packet(vcp,outp,op);
1956 smb_FreeTran2Packet(outp);
1961 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1963 smb_tran2Packet_t *asp;
1975 /* We sometimes see 0 word count. What to do? */
1976 if (*inp->wctp == 0) {
1977 osi_Log0(smb_logp, "Transaction2 word count = 0");
1978 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1980 smb_SetSMBDataLength(outp, 0);
1981 smb_SendPacket(vcp, outp);
1985 totalParms = smb_GetSMBParm(inp, 0);
1986 totalData = smb_GetSMBParm(inp, 1);
1988 firstPacket = (inp->inCom == 0x32);
1990 /* find the packet we're reassembling */
1991 lock_ObtainWrite(&smb_globalLock);
1992 asp = smb_FindTran2Packet(vcp, inp);
1994 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1996 lock_ReleaseWrite(&smb_globalLock);
1998 /* now merge in this latest packet; start by looking up offsets */
2000 parmDisp = dataDisp = 0;
2001 parmOffset = smb_GetSMBParm(inp, 10);
2002 dataOffset = smb_GetSMBParm(inp, 12);
2003 parmCount = smb_GetSMBParm(inp, 9);
2004 dataCount = smb_GetSMBParm(inp, 11);
2005 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2006 asp->maxReturnData = smb_GetSMBParm(inp, 3);
2008 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2009 totalData, dataCount, asp->maxReturnData);
2012 parmDisp = smb_GetSMBParm(inp, 4);
2013 parmOffset = smb_GetSMBParm(inp, 3);
2014 dataDisp = smb_GetSMBParm(inp, 7);
2015 dataOffset = smb_GetSMBParm(inp, 6);
2016 parmCount = smb_GetSMBParm(inp, 2);
2017 dataCount = smb_GetSMBParm(inp, 5);
2019 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2020 parmCount, dataCount);
2023 /* now copy the parms and data */
2024 if ( asp->totalParms > 0 && parmCount != 0 )
2026 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2028 if ( asp->totalData > 0 && dataCount != 0 ) {
2029 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2032 /* account for new bytes */
2033 asp->curData += dataCount;
2034 asp->curParms += parmCount;
2036 /* finally, if we're done, remove the packet from the queue and dispatch it */
2037 if (asp->totalParms > 0 &&
2038 asp->curParms > 0 &&
2039 asp->totalData <= asp->curData &&
2040 asp->totalParms <= asp->curParms) {
2041 /* we've received it all */
2042 lock_ObtainWrite(&smb_globalLock);
2043 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2044 lock_ReleaseWrite(&smb_globalLock);
2046 /* now dispatch it */
2047 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2048 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2049 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2052 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2053 code = CM_ERROR_BADOP;
2056 /* if an error is returned, we're supposed to send an error packet,
2057 * otherwise the dispatched function already did the data sending.
2058 * We give dispatched proc the responsibility since it knows how much
2059 * space to allocate.
2062 smb_SendTran2Error(vcp, asp, outp, code);
2065 /* free the input tran 2 packet */
2066 smb_FreeTran2Packet(asp);
2068 else if (firstPacket) {
2069 /* the first packet in a multi-packet request, we need to send an
2070 * ack to get more data.
2072 smb_SetSMBDataLength(outp, 0);
2073 smb_SendPacket(vcp, outp);
2079 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2082 smb_tran2Packet_t *outp;
2087 cm_scache_t *dscp; /* dir we're dealing with */
2088 cm_scache_t *scp; /* file we're creating */
2090 int initialModeBits;
2100 int parmSlot; /* which parm we're dealing with */
2101 long returnEALength;
2110 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2111 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2113 openFun = p->parmsp[6]; /* open function */
2114 excl = ((openFun & 3) == 0);
2115 trunc = ((openFun & 3) == 2); /* truncate it */
2116 openMode = (p->parmsp[1] & 0x7);
2117 openAction = 0; /* tracks what we did */
2119 attributes = p->parmsp[3];
2120 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2122 /* compute initial mode bits based on read-only flag in attributes */
2123 initialModeBits = 0666;
2124 if (attributes & SMB_ATTR_READONLY)
2125 initialModeBits &= ~0222;
2127 pathp = (char *) (&p->parmsp[14]);
2128 if (smb_StoreAnsiFilenames)
2129 OemToChar(pathp,pathp);
2131 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2133 spacep = cm_GetSpace();
2134 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2136 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2137 /* special case magic file name for receiving IOCTL requests
2138 * (since IOCTL calls themselves aren't getting through).
2140 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2141 smb_SetupIoctlFid(fidp, spacep);
2143 /* copy out remainder of the parms */
2145 outp->parmsp[parmSlot++] = fidp->fid;
2147 outp->parmsp[parmSlot++] = 0; /* attrs */
2148 outp->parmsp[parmSlot++] = 0; /* mod time */
2149 outp->parmsp[parmSlot++] = 0;
2150 outp->parmsp[parmSlot++] = 0; /* len */
2151 outp->parmsp[parmSlot++] = 0x7fff;
2152 outp->parmsp[parmSlot++] = openMode;
2153 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2154 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2156 /* and the final "always present" stuff */
2157 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2158 /* next write out the "unique" ID */
2159 outp->parmsp[parmSlot++] = 0x1234;
2160 outp->parmsp[parmSlot++] = 0x5678;
2161 outp->parmsp[parmSlot++] = 0;
2162 if (returnEALength) {
2163 outp->parmsp[parmSlot++] = 0;
2164 outp->parmsp[parmSlot++] = 0;
2167 outp->totalData = 0;
2168 outp->totalParms = parmSlot * 2;
2170 smb_SendTran2Packet(vcp, outp, op);
2172 smb_FreeTran2Packet(outp);
2174 /* and clean up fid reference */
2175 smb_ReleaseFID(fidp);
2179 #ifdef DEBUG_VERBOSE
2181 char *hexp, *asciip;
2182 asciip = (lastNamep ? lastNamep : pathp);
2183 hexp = osi_HexifyString( asciip );
2184 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2189 userp = smb_GetTran2User(vcp, p);
2190 /* In the off chance that userp is NULL, we log and abandon */
2192 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2193 smb_FreeTran2Packet(outp);
2194 return CM_ERROR_BADSMB;
2197 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2198 if (code == CM_ERROR_TIDIPC) {
2199 /* Attempt to use a TID allocated for IPC. The client
2200 * is probably looking for DCE RPC end points which we
2201 * don't support OR it could be looking to make a DFS
2204 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2206 cm_ReleaseUser(userp);
2207 smb_FreeTran2Packet(outp);
2208 return CM_ERROR_NOSUCHPATH;
2213 code = cm_NameI(cm_data.rootSCachep, pathp,
2214 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2215 userp, tidPathp, &req, &scp);
2217 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2218 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2219 userp, tidPathp, &req, &dscp);
2220 cm_FreeSpace(spacep);
2223 cm_ReleaseUser(userp);
2224 smb_FreeTran2Packet(outp);
2229 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2230 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
2231 cm_ReleaseSCache(dscp);
2232 cm_ReleaseUser(userp);
2233 smb_FreeTran2Packet(outp);
2234 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2235 return CM_ERROR_PATH_NOT_COVERED;
2237 return CM_ERROR_BADSHARENAME;
2239 #endif /* DFS_SUPPORT */
2241 /* otherwise, scp points to the parent directory. Do a lookup,
2242 * and truncate the file if we find it, otherwise we create the
2249 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2251 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2252 cm_ReleaseSCache(dscp);
2253 cm_ReleaseUser(userp);
2254 smb_FreeTran2Packet(outp);
2259 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2260 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2261 cm_ReleaseSCache(scp);
2262 cm_ReleaseUser(userp);
2263 smb_FreeTran2Packet(outp);
2264 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2265 return CM_ERROR_PATH_NOT_COVERED;
2267 return CM_ERROR_BADSHARENAME;
2269 #endif /* DFS_SUPPORT */
2271 /* macintosh is expensive to program for it */
2272 cm_FreeSpace(spacep);
2275 /* if we get here, if code is 0, the file exists and is represented by
2276 * scp. Otherwise, we have to create it.
2279 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2282 cm_ReleaseSCache(dscp);
2283 cm_ReleaseSCache(scp);
2284 cm_ReleaseUser(userp);
2285 smb_FreeTran2Packet(outp);
2290 /* oops, file shouldn't be there */
2292 cm_ReleaseSCache(dscp);
2293 cm_ReleaseSCache(scp);
2294 cm_ReleaseUser(userp);
2295 smb_FreeTran2Packet(outp);
2296 return CM_ERROR_EXISTS;
2300 setAttr.mask = CM_ATTRMASK_LENGTH;
2301 setAttr.length.LowPart = 0;
2302 setAttr.length.HighPart = 0;
2303 code = cm_SetAttr(scp, &setAttr, userp, &req);
2304 openAction = 3; /* truncated existing file */
2307 openAction = 1; /* found existing file */
2309 else if (!(openFun & 0x10)) {
2310 /* don't create if not found */
2312 cm_ReleaseSCache(dscp);
2313 osi_assertx(scp == NULL, "null cm_scache_t");
2314 cm_ReleaseUser(userp);
2315 smb_FreeTran2Packet(outp);
2316 return CM_ERROR_NOSUCHFILE;
2319 osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2320 openAction = 2; /* created file */
2321 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2322 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2323 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2327 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2328 smb_NotifyChange(FILE_ACTION_ADDED,
2329 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2330 dscp, lastNamep, NULL, TRUE);
2331 } else if (!excl && code == CM_ERROR_EXISTS) {
2332 /* not an exclusive create, and someone else tried
2333 * creating it already, then we open it anyway. We
2334 * don't bother retrying after this, since if this next
2335 * fails, that means that the file was deleted after we
2336 * started this call.
2338 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2342 setAttr.mask = CM_ATTRMASK_LENGTH;
2343 setAttr.length.LowPart = 0;
2344 setAttr.length.HighPart = 0;
2345 code = cm_SetAttr(scp, &setAttr, userp,
2348 } /* lookup succeeded */
2352 /* we don't need this any longer */
2354 cm_ReleaseSCache(dscp);
2357 /* something went wrong creating or truncating the file */
2359 cm_ReleaseSCache(scp);
2360 cm_ReleaseUser(userp);
2361 smb_FreeTran2Packet(outp);
2365 /* make sure we're about to open a file */
2366 if (scp->fileType != CM_SCACHETYPE_FILE) {
2368 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2369 cm_scache_t * targetScp = 0;
2370 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2372 /* we have a more accurate file to use (the
2373 * target of the symbolic link). Otherwise,
2374 * we'll just use the symlink anyway.
2376 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2378 cm_ReleaseSCache(scp);
2382 if (scp->fileType != CM_SCACHETYPE_FILE) {
2383 cm_ReleaseSCache(scp);
2384 cm_ReleaseUser(userp);
2385 smb_FreeTran2Packet(outp);
2386 return CM_ERROR_ISDIR;
2390 /* now all we have to do is open the file itself */
2391 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2392 osi_assertx(fidp, "null smb_fid_t");
2395 lock_ObtainMutex(&fidp->mx);
2396 /* save a pointer to the vnode */
2397 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2399 lock_ObtainMutex(&scp->mx);
2400 scp->flags |= CM_SCACHEFLAG_SMB_FID;
2401 lock_ReleaseMutex(&scp->mx);
2404 fidp->userp = userp;
2406 /* compute open mode */
2408 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
2409 if (openMode == 1 || openMode == 2)
2410 fidp->flags |= SMB_FID_OPENWRITE;
2412 /* remember that the file was newly created */
2414 fidp->flags |= SMB_FID_CREATED;
2416 lock_ReleaseMutex(&fidp->mx);
2418 smb_ReleaseFID(fidp);
2420 cm_Open(scp, 0, userp);
2422 /* copy out remainder of the parms */
2424 outp->parmsp[parmSlot++] = fidp->fid;
2425 lock_ObtainMutex(&scp->mx);
2427 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2428 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2429 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2430 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2431 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2432 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2433 outp->parmsp[parmSlot++] = openMode;
2434 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2435 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2437 /* and the final "always present" stuff */
2438 outp->parmsp[parmSlot++] = openAction;
2439 /* next write out the "unique" ID */
2440 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2441 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2442 outp->parmsp[parmSlot++] = 0;
2443 if (returnEALength) {
2444 outp->parmsp[parmSlot++] = 0;
2445 outp->parmsp[parmSlot++] = 0;
2447 lock_ReleaseMutex(&scp->mx);
2448 outp->totalData = 0; /* total # of data bytes */
2449 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2451 smb_SendTran2Packet(vcp, outp, op);
2453 smb_FreeTran2Packet(outp);
2455 cm_ReleaseUser(userp);
2456 /* leave scp held since we put it in fidp->scp */
2460 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2463 unsigned short infolevel;
2465 infolevel = p->parmsp[0];
2467 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2469 return CM_ERROR_BAD_LEVEL;
2472 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2474 smb_tran2Packet_t *outp;
2475 smb_tran2QFSInfo_t qi;
2477 static char FSname[8] = {'A', 0, 'F', 0, 'S', 0, 0, 0};
2479 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2481 switch (p->parmsp[0]) {
2482 case SMB_INFO_ALLOCATION:
2483 responseSize = sizeof(qi.u.allocInfo);
2485 case SMB_INFO_VOLUME:
2486 responseSize = sizeof(qi.u.volumeInfo);
2488 case SMB_QUERY_FS_VOLUME_INFO:
2489 responseSize = sizeof(qi.u.FSvolumeInfo);
2491 case SMB_QUERY_FS_SIZE_INFO:
2492 responseSize = sizeof(qi.u.FSsizeInfo);
2494 case SMB_QUERY_FS_DEVICE_INFO:
2495 responseSize = sizeof(qi.u.FSdeviceInfo);
2497 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2498 responseSize = sizeof(qi.u.FSattributeInfo);
2500 case SMB_INFO_UNIX: /* CIFS Unix Info */
2501 case SMB_INFO_MACOS: /* Mac FS Info */
2503 return CM_ERROR_BADOP;
2506 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2507 switch (p->parmsp[0]) {
2508 case SMB_INFO_ALLOCATION:
2510 qi.u.allocInfo.FSID = 0;
2511 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2512 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2513 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2514 qi.u.allocInfo.bytesPerSector = 1024;
2517 case SMB_INFO_VOLUME:
2519 qi.u.volumeInfo.vsn = 1234;
2520 qi.u.volumeInfo.vnCount = 4;
2521 /* we're supposed to pad it out with zeroes to the end */
2522 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2523 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2526 case SMB_QUERY_FS_VOLUME_INFO:
2527 /* FS volume info */
2528 memset((char *)&qi.u.FSvolumeInfo.vct, 0, 4);
2529 qi.u.FSvolumeInfo.vsn = 1234;
2530 qi.u.FSvolumeInfo.vnCount = 8;
2531 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0\0", 8);
2534 case SMB_QUERY_FS_SIZE_INFO:
2536 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2537 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2538 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2539 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2540 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2541 qi.u.FSsizeInfo.bytesPerSector = 1024;
2544 case SMB_QUERY_FS_DEVICE_INFO:
2545 /* FS device info */
2546 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2547 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2550 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2551 /* FS attribute info */
2552 /* attributes, defined in WINNT.H:
2553 * FILE_CASE_SENSITIVE_SEARCH 0x1
2554 * FILE_CASE_PRESERVED_NAMES 0x2
2555 * FILE_VOLUME_QUOTAS 0x10
2556 * <no name defined> 0x4000
2557 * If bit 0x4000 is not set, Windows 95 thinks
2558 * we can't handle long (non-8.3) names,
2559 * despite our protestations to the contrary.
2561 qi.u.FSattributeInfo.attributes = 0x4003;
2562 qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
2563 qi.u.FSattributeInfo.FSnameLength = sizeof(FSname);
2564 memcpy(qi.u.FSattributeInfo.FSname, FSname, sizeof(FSname));
2568 /* copy out return data, and set corresponding sizes */
2569 outp->totalParms = 0;
2570 outp->totalData = responseSize;
2571 memcpy(outp->datap, &qi, responseSize);
2573 /* send and free the packets */
2574 smb_SendTran2Packet(vcp, outp, op);
2575 smb_FreeTran2Packet(outp);
2580 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2582 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2583 return CM_ERROR_BADOP;
2586 struct smb_ShortNameRock {
2590 size_t shortNameLen;
2593 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2596 struct smb_ShortNameRock *rockp;
2600 /* compare both names and vnodes, though probably just comparing vnodes
2601 * would be safe enough.
2603 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2605 if (ntohl(dep->fid.vnode) != rockp->vnode)
2607 /* This is the entry */
2608 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2609 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2610 return CM_ERROR_STOPNOW;
2613 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2614 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2616 struct smb_ShortNameRock rock;
2620 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2624 spacep = cm_GetSpace();
2625 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2627 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2629 cm_FreeSpace(spacep);
2634 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2635 cm_ReleaseSCache(dscp);
2636 cm_ReleaseUser(userp);
2638 return CM_ERROR_PATH_NOT_COVERED;
2640 #endif /* DFS_SUPPORT */
2642 if (!lastNamep) lastNamep = pathp;
2645 thyper.HighPart = 0;
2646 rock.shortName = shortName;
2648 rock.maskp = lastNamep;
2649 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2651 cm_ReleaseSCache(dscp);
2654 return CM_ERROR_NOSUCHFILE;
2655 if (code == CM_ERROR_STOPNOW) {
2656 *shortNameLenp = rock.shortNameLen;
2662 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2664 smb_tran2Packet_t *outp;
2667 unsigned short infoLevel;
2668 smb_tran2QPathInfo_t qpi;
2670 unsigned short attributes;
2671 unsigned long extAttributes;
2676 cm_scache_t *scp, *dscp;
2677 int scp_mx_held = 0;
2687 infoLevel = p->parmsp[0];
2688 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2690 else if (infoLevel == SMB_INFO_STANDARD)
2691 responseSize = sizeof(qpi.u.QPstandardInfo);
2692 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2693 responseSize = sizeof(qpi.u.QPeaSizeInfo);
2694 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2695 responseSize = sizeof(qpi.u.QPfileBasicInfo);
2696 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2697 responseSize = sizeof(qpi.u.QPfileStandardInfo);
2698 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2699 responseSize = sizeof(qpi.u.QPfileEaInfo);
2700 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2701 responseSize = sizeof(qpi.u.QPfileNameInfo);
2702 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
2703 responseSize = sizeof(qpi.u.QPfileAllInfo);
2704 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2705 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2707 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2708 p->opcode, infoLevel);
2709 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
2713 pathp = (char *)(&p->parmsp[3]);
2714 if (smb_StoreAnsiFilenames)
2715 OemToChar(pathp,pathp);
2716 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2717 osi_LogSaveString(smb_logp, pathp));
2719 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2721 if (infoLevel > 0x100)
2722 outp->totalParms = 2;
2724 outp->totalParms = 0;
2725 outp->totalData = responseSize;
2727 /* now, if we're at infoLevel 6, we're only being asked to check
2728 * the syntax, so we just OK things now. In particular, we're *not*
2729 * being asked to verify anything about the state of any parent dirs.
2731 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2732 smb_SendTran2Packet(vcp, outp, opx);
2733 smb_FreeTran2Packet(outp);
2737 userp = smb_GetTran2User(vcp, p);
2739 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2740 smb_FreeTran2Packet(outp);
2741 return CM_ERROR_BADSMB;
2744 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2746 cm_ReleaseUser(userp);
2747 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2748 smb_FreeTran2Packet(outp);
2753 * XXX Strange hack XXX
2755 * As of Patch 7 (13 January 98), we are having the following problem:
2756 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2757 * requests to look up "desktop.ini" in all the subdirectories.
2758 * This can cause zillions of timeouts looking up non-existent cells
2759 * and volumes, especially in the top-level directory.
2761 * We have not found any way to avoid this or work around it except
2762 * to explicitly ignore the requests for mount points that haven't
2763 * yet been evaluated and for directories that haven't yet been
2766 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2767 spacep = cm_GetSpace();
2768 smb_StripLastComponent(spacep->data, &lastComp, pathp);
2769 #ifndef SPECIAL_FOLDERS
2770 /* Make sure that lastComp is not NULL */
2772 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2773 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2777 userp, tidPathp, &req, &dscp);
2780 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2781 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
2782 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2783 code = CM_ERROR_PATH_NOT_COVERED;
2785 code = CM_ERROR_BADSHARENAME;
2787 #endif /* DFS_SUPPORT */
2788 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2789 code = CM_ERROR_NOSUCHFILE;
2790 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2791 cm_buf_t *bp = buf_Find(dscp, &hzero);
2797 code = CM_ERROR_NOSUCHFILE;
2799 cm_ReleaseSCache(dscp);
2801 cm_FreeSpace(spacep);
2802 cm_ReleaseUser(userp);
2803 smb_SendTran2Error(vcp, p, opx, code);
2804 smb_FreeTran2Packet(outp);
2810 #endif /* SPECIAL_FOLDERS */
2812 cm_FreeSpace(spacep);
2815 /* now do namei and stat, and copy out the info */
2816 code = cm_NameI(cm_data.rootSCachep, pathp,
2817 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2820 cm_ReleaseUser(userp);
2821 smb_SendTran2Error(vcp, p, opx, code);
2822 smb_FreeTran2Packet(outp);
2827 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2828 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
2829 cm_ReleaseSCache(scp);
2830 cm_ReleaseUser(userp);
2831 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2832 code = CM_ERROR_PATH_NOT_COVERED;
2834 code = CM_ERROR_BADSHARENAME;
2835 smb_SendTran2Error(vcp, p, opx, code);
2836 smb_FreeTran2Packet(outp);
2839 #endif /* DFS_SUPPORT */
2841 lock_ObtainMutex(&scp->mx);
2843 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2844 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2845 if (code) goto done;
2847 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2849 /* now we have the status in the cache entry, and everything is locked.
2850 * Marshall the output data.
2852 /* for info level 108, figure out short name */
2853 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
2854 code = cm_GetShortName(pathp, userp, &req,
2855 tidPathp, scp->fid.vnode, shortName,
2861 qpi.u.QPfileAltNameInfo.fileNameLength = (len + 1) * 2;
2862 mbstowcs((unsigned short *)qpi.u.QPfileAltNameInfo.fileName, shortName, len + 1);
2866 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2867 len = strlen(lastComp);
2868 qpi.u.QPfileNameInfo.fileNameLength = (len + 1) * 2;
2869 mbstowcs((unsigned short *)qpi.u.QPfileNameInfo.fileName, lastComp, len + 1);
2873 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2874 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2875 qpi.u.QPstandardInfo.creationDateTime = dosTime;
2876 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
2877 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
2878 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
2879 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
2880 attributes = smb_Attributes(scp);
2881 qpi.u.QPstandardInfo.attributes = attributes;
2882 qpi.u.QPstandardInfo.eaSize = 0;
2884 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2885 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2886 qpi.u.QPfileBasicInfo.creationTime = ft;
2887 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
2888 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
2889 qpi.u.QPfileBasicInfo.changeTime = ft;
2890 extAttributes = smb_ExtAttributes(scp);
2891 qpi.u.QPfileBasicInfo.attributes = extAttributes;
2892 qpi.u.QPfileBasicInfo.reserved = 0;
2894 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2895 smb_fid_t *fidp = smb_FindFIDByScache(vcp, scp);
2897 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
2898 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
2899 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
2900 qpi.u.QPfileStandardInfo.directory =
2901 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2902 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2903 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2904 qpi.u.QPfileStandardInfo.reserved = 0;
2907 lock_ReleaseMutex(&scp->mx);
2909 lock_ObtainMutex(&fidp->mx);
2910 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
2911 lock_ReleaseMutex(&fidp->mx);
2912 smb_ReleaseFID(fidp);
2914 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
2916 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2917 qpi.u.QPfileEaInfo.eaSize = 0;
2919 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
2920 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2921 qpi.u.QPfileAllInfo.creationTime = ft;
2922 qpi.u.QPfileAllInfo.lastAccessTime = ft;
2923 qpi.u.QPfileAllInfo.lastWriteTime = ft;
2924 qpi.u.QPfileAllInfo.changeTime = ft;
2925 extAttributes = smb_ExtAttributes(scp);
2926 qpi.u.QPfileAllInfo.attributes = extAttributes;
2927 qpi.u.QPfileAllInfo.allocationSize = scp->length;
2928 qpi.u.QPfileAllInfo.endOfFile = scp->length;
2929 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
2930 qpi.u.QPfileAllInfo.deletePending = 0;
2931 qpi.u.QPfileAllInfo.directory =
2932 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2933 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2934 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2935 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
2936 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
2937 qpi.u.QPfileAllInfo.eaSize = 0;
2938 qpi.u.QPfileAllInfo.accessFlags = 0;
2939 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
2940 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
2941 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
2942 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
2943 qpi.u.QPfileAllInfo.mode = 0;
2944 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
2945 len = strlen(lastComp);
2946 qpi.u.QPfileAllInfo.fileNameLength = (len + 1) * 2;
2947 mbstowcs((unsigned short *)qpi.u.QPfileAllInfo.fileName, lastComp, len + 1);
2950 /* send and free the packets */
2953 lock_ReleaseMutex(&scp->mx);
2954 cm_ReleaseSCache(scp);
2955 cm_ReleaseUser(userp);
2957 memcpy(outp->datap, &qpi, responseSize);
2958 smb_SendTran2Packet(vcp, outp, opx);
2960 smb_SendTran2Error(vcp, p, opx, code);
2962 smb_FreeTran2Packet(outp);
2967 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2970 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2971 return CM_ERROR_BADOP;
2975 unsigned short infoLevel;
2977 smb_tran2Packet_t *outp;
2978 smb_tran2QPathInfo_t *spi;
2980 cm_scache_t *scp, *dscp;
2988 infoLevel = p->parmsp[0];
2989 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
2990 if (infoLevel != SMB_INFO_STANDARD &&
2991 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
2992 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
2993 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2994 p->opcode, infoLevel);
2995 smb_SendTran2Error(vcp, p, opx,
2996 infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3000 pathp = (char *)(&p->parmsp[3]);
3001 if (smb_StoreAnsiFilenames)
3002 OemToChar(pathp,pathp);
3003 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %s", infoLevel,
3004 osi_LogSaveString(smb_logp, pathp));
3006 userp = smb_GetTran2User(vcp, p);
3008 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3009 code = CM_ERROR_BADSMB;
3013 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3014 if (code == CM_ERROR_TIDIPC) {
3015 /* Attempt to use a TID allocated for IPC. The client
3016 * is probably looking for DCE RPC end points which we
3017 * don't support OR it could be looking to make a DFS
3020 osi_Log0(smb_logp, "Tran2Open received IPC TID");
3021 cm_ReleaseUser(userp);
3022 return CM_ERROR_NOSUCHPATH;
3026 * XXX Strange hack XXX
3028 * As of Patch 7 (13 January 98), we are having the following problem:
3029 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3030 * requests to look up "desktop.ini" in all the subdirectories.
3031 * This can cause zillions of timeouts looking up non-existent cells
3032 * and volumes, especially in the top-level directory.
3034 * We have not found any way to avoid this or work around it except
3035 * to explicitly ignore the requests for mount points that haven't
3036 * yet been evaluated and for directories that haven't yet been
3039 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3040 spacep = cm_GetSpace();
3041 smb_StripLastComponent(spacep->data, &lastComp, pathp);
3042 #ifndef SPECIAL_FOLDERS
3043 /* Make sure that lastComp is not NULL */
3045 if (stricmp(lastComp, "\\desktop.ini") == 0) {
3046 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3050 userp, tidPathp, &req, &dscp);
3053 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3054 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
3055 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3056 code = CM_ERROR_PATH_NOT_COVERED;
3058 code = CM_ERROR_BADSHARENAME;
3060 #endif /* DFS_SUPPORT */
3061 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3062 code = CM_ERROR_NOSUCHFILE;
3063 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3064 cm_buf_t *bp = buf_Find(dscp, &hzero);
3070 code = CM_ERROR_NOSUCHFILE;
3072 cm_ReleaseSCache(dscp);
3074 cm_FreeSpace(spacep);
3075 cm_ReleaseUser(userp);
3076 smb_SendTran2Error(vcp, p, opx, code);
3082 #endif /* SPECIAL_FOLDERS */
3084 cm_FreeSpace(spacep);
3087 /* now do namei and stat, and copy out the info */
3088 code = cm_NameI(cm_data.rootSCachep, pathp,
3089 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3091 cm_ReleaseUser(userp);
3092 smb_SendTran2Error(vcp, p, opx, code);
3096 fidp = smb_FindFIDByScache(vcp, scp);
3098 cm_ReleaseSCache(scp);
3099 cm_ReleaseUser(userp);
3100 smb_SendTran2Error(vcp, p, opx, code);
3104 lock_ObtainMutex(&fidp->mx);
3105 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
3106 lock_ReleaseMutex(&fidp->mx);
3107 cm_ReleaseSCache(scp);
3108 smb_ReleaseFID(fidp);
3109 cm_ReleaseUser(userp);
3110 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3113 lock_ReleaseMutex(&fidp->mx);
3115 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3117 outp->totalParms = 2;
3118 outp->totalData = 0;
3120 spi = (smb_tran2QPathInfo_t *)p->datap;
3121 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3124 /* lock the vnode with a callback; we need the current status
3125 * to determine what the new status is, in some cases.
3127 lock_ObtainMutex(&scp->mx);
3128 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3129 CM_SCACHESYNC_GETSTATUS
3130 | CM_SCACHESYNC_NEEDCALLBACK);
3132 lock_ReleaseMutex(&scp->mx);
3135 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3137 lock_ReleaseMutex(&scp->mx);
3138 lock_ObtainMutex(&fidp->mx);
3139 lock_ObtainMutex(&scp->mx);
3141 /* prepare for setattr call */
3142 attr.mask = CM_ATTRMASK_LENGTH;
3143 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3144 attr.length.HighPart = 0;
3146 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3147 smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3148 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3149 fidp->flags |= SMB_FID_MTIMESETDONE;
3152 if (spi->u.QPstandardInfo.attributes != 0) {
3153 if ((scp->unixModeBits & 0222)
3154 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3155 /* make a writable file read-only */
3156 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3157 attr.unixModeBits = scp->unixModeBits & ~0222;
3159 else if ((scp->unixModeBits & 0222) == 0
3160 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3161 /* make a read-only file writable */
3162 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3163 attr.unixModeBits = scp->unixModeBits | 0222;
3166 lock_ReleaseMutex(&scp->mx);
3167 lock_ReleaseMutex(&fidp->mx);
3171 code = cm_SetAttr(scp, &attr, userp, &req);
3175 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3176 /* we don't support EAs */
3177 code = CM_ERROR_EAS_NOT_SUPPORTED;
3181 cm_ReleaseSCache(scp);
3182 cm_ReleaseUser(userp);
3183 smb_ReleaseFID(fidp);
3185 smb_SendTran2Packet(vcp, outp, opx);
3187 smb_SendTran2Error(vcp, p, opx, code);
3188 smb_FreeTran2Packet(outp);
3194 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3196 smb_tran2Packet_t *outp;
3198 unsigned long attributes;
3199 unsigned short infoLevel;
3206 smb_tran2QFileInfo_t qfi;
3213 fidp = smb_FindFID(vcp, fid, 0);
3216 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3220 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3221 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3222 smb_CloseFID(vcp, fidp, NULL, 0);
3223 smb_ReleaseFID(fidp);
3227 infoLevel = p->parmsp[1];
3228 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3229 responseSize = sizeof(qfi.u.QFbasicInfo);
3230 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3231 responseSize = sizeof(qfi.u.QFstandardInfo);
3232 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3233 responseSize = sizeof(qfi.u.QFeaInfo);
3234 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3235 responseSize = sizeof(qfi.u.QFfileNameInfo);
3237 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3238 p->opcode, infoLevel);
3239 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3240 smb_ReleaseFID(fidp);
3243 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3245 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3247 if (infoLevel > 0x100)
3248 outp->totalParms = 2;
3250 outp->totalParms = 0;
3251 outp->totalData = responseSize;
3253 userp = smb_GetTran2User(vcp, p);
3255 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3256 code = CM_ERROR_BADSMB;
3260 lock_ObtainMutex(&fidp->mx);
3261 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3263 osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3265 lock_ReleaseMutex(&fidp->mx);
3266 lock_ObtainMutex(&scp->mx);
3267 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3268 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3272 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3274 /* now we have the status in the cache entry, and everything is locked.
3275 * Marshall the output data.
3277 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3278 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3279 qfi.u.QFbasicInfo.creationTime = ft;
3280 qfi.u.QFbasicInfo.lastAccessTime = ft;
3281 qfi.u.QFbasicInfo.lastWriteTime = ft;
3282 qfi.u.QFbasicInfo.lastChangeTime = ft;
3283 attributes = smb_ExtAttributes(scp);
3284 qfi.u.QFbasicInfo.attributes = attributes;
3286 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3287 qfi.u.QFstandardInfo.allocationSize = scp->length;
3288 qfi.u.QFstandardInfo.endOfFile = scp->length;
3289 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3290 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3291 qfi.u.QFstandardInfo.directory =
3292 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3293 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3294 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3296 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3297 qfi.u.QFeaInfo.eaSize = 0;
3299 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3303 lock_ReleaseMutex(&scp->mx);
3304 lock_ObtainMutex(&fidp->mx);
3305 lock_ObtainMutex(&scp->mx);
3306 if (fidp->NTopen_wholepathp)
3307 name = fidp->NTopen_wholepathp;
3309 name = "\\"; /* probably can't happen */
3310 lock_ReleaseMutex(&fidp->mx);
3311 len = (unsigned long)strlen(name);
3312 outp->totalData = ((len+1)*2) + 4; /* this is actually what we want to return */
3313 qfi.u.QFfileNameInfo.fileNameLength = (len + 1) * 2;
3314 mbstowcs((unsigned short *)qfi.u.QFfileNameInfo.fileName, name, len + 1);
3317 /* send and free the packets */
3319 lock_ReleaseMutex(&scp->mx);
3320 cm_ReleaseSCache(scp);
3321 cm_ReleaseUser(userp);
3322 smb_ReleaseFID(fidp);
3324 memcpy(outp->datap, &qfi, responseSize);
3325 smb_SendTran2Packet(vcp, outp, opx);
3327 smb_SendTran2Error(vcp, p, opx, code);
3329 smb_FreeTran2Packet(outp);
3334 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3339 unsigned short infoLevel;
3340 smb_tran2Packet_t *outp;
3341 cm_user_t *userp = NULL;
3342 cm_scache_t *scp = NULL;
3348 fidp = smb_FindFID(vcp, fid, 0);
3351 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3355 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3356 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3357 smb_CloseFID(vcp, fidp, NULL, 0);
3358 smb_ReleaseFID(fidp);
3362 infoLevel = p->parmsp[1];
3363 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3364 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3365 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3366 p->opcode, infoLevel);
3367 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3368 smb_ReleaseFID(fidp);
3372 lock_ObtainMutex(&fidp->mx);
3373 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
3374 !(fidp->flags & SMB_FID_OPENDELETE)) {
3375 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3376 fidp, fidp->scp, fidp->flags);
3377 lock_ReleaseMutex(&fidp->mx);
3378 smb_ReleaseFID(fidp);
3379 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3382 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3383 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3384 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3385 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3386 fidp, fidp->scp, fidp->flags);
3387 lock_ReleaseMutex(&fidp->mx);
3388 smb_ReleaseFID(fidp);
3389 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3394 osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3396 lock_ReleaseMutex(&fidp->mx);
3398 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3400 outp->totalParms = 2;
3401 outp->totalData = 0;
3403 userp = smb_GetTran2User(vcp, p);
3405 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3406 code = CM_ERROR_BADSMB;
3410 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3412 unsigned int attribute;
3414 smb_tran2QFileInfo_t *sfi;
3416 sfi = (smb_tran2QFileInfo_t *)p->datap;
3418 /* lock the vnode with a callback; we need the current status
3419 * to determine what the new status is, in some cases.
3421 lock_ObtainMutex(&scp->mx);
3422 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3423 CM_SCACHESYNC_GETSTATUS
3424 | CM_SCACHESYNC_NEEDCALLBACK);
3426 lock_ReleaseMutex(&scp->mx);
3430 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3432 lock_ReleaseMutex(&scp->mx);
3433 lock_ObtainMutex(&fidp->mx);
3434 lock_ObtainMutex(&scp->mx);
3436 /* prepare for setattr call */
3439 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3440 /* when called as result of move a b, lastMod is (-1, -1).
3441 * If the check for -1 is not present, timestamp
3442 * of the resulting file will be 1969 (-1)
3444 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3445 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3446 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3447 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3448 fidp->flags |= SMB_FID_MTIMESETDONE;
3451 attribute = sfi->u.QFbasicInfo.attributes;
3452 if (attribute != 0) {
3453 if ((scp->unixModeBits & 0222)
3454 && (attribute & SMB_ATTR_READONLY) != 0) {
3455 /* make a writable file read-only */
3456 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3457 attr.unixModeBits = scp->unixModeBits & ~0222;
3459 else if ((scp->unixModeBits & 0222) == 0
3460 && (attribute & SMB_ATTR_READONLY) == 0) {
3461 /* make a read-only file writable */
3462 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3463 attr.unixModeBits = scp->unixModeBits | 0222;
3466 lock_ReleaseMutex(&scp->mx);
3467 lock_ReleaseMutex(&fidp->mx);
3471 code = cm_SetAttr(scp, &attr, userp, &req);
3475 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3476 int delflag = *((char *)(p->datap));
3477 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
3478 delflag, fidp, scp);
3479 if (*((char *)(p->datap))) { /* File is Deleted */
3480 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3483 lock_ObtainMutex(&fidp->mx);
3484 fidp->flags |= SMB_FID_DELONCLOSE;
3485 lock_ReleaseMutex(&fidp->mx);
3487 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
3493 lock_ObtainMutex(&fidp->mx);
3494 fidp->flags &= ~SMB_FID_DELONCLOSE;
3495 lock_ReleaseMutex(&fidp->mx);
3498 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3499 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3500 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3503 attr.mask = CM_ATTRMASK_LENGTH;
3504 attr.length.LowPart = size.LowPart;
3505 attr.length.HighPart = size.HighPart;
3506 code = cm_SetAttr(scp, &attr, userp, &req);
3510 cm_ReleaseSCache(scp);
3511 cm_ReleaseUser(userp);
3512 smb_ReleaseFID(fidp);
3514 smb_SendTran2Packet(vcp, outp, opx);
3516 smb_SendTran2Error(vcp, p, opx, code);
3517 smb_FreeTran2Packet(outp);
3523 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3525 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3526 return CM_ERROR_BADOP;
3530 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3532 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3533 return CM_ERROR_BADOP;
3537 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3539 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3540 return CM_ERROR_BADOP;
3544 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3546 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3547 return CM_ERROR_BADOP;
3551 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3553 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3554 return CM_ERROR_BADOP;
3558 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3560 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3561 return CM_ERROR_BADOP;
3564 struct smb_v2_referral {
3566 USHORT ReferralFlags;
3569 USHORT DfsPathOffset;
3570 USHORT DfsAlternativePathOffset;
3571 USHORT NetworkAddressOffset;
3575 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3577 /* This is a UNICODE only request (bit15 of Flags2) */
3578 /* The TID must be IPC$ */
3580 /* The documentation for the Flags response field is contradictory */
3582 /* Use Version 1 Referral Element Format */
3583 /* ServerType = 0; indicates the next server should be queried for the file */
3584 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3585 /* Node = UnicodeString of UNC path of the next share name */
3588 int maxReferralLevel = 0;
3589 char requestFileName[1024] = "";
3590 char referralPath[1024] = "";
3591 smb_tran2Packet_t *outp = 0;
3592 cm_user_t *userp = 0;
3593 cm_scache_t *scp = 0;
3594 cm_scache_t *dscp = 0;
3596 CPINFO CodePageInfo;
3597 int i, nbnLen, reqLen, refLen;
3602 maxReferralLevel = p->parmsp[0];
3604 GetCPInfo(CP_ACP, &CodePageInfo);
3605 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
3606 requestFileName, 1024, NULL, NULL);
3608 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
3609 maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3611 nbnLen = strlen(cm_NetbiosName);
3612 reqLen = strlen(requestFileName);
3614 if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
3615 !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3616 requestFileName[nbnLen+1] == '\\')