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, 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, 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);
1071 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1073 SMB_SHARE_IS_IN_DFS |
1078 smb_SetSMBParm(outp, 2, 0);
1082 smb_ReleaseUID(uidp);
1084 lock_ObtainMutex(&tidp->mx);
1085 tidp->userp = userp;
1086 tidp->pathname = sharePath;
1088 tidp->flags |= SMB_TIDFLAG_IPC;
1089 lock_ReleaseMutex(&tidp->mx);
1090 smb_ReleaseTID(tidp);
1092 ((smb_t *)outp)->tid = newTid;
1093 ((smb_t *)inp)->tid = newTid;
1094 tp = smb_GetSMBData(outp, NULL);
1096 /* XXX - why is this a drive letter? */
1104 smb_SetSMBDataLength(outp, 7);
1107 smb_SetSMBDataLength(outp, 4);
1110 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1114 /* must be called with global tran lock held */
1115 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1117 smb_tran2Packet_t *tp;
1120 smbp = (smb_t *) inp->data;
1121 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1122 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1128 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1129 int totalParms, int totalData)
1131 smb_tran2Packet_t *tp;
1134 smbp = (smb_t *) inp->data;
1135 tp = malloc(sizeof(*tp));
1136 memset(tp, 0, sizeof(*tp));
1139 tp->curData = tp->curParms = 0;
1140 tp->totalData = totalData;
1141 tp->totalParms = totalParms;
1142 tp->tid = smbp->tid;
1143 tp->mid = smbp->mid;
1144 tp->uid = smbp->uid;
1145 tp->pid = smbp->pid;
1146 tp->res[0] = smbp->res[0];
1147 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1148 if (totalParms != 0)
1149 tp->parmsp = malloc(totalParms);
1151 tp->datap = malloc(totalData);
1152 if (smbp->com == 0x25 || smbp->com == 0x26)
1155 tp->opcode = smb_GetSMBParm(inp, 14);
1158 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1162 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1163 smb_tran2Packet_t *inp, smb_packet_t *outp,
1164 int totalParms, int totalData)
1166 smb_tran2Packet_t *tp;
1167 unsigned short parmOffset;
1168 unsigned short dataOffset;
1169 unsigned short dataAlign;
1171 tp = malloc(sizeof(*tp));
1172 memset(tp, 0, sizeof(*tp));
1175 tp->curData = tp->curParms = 0;
1176 tp->totalData = totalData;
1177 tp->totalParms = totalParms;
1178 tp->oldTotalParms = totalParms;
1183 tp->res[0] = inp->res[0];
1184 tp->opcode = inp->opcode;
1188 * We calculate where the parameters and data will start.
1189 * This calculation must parallel the calculation in
1190 * smb_SendTran2Packet.
1193 parmOffset = 10*2 + 35;
1194 parmOffset++; /* round to even */
1195 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1197 dataOffset = parmOffset + totalParms;
1198 dataAlign = dataOffset & 2; /* quad-align */
1199 dataOffset += dataAlign;
1200 tp->datap = outp->data + dataOffset;
1205 /* free a tran2 packet */
1206 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1209 smb_ReleaseVC(t2p->vcp);
1212 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1221 /* called with a VC, an input packet to respond to, and an error code.
1222 * sends an error response.
1224 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1225 smb_packet_t *tp, long code)
1228 unsigned short errCode;
1229 unsigned char errClass;
1230 unsigned long NTStatus;
1232 if (vcp->flags & SMB_VCFLAG_STATUS32)
1233 smb_MapNTError(code, &NTStatus);
1235 smb_MapCoreError(code, vcp, &errCode, &errClass);
1237 smb_FormatResponsePacket(vcp, NULL, tp);
1238 smbp = (smb_t *) tp;
1240 /* We can handle long names */
1241 if (vcp->flags & SMB_VCFLAG_USENT)
1242 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1244 /* now copy important fields from the tran 2 packet */
1245 smbp->com = t2p->com;
1246 smbp->tid = t2p->tid;
1247 smbp->mid = t2p->mid;
1248 smbp->pid = t2p->pid;
1249 smbp->uid = t2p->uid;
1250 smbp->res[0] = t2p->res[0];
1251 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1252 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1253 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1254 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1255 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1256 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1259 smbp->rcls = errClass;
1260 smbp->errLow = (unsigned char) (errCode & 0xff);
1261 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1265 smb_SendPacket(vcp, tp);
1268 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1271 unsigned short parmOffset;
1272 unsigned short dataOffset;
1273 unsigned short totalLength;
1274 unsigned short dataAlign;
1277 smb_FormatResponsePacket(vcp, NULL, tp);
1278 smbp = (smb_t *) tp;
1280 /* We can handle long names */
1281 if (vcp->flags & SMB_VCFLAG_USENT)
1282 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1284 /* now copy important fields from the tran 2 packet */
1285 smbp->com = t2p->com;
1286 smbp->tid = t2p->tid;
1287 smbp->mid = t2p->mid;
1288 smbp->pid = t2p->pid;
1289 smbp->uid = t2p->uid;
1290 smbp->res[0] = t2p->res[0];
1292 totalLength = 1 + t2p->totalData + t2p->totalParms;
1294 /* now add the core parameters (tran2 info) to the packet */
1295 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1296 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1297 smb_SetSMBParm(tp, 2, 0); /* reserved */
1298 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1299 parmOffset = 10*2 + 35; /* parm offset in packet */
1300 parmOffset++; /* round to even */
1301 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1302 * hdr, bcc and wct */
1303 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1304 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1305 dataOffset = parmOffset + t2p->oldTotalParms;
1306 dataAlign = dataOffset & 2; /* quad-align */
1307 dataOffset += dataAlign;
1308 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1309 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1310 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1313 datap = smb_GetSMBData(tp, NULL);
1314 *datap++ = 0; /* we rounded to even */
1316 totalLength += dataAlign;
1317 smb_SetSMBDataLength(tp, totalLength);
1319 /* next, send the datagram */
1320 smb_SendPacket(vcp, tp);
1323 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1325 smb_tran2Packet_t *asp;
1338 /* We sometimes see 0 word count. What to do? */
1339 if (*inp->wctp == 0) {
1340 osi_Log0(smb_logp, "Transaction2 word count = 0");
1341 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1343 smb_SetSMBDataLength(outp, 0);
1344 smb_SendPacket(vcp, outp);
1348 totalParms = smb_GetSMBParm(inp, 0);
1349 totalData = smb_GetSMBParm(inp, 1);
1351 firstPacket = (inp->inCom == 0x25);
1353 /* find the packet we're reassembling */
1354 lock_ObtainWrite(&smb_globalLock);
1355 asp = smb_FindTran2Packet(vcp, inp);
1357 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1359 lock_ReleaseWrite(&smb_globalLock);
1361 /* now merge in this latest packet; start by looking up offsets */
1363 parmDisp = dataDisp = 0;
1364 parmOffset = smb_GetSMBParm(inp, 10);
1365 dataOffset = smb_GetSMBParm(inp, 12);
1366 parmCount = smb_GetSMBParm(inp, 9);
1367 dataCount = smb_GetSMBParm(inp, 11);
1368 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1369 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1371 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1372 totalData, dataCount, asp->maxReturnData);
1375 parmDisp = smb_GetSMBParm(inp, 4);
1376 parmOffset = smb_GetSMBParm(inp, 3);
1377 dataDisp = smb_GetSMBParm(inp, 7);
1378 dataOffset = smb_GetSMBParm(inp, 6);
1379 parmCount = smb_GetSMBParm(inp, 2);
1380 dataCount = smb_GetSMBParm(inp, 5);
1382 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1383 parmCount, dataCount);
1386 /* now copy the parms and data */
1387 if ( asp->totalParms > 0 && parmCount != 0 )
1389 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1391 if ( asp->totalData > 0 && dataCount != 0 ) {
1392 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1395 /* account for new bytes */
1396 asp->curData += dataCount;
1397 asp->curParms += parmCount;
1399 /* finally, if we're done, remove the packet from the queue and dispatch it */
1400 if (asp->totalParms > 0 &&
1401 asp->curParms > 0 &&
1402 asp->totalData <= asp->curData &&
1403 asp->totalParms <= asp->curParms) {
1404 /* we've received it all */
1405 lock_ObtainWrite(&smb_globalLock);
1406 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1407 lock_ReleaseWrite(&smb_globalLock);
1409 /* now dispatch it */
1410 rapOp = asp->parmsp[0];
1412 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1413 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1414 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1415 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
1418 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1419 code = CM_ERROR_BADOP;
1422 /* if an error is returned, we're supposed to send an error packet,
1423 * otherwise the dispatched function already did the data sending.
1424 * We give dispatched proc the responsibility since it knows how much
1425 * space to allocate.
1428 smb_SendTran2Error(vcp, asp, outp, code);
1431 /* free the input tran 2 packet */
1432 smb_FreeTran2Packet(asp);
1434 else if (firstPacket) {
1435 /* the first packet in a multi-packet request, we need to send an
1436 * ack to get more data.
1438 smb_SetSMBDataLength(outp, 0);
1439 smb_SendPacket(vcp, outp);
1445 /* ANSI versions. The unicode versions support arbitrary length
1446 share names, but we don't support unicode yet. */
1448 typedef struct smb_rap_share_info_0 {
1449 char shi0_netname[13];
1450 } smb_rap_share_info_0_t;
1452 typedef struct smb_rap_share_info_1 {
1453 char shi1_netname[13];
1456 DWORD shi1_remark; /* char *shi1_remark; data offset */
1457 } smb_rap_share_info_1_t;
1459 typedef struct smb_rap_share_info_2 {
1460 char shi2_netname[13];
1462 unsigned short shi2_type;
1463 DWORD shi2_remark; /* char *shi2_remark; data offset */
1464 unsigned short shi2_permissions;
1465 unsigned short shi2_max_uses;
1466 unsigned short shi2_current_uses;
1467 DWORD shi2_path; /* char *shi2_path; data offset */
1468 unsigned short shi2_passwd[9];
1469 unsigned short shi2_pad2;
1470 } smb_rap_share_info_2_t;
1472 #define SMB_RAP_MAX_SHARES 512
1474 typedef struct smb_rap_share_list {
1477 smb_rap_share_info_0_t * shares;
1478 } smb_rap_share_list_t;
1480 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1481 smb_rap_share_list_t * sp;
1486 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1487 return 0; /* skip over '.' and '..' */
1489 sp = (smb_rap_share_list_t *) vrockp;
1491 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1492 sp->shares[sp->cShare].shi0_netname[12] = 0;
1496 if (sp->cShare >= sp->maxShares)
1497 return CM_ERROR_STOPNOW;
1502 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1504 smb_tran2Packet_t *outp;
1505 unsigned short * tp;
1509 int outParmsTotal; /* total parameter bytes */
1510 int outDataTotal; /* total data bytes */
1513 DWORD allSubmount = 0;
1515 DWORD nRegShares = 0;
1516 DWORD nSharesRet = 0;
1518 HKEY hkSubmount = NULL;
1519 smb_rap_share_info_1_t * shares;
1522 char thisShare[AFSPATHMAX];
1526 smb_rap_share_list_t rootShares;
1531 tp = p->parmsp + 1; /* skip over function number (always 0) */
1532 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1533 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1537 if (infoLevel != 1) {
1538 return CM_ERROR_INVAL;
1541 /* first figure out how many shares there are */
1542 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1543 KEY_QUERY_VALUE, &hkParam);
1544 if (rv == ERROR_SUCCESS) {
1545 len = sizeof(allSubmount);
1546 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1547 (BYTE *) &allSubmount, &len);
1548 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1551 RegCloseKey (hkParam);
1554 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1555 0, KEY_QUERY_VALUE, &hkSubmount);
1556 if (rv == ERROR_SUCCESS) {
1557 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1558 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1559 if (rv != ERROR_SUCCESS)
1565 /* fetch the root shares */
1566 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1567 rootShares.cShare = 0;
1568 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1572 userp = smb_GetTran2User(vcp,p);
1574 thyper.HighPart = 0;
1577 cm_HoldSCache(cm_data.rootSCachep);
1578 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1579 cm_ReleaseSCache(cm_data.rootSCachep);
1581 cm_ReleaseUser(userp);
1583 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1585 #define REMARK_LEN 1
1586 outParmsTotal = 8; /* 4 dwords */
1587 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1588 if(outDataTotal > bufsize) {
1589 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1590 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1593 nSharesRet = nShares;
1596 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1598 /* now for the submounts */
1599 shares = (smb_rap_share_info_1_t *) outp->datap;
1600 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1602 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1605 strcpy( shares[cshare].shi1_netname, "all" );
1606 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1607 /* type and pad are zero already */
1613 for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
1614 len = sizeof(thisShare);
1615 rv = RegEnumValue(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
1616 if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1617 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1618 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1619 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1624 nShares--; /* uncount key */
1627 RegCloseKey(hkSubmount);
1630 nonrootShares = cshare;
1632 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1633 /* in case there are collisions with submounts, submounts have higher priority */
1634 for (j=0; j < nonrootShares; j++)
1635 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1638 if (j < nonrootShares) {
1639 nShares--; /* uncount */
1643 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1644 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1649 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1650 outp->parmsp[1] = 0;
1651 outp->parmsp[2] = cshare;
1652 outp->parmsp[3] = nShares;
1654 outp->totalData = (int)(cstrp - outp->datap);
1655 outp->totalParms = outParmsTotal;
1657 smb_SendTran2Packet(vcp, outp, op);
1658 smb_FreeTran2Packet(outp);
1660 free(rootShares.shares);
1665 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1667 smb_tran2Packet_t *outp;
1668 unsigned short * tp;
1670 BOOL shareFound = FALSE;
1671 unsigned short infoLevel;
1672 unsigned short bufsize;
1682 tp = p->parmsp + 1; /* skip over function number (always 1) */
1683 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1684 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1685 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1692 totalData = sizeof(smb_rap_share_info_0_t);
1693 else if(infoLevel == SMB_INFO_STANDARD)
1694 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1695 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1696 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1698 return CM_ERROR_INVAL;
1700 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1702 if(!stricmp(shareName,"all") || !strcmp(shareName,"*.")) {
1703 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1704 KEY_QUERY_VALUE, &hkParam);
1705 if (rv == ERROR_SUCCESS) {
1706 len = sizeof(allSubmount);
1707 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1708 (BYTE *) &allSubmount, &len);
1709 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1712 RegCloseKey (hkParam);
1719 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1720 KEY_QUERY_VALUE, &hkSubmount);
1721 if (rv == ERROR_SUCCESS) {
1722 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1723 if (rv == ERROR_SUCCESS) {
1726 RegCloseKey(hkSubmount);
1731 smb_FreeTran2Packet(outp);
1732 return CM_ERROR_BADSHARENAME;
1735 memset(outp->datap, 0, totalData);
1737 outp->parmsp[0] = 0;
1738 outp->parmsp[1] = 0;
1739 outp->parmsp[2] = totalData;
1741 if (infoLevel == 0) {
1742 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1743 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1744 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1745 } else if(infoLevel == SMB_INFO_STANDARD) {
1746 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1747 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1748 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1749 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1750 /* type and pad are already zero */
1751 } else { /* infoLevel==2 */
1752 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1753 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1754 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1755 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1756 info->shi2_permissions = ACCESS_ALL;
1757 info->shi2_max_uses = (unsigned short) -1;
1758 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
1761 outp->totalData = totalData;
1762 outp->totalParms = totalParam;
1764 smb_SendTran2Packet(vcp, outp, op);
1765 smb_FreeTran2Packet(outp);
1770 typedef struct smb_rap_wksta_info_10 {
1771 DWORD wki10_computername; /*char *wki10_computername;*/
1772 DWORD wki10_username; /* char *wki10_username; */
1773 DWORD wki10_langroup; /* char *wki10_langroup;*/
1774 unsigned char wki10_ver_major;
1775 unsigned char wki10_ver_minor;
1776 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1777 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1778 } smb_rap_wksta_info_10_t;
1781 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1783 smb_tran2Packet_t *outp;
1787 unsigned short * tp;
1790 smb_rap_wksta_info_10_t * info;
1794 tp = p->parmsp + 1; /* Skip over function number */
1795 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1796 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1800 if (infoLevel != 10) {
1801 return CM_ERROR_INVAL;
1807 totalData = sizeof(*info) + /* info */
1808 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1809 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1810 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1811 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1812 1; /* wki10_oth_domains (null)*/
1814 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1816 memset(outp->parmsp,0,totalParams);
1817 memset(outp->datap,0,totalData);
1819 info = (smb_rap_wksta_info_10_t *) outp->datap;
1820 cstrp = (char *) (info + 1);
1822 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1823 strcpy(cstrp, smb_localNamep);
1824 cstrp += strlen(cstrp) + 1;
1826 info->wki10_username = (DWORD) (cstrp - outp->datap);
1827 uidp = smb_FindUID(vcp, p->uid, 0);
1829 lock_ObtainMutex(&uidp->mx);
1830 if(uidp->unp && uidp->unp->name)
1831 strcpy(cstrp, uidp->unp->name);
1832 lock_ReleaseMutex(&uidp->mx);
1833 smb_ReleaseUID(uidp);
1835 cstrp += strlen(cstrp) + 1;
1837 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1838 strcpy(cstrp, "WORKGROUP");
1839 cstrp += strlen(cstrp) + 1;
1841 /* TODO: Not sure what values these should take, but these work */
1842 info->wki10_ver_major = 5;
1843 info->wki10_ver_minor = 1;
1845 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1846 strcpy(cstrp, smb_ServerDomainName);
1847 cstrp += strlen(cstrp) + 1;
1849 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1850 cstrp ++; /* no other domains */
1852 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1853 outp->parmsp[2] = outp->totalData;
1854 outp->totalParms = totalParams;
1856 smb_SendTran2Packet(vcp,outp,op);
1857 smb_FreeTran2Packet(outp);
1862 typedef struct smb_rap_server_info_0 {
1864 } smb_rap_server_info_0_t;
1866 typedef struct smb_rap_server_info_1 {
1868 char sv1_version_major;
1869 char sv1_version_minor;
1870 unsigned long sv1_type;
1871 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1872 } smb_rap_server_info_1_t;
1874 char smb_ServerComment[] = "OpenAFS Client";
1875 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1877 #define SMB_SV_TYPE_SERVER 0x00000002L
1878 #define SMB_SV_TYPE_NT 0x00001000L
1879 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1881 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1883 smb_tran2Packet_t *outp;
1887 unsigned short * tp;
1890 smb_rap_server_info_0_t * info0;
1891 smb_rap_server_info_1_t * info1;
1894 tp = p->parmsp + 1; /* Skip over function number */
1895 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1896 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1900 if (infoLevel != 0 && infoLevel != 1) {
1901 return CM_ERROR_INVAL;
1907 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1908 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1910 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1912 memset(outp->parmsp,0,totalParams);
1913 memset(outp->datap,0,totalData);
1915 if (infoLevel == 0) {
1916 info0 = (smb_rap_server_info_0_t *) outp->datap;
1917 cstrp = (char *) (info0 + 1);
1918 strcpy(info0->sv0_name, "AFS");
1919 } else { /* infoLevel == SMB_INFO_STANDARD */
1920 info1 = (smb_rap_server_info_1_t *) outp->datap;
1921 cstrp = (char *) (info1 + 1);
1922 strcpy(info1->sv1_name, "AFS");
1925 SMB_SV_TYPE_SERVER |
1927 SMB_SV_TYPE_SERVER_NT;
1929 info1->sv1_version_major = 5;
1930 info1->sv1_version_minor = 1;
1931 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1933 strcpy(cstrp, smb_ServerComment);
1935 cstrp += smb_ServerCommentLen;
1938 totalData = (DWORD)(cstrp - outp->datap);
1939 outp->totalData = min(bufsize,totalData); /* actual data size */
1940 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1941 outp->parmsp[2] = totalData;
1942 outp->totalParms = totalParams;
1944 smb_SendTran2Packet(vcp,outp,op);
1945 smb_FreeTran2Packet(outp);
1950 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1952 smb_tran2Packet_t *asp;
1964 /* We sometimes see 0 word count. What to do? */
1965 if (*inp->wctp == 0) {
1966 osi_Log0(smb_logp, "Transaction2 word count = 0");
1967 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1969 smb_SetSMBDataLength(outp, 0);
1970 smb_SendPacket(vcp, outp);
1974 totalParms = smb_GetSMBParm(inp, 0);
1975 totalData = smb_GetSMBParm(inp, 1);
1977 firstPacket = (inp->inCom == 0x32);
1979 /* find the packet we're reassembling */
1980 lock_ObtainWrite(&smb_globalLock);
1981 asp = smb_FindTran2Packet(vcp, inp);
1983 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1985 lock_ReleaseWrite(&smb_globalLock);
1987 /* now merge in this latest packet; start by looking up offsets */
1989 parmDisp = dataDisp = 0;
1990 parmOffset = smb_GetSMBParm(inp, 10);
1991 dataOffset = smb_GetSMBParm(inp, 12);
1992 parmCount = smb_GetSMBParm(inp, 9);
1993 dataCount = smb_GetSMBParm(inp, 11);
1994 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1995 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1997 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1998 totalData, dataCount, asp->maxReturnData);
2001 parmDisp = smb_GetSMBParm(inp, 4);
2002 parmOffset = smb_GetSMBParm(inp, 3);
2003 dataDisp = smb_GetSMBParm(inp, 7);
2004 dataOffset = smb_GetSMBParm(inp, 6);
2005 parmCount = smb_GetSMBParm(inp, 2);
2006 dataCount = smb_GetSMBParm(inp, 5);
2008 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2009 parmCount, dataCount);
2012 /* now copy the parms and data */
2013 if ( asp->totalParms > 0 && parmCount != 0 )
2015 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2017 if ( asp->totalData > 0 && dataCount != 0 ) {
2018 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2021 /* account for new bytes */
2022 asp->curData += dataCount;
2023 asp->curParms += parmCount;
2025 /* finally, if we're done, remove the packet from the queue and dispatch it */
2026 if (asp->totalParms > 0 &&
2027 asp->curParms > 0 &&
2028 asp->totalData <= asp->curData &&
2029 asp->totalParms <= asp->curParms) {
2030 /* we've received it all */
2031 lock_ObtainWrite(&smb_globalLock);
2032 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2033 lock_ReleaseWrite(&smb_globalLock);
2035 /* now dispatch it */
2036 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2037 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2038 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2041 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2042 code = CM_ERROR_BADOP;
2045 /* if an error is returned, we're supposed to send an error packet,
2046 * otherwise the dispatched function already did the data sending.
2047 * We give dispatched proc the responsibility since it knows how much
2048 * space to allocate.
2051 smb_SendTran2Error(vcp, asp, outp, code);
2054 /* free the input tran 2 packet */
2055 smb_FreeTran2Packet(asp);
2057 else if (firstPacket) {
2058 /* the first packet in a multi-packet request, we need to send an
2059 * ack to get more data.
2061 smb_SetSMBDataLength(outp, 0);
2062 smb_SendPacket(vcp, outp);
2068 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2071 smb_tran2Packet_t *outp;
2076 cm_scache_t *dscp; /* dir we're dealing with */
2077 cm_scache_t *scp; /* file we're creating */
2079 int initialModeBits;
2089 int parmSlot; /* which parm we're dealing with */
2090 long returnEALength;
2099 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2100 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2102 openFun = p->parmsp[6]; /* open function */
2103 excl = ((openFun & 3) == 0);
2104 trunc = ((openFun & 3) == 2); /* truncate it */
2105 openMode = (p->parmsp[1] & 0x7);
2106 openAction = 0; /* tracks what we did */
2108 attributes = p->parmsp[3];
2109 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2111 /* compute initial mode bits based on read-only flag in attributes */
2112 initialModeBits = 0666;
2113 if (attributes & SMB_ATTR_READONLY)
2114 initialModeBits &= ~0222;
2116 pathp = (char *) (&p->parmsp[14]);
2117 if (smb_StoreAnsiFilenames)
2118 OemToChar(pathp,pathp);
2120 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2122 spacep = cm_GetSpace();
2123 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2125 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2126 /* special case magic file name for receiving IOCTL requests
2127 * (since IOCTL calls themselves aren't getting through).
2129 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2130 smb_SetupIoctlFid(fidp, spacep);
2132 /* copy out remainder of the parms */
2134 outp->parmsp[parmSlot++] = fidp->fid;
2136 outp->parmsp[parmSlot++] = 0; /* attrs */
2137 outp->parmsp[parmSlot++] = 0; /* mod time */
2138 outp->parmsp[parmSlot++] = 0;
2139 outp->parmsp[parmSlot++] = 0; /* len */
2140 outp->parmsp[parmSlot++] = 0x7fff;
2141 outp->parmsp[parmSlot++] = openMode;
2142 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2143 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2145 /* and the final "always present" stuff */
2146 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2147 /* next write out the "unique" ID */
2148 outp->parmsp[parmSlot++] = 0x1234;
2149 outp->parmsp[parmSlot++] = 0x5678;
2150 outp->parmsp[parmSlot++] = 0;
2151 if (returnEALength) {
2152 outp->parmsp[parmSlot++] = 0;
2153 outp->parmsp[parmSlot++] = 0;
2156 outp->totalData = 0;
2157 outp->totalParms = parmSlot * 2;
2159 smb_SendTran2Packet(vcp, outp, op);
2161 smb_FreeTran2Packet(outp);
2163 /* and clean up fid reference */
2164 smb_ReleaseFID(fidp);
2168 #ifdef DEBUG_VERBOSE
2170 char *hexp, *asciip;
2171 asciip = (lastNamep ? lastNamep : pathp);
2172 hexp = osi_HexifyString( asciip );
2173 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2178 userp = smb_GetTran2User(vcp, p);
2179 /* In the off chance that userp is NULL, we log and abandon */
2181 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2182 smb_FreeTran2Packet(outp);
2183 return CM_ERROR_BADSMB;
2186 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2187 if (code == CM_ERROR_TIDIPC) {
2188 /* Attempt to use a TID allocated for IPC. The client
2189 * is probably looking for DCE RPC end points which we
2190 * don't support OR it could be looking to make a DFS
2193 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2195 cm_ReleaseUser(userp);
2196 smb_FreeTran2Packet(outp);
2197 return CM_ERROR_NOSUCHPATH;
2202 code = cm_NameI(cm_data.rootSCachep, pathp,
2203 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2204 userp, tidPathp, &req, &scp);
2206 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2207 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2208 userp, tidPathp, &req, &dscp);
2209 cm_FreeSpace(spacep);
2212 cm_ReleaseUser(userp);
2213 smb_FreeTran2Packet(outp);
2218 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2219 cm_ReleaseSCache(dscp);
2220 cm_ReleaseUser(userp);
2221 smb_FreeTran2Packet(outp);
2222 if ( WANTS_DFS_PATHNAMES(p) )
2223 return CM_ERROR_PATH_NOT_COVERED;
2225 return CM_ERROR_BADSHARENAME;
2227 #endif /* DFS_SUPPORT */
2229 /* otherwise, scp points to the parent directory. Do a lookup,
2230 * and truncate the file if we find it, otherwise we create the
2237 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2239 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2240 cm_ReleaseSCache(dscp);
2241 cm_ReleaseUser(userp);
2242 smb_FreeTran2Packet(outp);
2247 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2248 cm_ReleaseSCache(scp);
2249 cm_ReleaseUser(userp);
2250 smb_FreeTran2Packet(outp);
2251 if ( WANTS_DFS_PATHNAMES(p) )
2252 return CM_ERROR_PATH_NOT_COVERED;
2254 return CM_ERROR_BADSHARENAME;
2256 #endif /* DFS_SUPPORT */
2258 /* macintosh is expensive to program for it */
2259 cm_FreeSpace(spacep);
2262 /* if we get here, if code is 0, the file exists and is represented by
2263 * scp. Otherwise, we have to create it.
2266 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2269 cm_ReleaseSCache(dscp);
2270 cm_ReleaseSCache(scp);
2271 cm_ReleaseUser(userp);
2272 smb_FreeTran2Packet(outp);
2277 /* oops, file shouldn't be there */
2279 cm_ReleaseSCache(dscp);
2280 cm_ReleaseSCache(scp);
2281 cm_ReleaseUser(userp);
2282 smb_FreeTran2Packet(outp);
2283 return CM_ERROR_EXISTS;
2287 setAttr.mask = CM_ATTRMASK_LENGTH;
2288 setAttr.length.LowPart = 0;
2289 setAttr.length.HighPart = 0;
2290 code = cm_SetAttr(scp, &setAttr, userp, &req);
2291 openAction = 3; /* truncated existing file */
2294 openAction = 1; /* found existing file */
2296 else if (!(openFun & 0x10)) {
2297 /* don't create if not found */
2299 cm_ReleaseSCache(dscp);
2300 osi_assertx(scp == NULL, "null cm_scache_t");
2301 cm_ReleaseUser(userp);
2302 smb_FreeTran2Packet(outp);
2303 return CM_ERROR_NOSUCHFILE;
2306 osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2307 openAction = 2; /* created file */
2308 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2309 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2310 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2314 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2315 smb_NotifyChange(FILE_ACTION_ADDED,
2316 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2317 dscp, lastNamep, NULL, TRUE);
2318 } else if (!excl && code == CM_ERROR_EXISTS) {
2319 /* not an exclusive create, and someone else tried
2320 * creating it already, then we open it anyway. We
2321 * don't bother retrying after this, since if this next
2322 * fails, that means that the file was deleted after we
2323 * started this call.
2325 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2329 setAttr.mask = CM_ATTRMASK_LENGTH;
2330 setAttr.length.LowPart = 0;
2331 setAttr.length.HighPart = 0;
2332 code = cm_SetAttr(scp, &setAttr, userp,
2335 } /* lookup succeeded */
2339 /* we don't need this any longer */
2341 cm_ReleaseSCache(dscp);
2344 /* something went wrong creating or truncating the file */
2346 cm_ReleaseSCache(scp);
2347 cm_ReleaseUser(userp);
2348 smb_FreeTran2Packet(outp);
2352 /* make sure we're about to open a file */
2353 if (scp->fileType != CM_SCACHETYPE_FILE) {
2355 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2356 cm_scache_t * targetScp = 0;
2357 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2359 /* we have a more accurate file to use (the
2360 * target of the symbolic link). Otherwise,
2361 * we'll just use the symlink anyway.
2363 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2365 cm_ReleaseSCache(scp);
2369 if (scp->fileType != CM_SCACHETYPE_FILE) {
2370 cm_ReleaseSCache(scp);
2371 cm_ReleaseUser(userp);
2372 smb_FreeTran2Packet(outp);
2373 return CM_ERROR_ISDIR;
2377 /* now all we have to do is open the file itself */
2378 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2379 osi_assertx(fidp, "null smb_fid_t");
2382 lock_ObtainMutex(&fidp->mx);
2383 /* save a pointer to the vnode */
2384 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2386 lock_ObtainMutex(&scp->mx);
2387 scp->flags |= CM_SCACHEFLAG_SMB_FID;
2388 lock_ReleaseMutex(&scp->mx);
2391 fidp->userp = userp;
2393 /* compute open mode */
2395 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
2396 if (openMode == 1 || openMode == 2)
2397 fidp->flags |= SMB_FID_OPENWRITE;
2399 /* remember that the file was newly created */
2401 fidp->flags |= SMB_FID_CREATED;
2403 lock_ReleaseMutex(&fidp->mx);
2405 smb_ReleaseFID(fidp);
2407 cm_Open(scp, 0, userp);
2409 /* copy out remainder of the parms */
2411 outp->parmsp[parmSlot++] = fidp->fid;
2412 lock_ObtainMutex(&scp->mx);
2414 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2415 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2416 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2417 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2418 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2419 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2420 outp->parmsp[parmSlot++] = openMode;
2421 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2422 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2424 /* and the final "always present" stuff */
2425 outp->parmsp[parmSlot++] = openAction;
2426 /* next write out the "unique" ID */
2427 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2428 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2429 outp->parmsp[parmSlot++] = 0;
2430 if (returnEALength) {
2431 outp->parmsp[parmSlot++] = 0;
2432 outp->parmsp[parmSlot++] = 0;
2434 lock_ReleaseMutex(&scp->mx);
2435 outp->totalData = 0; /* total # of data bytes */
2436 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2438 smb_SendTran2Packet(vcp, outp, op);
2440 smb_FreeTran2Packet(outp);
2442 cm_ReleaseUser(userp);
2443 /* leave scp held since we put it in fidp->scp */
2447 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2450 unsigned short infolevel;
2452 infolevel = p->parmsp[0];
2454 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2456 return CM_ERROR_BAD_LEVEL;
2459 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2461 smb_tran2Packet_t *outp;
2462 smb_tran2QFSInfo_t qi;
2464 static char FSname[8] = {'A', 0, 'F', 0, 'S', 0, 0, 0};
2466 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2468 switch (p->parmsp[0]) {
2469 case SMB_INFO_ALLOCATION:
2470 responseSize = sizeof(qi.u.allocInfo);
2472 case SMB_INFO_VOLUME:
2473 responseSize = sizeof(qi.u.volumeInfo);
2475 case SMB_QUERY_FS_VOLUME_INFO:
2476 responseSize = sizeof(qi.u.FSvolumeInfo);
2478 case SMB_QUERY_FS_SIZE_INFO:
2479 responseSize = sizeof(qi.u.FSsizeInfo);
2481 case SMB_QUERY_FS_DEVICE_INFO:
2482 responseSize = sizeof(qi.u.FSdeviceInfo);
2484 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2485 responseSize = sizeof(qi.u.FSattributeInfo);
2487 case SMB_INFO_UNIX: /* CIFS Unix Info */
2488 case SMB_INFO_MACOS: /* Mac FS Info */
2490 return CM_ERROR_BADOP;
2493 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2494 switch (p->parmsp[0]) {
2495 case SMB_INFO_ALLOCATION:
2497 qi.u.allocInfo.FSID = 0;
2498 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2499 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2500 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2501 qi.u.allocInfo.bytesPerSector = 1024;
2504 case SMB_INFO_VOLUME:
2506 qi.u.volumeInfo.vsn = 1234;
2507 qi.u.volumeInfo.vnCount = 4;
2508 /* we're supposed to pad it out with zeroes to the end */
2509 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2510 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2513 case SMB_QUERY_FS_VOLUME_INFO:
2514 /* FS volume info */
2515 memset((char *)&qi.u.FSvolumeInfo.vct, 0, 4);
2516 qi.u.FSvolumeInfo.vsn = 1234;
2517 qi.u.FSvolumeInfo.vnCount = 8;
2518 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0\0", 8);
2521 case SMB_QUERY_FS_SIZE_INFO:
2523 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2524 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2525 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2526 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2527 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2528 qi.u.FSsizeInfo.bytesPerSector = 1024;
2531 case SMB_QUERY_FS_DEVICE_INFO:
2532 /* FS device info */
2533 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2534 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2537 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2538 /* FS attribute info */
2539 /* attributes, defined in WINNT.H:
2540 * FILE_CASE_SENSITIVE_SEARCH 0x1
2541 * FILE_CASE_PRESERVED_NAMES 0x2
2542 * FILE_VOLUME_QUOTAS 0x10
2543 * <no name defined> 0x4000
2544 * If bit 0x4000 is not set, Windows 95 thinks
2545 * we can't handle long (non-8.3) names,
2546 * despite our protestations to the contrary.
2548 qi.u.FSattributeInfo.attributes = 0x4003;
2549 qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
2550 qi.u.FSattributeInfo.FSnameLength = sizeof(FSname);
2551 memcpy(qi.u.FSattributeInfo.FSname, FSname, sizeof(FSname));
2555 /* copy out return data, and set corresponding sizes */
2556 outp->totalParms = 0;
2557 outp->totalData = responseSize;
2558 memcpy(outp->datap, &qi, responseSize);
2560 /* send and free the packets */
2561 smb_SendTran2Packet(vcp, outp, op);
2562 smb_FreeTran2Packet(outp);
2567 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2569 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2570 return CM_ERROR_BADOP;
2573 struct smb_ShortNameRock {
2577 size_t shortNameLen;
2580 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2583 struct smb_ShortNameRock *rockp;
2587 /* compare both names and vnodes, though probably just comparing vnodes
2588 * would be safe enough.
2590 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2592 if (ntohl(dep->fid.vnode) != rockp->vnode)
2594 /* This is the entry */
2595 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2596 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2597 return CM_ERROR_STOPNOW;
2600 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2601 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2603 struct smb_ShortNameRock rock;
2607 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2611 spacep = cm_GetSpace();
2612 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2614 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2616 cm_FreeSpace(spacep);
2621 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2622 cm_ReleaseSCache(dscp);
2623 cm_ReleaseUser(userp);
2624 return CM_ERROR_PATH_NOT_COVERED;
2626 #endif /* DFS_SUPPORT */
2628 if (!lastNamep) lastNamep = pathp;
2631 thyper.HighPart = 0;
2632 rock.shortName = shortName;
2634 rock.maskp = lastNamep;
2635 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2637 cm_ReleaseSCache(dscp);
2640 return CM_ERROR_NOSUCHFILE;
2641 if (code == CM_ERROR_STOPNOW) {
2642 *shortNameLenp = rock.shortNameLen;
2648 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2650 smb_tran2Packet_t *outp;
2653 unsigned short infoLevel;
2654 smb_tran2QPathInfo_t qpi;
2656 unsigned short attributes;
2657 unsigned long extAttributes;
2662 cm_scache_t *scp, *dscp;
2663 int scp_mx_held = 0;
2673 infoLevel = p->parmsp[0];
2674 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2676 else if (infoLevel == SMB_INFO_STANDARD)
2677 responseSize = sizeof(qpi.u.QPstandardInfo);
2678 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2679 responseSize = sizeof(qpi.u.QPeaSizeInfo);
2680 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2681 responseSize = sizeof(qpi.u.QPfileBasicInfo);
2682 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2683 responseSize = sizeof(qpi.u.QPfileStandardInfo);
2684 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2685 responseSize = sizeof(qpi.u.QPfileEaInfo);
2686 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2687 responseSize = sizeof(qpi.u.QPfileNameInfo);
2688 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
2689 responseSize = sizeof(qpi.u.QPfileAllInfo);
2690 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2691 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2693 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2694 p->opcode, infoLevel);
2695 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
2699 pathp = (char *)(&p->parmsp[3]);
2700 if (smb_StoreAnsiFilenames)
2701 OemToChar(pathp,pathp);
2702 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2703 osi_LogSaveString(smb_logp, pathp));
2705 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2707 if (infoLevel > 0x100)
2708 outp->totalParms = 2;
2710 outp->totalParms = 0;
2711 outp->totalData = responseSize;
2713 /* now, if we're at infoLevel 6, we're only being asked to check
2714 * the syntax, so we just OK things now. In particular, we're *not*
2715 * being asked to verify anything about the state of any parent dirs.
2717 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2718 smb_SendTran2Packet(vcp, outp, opx);
2719 smb_FreeTran2Packet(outp);
2723 userp = smb_GetTran2User(vcp, p);
2725 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2726 smb_FreeTran2Packet(outp);
2727 return CM_ERROR_BADSMB;
2730 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2732 cm_ReleaseUser(userp);
2733 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2734 smb_FreeTran2Packet(outp);
2739 * XXX Strange hack XXX
2741 * As of Patch 7 (13 January 98), we are having the following problem:
2742 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2743 * requests to look up "desktop.ini" in all the subdirectories.
2744 * This can cause zillions of timeouts looking up non-existent cells
2745 * and volumes, especially in the top-level directory.
2747 * We have not found any way to avoid this or work around it except
2748 * to explicitly ignore the requests for mount points that haven't
2749 * yet been evaluated and for directories that haven't yet been
2752 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2753 spacep = cm_GetSpace();
2754 smb_StripLastComponent(spacep->data, &lastComp, pathp);
2755 #ifndef SPECIAL_FOLDERS
2756 /* Make sure that lastComp is not NULL */
2758 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2759 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2763 userp, tidPathp, &req, &dscp);
2766 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2767 if ( WANTS_DFS_PATHNAMES(p) )
2768 code = CM_ERROR_PATH_NOT_COVERED;
2770 code = CM_ERROR_BADSHARENAME;
2772 #endif /* DFS_SUPPORT */
2773 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2774 code = CM_ERROR_NOSUCHFILE;
2775 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2776 cm_buf_t *bp = buf_Find(dscp, &hzero);
2782 code = CM_ERROR_NOSUCHFILE;
2784 cm_ReleaseSCache(dscp);
2786 cm_FreeSpace(spacep);
2787 cm_ReleaseUser(userp);
2788 smb_SendTran2Error(vcp, p, opx, code);
2789 smb_FreeTran2Packet(outp);
2795 #endif /* SPECIAL_FOLDERS */
2797 cm_FreeSpace(spacep);
2800 /* now do namei and stat, and copy out the info */
2801 code = cm_NameI(cm_data.rootSCachep, pathp,
2802 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2805 cm_ReleaseUser(userp);
2806 smb_SendTran2Error(vcp, p, opx, code);
2807 smb_FreeTran2Packet(outp);
2812 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2813 cm_ReleaseSCache(scp);
2814 cm_ReleaseUser(userp);
2815 if ( WANTS_DFS_PATHNAMES(p) )
2816 code = CM_ERROR_PATH_NOT_COVERED;
2818 code = CM_ERROR_BADSHARENAME;
2819 smb_SendTran2Error(vcp, p, opx, code);
2820 smb_FreeTran2Packet(outp);
2823 #endif /* DFS_SUPPORT */
2825 lock_ObtainMutex(&scp->mx);
2827 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2828 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2829 if (code) goto done;
2831 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2833 /* now we have the status in the cache entry, and everything is locked.
2834 * Marshall the output data.
2836 /* for info level 108, figure out short name */
2837 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
2838 code = cm_GetShortName(pathp, userp, &req,
2839 tidPathp, scp->fid.vnode, shortName,
2845 qpi.u.QPfileAltNameInfo.fileNameLength = (len + 1) * 2;
2846 mbstowcs((unsigned short *)qpi.u.QPfileAltNameInfo.fileName, shortName, len + 1);
2850 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2851 len = strlen(lastComp);
2852 qpi.u.QPfileNameInfo.fileNameLength = (len + 1) * 2;
2853 mbstowcs((unsigned short *)qpi.u.QPfileNameInfo.fileName, lastComp, len + 1);
2857 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2858 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2859 qpi.u.QPstandardInfo.creationDateTime = dosTime;
2860 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
2861 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
2862 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
2863 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
2864 attributes = smb_Attributes(scp);
2865 qpi.u.QPstandardInfo.attributes = attributes;
2866 qpi.u.QPstandardInfo.eaSize = 0;
2868 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2869 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2870 qpi.u.QPfileBasicInfo.creationTime = ft;
2871 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
2872 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
2873 qpi.u.QPfileBasicInfo.changeTime = ft;
2874 extAttributes = smb_ExtAttributes(scp);
2875 qpi.u.QPfileBasicInfo.attributes = extAttributes;
2876 qpi.u.QPfileBasicInfo.reserved = 0;
2878 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2879 smb_fid_t *fidp = smb_FindFIDByScache(vcp, scp);
2881 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
2882 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
2883 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
2884 qpi.u.QPfileStandardInfo.directory =
2885 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2886 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2887 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2888 qpi.u.QPfileStandardInfo.reserved = 0;
2891 lock_ReleaseMutex(&scp->mx);
2893 lock_ObtainMutex(&fidp->mx);
2894 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
2895 lock_ReleaseMutex(&fidp->mx);
2896 smb_ReleaseFID(fidp);
2898 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
2900 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2901 qpi.u.QPfileEaInfo.eaSize = 0;
2903 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
2904 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2905 qpi.u.QPfileAllInfo.creationTime = ft;
2906 qpi.u.QPfileAllInfo.lastAccessTime = ft;
2907 qpi.u.QPfileAllInfo.lastWriteTime = ft;
2908 qpi.u.QPfileAllInfo.changeTime = ft;
2909 extAttributes = smb_ExtAttributes(scp);
2910 qpi.u.QPfileAllInfo.attributes = extAttributes;
2911 qpi.u.QPfileAllInfo.allocationSize = scp->length;
2912 qpi.u.QPfileAllInfo.endOfFile = scp->length;
2913 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
2914 qpi.u.QPfileAllInfo.deletePending = 0;
2915 qpi.u.QPfileAllInfo.directory =
2916 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2917 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2918 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2919 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
2920 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
2921 qpi.u.QPfileAllInfo.eaSize = 0;
2922 qpi.u.QPfileAllInfo.accessFlags = 0;
2923 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
2924 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
2925 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
2926 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
2927 qpi.u.QPfileAllInfo.mode = 0;
2928 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
2929 len = strlen(lastComp);
2930 qpi.u.QPfileAllInfo.fileNameLength = (len + 1) * 2;
2931 mbstowcs((unsigned short *)qpi.u.QPfileAllInfo.fileName, lastComp, len + 1);
2934 /* send and free the packets */
2937 lock_ReleaseMutex(&scp->mx);
2938 cm_ReleaseSCache(scp);
2939 cm_ReleaseUser(userp);
2941 memcpy(outp->datap, &qpi, responseSize);
2942 smb_SendTran2Packet(vcp, outp, opx);
2944 smb_SendTran2Error(vcp, p, opx, code);
2946 smb_FreeTran2Packet(outp);
2951 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2954 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2955 return CM_ERROR_BADOP;
2959 unsigned short infoLevel;
2961 smb_tran2Packet_t *outp;
2962 smb_tran2QPathInfo_t *spi;
2964 cm_scache_t *scp, *dscp;
2972 infoLevel = p->parmsp[0];
2973 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
2974 if (infoLevel != SMB_INFO_STANDARD &&
2975 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
2976 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
2977 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2978 p->opcode, infoLevel);
2979 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
2983 pathp = (char *)(&p->parmsp[3]);
2984 if (smb_StoreAnsiFilenames)
2985 OemToChar(pathp,pathp);
2986 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %s", infoLevel,
2987 osi_LogSaveString(smb_logp, pathp));
2989 userp = smb_GetTran2User(vcp, p);
2991 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
2992 code = CM_ERROR_BADSMB;
2996 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2997 if (code == CM_ERROR_TIDIPC) {
2998 /* Attempt to use a TID allocated for IPC. The client
2999 * is probably looking for DCE RPC end points which we
3000 * don't support OR it could be looking to make a DFS
3003 osi_Log0(smb_logp, "Tran2Open received IPC TID");
3004 cm_ReleaseUser(userp);
3005 return CM_ERROR_NOSUCHPATH;
3009 * XXX Strange hack XXX
3011 * As of Patch 7 (13 January 98), we are having the following problem:
3012 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3013 * requests to look up "desktop.ini" in all the subdirectories.
3014 * This can cause zillions of timeouts looking up non-existent cells
3015 * and volumes, especially in the top-level directory.
3017 * We have not found any way to avoid this or work around it except
3018 * to explicitly ignore the requests for mount points that haven't
3019 * yet been evaluated and for directories that haven't yet been
3022 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3023 spacep = cm_GetSpace();
3024 smb_StripLastComponent(spacep->data, &lastComp, pathp);
3025 #ifndef SPECIAL_FOLDERS
3026 /* Make sure that lastComp is not NULL */
3028 if (stricmp(lastComp, "\\desktop.ini") == 0) {
3029 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3033 userp, tidPathp, &req, &dscp);
3036 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3037 if ( WANTS_DFS_PATHNAMES(p) )
3038 code = CM_ERROR_PATH_NOT_COVERED;
3040 code = CM_ERROR_BADSHARENAME;
3042 #endif /* DFS_SUPPORT */
3043 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3044 code = CM_ERROR_NOSUCHFILE;
3045 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3046 cm_buf_t *bp = buf_Find(dscp, &hzero);
3052 code = CM_ERROR_NOSUCHFILE;
3054 cm_ReleaseSCache(dscp);
3056 cm_FreeSpace(spacep);
3057 cm_ReleaseUser(userp);
3058 smb_SendTran2Error(vcp, p, opx, code);
3064 #endif /* SPECIAL_FOLDERS */
3066 cm_FreeSpace(spacep);
3069 /* now do namei and stat, and copy out the info */
3070 code = cm_NameI(cm_data.rootSCachep, pathp,
3071 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3073 cm_ReleaseUser(userp);
3074 smb_SendTran2Error(vcp, p, opx, code);
3078 fidp = smb_FindFIDByScache(vcp, scp);
3080 cm_ReleaseSCache(scp);
3081 cm_ReleaseUser(userp);
3082 smb_SendTran2Error(vcp, p, opx, code);
3086 lock_ObtainMutex(&fidp->mx);
3087 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
3088 lock_ReleaseMutex(&fidp->mx);
3089 cm_ReleaseSCache(scp);
3090 smb_ReleaseFID(fidp);
3091 cm_ReleaseUser(userp);
3092 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3095 lock_ReleaseMutex(&fidp->mx);
3097 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3099 outp->totalParms = 2;
3100 outp->totalData = 0;
3102 spi = (smb_tran2QPathInfo_t *)p->datap;
3103 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3106 /* lock the vnode with a callback; we need the current status
3107 * to determine what the new status is, in some cases.
3109 lock_ObtainMutex(&scp->mx);
3110 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3111 CM_SCACHESYNC_GETSTATUS
3112 | CM_SCACHESYNC_NEEDCALLBACK);
3114 lock_ReleaseMutex(&scp->mx);
3117 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3119 lock_ReleaseMutex(&scp->mx);
3120 lock_ObtainMutex(&fidp->mx);
3121 lock_ObtainMutex(&scp->mx);
3123 /* prepare for setattr call */
3124 attr.mask = CM_ATTRMASK_LENGTH;
3125 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3126 attr.length.HighPart = 0;
3128 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3129 smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3130 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3131 fidp->flags |= SMB_FID_MTIMESETDONE;
3134 if (spi->u.QPstandardInfo.attributes != 0) {
3135 if ((scp->unixModeBits & 0222)
3136 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3137 /* make a writable file read-only */
3138 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3139 attr.unixModeBits = scp->unixModeBits & ~0222;
3141 else if ((scp->unixModeBits & 0222) == 0
3142 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3143 /* make a read-only file writable */
3144 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3145 attr.unixModeBits = scp->unixModeBits | 0222;
3148 lock_ReleaseMutex(&scp->mx);
3149 lock_ReleaseMutex(&fidp->mx);
3153 code = cm_SetAttr(scp, &attr, userp, &req);
3157 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3158 /* we don't support EAs */
3159 code = CM_ERROR_INVAL;
3163 cm_ReleaseSCache(scp);
3164 cm_ReleaseUser(userp);
3165 smb_ReleaseFID(fidp);
3167 smb_SendTran2Packet(vcp, outp, opx);
3169 smb_SendTran2Error(vcp, p, opx, code);
3170 smb_FreeTran2Packet(outp);
3176 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3178 smb_tran2Packet_t *outp;
3180 unsigned long attributes;
3181 unsigned short infoLevel;
3188 smb_tran2QFileInfo_t qfi;
3195 fidp = smb_FindFID(vcp, fid, 0);
3198 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3202 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3203 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3204 smb_CloseFID(vcp, fidp, NULL, 0);
3205 smb_ReleaseFID(fidp);
3209 infoLevel = p->parmsp[1];
3210 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3211 responseSize = sizeof(qfi.u.QFbasicInfo);
3212 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3213 responseSize = sizeof(qfi.u.QFstandardInfo);
3214 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3215 responseSize = sizeof(qfi.u.QFeaInfo);
3216 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3217 responseSize = sizeof(qfi.u.QFfileNameInfo);
3219 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3220 p->opcode, infoLevel);
3221 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3222 smb_ReleaseFID(fidp);
3225 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3227 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3229 if (infoLevel > 0x100)
3230 outp->totalParms = 2;
3232 outp->totalParms = 0;
3233 outp->totalData = responseSize;
3235 userp = smb_GetTran2User(vcp, p);
3237 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3238 code = CM_ERROR_BADSMB;
3242 lock_ObtainMutex(&fidp->mx);
3243 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3245 osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3247 lock_ReleaseMutex(&fidp->mx);
3248 lock_ObtainMutex(&scp->mx);
3249 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3250 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3254 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3256 /* now we have the status in the cache entry, and everything is locked.
3257 * Marshall the output data.
3259 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3260 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3261 qfi.u.QFbasicInfo.creationTime = ft;
3262 qfi.u.QFbasicInfo.lastAccessTime = ft;
3263 qfi.u.QFbasicInfo.lastWriteTime = ft;
3264 qfi.u.QFbasicInfo.lastChangeTime = ft;
3265 attributes = smb_ExtAttributes(scp);
3266 qfi.u.QFbasicInfo.attributes = attributes;
3268 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3269 qfi.u.QFstandardInfo.allocationSize = scp->length;
3270 qfi.u.QFstandardInfo.endOfFile = scp->length;
3271 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3272 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3273 qfi.u.QFstandardInfo.directory =
3274 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3275 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3276 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3278 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3279 qfi.u.QFeaInfo.eaSize = 0;
3281 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3285 lock_ReleaseMutex(&scp->mx);
3286 lock_ObtainMutex(&fidp->mx);
3287 lock_ObtainMutex(&scp->mx);
3288 if (fidp->NTopen_wholepathp)
3289 name = fidp->NTopen_wholepathp;
3291 name = "\\"; /* probably can't happen */
3292 lock_ReleaseMutex(&fidp->mx);
3293 len = (unsigned long)strlen(name);
3294 outp->totalData = ((len+1)*2) + 4; /* this is actually what we want to return */
3295 qfi.u.QFfileNameInfo.fileNameLength = (len + 1) * 2;
3296 mbstowcs((unsigned short *)qfi.u.QFfileNameInfo.fileName, name, len + 1);
3299 /* send and free the packets */
3301 lock_ReleaseMutex(&scp->mx);
3302 cm_ReleaseSCache(scp);
3303 cm_ReleaseUser(userp);
3304 smb_ReleaseFID(fidp);
3306 memcpy(outp->datap, &qfi, responseSize);
3307 smb_SendTran2Packet(vcp, outp, opx);
3309 smb_SendTran2Error(vcp, p, opx, code);
3311 smb_FreeTran2Packet(outp);
3316 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3321 unsigned short infoLevel;
3322 smb_tran2Packet_t *outp;
3323 cm_user_t *userp = NULL;
3324 cm_scache_t *scp = NULL;
3330 fidp = smb_FindFID(vcp, fid, 0);
3333 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3337 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3338 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3339 smb_CloseFID(vcp, fidp, NULL, 0);
3340 smb_ReleaseFID(fidp);
3344 infoLevel = p->parmsp[1];
3345 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3346 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3347 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3348 p->opcode, infoLevel);
3349 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3350 smb_ReleaseFID(fidp);
3354 lock_ObtainMutex(&fidp->mx);
3355 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
3356 !(fidp->flags & SMB_FID_OPENDELETE)) {
3357 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3358 fidp, fidp->scp, fidp->flags);
3359 lock_ReleaseMutex(&fidp->mx);
3360 smb_ReleaseFID(fidp);
3361 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3364 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3365 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3366 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3367 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3368 fidp, fidp->scp, fidp->flags);
3369 lock_ReleaseMutex(&fidp->mx);
3370 smb_ReleaseFID(fidp);
3371 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3376 osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3378 lock_ReleaseMutex(&fidp->mx);
3380 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3382 outp->totalParms = 2;
3383 outp->totalData = 0;
3385 userp = smb_GetTran2User(vcp, p);
3387 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3388 code = CM_ERROR_BADSMB;
3392 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3394 unsigned int attribute;
3396 smb_tran2QFileInfo_t *sfi;
3398 sfi = (smb_tran2QFileInfo_t *)p->datap;
3400 /* lock the vnode with a callback; we need the current status
3401 * to determine what the new status is, in some cases.
3403 lock_ObtainMutex(&scp->mx);
3404 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3405 CM_SCACHESYNC_GETSTATUS
3406 | CM_SCACHESYNC_NEEDCALLBACK);
3408 lock_ReleaseMutex(&scp->mx);
3412 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3414 lock_ReleaseMutex(&scp->mx);
3415 lock_ObtainMutex(&fidp->mx);
3416 lock_ObtainMutex(&scp->mx);
3418 /* prepare for setattr call */
3421 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3422 /* when called as result of move a b, lastMod is (-1, -1).
3423 * If the check for -1 is not present, timestamp
3424 * of the resulting file will be 1969 (-1)
3426 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3427 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3428 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3429 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3430 fidp->flags |= SMB_FID_MTIMESETDONE;
3433 attribute = sfi->u.QFbasicInfo.attributes;
3434 if (attribute != 0) {
3435 if ((scp->unixModeBits & 0222)
3436 && (attribute & SMB_ATTR_READONLY) != 0) {
3437 /* make a writable file read-only */
3438 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3439 attr.unixModeBits = scp->unixModeBits & ~0222;
3441 else if ((scp->unixModeBits & 0222) == 0
3442 && (attribute & SMB_ATTR_READONLY) == 0) {
3443 /* make a read-only file writable */
3444 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3445 attr.unixModeBits = scp->unixModeBits | 0222;
3448 lock_ReleaseMutex(&scp->mx);
3449 lock_ReleaseMutex(&fidp->mx);
3453 code = cm_SetAttr(scp, &attr, userp, &req);
3457 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3458 int delflag = *((char *)(p->datap));
3459 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
3460 delflag, fidp, scp);
3461 if (*((char *)(p->datap))) { /* File is Deleted */
3462 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3465 lock_ObtainMutex(&fidp->mx);
3466 fidp->flags |= SMB_FID_DELONCLOSE;
3467 lock_ReleaseMutex(&fidp->mx);
3469 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
3475 lock_ObtainMutex(&fidp->mx);
3476 fidp->flags &= ~SMB_FID_DELONCLOSE;
3477 lock_ReleaseMutex(&fidp->mx);
3480 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3481 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3482 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3485 attr.mask = CM_ATTRMASK_LENGTH;
3486 attr.length.LowPart = size.LowPart;
3487 attr.length.HighPart = size.HighPart;
3488 code = cm_SetAttr(scp, &attr, userp, &req);
3492 cm_ReleaseSCache(scp);
3493 cm_ReleaseUser(userp);
3494 smb_ReleaseFID(fidp);
3496 smb_SendTran2Packet(vcp, outp, opx);
3498 smb_SendTran2Error(vcp, p, opx, code);
3499 smb_FreeTran2Packet(outp);
3505 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3507 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3508 return CM_ERROR_BADOP;
3512 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3514 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3515 return CM_ERROR_BADOP;
3519 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3521 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3522 return CM_ERROR_BADOP;
3526 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3528 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3529 return CM_ERROR_BADOP;
3533 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3535 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3536 return CM_ERROR_BADOP;
3540 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3542 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3543 return CM_ERROR_BADOP;
3546 struct smb_v2_referral {
3548 USHORT ReferralFlags;
3551 USHORT DfsPathOffset;
3552 USHORT DfsAlternativePathOffset;
3553 USHORT NetworkAddressOffset;
3557 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3559 /* This is a UNICODE only request (bit15 of Flags2) */
3560 /* The TID must be IPC$ */
3562 /* The documentation for the Flags response field is contradictory */
3564 /* Use Version 1 Referral Element Format */
3565 /* ServerType = 0; indicates the next server should be queried for the file */
3566 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3567 /* Node = UnicodeString of UNC path of the next share name */
3570 int maxReferralLevel = 0;
3571 char requestFileName[1024] = "";
3572 smb_tran2Packet_t *outp = 0;
3573 cm_user_t *userp = 0;
3575 CPINFO CodePageInfo;
3576 int i, nbnLen, reqLen;
3581 maxReferralLevel = p->parmsp[0];
3583 GetCPInfo(CP_ACP, &CodePageInfo);
3584 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
3585 requestFileName, 1024, NULL, NULL);
3587 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
3588 maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3590 nbnLen = strlen(cm_NetbiosName);
3591 reqLen = strlen(requestFileName);
3593 if (reqLen == nbnLen + 5 &&
3594 requestFileName[0] == '\\' &&
3595 !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3596 requestFileName[nbnLen+1] == '\\' &&
3597 (!_strnicmp("all",&requestFileName[nbnLen+2],3) ||
3598 !_strnicmp("*.",&requestFileName[nbnLen+2],2)))
3601 struct smb_v2_referral * v2ref;
3602 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
3604 sp = (USHORT *)outp->datap;
3606 sp[idx++] = reqLen; /* path consumed */
3607 sp[idx++] = 1; /* number of referrals */
3608 sp[idx++] = 0x03; /* flags */
3609 #ifdef DFS_VERSION_1
3610 sp[idx++] = 1; /* Version Number */
3611 sp[idx++] = reqLen + 4; /* Referral Size */
3612 sp[idx++] = 1; /* Type = SMB Server */
3613 sp[idx++] = 0; /* Do not strip path consumed */
3614 for ( i=0;i<=reqLen; i++ )
3615 sp[i+idx] = requestFileName[i];
3616 #else /* DFS_VERSION_2 */
3617 sp[idx++] = 2; /* Version Number */
3618 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3619 idx += (sizeof(struct smb_v2_referral) / 2);
3620 v2ref = (struct smb_v2_referral *) &sp[5];
3621 v2ref->ServerType = 1; /* SMB Server */
3622 v2ref->ReferralFlags = 0x03;
3623 v2ref->Proximity = 0; /* closest */
3624 v2ref->TimeToLive = 3600; /* seconds */
3625 v2ref->DfsPathOffset = idx * 2;
3626 v2ref->DfsAlternativePathOffset = idx * 2;
3627 v2ref->NetworkAddressOffset = 0;
3628 for ( i=0;i<=reqLen; i++ )
3629 sp[i+idx] = requestFileName[i];
3632 userp = smb_GetTran2User(vcp, p);
3634 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3635 code = CM_ERROR_BADSMB;
3640 code = CM_ERROR_NOSUCHPATH;
3645 cm_ReleaseUser(userp);
3647 smb_SendTran2Packet(vcp, outp, op);
3649 smb_SendTran2Error(vcp, p, op, code);
3651 smb_FreeTran2Packet(outp);
3654 #else /* DFS_SUPPORT */
3655 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3656 return CM_ERROR_BADOP;
3657 #endif /* DFS_SUPPORT */
3661 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3663 /* This is a UNICODE only request (bit15 of Flags2) */
3665 /* There is nothing we can do about this operation. The client is going to
3666 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3667 * Unfortunately, there is really nothing we can do about it other then log it
3668 * somewhere. Even then I don't think there is anything for us to do.
3669 * So let's return an error value.
3672 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3673 return CM_ERROR_BADOP;
3677 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3678 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3683 cm_scache_t *targetScp; /* target if scp is a symlink */
3688 unsigned short attr;
3689 unsigned long lattr;
3690 smb_dirListPatch_t *patchp;
3691 smb_dirListPatch_t *npatchp;
3693 afs_int32 mustFake = 0;
3695 code = cm_FindACLCache(dscp, userp, &rights);
3696 if (code == 0 && !(rights & PRSFS_READ))
3698 else if (code == -1) {
3699 lock_ObtainMutex(&dscp->mx);
3700 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
3701 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3702 lock_ReleaseMutex(&dscp->mx);
3703 if (code == CM_ERROR_NOACCESS) {
3711 for(patchp = *dirPatchespp; patchp; patchp =
3712 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3713 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3717 lock_ObtainMutex(&scp->mx);
3719 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3720 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3721 if (mustFake || code) {
3722 lock_ReleaseMutex(&scp->mx);
3724 dptr = patchp->dptr;
3726 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3727 errors in the client. */
3728 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3729 /* 1969-12-31 23:59:59 +00 */
3730 ft.dwHighDateTime = 0x19DB200;
3731 ft.dwLowDateTime = 0x5BB78980;
3733 /* copy to Creation Time */
3734 *((FILETIME *)dptr) = ft;
3737 /* copy to Last Access Time */
3738 *((FILETIME *)dptr) = ft;
3741 /* copy to Last Write Time */
3742 *((FILETIME *)dptr) = ft;
3745 /* copy to Change Time */
3746 *((FILETIME *)dptr) = ft;
3749 switch (scp->fileType) {
3750 case CM_SCACHETYPE_DIRECTORY:
3751 case CM_SCACHETYPE_MOUNTPOINT:
3752 case CM_SCACHETYPE_SYMLINK:
3753 case CM_SCACHETYPE_INVALID:
3754 *((u_long *)dptr) = SMB_ATTR_DIRECTORY;
3757 /* if we get here we either have a normal file
3758 * or we have a file for which we have never
3759 * received status info. In this case, we can
3760 * check the even/odd value of the entry's vnode.
3761 * even means it is to be treated as a directory
3762 * and odd means it is to be treated as a file.
3764 if (mustFake && (scp->fid.vnode & 0x1))
3765 *((u_long *)dptr) = SMB_ATTR_DIRECTORY;
3767 *((u_long *)dptr) = SMB_ATTR_NORMAL;
3770 /* merge in hidden attribute */
3771 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3772 *((u_long *)dptr) |= SMB_ATTR_HIDDEN;
3776 /* 1969-12-31 23:59:58 +00*/
3777 dosTime = 0xEBBFBF7D;
3779 /* and copy out date */
3780 shortTemp = (dosTime>>16) & 0xffff;
3781 *((u_short *)dptr) = shortTemp;
3784 /* copy out creation time */
3785 shortTemp = dosTime & 0xffff;
3786 *((u_short *)dptr) = shortTemp;
3789 /* and copy out date */
3790 shortTemp = (dosTime>>16) & 0xffff;
3791 *((u_short *)dptr) = shortTemp;
3794 /* copy out access time */
3795 shortTemp = dosTime & 0xffff;
3796 *((u_short *)dptr) = shortTemp;
3799 /* and copy out date */
3800 shortTemp = (dosTime>>16) & 0xffff;
3801 *((u_short *)dptr) = shortTemp;
3804 /* copy out mod time */
3805 shortTemp = dosTime & 0xffff;
3806 *((u_short *)dptr) = shortTemp;
3809 /* set the attribute */
3810 switch (scp->fileType) {
3811 case CM_SCACHETYPE_DIRECTORY:
3812 case CM_SCACHETYPE_MOUNTPOINT:
3813 case CM_SCACHETYPE_SYMLINK:
3814 case CM_SCACHETYPE_INVALID:
3815 attr = SMB_ATTR_DIRECTORY;
3817 attr = SMB_ATTR_NORMAL;
3819 /* merge in hidden (dot file) attribute */
3820 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3821 attr |= SMB_ATTR_HIDDEN;
3823 *dptr++ = attr & 0xff;
3824 *dptr++ = (attr >> 8) & 0xff;
3827 cm_ReleaseSCache(scp);
3831 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3833 /* now watch for a symlink */
3835 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3836 lock_ReleaseMutex(&scp->mx);
3837 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3839 /* we have a more accurate file to use (the
3840 * target of the symbolic link). Otherwise,
3841 * we'll just use the symlink anyway.
3843 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3845 cm_ReleaseSCache(scp);
3848 lock_ObtainMutex(&scp->mx);
3851 dptr = patchp->dptr;
3853 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3855 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3857 /* copy to Creation Time */
3858 *((FILETIME *)dptr) = ft;
3861 /* copy to Last Access Time */
3862 *((FILETIME *)dptr) = ft;
3865 /* copy to Last Write Time */
3866 *((FILETIME *)dptr) = ft;
3869 /* copy to Change Time */
3870 *((FILETIME *)dptr) = ft;
3873 /* Use length for both file length and alloc length */
3874 *((LARGE_INTEGER *)dptr) = scp->length;
3876 *((LARGE_INTEGER *)dptr) = scp->length;
3879 /* Copy attributes */
3880 lattr = smb_ExtAttributes(scp);
3881 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3882 if (lattr == SMB_ATTR_NORMAL)
3883 lattr = SMB_ATTR_DIRECTORY;
3885 lattr |= SMB_ATTR_DIRECTORY;
3887 /* merge in hidden (dot file) attribute */
3888 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3889 if (lattr == SMB_ATTR_NORMAL)
3890 lattr = SMB_ATTR_HIDDEN;
3892 lattr |= SMB_ATTR_HIDDEN;
3894 *((u_long *)dptr) = lattr;
3898 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3900 /* and copy out date */
3901 shortTemp = (dosTime>>16) & 0xffff;
3902 *((u_short *)dptr) = shortTemp;
3905 /* copy out creation time */
3906 shortTemp = dosTime & 0xffff;
3907 *((u_short *)dptr) = shortTemp;
3910 /* and copy out date */
3911 shortTemp = (dosTime>>16) & 0xffff;
3912 *((u_short *)dptr) = shortTemp;
3915 /* copy out access time */
3916 shortTemp = dosTime & 0xffff;
3917 *((u_short *)dptr) = shortTemp;
3920 /* and copy out date */
3921 shortTemp = (dosTime>>16) & 0xffff;
3922 *((u_short *)dptr) = shortTemp;
3925 /* copy out mod time */
3926 shortTemp = dosTime & 0xffff;
3927 *((u_short *)dptr) = shortTemp;
3930 /* copy out file length and alloc length,
3931 * using the same for both
3933 *((u_long *)dptr) = scp->length.LowPart;
3935 *((u_long *)dptr) = scp->length.LowPart;
3938 /* finally copy out attributes as short */
3939 attr = smb_Attributes(scp);
3940 /* merge in hidden (dot file) attribute */
3941 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3942 if (lattr == SMB_ATTR_NORMAL)
3943 lattr = SMB_ATTR_HIDDEN;
3945 lattr |= SMB_ATTR_HIDDEN;
3947 *dptr++ = attr & 0xff;
3948 *dptr++ = (attr >> 8) & 0xff;
3951 lock_ReleaseMutex(&scp->mx);
3952 cm_ReleaseSCache(scp);
3955 /* now free the patches */
3956 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3957 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3961 /* and mark the list as empty */
3962 *dirPatchespp = NULL;
3967 // char table for case insensitive comparison
3968 char mapCaseTable[256];
3970 VOID initUpperCaseTable(VOID)
3973 for (i = 0; i < 256; ++i)
3974 mapCaseTable[i] = toupper(i);
3975 // make '"' match '.'
3976 mapCaseTable[(int)'"'] = toupper('.');
3977 // make '<' match '*'
3978 mapCaseTable[(int)'<'] = toupper('*');
3979 // make '>' match '?'
3980 mapCaseTable[(int)'>'] = toupper('?');
3983 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3985 // Note : this procedure works recursively calling itself.
3987 // PSZ pattern : string containing metacharacters.
3988 // PSZ name : file name to be compared with 'pattern'.
3990 // BOOL : TRUE/FALSE (match/mistmatch)
3993 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
3995 PSZ pename; // points to the last 'name' character
3997 pename = name + strlen(name) - 1;
4008 if (*pattern == '\0')
4010 for (p = pename; p >= name; --p) {
4011 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
4012 !casefold && (*p == *pattern)) &&
4013 szWildCardMatchFileName(pattern + 1, p + 1, casefold))
4018 if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
4019 (!casefold && *name != *pattern))
4026 /* if all we have left are wildcards, then we match */
4027 for (;*pattern; pattern++) {
4028 if (*pattern != '*' && *pattern != '?')
4034 /* do a case-folding search of the star name mask with the name in namep.
4035 * Return 1 if we match, otherwise 0.
4037 int smb_V3MatchMask(char *namep, char *maskp, int flags)
4040 int i, j, star, qmark, casefold, retval;
4042 /* make sure we only match 8.3 names, if requested */
4043 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
4046 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
4048 /* optimize the pattern:
4049 * if there is a mixture of '?' and '*',
4050 * for example the sequence "*?*?*?*"
4051 * must be turned into the form "*"
4053 newmask = (char *)malloc(strlen(maskp)+1);
4054 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
4055 switch ( maskp[i] ) {
4067 } else if ( qmark ) {
4071 newmask[j++] = maskp[i];
4078 } else if ( qmark ) {
4082 newmask[j++] = '\0';
4084 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
4091 /* smb_ReceiveTran2SearchDir implements both
4092 * Tran2_Find_First and Tran2_Find_Next
4094 #define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
4095 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
4096 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
4097 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
4098 #define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
4100 /* this is an optimized handler for T2SearchDir that handles the case
4101 where there are no wildcards in the search path. I.e. an
4102 application is using FindFirst(Ex) to get information about a
4103 single file or directory. It will attempt to do a single lookup.
4104 If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4105 the usual mechanism.
4107 This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4109 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4113 long code = 0, code2 = 0;
4116 smb_dirListPatch_t *dirListPatchesp;
4117 smb_dirListPatch_t *curPatchp;
4118 long orbytes; /* # of bytes in this output record */
4119 long ohbytes; /* # of bytes, except file name */
4120 long onbytes; /* # of bytes in name, incl. term. null */
4121 cm_scache_t *scp = NULL;
4122 cm_scache_t *targetscp = NULL;
4123 cm_user_t *userp = NULL;
4124 char *op; /* output data ptr */
4125 char *origOp; /* original value of op */
4126 cm_space_t *spacep; /* for pathname buffer */
4127 long maxReturnData; /* max # of return data */
4128 long maxReturnParms; /* max # of return parms */
4129 long bytesInBuffer; /* # data bytes in the output buffer */
4130 char *maskp; /* mask part of path */
4134 smb_tran2Packet_t *outp; /* response packet */
4137 char shortName[13]; /* 8.3 name if needed */
4146 osi_assertx(p->opcode == 1, "invalid opcode");
4148 /* find first; obtain basic parameters from request */
4150 /* note that since we are going to failover to regular
4151 * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4152 * modify any of the input parameters here. */
4153 attribute = p->parmsp[0];
4154 maxCount = p->parmsp[1];
4155 infoLevel = p->parmsp[3];
4156 searchFlags = p->parmsp[2];
4157 pathp = ((char *) p->parmsp) + 12; /* points to path */
4159 maskp = strrchr(pathp, '\\');
4163 maskp++; /* skip over backslash */
4164 /* track if this is likely to match a lot of entries */
4166 osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%s], mask[%s]",
4167 osi_LogSaveString(smb_logp, pathp),
4168 osi_LogSaveString(smb_logp, maskp));
4170 switch ( infoLevel ) {
4171 case SMB_INFO_STANDARD:
4174 case SMB_INFO_QUERY_EA_SIZE:
4175 s = "InfoQueryEaSize";
4177 case SMB_INFO_QUERY_EAS_FROM_LIST:
4178 s = "InfoQueryEasFromList";
4180 case SMB_FIND_FILE_DIRECTORY_INFO:
4181 s = "FindFileDirectoryInfo";
4183 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4184 s = "FindFileFullDirectoryInfo";
4186 case SMB_FIND_FILE_NAMES_INFO:
4187 s = "FindFileNamesInfo";
4189 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4190 s = "FindFileBothDirectoryInfo";
4193 s = "unknownInfoLevel";
4196 osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
4199 "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4200 attribute, infoLevel, maxCount, searchFlags);
4202 if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4203 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4204 return CM_ERROR_INVAL;
4207 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4208 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4210 dirListPatchesp = NULL;
4212 maxReturnData = p->maxReturnData;
4213 maxReturnParms = 10; /* return params for findfirst, which
4214 is the only one we handle.*/
4216 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4217 if (maxReturnData > 6000)
4218 maxReturnData = 6000;
4219 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4221 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4224 osi_Log2(smb_logp, "T2SDSingle search dir count %d [%s]",
4225 maxCount, osi_LogSaveString(smb_logp, pathp));
4227 /* bail out if request looks bad */
4229 smb_FreeTran2Packet(outp);
4230 return CM_ERROR_BADSMB;
4233 userp = smb_GetTran2User(vcp, p);
4235 osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
4236 smb_FreeTran2Packet(outp);
4237 return CM_ERROR_BADSMB;
4240 /* try to get the vnode for the path name next */
4241 spacep = cm_GetSpace();
4242 smb_StripLastComponent(spacep->data, NULL, pathp);
4243 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4245 cm_ReleaseUser(userp);
4246 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4247 smb_FreeTran2Packet(outp);