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)
76 len = (int)strlen(name);
78 for ( i=0; smb_ExecutableExtensions[i]; i++) {
79 j = len - (int)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_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
173 OutputDebugString(buf);
175 sprintf(buf,"%5x",i);
176 memset(buf+5,' ',80);
181 j = j*3 + 7 + ((j>7)?1:0);
184 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
187 j = j + 56 + ((j>7)?1:0);
189 buf[j] = (k>32 && k<127)?k:'.';
192 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
194 OutputDebugString(buf);
198 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
200 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
201 SECURITY_STATUS status, istatus;
202 CredHandle creds = {0,0};
204 SecBufferDesc secOut;
212 OutputDebugF("Negotiating Extended Security");
214 status = AcquireCredentialsHandle( NULL,
215 SMB_EXT_SEC_PACKAGE_NAME,
224 if (status != SEC_E_OK) {
225 /* Really bad. We return an empty security blob */
226 OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
231 secOut.pBuffers = &secTok;
232 secOut.ulVersion = SECBUFFER_VERSION;
234 secTok.BufferType = SECBUFFER_TOKEN;
236 secTok.pvBuffer = NULL;
238 ctx.dwLower = ctx.dwUpper = 0;
240 status = AcceptSecurityContext( &creds,
243 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
244 SECURITY_NETWORK_DREP,
251 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
252 OutputDebugF("Completing token...");
253 istatus = CompleteAuthToken(&ctx, &secOut);
254 if ( istatus != SEC_E_OK )
255 OutputDebugF("Token completion failed: %x", istatus);
258 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
259 if (secTok.pvBuffer) {
260 *secBlobLength = secTok.cbBuffer;
261 *secBlob = malloc( secTok.cbBuffer );
262 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
265 if ( status != SEC_E_OK )
266 OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
269 /* Discard partial security context */
270 DeleteSecurityContext(&ctx);
272 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
274 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
275 FreeCredentialsHandle(&creds);
281 struct smb_ext_context {
288 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
289 SECURITY_STATUS status, istatus;
293 SecBufferDesc secBufIn;
295 SecBufferDesc secBufOut;
298 struct smb_ext_context * secCtx = NULL;
299 struct smb_ext_context * newSecCtx = NULL;
300 void * assembledBlob = NULL;
301 int assembledBlobLength = 0;
304 OutputDebugF("In smb_AuthenticateUserExt");
307 *secBlobOutLength = 0;
309 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
310 secCtx = vcp->secCtx;
311 lock_ObtainMutex(&vcp->mx);
312 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
314 lock_ReleaseMutex(&vcp->mx);
318 OutputDebugF("Received incoming token:");
319 OutputDebugHexDump(secBlobIn,secBlobInLength);
323 OutputDebugF("Continuing with existing context.");
324 creds = secCtx->creds;
327 if (secCtx->partialToken) {
328 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
329 assembledBlob = malloc(assembledBlobLength);
330 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
331 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
334 status = AcquireCredentialsHandle( NULL,
335 SMB_EXT_SEC_PACKAGE_NAME,
344 if (status != SEC_E_OK) {
345 OutputDebugF("Can't acquire Credentials handle [%lX]", status);
346 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
354 secBufIn.cBuffers = 1;
355 secBufIn.pBuffers = &secTokIn;
356 secBufIn.ulVersion = SECBUFFER_VERSION;
358 secTokIn.BufferType = SECBUFFER_TOKEN;
360 secTokIn.cbBuffer = assembledBlobLength;
361 secTokIn.pvBuffer = assembledBlob;
363 secTokIn.cbBuffer = secBlobInLength;
364 secTokIn.pvBuffer = secBlobIn;
367 secBufOut.cBuffers = 1;
368 secBufOut.pBuffers = &secTokOut;
369 secBufOut.ulVersion = SECBUFFER_VERSION;
371 secTokOut.BufferType = SECBUFFER_TOKEN;
372 secTokOut.cbBuffer = 0;
373 secTokOut.pvBuffer = NULL;
375 status = AcceptSecurityContext( &creds,
376 ((secCtx)?&ctx:NULL),
378 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
379 SECURITY_NETWORK_DREP,
386 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
387 OutputDebugF("Completing token...");
388 istatus = CompleteAuthToken(&ctx, &secBufOut);
389 if ( istatus != SEC_E_OK )
390 OutputDebugF("Token completion failed: %lX", istatus);
393 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
394 OutputDebugF("Continue needed");
396 newSecCtx = malloc(sizeof(*newSecCtx));
398 newSecCtx->creds = creds;
399 newSecCtx->ctx = ctx;
400 newSecCtx->partialToken = NULL;
401 newSecCtx->partialTokenLen = 0;
403 lock_ObtainMutex( &vcp->mx );
404 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
405 vcp->secCtx = newSecCtx;
406 lock_ReleaseMutex( &vcp->mx );
408 code = CM_ERROR_GSSCONTINUE;
411 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
412 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
413 secTokOut.pvBuffer) {
414 OutputDebugF("Need to send token back to client");
416 *secBlobOutLength = secTokOut.cbBuffer;
417 *secBlobOut = malloc(secTokOut.cbBuffer);
418 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
420 OutputDebugF("Outgoing token:");
421 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
422 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
423 OutputDebugF("Incomplete message");
425 newSecCtx = malloc(sizeof(*newSecCtx));
427 newSecCtx->creds = creds;
428 newSecCtx->ctx = ctx;
429 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
430 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
431 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
433 lock_ObtainMutex( &vcp->mx );
434 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
435 vcp->secCtx = newSecCtx;
436 lock_ReleaseMutex( &vcp->mx );
438 code = CM_ERROR_GSSCONTINUE;
441 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
443 SecPkgContext_Names names;
445 OutputDebugF("Authentication completed");
446 OutputDebugF("Returned flags : [%lX]", flags);
448 if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
449 OutputDebugF("Received name [%s]", names.sUserName);
450 strcpy(usern, names.sUserName);
451 strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
452 FreeContextBuffer(names.sUserName);
454 /* Force the user to retry if the context is invalid */
455 OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
456 code = CM_ERROR_BADPASSWORD;
460 case SEC_E_INVALID_TOKEN:
461 OutputDebugF("Returning bad password :: INVALID_TOKEN");
463 case SEC_E_INVALID_HANDLE:
464 OutputDebugF("Returning bad password :: INVALID_HANDLE");
466 case SEC_E_LOGON_DENIED:
467 OutputDebugF("Returning bad password :: LOGON_DENIED");
469 case SEC_E_UNKNOWN_CREDENTIALS:
470 OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
472 case SEC_E_NO_CREDENTIALS:
473 OutputDebugF("Returning bad password :: NO_CREDENTIALS");
475 case SEC_E_CONTEXT_EXPIRED:
476 OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
478 case SEC_E_INCOMPLETE_CREDENTIALS:
479 OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
481 case SEC_E_WRONG_PRINCIPAL:
482 OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
484 case SEC_E_TIME_SKEW:
485 OutputDebugF("Returning bad password :: TIME_SKEW");
488 OutputDebugF("Returning bad password :: Status == %lX", status);
490 code = CM_ERROR_BADPASSWORD;
494 if (secCtx->partialToken) free(secCtx->partialToken);
502 if (secTokOut.pvBuffer)
503 FreeContextBuffer(secTokOut.pvBuffer);
505 if (code != CM_ERROR_GSSCONTINUE) {
506 DeleteSecurityContext(&ctx);
507 FreeCredentialsHandle(&creds);
515 #define P_RESP_LEN 128
517 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
518 So put stuff in a struct. */
519 struct Lm20AuthBlob {
520 MSV1_0_LM20_LOGON lmlogon;
521 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
522 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
523 WCHAR accountNameW[P_LEN];
524 WCHAR primaryDomainW[P_LEN];
525 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
526 TOKEN_GROUPS tgroups;
527 TOKEN_SOURCE tsource;
530 long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
533 struct Lm20AuthBlob lmAuth;
534 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
535 QUOTA_LIMITS quotaLimits;
537 ULONG lmprofilepSize;
541 OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
542 OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
544 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
545 OutputDebugF("ciPwdLength or csPwdLength is too long");
546 return CM_ERROR_BADPASSWORD;
549 memset(&lmAuth,0,sizeof(lmAuth));
551 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
553 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
554 mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
555 lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
556 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
558 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
559 mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
560 lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
561 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
563 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
564 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
565 size = MAX_COMPUTERNAME_LENGTH + 1;
566 GetComputerNameW(lmAuth.workstationW, &size);
567 lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
569 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
571 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
572 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
573 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
574 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
576 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
577 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
578 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
579 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
581 lmAuth.lmlogon.ParameterControl = 0;
583 lmAuth.tgroups.GroupCount = 0;
584 lmAuth.tgroups.Groups[0].Sid = NULL;
585 lmAuth.tgroups.Groups[0].Attributes = 0;
587 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
588 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
589 strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
591 nts = LsaLogonUser( smb_lsaHandle,
606 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
607 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
610 OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
611 OutputDebugF("Extended status is 0x%lX", ntsEx);
613 if (nts == ERROR_SUCCESS) {
615 LsaFreeReturnBuffer(lmprofilep);
616 CloseHandle(lmToken);
620 if (nts == 0xC000015BL)
621 return CM_ERROR_BADLOGONTYPE;
622 else /* our catchall is a bad password though we could be more specific */
623 return CM_ERROR_BADPASSWORD;
627 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
628 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName)
633 /* check if we have sane input */
634 if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
637 /* we could get : [accountName][domainName]
643 atsign = strchr(accountName, '@');
645 if (atsign) /* [user@domain][] -> [user@domain][domain] */
650 /* if for some reason the client doesn't know what domain to use,
651 it will either return an empty string or a '?' */
652 if (!domain[0] || domain[0] == '?')
653 /* Empty domains and empty usernames are usually sent from tokenless contexts.
654 This way such logins will get an empty username (easy to check). I don't know
655 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
656 strcpy(usern,accountName);
658 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
659 strcpy(usern,domain);
662 strncat(usern,accountName,atsign - accountName);
664 strcat(usern,accountName);
672 /* When using SMB auth, all SMB sessions have to pass through here
673 * first to authenticate the user.
675 * Caveat: If not using SMB auth, the protocol does not require
676 * sending a session setup packet, which means that we can't rely on a
677 * UID in subsequent packets. Though in practice we get one anyway.
679 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
683 unsigned short newUid;
684 unsigned long caps = 0;
688 char usern[SMB_MAX_USERNAME_LENGTH];
689 char *secBlobOut = NULL;
690 int secBlobOutLength = 0;
692 /* Check for bad conns */
693 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
694 return CM_ERROR_REMOTECONN;
696 if (vcp->flags & SMB_VCFLAG_USENT) {
697 if (smb_authType == SMB_AUTH_EXTENDED) {
698 /* extended authentication */
702 OutputDebugF("NT Session Setup: Extended");
704 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
705 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
708 secBlobInLength = smb_GetSMBParm(inp, 7);
709 secBlobIn = smb_GetSMBData(inp, NULL);
711 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
713 if (code == CM_ERROR_GSSCONTINUE) {
714 smb_SetSMBParm(outp, 2, 0);
715 smb_SetSMBParm(outp, 3, secBlobOutLength);
716 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
717 tp = smb_GetSMBData(outp, NULL);
718 if (secBlobOutLength) {
719 memcpy(tp, secBlobOut, secBlobOutLength);
721 tp += secBlobOutLength;
723 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
724 tp += smb_ServerOSLength;
725 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
726 tp += smb_ServerLanManagerLength;
727 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
728 tp += smb_ServerDomainNameLength;
731 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
733 unsigned ciPwdLength, csPwdLength;
739 if (smb_authType == SMB_AUTH_NTLM)
740 OutputDebugF("NT Session Setup: NTLM");
742 OutputDebugF("NT Session Setup: None");
744 /* TODO: parse for extended auth as well */
745 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
746 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
748 tp = smb_GetSMBData(inp, &datalen);
750 OutputDebugF("Session packet data size [%d]",datalen);
757 accountName = smb_ParseString(tp, &tp);
758 primaryDomain = smb_ParseString(tp, NULL);
760 OutputDebugF("Account Name: %s",accountName);
761 OutputDebugF("Primary Domain: %s", primaryDomain);
762 OutputDebugF("Case Sensitive Password: %s", csPwd && csPwd[0] ? "yes" : "no");
763 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
765 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
766 /* shouldn't happen */
767 code = CM_ERROR_BADSMB;
768 goto after_read_packet;
771 /* capabilities are only valid for first session packet */
772 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
773 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
776 if (smb_authType == SMB_AUTH_NTLM) {
777 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
779 OutputDebugF("LM authentication failed [%d]", code);
781 OutputDebugF("LM authentication succeeded");
785 unsigned ciPwdLength;
790 switch ( smb_authType ) {
791 case SMB_AUTH_EXTENDED:
792 OutputDebugF("V3 Session Setup: Extended");
795 OutputDebugF("V3 Session Setup: NTLM");
798 OutputDebugF("V3 Session Setup: None");
800 ciPwdLength = smb_GetSMBParm(inp, 7);
801 tp = smb_GetSMBData(inp, NULL);
805 accountName = smb_ParseString(tp, &tp);
806 primaryDomain = smb_ParseString(tp, NULL);
808 OutputDebugF("Account Name: %s",accountName);
809 OutputDebugF("Primary Domain: %s", primaryDomain);
810 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
812 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
813 /* shouldn't happen */
814 code = CM_ERROR_BADSMB;
815 goto after_read_packet;
818 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
821 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
822 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
824 OutputDebugF("LM authentication failed [%d]", code);
826 OutputDebugF("LM authentication succeeded");
831 /* note down that we received a session setup X and set the capabilities flag */
832 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
833 lock_ObtainMutex(&vcp->mx);
834 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
835 /* for the moment we can only deal with NTSTATUS */
836 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
837 vcp->flags |= SMB_VCFLAG_STATUS32;
839 lock_ReleaseMutex(&vcp->mx);
842 /* code would be non-zero if there was an authentication failure.
843 Ideally we would like to invalidate the uid for this session or break
844 early to avoid accidently stealing someone else's tokens. */
850 OutputDebugF("Received username=[%s]", usern);
852 /* On Windows 2000, this function appears to be called more often than
853 it is expected to be called. This resulted in multiple smb_user_t
854 records existing all for the same user session which results in all
855 of the users tokens disappearing.
857 To avoid this problem, we look for an existing smb_user_t record
858 based on the users name, and use that one if we find it.
861 uidp = smb_FindUserByNameThisSession(vcp, usern);
862 if (uidp) { /* already there, so don't create a new one */
864 newUid = uidp->userID;
865 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
866 vcp->lana,vcp->lsn,newUid);
867 smb_ReleaseUID(uidp);
872 /* do a global search for the username/machine name pair */
873 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
874 lock_ObtainMutex(&unp->mx);
875 if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
876 /* clear the afslogon flag so that the tickets can now
877 * be freed when the refCount returns to zero.
879 unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
881 lock_ReleaseMutex(&unp->mx);
883 /* Create a new UID and cm_user_t structure */
886 userp = cm_NewUser();
887 cm_HoldUserVCRef(userp);
888 lock_ObtainMutex(&vcp->mx);
889 if (!vcp->uidCounter)
890 vcp->uidCounter++; /* handle unlikely wraparounds */
891 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
892 lock_ReleaseMutex(&vcp->mx);
894 /* Create a new smb_user_t structure and connect them up */
895 lock_ObtainMutex(&unp->mx);
897 lock_ReleaseMutex(&unp->mx);
899 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
901 lock_ObtainMutex(&uidp->mx);
903 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
904 lock_ReleaseMutex(&uidp->mx);
905 smb_ReleaseUID(uidp);
909 /* Return UID to the client */
910 ((smb_t *)outp)->uid = newUid;
911 /* Also to the next chained message */
912 ((smb_t *)inp)->uid = newUid;
914 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
915 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
917 smb_SetSMBParm(outp, 2, 0);
919 if (vcp->flags & SMB_VCFLAG_USENT) {
920 if (smb_authType == SMB_AUTH_EXTENDED) {
921 smb_SetSMBParm(outp, 3, secBlobOutLength);
922 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
923 tp = smb_GetSMBData(outp, NULL);
924 if (secBlobOutLength) {
925 memcpy(tp, secBlobOut, secBlobOutLength);
927 tp += secBlobOutLength;
929 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
930 tp += smb_ServerOSLength;
931 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
932 tp += smb_ServerLanManagerLength;
933 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
934 tp += smb_ServerDomainNameLength;
936 smb_SetSMBDataLength(outp, 0);
939 if (smb_authType == SMB_AUTH_EXTENDED) {
940 smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
941 tp = smb_GetSMBData(outp, NULL);
942 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
943 tp += smb_ServerOSLength;
944 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
945 tp += smb_ServerLanManagerLength;
946 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
947 tp += smb_ServerDomainNameLength;
949 smb_SetSMBDataLength(outp, 0);
956 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
960 /* find the tree and free it */
961 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
963 smb_username_t * unp;
965 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %s", uidp->userID,
966 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "));
968 lock_ObtainMutex(&uidp->mx);
969 uidp->flags |= SMB_USERFLAG_DELETE;
971 * it doesn't get deleted right away
972 * because the vcp points to it
975 lock_ReleaseMutex(&uidp->mx);
978 /* we can't do this. we get logoff messages prior to a session
979 * disconnect even though it doesn't mean the user is logging out.
980 * we need to create a new pioctl and EventLogoff handler to set
981 * SMB_USERNAMEFLAG_LOGOFF.
983 if (unp && smb_LogoffTokenTransfer) {
984 lock_ObtainMutex(&unp->mx);
985 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
986 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
987 lock_ReleaseMutex(&unp->mx);
991 smb_ReleaseUID(uidp);
994 osi_Log0(smb_logp, "SMB3 user logoffX");
996 smb_SetSMBDataLength(outp, 0);
1000 #define SMB_SUPPORT_SEARCH_BITS 0x0001
1001 #define SMB_SHARE_IS_IN_DFS 0x0002
1003 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1006 smb_user_t *uidp = NULL;
1007 unsigned short newTid;
1008 char shareName[AFSPATHMAX];
1015 cm_user_t *userp = NULL;
1018 osi_Log0(smb_logp, "SMB3 receive tree connect");
1020 /* parse input parameters */
1021 tp = smb_GetSMBData(inp, NULL);
1022 passwordp = smb_ParseString(tp, &tp);
1023 pathp = smb_ParseString(tp, &tp);
1024 if (smb_StoreAnsiFilenames)
1025 OemToChar(pathp,pathp);
1026 servicep = smb_ParseString(tp, &tp);
1028 tp = strrchr(pathp, '\\');
1030 return CM_ERROR_BADSMB;
1032 strcpy(shareName, tp+1);
1034 osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
1035 osi_LogSaveString(smb_logp, pathp),
1036 osi_LogSaveString(smb_logp, shareName));
1038 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
1040 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1043 return CM_ERROR_NOIPC;
1047 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1049 userp = smb_GetUserFromUID(uidp);
1051 lock_ObtainMutex(&vcp->mx);
1052 newTid = vcp->tidCounter++;
1053 lock_ReleaseMutex(&vcp->mx);
1055 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1058 if (!strcmp(shareName, "*."))
1059 strcpy(shareName, "all");
1060 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1063 smb_ReleaseUID(uidp);
1064 smb_ReleaseTID(tidp, FALSE);
1065 return CM_ERROR_BADSHARENAME;
1068 if (vcp->flags & SMB_VCFLAG_USENT)
1070 int policy = smb_FindShareCSCPolicy(shareName);
1073 DWORD dwAdvertiseDFS = 0, dwSize = sizeof(DWORD);
1075 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1076 0, KEY_QUERY_VALUE, &parmKey);
1077 if (code == ERROR_SUCCESS) {
1078 code = RegQueryValueEx(parmKey, "AdvertiseDFS", NULL, NULL,
1079 (BYTE *)&dwAdvertiseDFS, &dwSize);
1080 if (code != ERROR_SUCCESS)
1082 RegCloseKey (parmKey);
1084 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1085 (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
1089 smb_SetSMBParm(outp, 2, 0);
1093 smb_ReleaseUID(uidp);
1095 lock_ObtainMutex(&tidp->mx);
1096 tidp->userp = userp;
1097 tidp->pathname = sharePath;
1099 tidp->flags |= SMB_TIDFLAG_IPC;
1100 lock_ReleaseMutex(&tidp->mx);
1101 smb_ReleaseTID(tidp, FALSE);
1103 ((smb_t *)outp)->tid = newTid;
1104 ((smb_t *)inp)->tid = newTid;
1105 tp = smb_GetSMBData(outp, NULL);
1107 /* XXX - why is this a drive letter? */
1115 smb_SetSMBDataLength(outp, 7);
1118 smb_SetSMBDataLength(outp, 4);
1121 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1125 /* must be called with global tran lock held */
1126 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1128 smb_tran2Packet_t *tp;
1131 smbp = (smb_t *) inp->data;
1132 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1133 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1139 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1140 int totalParms, int totalData)
1142 smb_tran2Packet_t *tp;
1145 smbp = (smb_t *) inp->data;
1146 tp = malloc(sizeof(*tp));
1147 memset(tp, 0, sizeof(*tp));
1150 tp->curData = tp->curParms = 0;
1151 tp->totalData = totalData;
1152 tp->totalParms = totalParms;
1153 tp->tid = smbp->tid;
1154 tp->mid = smbp->mid;
1155 tp->uid = smbp->uid;
1156 tp->pid = smbp->pid;
1157 tp->res[0] = smbp->res[0];
1158 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1159 if (totalParms != 0)
1160 tp->parmsp = malloc(totalParms);
1162 tp->datap = malloc(totalData);
1163 if (smbp->com == 0x25 || smbp->com == 0x26)
1166 tp->opcode = smb_GetSMBParm(inp, 14);
1169 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1173 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1174 smb_tran2Packet_t *inp, smb_packet_t *outp,
1175 int totalParms, int totalData)
1177 smb_tran2Packet_t *tp;
1178 unsigned short parmOffset;
1179 unsigned short dataOffset;
1180 unsigned short dataAlign;
1182 tp = malloc(sizeof(*tp));
1183 memset(tp, 0, sizeof(*tp));
1186 tp->curData = tp->curParms = 0;
1187 tp->totalData = totalData;
1188 tp->totalParms = totalParms;
1189 tp->oldTotalParms = totalParms;
1194 tp->res[0] = inp->res[0];
1195 tp->opcode = inp->opcode;
1199 * We calculate where the parameters and data will start.
1200 * This calculation must parallel the calculation in
1201 * smb_SendTran2Packet.
1204 parmOffset = 10*2 + 35;
1205 parmOffset++; /* round to even */
1206 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1208 dataOffset = parmOffset + totalParms;
1209 dataAlign = dataOffset & 2; /* quad-align */
1210 dataOffset += dataAlign;
1211 tp->datap = outp->data + dataOffset;
1216 /* free a tran2 packet */
1217 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1220 smb_ReleaseVC(t2p->vcp);
1223 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1232 /* called with a VC, an input packet to respond to, and an error code.
1233 * sends an error response.
1235 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1236 smb_packet_t *tp, long code)
1239 unsigned short errCode;
1240 unsigned char errClass;
1241 unsigned long NTStatus;
1243 if (vcp->flags & SMB_VCFLAG_STATUS32)
1244 smb_MapNTError(code, &NTStatus);
1246 smb_MapCoreError(code, vcp, &errCode, &errClass);
1248 smb_FormatResponsePacket(vcp, NULL, tp);
1249 smbp = (smb_t *) tp;
1251 /* We can handle long names */
1252 if (vcp->flags & SMB_VCFLAG_USENT)
1253 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1255 /* now copy important fields from the tran 2 packet */
1256 smbp->com = t2p->com;
1257 smbp->tid = t2p->tid;
1258 smbp->mid = t2p->mid;
1259 smbp->pid = t2p->pid;
1260 smbp->uid = t2p->uid;
1261 smbp->res[0] = t2p->res[0];
1262 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1263 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1264 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1265 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1266 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1267 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1270 smbp->rcls = errClass;
1271 smbp->errLow = (unsigned char) (errCode & 0xff);
1272 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1276 smb_SendPacket(vcp, tp);
1279 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1282 unsigned short parmOffset;
1283 unsigned short dataOffset;
1284 unsigned short totalLength;
1285 unsigned short dataAlign;
1288 smb_FormatResponsePacket(vcp, NULL, tp);
1289 smbp = (smb_t *) tp;
1291 /* We can handle long names */
1292 if (vcp->flags & SMB_VCFLAG_USENT)
1293 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1295 /* now copy important fields from the tran 2 packet */
1296 smbp->com = t2p->com;
1297 smbp->tid = t2p->tid;
1298 smbp->mid = t2p->mid;
1299 smbp->pid = t2p->pid;
1300 smbp->uid = t2p->uid;
1301 smbp->res[0] = t2p->res[0];
1303 totalLength = 1 + t2p->totalData + t2p->totalParms;
1305 /* now add the core parameters (tran2 info) to the packet */
1306 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1307 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1308 smb_SetSMBParm(tp, 2, 0); /* reserved */
1309 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1310 parmOffset = 10*2 + 35; /* parm offset in packet */
1311 parmOffset++; /* round to even */
1312 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1313 * hdr, bcc and wct */
1314 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1315 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1316 dataOffset = parmOffset + t2p->oldTotalParms;
1317 dataAlign = dataOffset & 2; /* quad-align */
1318 dataOffset += dataAlign;
1319 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1320 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1321 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1324 datap = smb_GetSMBData(tp, NULL);
1325 *datap++ = 0; /* we rounded to even */
1327 totalLength += dataAlign;
1328 smb_SetSMBDataLength(tp, totalLength);
1330 /* next, send the datagram */
1331 smb_SendPacket(vcp, tp);
1334 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1336 smb_tran2Packet_t *asp;
1349 /* We sometimes see 0 word count. What to do? */
1350 if (*inp->wctp == 0) {
1351 osi_Log0(smb_logp, "Transaction2 word count = 0");
1352 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1354 smb_SetSMBDataLength(outp, 0);
1355 smb_SendPacket(vcp, outp);
1359 totalParms = smb_GetSMBParm(inp, 0);
1360 totalData = smb_GetSMBParm(inp, 1);
1362 firstPacket = (inp->inCom == 0x25);
1364 /* find the packet we're reassembling */
1365 lock_ObtainWrite(&smb_globalLock);
1366 asp = smb_FindTran2Packet(vcp, inp);
1368 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1370 lock_ReleaseWrite(&smb_globalLock);
1372 /* now merge in this latest packet; start by looking up offsets */
1374 parmDisp = dataDisp = 0;
1375 parmOffset = smb_GetSMBParm(inp, 10);
1376 dataOffset = smb_GetSMBParm(inp, 12);
1377 parmCount = smb_GetSMBParm(inp, 9);
1378 dataCount = smb_GetSMBParm(inp, 11);
1379 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1380 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1382 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1383 totalData, dataCount, asp->maxReturnData);
1386 parmDisp = smb_GetSMBParm(inp, 4);
1387 parmOffset = smb_GetSMBParm(inp, 3);
1388 dataDisp = smb_GetSMBParm(inp, 7);
1389 dataOffset = smb_GetSMBParm(inp, 6);
1390 parmCount = smb_GetSMBParm(inp, 2);
1391 dataCount = smb_GetSMBParm(inp, 5);
1393 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1394 parmCount, dataCount);
1397 /* now copy the parms and data */
1398 if ( asp->totalParms > 0 && parmCount != 0 )
1400 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1402 if ( asp->totalData > 0 && dataCount != 0 ) {
1403 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1406 /* account for new bytes */
1407 asp->curData += dataCount;
1408 asp->curParms += parmCount;
1410 /* finally, if we're done, remove the packet from the queue and dispatch it */
1411 if (asp->totalParms > 0 &&
1412 asp->curParms > 0 &&
1413 asp->totalData <= asp->curData &&
1414 asp->totalParms <= asp->curParms) {
1415 /* we've received it all */
1416 lock_ObtainWrite(&smb_globalLock);
1417 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1418 lock_ReleaseWrite(&smb_globalLock);
1420 /* now dispatch it */
1421 rapOp = asp->parmsp[0];
1423 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1424 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1425 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1426 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
1429 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1430 code = CM_ERROR_BADOP;
1433 /* if an error is returned, we're supposed to send an error packet,
1434 * otherwise the dispatched function already did the data sending.
1435 * We give dispatched proc the responsibility since it knows how much
1436 * space to allocate.
1439 smb_SendTran2Error(vcp, asp, outp, code);
1442 /* free the input tran 2 packet */
1443 smb_FreeTran2Packet(asp);
1445 else if (firstPacket) {
1446 /* the first packet in a multi-packet request, we need to send an
1447 * ack to get more data.
1449 smb_SetSMBDataLength(outp, 0);
1450 smb_SendPacket(vcp, outp);
1456 /* ANSI versions. The unicode versions support arbitrary length
1457 share names, but we don't support unicode yet. */
1459 typedef struct smb_rap_share_info_0 {
1460 char shi0_netname[13];
1461 } smb_rap_share_info_0_t;
1463 typedef struct smb_rap_share_info_1 {
1464 char shi1_netname[13];
1467 DWORD shi1_remark; /* char *shi1_remark; data offset */
1468 } smb_rap_share_info_1_t;
1470 typedef struct smb_rap_share_info_2 {
1471 char shi2_netname[13];
1473 unsigned short shi2_type;
1474 DWORD shi2_remark; /* char *shi2_remark; data offset */
1475 unsigned short shi2_permissions;
1476 unsigned short shi2_max_uses;
1477 unsigned short shi2_current_uses;
1478 DWORD shi2_path; /* char *shi2_path; data offset */
1479 unsigned short shi2_passwd[9];
1480 unsigned short shi2_pad2;
1481 } smb_rap_share_info_2_t;
1483 #define SMB_RAP_MAX_SHARES 512
1485 typedef struct smb_rap_share_list {
1488 smb_rap_share_info_0_t * shares;
1489 } smb_rap_share_list_t;
1491 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1492 smb_rap_share_list_t * sp;
1497 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1498 return 0; /* skip over '.' and '..' */
1500 sp = (smb_rap_share_list_t *) vrockp;
1502 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1503 sp->shares[sp->cShare].shi0_netname[12] = 0;
1507 if (sp->cShare >= sp->maxShares)
1508 return CM_ERROR_STOPNOW;
1513 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1515 smb_tran2Packet_t *outp;
1516 unsigned short * tp;
1520 int outParmsTotal; /* total parameter bytes */
1521 int outDataTotal; /* total data bytes */
1524 DWORD allSubmount = 0;
1526 DWORD nRegShares = 0;
1527 DWORD nSharesRet = 0;
1529 HKEY hkSubmount = NULL;
1530 smb_rap_share_info_1_t * shares;
1533 char thisShare[AFSPATHMAX];
1537 smb_rap_share_list_t rootShares;
1542 tp = p->parmsp + 1; /* skip over function number (always 0) */
1543 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1544 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1548 if (infoLevel != 1) {
1549 return CM_ERROR_INVAL;
1552 /* first figure out how many shares there are */
1553 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1554 KEY_QUERY_VALUE, &hkParam);
1555 if (rv == ERROR_SUCCESS) {
1556 len = sizeof(allSubmount);
1557 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1558 (BYTE *) &allSubmount, &len);
1559 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1562 RegCloseKey (hkParam);
1565 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1566 0, KEY_QUERY_VALUE, &hkSubmount);
1567 if (rv == ERROR_SUCCESS) {
1568 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1569 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1570 if (rv != ERROR_SUCCESS)
1576 /* fetch the root shares */
1577 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1578 rootShares.cShare = 0;
1579 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1583 userp = smb_GetTran2User(vcp,p);
1585 thyper.HighPart = 0;
1588 cm_HoldSCache(cm_data.rootSCachep);
1589 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1590 cm_ReleaseSCache(cm_data.rootSCachep);
1592 cm_ReleaseUser(userp);
1594 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1596 #define REMARK_LEN 1
1597 outParmsTotal = 8; /* 4 dwords */
1598 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1599 if(outDataTotal > bufsize) {
1600 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1601 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1604 nSharesRet = nShares;
1607 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1609 /* now for the submounts */
1610 shares = (smb_rap_share_info_1_t *) outp->datap;
1611 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1613 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1616 strcpy( shares[cshare].shi1_netname, "all" );
1617 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1618 /* type and pad are zero already */
1624 for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
1625 len = sizeof(thisShare);
1626 rv = RegEnumValue(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
1627 if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1628 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1629 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1630 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1635 nShares--; /* uncount key */
1638 RegCloseKey(hkSubmount);
1641 nonrootShares = cshare;
1643 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1644 /* in case there are collisions with submounts, submounts have higher priority */
1645 for (j=0; j < nonrootShares; j++)
1646 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1649 if (j < nonrootShares) {
1650 nShares--; /* uncount */
1654 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1655 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1660 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1661 outp->parmsp[1] = 0;
1662 outp->parmsp[2] = cshare;
1663 outp->parmsp[3] = nShares;
1665 outp->totalData = (int)(cstrp - outp->datap);
1666 outp->totalParms = outParmsTotal;
1668 smb_SendTran2Packet(vcp, outp, op);
1669 smb_FreeTran2Packet(outp);
1671 free(rootShares.shares);
1676 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1678 smb_tran2Packet_t *outp;
1679 unsigned short * tp;
1681 BOOL shareFound = FALSE;
1682 unsigned short infoLevel;
1683 unsigned short bufsize;
1692 cm_scache_t *scp = NULL;
1698 tp = p->parmsp + 1; /* skip over function number (always 1) */
1699 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1700 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1701 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1708 totalData = sizeof(smb_rap_share_info_0_t);
1709 else if(infoLevel == SMB_INFO_STANDARD)
1710 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1711 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1712 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1714 return CM_ERROR_INVAL;
1716 if(!stricmp(shareName,"all") || !strcmp(shareName,"*.")) {
1717 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1718 KEY_QUERY_VALUE, &hkParam);
1719 if (rv == ERROR_SUCCESS) {
1720 len = sizeof(allSubmount);
1721 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1722 (BYTE *) &allSubmount, &len);
1723 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1726 RegCloseKey (hkParam);
1733 userp = smb_GetTran2User(vcp, p);
1735 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
1736 return CM_ERROR_BADSMB;
1738 code = cm_NameI(cm_data.rootSCachep, shareName,
1739 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
1740 userp, NULL, &req, &scp);
1742 cm_ReleaseSCache(scp);
1745 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1746 KEY_QUERY_VALUE, &hkSubmount);
1747 if (rv == ERROR_SUCCESS) {
1748 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1749 if (rv == ERROR_SUCCESS) {
1752 RegCloseKey(hkSubmount);
1758 return CM_ERROR_BADSHARENAME;
1760 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1761 memset(outp->datap, 0, totalData);
1763 outp->parmsp[0] = 0;
1764 outp->parmsp[1] = 0;
1765 outp->parmsp[2] = totalData;
1767 if (infoLevel == 0) {
1768 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1769 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1770 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1771 } else if(infoLevel == SMB_INFO_STANDARD) {
1772 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1773 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1774 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1775 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1776 /* type and pad are already zero */
1777 } else { /* infoLevel==2 */
1778 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1779 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1780 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1781 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1782 info->shi2_permissions = ACCESS_ALL;
1783 info->shi2_max_uses = (unsigned short) -1;
1784 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
1787 outp->totalData = totalData;
1788 outp->totalParms = totalParam;
1790 smb_SendTran2Packet(vcp, outp, op);
1791 smb_FreeTran2Packet(outp);
1796 typedef struct smb_rap_wksta_info_10 {
1797 DWORD wki10_computername; /*char *wki10_computername;*/
1798 DWORD wki10_username; /* char *wki10_username; */
1799 DWORD wki10_langroup; /* char *wki10_langroup;*/
1800 unsigned char wki10_ver_major;
1801 unsigned char wki10_ver_minor;
1802 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1803 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1804 } smb_rap_wksta_info_10_t;
1807 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1809 smb_tran2Packet_t *outp;
1813 unsigned short * tp;
1816 smb_rap_wksta_info_10_t * info;
1820 tp = p->parmsp + 1; /* Skip over function number */
1821 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1822 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1826 if (infoLevel != 10) {
1827 return CM_ERROR_INVAL;
1833 totalData = sizeof(*info) + /* info */
1834 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1835 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1836 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1837 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1838 1; /* wki10_oth_domains (null)*/
1840 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1842 memset(outp->parmsp,0,totalParams);
1843 memset(outp->datap,0,totalData);
1845 info = (smb_rap_wksta_info_10_t *) outp->datap;
1846 cstrp = (char *) (info + 1);
1848 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1849 strcpy(cstrp, smb_localNamep);
1850 cstrp += strlen(cstrp) + 1;
1852 info->wki10_username = (DWORD) (cstrp - outp->datap);
1853 uidp = smb_FindUID(vcp, p->uid, 0);
1855 lock_ObtainMutex(&uidp->mx);
1856 if(uidp->unp && uidp->unp->name)
1857 strcpy(cstrp, uidp->unp->name);
1858 lock_ReleaseMutex(&uidp->mx);
1859 smb_ReleaseUID(uidp);
1861 cstrp += strlen(cstrp) + 1;
1863 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1864 strcpy(cstrp, "WORKGROUP");
1865 cstrp += strlen(cstrp) + 1;
1867 /* TODO: Not sure what values these should take, but these work */
1868 info->wki10_ver_major = 5;
1869 info->wki10_ver_minor = 1;
1871 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1872 strcpy(cstrp, smb_ServerDomainName);
1873 cstrp += strlen(cstrp) + 1;
1875 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1876 cstrp ++; /* no other domains */
1878 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1879 outp->parmsp[2] = outp->totalData;
1880 outp->totalParms = totalParams;
1882 smb_SendTran2Packet(vcp,outp,op);
1883 smb_FreeTran2Packet(outp);
1888 typedef struct smb_rap_server_info_0 {
1890 } smb_rap_server_info_0_t;
1892 typedef struct smb_rap_server_info_1 {
1894 char sv1_version_major;
1895 char sv1_version_minor;
1896 unsigned long sv1_type;
1897 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1898 } smb_rap_server_info_1_t;
1900 char smb_ServerComment[] = "OpenAFS Client";
1901 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1903 #define SMB_SV_TYPE_SERVER 0x00000002L
1904 #define SMB_SV_TYPE_NT 0x00001000L
1905 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1907 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1909 smb_tran2Packet_t *outp;
1913 unsigned short * tp;
1916 smb_rap_server_info_0_t * info0;
1917 smb_rap_server_info_1_t * info1;
1920 tp = p->parmsp + 1; /* Skip over function number */
1921 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1922 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1926 if (infoLevel != 0 && infoLevel != 1) {
1927 return CM_ERROR_INVAL;
1933 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1934 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1936 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1938 memset(outp->parmsp,0,totalParams);
1939 memset(outp->datap,0,totalData);
1941 if (infoLevel == 0) {
1942 info0 = (smb_rap_server_info_0_t *) outp->datap;
1943 cstrp = (char *) (info0 + 1);
1944 strcpy(info0->sv0_name, "AFS");
1945 } else { /* infoLevel == SMB_INFO_STANDARD */
1946 info1 = (smb_rap_server_info_1_t *) outp->datap;
1947 cstrp = (char *) (info1 + 1);
1948 strcpy(info1->sv1_name, "AFS");
1951 SMB_SV_TYPE_SERVER |
1953 SMB_SV_TYPE_SERVER_NT;
1955 info1->sv1_version_major = 5;
1956 info1->sv1_version_minor = 1;
1957 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1959 strcpy(cstrp, smb_ServerComment);
1961 cstrp += smb_ServerCommentLen;
1964 totalData = (DWORD)(cstrp - outp->datap);
1965 outp->totalData = min(bufsize,totalData); /* actual data size */
1966 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1967 outp->parmsp[2] = totalData;
1968 outp->totalParms = totalParams;
1970 smb_SendTran2Packet(vcp,outp,op);
1971 smb_FreeTran2Packet(outp);
1976 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1978 smb_tran2Packet_t *asp;
1990 /* We sometimes see 0 word count. What to do? */
1991 if (*inp->wctp == 0) {
1992 osi_Log0(smb_logp, "Transaction2 word count = 0");
1993 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1995 smb_SetSMBDataLength(outp, 0);
1996 smb_SendPacket(vcp, outp);
2000 totalParms = smb_GetSMBParm(inp, 0);
2001 totalData = smb_GetSMBParm(inp, 1);
2003 firstPacket = (inp->inCom == 0x32);
2005 /* find the packet we're reassembling */
2006 lock_ObtainWrite(&smb_globalLock);
2007 asp = smb_FindTran2Packet(vcp, inp);
2009 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
2011 lock_ReleaseWrite(&smb_globalLock);
2013 /* now merge in this latest packet; start by looking up offsets */
2015 parmDisp = dataDisp = 0;
2016 parmOffset = smb_GetSMBParm(inp, 10);
2017 dataOffset = smb_GetSMBParm(inp, 12);
2018 parmCount = smb_GetSMBParm(inp, 9);
2019 dataCount = smb_GetSMBParm(inp, 11);
2020 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2021 asp->maxReturnData = smb_GetSMBParm(inp, 3);
2023 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2024 totalData, dataCount, asp->maxReturnData);
2027 parmDisp = smb_GetSMBParm(inp, 4);
2028 parmOffset = smb_GetSMBParm(inp, 3);
2029 dataDisp = smb_GetSMBParm(inp, 7);
2030 dataOffset = smb_GetSMBParm(inp, 6);
2031 parmCount = smb_GetSMBParm(inp, 2);
2032 dataCount = smb_GetSMBParm(inp, 5);
2034 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2035 parmCount, dataCount);
2038 /* now copy the parms and data */
2039 if ( asp->totalParms > 0 && parmCount != 0 )
2041 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2043 if ( asp->totalData > 0 && dataCount != 0 ) {
2044 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2047 /* account for new bytes */
2048 asp->curData += dataCount;
2049 asp->curParms += parmCount;
2051 /* finally, if we're done, remove the packet from the queue and dispatch it */
2052 if (asp->totalParms > 0 &&
2053 asp->curParms > 0 &&
2054 asp->totalData <= asp->curData &&
2055 asp->totalParms <= asp->curParms) {
2056 /* we've received it all */
2057 lock_ObtainWrite(&smb_globalLock);
2058 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2059 lock_ReleaseWrite(&smb_globalLock);
2061 /* now dispatch it */
2062 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2063 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2064 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2067 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2068 code = CM_ERROR_BADOP;
2071 /* if an error is returned, we're supposed to send an error packet,
2072 * otherwise the dispatched function already did the data sending.
2073 * We give dispatched proc the responsibility since it knows how much
2074 * space to allocate.
2077 smb_SendTran2Error(vcp, asp, outp, code);
2080 /* free the input tran 2 packet */
2081 smb_FreeTran2Packet(asp);
2083 else if (firstPacket) {
2084 /* the first packet in a multi-packet request, we need to send an
2085 * ack to get more data.
2087 smb_SetSMBDataLength(outp, 0);
2088 smb_SendPacket(vcp, outp);
2094 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2097 smb_tran2Packet_t *outp;
2102 cm_scache_t *dscp; /* dir we're dealing with */
2103 cm_scache_t *scp; /* file we're creating */
2105 int initialModeBits;
2115 int parmSlot; /* which parm we're dealing with */
2116 long returnEALength;
2125 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2126 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2128 openFun = p->parmsp[6]; /* open function */
2129 excl = ((openFun & 3) == 0);
2130 trunc = ((openFun & 3) == 2); /* truncate it */
2131 openMode = (p->parmsp[1] & 0x7);
2132 openAction = 0; /* tracks what we did */
2134 attributes = p->parmsp[3];
2135 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2137 /* compute initial mode bits based on read-only flag in attributes */
2138 initialModeBits = 0666;
2139 if (attributes & SMB_ATTR_READONLY)
2140 initialModeBits &= ~0222;
2142 pathp = (char *) (&p->parmsp[14]);
2143 if (smb_StoreAnsiFilenames)
2144 OemToChar(pathp,pathp);
2146 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2148 spacep = cm_GetSpace();
2149 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2152 (stricmp(lastNamep, SMB_IOCTL_FILENAME) == 0 ||
2153 stricmp(lastNamep, "\\srvsvc") == 0 ||
2154 stricmp(lastNamep, "\\wkssvc") == 0 ||
2155 stricmp(lastNamep, "\\ipc$") == 0)) {
2156 /* special case magic file name for receiving IOCTL requests
2157 * (since IOCTL calls themselves aren't getting through).
2159 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2160 smb_SetupIoctlFid(fidp, spacep);
2162 /* copy out remainder of the parms */
2164 outp->parmsp[parmSlot++] = fidp->fid;
2166 outp->parmsp[parmSlot++] = 0; /* attrs */
2167 outp->parmsp[parmSlot++] = 0; /* mod time */
2168 outp->parmsp[parmSlot++] = 0;
2169 outp->parmsp[parmSlot++] = 0; /* len */
2170 outp->parmsp[parmSlot++] = 0x7fff;
2171 outp->parmsp[parmSlot++] = openMode;
2172 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2173 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2175 /* and the final "always present" stuff */
2176 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2177 /* next write out the "unique" ID */
2178 outp->parmsp[parmSlot++] = 0x1234;
2179 outp->parmsp[parmSlot++] = 0x5678;
2180 outp->parmsp[parmSlot++] = 0;
2181 if (returnEALength) {
2182 outp->parmsp[parmSlot++] = 0;
2183 outp->parmsp[parmSlot++] = 0;
2186 outp->totalData = 0;
2187 outp->totalParms = parmSlot * 2;
2189 smb_SendTran2Packet(vcp, outp, op);
2191 smb_FreeTran2Packet(outp);
2193 /* and clean up fid reference */
2194 smb_ReleaseFID(fidp);
2198 #ifdef DEBUG_VERBOSE
2200 char *hexp, *asciip;
2201 asciip = (lastNamep ? lastNamep : pathp);
2202 hexp = osi_HexifyString( asciip );
2203 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2208 userp = smb_GetTran2User(vcp, p);
2209 /* In the off chance that userp is NULL, we log and abandon */
2211 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2212 smb_FreeTran2Packet(outp);
2213 return CM_ERROR_BADSMB;
2216 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2217 if (code == CM_ERROR_TIDIPC) {
2218 /* Attempt to use a TID allocated for IPC. The client
2219 * is probably looking for DCE RPC end points which we
2220 * don't support OR it could be looking to make a DFS
2223 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2225 cm_ReleaseUser(userp);
2226 smb_FreeTran2Packet(outp);
2227 return CM_ERROR_NOSUCHPATH;
2232 code = cm_NameI(cm_data.rootSCachep, pathp,
2233 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2234 userp, tidPathp, &req, &scp);
2236 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2237 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2238 userp, tidPathp, &req, &dscp);
2239 cm_FreeSpace(spacep);
2242 cm_ReleaseUser(userp);
2243 smb_FreeTran2Packet(outp);
2248 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2249 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
2250 cm_ReleaseSCache(dscp);
2251 cm_ReleaseUser(userp);
2252 smb_FreeTran2Packet(outp);
2253 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2254 return CM_ERROR_PATH_NOT_COVERED;
2256 return CM_ERROR_BADSHARENAME;
2258 #endif /* DFS_SUPPORT */
2260 /* otherwise, scp points to the parent directory. Do a lookup,
2261 * and truncate the file if we find it, otherwise we create the
2268 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2270 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2271 cm_ReleaseSCache(dscp);
2272 cm_ReleaseUser(userp);
2273 smb_FreeTran2Packet(outp);
2278 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2279 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2280 cm_ReleaseSCache(scp);
2281 cm_ReleaseUser(userp);
2282 smb_FreeTran2Packet(outp);
2283 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2284 return CM_ERROR_PATH_NOT_COVERED;
2286 return CM_ERROR_BADSHARENAME;
2288 #endif /* DFS_SUPPORT */
2290 /* macintosh is expensive to program for it */
2291 cm_FreeSpace(spacep);
2294 /* if we get here, if code is 0, the file exists and is represented by
2295 * scp. Otherwise, we have to create it.
2298 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2301 cm_ReleaseSCache(dscp);
2302 cm_ReleaseSCache(scp);
2303 cm_ReleaseUser(userp);
2304 smb_FreeTran2Packet(outp);
2309 /* oops, file shouldn't be there */
2311 cm_ReleaseSCache(dscp);
2312 cm_ReleaseSCache(scp);
2313 cm_ReleaseUser(userp);
2314 smb_FreeTran2Packet(outp);
2315 return CM_ERROR_EXISTS;
2319 setAttr.mask = CM_ATTRMASK_LENGTH;
2320 setAttr.length.LowPart = 0;
2321 setAttr.length.HighPart = 0;
2322 code = cm_SetAttr(scp, &setAttr, userp, &req);
2323 openAction = 3; /* truncated existing file */
2326 openAction = 1; /* found existing file */
2328 else if (!(openFun & 0x10)) {
2329 /* don't create if not found */
2331 cm_ReleaseSCache(dscp);
2332 osi_assertx(scp == NULL, "null cm_scache_t");
2333 cm_ReleaseUser(userp);
2334 smb_FreeTran2Packet(outp);
2335 return CM_ERROR_NOSUCHFILE;
2338 osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2339 openAction = 2; /* created file */
2340 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2341 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2342 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2346 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2347 smb_NotifyChange(FILE_ACTION_ADDED,
2348 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2349 dscp, lastNamep, NULL, TRUE);
2350 } else if (!excl && code == CM_ERROR_EXISTS) {
2351 /* not an exclusive create, and someone else tried
2352 * creating it already, then we open it anyway. We
2353 * don't bother retrying after this, since if this next
2354 * fails, that means that the file was deleted after we
2355 * started this call.
2357 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2361 setAttr.mask = CM_ATTRMASK_LENGTH;
2362 setAttr.length.LowPart = 0;
2363 setAttr.length.HighPart = 0;
2364 code = cm_SetAttr(scp, &setAttr, userp,
2367 } /* lookup succeeded */
2371 /* we don't need this any longer */
2373 cm_ReleaseSCache(dscp);
2376 /* something went wrong creating or truncating the file */
2378 cm_ReleaseSCache(scp);
2379 cm_ReleaseUser(userp);
2380 smb_FreeTran2Packet(outp);
2384 /* make sure we're about to open a file */
2385 if (scp->fileType != CM_SCACHETYPE_FILE) {
2387 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2388 cm_scache_t * targetScp = 0;
2389 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2391 /* we have a more accurate file to use (the
2392 * target of the symbolic link). Otherwise,
2393 * we'll just use the symlink anyway.
2395 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2397 cm_ReleaseSCache(scp);
2401 if (scp->fileType != CM_SCACHETYPE_FILE) {
2402 cm_ReleaseSCache(scp);
2403 cm_ReleaseUser(userp);
2404 smb_FreeTran2Packet(outp);
2405 return CM_ERROR_ISDIR;
2409 /* now all we have to do is open the file itself */
2410 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2411 osi_assertx(fidp, "null smb_fid_t");
2414 lock_ObtainMutex(&fidp->mx);
2415 /* save a pointer to the vnode */
2416 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2418 lock_ObtainWrite(&scp->rw);
2419 scp->flags |= CM_SCACHEFLAG_SMB_FID;
2420 lock_ReleaseWrite(&scp->rw);
2423 fidp->userp = userp;
2425 /* compute open mode */
2427 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
2428 if (openMode == 1 || openMode == 2)
2429 fidp->flags |= SMB_FID_OPENWRITE;
2431 /* remember that the file was newly created */
2433 fidp->flags |= SMB_FID_CREATED;
2435 lock_ReleaseMutex(&fidp->mx);
2437 smb_ReleaseFID(fidp);
2439 cm_Open(scp, 0, userp);
2441 /* copy out remainder of the parms */
2443 outp->parmsp[parmSlot++] = fidp->fid;
2444 lock_ObtainRead(&scp->rw);
2446 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2447 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2448 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2449 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2450 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2451 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2452 outp->parmsp[parmSlot++] = openMode;
2453 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2454 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2456 /* and the final "always present" stuff */
2457 outp->parmsp[parmSlot++] = openAction;
2458 /* next write out the "unique" ID */
2459 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2460 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2461 outp->parmsp[parmSlot++] = 0;
2462 if (returnEALength) {
2463 outp->parmsp[parmSlot++] = 0;
2464 outp->parmsp[parmSlot++] = 0;
2466 lock_ReleaseRead(&scp->rw);
2467 outp->totalData = 0; /* total # of data bytes */
2468 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2470 smb_SendTran2Packet(vcp, outp, op);
2472 smb_FreeTran2Packet(outp);
2474 cm_ReleaseUser(userp);
2475 /* leave scp held since we put it in fidp->scp */
2479 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2482 unsigned short infolevel;
2484 infolevel = p->parmsp[0];
2486 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2488 return CM_ERROR_BAD_LEVEL;
2491 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2493 smb_tran2Packet_t *outp;
2494 smb_tran2QFSInfo_t qi;
2496 static char FSname[8] = {'A', 0, 'F', 0, 'S', 0, 0, 0};
2498 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2500 switch (p->parmsp[0]) {
2501 case SMB_INFO_ALLOCATION:
2502 responseSize = sizeof(qi.u.allocInfo);
2504 case SMB_INFO_VOLUME:
2505 responseSize = sizeof(qi.u.volumeInfo);
2507 case SMB_QUERY_FS_VOLUME_INFO:
2508 responseSize = sizeof(qi.u.FSvolumeInfo);
2510 case SMB_QUERY_FS_SIZE_INFO:
2511 responseSize = sizeof(qi.u.FSsizeInfo);
2513 case SMB_QUERY_FS_DEVICE_INFO:
2514 responseSize = sizeof(qi.u.FSdeviceInfo);
2516 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2517 responseSize = sizeof(qi.u.FSattributeInfo);
2519 case SMB_INFO_UNIX: /* CIFS Unix Info */
2520 case SMB_INFO_MACOS: /* Mac FS Info */
2522 return CM_ERROR_BADOP;
2525 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2526 switch (p->parmsp[0]) {
2527 case SMB_INFO_ALLOCATION:
2529 qi.u.allocInfo.FSID = 0;
2530 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2531 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2532 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2533 qi.u.allocInfo.bytesPerSector = 1024;
2536 case SMB_INFO_VOLUME:
2538 qi.u.volumeInfo.vsn = 1234;
2539 qi.u.volumeInfo.vnCount = 4;
2540 /* we're supposed to pad it out with zeroes to the end */
2541 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2542 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2545 case SMB_QUERY_FS_VOLUME_INFO:
2546 /* FS volume info */
2547 memset((char *)&qi.u.FSvolumeInfo.vct, 0, 4);
2548 qi.u.FSvolumeInfo.vsn = 1234;
2549 qi.u.FSvolumeInfo.vnCount = 8;
2550 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0\0", 8);
2553 case SMB_QUERY_FS_SIZE_INFO:
2555 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2556 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2557 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2558 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2559 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2560 qi.u.FSsizeInfo.bytesPerSector = 1024;
2563 case SMB_QUERY_FS_DEVICE_INFO:
2564 /* FS device info */
2565 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2566 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2569 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2570 /* FS attribute info */
2571 /* attributes, defined in WINNT.H:
2572 * FILE_CASE_SENSITIVE_SEARCH 0x1
2573 * FILE_CASE_PRESERVED_NAMES 0x2
2574 * FILE_VOLUME_QUOTAS 0x10
2575 * <no name defined> 0x4000
2576 * If bit 0x4000 is not set, Windows 95 thinks
2577 * we can't handle long (non-8.3) names,
2578 * despite our protestations to the contrary.
2580 qi.u.FSattributeInfo.attributes = 0x4003;
2581 qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
2582 qi.u.FSattributeInfo.FSnameLength = sizeof(FSname);
2583 memcpy(qi.u.FSattributeInfo.FSname, FSname, sizeof(FSname));
2587 /* copy out return data, and set corresponding sizes */
2588 outp->totalParms = 0;
2589 outp->totalData = responseSize;
2590 memcpy(outp->datap, &qi, responseSize);
2592 /* send and free the packets */
2593 smb_SendTran2Packet(vcp, outp, op);
2594 smb_FreeTran2Packet(outp);
2599 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2601 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2602 return CM_ERROR_BADOP;
2605 struct smb_ShortNameRock {
2609 size_t shortNameLen;
2612 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2615 struct smb_ShortNameRock *rockp;
2619 /* compare both names and vnodes, though probably just comparing vnodes
2620 * would be safe enough.
2622 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2624 if (ntohl(dep->fid.vnode) != rockp->vnode)
2626 /* This is the entry */
2627 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2628 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2629 return CM_ERROR_STOPNOW;
2632 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2633 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2635 struct smb_ShortNameRock rock;
2639 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2643 spacep = cm_GetSpace();
2644 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2646 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2648 cm_FreeSpace(spacep);
2653 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2654 cm_ReleaseSCache(dscp);
2655 cm_ReleaseUser(userp);
2657 return CM_ERROR_PATH_NOT_COVERED;
2659 #endif /* DFS_SUPPORT */
2661 if (!lastNamep) lastNamep = pathp;
2664 thyper.HighPart = 0;
2665 rock.shortName = shortName;
2667 rock.maskp = lastNamep;
2668 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2670 cm_ReleaseSCache(dscp);
2673 return CM_ERROR_NOSUCHFILE;
2674 if (code == CM_ERROR_STOPNOW) {
2675 *shortNameLenp = rock.shortNameLen;
2681 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2683 smb_tran2Packet_t *outp;
2686 unsigned short infoLevel;
2687 smb_tran2QPathInfo_t qpi;
2689 unsigned short attributes;
2690 unsigned long extAttributes;
2695 cm_scache_t *scp, *dscp;
2696 int scp_mx_held = 0;
2706 infoLevel = p->parmsp[0];
2707 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2709 else if (infoLevel == SMB_INFO_STANDARD)
2710 responseSize = sizeof(qpi.u.QPstandardInfo);
2711 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2712 responseSize = sizeof(qpi.u.QPeaSizeInfo);
2713 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2714 responseSize = sizeof(qpi.u.QPfileBasicInfo);
2715 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2716 responseSize = sizeof(qpi.u.QPfileStandardInfo);
2717 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2718 responseSize = sizeof(qpi.u.QPfileEaInfo);
2719 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2720 responseSize = sizeof(qpi.u.QPfileNameInfo);
2721 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
2722 responseSize = sizeof(qpi.u.QPfileAllInfo);
2723 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2724 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2726 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2727 p->opcode, infoLevel);
2728 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
2732 pathp = (char *)(&p->parmsp[3]);
2733 if (smb_StoreAnsiFilenames)
2734 OemToChar(pathp,pathp);
2735 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2736 osi_LogSaveString(smb_logp, pathp));
2738 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2740 if (infoLevel > 0x100)
2741 outp->totalParms = 2;
2743 outp->totalParms = 0;
2744 outp->totalData = responseSize;
2746 /* now, if we're at infoLevel 6, we're only being asked to check
2747 * the syntax, so we just OK things now. In particular, we're *not*
2748 * being asked to verify anything about the state of any parent dirs.
2750 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2751 smb_SendTran2Packet(vcp, outp, opx);
2752 smb_FreeTran2Packet(outp);
2756 userp = smb_GetTran2User(vcp, p);
2758 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2759 smb_FreeTran2Packet(outp);
2760 return CM_ERROR_BADSMB;
2763 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2765 cm_ReleaseUser(userp);
2766 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2767 smb_FreeTran2Packet(outp);
2772 * XXX Strange hack XXX
2774 * As of Patch 7 (13 January 98), we are having the following problem:
2775 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2776 * requests to look up "desktop.ini" in all the subdirectories.
2777 * This can cause zillions of timeouts looking up non-existent cells
2778 * and volumes, especially in the top-level directory.
2780 * We have not found any way to avoid this or work around it except
2781 * to explicitly ignore the requests for mount points that haven't
2782 * yet been evaluated and for directories that haven't yet been
2785 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2786 spacep = cm_GetSpace();
2787 smb_StripLastComponent(spacep->data, &lastComp, pathp);
2788 #ifndef SPECIAL_FOLDERS
2789 /* Make sure that lastComp is not NULL */
2791 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2792 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2796 userp, tidPathp, &req, &dscp);
2799 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2800 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
2801 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2802 code = CM_ERROR_PATH_NOT_COVERED;
2804 code = CM_ERROR_BADSHARENAME;
2806 #endif /* DFS_SUPPORT */
2807 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2808 code = CM_ERROR_NOSUCHFILE;
2809 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2810 cm_buf_t *bp = buf_Find(dscp, &hzero);
2816 code = CM_ERROR_NOSUCHFILE;
2818 cm_ReleaseSCache(dscp);
2820 cm_FreeSpace(spacep);
2821 cm_ReleaseUser(userp);
2822 smb_SendTran2Error(vcp, p, opx, code);
2823 smb_FreeTran2Packet(outp);
2829 #endif /* SPECIAL_FOLDERS */
2831 cm_FreeSpace(spacep);
2834 /* now do namei and stat, and copy out the info */
2835 code = cm_NameI(cm_data.rootSCachep, pathp,
2836 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2839 cm_ReleaseUser(userp);
2840 smb_SendTran2Error(vcp, p, opx, code);
2841 smb_FreeTran2Packet(outp);
2846 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2847 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
2848 cm_ReleaseSCache(scp);
2849 cm_ReleaseUser(userp);
2850 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2851 code = CM_ERROR_PATH_NOT_COVERED;
2853 code = CM_ERROR_BADSHARENAME;
2854 smb_SendTran2Error(vcp, p, opx, code);
2855 smb_FreeTran2Packet(outp);
2858 #endif /* DFS_SUPPORT */
2860 lock_ObtainWrite(&scp->rw);
2862 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2863 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2864 if (code) goto done;
2866 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2868 lock_ConvertWToR(&scp->rw);
2870 /* now we have the status in the cache entry, and everything is locked.
2871 * Marshall the output data.
2873 /* for info level 108, figure out short name */
2874 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
2875 code = cm_GetShortName(pathp, userp, &req,
2876 tidPathp, scp->fid.vnode, shortName,
2882 qpi.u.QPfileAltNameInfo.fileNameLength = (len + 1) * 2;
2883 mbstowcs((unsigned short *)qpi.u.QPfileAltNameInfo.fileName, shortName, len + 1);
2887 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2888 len = (unsigned int)strlen(lastComp);
2889 qpi.u.QPfileNameInfo.fileNameLength = (len + 1) * 2;
2890 mbstowcs((unsigned short *)qpi.u.QPfileNameInfo.fileName, lastComp, len + 1);
2894 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2895 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2896 qpi.u.QPstandardInfo.creationDateTime = dosTime;
2897 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
2898 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
2899 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
2900 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
2901 attributes = smb_Attributes(scp);
2902 qpi.u.QPstandardInfo.attributes = attributes;
2903 qpi.u.QPstandardInfo.eaSize = 0;
2905 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2906 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2907 qpi.u.QPfileBasicInfo.creationTime = ft;
2908 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
2909 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
2910 qpi.u.QPfileBasicInfo.changeTime = ft;
2911 extAttributes = smb_ExtAttributes(scp);
2912 qpi.u.QPfileBasicInfo.attributes = extAttributes;
2913 qpi.u.QPfileBasicInfo.reserved = 0;
2915 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2916 smb_fid_t *fidp = smb_FindFIDByScache(vcp, scp);
2918 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
2919 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
2920 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
2921 qpi.u.QPfileStandardInfo.directory =
2922 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2923 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2924 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2925 qpi.u.QPfileStandardInfo.reserved = 0;
2928 lock_ReleaseRead(&scp->rw);
2930 lock_ObtainMutex(&fidp->mx);
2931 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
2932 lock_ReleaseMutex(&fidp->mx);
2933 smb_ReleaseFID(fidp);
2935 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
2937 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2938 qpi.u.QPfileEaInfo.eaSize = 0;
2940 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
2941 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2942 qpi.u.QPfileAllInfo.creationTime = ft;
2943 qpi.u.QPfileAllInfo.lastAccessTime = ft;
2944 qpi.u.QPfileAllInfo.lastWriteTime = ft;
2945 qpi.u.QPfileAllInfo.changeTime = ft;
2946 extAttributes = smb_ExtAttributes(scp);
2947 qpi.u.QPfileAllInfo.attributes = extAttributes;
2948 qpi.u.QPfileAllInfo.allocationSize = scp->length;
2949 qpi.u.QPfileAllInfo.endOfFile = scp->length;
2950 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
2951 qpi.u.QPfileAllInfo.deletePending = 0;
2952 qpi.u.QPfileAllInfo.directory =
2953 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2954 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2955 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2956 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
2957 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
2958 qpi.u.QPfileAllInfo.eaSize = 0;
2959 qpi.u.QPfileAllInfo.accessFlags = 0;
2960 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
2961 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
2962 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
2963 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
2964 qpi.u.QPfileAllInfo.mode = 0;
2965 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
2966 len = (unsigned int)strlen(lastComp);
2967 qpi.u.QPfileAllInfo.fileNameLength = (len + 1) * 2;
2968 mbstowcs((unsigned short *)qpi.u.QPfileAllInfo.fileName, lastComp, len + 1);
2971 /* send and free the packets */
2974 lock_ReleaseRead(&scp->rw);
2975 cm_ReleaseSCache(scp);
2976 cm_ReleaseUser(userp);
2978 memcpy(outp->datap, &qpi, responseSize);
2979 smb_SendTran2Packet(vcp, outp, opx);
2981 smb_SendTran2Error(vcp, p, opx, code);
2983 smb_FreeTran2Packet(outp);
2988 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2991 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2992 return CM_ERROR_BADOP;
2996 unsigned short infoLevel;
2998 smb_tran2Packet_t *outp;
2999 smb_tran2QPathInfo_t *spi;
3001 cm_scache_t *scp, *dscp;
3009 infoLevel = p->parmsp[0];
3010 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
3011 if (infoLevel != SMB_INFO_STANDARD &&
3012 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
3013 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
3014 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3015 p->opcode, infoLevel);
3016 smb_SendTran2Error(vcp, p, opx,
3017 infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3021 pathp = (char *)(&p->parmsp[3]);
3022 if (smb_StoreAnsiFilenames)
3023 OemToChar(pathp,pathp);
3024 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %s", infoLevel,
3025 osi_LogSaveString(smb_logp, pathp));
3027 userp = smb_GetTran2User(vcp, p);
3029 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3030 code = CM_ERROR_BADSMB;
3034 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3035 if (code == CM_ERROR_TIDIPC) {
3036 /* Attempt to use a TID allocated for IPC. The client
3037 * is probably looking for DCE RPC end points which we
3038 * don't support OR it could be looking to make a DFS
3041 osi_Log0(smb_logp, "Tran2Open received IPC TID");
3042 cm_ReleaseUser(userp);
3043 return CM_ERROR_NOSUCHPATH;
3047 * XXX Strange hack XXX
3049 * As of Patch 7 (13 January 98), we are having the following problem:
3050 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3051 * requests to look up "desktop.ini" in all the subdirectories.
3052 * This can cause zillions of timeouts looking up non-existent cells
3053 * and volumes, especially in the top-level directory.
3055 * We have not found any way to avoid this or work around it except
3056 * to explicitly ignore the requests for mount points that haven't
3057 * yet been evaluated and for directories that haven't yet been
3060 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3061 spacep = cm_GetSpace();
3062 smb_StripLastComponent(spacep->data, &lastComp, pathp);
3063 #ifndef SPECIAL_FOLDERS
3064 /* Make sure that lastComp is not NULL */
3066 if (stricmp(lastComp, "\\desktop.ini") == 0) {
3067 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3071 userp, tidPathp, &req, &dscp);
3074 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3075 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
3076 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3077 code = CM_ERROR_PATH_NOT_COVERED;
3079 code = CM_ERROR_BADSHARENAME;
3081 #endif /* DFS_SUPPORT */
3082 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3083 code = CM_ERROR_NOSUCHFILE;
3084 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3085 cm_buf_t *bp = buf_Find(dscp, &hzero);
3091 code = CM_ERROR_NOSUCHFILE;
3093 cm_ReleaseSCache(dscp);
3095 cm_FreeSpace(spacep);
3096 cm_ReleaseUser(userp);
3097 smb_SendTran2Error(vcp, p, opx, code);
3103 #endif /* SPECIAL_FOLDERS */
3105 cm_FreeSpace(spacep);
3108 /* now do namei and stat, and copy out the info */
3109 code = cm_NameI(cm_data.rootSCachep, pathp,
3110 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3112 cm_ReleaseUser(userp);
3113 smb_SendTran2Error(vcp, p, opx, code);
3117 fidp = smb_FindFIDByScache(vcp, scp);
3119 cm_ReleaseSCache(scp);
3120 cm_ReleaseUser(userp);
3121 smb_SendTran2Error(vcp, p, opx, code);
3125 lock_ObtainMutex(&fidp->mx);
3126 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
3127 lock_ReleaseMutex(&fidp->mx);
3128 cm_ReleaseSCache(scp);
3129 smb_ReleaseFID(fidp);
3130 cm_ReleaseUser(userp);
3131 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3134 lock_ReleaseMutex(&fidp->mx);
3136 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3138 outp->totalParms = 2;
3139 outp->totalData = 0;
3141 spi = (smb_tran2QPathInfo_t *)p->datap;
3142 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3145 /* lock the vnode with a callback; we need the current status
3146 * to determine what the new status is, in some cases.
3148 lock_ObtainWrite(&scp->rw);
3149 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3150 CM_SCACHESYNC_GETSTATUS
3151 | CM_SCACHESYNC_NEEDCALLBACK);
3153 lock_ReleaseWrite(&scp->rw);
3156 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3158 lock_ReleaseWrite(&scp->rw);
3159 lock_ObtainMutex(&fidp->mx);
3160 lock_ObtainRead(&scp->rw);
3162 /* prepare for setattr call */
3163 attr.mask = CM_ATTRMASK_LENGTH;
3164 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3165 attr.length.HighPart = 0;
3167 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3168 smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3169 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3170 fidp->flags |= SMB_FID_MTIMESETDONE;
3173 if (spi->u.QPstandardInfo.attributes != 0) {
3174 if ((scp->unixModeBits & 0222)
3175 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3176 /* make a writable file read-only */
3177 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3178 attr.unixModeBits = scp->unixModeBits & ~0222;
3180 else if ((scp->unixModeBits & 0222) == 0
3181 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3182 /* make a read-only file writable */
3183 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3184 attr.unixModeBits = scp->unixModeBits | 0222;
3187 lock_ReleaseRead(&scp->rw);
3188 lock_ReleaseMutex(&fidp->mx);
3192 code = cm_SetAttr(scp, &attr, userp, &req);
3196 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3197 /* we don't support EAs */
3198 code = CM_ERROR_EAS_NOT_SUPPORTED;
3202 cm_ReleaseSCache(scp);
3203 cm_ReleaseUser(userp);
3204 smb_ReleaseFID(fidp);
3206 smb_SendTran2Packet(vcp, outp, opx);
3208 smb_SendTran2Error(vcp, p, opx, code);
3209 smb_FreeTran2Packet(outp);
3215 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3217 smb_tran2Packet_t *outp;
3219 unsigned long attributes;
3220 unsigned short infoLevel;
3227 smb_tran2QFileInfo_t qfi;
3235 fidp = smb_FindFID(vcp, fid, 0);
3238 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3242 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3243 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3244 smb_CloseFID(vcp, fidp, NULL, 0);
3245 smb_ReleaseFID(fidp);
3249 infoLevel = p->parmsp[1];
3250 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3251 responseSize = sizeof(qfi.u.QFbasicInfo);
3252 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3253 responseSize = sizeof(qfi.u.QFstandardInfo);
3254 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3255 responseSize = sizeof(qfi.u.QFeaInfo);
3256 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3257 responseSize = sizeof(qfi.u.QFfileNameInfo);
3259 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3260 p->opcode, infoLevel);
3261 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3262 smb_ReleaseFID(fidp);
3265 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3267 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3269 if (infoLevel > 0x100)
3270 outp->totalParms = 2;
3272 outp->totalParms = 0;
3273 outp->totalData = responseSize;
3275 userp = smb_GetTran2User(vcp, p);
3277 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3278 code = CM_ERROR_BADSMB;
3282 lock_ObtainMutex(&fidp->mx);
3283 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3285 osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3287 lock_ReleaseMutex(&fidp->mx);
3288 lock_ObtainWrite(&scp->rw);
3289 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3290 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3294 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3296 lock_ConvertWToR(&scp->rw);
3299 /* now we have the status in the cache entry, and everything is locked.
3300 * Marshall the output data.
3302 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3303 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3304 qfi.u.QFbasicInfo.creationTime = ft;
3305 qfi.u.QFbasicInfo.lastAccessTime = ft;
3306 qfi.u.QFbasicInfo.lastWriteTime = ft;
3307 qfi.u.QFbasicInfo.lastChangeTime = ft;
3308 attributes = smb_ExtAttributes(scp);
3309 qfi.u.QFbasicInfo.attributes = attributes;
3311 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3312 qfi.u.QFstandardInfo.allocationSize = scp->length;
3313 qfi.u.QFstandardInfo.endOfFile = scp->length;
3314 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3315 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3316 qfi.u.QFstandardInfo.directory =
3317 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3318 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3319 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3321 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3322 qfi.u.QFeaInfo.eaSize = 0;
3324 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3328 lock_ReleaseRead(&scp->rw);
3329 lock_ObtainMutex(&fidp->mx);
3330 lock_ObtainRead(&scp->rw);
3331 if (fidp->NTopen_wholepathp)
3332 name = fidp->NTopen_wholepathp;
3334 name = "\\"; /* probably can't happen */
3335 lock_ReleaseMutex(&fidp->mx);
3336 len = (unsigned long)strlen(name);
3337 outp->totalData = ((len+1)*2) + 4; /* this is actually what we want to return */
3338 qfi.u.QFfileNameInfo.fileNameLength = (len + 1) * 2;
3339 mbstowcs((unsigned short *)qfi.u.QFfileNameInfo.fileName, name, len + 1);
3342 /* send and free the packets */
3345 lock_ReleaseRead(&scp->rw);
3347 lock_ReleaseWrite(&scp->rw);
3348 cm_ReleaseSCache(scp);
3349 cm_ReleaseUser(userp);
3350 smb_ReleaseFID(fidp);
3352 memcpy(outp->datap, &qfi, responseSize);
3353 smb_SendTran2Packet(vcp, outp, opx);
3355 smb_SendTran2Error(vcp, p, opx, code);
3357 smb_FreeTran2Packet(outp);
3362 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3367 unsigned short infoLevel;
3368 smb_tran2Packet_t *outp;
3369 cm_user_t *userp = NULL;
3370 cm_scache_t *scp = NULL;
3376 fidp = smb_FindFID(vcp, fid, 0);
3379 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3383 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3384 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3385 smb_CloseFID(vcp, fidp, NULL, 0);
3386 smb_ReleaseFID(fidp);
3390 infoLevel = p->parmsp[1];
3391 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3392 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3393 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3394 p->opcode, infoLevel);
3395 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3396 smb_ReleaseFID(fidp);
3400 lock_ObtainMutex(&fidp->mx);
3401 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
3402 !(fidp->flags & SMB_FID_OPENDELETE)) {
3403 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3404 fidp, fidp->scp, fidp->flags);
3405 lock_ReleaseMutex(&fidp->mx);
3406 smb_ReleaseFID(fidp);
3407 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3410 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3411 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3412 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3413 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3414 fidp, fidp->scp, fidp->flags);
3415 lock_ReleaseMutex(&fidp->mx);
3416 smb_ReleaseFID(fidp);
3417 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3422 osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3424 lock_ReleaseMutex(&fidp->mx);
3426 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3428 outp->totalParms = 2;
3429 outp->totalData = 0;
3431 userp = smb_GetTran2User(vcp, p);
3433 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3434 code = CM_ERROR_BADSMB;
3438 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3440 unsigned int attribute;
3442 smb_tran2QFileInfo_t *sfi;
3444 sfi = (smb_tran2QFileInfo_t *)p->datap;
3446 /* lock the vnode with a callback; we need the current status
3447 * to determine what the new status is, in some cases.
3449 lock_ObtainWrite(&scp->rw);
3450 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3451 CM_SCACHESYNC_GETSTATUS
3452 | CM_SCACHESYNC_NEEDCALLBACK);
3454 lock_ReleaseWrite(&scp->rw);
3458 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3460 lock_ReleaseWrite(&scp->rw);
3461 lock_ObtainMutex(&fidp->mx);
3462 lock_ObtainRead(&scp->rw);
3464 /* prepare for setattr call */
3467 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3468 /* when called as result of move a b, lastMod is (-1, -1).
3469 * If the check for -1 is not present, timestamp
3470 * of the resulting file will be 1969 (-1)
3472 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3473 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3474 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3475 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3476 fidp->flags |= SMB_FID_MTIMESETDONE;
3479 attribute = sfi->u.QFbasicInfo.attributes;
3480 if (attribute != 0) {
3481 if ((scp->unixModeBits & 0222)
3482 && (attribute & SMB_ATTR_READONLY) != 0) {
3483 /* make a writable file read-only */
3484 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3485 attr.unixModeBits = scp->unixModeBits & ~0222;
3487 else if ((scp->unixModeBits & 0222) == 0
3488 && (attribute & SMB_ATTR_READONLY) == 0) {
3489 /* make a read-only file writable */
3490 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3491 attr.unixModeBits = scp->unixModeBits | 0222;
3494 lock_ReleaseRead(&scp->rw);
3495 lock_ReleaseMutex(&fidp->mx);
3499 code = cm_SetAttr(scp, &attr, userp, &req);
3503 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3504 int delflag = *((char *)(p->datap));
3505 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
3506 delflag, fidp, scp);
3507 if (*((char *)(p->datap))) { /* File is Deleted */
3508 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3511 lock_ObtainMutex(&fidp->mx);
3512 fidp->flags |= SMB_FID_DELONCLOSE;
3513 lock_ReleaseMutex(&fidp->mx);
3515 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
3521 lock_ObtainMutex(&fidp->mx);
3522 fidp->flags &= ~SMB_FID_DELONCLOSE;
3523 lock_ReleaseMutex(&fidp->mx);
3526 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3527 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3528 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3531 attr.mask = CM_ATTRMASK_LENGTH;
3532 attr.length.LowPart = size.LowPart;
3533 attr.length.HighPart = size.HighPart;
3534 code = cm_SetAttr(scp, &attr, userp, &req);
3538 cm_ReleaseSCache(scp);
3539 cm_ReleaseUser(userp);
3540 smb_ReleaseFID(fidp);
3542 smb_SendTran2Packet(vcp, outp, opx);
3544 smb_SendTran2Error(vcp, p, opx, code);
3545 smb_FreeTran2Packet(outp);
3551 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3553 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3554 return CM_ERROR_BADOP;
3558 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3560 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3561 return CM_ERROR_BADOP;
3565 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3567 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3568 return CM_ERROR_BADOP;
3572 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3574 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3575 return CM_ERROR_BADOP;
3579 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3581 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3582 return CM_ERROR_BADOP;
3586 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3588 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3589 return CM_ERROR_BADOP;
3592 struct smb_v2_referral {
3594 USHORT ReferralFlags;
3597 USHORT DfsPathOffset;
3598 USHORT DfsAlternativePathOffset;
3599 USHORT NetworkAddressOffset;
3603 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3605 /* This is a UNICODE only request (bit15 of Flags2) */
3606 /* The TID must be IPC$ */
3608 /* The documentation for the Flags response field is contradictory */
3610 /* Use Version 1 Referral Element Format */
3611 /* ServerType = 0; indicates the next server should be queried for the file */
3612 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3613 /* Node = UnicodeString of UNC path of the next share name */
3616 int maxReferralLevel = 0;
3617 char requestFileName[1024] = "";
3618 char referralPath[1024] = "";
3619 smb_tran2Packet_t *outp = 0;
3620 cm_user_t *userp = 0;
3621 cm_scache_t *scp = 0;
3622 cm_scache_t *dscp = 0;
3624 CPINFO CodePageInfo;
3625 int i, nbnLen, reqLen, refLen;
3630 maxReferralLevel = p->parmsp[0];
3632 GetCPInfo(CP_ACP, &CodePageInfo);
3633 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
3634 requestFileName, 1024, NULL, NULL);
3636 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
3637 maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3639 nbnLen = (int)strlen(cm_NetbiosName);
3640 reqLen = (int)strlen(requestFileName);
3642 if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
3643 !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3644 requestFileName[nbnLen+1] == '\\')
3648 if (!_strnicmp("all",&requestFileName[nbnLen+2],3) ||
3649 !_strnicmp("*.",&requestFileName[nbnLen+2],2))
3652 strcpy(referralPath, requestFileName);
3655 userp = smb_GetTran2User(vcp, p);
3657 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3658 code = CM_ERROR_BADSMB;
3663 * We have a requested path. Check to see if it is something
3666 * But be careful because the name that we might be searching
3667 * for might be a known name with the final character stripped
3670 code = cm_NameI(cm_data.rootSCachep, &requestFileName[nbnLen+2],
3671 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
3672 userp, NULL, &req, &scp);
3676 strcpy(referralPath, requestFileName);
3678 } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
3680 char pathName[1024];
3681 char *lastComponent;
3683 * we have a msdfs link somewhere in the path
3684 * we should figure out where in the path the link is.
3687 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%s]", requestFileName);
3689 strcpy(temp, &requestFileName[nbnLen+2]);
3693 cm_ReleaseSCache(dscp);
3697 cm_ReleaseSCache(scp);
3700 smb_StripLastComponent(pathName, &lastComponent, temp);
3702 code = cm_NameI(cm_data.rootSCachep, pathName,
3703 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3704 userp, NULL, &req, &dscp);
3706 code = cm_NameI(dscp, ++lastComponent,
3708 userp, NULL, &req, &scp);
3709 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK)
3712 } while (code == CM_ERROR_PATH_NOT_COVERED);
3714 /* scp should now be the DfsLink we are looking for */
3716 /* figure out how much of the input path was used */
3717 reqLen = (int)(nbnLen+2 + strlen(pathName) + 1 + strlen(lastComponent));
3719 strcpy(referralPath, &scp->mountPointStringp[strlen("msdfs:")]);
3720 refLen = (int)strlen(referralPath);
3724 char shareName[MAX_PATH + 1];
3726 /* we may have a sharename that is a volume reference */
3728 for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
3734 if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
3735 code = cm_NameI(cm_data.rootSCachep, "",
3736 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
3737 userp, p, &req, &scp);
3742 strcpy(referralPath, requestFileName);
3752 struct smb_v2_referral * v2ref;
3753 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (refLen + 8));
3755 sp = (USHORT *)outp->datap;
3757 sp[idx++] = reqLen; /* path consumed */
3758 sp[idx++] = 1; /* number of referrals */
3759 sp[idx++] = 0x03; /* flags */
3760 #ifdef DFS_VERSION_1
3761 sp[idx++] = 1; /* Version Number */
3762 sp[idx++] = refLen + 4; /* Referral Size */
3763 sp[idx++] = 1; /* Type = SMB Server */
3764 sp[idx++] = 0; /* Do not strip path consumed */
3765 for ( i=0;i<=refLen; i++ )
3766 sp[i+idx] = referralPath[i];
3767 #else /* DFS_VERSION_2 */
3768 sp[idx++] = 2; /* Version Number */
3769 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3770 idx += (sizeof(struct smb_v2_referral) / 2);
3771 v2ref = (struct smb_v2_referral *) &sp[5];
3772 v2ref->ServerType = 1; /* SMB Server */
3773 v2ref->ReferralFlags = 0x03;
3774 v2ref->Proximity = 0; /* closest */
3775 v2ref->TimeToLive = 3600; /* seconds */
3776 v2ref->DfsPathOffset = idx * 2;
3777 v2ref->DfsAlternativePathOffset = idx * 2;
3778 v2ref->NetworkAddressOffset = 0;
3779 for ( i=0;i<=refLen; i++ )
3780 sp[i+idx] = referralPath[i];
3784 code = CM_ERROR_NOSUCHPATH;
3789 cm_ReleaseSCache(dscp);
3791 cm_ReleaseSCache(scp);
3793 cm_ReleaseUser(userp);
3795 smb_SendTran2Packet(vcp, outp, op);
3797 smb_SendTran2Error(vcp, p, op, code);
3799 smb_FreeTran2Packet(outp);
3802 #else /* DFS_SUPPORT */
3803 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3804 return CM_ERROR_NOSUCHDEVICE;
3805 #endif /* DFS_SUPPORT */
3809 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3811 /* This is a UNICODE only request (bit15 of Flags2) */
3813 /* There is nothing we can do about this operation. The client is going to
3814 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3815 * Unfortunately, there is really nothing we can do about it other then log it
3816 * somewhere. Even then I don't think there is anything for us to do.
3817 * So let's return an error value.
3820 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3821 return CM_ERROR_BADOP;
3825 smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
3826 char * tidPathp, char * relPathp,
3827 int infoLevel, cm_user_t *userp,
3832 cm_scache_t *targetScp; /* target if scp is a symlink */
3837 unsigned short attr;
3838 unsigned long lattr;
3839 smb_dirListPatch_t *patchp;
3840 smb_dirListPatch_t *npatchp;
3842 afs_int32 mustFake = 0;
3843 char path[AFSPATHMAX];
3845 code = cm_FindACLCache(dscp, userp, &rights);
3846 if (code == 0 && !(rights & PRSFS_READ))
3848 else if (code == -1) {
3849 lock_ObtainWrite(&dscp->rw);
3850 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
3851 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3852 lock_ReleaseWrite(&dscp->rw);
3853 if (code == CM_ERROR_NOACCESS) {
3861 for(patchp = *dirPatchespp; patchp; patchp =
3862 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3863 snprintf(path, AFSPATHMAX, "%s\\%s", relPathp ? relPathp : "", patchp->dep->name);
3864 reqp->relPathp = path;
3865 reqp->tidPathp = tidPathp;
3867 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3868 reqp->relPathp = reqp->tidPathp = NULL;
3872 lock_ObtainWrite(&scp->rw);
3874 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3875 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3876 if (mustFake || code) {
3877 lock_ReleaseWrite(&scp->rw);
3879 dptr = patchp->dptr;
3881 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3882 errors in the client. */
3883 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3884 /* 1969-12-31 23:59:59 +00 */
3885 ft.dwHighDateTime = 0x19DB200;
3886 ft.dwLowDateTime = 0x5BB78980;
3888 /* copy to Creation Time */
3889 *((FILETIME *)dptr) = ft;
3892 /* copy to Last Access Time */
3893 *((FILETIME *)dptr) = ft;
3896 /* copy to Last Write Time */
3897 *((FILETIME *)dptr) = ft;
3900 /* copy to Change Time */
3901 *((FILETIME *)dptr) = ft;
3904 switch (scp->fileType) {
3905 case CM_SCACHETYPE_DIRECTORY:
3906 case CM_SCACHETYPE_MOUNTPOINT:
3907 case CM_SCACHETYPE_SYMLINK:
3908 case CM_SCACHETYPE_INVALID:
3909 *((u_long *)dptr) = SMB_ATTR_DIRECTORY;
3912 /* if we get here we either have a normal file
3913 * or we have a file for which we have never
3914 * received status info. In this case, we can
3915 * check the even/odd value of the entry's vnode.
3916 * even means it is to be treated as a directory
3917 * and odd means it is to be treated as a file.
3919 if (mustFake && (scp->fid.vnode & 0x1))
3920 *((u_long *)dptr) = SMB_ATTR_DIRECTORY;
3922 *((u_long *)dptr) = SMB_ATTR_NORMAL;
3925 /* merge in hidden attribute */
3926 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3927 *((u_long *)dptr) |= SMB_ATTR_HIDDEN;
3931 /* 1969-12-31 23:59:58 +00*/
3932 dosTime = 0xEBBFBF7D;
3934 /* and copy out date */
3935 shortTemp = (dosTime>>16) & 0xffff;
3936 *((u_short *)dptr) = shortTemp;
3939 /* copy out creation time */
3940 shortTemp = dosTime & 0xffff;
3941 *((u_short *)dptr) = shortTemp;
3944 /* and copy out date */
3945 shortTemp = (dosTime>>16) & 0xffff;
3946 *((u_short *)dptr) = shortTemp;
3949 /* copy out access time */
3950 shortTemp = dosTime & 0xffff;
3951 *((u_short *)dptr) = shortTemp;
3954 /* and copy out date */
3955 shortTemp = (dosTime>>16) & 0xffff;
3956 *((u_short *)dptr) = shortTemp;
3959 /* copy out mod time */
3960 shortTemp = dosTime & 0xffff;
3961 *((u_short *)dptr) = shortTemp;
3964 /* set the attribute */
3965 switch (scp->fileType) {
3966 case CM_SCACHETYPE_DIRECTORY:
3967 case CM_SCACHETYPE_MOUNTPOINT:
3968 case CM_SCACHETYPE_SYMLINK:
3969 case CM_SCACHETYPE_INVALID:
3970 attr = SMB_ATTR_DIRECTORY;
3972 attr = SMB_ATTR_NORMAL;
3974 /* merge in hidden (dot file) attribute */
3975 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3976 attr |= SMB_ATTR_HIDDEN;
3978 *dptr++ = attr & 0xff;
3979 *dptr++ = (attr >> 8) & 0xff;
3982 cm_ReleaseSCache(scp);
3986 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3988 /* now watch for a symlink */
3990 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3991 lock_ReleaseWrite(&scp->rw);
3992 snprintf(path, AFSPATHMAX, "%s\\%s", relPathp ? relPathp : "", patchp->dep->name);
3993 reqp->relPathp = path;
3994 reqp->tidPathp = tidPathp;
3995 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3996 reqp->relPathp = reqp->tidPathp = NULL;
3998 /* we have a more accurate file to use (the
3999 * target of the symbolic link). Otherwise,
4000 * we'll just use the symlink anyway.
4002 osi_Log2(smb_logp, "symlink vp %x to vp %x",
4004 cm_ReleaseSCache(scp);
4007 lock_ObtainWrite(&scp->rw);
4010 lock_ConvertWToR(&scp->rw);
4012 dptr = patchp->dptr;
4014 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4016 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4018 /* copy to Creation Time */
4019 *((FILETIME *)dptr) = ft;
4022 /* copy to Last Access Time */
4023 *((FILETIME *)dptr) = ft;
4026 /* copy to Last Write Time */
4027 *((FILETIME *)dptr) = ft;
4030 /* copy to Change Time */
4031 *((FILETIME *)dptr) = ft;
4034 /* Use length for both file length and alloc length */
4035 *((LARGE_INTEGER *)dptr) = scp->length;
4037 *((LARGE_INTEGER *)dptr) = scp->length;
4040 /* Copy attributes */
4041 lattr = smb_ExtAttributes(scp);
4042 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK ||
4043 code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4044 if (lattr == SMB_ATTR_NORMAL)
4045 lattr = SMB_ATTR_DIRECTORY;
4047 lattr |= SMB_ATTR_DIRECTORY;
4049 /* merge in hidden (dot file) attribute */
4050 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4051 if (lattr == SMB_ATTR_NORMAL)
4052 lattr = SMB_ATTR_HIDDEN;
4054 lattr |= SMB_ATTR_HIDDEN;
4056 *((u_long *)dptr) = lattr;
4060 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4062 /* and copy out date */
4063 shortTemp = (dosTime>>16) & 0xffff;
4064 *((u_short *)dptr) = shortTemp;
4067 /* copy out creation time */
4068 shortTemp = dosTime & 0xffff;
4069 *((u_short *)dptr) = shortTemp;
4072 /* and copy out date */
4073 shortTemp = (dosTime>>16) & 0xffff;
4074 *((u_short *)dptr) = shortTemp;
4077 /* copy out access time */
4078 shortTemp = dosTime & 0xffff;
4079 *((u_short *)dptr) = shortTemp;
4082 /* and copy out date */
4083 shortTemp = (dosTime>>16) & 0xffff;
4084 *((u_short *)dptr) = shortTemp;
4087 /* copy out mod time */
4088 shortTemp = dosTime & 0xffff;
4089 *((u_short *)dptr) = shortTemp;
4092 /* copy out file length and alloc length,
4093 * using the same for both
4095 *((u_long *)dptr) = scp->length.LowPart;
4097 *((u_long *)dptr) = scp->length.LowPart;
4100 /* finally copy out attributes as short */
4101 attr = smb_Attributes(scp);
4102 /* merge in hidden (dot file) attribute */
4103 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4104 if (lattr == SMB_ATTR_NORMAL)
4105 lattr = SMB_ATTR_HIDDEN;
4107 lattr |= SMB_ATTR_HIDDEN;
4109 *dptr++ = attr & 0xff;
4110 *dptr++ = (attr >> 8) & 0xff;
4113 lock_ReleaseRead(&scp->rw);
4114 cm_ReleaseSCache(scp);
4117 /* now free the patches */
4118 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4119 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4123 /* and mark the list as empty */
4124 *dirPatchespp = NULL;
4129 // char table for case insensitive comparison
4130 char mapCaseTable[256];
4132 VOID initUpperCaseTable(VOID)
4135 for (i = 0; i < 256; ++i)
4136 mapCaseTable[i] = toupper(i);
4137 // make '"' match '.'
4138 mapCaseTable[(int)'"'] = toupper('.');
4139 // make '<' match '*'
4140 mapCaseTable[(int)'<'] = toupper('*');
4141 // make '>' match '?'
4142 mapCaseTable[(int)'>'] = toupper('?');
4145 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
4147 // Note : this procedure works recursively calling itself.
4149 // PSZ pattern : string containing metacharacters.
4150 // PSZ name : file name to be compared with 'pattern'.
4152 // BOOL : TRUE/FALSE (match/mistmatch)
4155 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
4157 PSZ pename; // points to the last 'name' character
4159 pename = name + strlen(name) - 1;
4170 if (*pattern == '\0')
4172 for (p = pename; p >= name; --p) {
4173 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
4174 !casefold && (*p == *pattern)) &&
4175 szWildCardMatchFileName(pattern + 1, p + 1, casefold))
4180 if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
4181 (!casefold && *name != *pattern))
4188 /* if all we have left are wildcards, then we match */
4189 for (;*pattern; pattern++) {
4190 if (*pattern != '*' && *pattern != '?')
4196 /* do a case-folding search of the star name mask with the name in namep.
4197 * Return 1 if we match, otherwise 0.
4199 int smb_V3MatchMask(char *namep, char *maskp, int flags)
4202 int i, j, star, qmark, casefold, retval;
4204 /* make sure we only match 8.3 names, if requested */
4205 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
4208 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
4210 /* optimize the pattern:
4211 * if there is a mixture of '?' and '*',
4212 * for example the sequence "*?*?*?*"
4213 * must be turned into the form "*"
4215 newmask = (char *)malloc(strlen(maskp)+1);
4216 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
4217 switch ( maskp[i] ) {
4229 } else if ( qmark ) {
4233 newmask[j++] = maskp[i];
4240 } else if ( qmark ) {
4244 newmask[j++] = '\0';
4246 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
4253 /* smb_ReceiveTran2SearchDir implements both
4254 * Tran2_Find_First and Tran2_Find_Next
4256 #define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
4257 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
4258 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
4259 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
4260 #define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
4262 /* this is an optimized handler for T2SearchDir that handles the case
4263 where there are no wildcards in the search path. I.e. an
4264 application is using FindFirst(Ex) to get information about a
4265 single file or directory. It will attempt to do a single lookup.
4266 If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4267 the usual mechanism.
4269 This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4271 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4275 long code = 0, code2 = 0;
4278 smb_dirListPatch_t *dirListPatchesp;
4279 smb_dirListPatch_t *curPatchp;
4280 long orbytes; /* # of bytes in this output record */
4281 long ohbytes; /* # of bytes, except file name */
4282 long onbytes; /* # of bytes in name, incl. term. null */
4283 cm_scache_t *scp = NULL;
4284 cm_scache_t *targetscp = NULL;
4285 cm_user_t *userp = NULL;
4286 char *op; /* output data ptr */
4287 char *origOp; /* original value of op */
4288 cm_space_t *spacep; /* for pathname buffer */
4289 long maxReturnData; /* max # of return data */
4290 long maxReturnParms; /* max # of return parms */
4291 long bytesInBuffer; /* # data bytes in the output buffer */
4292 char *maskp; /* mask part of path */
4296 smb_tran2Packet_t *outp; /* response packet */
4299 char shortName[13]; /* 8.3 name if needed */
4302 cm_dirEntry_t * dep = NULL;
4309 osi_assertx(p->opcode == 1, "invalid opcode");
4311 /* find first; obtain basic parameters from request */
4313 /* note that since we are going to failover to regular
4314 * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4315 * modify any of the input parameters here. */
4316 attribute = p->parmsp[0];
4317 maxCount = p->parmsp[1];
4318 infoLevel = p->parmsp[3];
4319 searchFlags = p->parmsp[2];
4320 pathp = ((char *) p->parmsp) + 12; /* points to path */
4322 maskp = strrchr(pathp, '\\');
4326 maskp++; /* skip over backslash */
4327 /* track if this is likely to match a lot of entries */
4329 osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%s], mask[%s]",
4330 osi_LogSaveString(smb_logp, pathp),
4331 osi_LogSaveString(smb_logp, maskp));
4333 switch ( infoLevel ) {
4334 case SMB_INFO_STANDARD:
4337 case SMB_INFO_QUERY_EA_SIZE:
4338 s = "InfoQueryEaSize";
4340 case SMB_INFO_QUERY_EAS_FROM_LIST:
4341 s = "InfoQueryEasFromList";
4343 case SMB_FIND_FILE_DIRECTORY_INFO:
4344 s = "FindFileDirectoryInfo";
4346 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4347 s = "FindFileFullDirectoryInfo";
4349 case SMB_FIND_FILE_NAMES_INFO:
4350 s = "FindFileNamesInfo";
4352 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4353 s = "FindFileBothDirectoryInfo";
4356 s = "unknownInfoLevel";
4359 osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
4362 "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4363 attribute, infoLevel, maxCount, searchFlags);
4365 if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4366 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4367 return CM_ERROR_INVAL;
4370 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4371 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4373 dirListPatchesp = NULL;
4375 maxReturnData = p->maxReturnData;
4376 maxReturnParms = 10; /* return params for findfirst, which
4377 is the only one we handle.*/
4379 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4380 if (maxReturnData > 6000)
4381 maxReturnData = 6000;
4382 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4384 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4387 osi_Log2(smb_logp, "T2SDSingle search dir count %d [%s]",
4388 maxCount, osi_LogSaveString(smb_logp, pathp));
4390 /* bail out if request looks bad */
4392 smb_FreeTran2Packet(outp);
4393 return CM_ERROR_BADSMB;
4396 userp = smb_GetTran2User(vcp, p);
4398 osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
4399 smb_FreeTran2Packet(outp);
4400 return CM_ERROR_BADSMB;
4403 /* try to get the vnode for the path name next */
4404 spacep = cm_GetSpace();
4405 smb_StripLastComponent(spacep->data, NULL, pathp);
4406 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4408 cm_ReleaseUser(userp);
4409 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4410 smb_FreeTran2Packet(outp);
4414 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4415 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4416 userp, tidPathp, &req, &scp);
4417 cm_FreeSpace(spacep);
4420 cm_ReleaseUser(userp);
4421 smb_SendTran2Error(vcp, p, opx, code);
4422 smb_FreeTran2Packet(outp);
4426 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4427 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4428 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
4429 cm_ReleaseSCache(scp);
4430 cm_ReleaseUser(userp);
4431 if ( WANTS_DFS_PATHNAMES(p) || pnc )
4432 code = CM_ERROR_PATH_NOT_COVERED;
4434 code = CM_ERROR_BADSHARENAME;
4435 smb_SendTran2Error(vcp, p, opx, code);
4436 smb_FreeTran2Packet(outp);
4439 #endif /* DFS_SUPPORT */
4440 osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
4442 /* now do a single case sensitive lookup for the file in question */
4443 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
4445 /* if a case sensitive match failed, we try a case insensitive one
4447 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
4448 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
4451 if (code == 0 && targetscp->fid.vnode == 0) {
4452 cm_ReleaseSCache(targetscp);
4453 code = CM_ERROR_NOSUCHFILE;
4457 /* if we can't find the directory entry, this block will
4458 return CM_ERROR_NOSUCHFILE, which we will pass on to
4459 smb_ReceiveTran2SearchDir(). */
4460 cm_ReleaseSCache(scp);
4461 cm_ReleaseUser(userp);
4462 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4463 smb_SendTran2Error(vcp, p, opx, code);
4466 smb_FreeTran2Packet(outp);
4470 /* now that we have the target in sight, we proceed with filling
4471 up the return data. */
4473 op = origOp = outp->datap;
4476 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4477 /* skip over resume key */
4481 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4482 && targetscp->fid.vnode != 0
4483 && !cm_Is8Dot3(maskp)) {
4486 dfid.vnode = htonl(targetscp->fid.vnode);
4487 dfid.unique = htonl(targetscp->fid.unique);
4489 cm_Gen8Dot3NameInt(maskp, &dfid, shortName, &shortNameEnd);
4495 osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %s (%s)",
4496 htonl(targetscp->fid.vnode),
4497 htonl(targetscp->fid.unique),
4498 osi_LogSaveString(smb_logp, pathp),
4499 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4501 /* Eliminate entries that don't match requested attributes */
4502 if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
4503 smb_IsDotFile(maskp)) {
4505 code = CM_ERROR_NOSUCHFILE;
4506 osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
4511 if (!(attribute & SMB_ATTR_DIRECTORY) &&
4512 (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
4513 targetscp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4514 targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
4515 targetscp->fileType == CM_SCACHETYPE_INVALID)) {
4517 code = CM_ERROR_NOSUCHFILE;
4518 osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
4523 /* Check if the name will fit */
4524 if (infoLevel < 0x101)
4525 ohbytes = 23; /* pre-NT */
4526 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4527 ohbytes = 12; /* NT names only */
4529 ohbytes = 64; /* NT */
4531 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
4532 ohbytes += 26; /* Short name & length */
4534 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4535 ohbytes += 4; /* if resume key required */
4538 if (infoLevel != SMB_INFO_STANDARD
4539 && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
4540 && infoLevel != SMB_FIND_FILE_NAMES_INFO)
4541 ohbytes += 4; /* EASIZE */
4543 /* add header to name & term. null */
4544 onbytes = (int)strlen(maskp);
4545 orbytes = ohbytes + onbytes + 1;
4547 /* now, we round up the record to a 4 byte alignment, and we make
4548 * sure that we have enough room here for even the aligned version
4549 * (so we don't have to worry about an * overflow when we pad
4550 * things out below). That's the reason for the alignment
4553 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4554 align = (4 - (orbytes & 3)) & 3;
4558 if (orbytes + align > maxReturnData) {
4560 /* even though this request is unlikely to succeed with a
4561 failover, we do it anyway. */
4562 code = CM_ERROR_NOSUCHFILE;
4563 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4568 /* this is one of the entries to use: it is not deleted and it
4569 * matches the star pattern we're looking for. Put out the name,
4570 * preceded by its length.
4572 /* First zero everything else */
4573 memset(origOp, 0, ohbytes);
4575 if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
4576 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4577 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4578 *((u_long *)(op + 8)) = onbytes;
4580 *((u_long *)(op + 60)) = onbytes;
4581 strcpy(origOp+ohbytes, maskp);
4582 if (smb_StoreAnsiFilenames)
4583 CharToOem(origOp+ohbytes, origOp+ohbytes);
4585 /* Short name if requested and needed */
4586 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4587 if (NeedShortName) {
4588 strcpy(op + 70, shortName);
4589 if (smb_StoreAnsiFilenames)
4590 CharToOem(op + 70, op + 70);
4591 *(op + 68) = (char)(shortNameEnd - shortName);
4595 /* NextEntryOffset and FileIndex */
4596 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4597 int entryOffset = orbytes + align;
4598 *((u_long *)op) = 0;
4599 *((u_long *)(op+4)) = 0;
4602 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4603 curPatchp = malloc(sizeof(*curPatchp));
4604 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4606 curPatchp->dptr = op;
4607 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4608 curPatchp->dptr += 8;
4610 if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
4611 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4613 curPatchp->flags = 0;
4616 cm_SetFid(&curPatchp->fid, targetscp->fid.cell, targetscp->fid.volume, targetscp->fid.vnode, targetscp->fid.unique);
4619 dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+strlen(maskp));
4620 strcpy(dep->name, maskp);
4621 dep->fid.vnode = targetscp->fid.vnode;
4622 dep->fid.unique = targetscp->fid.unique;
4623 curPatchp->dep = dep;
4626 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4627 /* put out resume key */
4628 *((u_long *)origOp) = 0;
4631 /* Adjust byte ptr and count */
4632 origOp += orbytes; /* skip entire record */
4633 bytesInBuffer += orbytes;
4635 /* and pad the record out */
4636 while (--align >= 0) {
4641 /* apply the patches */
4642 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->data, infoLevel, userp, &req);
4644 outp->parmsp[0] = 0;
4645 outp->parmsp[1] = 1; /* number of names returned */
4646 outp->parmsp[2] = 1; /* end of search */
4647 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4648 outp->parmsp[4] = 0;
4650 outp->totalParms = 10; /* in bytes */
4652 outp->totalData = bytesInBuffer;
4654 osi_Log0(smb_logp, "T2SDSingle done.");
4656 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4658 smb_SendTran2Error(vcp, p, opx, code);
4660 smb_SendTran2Packet(vcp, outp, opx);
4665 smb_FreeTran2Packet(outp);
4669 cm_ReleaseSCache(scp);
4670 cm_ReleaseSCache(targetscp);
4671 cm_ReleaseUser(userp);
4677 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4682 long code = 0, code2 = 0;
4684 cm_dirEntry_t *dep = 0;
4686 smb_dirListPatch_t *dirListPatchesp = 0;
4687 smb_dirListPatch_t *curPatchp = 0;
4690 long orbytes; /* # of bytes in this output record */
4691 long ohbytes; /* # of bytes, except file name */
4692 long onbytes; /* # of bytes in name, incl. term. null */
4693 osi_hyper_t dirLength;
4694 osi_hyper_t bufferOffset;
4695 osi_hyper_t curOffset;
4697 smb_dirSearch_t *dsp;
4701 cm_pageHeader_t *pageHeaderp;
4702 cm_user_t *userp = NULL;
4705 long nextEntryCookie;
4706 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4707 char *op; /* output data ptr */
4708 char *origOp; /* original value of op */
4709 cm_space_t *spacep; /* for pathname buffer */
4710 long maxReturnData; /* max # of return data */
4711 long maxReturnParms; /* max # of return parms */
4712 long bytesInBuffer; /* # data bytes in the output buffer */
4714 char *maskp; /* mask part of path */
4718 smb_tran2Packet_t *outp; /* response packet */
4721 char shortName[13]; /* 8.3 name if needed */
4733 if (p->opcode == 1) {
4734 /* find first; obtain basic parameters from request */
4735 attribute = p->parmsp[0];
4736 maxCount = p->parmsp[1];
4737 infoLevel = p->parmsp[3];
4738 searchFlags = p->parmsp[2];
4739 pathp = ((char *) p->parmsp) + 12; /* points to path */
4740 if (smb_StoreAnsiFilenames)
4741 OemToChar(pathp,pathp);
4743 maskp = strrchr(pathp, '\\');
4747 maskp++; /* skip over backslash */
4749 /* track if this is likely to match a lot of entries */
4750 starPattern = smb_V3IsStarMask(maskp);
4752 #ifndef NOFINDFIRSTOPTIMIZE
4754 /* if this is for a single directory or file, we let the
4755 optimized routine handle it. The only error it
4756 returns is CM_ERROR_NOSUCHFILE. The */
4757 code = smb_T2SearchDirSingle(vcp, p, opx);
4759 /* we only failover if we see a CM_ERROR_NOSUCHFILE */
4760 if (code != CM_ERROR_NOSUCHFILE) {
4762 /* unless we are using the BPlusTree */
4763 if (code == CM_ERROR_BPLUS_NOMATCH)
4764 code = CM_ERROR_NOSUCHFILE;
4765 #endif /* USE_BPLUS */
4772 dsp = smb_NewDirSearch(1);
4773 dsp->attribute = attribute;
4774 strcpy(dsp->mask, maskp); /* and save mask */
4777 osi_assertx(p->opcode == 2, "invalid opcode");
4778 /* find next; obtain basic parameters from request or open dir file */
4779 dsp = smb_FindDirSearch(p->parmsp[0]);
4780 maxCount = p->parmsp[1];
4781 infoLevel = p->parmsp[2];
4782 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4783 searchFlags = p->parmsp[5];
4785 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4786 p->parmsp[0], nextCookie);
4787 return CM_ERROR_BADFD;
4789 attribute = dsp->attribute;
4792 starPattern = 1; /* assume, since required a Find Next */
4795 switch ( infoLevel ) {
4796 case SMB_INFO_STANDARD:
4799 case SMB_INFO_QUERY_EA_SIZE:
4800 s = "InfoQueryEaSize";
4802 case SMB_INFO_QUERY_EAS_FROM_LIST:
4803 s = "InfoQueryEasFromList";
4805 case SMB_FIND_FILE_DIRECTORY_INFO:
4806 s = "FindFileDirectoryInfo";
4808 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4809 s = "FindFileFullDirectoryInfo";
4811 case SMB_FIND_FILE_NAMES_INFO:
4812 s = "FindFileNamesInfo";
4814 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4815 s = "FindFileBothDirectoryInfo";
4818 s = "unknownInfoLevel";
4821 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
4824 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4825 attribute, infoLevel, maxCount, searchFlags);
4827 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
4828 p->opcode, dsp->cookie, nextCookie);
4830 if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4831 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4832 smb_ReleaseDirSearch(dsp);
4833 return CM_ERROR_INVAL;
4836 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4837 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4839 dirListPatchesp = NULL;
4841 maxReturnData = p->maxReturnData;
4842 if (p->opcode == 1) /* find first */
4843 maxReturnParms = 10; /* bytes */
4845 maxReturnParms = 8; /* bytes */
4847 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4848 if (maxReturnData > 6000)
4849 maxReturnData = 6000;
4850 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4852 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4855 osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
4856 maxCount, osi_LogSaveString(smb_logp, pathp));
4858 /* bail out if request looks bad */
4859 if (p->opcode == 1 && !pathp) {
4860 smb_ReleaseDirSearch(dsp);
4861 smb_FreeTran2Packet(outp);
4862 return CM_ERROR_BADSMB;
4865 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
4866 dsp->cookie, nextCookie, attribute);
4868 userp = smb_GetTran2User(vcp, p);
4870 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
4871 smb_ReleaseDirSearch(dsp);
4872 smb_FreeTran2Packet(outp);
4873 return CM_ERROR_BADSMB;
4876 /* try to get the vnode for the path name next */
4877 lock_ObtainMutex(&dsp->mx);
4880 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4884 spacep = cm_GetSpace();
4885 smb_StripLastComponent(spacep->data, NULL, pathp);
4886 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4888 cm_ReleaseUser(userp);
4889 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4890 smb_FreeTran2Packet(outp);
4891 lock_ReleaseMutex(&dsp->mx);
4892 smb_DeleteDirSearch(dsp);
4893 smb_ReleaseDirSearch(dsp);
4897 strcpy(dsp->tidPath, tidPathp ? tidPathp : "/");
4898 strcpy(dsp->relPath, spacep->data);
4900 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4901 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4902 userp, tidPathp, &req, &scp);
4903 cm_FreeSpace(spacep);
4906 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4907 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4908 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
4909 cm_ReleaseSCache(scp);
4910 cm_ReleaseUser(userp);
4911 if ( WANTS_DFS_PATHNAMES(p) || pnc )
4912 code = CM_ERROR_PATH_NOT_COVERED;
4914 code = CM_ERROR_BADSHARENAME;
4915 smb_SendTran2Error(vcp, p, opx, code);
4916 smb_FreeTran2Packet(outp);
4917 lock_ReleaseMutex(&dsp->mx);
4918 smb_DeleteDirSearch(dsp);
4919 smb_ReleaseDirSearch(dsp);
4922 #endif /* DFS_SUPPORT */
4924 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4925 /* we need one hold for the entry we just stored into,
4926 * and one for our own processing. When we're done
4927 * with this function, we'll drop the one for our own
4928 * processing. We held it once from the namei call,
4929 * and so we do another hold now.
4932 lock_ObtainWrite(&scp->rw);
4933 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
4934 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4935 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4936 dsp->flags |= SMB_DIRSEARCH_BULKST;
4938 lock_ReleaseWrite(&scp->rw);
4941 lock_ReleaseMutex(&dsp->mx);
4943 cm_ReleaseUser(userp);
4944 smb_FreeTran2Packet(outp);
4945 smb_DeleteDirSearch(dsp);
4946 smb_ReleaseDirSearch(dsp);
4950 /* get the directory size */
4951 lock_ObtainWrite(&scp->rw);
4952 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4953 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4955 lock_ReleaseWrite(&scp->rw);
4956 cm_ReleaseSCache(scp);
4957 cm_ReleaseUser(userp);
4958 smb_FreeTran2Packet(outp);
4959 smb_DeleteDirSearch(dsp);
4960 smb_ReleaseDirSearch(dsp);
4964 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4967 dirLength = scp->length;
4969 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4970 curOffset.HighPart = 0;
4971 curOffset.LowPart = nextCookie;
4972 origOp = outp->datap;
4980 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4981 /* skip over resume key */
4984 /* make sure that curOffset.LowPart doesn't point to the first
4985 * 32 bytes in the 2nd through last dir page, and that it doesn't
4986 * point at the first 13 32-byte chunks in the first dir page,
4987 * since those are dir and page headers, and don't contain useful
4990 temp = curOffset.LowPart & (2048-1);
4991 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4992 /* we're in the first page */
4993 if (temp < 13*32) temp = 13*32;
4996 /* we're in a later dir page */
4997 if (temp < 32) temp = 32;
5000 /* make sure the low order 5 bits are zero */
5003 /* now put temp bits back ito curOffset.LowPart */
5004 curOffset.LowPart &= ~(2048-1);
5005 curOffset.LowPart |= temp;
5007 /* check if we've passed the dir's EOF */
5008 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
5009 osi_Log0(smb_logp, "T2 search dir passed eof");
5014 /* check if we've returned all the names that will fit in the
5015 * response packet; we check return count as well as the number
5016 * of bytes requested. We check the # of bytes after we find
5017 * the dir entry, since we'll need to check its size.
5019 if (returnedNames >= maxCount) {
5020 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
5021 returnedNames, maxCount);
5025 /* see if we can use the bufferp we have now; compute in which
5026 * page the current offset would be, and check whether that's
5027 * the offset of the buffer we have. If not, get the buffer.
5029 thyper.HighPart = curOffset.HighPart;
5030 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5031 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5034 buf_Release(bufferp);
5037 lock_ReleaseWrite(&scp->rw);
5038 code = buf_Get(scp, &thyper, &bufferp);
5039 lock_ObtainMutex(&dsp->mx);
5041 /* now, if we're doing a star match, do bulk fetching
5042 * of all of the status info for files in the dir.
5045 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, infoLevel, userp, &req);
5047 lock_ObtainWrite(&scp->rw);
5048 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
5049 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
5050 /* Don't bulk stat if risking timeout */
5051 DWORD now = GetTickCount();
5052 if (now - req.startTime > RDRtimeout * 1000) {
5053 scp->bulkStatProgress = thyper;
5054 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
5055 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
5057 code = cm_TryBulkStat(scp, &thyper, userp, &req);
5060 lock_ObtainWrite(&scp->rw);
5062 lock_ReleaseMutex(&dsp->mx);
5064 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
5068 bufferOffset = thyper;
5070 /* now get the data in the cache */
5072 code = cm_SyncOp(scp, bufferp, userp, &req,
5074 CM_SCACHESYNC_NEEDCALLBACK
5075 | CM_SCACHESYNC_READ);
5077 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5081 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5083 if (cm_HaveBuffer(scp, bufferp, 0)) {
5084 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5088 /* otherwise, load the buffer and try again */
5089 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5092 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5093 scp, bufferp, code);
5098 buf_Release(bufferp);
5102 } /* if (wrong buffer) ... */
5104 /* now we have the buffer containing the entry we're interested
5105 * in; copy it out if it represents a non-deleted entry.
5107 entryInDir = curOffset.LowPart & (2048-1);
5108 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5110 /* page header will help tell us which entries are free. Page
5111 * header can change more often than once per buffer, since
5112 * AFS 3 dir page size may be less than (but not more than)
5113 * a buffer package buffer.
5115 /* only look intra-buffer */
5116 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5117 temp &= ~(2048 - 1); /* turn off intra-page bits */
5118 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5120 /* now determine which entry we're looking at in the page.
5121 * If it is free (there's a free bitmap at the start of the
5122 * dir), we should skip these 32 bytes.
5124 slotInPage = (entryInDir & 0x7e0) >> 5;
5125 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5126 (1 << (slotInPage & 0x7)))) {
5127 /* this entry is free */
5128 numDirChunks = 1; /* only skip this guy */
5132 tp = bufferp->datap + entryInBuffer;
5133 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5135 /* while we're here, compute the next entry's location, too,
5136 * since we'll need it when writing out the cookie into the dir
5139 * XXXX Probably should do more sanity checking.
5141 numDirChunks = cm_NameEntries(dep->name, &onbytes);
5143 /* compute offset of cookie representing next entry */
5144 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5146 if (dep->fid.vnode == 0)
5147 goto nextEntry; /* This entry is not in use */
5149 /* Need 8.3 name? */
5151 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
5152 !cm_Is8Dot3(dep->name)) {
5153 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5157 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %s (%s)",
5158 dep->fid.vnode, dep->fid.unique,
5159 osi_LogSaveString(smb_logp, dep->name),
5160 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
5162 /* When matching, we are using doing a case fold if we have a wildcard mask.
5163 * If we get a non-wildcard match, it's a lookup for a specific file.
5165 if (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5166 (NeedShortName && smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))
5168 /* Eliminate entries that don't match requested attributes */
5169 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5170 smb_IsDotFile(dep->name)) {
5171 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5172 goto nextEntry; /* no hidden files */
5175 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5177 /* We have already done the cm_TryBulkStat above */
5178 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5179 fileType = cm_FindFileType(&fid);
5180 /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5181 * "has filetype %d", dep->name, fileType);
5183 if ( fileType == CM_SCACHETYPE_DIRECTORY ||
5184 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5185 fileType == CM_SCACHETYPE_DFSLINK ||
5186 fileType == CM_SCACHETYPE_INVALID)
5187 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5191 /* finally check if this name will fit */
5193 /* standard dir entry stuff */
5194 if (infoLevel < 0x101)
5195 ohbytes = 23; /* pre-NT */
5196 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
5197 ohbytes = 12; /* NT names only */
5199 ohbytes = 64; /* NT */
5201 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
5202 ohbytes += 26; /* Short name & length */
5204 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
5205 ohbytes += 4; /* if resume key required */
5208 if ( infoLevel != SMB_INFO_STANDARD &&
5209 infoLevel != SMB_FIND_FILE_DIRECTORY_INFO &&
5210 infoLevel != SMB_FIND_FILE_NAMES_INFO)
5211 ohbytes += 4; /* EASIZE */
5213 /* add header to name & term. null */
5214 orbytes = onbytes + ohbytes + 1;
5216 /* now, we round up the record to a 4 byte alignment,
5217 * and we make sure that we have enough room here for
5218 * even the aligned version (so we don't have to worry
5219 * about an overflow when we pad things out below).
5220 * That's the reason for the alignment arithmetic below.
5222 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5223 align = (4 - (orbytes & 3)) & 3;
5226 if (orbytes + bytesInBuffer + align > maxReturnData) {
5227 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5232 /* this is one of the entries to use: it is not deleted
5233 * and it matches the star pattern we're looking for.
5234 * Put out the name, preceded by its length.
5236 /* First zero everything else */
5237 memset(origOp, 0, ohbytes);
5239 if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
5240 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
5241 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
5242 *((u_long *)(op + 8)) = onbytes;
5244 *((u_long *)(op + 60)) = onbytes;
5245 strcpy(origOp+ohbytes, dep->name);
5246 if (smb_StoreAnsiFilenames)
5247 CharToOem(origOp+ohbytes, origOp+ohbytes);
5249 /* Short name if requested and needed */
5250 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
5251 if (NeedShortName) {
5252 strcpy(op + 70, shortName);
5253 if (smb_StoreAnsiFilenames)
5254 CharToOem(op + 70, op + 70);
5255 *(op + 68) = (char)(shortNameEnd - shortName);
5259 /* now, adjust the # of entries copied */
5262 /* NextEntryOffset and FileIndex */
5263 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
5264 int entryOffset = orbytes + align;
5265 *((u_long *)op) = entryOffset;
5266 *((u_long *)(op+4)) = nextEntryCookie;
5269 /* now we emit the attribute. This is tricky, since
5270 * we need to really stat the file to find out what
5271 * type of entry we've got. Right now, we're copying
5272 * out data from a buffer, while holding the scp
5273 * locked, so it isn't really convenient to stat
5274 * something now. We'll put in a place holder
5275 * now, and make a second pass before returning this
5276 * to get the real attributes. So, we just skip the
5277 * data for now, and adjust it later. We allocate a
5278 * patch record to make it easy to find this point
5279 * later. The replay will happen at a time when it is
5280 * safe to unlock the directory.
5282 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5283 curPatchp = malloc(sizeof(*curPatchp));
5284 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5285 curPatchp->dptr = op;
5286 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5287 curPatchp->dptr += 8;
5289 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
5290 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5293 curPatchp->flags = 0;
5295 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5298 curPatchp->dep = dep;
5301 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5302 /* put out resume key */
5303 *((u_long *)origOp) = nextEntryCookie;
5305 /* Adjust byte ptr and count */
5306 origOp += orbytes; /* skip entire record */
5307 bytesInBuffer += orbytes;
5309 /* and pad the record out */
5310 while (--align >= 0) {
5314 } /* if we're including this name */
5315 else if (!starPattern &&
5317 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
5318 /* We were looking for exact matches, but here's an inexact one*/
5323 /* and adjust curOffset to be where the new cookie is */
5324 thyper.HighPart = 0;
5325 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5326 curOffset = LargeIntegerAdd(thyper, curOffset);
5327 } /* while copying data for dir listing */
5329 /* If we didn't get a star pattern, we did an exact match during the first pass.
5330 * If there were no exact matches found, we fail over to inexact matches by
5331 * marking the query as a star pattern (matches all case permutations), and
5332 * re-running the query.
5334 if (returnedNames == 0 && !starPattern && foundInexact) {
5335 osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
5340 /* release the mutex */
5341 lock_ReleaseWrite(&scp->rw);
5343 buf_Release(bufferp);
5347 /* apply and free last set of patches; if not doing a star match, this
5348 * will be empty, but better safe (and freeing everything) than sorry.
5350 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5351 dsp->relPath, infoLevel, userp, &req);
5353 /* now put out the final parameters */
5354 if (returnedNames == 0)
5356 if (p->opcode == 1) {
5358 outp->parmsp[0] = (unsigned short) dsp->cookie;
5359 outp->parmsp[1] = returnedNames;
5360 outp->parmsp[2] = eos;
5361 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5362 outp->parmsp[4] = 0;
5363 /* don't need last name to continue
5364 * search, cookie is enough. Normally,
5365 * this is the offset of the file name
5366 * of the last entry returned.
5368 outp->totalParms = 10; /* in bytes */
5372 outp->parmsp[0] = returnedNames;
5373 outp->parmsp[1] = eos;
5374 outp->parmsp[2] = 0; /* EAS error */
5375 outp->parmsp[3] = 0; /* last name, as above */
5376 outp->totalParms = 8; /* in bytes */
5379 /* return # of bytes in the buffer */
5380 outp->totalData = bytesInBuffer;
5382 /* Return error code if unsuccessful on first request */
5383 if (code == 0 && p->opcode == 1 && returnedNames == 0)
5384 code = CM_ERROR_NOSUCHFILE;
5386 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
5387 p->opcode, dsp->cookie, returnedNames, code);
5389 /* if we're supposed to close the search after this request, or if
5390 * we're supposed to close the search if we're done, and we're done,
5391 * or if something went wrong, close the search.
5393 if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
5394 (returnedNames == 0) ||
5395 ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
5397 smb_DeleteDirSearch(dsp);
5400 smb_SendTran2Error(vcp, p, opx, code);
5402 smb_SendTran2Packet(vcp, outp, opx);
5404 smb_FreeTran2Packet(outp);
5405 smb_ReleaseDirSearch(dsp);
5406 cm_ReleaseSCache(scp);
5407 cm_ReleaseUser(userp);
5411 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5414 smb_dirSearch_t *dsp;
5416 dirHandle = smb_GetSMBParm(inp, 0);
5418 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
5420 dsp = smb_FindDirSearch(dirHandle);
5423 return CM_ERROR_BADFD;
5425 /* otherwise, we have an FD to destroy */
5426 smb_DeleteDirSearch(dsp);
5427 smb_ReleaseDirSearch(dsp);
5429 /* and return results */
5430 smb_SetSMBDataLength(outp, 0);
5435 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5437 smb_SetSMBDataLength(outp, 0);
5441 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5448 cm_scache_t *dscp; /* dir we're dealing with */
5449 cm_scache_t *scp; /* file we're creating */
5451 int initialModeBits;
5461 int parmSlot; /* which parm we're dealing with */
5470 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
5471 openFun = smb_GetSMBParm(inp, 8); /* open function */
5472 excl = ((openFun & 3) == 0);
5473 trunc = ((openFun & 3) == 2); /* truncate it */
5474 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
5475 openAction = 0; /* tracks what we did */
5477 attributes = smb_GetSMBParm(inp, 5);
5478 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
5480 /* compute initial mode bits based on read-only flag in attributes */
5481 initialModeBits = 0666;
5482 if (attributes & SMB_ATTR_READONLY)
5483 initialModeBits &= ~0222;
5485 pathp = smb_GetSMBData(inp, NULL);
5486 if (smb_StoreAnsiFilenames)
5487 OemToChar(pathp,pathp);
5489 spacep = inp->spacep;
5490 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5493 (stricmp(lastNamep, SMB_IOCTL_FILENAME) == 0 ||
5494 stricmp(lastNamep, "\\srvsvc") == 0 ||
5495 stricmp(lastNamep, "\\wkssvc") == 0 ||
5496 stricmp(lastNamep, "ipc$") == 0)) {
5497 /* special case magic file name for receiving IOCTL requests
5498 * (since IOCTL calls themselves aren't getting through).
5501 osi_Log0(smb_logp, "IOCTL Open");
5504 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5505 smb_SetupIoctlFid(fidp, spacep);
5507 /* set inp->fid so that later read calls in same msg can find fid */
5508 inp->fid = fidp->fid;
5510 /* copy out remainder of the parms */
5512 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5514 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
5515 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
5516 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5517 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
5518 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
5519 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5520 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5521 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5523 /* and the final "always present" stuff */
5524 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
5525 /* next write out the "unique" ID */
5526 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
5527 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
5528 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5529 smb_SetSMBDataLength(outp, 0);
5531 /* and clean up fid reference */
5532 smb_ReleaseFID(fidp);
5536 #ifdef DEBUG_VERBOSE
5538 char *hexp, *asciip;
5539 asciip = (lastNamep ? lastNamep : pathp );
5540 hexp = osi_HexifyString(asciip);
5541 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
5545 userp = smb_GetUserFromVCP(vcp, inp);
5548 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5550 cm_ReleaseUser(userp);
5551 return CM_ERROR_NOSUCHPATH;
5553 code = cm_NameI(cm_data.rootSCachep, pathp,
5554 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5555 userp, tidPathp, &req, &scp);
5558 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5559 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5560 cm_ReleaseSCache(scp);
5561 cm_ReleaseUser(userp);
5562 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5563 return CM_ERROR_PATH_NOT_COVERED;
5565 return CM_ERROR_BADSHARENAME;
5567 #endif /* DFS_SUPPORT */
5570 code = cm_NameI(cm_data.rootSCachep, spacep->data,
5571 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5572 userp, tidPathp, &req, &dscp);
5574 cm_ReleaseUser(userp);
5579 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5580 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
5581 cm_ReleaseSCache(dscp);
5582 cm_ReleaseUser(userp);
5583 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5584 return CM_ERROR_PATH_NOT_COVERED;
5586 return CM_ERROR_BADSHARENAME;
5588 #endif /* DFS_SUPPORT */
5589 /* otherwise, scp points to the parent directory. Do a lookup,
5590 * and truncate the file if we find it, otherwise we create the
5597 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
5599 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5600 cm_ReleaseSCache(dscp);
5601 cm_ReleaseUser(userp);
5606 /* if we get here, if code is 0, the file exists and is represented by
5607 * scp. Otherwise, we have to create it. The dir may be represented
5608 * by dscp, or we may have found the file directly. If code is non-zero,
5612 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
5614 if (dscp) cm_ReleaseSCache(dscp);
5615 cm_ReleaseSCache(scp);
5616 cm_ReleaseUser(userp);
5621 /* oops, file shouldn't be there */
5623 cm_ReleaseSCache(dscp);
5624 cm_ReleaseSCache(scp);
5625 cm_ReleaseUser(userp);
5626 return CM_ERROR_EXISTS;
5630 setAttr.mask = CM_ATTRMASK_LENGTH;
5631 setAttr.length.LowPart = 0;
5632 setAttr.length.HighPart = 0;
5633 code = cm_SetAttr(scp, &setAttr, userp, &req);
5634 openAction = 3; /* truncated existing file */
5636 else openAction = 1; /* found existing file */
5638 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
5639 /* don't create if not found */
5640 if (dscp) cm_ReleaseSCache(dscp);
5641 cm_ReleaseUser(userp);
5642 return CM_ERROR_NOSUCHFILE;
5645 osi_assertx(dscp != NULL, "null cm_scache_t");
5646 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
5647 osi_LogSaveString(smb_logp, lastNamep));
5648 openAction = 2; /* created file */
5649 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5650 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5651 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5655 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5656 smb_NotifyChange(FILE_ACTION_ADDED,
5657 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5658 dscp, lastNamep, NULL, TRUE);
5659 } else if (!excl && code == CM_ERROR_EXISTS) {
5660 /* not an exclusive create, and someone else tried
5661 * creating it already, then we open it anyway. We
5662 * don't bother retrying after this, since if this next
5663 * fails, that means that the file was deleted after we
5664 * started this call.
5666 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5670 setAttr.mask = CM_ATTRMASK_LENGTH;
5671 setAttr.length.LowPart = 0;
5672 setAttr.length.HighPart = 0;
5673 code = cm_SetAttr(scp, &setAttr, userp, &req);
5675 } /* lookup succeeded */
5679 /* we don't need this any longer */
5681 cm_ReleaseSCache(dscp);
5684 /* something went wrong creating or truncating the file */
5686 cm_ReleaseSCache(scp);
5687 cm_ReleaseUser(userp);
5691 /* make sure we're about to open a file */
5692 if (scp->fileType != CM_SCACHETYPE_FILE) {
5693 cm_ReleaseSCache(scp);
5694 cm_ReleaseUser(userp);
5695 return CM_ERROR_ISDIR;
5698 /* now all we have to do is open the file itself */
5699 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5700 osi_assertx(fidp, "null smb_fid_t");
5703 lock_ObtainMutex(&fidp->mx);
5704 /* save a pointer to the vnode */
5706 lock_ObtainWrite(&scp->rw);
5707 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5708 lock_ReleaseWrite(&scp->rw);
5709 osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
5711 fidp->userp = userp;
5713 /* compute open mode */
5715 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5716 if (openMode == 1 || openMode == 2)
5717 fidp->flags |= SMB_FID_OPENWRITE;
5719 /* remember if the file was newly created */
5721 fidp->flags |= SMB_FID_CREATED;
5723 lock_ReleaseMutex(&fidp->mx);
5724 smb_ReleaseFID(fidp);
5726 cm_Open(scp, 0, userp);
5728 /* set inp->fid so that later read calls in same msg can find fid */
5729 inp->fid = fidp->fid;
5731 /* copy out remainder of the parms */
5733 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5734 lock_ObtainRead(&scp->rw);
5736 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5737 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5738 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5739 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5740 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5741 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5742 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5743 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5744 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5746 /* and the final "always present" stuff */
5747 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5748 /* next write out the "unique" ID */
5749 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5750 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5751 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5752 lock_ReleaseRead(&scp->rw);
5753 smb_SetSMBDataLength(outp, 0);
5755 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5757 cm_ReleaseUser(userp);
5758 /* leave scp held since we put it in fidp->scp */
5762 static void smb_GetLockParams(unsigned char LockType,
5764 unsigned int * ppid,
5765 LARGE_INTEGER * pOffset,
5766 LARGE_INTEGER * pLength)
5768 if (LockType & LOCKING_ANDX_LARGE_FILES) {
5770 *ppid = *((USHORT *) *buf);
5771 pOffset->HighPart = *((LONG *)(*buf + 4));
5772 pOffset->LowPart = *((DWORD *)(*buf + 8));
5773 pLength->HighPart = *((LONG *)(*buf + 12));
5774 pLength->LowPart = *((DWORD *)(*buf + 16));
5778 /* Not Large Files */
5779 *ppid = *((USHORT *) *buf);
5780 pOffset->HighPart = 0;
5781 pOffset->LowPart = *((DWORD *)(*buf + 2));
5782 pLength->HighPart = 0;
5783 pLength->LowPart = *((DWORD *)(*buf + 6));
5788 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5795 unsigned char LockType;
5796 unsigned short NumberOfUnlocks, NumberOfLocks;
5800 LARGE_INTEGER LOffset, LLength;
5801 smb_waitingLockRequest_t *wlRequest = NULL;
5802 cm_file_lock_t *lockp;
5810 fid = smb_GetSMBParm(inp, 2);
5811 fid = smb_ChainFID(fid, inp);
5813 fidp = smb_FindFID(vcp, fid, 0);
5815 return CM_ERROR_BADFD;
5817 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
5818 smb_CloseFID(vcp, fidp, NULL, 0);
5819 smb_ReleaseFID(fidp);
5820 return CM_ERROR_NOSUCHFILE;
5823 lock_ObtainMutex(&fidp->mx);
5824 if (fidp->flags & SMB_FID_IOCTL) {
5825 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
5826 lock_ReleaseMutex(&fidp->mx);
5827 smb_ReleaseFID(fidp);
5828 return CM_ERROR_BADFD;
5831 osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
5833 lock_ReleaseMutex(&fidp->mx);
5835 /* set inp->fid so that later read calls in same msg can find fid */
5838 userp = smb_GetUserFromVCP(vcp, inp);
5841 lock_ObtainWrite(&scp->rw);
5842 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5843 CM_SCACHESYNC_NEEDCALLBACK
5844 | CM_SCACHESYNC_GETSTATUS
5845 | CM_SCACHESYNC_LOCK);
5847 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
5851 LockType = smb_GetSMBParm(inp, 3) & 0xff;
5852 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
5853 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
5854 NumberOfLocks = smb_GetSMBParm(inp, 7);
5856 if (!(fidp->flags & SMB_FID_OPENWRITE) &&
5857 !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
5858 /* somebody wants exclusive locks on a file that they only
5859 opened for reading. We downgrade this to a shared lock. */
5860 osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
5861 LockType |= LOCKING_ANDX_SHARED_LOCK;
5864 if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
5865 /* AFS does not support atomic changes of lock types from read or write and vice-versa */
5866 osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]");
5867 code = CM_ERROR_BADOP;
5872 op = smb_GetSMBData(inp, NULL);
5874 if (LockType & LOCKING_ANDX_CANCEL_LOCK) {
5875 /* Cancel outstanding lock requests */
5876 smb_waitingLock_t * wl;
5878 for (i=0; i<NumberOfLocks; i++) {
5879 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5881 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5883 lock_ObtainWrite(&smb_globalLock);
5884 for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
5886 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
5887 if (wl->key == key && LargeIntegerEqualTo(wl->LOffset, LOffset) &&
5888 LargeIntegerEqualTo(wl->LLength, LLength)) {
5889 wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
5890 goto found_lock_request;
5895 lock_ReleaseWrite(&smb_globalLock);
5898 smb_SetSMBDataLength(outp, 0);
5903 for (i=0; i<NumberOfUnlocks; i++) {
5904 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5906 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5908 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
5916 for (i=0; i<NumberOfLocks; i++) {
5917 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5919 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5921 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
5922 userp, &req, &lockp);
5924 if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
5925 (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
5927 code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
5928 userp, &req, &lockp);
5931 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
5932 smb_waitingLock_t * wLock;
5934 /* Put on waiting list */
5935 if(wlRequest == NULL) {
5939 LARGE_INTEGER tOffset, tLength;
5941 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
5943 osi_assertx(wlRequest != NULL, "null wlRequest");
5945 wlRequest->vcp = vcp;
5947 wlRequest->scp = scp;
5948 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
5950 wlRequest->inp = smb_CopyPacket(inp);
5951 wlRequest->outp = smb_CopyPacket(outp);
5952 wlRequest->lockType = LockType;
5953 wlRequest->msTimeout = Timeout;
5954 wlRequest->start_t = osi_Time();
5955 wlRequest->locks = NULL;
5957 /* The waiting lock request needs to have enough
5958 information to undo all the locks in the request.
5959 We do the following to store info about locks that
5960 have already been granted. Sure, we can get most
5961 of the info from the packet, but the packet doesn't
5962 hold the result of cm_Lock call. In practice we
5963 only receive packets with one or two locks, so we
5964 are only wasting a few bytes here and there and
5965 only for a limited period of time until the waiting
5966 lock times out or is freed. */
5968 for(opt = op_locks, j=i; j > 0; j--) {
5969 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
5971 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5973 wLock = malloc(sizeof(smb_waitingLock_t));
5975 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
5978 wLock->LOffset = tOffset;
5979 wLock->LLength = tLength;
5980 wLock->lockp = NULL;
5981 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
5982 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5987 wLock = malloc(sizeof(smb_waitingLock_t));
5989 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
5992 wLock->LOffset = LOffset;
5993 wLock->LLength = LLength;
5994 wLock->lockp = lockp;
5995 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
5996 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5999 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
6007 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
6014 /* Since something went wrong with the lock number i, we now
6015 have to go ahead and release any locks acquired before the
6016 failure. All locks before lock number i (of which there
6017 are i of them) have either been successful or are waiting.
6018 Either case requires calling cm_Unlock(). */
6020 /* And purge the waiting lock */
6021 if(wlRequest != NULL) {
6022 smb_waitingLock_t * wl;
6023 smb_waitingLock_t * wlNext;
6026 for(wl = wlRequest->locks; wl; wl = wlNext) {
6028 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
6030 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
6033 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
6035 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
6038 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
6043 smb_ReleaseVC(wlRequest->vcp);
6044 cm_ReleaseSCache(wlRequest->scp);
6045 smb_FreePacket(wlRequest->inp);
6046 smb_FreePacket(wlRequest->outp);
6055 if (wlRequest != NULL) {
6057 lock_ObtainWrite(&smb_globalLock);
6058 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
6060 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
6061 lock_ReleaseWrite(&smb_globalLock);
6063 /* don't send reply immediately */
6064 outp->flags |= SMB_PACKETFLAG_NOSEND;
6067 smb_SetSMBDataLength(outp, 0);
6071 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
6074 lock_ReleaseWrite(&scp->rw);
6075 cm_ReleaseSCache(scp);
6076 cm_ReleaseUser(userp);
6077 smb_ReleaseFID(fidp);
6082 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6088 afs_uint32 searchTime;
6095 fid = smb_GetSMBParm(inp, 0);
6096 fid = smb_ChainFID(fid, inp);
6098 fidp = smb_FindFID(vcp, fid, 0);
6100 return CM_ERROR_BADFD;
6102 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6103 smb_CloseFID(vcp, fidp, NULL, 0);
6104 smb_ReleaseFID(fidp);
6105 return CM_ERROR_NOSUCHFILE;
6108 lock_ObtainMutex(&fidp->mx);
6109 if (fidp->flags & SMB_FID_IOCTL) {
6110 lock_ReleaseMutex(&fidp->mx);
6111 smb_ReleaseFID(fidp);
6112 return CM_ERROR_BADFD;
6115 osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6117 lock_ReleaseMutex(&fidp->mx);
6119 userp = smb_GetUserFromVCP(vcp, inp);
6122 /* otherwise, stat the file */
6123 lock_ObtainWrite(&scp->rw);
6124 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6125 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6129 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6131 lock_ConvertWToR(&scp->rw);
6133 /* decode times. We need a search time, but the response to this
6134 * call provides the date first, not the time, as returned in the
6135 * searchTime variable. So we take the high-order bits first.
6137 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
6138 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
6139 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
6140 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
6141 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
6142 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
6143 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
6145 /* now handle file size and allocation size */
6146 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
6147 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
6148 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
6149 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
6151 /* file attribute */
6152 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
6154 /* and finalize stuff */
6155 smb_SetSMBDataLength(outp, 0);
6160 lock_ReleaseRead(&scp->rw);
6162 lock_ReleaseWrite(&scp->rw);
6163 cm_ReleaseSCache(scp);
6164 cm_ReleaseUser(userp);
6165 smb_ReleaseFID(fidp);
6169 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6175 afs_uint32 searchTime;
6183 fid = smb_GetSMBParm(inp, 0);
6184 fid = smb_ChainFID(fid, inp);
6186 fidp = smb_FindFID(vcp, fid, 0);
6188 return CM_ERROR_BADFD;
6190 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6191 smb_CloseFID(vcp, fidp, NULL, 0);
6192 smb_ReleaseFID(fidp);
6193 return CM_ERROR_NOSUCHFILE;
6196 lock_ObtainMutex(&fidp->mx);
6197 if (fidp->flags & SMB_FID_IOCTL) {
6198 lock_ReleaseMutex(&fidp->mx);
6199 smb_ReleaseFID(fidp);
6200 return CM_ERROR_BADFD;
6203 osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6205 lock_ReleaseMutex(&fidp->mx);
6207 userp = smb_GetUserFromVCP(vcp, inp);
6210 /* now prepare to call cm_setattr. This message only sets various times,
6211 * and AFS only implements mtime, and we'll set the mtime if that's
6212 * requested. The others we'll ignore.
6214 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
6216 if (searchTime != 0) {
6217 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
6219 if ( unixTime != -1 ) {
6220 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
6221 attrs.clientModTime = unixTime;
6222 code = cm_SetAttr(scp, &attrs, userp, &req);
6224 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
6226 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
6232 cm_ReleaseSCache(scp);
6233 cm_ReleaseUser(userp);
6234 smb_ReleaseFID(fidp);
6238 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6241 long count, written = 0, total_written = 0;
6248 int inDataBlockCount;
6250 fd = smb_GetSMBParm(inp, 2);
6251 count = smb_GetSMBParm(inp, 10);
6253 offset.HighPart = 0;
6254 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6256 if (*inp->wctp == 14) {
6257 /* we have a request with 64-bit file offsets */
6258 #ifdef AFS_LARGEFILES
6259 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6261 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6263 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
6264 /* we shouldn't have received this op if we didn't specify
6265 largefile support */
6266 return CM_ERROR_BADOP;
6271 op = inp->data + smb_GetSMBParm(inp, 11);
6272 inDataBlockCount = count;
6274 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
6275 fd, offset.HighPart, offset.LowPart, count);
6277 fd = smb_ChainFID(fd, inp);
6278 fidp = smb_FindFID(vcp, fd, 0);
6280 return CM_ERROR_BADFD;
6282 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6283 smb_CloseFID(vcp, fidp, NULL, 0);
6284 smb_ReleaseFID(fidp);
6285 return CM_ERROR_NOSUCHFILE;
6288 lock_ObtainMutex(&fidp->mx);
6289 if (fidp->flags & SMB_FID_IOCTL) {
6290 lock_ReleaseMutex(&fidp->mx);
6291 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
6292 smb_ReleaseFID(fidp);
6295 lock_ReleaseMutex(&fidp->mx);
6296 userp = smb_GetUserFromVCP(vcp, inp);
6298 /* special case: 0 bytes transferred means there is no data
6299 transferred. A slight departure from SMB_COM_WRITE where this
6300 means that we are supposed to truncate the file at this
6305 LARGE_INTEGER LOffset;
6306 LARGE_INTEGER LLength;
6309 pid = ((smb_t *) inp)->pid;
6310 key = cm_GenerateKey(vcp->vcID, pid, fd);
6312 LOffset.HighPart = offset.HighPart;
6313 LOffset.LowPart = offset.LowPart;
6314 LLength.HighPart = 0;
6315 LLength.LowPart = count;
6318 lock_ObtainWrite(&scp->rw);
6319 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
6320 lock_ReleaseWrite(&scp->rw);
6327 * Work around bug in NT client
6329 * When copying a file, the NT client should first copy the data,
6330 * then copy the last write time. But sometimes the NT client does
6331 * these in the wrong order, so the data copies would inadvertently
6332 * cause the last write time to be overwritten. We try to detect this,
6333 * and don't set client mod time if we think that would go against the
6336 lock_ObtainMutex(&fidp->mx);
6337 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6338 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6339 fidp->scp->clientModTime = time(NULL);
6341 lock_ReleaseMutex(&fidp->mx);
6344 while ( code == 0 && count > 0 ) {
6345 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6346 if (code == 0 && written == 0)
6347 code = CM_ERROR_PARTIALWRITE;
6349 offset = LargeIntegerAdd(offset,
6350 ConvertLongToLargeInteger(written));
6352 total_written += written;
6356 /* slots 0 and 1 are reserved for request chaining and will be
6357 filled in when we return. */
6358 smb_SetSMBParm(outp, 2, total_written);
6359 smb_SetSMBParm(outp, 3, 0); /* reserved */
6360 smb_SetSMBParm(outp, 4, 0); /* reserved */
6361 smb_SetSMBParm(outp, 5, 0); /* reserved */
6362 smb_SetSMBDataLength(outp, 0);
6365 cm_ReleaseUser(userp);
6366 smb_ReleaseFID(fidp);
6371 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6375 long finalCount = 0;
6384 fd = smb_GetSMBParm(inp, 2);
6385 count = smb_GetSMBParm(inp, 5);
6386 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6388 if (*inp->wctp == 12) {
6389 /* a request with 64-bit offsets */
6390 #ifdef AFS_LARGEFILES
6391 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
6393 if (LargeIntegerLessThanZero(offset)) {
6394 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
6395 offset.HighPart, offset.LowPart);
6396 return CM_ERROR_BADSMB;
6399 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
6400 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
6401 return CM_ERROR_BADSMB;
6403 offset.HighPart = 0;
6407 offset.HighPart = 0;
6410 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
6411 fd, offset.HighPart, offset.LowPart, count);
6413 fd = smb_ChainFID(fd, inp);
6414 fidp = smb_FindFID(vcp, fd, 0);
6416 return CM_ERROR_BADFD;
6419 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6420 smb_CloseFID(vcp, fidp, NULL, 0);
6421 smb_ReleaseFID(fidp);
6422 return CM_ERROR_NOSUCHFILE;
6425 pid = ((smb_t *) inp)->pid;
6426 key = cm_GenerateKey(vcp->vcID, pid, fd);
6428 LARGE_INTEGER LOffset, LLength;
6431 LOffset.HighPart = offset.HighPart;
6432 LOffset.LowPart = offset.LowPart;
6433 LLength.HighPart = 0;
6434 LLength.LowPart = count;
6437 lock_ObtainWrite(&scp->rw);
6438 code = cm_LockCheckRead(scp, LOffset, LLength, key);
6439 lock_ReleaseWrite(&scp->rw);
6443 smb_ReleaseFID(fidp);
6447 /* set inp->fid so that later read calls in same msg can find fid */
6450 lock_ObtainMutex(&fidp->mx);
6451 if (fidp->flags & SMB_FID_IOCTL) {
6452 lock_ReleaseMutex(&fidp->mx);
6453 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
6454 smb_ReleaseFID(fidp);
6457 lock_ReleaseMutex(&fidp->mx);
6459 userp = smb_GetUserFromVCP(vcp, inp);
6461 /* 0 and 1 are reserved for request chaining, were setup by our caller,
6462 * and will be further filled in after we return.
6464 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
6465 smb_SetSMBParm(outp, 3, 0); /* resvd */
6466 smb_SetSMBParm(outp, 4, 0); /* resvd */
6467 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
6468 /* fill in #6 when we have all the parameters' space reserved */
6469 smb_SetSMBParm(outp, 7, 0); /* resv'd */
6470 smb_SetSMBParm(outp, 8, 0); /* resv'd */
6471 smb_SetSMBParm(outp, 9, 0); /* resv'd */
6472 smb_SetSMBParm(outp, 10, 0); /* resv'd */
6473 smb_SetSMBParm(outp, 11, 0); /* reserved */
6475 /* get op ptr after putting in the parms, since otherwise we don't
6476 * know where the data really is.
6478 op = smb_GetSMBData(outp, NULL);
6480 /* now fill in offset from start of SMB header to first data byte (to op) */
6481 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
6483 /* set the packet data length the count of the # of bytes */
6484 smb_SetSMBDataLength(outp, count);
6486 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6488 /* fix some things up */
6489 smb_SetSMBParm(outp, 5, finalCount);
6490 smb_SetSMBDataLength(outp, finalCount);
6492 cm_ReleaseUser(userp);
6493 smb_ReleaseFID(fidp);
6498 * Values for createDisp, copied from NTDDK.H
6500 #define FILE_SUPERSEDE 0 // (???)
6501 #define FILE_OPEN 1 // (open)
6502 #define FILE_CREATE 2 // (exclusive)
6503 #define FILE_OPEN_IF 3 // (non-exclusive)
6504 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
6505 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
6508 #define REQUEST_OPLOCK 2
6509 #define REQUEST_BATCH_OPLOCK 4
6510 #define OPEN_DIRECTORY 8
6511 #define EXTENDED_RESPONSE_REQUIRED 0x10
6513 /* CreateOptions field. */
6514 #define FILE_DIRECTORY_FILE 0x0001
6515 #define FILE_WRITE_THROUGH 0x0002
6516 #define FILE_SEQUENTIAL_ONLY 0x0004
6517 #define FILE_NON_DIRECTORY_FILE 0x0040
6518 #define FILE_NO_EA_KNOWLEDGE 0x0200
6519 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
6520 #define FILE_RANDOM_ACCESS 0x0800
6521 #define FILE_DELETE_ON_CLOSE 0x1000
6522 #define FILE_OPEN_BY_FILE_ID 0x2000
6524 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6526 char *pathp, *realPathp;
6530 cm_scache_t *dscp; /* parent dir */
6531 cm_scache_t *scp; /* file to create or open */
6532 cm_scache_t *targetScp; /* if scp is a symlink */
6536 unsigned short nameLength;
6538 unsigned int requestOpLock;
6539 unsigned int requestBatchOpLock;
6540 unsigned int mustBeDir;
6541 unsigned int extendedRespRequired;
6542 unsigned int treeCreate;
6544 unsigned int desiredAccess;
6545 unsigned int extAttributes;
6546 unsigned int createDisp;
6547 unsigned int createOptions;
6548 unsigned int shareAccess;
6549 int initialModeBits;
6550 unsigned short baseFid;
6551 smb_fid_t *baseFidp;
6553 cm_scache_t *baseDirp;
6554 unsigned short openAction;
6563 cm_lock_data_t *ldp = NULL;
6567 /* This code is very long and has a lot of if-then-else clauses
6568 * scp and dscp get reused frequently and we need to ensure that
6569 * we don't lose a reference. Start by ensuring that they are NULL.
6576 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
6577 flags = smb_GetSMBOffsetParm(inp, 3, 1)
6578 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
6579 requestOpLock = flags & REQUEST_OPLOCK;
6580 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6581 mustBeDir = flags & OPEN_DIRECTORY;
6582 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6585 * Why all of a sudden 32-bit FID?
6586 * We will reject all bits higher than 16.
6588 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
6589 return CM_ERROR_INVAL;
6590 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
6591 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
6592 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6593 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
6594 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
6595 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
6596 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
6597 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
6598 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
6599 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
6600 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
6602 /* mustBeDir is never set; createOptions directory bit seems to be
6605 if (createOptions & FILE_DIRECTORY_FILE)
6607 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6613 * compute initial mode bits based on read-only flag in
6614 * extended attributes
6616 initialModeBits = 0666;
6617 if (extAttributes & SMB_ATTR_READONLY)
6618 initialModeBits &= ~0222;
6620 pathp = smb_GetSMBData(inp, NULL);
6621 /* Sometimes path is not null-terminated, so we make a copy. */
6622 realPathp = malloc(nameLength+1);
6623 memcpy(realPathp, pathp, nameLength);
6624 realPathp[nameLength] = 0;
6625 if (smb_StoreAnsiFilenames)
6626 OemToChar(realPathp,realPathp);
6628 spacep = inp->spacep;
6629 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6631 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
6632 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
6633 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
6636 (stricmp(lastNamep, SMB_IOCTL_FILENAME) == 0 ||
6637 stricmp(lastNamep, "\\srvsvc") == 0 ||
6638 stricmp(lastNamep, "\\wkssvc") == 0 ||
6639 stricmp(lastNamep, "ipc$") == 0)) {
6640 /* special case magic file name for receiving IOCTL requests
6641 * (since IOCTL calls themselves aren't getting through).
6643 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6644 smb_SetupIoctlFid(fidp, spacep);
6645 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
6647 /* set inp->fid so that later read calls in same msg can find fid */
6648 inp->fid = fidp->fid;
6652 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6653 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6654 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
6656 memset(&ft, 0, sizeof(ft));
6657 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6658 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6659 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6660 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6661 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
6662 sz.HighPart = 0x7fff; sz.LowPart = 0;
6663 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
6664 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
6665 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6666 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6667 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
6668 smb_SetSMBDataLength(outp, 0);
6670 /* clean up fid reference */
6671 smb_ReleaseFID(fidp);
6676 #ifdef DEBUG_VERBOSE
6678 char *hexp, *asciip;
6679 asciip = (lastNamep? lastNamep : realPathp);
6680 hexp = osi_HexifyString( asciip );
6681 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
6686 userp = smb_GetUserFromVCP(vcp, inp);
6688 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
6690 return CM_ERROR_INVAL;
6695 baseDirp = cm_data.rootSCachep;
6696 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6697 if (code == CM_ERROR_TIDIPC) {
6698 /* Attempt to use a TID allocated for IPC. The client
6699 * is probably looking for DCE RPC end points which we
6700 * don't support OR it could be looking to make a DFS
6703 osi_Log0(smb_logp, "NTCreateX received IPC TID");
6706 cm_ReleaseUser(userp);
6707 return CM_ERROR_NOSUCHFILE;
6708 #endif /* DFS_SUPPORT */
6711 baseFidp = smb_FindFID(vcp, baseFid, 0);
6713 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
6715 cm_ReleaseUser(userp);
6716 return CM_ERROR_INVAL;
6719 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6721 cm_ReleaseUser(userp);
6722 smb_CloseFID(vcp, baseFidp, NULL, 0);
6723 smb_ReleaseFID(baseFidp);
6724 return CM_ERROR_NOSUCHPATH;
6727 baseDirp = baseFidp->scp;
6731 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
6733 /* compute open mode */
6735 if (desiredAccess & DELETE)
6736 fidflags |= SMB_FID_OPENDELETE;
6737 if (desiredAccess & AFS_ACCESS_READ)
6738 fidflags |= SMB_FID_OPENREAD_LISTDIR;
6739 if (desiredAccess & AFS_ACCESS_WRITE)
6740 fidflags |= SMB_FID_OPENWRITE;
6741 if (createOptions & FILE_DELETE_ON_CLOSE)
6742 fidflags |= SMB_FID_DELONCLOSE;
6743 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6744 fidflags |= SMB_FID_SEQUENTIAL;
6745 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6746 fidflags |= SMB_FID_RANDOM;
6747 if (smb_IsExecutableFileName(lastNamep))
6748 fidflags |= SMB_FID_EXECUTABLE;
6750 /* and the share mode */
6751 if (shareAccess & FILE_SHARE_READ)
6752 fidflags |= SMB_FID_SHARE_READ;
6753 if (shareAccess & FILE_SHARE_WRITE)
6754 fidflags |= SMB_FID_SHARE_WRITE;
6756 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
6759 /* For an exclusive create, we want to do a case sensitive match for the last component. */
6760 if ( createDisp == FILE_CREATE ||
6761 createDisp == FILE_OVERWRITE ||
6762 createDisp == FILE_OVERWRITE_IF) {
6763 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6764 userp, tidPathp, &req, &dscp);
6767 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6768 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
6769 cm_ReleaseSCache(dscp);
6770 cm_ReleaseUser(userp);
6773 smb_ReleaseFID(baseFidp);
6774 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6775 return CM_ERROR_PATH_NOT_COVERED;
6777 return CM_ERROR_BADSHARENAME;
6779 #endif /* DFS_SUPPORT */
6780 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6782 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
6783 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6784 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6785 if (code == 0 && realDirFlag == 1) {
6786 cm_ReleaseSCache(scp);
6787 cm_ReleaseSCache(dscp);
6788 cm_ReleaseUser(userp);
6791 smb_ReleaseFID(baseFidp);
6792 return CM_ERROR_EXISTS;
6796 /* we have both scp and dscp */
6798 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6799 userp, tidPathp, &req, &scp);
6801 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6802 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
6803 cm_ReleaseSCache(scp);
6804 cm_ReleaseUser(userp);
6807 smb_ReleaseFID(baseFidp);
6808 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6809 return CM_ERROR_PATH_NOT_COVERED;
6811 return CM_ERROR_BADSHARENAME;
6813 #endif /* DFS_SUPPORT */
6814 /* we might have scp but not dscp */
6820 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6821 /* look up parent directory */
6822 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
6823 * the immediate parent. We have to work our way up realPathp until we hit something that we
6827 /* we might or might not have scp */
6833 code = cm_NameI(baseDirp, spacep->data,
6834 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6835 userp, tidPathp, &req, &dscp);
6838 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6839 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
6841 cm_ReleaseSCache(scp);
6842 cm_ReleaseSCache(dscp);
6843 cm_ReleaseUser(userp);
6846 smb_ReleaseFID(baseFidp);
6847 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6848 return CM_ERROR_PATH_NOT_COVERED;
6850 return CM_ERROR_BADSHARENAME;
6852 #endif /* DFS_SUPPORT */
6855 (tp = strrchr(spacep->data,'\\')) &&
6856 (createDisp == FILE_CREATE) &&
6857 (realDirFlag == 1)) {
6860 treeStartp = realPathp + (tp - spacep->data);
6862 if (*tp && !smb_IsLegalFilename(tp)) {
6863 cm_ReleaseUser(userp);
6865 smb_ReleaseFID(baseFidp);
6868 cm_ReleaseSCache(scp);
6869 return CM_ERROR_BADNTFILENAME;
6873 } while (dscp == NULL && code == 0);
6877 /* we might have scp and we might have dscp */
6880 smb_ReleaseFID(baseFidp);
6883 osi_Log0(smb_logp,"NTCreateX parent not found");
6885 cm_ReleaseSCache(scp);
6887 cm_ReleaseSCache(dscp);
6888 cm_ReleaseUser(userp);
6893 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
6894 /* A file exists where we want a directory. */
6896 cm_ReleaseSCache(scp);
6897 cm_ReleaseSCache(dscp);
6898 cm_ReleaseUser(userp);
6900 return CM_ERROR_EXISTS;
6904 lastNamep = realPathp;
6908 if (!smb_IsLegalFilename(lastNamep)) {
6910 cm_ReleaseSCache(scp);
6912 cm_ReleaseSCache(dscp);
6913 cm_ReleaseUser(userp);
6915 return CM_ERROR_BADNTFILENAME;
6918 if (!foundscp && !treeCreate) {
6919 if ( createDisp == FILE_CREATE ||
6920 createDisp == FILE_OVERWRITE ||
6921 createDisp == FILE_OVERWRITE_IF)
6923 code = cm_Lookup(dscp, lastNamep,
6924 CM_FLAG_FOLLOW, userp, &req, &scp);
6926 code = cm_Lookup(dscp, lastNamep,
6927 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6930 if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
6932 cm_ReleaseSCache(dscp);
6933 cm_ReleaseUser(userp);
6938 /* we have scp and dscp */
6940 /* we have scp but not dscp */
6942 smb_ReleaseFID(baseFidp);
6945 /* if we get here, if code is 0, the file exists and is represented by
6946 * scp. Otherwise, we have to create it. The dir may be represented
6947 * by dscp, or we may have found the file directly. If code is non-zero,
6950 if (code == 0 && !treeCreate) {
6951 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
6954 cm_ReleaseSCache(dscp);
6956 cm_ReleaseSCache(scp);
6957 cm_ReleaseUser(userp);
6962 if (createDisp == FILE_CREATE) {
6963 /* oops, file shouldn't be there */
6964 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6966 cm_ReleaseSCache(dscp);
6968 cm_ReleaseSCache(scp);
6969 cm_ReleaseUser(userp);
6971 return CM_ERROR_EXISTS;
6974 if ( createDisp == FILE_OVERWRITE ||
6975 createDisp == FILE_OVERWRITE_IF) {
6977 setAttr.mask = CM_ATTRMASK_LENGTH;
6978 setAttr.length.LowPart = 0;
6979 setAttr.length.HighPart = 0;
6980 /* now watch for a symlink */
6982 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6984 osi_assertx(dscp != NULL, "null cm_scache_t");
6985 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6987 /* we have a more accurate file to use (the
6988 * target of the symbolic link). Otherwise,
6989 * we'll just use the symlink anyway.
6991 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6993 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6994 cm_ReleaseSCache(scp);
6996 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
6999 cm_ReleaseSCache(dscp);
7001 cm_ReleaseSCache(scp);
7002 cm_ReleaseUser(userp);
7008 code = cm_SetAttr(scp, &setAttr, userp, &req);
7009 openAction = 3; /* truncated existing file */
7012 openAction = 1; /* found existing file */
7014 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7015 /* don't create if not found */
7017 cm_ReleaseSCache(dscp);
7019 cm_ReleaseSCache(scp);
7020 cm_ReleaseUser(userp);
7022 return CM_ERROR_NOSUCHFILE;
7023 } else if (realDirFlag == 0 || realDirFlag == -1) {
7024 osi_assertx(dscp != NULL, "null cm_scache_t");
7025 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
7026 osi_LogSaveString(smb_logp, lastNamep));
7027 openAction = 2; /* created file */
7028 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7029 setAttr.clientModTime = time(NULL);
7030 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
7033 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7034 smb_NotifyChange(FILE_ACTION_ADDED,
7035 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7036 dscp, lastNamep, NULL, TRUE);
7037 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7038 /* Not an exclusive create, and someone else tried
7039 * creating it already, then we open it anyway. We
7040 * don't bother retrying after this, since if this next
7041 * fails, that means that the file was deleted after we
7042 * started this call.
7044 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7047 if (createDisp == FILE_OVERWRITE_IF) {
7048 setAttr.mask = CM_ATTRMASK_LENGTH;
7049 setAttr.length.LowPart = 0;
7050 setAttr.length.HighPart = 0;
7052 /* now watch for a symlink */
7054 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7056 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7058 /* we have a more accurate file to use (the
7059 * target of the symbolic link). Otherwise,
7060 * we'll just use the symlink anyway.
7062 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7064 cm_ReleaseSCache(scp);
7068 code = cm_SetAttr(scp, &setAttr, userp, &req);
7070 } /* lookup succeeded */
7074 char *cp; /* This component */
7075 int clen = 0; /* length of component */
7076 cm_scache_t *tscp1, *tscp2;
7079 /* create directory */
7081 treeStartp = lastNamep;
7082 osi_assertx(dscp != NULL, "null cm_scache_t");
7083 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
7084 osi_LogSaveString(smb_logp, treeStartp));
7085 openAction = 2; /* created directory */
7087 /* if the request is to create the root directory
7088 * it will appear as a directory name of the nul-string
7089 * and a code of CM_ERROR_NOSUCHFILE
7091 if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
7092 code = CM_ERROR_EXISTS;
7094 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7095 setAttr.clientModTime = time(NULL);
7100 cm_HoldSCache(tscp1);
7104 tp = strchr(pp, '\\');
7107 clen = (int)strlen(cp);
7108 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
7110 clen = (int)(tp - pp);
7111 strncpy(cp,pp,clen);
7118 continue; /* the supplied path can't have consecutive slashes either , but */
7120 /* cp is the next component to be created. */
7121 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
7122 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
7123 smb_NotifyChange(FILE_ACTION_ADDED,
7124 FILE_NOTIFY_CHANGE_DIR_NAME,
7125 tscp1, cp, NULL, TRUE);
7127 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7128 /* Not an exclusive create, and someone else tried
7129 * creating it already, then we open it anyway. We
7130 * don't bother retrying after this, since if this next
7131 * fails, that means that the file was deleted after we
7132 * started this call.
7134 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
7135 userp, &req, &tscp2);
7140 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
7141 cm_ReleaseSCache(tscp1);
7142 tscp1 = tscp2; /* Newly created directory will be next parent */
7143 /* the hold is transfered to tscp1 from tscp2 */
7148 cm_ReleaseSCache(dscp);
7151 cm_ReleaseSCache(scp);
7154 * if we get here and code == 0, then scp is the last directory created, and dscp is the
7160 /* something went wrong creating or truncating the file */
7162 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7164 cm_ReleaseSCache(scp);
7166 cm_ReleaseSCache(dscp);
7167 cm_ReleaseUser(userp);
7172 /* make sure we have file vs. dir right (only applies for single component case) */
7173 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7174 /* now watch for a symlink */
7176 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7177 cm_scache_t * targetScp = 0;
7178 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7180 /* we have a more accurate file to use (the
7181 * target of the symbolic link). Otherwise,
7182 * we'll just use the symlink anyway.
7184 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
7186 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7187 cm_ReleaseSCache(scp);
7192 if (scp->fileType != CM_SCACHETYPE_FILE) {
7194 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7196 cm_ReleaseSCache(dscp);
7197 cm_ReleaseSCache(scp);
7198 cm_ReleaseUser(userp);
7200 return CM_ERROR_ISDIR;
7204 /* (only applies to single component case) */
7205 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7207 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7208 cm_ReleaseSCache(scp);
7210 cm_ReleaseSCache(dscp);
7211 cm_ReleaseUser(userp);
7213 return CM_ERROR_NOTDIR;
7216 /* open the file itself */
7217 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7218 osi_assertx(fidp, "null smb_fid_t");
7220 /* save a reference to the user */
7222 fidp->userp = userp;
7224 /* If we are restricting sharing, we should do so with a suitable
7226 if (scp->fileType == CM_SCACHETYPE_FILE &&
7227 !(fidflags & SMB_FID_SHARE_WRITE)) {
7229 LARGE_INTEGER LOffset, LLength;
7232 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7233 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7234 LLength.HighPart = 0;
7235 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7237 /* If we are not opening the file for writing, then we don't
7238 try to get an exclusive lock. No one else should be able to
7239 get an exclusive lock on the file anyway, although someone
7240 else can get a shared lock. */
7241 if ((fidflags & SMB_FID_SHARE_READ) ||
7242 !(fidflags & SMB_FID_OPENWRITE)) {
7243 sLockType = LOCKING_ANDX_SHARED_LOCK;
7248 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7250 lock_ObtainWrite(&scp->rw);
7251 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7252 lock_ReleaseWrite(&scp->rw);
7256 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7257 cm_ReleaseSCache(scp);
7259 cm_ReleaseSCache(dscp);
7260 cm_ReleaseUser(userp);
7261 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7262 smb_CloseFID(vcp, fidp, NULL, 0);
7263 smb_ReleaseFID(fidp);
7269 /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
7271 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7273 lock_ObtainMutex(&fidp->mx);
7274 /* save a pointer to the vnode */
7275 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
7276 lock_ObtainWrite(&scp->rw);
7277 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7278 lock_ReleaseWrite(&scp->rw);
7279 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
7281 fidp->flags = fidflags;
7283 /* remember if the file was newly created */
7285 fidp->flags |= SMB_FID_CREATED;
7287 /* save parent dir and pathname for delete or change notification */
7288 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7289 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
7290 fidp->flags |= SMB_FID_NTOPEN;
7291 fidp->NTopen_dscp = dscp;
7293 fidp->NTopen_pathp = strdup(lastNamep);
7295 fidp->NTopen_wholepathp = realPathp;
7296 lock_ReleaseMutex(&fidp->mx);
7298 /* we don't need this any longer */
7300 cm_ReleaseSCache(dscp);
7304 cm_Open(scp, 0, userp);
7306 /* set inp->fid so that later read calls in same msg can find fid */
7307 inp->fid = fidp->fid;
7311 lock_ObtainRead(&scp->rw);
7312 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7313 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7314 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7315 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7316 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7317 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7318 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7319 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7320 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7322 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7323 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7324 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
7325 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
7326 smb_SetSMBParmByte(outp, parmSlot,
7327 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7328 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7329 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7330 smb_SetSMBDataLength(outp, 0);
7332 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
7333 LargeIntegerGreaterThanZero(fidp->scp->length) &&
7334 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
7335 cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
7336 fidp->scp->length.LowPart, fidp->scp->length.HighPart,
7339 lock_ReleaseRead(&scp->rw);
7341 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
7342 osi_LogSaveString(smb_logp, realPathp));
7344 cm_ReleaseUser(userp);
7345 smb_ReleaseFID(fidp);
7347 /* Can't free realPathp if we get here since
7348 fidp->NTopen_wholepathp is pointing there */
7350 /* leave scp held since we put it in fidp->scp */
7355 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
7356 * Instead, ultimately, would like to use a subroutine for common code.
7358 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7360 char *pathp, *realPathp;
7364 cm_scache_t *dscp; /* parent dir */
7365 cm_scache_t *scp; /* file to create or open */
7366 cm_scache_t *targetScp; /* if scp is a symlink */
7369 unsigned long nameLength;
7371 unsigned int requestOpLock;
7372 unsigned int requestBatchOpLock;
7373 unsigned int mustBeDir;
7374 unsigned int extendedRespRequired;
7376 unsigned int desiredAccess;
7377 #ifdef DEBUG_VERBOSE
7378 unsigned int allocSize;
7380 unsigned int shareAccess;
7381 unsigned int extAttributes;
7382 unsigned int createDisp;
7383 #ifdef DEBUG_VERBOSE
7386 unsigned int createOptions;
7387 int initialModeBits;
7388 unsigned short baseFid;
7389 smb_fid_t *baseFidp;
7391 cm_scache_t *baseDirp;
7392 unsigned short openAction;
7398 int parmOffset, dataOffset;
7404 cm_lock_data_t *ldp = NULL;
7411 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7412 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7413 parmp = inp->data + parmOffset;
7414 lparmp = (ULONG *) parmp;
7417 requestOpLock = flags & REQUEST_OPLOCK;
7418 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7419 mustBeDir = flags & OPEN_DIRECTORY;
7420 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7423 * Why all of a sudden 32-bit FID?
7424 * We will reject all bits higher than 16.
7426 if (lparmp[1] & 0xFFFF0000)
7427 return CM_ERROR_INVAL;
7428 baseFid = (unsigned short)lparmp[1];
7429 desiredAccess = lparmp[2];
7430 #ifdef DEBUG_VERBOSE
7431 allocSize = lparmp[3];
7432 #endif /* DEBUG_VERSOSE */
7433 extAttributes = lparmp[5];
7434 shareAccess = lparmp[6];
7435 createDisp = lparmp[7];
7436 createOptions = lparmp[8];
7437 #ifdef DEBUG_VERBOSE
7440 nameLength = lparmp[11];
7442 #ifdef DEBUG_VERBOSE
7443 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
7444 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
7445 osi_Log1(smb_logp,"... flags[%x]",flags);
7448 /* mustBeDir is never set; createOptions directory bit seems to be
7451 if (createOptions & FILE_DIRECTORY_FILE)
7453 else if (createOptions & FILE_NON_DIRECTORY_FILE)
7459 * compute initial mode bits based on read-only flag in
7460 * extended attributes
7462 initialModeBits = 0666;
7463 if (extAttributes & SMB_ATTR_READONLY)
7464 initialModeBits &= ~0222;
7466 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
7467 /* Sometimes path is not null-terminated, so we make a copy. */
7468 realPathp = malloc(nameLength+1);
7469 memcpy(realPathp, pathp, nameLength);
7470 realPathp[nameLength] = 0;
7471 if (smb_StoreAnsiFilenames)
7472 OemToChar(realPathp,realPathp);
7474 spacep = cm_GetSpace();
7475 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
7478 * Nothing here to handle SMB_IOCTL_FILENAME.
7479 * Will add it if necessary.
7482 #ifdef DEBUG_VERBOSE
7484 char *hexp, *asciip;
7485 asciip = (lastNamep? lastNamep : realPathp);
7486 hexp = osi_HexifyString( asciip );
7487 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
7492 userp = smb_GetUserFromVCP(vcp, inp);
7494 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
7496 return CM_ERROR_INVAL;
7501 baseDirp = cm_data.rootSCachep;
7502 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7503 if (code == CM_ERROR_TIDIPC) {
7504 /* Attempt to use a TID allocated for IPC. The client
7505 * is probably looking for DCE RPC end points which we
7506 * don't support OR it could be looking to make a DFS
7509 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
7512 cm_ReleaseUser(userp);
7513 return CM_ERROR_NOSUCHPATH;
7517 baseFidp = smb_FindFID(vcp, baseFid, 0);
7519 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
7521 cm_ReleaseUser(userp);
7522 return CM_ERROR_BADFD;
7525 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7527 cm_ReleaseUser(userp);
7528 smb_CloseFID(vcp, baseFidp, NULL, 0);
7529 smb_ReleaseFID(baseFidp);
7530 return CM_ERROR_NOSUCHPATH;
7533 baseDirp = baseFidp->scp;
7537 /* compute open mode */
7539 if (desiredAccess & DELETE)
7540 fidflags |= SMB_FID_OPENDELETE;
7541 if (desiredAccess & AFS_ACCESS_READ)
7542 fidflags |= SMB_FID_OPENREAD_LISTDIR;
7543 if (desiredAccess & AFS_ACCESS_WRITE)
7544 fidflags |= SMB_FID_OPENWRITE;
7545 if (createOptions & FILE_DELETE_ON_CLOSE)
7546 fidflags |= SMB_FID_DELONCLOSE;
7547 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7548 fidflags |= SMB_FID_SEQUENTIAL;
7549 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7550 fidflags |= SMB_FID_RANDOM;
7551 if (smb_IsExecutableFileName(lastNamep))
7552 fidflags |= SMB_FID_EXECUTABLE;
7554 /* And the share mode */
7555 if (shareAccess & FILE_SHARE_READ)
7556 fidflags |= SMB_FID_SHARE_READ;
7557 if (shareAccess & FILE_SHARE_WRITE)
7558 fidflags |= SMB_FID_SHARE_WRITE;
7562 if ( createDisp == FILE_OPEN ||
7563 createDisp == FILE_OVERWRITE ||
7564 createDisp == FILE_OVERWRITE_IF) {
7565 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7566 userp, tidPathp, &req, &dscp);
7569 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7570 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
7571 cm_ReleaseSCache(dscp);
7572 cm_ReleaseUser(userp);
7575 smb_ReleaseFID(baseFidp);
7576 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7577 return CM_ERROR_PATH_NOT_COVERED;
7579 return CM_ERROR_BADSHARENAME;
7581 #endif /* DFS_SUPPORT */
7582 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7584 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7585 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7586 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7587 if (code == 0 && realDirFlag == 1) {
7588 cm_ReleaseSCache(scp);
7589 cm_ReleaseSCache(dscp);
7590 cm_ReleaseUser(userp);
7593 smb_ReleaseFID(baseFidp);
7594 return CM_ERROR_EXISTS;
7600 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7601 userp, tidPathp, &req, &scp);
7603 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7604 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7605 cm_ReleaseSCache(scp);
7606 cm_ReleaseUser(userp);
7609 smb_ReleaseFID(baseFidp);
7610 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7611 return CM_ERROR_PATH_NOT_COVERED;
7613 return CM_ERROR_BADSHARENAME;
7615 #endif /* DFS_SUPPORT */
7621 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7622 /* look up parent directory */
7624 code = cm_NameI(baseDirp, spacep->data,
7625 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7626 userp, tidPathp, &req, &dscp);
7628 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7629 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
7630 cm_ReleaseSCache(dscp);
7631 cm_ReleaseUser(userp);
7634 smb_ReleaseFID(baseFidp);
7635 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7636 return CM_ERROR_PATH_NOT_COVERED;
7638 return CM_ERROR_BADSHARENAME;
7640 #endif /* DFS_SUPPORT */
7644 cm_FreeSpace(spacep);
7647 smb_ReleaseFID(baseFidp);
7650 cm_ReleaseUser(userp);
7656 lastNamep = realPathp;
7660 if (!smb_IsLegalFilename(lastNamep))
7661 return CM_ERROR_BADNTFILENAME;
7664 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
7665 code = cm_Lookup(dscp, lastNamep,
7666 CM_FLAG_FOLLOW, userp, &req, &scp);
7668 code = cm_Lookup(dscp, lastNamep,
7669 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7672 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7673 cm_ReleaseSCache(dscp);
7674 cm_ReleaseUser(userp);
7681 smb_ReleaseFID(baseFidp);
7682 cm_FreeSpace(spacep);
7685 /* if we get here, if code is 0, the file exists and is represented by
7686 * scp. Otherwise, we have to create it. The dir may be represented
7687 * by dscp, or we may have found the file directly. If code is non-zero,
7691 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7694 cm_ReleaseSCache(dscp);
7695 cm_ReleaseSCache(scp);
7696 cm_ReleaseUser(userp);
7701 if (createDisp == FILE_CREATE) {
7702 /* oops, file shouldn't be there */
7703 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7705 cm_ReleaseSCache(dscp);
7706 cm_ReleaseSCache(scp);
7707 cm_ReleaseUser(userp);
7709 return CM_ERROR_EXISTS;
7712 if (createDisp == FILE_OVERWRITE ||
7713 createDisp == FILE_OVERWRITE_IF) {
7714 setAttr.mask = CM_ATTRMASK_LENGTH;
7715 setAttr.length.LowPart = 0;
7716 setAttr.length.HighPart = 0;
7718 /* now watch for a symlink */
7720 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7722 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7724 /* we have a more accurate file to use (the
7725 * target of the symbolic link). Otherwise,
7726 * we'll just use the symlink anyway.
7728 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7730 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7731 cm_ReleaseSCache(scp);
7733 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7736 cm_ReleaseSCache(dscp);
7738 cm_ReleaseSCache(scp);
7739 cm_ReleaseUser(userp);
7745 code = cm_SetAttr(scp, &setAttr, userp, &req);
7746 openAction = 3; /* truncated existing file */
7748 else openAction = 1; /* found existing file */
7750 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7751 /* don't create if not found */
7753 cm_ReleaseSCache(dscp);
7754 cm_ReleaseUser(userp);
7756 return CM_ERROR_NOSUCHFILE;
7758 else if (realDirFlag == 0 || realDirFlag == -1) {
7759 osi_assertx(dscp != NULL, "null cm_scache_t");
7760 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
7761 osi_LogSaveString(smb_logp, lastNamep));
7762 openAction = 2; /* created file */
7763 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7764 setAttr.clientModTime = time(NULL);
7765 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7769 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7770 smb_NotifyChange(FILE_ACTION_ADDED,
7771 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7772 dscp, lastNamep, NULL, TRUE);
7773 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7774 /* Not an exclusive create, and someone else tried
7775 * creating it already, then we open it anyway. We
7776 * don't bother retrying after this, since if this next
7777 * fails, that means that the file was deleted after we
7778 * started this call.
7780 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7783 if (createDisp == FILE_OVERWRITE_IF) {
7784 setAttr.mask = CM_ATTRMASK_LENGTH;
7785 setAttr.length.LowPart = 0;
7786 setAttr.length.HighPart = 0;
7788 /* now watch for a symlink */
7790 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7792 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7794 /* we have a more accurate file to use (the
7795 * target of the symbolic link). Otherwise,
7796 * we'll just use the symlink anyway.
7798 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7800 cm_ReleaseSCache(scp);
7804 code = cm_SetAttr(scp, &setAttr, userp, &req);
7806 } /* lookup succeeded */
7809 /* create directory */
7810 osi_assertx(dscp != NULL, "null cm_scache_t");
7812 "smb_ReceiveNTTranCreate creating directory %s",
7813 osi_LogSaveString(smb_logp, lastNamep));
7814 openAction = 2; /* created directory */
7815 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7816 setAttr.clientModTime = time(NULL);
7817 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
7818 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7819 smb_NotifyChange(FILE_ACTION_ADDED,
7820 FILE_NOTIFY_CHANGE_DIR_NAME,
7821 dscp, lastNamep, NULL, TRUE);
7823 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7824 /* Not an exclusive create, and someone else tried
7825 * creating it already, then we open it anyway. We
7826 * don't bother retrying after this, since if this next
7827 * fails, that means that the file was deleted after we
7828 * started this call.
7830 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7836 /* something went wrong creating or truncating the file */
7838 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7840 cm_ReleaseSCache(scp);
7841 cm_ReleaseUser(userp);
7846 /* make sure we have file vs. dir right */
7847 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7848 /* now watch for a symlink */
7850 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7852 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7854 /* we have a more accurate file to use (the
7855 * target of the symbolic link). Otherwise,
7856 * we'll just use the symlink anyway.
7858 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7861 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7862 cm_ReleaseSCache(scp);
7867 if (scp->fileType != CM_SCACHETYPE_FILE) {
7869 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7870 cm_ReleaseSCache(scp);
7871 cm_ReleaseUser(userp);
7873 return CM_ERROR_ISDIR;
7877 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7879 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7880 cm_ReleaseSCache(scp);
7881 cm_ReleaseUser(userp);
7883 return CM_ERROR_NOTDIR;
7886 /* open the file itself */
7887 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7888 osi_assertx(fidp, "null smb_fid_t");
7890 /* save a reference to the user */
7892 fidp->userp = userp;
7894 /* If we are restricting sharing, we should do so with a suitable
7896 if (scp->fileType == CM_SCACHETYPE_FILE &&
7897 !(fidflags & SMB_FID_SHARE_WRITE)) {
7899 LARGE_INTEGER LOffset, LLength;
7902 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7903 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7904 LLength.HighPart = 0;
7905 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7907 /* Similar to what we do in handling NTCreateX. We get a
7908 shared lock if we are only opening the file for reading. */
7909 if ((fidflags & SMB_FID_SHARE_READ) ||
7910 !(fidflags & SMB_FID_OPENWRITE)) {
7911 sLockType = LOCKING_ANDX_SHARED_LOCK;
7916 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7918 lock_ObtainWrite(&scp->rw);
7919 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7920 lock_ReleaseWrite(&scp->rw);
7924 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7925 cm_ReleaseSCache(scp);
7926 cm_ReleaseUser(userp);
7927 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7928 smb_CloseFID(vcp, fidp, NULL, 0);
7929 smb_ReleaseFID(fidp);
7931 return CM_ERROR_SHARING_VIOLATION;
7935 /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
7937 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7939 lock_ObtainMutex(&fidp->mx);
7940 /* save a pointer to the vnode */
7942 lock_ObtainWrite(&scp->rw);
7943 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7944 lock_ReleaseWrite(&scp->rw);
7945 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
7947 fidp->flags = fidflags;
7949 /* remember if the file was newly created */
7951 fidp->flags |= SMB_FID_CREATED;
7953 /* save parent dir and pathname for deletion or change notification */
7954 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7955 fidp->flags |= SMB_FID_NTOPEN;
7956 fidp->NTopen_dscp = dscp;
7957 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
7959 fidp->NTopen_pathp = strdup(lastNamep);
7961 fidp->NTopen_wholepathp = realPathp;
7962 lock_ReleaseMutex(&fidp->mx);
7964 /* we don't need this any longer */
7966 cm_ReleaseSCache(dscp);
7968 cm_Open(scp, 0, userp);
7970 /* set inp->fid so that later read calls in same msg can find fid */
7971 inp->fid = fidp->fid;
7973 /* check whether we are required to send an extended response */
7974 if (!extendedRespRequired) {
7976 parmOffset = 8*4 + 39;
7977 parmOffset += 1; /* pad to 4 */
7978 dataOffset = parmOffset + 70;
7982 /* Total Parameter Count */
7983 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7984 /* Total Data Count */
7985 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7986 /* Parameter Count */
7987 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7988 /* Parameter Offset */
7989 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7990 /* Parameter Displacement */
7991 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7993 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7995 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7996 /* Data Displacement */
7997 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7998 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7999 smb_SetSMBDataLength(outp, 70);
8001 lock_ObtainRead(&scp->rw);
8002 outData = smb_GetSMBData(outp, NULL);
8003 outData++; /* round to get to parmOffset */
8004 *outData = 0; outData++; /* oplock */
8005 *outData = 0; outData++; /* reserved */
8006 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8007 *((ULONG *)outData) = openAction; outData += 4;
8008 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8009 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8010 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8011 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8012 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8013 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8014 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8015 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8016 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8017 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8018 *((USHORT *)outData) = 0; outData += 2; /* dev state */
8019 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8020 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8021 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8022 outData += 2; /* is a dir? */
8025 parmOffset = 8*4 + 39;
8026 parmOffset += 1; /* pad to 4 */
8027 dataOffset = parmOffset + 104;
8031 /* Total Parameter Count */
8032 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8033 /* Total Data Count */
8034 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8035 /* Parameter Count */
8036 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8037 /* Parameter Offset */
8038 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8039 /* Parameter Displacement */
8040 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8042 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8044 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8045 /* Data Displacement */
8046 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8047 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8048 smb_SetSMBDataLength(outp, 105);
8050 lock_ObtainRead(&scp->rw);
8051 outData = smb_GetSMBData(outp, NULL);
8052 outData++; /* round to get to parmOffset */
8053 *outData = 0; outData++; /* oplock */
8054 *outData = 1; outData++; /* response type */
8055 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8056 *((ULONG *)outData) = openAction; outData += 4;
8057 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8058 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8059 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8060 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8061 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8062 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8063 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8064 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8065 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8066 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8067 *((USHORT *)outData) = 0; outData += 2; /* dev state */
8068 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8069 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8070 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8071 outData += 1; /* is a dir? */
8072 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
8073 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
8074 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
8077 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
8078 LargeIntegerGreaterThanZero(fidp->scp->length) &&
8079 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
8080 cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
8081 fidp->scp->length.LowPart, fidp->scp->length.HighPart,
8084 lock_ReleaseRead(&scp->rw);
8086 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
8088 cm_ReleaseUser(userp);
8089 smb_ReleaseFID(fidp);
8091 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
8092 /* leave scp held since we put it in fidp->scp */
8096 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
8099 smb_packet_t *savedPacketp;
8101 USHORT fid, watchtree;
8105 filter = smb_GetSMBParm(inp, 19) |
8106 (smb_GetSMBParm(inp, 20) << 16);
8107 fid = smb_GetSMBParm(inp, 21);
8108 watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
8110 fidp = smb_FindFID(vcp, fid, 0);
8112 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
8113 return CM_ERROR_BADFD;
8116 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8117 smb_CloseFID(vcp, fidp, NULL, 0);
8118 smb_ReleaseFID(fidp);
8119 return CM_ERROR_NOSUCHFILE;
8122 /* Create a copy of the Directory Watch Packet to use when sending the
8123 * notification if in the future a matching change is detected.
8125 savedPacketp = smb_CopyPacket(inp);
8127 if (savedPacketp->vcp)
8128 smb_ReleaseVC(savedPacketp->vcp);
8129 savedPacketp->vcp = vcp;
8131 /* Add the watch to the list of events to send notifications for */
8132 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8133 savedPacketp->nextp = smb_Directory_Watches;
8134 smb_Directory_Watches = savedPacketp;
8135 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8138 osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%s\"",
8139 fidp, scp, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
8140 osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
8141 filter, fid, watchtree);
8142 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8143 osi_Log0(smb_logp, " Notify Change File Name");
8144 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8145 osi_Log0(smb_logp, " Notify Change Directory Name");
8146 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8147 osi_Log0(smb_logp, " Notify Change Attributes");
8148 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8149 osi_Log0(smb_logp, " Notify Change Size");
8150 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8151 osi_Log0(smb_logp, " Notify Change Last Write");
8152 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8153 osi_Log0(smb_logp, " Notify Change Last Access");
8154 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8155 osi_Log0(smb_logp, " Notify Change Creation");
8156 if (filter & FILE_NOTIFY_CHANGE_EA)
8157 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8158 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8159 osi_Log0(smb_logp, " Notify Change Security");
8160 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8161 osi_Log0(smb_logp, " Notify Change Stream Name");
8162 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8163 osi_Log0(smb_logp, " Notify Change Stream Size");
8164 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8165 osi_Log0(smb_logp, " Notify Change Stream Write");
8167 lock_ObtainWrite(&scp->rw);
8169 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
8171 scp->flags |= CM_SCACHEFLAG_WATCHED;
8172 lock_ReleaseWrite(&scp->rw);
8173 smb_ReleaseFID(fidp);
8175 outp->flags |= SMB_PACKETFLAG_NOSEND;
8179 unsigned char nullSecurityDesc[36] = {
8180 0x01, /* security descriptor revision */
8181 0x00, /* reserved, should be zero */
8182 0x00, 0x80, /* security descriptor control;
8183 * 0x8000 : self-relative format */
8184 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
8185 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
8186 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
8187 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
8188 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8189 /* "null SID" owner SID */
8190 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
8191 /* "null SID" group SID */
8194 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8196 int parmOffset, parmCount, dataOffset, dataCount;
8204 ULONG securityInformation;
8206 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8207 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8208 parmp = inp->data + parmOffset;
8209 sparmp = (USHORT *) parmp;
8210 lparmp = (ULONG *) parmp;
8213 securityInformation = lparmp[1];
8215 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
8216 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
8224 parmOffset = 8*4 + 39;
8225 parmOffset += 1; /* pad to 4 */
8227 dataOffset = parmOffset + parmCount;
8231 /* Total Parameter Count */
8232 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8233 /* Total Data Count */
8234 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8235 /* Parameter Count */
8236 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8237 /* Parameter Offset */
8238 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8239 /* Parameter Displacement */
8240 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8242 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8244 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8245 /* Data Displacement */
8246 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8247 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8248 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
8250 outData = smb_GetSMBData(outp, NULL);
8251 outData++; /* round to get to parmOffset */
8252 *((ULONG *)outData) = 36; outData += 4; /* length */
8254 if (maxData >= 36) {
8255 memcpy(outData, nullSecurityDesc, 36);
8259 return CM_ERROR_BUFFERTOOSMALL;
8262 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8264 unsigned short function;
8266 function = smb_GetSMBParm(inp, 18);
8268 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
8270 /* We can handle long names */
8271 if (vcp->flags & SMB_VCFLAG_USENT)
8272 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
8276 return smb_ReceiveNTTranCreate(vcp, inp, outp);
8278 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
8281 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
8284 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
8286 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
8289 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
8291 osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
8294 osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
8297 return CM_ERROR_INVAL;
8301 * smb_NotifyChange -- find relevant change notification messages and
8304 * If we don't know the file name (i.e. a callback break), filename is
8305 * NULL, and we return a zero-length list.
8307 * At present there is not a single call to smb_NotifyChange that
8308 * has the isDirectParent parameter set to FALSE.
8310 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
8311 cm_scache_t *dscp, char *filename, char *otherFilename,
8312 BOOL isDirectParent)
8314 smb_packet_t *watch, *lastWatch, *nextWatch;
8315 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
8316 char *outData, *oldOutData;
8320 BOOL twoEntries = FALSE;
8321 ULONG otherNameLen, oldParmCount = 0;
8325 /* Get ready for rename within directory */
8326 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
8328 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
8331 osi_Log4(smb_logp,"in smb_NotifyChange for file [%s] dscp [%p] notification 0x%x parent %d",
8332 osi_LogSaveString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
8334 osi_Log0(smb_logp," FILE_ACTION_NONE");
8335 if (action == FILE_ACTION_ADDED)
8336 osi_Log0(smb_logp," FILE_ACTION_ADDED");
8337 if (action == FILE_ACTION_REMOVED)
8338 osi_Log0(smb_logp," FILE_ACTION_REMOVED");
8339 if (action == FILE_ACTION_MODIFIED)
8340 osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
8341 if (action == FILE_ACTION_RENAMED_OLD_NAME)
8342 osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
8343 if (action == FILE_ACTION_RENAMED_NEW_NAME)
8344 osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
8346 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8347 watch = smb_Directory_Watches;
8349 filter = smb_GetSMBParm(watch, 19)
8350 | (smb_GetSMBParm(watch, 20) << 16);
8351 fid = smb_GetSMBParm(watch, 21);
8352 wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
8354 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
8355 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
8358 * Strange hack - bug in NT Client and NT Server that we must emulate?
8360 if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
8361 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
8363 fidp = smb_FindFID(watch->vcp, fid, 0);
8365 osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
8367 watch = watch->nextp;
8371 if (fidp->scp != dscp ||
8372 fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
8373 (filter & notifyFilter) == 0 ||
8374 (!isDirectParent && !wtree))
8376 osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
8377 smb_ReleaseFID(fidp);
8379 watch = watch->nextp;
8382 smb_ReleaseFID(fidp);
8385 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
8386 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
8387 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8388 osi_Log0(smb_logp, " Notify Change File Name");
8389 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8390 osi_Log0(smb_logp, " Notify Change Directory Name");
8391 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8392 osi_Log0(smb_logp, " Notify Change Attributes");
8393 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8394 osi_Log0(smb_logp, " Notify Change Size");
8395 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8396 osi_Log0(smb_logp, " Notify Change Last Write");
8397 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8398 osi_Log0(smb_logp, " Notify Change Last Access");
8399 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8400 osi_Log0(smb_logp, " Notify Change Creation");
8401 if (filter & FILE_NOTIFY_CHANGE_EA)
8402 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8403 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8404 osi_Log0(smb_logp, " Notify Change Security");
8405 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8406 osi_Log0(smb_logp, " Notify Change Stream Name");
8407 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8408 osi_Log0(smb_logp, " Notify Change Stream Size");
8409 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8410 osi_Log0(smb_logp, " Notify Change Stream Write");
8412 /* A watch can only be notified once. Remove it from the list */
8413 nextWatch = watch->nextp;
8414 if (watch == smb_Directory_Watches)
8415 smb_Directory_Watches = nextWatch;
8417 lastWatch->nextp = nextWatch;
8419 /* Turn off WATCHED flag in dscp */
8420 lock_ObtainWrite(&dscp->rw);
8422 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8424 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
8425 lock_ReleaseWrite(&dscp->rw);
8427 /* Convert to response packet */
8428 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
8429 #ifdef SEND_CANONICAL_PATHNAMES
8430 ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
8432 ((smb_t *) watch)->wct = 0;
8435 if (filename == NULL)
8438 nameLen = (ULONG)strlen(filename);
8439 parmCount = 3*4 + nameLen*2;
8440 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8442 otherNameLen = (ULONG)strlen(otherFilename);
8443 oldParmCount = parmCount;
8444 parmCount += 3*4 + otherNameLen*2;
8445 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8447 if (maxLen < parmCount)
8448 parmCount = 0; /* not enough room */
8450 parmOffset = 8*4 + 39;
8451 parmOffset += 1; /* pad to 4 */
8452 dataOffset = parmOffset + parmCount;
8456 /* Total Parameter Count */
8457 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8458 /* Total Data Count */
8459 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8460 /* Parameter Count */
8461 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8462 /* Parameter Offset */
8463 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
8464 /* Parameter Displacement */
8465 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8467 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8469 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
8470 /* Data Displacement */
8471 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8472 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
8473 smb_SetSMBDataLength(watch, parmCount + 1);
8475 if (parmCount != 0) {
8477 outData = smb_GetSMBData(watch, NULL);
8478 outData++; /* round to get to parmOffset */
8479 oldOutData = outData;
8480 *((DWORD *)outData) = oldParmCount; outData += 4;
8481 /* Next Entry Offset */
8482 *((DWORD *)outData) = action; outData += 4;
8484 *((DWORD *)outData) = nameLen*2; outData += 4;
8485 /* File Name Length */
8486 p = strdup(filename);
8487 if (smb_StoreAnsiFilenames)
8489 mbstowcs((WCHAR *)outData, p, nameLen);
8493 outData = oldOutData + oldParmCount;
8494 *((DWORD *)outData) = 0; outData += 4;
8495 /* Next Entry Offset */
8496 *((DWORD *)outData) = otherAction; outData += 4;
8498 *((DWORD *)outData) = otherNameLen*2;
8499 outData += 4; /* File Name Length */
8500 p = strdup(otherFilename);
8501 if (smb_StoreAnsiFilenames)
8503 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
8509 * If filename is null, we don't know the cause of the
8510 * change notification. We return zero data (see above),
8511 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
8512 * (= 0x010C). We set the error code here by hand, without
8513 * modifying wct and bcc.
8515 if (filename == NULL) {
8516 ((smb_t *) watch)->rcls = 0x0C;
8517 ((smb_t *) watch)->reh = 0x01;
8518 ((smb_t *) watch)->errLow = 0;
8519 ((smb_t *) watch)->errHigh = 0;
8520 /* Set NT Status codes flag */
8521 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8524 smb_SendPacket(watch->vcp, watch);
8525 smb_FreePacket(watch);
8528 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8531 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8533 unsigned char *replyWctp;
8534 smb_packet_t *watch, *lastWatch;
8535 USHORT fid, watchtree;
8539 osi_Log0(smb_logp, "SMB3 receive NT cancel");
8541 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8542 watch = smb_Directory_Watches;
8544 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
8545 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
8546 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
8547 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
8548 if (watch == smb_Directory_Watches)
8549 smb_Directory_Watches = watch->nextp;
8551 lastWatch->nextp = watch->nextp;
8552 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8554 /* Turn off WATCHED flag in scp */
8555 fid = smb_GetSMBParm(watch, 21);
8556 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
8558 if (vcp != watch->vcp)
8559 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
8562 fidp = smb_FindFID(vcp, fid, 0);
8564 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
8566 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
8569 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
8570 lock_ObtainWrite(&scp->rw);
8572 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8574 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
8575 lock_ReleaseWrite(&scp->rw);
8576 smb_ReleaseFID(fidp);
8578 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
8581 /* assume STATUS32; return 0xC0000120 (CANCELED) */
8582 replyWctp = watch->wctp;
8586 ((smb_t *)watch)->rcls = 0x20;
8587 ((smb_t *)watch)->reh = 0x1;
8588 ((smb_t *)watch)->errLow = 0;
8589 ((smb_t *)watch)->errHigh = 0xC0;
8590 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8591 smb_SendPacket(vcp, watch);
8592 smb_FreePacket(watch);
8596 watch = watch->nextp;
8598 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8604 * NT rename also does hard links.
8607 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
8608 #define RENAME_FLAG_HARD_LINK 0x103
8609 #define RENAME_FLAG_RENAME 0x104
8610 #define RENAME_FLAG_COPY 0x105
8612 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8614 char *oldPathp, *newPathp;
8620 attrs = smb_GetSMBParm(inp, 0);
8621 rename_type = smb_GetSMBParm(inp, 1);
8623 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
8624 osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
8625 return CM_ERROR_NOACCESS;
8628 tp = smb_GetSMBData(inp, NULL);
8629 oldPathp = smb_ParseASCIIBlock(tp, &tp);
8630 if (smb_StoreAnsiFilenames)
8631 OemToChar(oldPathp,oldPathp);
8632 newPathp = smb_ParseASCIIBlock(tp, &tp);
8633 if (smb_StoreAnsiFilenames)
8634 OemToChar(newPathp,newPathp);
8636 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
8637 osi_LogSaveString(smb_logp, oldPathp),
8638 osi_LogSaveString(smb_logp, newPathp),
8639 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
8641 if (rename_type == RENAME_FLAG_RENAME) {
8642 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
8643 } else { /* RENAME_FLAG_HARD_LINK */
8644 code = smb_Link(vcp,inp,oldPathp,newPathp);
8651 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
8654 cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
8656 smb_username_t *unp;
8659 unp = smb_FindUserByName(usern, machine, flags);
8661 lock_ObtainMutex(&unp->mx);
8662 unp->userp = cm_NewUser();
8663 lock_ReleaseMutex(&unp->mx);
8664 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
8666 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
8670 smb_ReleaseUsername(unp);