2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
15 #pragma warning(disable: 4005)
17 #define SECURITY_WIN32
29 #include <WINNT\afsreg.h>
33 extern osi_hyper_t hzero;
35 smb_packet_t *smb_Directory_Watches = NULL;
36 osi_mutex_t smb_Dir_Watch_Lock;
38 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
40 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
42 /* protected by the smb_globalLock */
43 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
45 const char **smb_ExecutableExtensions = NULL;
47 /* retrieve a held reference to a user structure corresponding to an incoming
49 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
54 uidp = smb_FindUID(vcp, inp->uid, 0);
58 up = smb_GetUserFromUID(uidp);
66 * Return boolean specifying if the path name is thought to be an
67 * executable file. For now .exe or .dll.
69 afs_uint32 smb_IsExecutableFileName(const char *name)
73 if ( smb_ExecutableExtensions == NULL || name == NULL)
78 for ( i=0; smb_ExecutableExtensions[i]; i++) {
79 j = len - strlen(smb_ExecutableExtensions[i]);
80 if (_stricmp(smb_ExecutableExtensions[i], &name[j]) == 0)
88 * Return extended attributes.
89 * Right now, we aren't using any of the "new" bits, so this looks exactly
90 * like smb_Attributes() (see smb.c).
92 unsigned long smb_ExtAttributes(cm_scache_t *scp)
96 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
97 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
98 scp->fileType == CM_SCACHETYPE_INVALID)
100 attrs = SMB_ATTR_DIRECTORY;
101 #ifdef SPECIAL_FOLDERS
102 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
103 #endif /* SPECIAL_FOLDERS */
104 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
105 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
109 * We used to mark a file RO if it was in an RO volume, but that
110 * turns out to be impolitic in NT. See defect 10007.
113 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
114 attrs |= SMB_ATTR_READONLY; /* Read-only */
116 if ((scp->unixModeBits & 0222) == 0)
117 attrs |= SMB_ATTR_READONLY; /* Read-only */
121 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
126 int smb_V3IsStarMask(char *maskp)
130 while (tc = *maskp++)
131 if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
136 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
139 /* skip over null-terminated string */
140 *chainpp = inp + strlen(inp) + 1;
145 void OutputDebugF(char * format, ...) {
150 va_start( args, format );
151 len = _vscprintf( format, args ) // _vscprintf doesn't count
152 + 3; // terminating '\0' + '\n'
153 buffer = malloc( len * sizeof(char) );
154 vsprintf( buffer, format, args );
155 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buffer));
156 strcat(buffer, "\n");
157 OutputDebugString(buffer);
161 void OutputDebugHexDump(unsigned char * buffer, int len) {
164 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
166 OutputDebugF("Hexdump length [%d]",len);
168 for (i=0;i<len;i++) {
171 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
173 OutputDebugString(buf);
175 sprintf(buf,"%5x",i);
176 memset(buf+5,' ',80);
181 j = j*3 + 7 + ((j>7)?1:0);
184 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
187 j = j + 56 + ((j>7)?1:0);
189 buf[j] = (k>32 && k<127)?k:'.';
192 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
194 OutputDebugString(buf);
198 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
200 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
201 SECURITY_STATUS status, istatus;
202 CredHandle creds = {0,0};
204 SecBufferDesc secOut;
212 OutputDebugF("Negotiating Extended Security");
214 status = AcquireCredentialsHandle( NULL,
215 SMB_EXT_SEC_PACKAGE_NAME,
224 if (status != SEC_E_OK) {
225 /* Really bad. We return an empty security blob */
226 OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
231 secOut.pBuffers = &secTok;
232 secOut.ulVersion = SECBUFFER_VERSION;
234 secTok.BufferType = SECBUFFER_TOKEN;
236 secTok.pvBuffer = NULL;
238 ctx.dwLower = ctx.dwUpper = 0;
240 status = AcceptSecurityContext( &creds,
243 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
244 SECURITY_NETWORK_DREP,
251 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
252 OutputDebugF("Completing token...");
253 istatus = CompleteAuthToken(&ctx, &secOut);
254 if ( istatus != SEC_E_OK )
255 OutputDebugF("Token completion failed: %x", istatus);
258 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
259 if (secTok.pvBuffer) {
260 *secBlobLength = secTok.cbBuffer;
261 *secBlob = malloc( secTok.cbBuffer );
262 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
265 if ( status != SEC_E_OK )
266 OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
269 /* Discard partial security context */
270 DeleteSecurityContext(&ctx);
272 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
274 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
275 FreeCredentialsHandle(&creds);
281 struct smb_ext_context {
288 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
289 SECURITY_STATUS status, istatus;
293 SecBufferDesc secBufIn;
295 SecBufferDesc secBufOut;
298 struct smb_ext_context * secCtx = NULL;
299 struct smb_ext_context * newSecCtx = NULL;
300 void * assembledBlob = NULL;
301 int assembledBlobLength = 0;
304 OutputDebugF("In smb_AuthenticateUserExt");
307 *secBlobOutLength = 0;
309 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
310 secCtx = vcp->secCtx;
311 lock_ObtainMutex(&vcp->mx);
312 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
314 lock_ReleaseMutex(&vcp->mx);
318 OutputDebugF("Received incoming token:");
319 OutputDebugHexDump(secBlobIn,secBlobInLength);
323 OutputDebugF("Continuing with existing context.");
324 creds = secCtx->creds;
327 if (secCtx->partialToken) {
328 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
329 assembledBlob = malloc(assembledBlobLength);
330 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
331 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
334 status = AcquireCredentialsHandle( NULL,
335 SMB_EXT_SEC_PACKAGE_NAME,
344 if (status != SEC_E_OK) {
345 OutputDebugF("Can't acquire Credentials handle [%lX]", status);
346 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
354 secBufIn.cBuffers = 1;
355 secBufIn.pBuffers = &secTokIn;
356 secBufIn.ulVersion = SECBUFFER_VERSION;
358 secTokIn.BufferType = SECBUFFER_TOKEN;
360 secTokIn.cbBuffer = assembledBlobLength;
361 secTokIn.pvBuffer = assembledBlob;
363 secTokIn.cbBuffer = secBlobInLength;
364 secTokIn.pvBuffer = secBlobIn;
367 secBufOut.cBuffers = 1;
368 secBufOut.pBuffers = &secTokOut;
369 secBufOut.ulVersion = SECBUFFER_VERSION;
371 secTokOut.BufferType = SECBUFFER_TOKEN;
372 secTokOut.cbBuffer = 0;
373 secTokOut.pvBuffer = NULL;
375 status = AcceptSecurityContext( &creds,
376 ((secCtx)?&ctx:NULL),
378 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
379 SECURITY_NETWORK_DREP,
386 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
387 OutputDebugF("Completing token...");
388 istatus = CompleteAuthToken(&ctx, &secBufOut);
389 if ( istatus != SEC_E_OK )
390 OutputDebugF("Token completion failed: %lX", istatus);
393 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
394 OutputDebugF("Continue needed");
396 newSecCtx = malloc(sizeof(*newSecCtx));
398 newSecCtx->creds = creds;
399 newSecCtx->ctx = ctx;
400 newSecCtx->partialToken = NULL;
401 newSecCtx->partialTokenLen = 0;
403 lock_ObtainMutex( &vcp->mx );
404 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
405 vcp->secCtx = newSecCtx;
406 lock_ReleaseMutex( &vcp->mx );
408 code = CM_ERROR_GSSCONTINUE;
411 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
412 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
413 secTokOut.pvBuffer) {
414 OutputDebugF("Need to send token back to client");
416 *secBlobOutLength = secTokOut.cbBuffer;
417 *secBlobOut = malloc(secTokOut.cbBuffer);
418 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
420 OutputDebugF("Outgoing token:");
421 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
422 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
423 OutputDebugF("Incomplete message");
425 newSecCtx = malloc(sizeof(*newSecCtx));
427 newSecCtx->creds = creds;
428 newSecCtx->ctx = ctx;
429 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
430 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
431 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
433 lock_ObtainMutex( &vcp->mx );
434 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
435 vcp->secCtx = newSecCtx;
436 lock_ReleaseMutex( &vcp->mx );
438 code = CM_ERROR_GSSCONTINUE;
441 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
443 SecPkgContext_Names names;
445 OutputDebugF("Authentication completed");
446 OutputDebugF("Returned flags : [%lX]", flags);
448 if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
449 OutputDebugF("Received name [%s]", names.sUserName);
450 strcpy(usern, names.sUserName);
451 strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
452 FreeContextBuffer(names.sUserName);
454 /* Force the user to retry if the context is invalid */
455 OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
456 code = CM_ERROR_BADPASSWORD;
460 case SEC_E_INVALID_TOKEN:
461 OutputDebugF("Returning bad password :: INVALID_TOKEN");
463 case SEC_E_INVALID_HANDLE:
464 OutputDebugF("Returning bad password :: INVALID_HANDLE");
466 case SEC_E_LOGON_DENIED:
467 OutputDebugF("Returning bad password :: LOGON_DENIED");
469 case SEC_E_UNKNOWN_CREDENTIALS:
470 OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
472 case SEC_E_NO_CREDENTIALS:
473 OutputDebugF("Returning bad password :: NO_CREDENTIALS");
475 case SEC_E_CONTEXT_EXPIRED:
476 OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
478 case SEC_E_INCOMPLETE_CREDENTIALS:
479 OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
481 case SEC_E_WRONG_PRINCIPAL:
482 OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
484 case SEC_E_TIME_SKEW:
485 OutputDebugF("Returning bad password :: TIME_SKEW");
488 OutputDebugF("Returning bad password :: Status == %lX", status);
490 code = CM_ERROR_BADPASSWORD;
494 if (secCtx->partialToken) free(secCtx->partialToken);
502 if (secTokOut.pvBuffer)
503 FreeContextBuffer(secTokOut.pvBuffer);
505 if (code != CM_ERROR_GSSCONTINUE) {
506 DeleteSecurityContext(&ctx);
507 FreeCredentialsHandle(&creds);
515 #define P_RESP_LEN 128
517 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
518 So put stuff in a struct. */
519 struct Lm20AuthBlob {
520 MSV1_0_LM20_LOGON lmlogon;
521 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
522 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
523 WCHAR accountNameW[P_LEN];
524 WCHAR primaryDomainW[P_LEN];
525 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
526 TOKEN_GROUPS tgroups;
527 TOKEN_SOURCE tsource;
530 long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
533 struct Lm20AuthBlob lmAuth;
534 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
535 QUOTA_LIMITS quotaLimits;
537 ULONG lmprofilepSize;
541 OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
542 OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
544 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
545 OutputDebugF("ciPwdLength or csPwdLength is too long");
546 return CM_ERROR_BADPASSWORD;
549 memset(&lmAuth,0,sizeof(lmAuth));
551 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
553 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
554 mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
555 lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
556 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
558 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
559 mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
560 lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
561 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
563 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
564 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
565 size = MAX_COMPUTERNAME_LENGTH + 1;
566 GetComputerNameW(lmAuth.workstationW, &size);
567 lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
569 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
571 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
572 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
573 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
574 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
576 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
577 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
578 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
579 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
581 lmAuth.lmlogon.ParameterControl = 0;
583 lmAuth.tgroups.GroupCount = 0;
584 lmAuth.tgroups.Groups[0].Sid = NULL;
585 lmAuth.tgroups.Groups[0].Attributes = 0;
587 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
588 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
589 strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
591 nts = LsaLogonUser( smb_lsaHandle,
606 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
607 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
610 OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
611 OutputDebugF("Extended status is 0x%lX", ntsEx);
613 if (nts == ERROR_SUCCESS) {
615 LsaFreeReturnBuffer(lmprofilep);
616 CloseHandle(lmToken);
620 if (nts == 0xC000015BL)
621 return CM_ERROR_BADLOGONTYPE;
622 else /* our catchall is a bad password though we could be more specific */
623 return CM_ERROR_BADPASSWORD;
627 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
628 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName)
633 /* check if we have sane input */
634 if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
637 /* we could get : [accountName][domainName]
643 atsign = strchr(accountName, '@');
645 if (atsign) /* [user@domain][] -> [user@domain][domain] */
650 /* if for some reason the client doesn't know what domain to use,
651 it will either return an empty string or a '?' */
652 if (!domain[0] || domain[0] == '?')
653 /* Empty domains and empty usernames are usually sent from tokenless contexts.
654 This way such logins will get an empty username (easy to check). I don't know
655 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
656 strcpy(usern,accountName);
658 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
659 strcpy(usern,domain);
662 strncat(usern,accountName,atsign - accountName);
664 strcat(usern,accountName);
672 /* When using SMB auth, all SMB sessions have to pass through here
673 * first to authenticate the user.
675 * Caveat: If not using SMB auth, the protocol does not require
676 * sending a session setup packet, which means that we can't rely on a
677 * UID in subsequent packets. Though in practice we get one anyway.
679 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
683 unsigned short newUid;
684 unsigned long caps = 0;
688 char usern[SMB_MAX_USERNAME_LENGTH];
689 char *secBlobOut = NULL;
690 int secBlobOutLength = 0;
692 /* Check for bad conns */
693 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
694 return CM_ERROR_REMOTECONN;
696 if (vcp->flags & SMB_VCFLAG_USENT) {
697 if (smb_authType == SMB_AUTH_EXTENDED) {
698 /* extended authentication */
702 OutputDebugF("NT Session Setup: Extended");
704 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
705 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
708 secBlobInLength = smb_GetSMBParm(inp, 7);
709 secBlobIn = smb_GetSMBData(inp, NULL);
711 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
713 if (code == CM_ERROR_GSSCONTINUE) {
714 smb_SetSMBParm(outp, 2, 0);
715 smb_SetSMBParm(outp, 3, secBlobOutLength);
716 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
717 tp = smb_GetSMBData(outp, NULL);
718 if (secBlobOutLength) {
719 memcpy(tp, secBlobOut, secBlobOutLength);
721 tp += secBlobOutLength;
723 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
724 tp += smb_ServerOSLength;
725 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
726 tp += smb_ServerLanManagerLength;
727 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
728 tp += smb_ServerDomainNameLength;
731 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
733 unsigned ciPwdLength, csPwdLength;
739 if (smb_authType == SMB_AUTH_NTLM)
740 OutputDebugF("NT Session Setup: NTLM");
742 OutputDebugF("NT Session Setup: None");
744 /* TODO: parse for extended auth as well */
745 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
746 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
748 tp = smb_GetSMBData(inp, &datalen);
750 OutputDebugF("Session packet data size [%d]",datalen);
757 accountName = smb_ParseString(tp, &tp);
758 primaryDomain = smb_ParseString(tp, NULL);
760 OutputDebugF("Account Name: %s",accountName);
761 OutputDebugF("Primary Domain: %s", primaryDomain);
762 OutputDebugF("Case Sensitive Password: %s", csPwd && csPwd[0] ? "yes" : "no");
763 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
765 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
766 /* shouldn't happen */
767 code = CM_ERROR_BADSMB;
768 goto after_read_packet;
771 /* capabilities are only valid for first session packet */
772 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
773 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
776 if (smb_authType == SMB_AUTH_NTLM) {
777 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
779 OutputDebugF("LM authentication failed [%d]", code);
781 OutputDebugF("LM authentication succeeded");
785 unsigned ciPwdLength;
790 switch ( smb_authType ) {
791 case SMB_AUTH_EXTENDED:
792 OutputDebugF("V3 Session Setup: Extended");
795 OutputDebugF("V3 Session Setup: NTLM");
798 OutputDebugF("V3 Session Setup: None");
800 ciPwdLength = smb_GetSMBParm(inp, 7);
801 tp = smb_GetSMBData(inp, NULL);
805 accountName = smb_ParseString(tp, &tp);
806 primaryDomain = smb_ParseString(tp, NULL);
808 OutputDebugF("Account Name: %s",accountName);
809 OutputDebugF("Primary Domain: %s", primaryDomain);
810 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
812 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
813 /* shouldn't happen */
814 code = CM_ERROR_BADSMB;
815 goto after_read_packet;
818 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
821 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
822 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
824 OutputDebugF("LM authentication failed [%d]", code);
826 OutputDebugF("LM authentication succeeded");
831 /* note down that we received a session setup X and set the capabilities flag */
832 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
833 lock_ObtainMutex(&vcp->mx);
834 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
835 /* for the moment we can only deal with NTSTATUS */
836 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
837 vcp->flags |= SMB_VCFLAG_STATUS32;
839 lock_ReleaseMutex(&vcp->mx);
842 /* code would be non-zero if there was an authentication failure.
843 Ideally we would like to invalidate the uid for this session or break
844 early to avoid accidently stealing someone else's tokens. */
850 OutputDebugF("Received username=[%s]", usern);
852 /* On Windows 2000, this function appears to be called more often than
853 it is expected to be called. This resulted in multiple smb_user_t
854 records existing all for the same user session which results in all
855 of the users tokens disappearing.
857 To avoid this problem, we look for an existing smb_user_t record
858 based on the users name, and use that one if we find it.
861 uidp = smb_FindUserByNameThisSession(vcp, usern);
862 if (uidp) { /* already there, so don't create a new one */
864 newUid = uidp->userID;
865 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
866 vcp->lana,vcp->lsn,newUid);
867 smb_ReleaseUID(uidp);
872 /* do a global search for the username/machine name pair */
873 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
874 lock_ObtainMutex(&unp->mx);
875 if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
876 /* clear the afslogon flag so that the tickets can now
877 * be freed when the refCount returns to zero.
879 unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
881 lock_ReleaseMutex(&unp->mx);
883 /* Create a new UID and cm_user_t structure */
886 userp = cm_NewUser();
887 cm_HoldUserVCRef(userp);
888 lock_ObtainMutex(&vcp->mx);
889 if (!vcp->uidCounter)
890 vcp->uidCounter++; /* handle unlikely wraparounds */
891 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
892 lock_ReleaseMutex(&vcp->mx);
894 /* Create a new smb_user_t structure and connect them up */
895 lock_ObtainMutex(&unp->mx);
897 lock_ReleaseMutex(&unp->mx);
899 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
901 lock_ObtainMutex(&uidp->mx);
903 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
904 lock_ReleaseMutex(&uidp->mx);
905 smb_ReleaseUID(uidp);
909 /* Return UID to the client */
910 ((smb_t *)outp)->uid = newUid;
911 /* Also to the next chained message */
912 ((smb_t *)inp)->uid = newUid;
914 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
915 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
917 smb_SetSMBParm(outp, 2, 0);
919 if (vcp->flags & SMB_VCFLAG_USENT) {
920 if (smb_authType == SMB_AUTH_EXTENDED) {
921 smb_SetSMBParm(outp, 3, secBlobOutLength);
922 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
923 tp = smb_GetSMBData(outp, NULL);
924 if (secBlobOutLength) {
925 memcpy(tp, secBlobOut, secBlobOutLength);
927 tp += secBlobOutLength;
929 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
930 tp += smb_ServerOSLength;
931 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
932 tp += smb_ServerLanManagerLength;
933 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
934 tp += smb_ServerDomainNameLength;
936 smb_SetSMBDataLength(outp, 0);
939 if (smb_authType == SMB_AUTH_EXTENDED) {
940 smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
941 tp = smb_GetSMBData(outp, NULL);
942 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
943 tp += smb_ServerOSLength;
944 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
945 tp += smb_ServerLanManagerLength;
946 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
947 tp += smb_ServerDomainNameLength;
949 smb_SetSMBDataLength(outp, 0);
956 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
960 /* find the tree and free it */
961 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
963 smb_username_t * unp;
965 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %s", uidp->userID,
966 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "));
968 lock_ObtainMutex(&uidp->mx);
969 uidp->flags |= SMB_USERFLAG_DELETE;
971 * it doesn't get deleted right away
972 * because the vcp points to it
975 lock_ReleaseMutex(&uidp->mx);
978 /* we can't do this. we get logoff messages prior to a session
979 * disconnect even though it doesn't mean the user is logging out.
980 * we need to create a new pioctl and EventLogoff handler to set
981 * SMB_USERNAMEFLAG_LOGOFF.
983 if (unp && smb_LogoffTokenTransfer) {
984 lock_ObtainMutex(&unp->mx);
985 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
986 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
987 lock_ReleaseMutex(&unp->mx);
991 smb_ReleaseUID(uidp);
994 osi_Log0(smb_logp, "SMB3 user logoffX");
996 smb_SetSMBDataLength(outp, 0);
1000 #define SMB_SUPPORT_SEARCH_BITS 0x0001
1001 #define SMB_SHARE_IS_IN_DFS 0x0002
1003 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1006 smb_user_t *uidp = NULL;
1007 unsigned short newTid;
1008 char shareName[AFSPATHMAX];
1015 cm_user_t *userp = NULL;
1018 osi_Log0(smb_logp, "SMB3 receive tree connect");
1020 /* parse input parameters */
1021 tp = smb_GetSMBData(inp, NULL);
1022 passwordp = smb_ParseString(tp, &tp);
1023 pathp = smb_ParseString(tp, &tp);
1024 if (smb_StoreAnsiFilenames)
1025 OemToChar(pathp,pathp);
1026 servicep = smb_ParseString(tp, &tp);
1028 tp = strrchr(pathp, '\\');
1030 return CM_ERROR_BADSMB;
1032 strcpy(shareName, tp+1);
1034 osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
1035 osi_LogSaveString(smb_logp, pathp),
1036 osi_LogSaveString(smb_logp, shareName));
1038 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
1040 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1043 return CM_ERROR_NOIPC;
1047 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1049 userp = smb_GetUserFromUID(uidp);
1051 lock_ObtainMutex(&vcp->mx);
1052 newTid = vcp->tidCounter++;
1053 lock_ReleaseMutex(&vcp->mx);
1055 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1058 if (!strcmp(shareName, "*."))
1059 strcpy(shareName, "all");
1060 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1063 smb_ReleaseUID(uidp);
1064 smb_ReleaseTID(tidp);
1065 return CM_ERROR_BADSHARENAME;
1068 if (vcp->flags & SMB_VCFLAG_USENT)
1070 int policy = smb_FindShareCSCPolicy(shareName);
1071 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1073 SMB_SHARE_IS_IN_DFS |
1078 smb_SetSMBParm(outp, 2, 0);
1082 smb_ReleaseUID(uidp);
1084 lock_ObtainMutex(&tidp->mx);
1085 tidp->userp = userp;
1086 tidp->pathname = sharePath;
1088 tidp->flags |= SMB_TIDFLAG_IPC;
1089 lock_ReleaseMutex(&tidp->mx);
1090 smb_ReleaseTID(tidp);
1092 ((smb_t *)outp)->tid = newTid;
1093 ((smb_t *)inp)->tid = newTid;
1094 tp = smb_GetSMBData(outp, NULL);
1096 /* XXX - why is this a drive letter? */
1104 smb_SetSMBDataLength(outp, 7);
1107 smb_SetSMBDataLength(outp, 4);
1110 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1114 /* must be called with global tran lock held */
1115 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1117 smb_tran2Packet_t *tp;
1120 smbp = (smb_t *) inp->data;
1121 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1122 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1128 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1129 int totalParms, int totalData)
1131 smb_tran2Packet_t *tp;
1134 smbp = (smb_t *) inp->data;
1135 tp = malloc(sizeof(*tp));
1136 memset(tp, 0, sizeof(*tp));
1139 tp->curData = tp->curParms = 0;
1140 tp->totalData = totalData;
1141 tp->totalParms = totalParms;
1142 tp->tid = smbp->tid;
1143 tp->mid = smbp->mid;
1144 tp->uid = smbp->uid;
1145 tp->pid = smbp->pid;
1146 tp->res[0] = smbp->res[0];
1147 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1148 if (totalParms != 0)
1149 tp->parmsp = malloc(totalParms);
1151 tp->datap = malloc(totalData);
1152 if (smbp->com == 0x25 || smbp->com == 0x26)
1155 tp->opcode = smb_GetSMBParm(inp, 14);
1158 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1162 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1163 smb_tran2Packet_t *inp, smb_packet_t *outp,
1164 int totalParms, int totalData)
1166 smb_tran2Packet_t *tp;
1167 unsigned short parmOffset;
1168 unsigned short dataOffset;
1169 unsigned short dataAlign;
1171 tp = malloc(sizeof(*tp));
1172 memset(tp, 0, sizeof(*tp));
1175 tp->curData = tp->curParms = 0;
1176 tp->totalData = totalData;
1177 tp->totalParms = totalParms;
1178 tp->oldTotalParms = totalParms;
1183 tp->res[0] = inp->res[0];
1184 tp->opcode = inp->opcode;
1188 * We calculate where the parameters and data will start.
1189 * This calculation must parallel the calculation in
1190 * smb_SendTran2Packet.
1193 parmOffset = 10*2 + 35;
1194 parmOffset++; /* round to even */
1195 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1197 dataOffset = parmOffset + totalParms;
1198 dataAlign = dataOffset & 2; /* quad-align */
1199 dataOffset += dataAlign;
1200 tp->datap = outp->data + dataOffset;
1205 /* free a tran2 packet */
1206 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1209 smb_ReleaseVC(t2p->vcp);
1212 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1221 /* called with a VC, an input packet to respond to, and an error code.
1222 * sends an error response.
1224 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1225 smb_packet_t *tp, long code)
1228 unsigned short errCode;
1229 unsigned char errClass;
1230 unsigned long NTStatus;
1232 if (vcp->flags & SMB_VCFLAG_STATUS32)
1233 smb_MapNTError(code, &NTStatus);
1235 smb_MapCoreError(code, vcp, &errCode, &errClass);
1237 smb_FormatResponsePacket(vcp, NULL, tp);
1238 smbp = (smb_t *) tp;
1240 /* We can handle long names */
1241 if (vcp->flags & SMB_VCFLAG_USENT)
1242 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1244 /* now copy important fields from the tran 2 packet */
1245 smbp->com = t2p->com;
1246 smbp->tid = t2p->tid;
1247 smbp->mid = t2p->mid;
1248 smbp->pid = t2p->pid;
1249 smbp->uid = t2p->uid;
1250 smbp->res[0] = t2p->res[0];
1251 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1252 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1253 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1254 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1255 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1256 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1259 smbp->rcls = errClass;
1260 smbp->errLow = (unsigned char) (errCode & 0xff);
1261 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1265 smb_SendPacket(vcp, tp);
1268 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1271 unsigned short parmOffset;
1272 unsigned short dataOffset;
1273 unsigned short totalLength;
1274 unsigned short dataAlign;
1277 smb_FormatResponsePacket(vcp, NULL, tp);
1278 smbp = (smb_t *) tp;
1280 /* We can handle long names */
1281 if (vcp->flags & SMB_VCFLAG_USENT)
1282 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1284 /* now copy important fields from the tran 2 packet */
1285 smbp->com = t2p->com;
1286 smbp->tid = t2p->tid;
1287 smbp->mid = t2p->mid;
1288 smbp->pid = t2p->pid;
1289 smbp->uid = t2p->uid;
1290 smbp->res[0] = t2p->res[0];
1292 totalLength = 1 + t2p->totalData + t2p->totalParms;
1294 /* now add the core parameters (tran2 info) to the packet */
1295 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1296 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1297 smb_SetSMBParm(tp, 2, 0); /* reserved */
1298 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1299 parmOffset = 10*2 + 35; /* parm offset in packet */
1300 parmOffset++; /* round to even */
1301 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1302 * hdr, bcc and wct */
1303 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1304 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1305 dataOffset = parmOffset + t2p->oldTotalParms;
1306 dataAlign = dataOffset & 2; /* quad-align */
1307 dataOffset += dataAlign;
1308 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1309 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1310 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1313 datap = smb_GetSMBData(tp, NULL);
1314 *datap++ = 0; /* we rounded to even */
1316 totalLength += dataAlign;
1317 smb_SetSMBDataLength(tp, totalLength);
1319 /* next, send the datagram */
1320 smb_SendPacket(vcp, tp);
1323 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1325 smb_tran2Packet_t *asp;
1338 /* We sometimes see 0 word count. What to do? */
1339 if (*inp->wctp == 0) {
1340 osi_Log0(smb_logp, "Transaction2 word count = 0");
1341 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1343 smb_SetSMBDataLength(outp, 0);
1344 smb_SendPacket(vcp, outp);
1348 totalParms = smb_GetSMBParm(inp, 0);
1349 totalData = smb_GetSMBParm(inp, 1);
1351 firstPacket = (inp->inCom == 0x25);
1353 /* find the packet we're reassembling */
1354 lock_ObtainWrite(&smb_globalLock);
1355 asp = smb_FindTran2Packet(vcp, inp);
1357 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1359 lock_ReleaseWrite(&smb_globalLock);
1361 /* now merge in this latest packet; start by looking up offsets */
1363 parmDisp = dataDisp = 0;
1364 parmOffset = smb_GetSMBParm(inp, 10);
1365 dataOffset = smb_GetSMBParm(inp, 12);
1366 parmCount = smb_GetSMBParm(inp, 9);
1367 dataCount = smb_GetSMBParm(inp, 11);
1368 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1369 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1371 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1372 totalData, dataCount, asp->maxReturnData);
1375 parmDisp = smb_GetSMBParm(inp, 4);
1376 parmOffset = smb_GetSMBParm(inp, 3);
1377 dataDisp = smb_GetSMBParm(inp, 7);
1378 dataOffset = smb_GetSMBParm(inp, 6);
1379 parmCount = smb_GetSMBParm(inp, 2);
1380 dataCount = smb_GetSMBParm(inp, 5);
1382 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1383 parmCount, dataCount);
1386 /* now copy the parms and data */
1387 if ( asp->totalParms > 0 && parmCount != 0 )
1389 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1391 if ( asp->totalData > 0 && dataCount != 0 ) {
1392 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1395 /* account for new bytes */
1396 asp->curData += dataCount;
1397 asp->curParms += parmCount;
1399 /* finally, if we're done, remove the packet from the queue and dispatch it */
1400 if (asp->totalParms > 0 &&
1401 asp->curParms > 0 &&
1402 asp->totalData <= asp->curData &&
1403 asp->totalParms <= asp->curParms) {
1404 /* we've received it all */
1405 lock_ObtainWrite(&smb_globalLock);
1406 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1407 lock_ReleaseWrite(&smb_globalLock);
1409 /* now dispatch it */
1410 rapOp = asp->parmsp[0];
1412 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1413 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1414 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1415 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
1418 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1419 code = CM_ERROR_BADOP;
1422 /* if an error is returned, we're supposed to send an error packet,
1423 * otherwise the dispatched function already did the data sending.
1424 * We give dispatched proc the responsibility since it knows how much
1425 * space to allocate.
1428 smb_SendTran2Error(vcp, asp, outp, code);
1431 /* free the input tran 2 packet */
1432 smb_FreeTran2Packet(asp);
1434 else if (firstPacket) {
1435 /* the first packet in a multi-packet request, we need to send an
1436 * ack to get more data.
1438 smb_SetSMBDataLength(outp, 0);
1439 smb_SendPacket(vcp, outp);
1445 /* ANSI versions. The unicode versions support arbitrary length
1446 share names, but we don't support unicode yet. */
1448 typedef struct smb_rap_share_info_0 {
1449 char shi0_netname[13];
1450 } smb_rap_share_info_0_t;
1452 typedef struct smb_rap_share_info_1 {
1453 char shi1_netname[13];
1456 DWORD shi1_remark; /* char *shi1_remark; data offset */
1457 } smb_rap_share_info_1_t;
1459 typedef struct smb_rap_share_info_2 {
1460 char shi2_netname[13];
1462 unsigned short shi2_type;
1463 DWORD shi2_remark; /* char *shi2_remark; data offset */
1464 unsigned short shi2_permissions;
1465 unsigned short shi2_max_uses;
1466 unsigned short shi2_current_uses;
1467 DWORD shi2_path; /* char *shi2_path; data offset */
1468 unsigned short shi2_passwd[9];
1469 unsigned short shi2_pad2;
1470 } smb_rap_share_info_2_t;
1472 #define SMB_RAP_MAX_SHARES 512
1474 typedef struct smb_rap_share_list {
1477 smb_rap_share_info_0_t * shares;
1478 } smb_rap_share_list_t;
1480 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1481 smb_rap_share_list_t * sp;
1486 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1487 return 0; /* skip over '.' and '..' */
1489 sp = (smb_rap_share_list_t *) vrockp;
1491 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1492 sp->shares[sp->cShare].shi0_netname[12] = 0;
1496 if (sp->cShare >= sp->maxShares)
1497 return CM_ERROR_STOPNOW;
1502 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1504 smb_tran2Packet_t *outp;
1505 unsigned short * tp;
1509 int outParmsTotal; /* total parameter bytes */
1510 int outDataTotal; /* total data bytes */
1513 DWORD allSubmount = 0;
1515 DWORD nRegShares = 0;
1516 DWORD nSharesRet = 0;
1518 HKEY hkSubmount = NULL;
1519 smb_rap_share_info_1_t * shares;
1522 char thisShare[AFSPATHMAX];
1526 smb_rap_share_list_t rootShares;
1531 tp = p->parmsp + 1; /* skip over function number (always 0) */
1532 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1533 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1537 if (infoLevel != 1) {
1538 return CM_ERROR_INVAL;
1541 /* first figure out how many shares there are */
1542 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1543 KEY_QUERY_VALUE, &hkParam);
1544 if (rv == ERROR_SUCCESS) {
1545 len = sizeof(allSubmount);
1546 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1547 (BYTE *) &allSubmount, &len);
1548 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1551 RegCloseKey (hkParam);
1554 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1555 0, KEY_QUERY_VALUE, &hkSubmount);
1556 if (rv == ERROR_SUCCESS) {
1557 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1558 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1559 if (rv != ERROR_SUCCESS)
1565 /* fetch the root shares */
1566 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1567 rootShares.cShare = 0;
1568 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1572 userp = smb_GetTran2User(vcp,p);
1574 thyper.HighPart = 0;
1577 cm_HoldSCache(cm_data.rootSCachep);
1578 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1579 cm_ReleaseSCache(cm_data.rootSCachep);
1581 cm_ReleaseUser(userp);
1583 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1585 #define REMARK_LEN 1
1586 outParmsTotal = 8; /* 4 dwords */
1587 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1588 if(outDataTotal > bufsize) {
1589 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1590 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1593 nSharesRet = nShares;
1596 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1598 /* now for the submounts */
1599 shares = (smb_rap_share_info_1_t *) outp->datap;
1600 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1602 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1605 strcpy( shares[cshare].shi1_netname, "all" );
1606 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1607 /* type and pad are zero already */
1613 for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
1614 len = sizeof(thisShare);
1615 rv = RegEnumValue(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
1616 if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1617 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1618 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1619 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1624 nShares--; /* uncount key */
1627 RegCloseKey(hkSubmount);
1630 nonrootShares = cshare;
1632 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1633 /* in case there are collisions with submounts, submounts have higher priority */
1634 for (j=0; j < nonrootShares; j++)
1635 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1638 if (j < nonrootShares) {
1639 nShares--; /* uncount */
1643 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1644 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1649 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1650 outp->parmsp[1] = 0;
1651 outp->parmsp[2] = cshare;
1652 outp->parmsp[3] = nShares;
1654 outp->totalData = (int)(cstrp - outp->datap);
1655 outp->totalParms = outParmsTotal;
1657 smb_SendTran2Packet(vcp, outp, op);
1658 smb_FreeTran2Packet(outp);
1660 free(rootShares.shares);
1665 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1667 smb_tran2Packet_t *outp;
1668 unsigned short * tp;
1670 BOOL shareFound = FALSE;
1671 unsigned short infoLevel;
1672 unsigned short bufsize;
1682 tp = p->parmsp + 1; /* skip over function number (always 1) */
1683 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1684 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1685 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1692 totalData = sizeof(smb_rap_share_info_0_t);
1693 else if(infoLevel == SMB_INFO_STANDARD)
1694 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1695 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1696 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1698 return CM_ERROR_INVAL;
1700 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1702 if(!stricmp(shareName,"all") || !strcmp(shareName,"*.")) {
1703 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1704 KEY_QUERY_VALUE, &hkParam);
1705 if (rv == ERROR_SUCCESS) {
1706 len = sizeof(allSubmount);
1707 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1708 (BYTE *) &allSubmount, &len);
1709 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1712 RegCloseKey (hkParam);
1719 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1720 KEY_QUERY_VALUE, &hkSubmount);
1721 if (rv == ERROR_SUCCESS) {
1722 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1723 if (rv == ERROR_SUCCESS) {
1726 RegCloseKey(hkSubmount);
1731 smb_FreeTran2Packet(outp);
1732 return CM_ERROR_BADSHARENAME;
1735 memset(outp->datap, 0, totalData);
1737 outp->parmsp[0] = 0;
1738 outp->parmsp[1] = 0;
1739 outp->parmsp[2] = totalData;
1741 if (infoLevel == 0) {
1742 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1743 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1744 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1745 } else if(infoLevel == SMB_INFO_STANDARD) {
1746 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1747 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1748 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1749 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1750 /* type and pad are already zero */
1751 } else { /* infoLevel==2 */
1752 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1753 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1754 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1755 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1756 info->shi2_permissions = ACCESS_ALL;
1757 info->shi2_max_uses = (unsigned short) -1;
1758 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
1761 outp->totalData = totalData;
1762 outp->totalParms = totalParam;
1764 smb_SendTran2Packet(vcp, outp, op);
1765 smb_FreeTran2Packet(outp);
1770 typedef struct smb_rap_wksta_info_10 {
1771 DWORD wki10_computername; /*char *wki10_computername;*/
1772 DWORD wki10_username; /* char *wki10_username; */
1773 DWORD wki10_langroup; /* char *wki10_langroup;*/
1774 unsigned char wki10_ver_major;
1775 unsigned char wki10_ver_minor;
1776 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1777 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1778 } smb_rap_wksta_info_10_t;
1781 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1783 smb_tran2Packet_t *outp;
1787 unsigned short * tp;
1790 smb_rap_wksta_info_10_t * info;
1794 tp = p->parmsp + 1; /* Skip over function number */
1795 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1796 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1800 if (infoLevel != 10) {
1801 return CM_ERROR_INVAL;
1807 totalData = sizeof(*info) + /* info */
1808 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1809 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1810 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1811 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1812 1; /* wki10_oth_domains (null)*/
1814 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1816 memset(outp->parmsp,0,totalParams);
1817 memset(outp->datap,0,totalData);
1819 info = (smb_rap_wksta_info_10_t *) outp->datap;
1820 cstrp = (char *) (info + 1);
1822 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1823 strcpy(cstrp, smb_localNamep);
1824 cstrp += strlen(cstrp) + 1;
1826 info->wki10_username = (DWORD) (cstrp - outp->datap);
1827 uidp = smb_FindUID(vcp, p->uid, 0);
1829 lock_ObtainMutex(&uidp->mx);
1830 if(uidp->unp && uidp->unp->name)
1831 strcpy(cstrp, uidp->unp->name);
1832 lock_ReleaseMutex(&uidp->mx);
1833 smb_ReleaseUID(uidp);
1835 cstrp += strlen(cstrp) + 1;
1837 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1838 strcpy(cstrp, "WORKGROUP");
1839 cstrp += strlen(cstrp) + 1;
1841 /* TODO: Not sure what values these should take, but these work */
1842 info->wki10_ver_major = 5;
1843 info->wki10_ver_minor = 1;
1845 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1846 strcpy(cstrp, smb_ServerDomainName);
1847 cstrp += strlen(cstrp) + 1;
1849 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1850 cstrp ++; /* no other domains */
1852 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1853 outp->parmsp[2] = outp->totalData;
1854 outp->totalParms = totalParams;
1856 smb_SendTran2Packet(vcp,outp,op);
1857 smb_FreeTran2Packet(outp);
1862 typedef struct smb_rap_server_info_0 {
1864 } smb_rap_server_info_0_t;
1866 typedef struct smb_rap_server_info_1 {
1868 char sv1_version_major;
1869 char sv1_version_minor;
1870 unsigned long sv1_type;
1871 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1872 } smb_rap_server_info_1_t;
1874 char smb_ServerComment[] = "OpenAFS Client";
1875 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1877 #define SMB_SV_TYPE_SERVER 0x00000002L
1878 #define SMB_SV_TYPE_NT 0x00001000L
1879 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1881 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1883 smb_tran2Packet_t *outp;
1887 unsigned short * tp;
1890 smb_rap_server_info_0_t * info0;
1891 smb_rap_server_info_1_t * info1;
1894 tp = p->parmsp + 1; /* Skip over function number */
1895 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1896 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1900 if (infoLevel != 0 && infoLevel != 1) {
1901 return CM_ERROR_INVAL;
1907 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1908 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1910 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1912 memset(outp->parmsp,0,totalParams);
1913 memset(outp->datap,0,totalData);
1915 if (infoLevel == 0) {
1916 info0 = (smb_rap_server_info_0_t *) outp->datap;
1917 cstrp = (char *) (info0 + 1);
1918 strcpy(info0->sv0_name, "AFS");
1919 } else { /* infoLevel == SMB_INFO_STANDARD */
1920 info1 = (smb_rap_server_info_1_t *) outp->datap;
1921 cstrp = (char *) (info1 + 1);
1922 strcpy(info1->sv1_name, "AFS");
1925 SMB_SV_TYPE_SERVER |
1927 SMB_SV_TYPE_SERVER_NT;
1929 info1->sv1_version_major = 5;
1930 info1->sv1_version_minor = 1;
1931 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1933 strcpy(cstrp, smb_ServerComment);
1935 cstrp += smb_ServerCommentLen;
1938 totalData = (DWORD)(cstrp - outp->datap);
1939 outp->totalData = min(bufsize,totalData); /* actual data size */
1940 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1941 outp->parmsp[2] = totalData;
1942 outp->totalParms = totalParams;
1944 smb_SendTran2Packet(vcp,outp,op);
1945 smb_FreeTran2Packet(outp);
1950 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1952 smb_tran2Packet_t *asp;
1964 /* We sometimes see 0 word count. What to do? */
1965 if (*inp->wctp == 0) {
1966 osi_Log0(smb_logp, "Transaction2 word count = 0");
1967 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1969 smb_SetSMBDataLength(outp, 0);
1970 smb_SendPacket(vcp, outp);
1974 totalParms = smb_GetSMBParm(inp, 0);
1975 totalData = smb_GetSMBParm(inp, 1);
1977 firstPacket = (inp->inCom == 0x32);
1979 /* find the packet we're reassembling */
1980 lock_ObtainWrite(&smb_globalLock);
1981 asp = smb_FindTran2Packet(vcp, inp);
1983 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1985 lock_ReleaseWrite(&smb_globalLock);
1987 /* now merge in this latest packet; start by looking up offsets */
1989 parmDisp = dataDisp = 0;
1990 parmOffset = smb_GetSMBParm(inp, 10);
1991 dataOffset = smb_GetSMBParm(inp, 12);
1992 parmCount = smb_GetSMBParm(inp, 9);
1993 dataCount = smb_GetSMBParm(inp, 11);
1994 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1995 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1997 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1998 totalData, dataCount, asp->maxReturnData);
2001 parmDisp = smb_GetSMBParm(inp, 4);
2002 parmOffset = smb_GetSMBParm(inp, 3);
2003 dataDisp = smb_GetSMBParm(inp, 7);
2004 dataOffset = smb_GetSMBParm(inp, 6);
2005 parmCount = smb_GetSMBParm(inp, 2);
2006 dataCount = smb_GetSMBParm(inp, 5);
2008 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2009 parmCount, dataCount);
2012 /* now copy the parms and data */
2013 if ( asp->totalParms > 0 && parmCount != 0 )
2015 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2017 if ( asp->totalData > 0 && dataCount != 0 ) {
2018 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2021 /* account for new bytes */
2022 asp->curData += dataCount;
2023 asp->curParms += parmCount;
2025 /* finally, if we're done, remove the packet from the queue and dispatch it */
2026 if (asp->totalParms > 0 &&
2027 asp->curParms > 0 &&
2028 asp->totalData <= asp->curData &&
2029 asp->totalParms <= asp->curParms) {
2030 /* we've received it all */
2031 lock_ObtainWrite(&smb_globalLock);
2032 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2033 lock_ReleaseWrite(&smb_globalLock);
2035 /* now dispatch it */
2036 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2037 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2038 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2041 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2042 code = CM_ERROR_BADOP;
2045 /* if an error is returned, we're supposed to send an error packet,
2046 * otherwise the dispatched function already did the data sending.
2047 * We give dispatched proc the responsibility since it knows how much
2048 * space to allocate.
2051 smb_SendTran2Error(vcp, asp, outp, code);
2054 /* free the input tran 2 packet */
2055 smb_FreeTran2Packet(asp);
2057 else if (firstPacket) {
2058 /* the first packet in a multi-packet request, we need to send an
2059 * ack to get more data.
2061 smb_SetSMBDataLength(outp, 0);
2062 smb_SendPacket(vcp, outp);
2068 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2071 smb_tran2Packet_t *outp;
2076 cm_scache_t *dscp; /* dir we're dealing with */
2077 cm_scache_t *scp; /* file we're creating */
2079 int initialModeBits;
2089 int parmSlot; /* which parm we're dealing with */
2090 long returnEALength;
2099 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2100 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2102 openFun = p->parmsp[6]; /* open function */
2103 excl = ((openFun & 3) == 0);
2104 trunc = ((openFun & 3) == 2); /* truncate it */
2105 openMode = (p->parmsp[1] & 0x7);
2106 openAction = 0; /* tracks what we did */
2108 attributes = p->parmsp[3];
2109 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2111 /* compute initial mode bits based on read-only flag in attributes */
2112 initialModeBits = 0666;
2113 if (attributes & SMB_ATTR_READONLY)
2114 initialModeBits &= ~0222;
2116 pathp = (char *) (&p->parmsp[14]);
2117 if (smb_StoreAnsiFilenames)
2118 OemToChar(pathp,pathp);
2120 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2122 spacep = cm_GetSpace();
2123 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2125 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2126 /* special case magic file name for receiving IOCTL requests
2127 * (since IOCTL calls themselves aren't getting through).
2129 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2130 smb_SetupIoctlFid(fidp, spacep);
2132 /* copy out remainder of the parms */
2134 outp->parmsp[parmSlot++] = fidp->fid;
2136 outp->parmsp[parmSlot++] = 0; /* attrs */
2137 outp->parmsp[parmSlot++] = 0; /* mod time */
2138 outp->parmsp[parmSlot++] = 0;
2139 outp->parmsp[parmSlot++] = 0; /* len */
2140 outp->parmsp[parmSlot++] = 0x7fff;
2141 outp->parmsp[parmSlot++] = openMode;
2142 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2143 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2145 /* and the final "always present" stuff */
2146 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2147 /* next write out the "unique" ID */
2148 outp->parmsp[parmSlot++] = 0x1234;
2149 outp->parmsp[parmSlot++] = 0x5678;
2150 outp->parmsp[parmSlot++] = 0;
2151 if (returnEALength) {
2152 outp->parmsp[parmSlot++] = 0;
2153 outp->parmsp[parmSlot++] = 0;
2156 outp->totalData = 0;
2157 outp->totalParms = parmSlot * 2;
2159 smb_SendTran2Packet(vcp, outp, op);
2161 smb_FreeTran2Packet(outp);
2163 /* and clean up fid reference */
2164 smb_ReleaseFID(fidp);
2168 #ifdef DEBUG_VERBOSE
2170 char *hexp, *asciip;
2171 asciip = (lastNamep ? lastNamep : pathp);
2172 hexp = osi_HexifyString( asciip );
2173 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2178 userp = smb_GetTran2User(vcp, p);
2179 /* In the off chance that userp is NULL, we log and abandon */
2181 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2182 smb_FreeTran2Packet(outp);
2183 return CM_ERROR_BADSMB;
2186 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2187 if (code == CM_ERROR_TIDIPC) {
2188 /* Attempt to use a TID allocated for IPC. The client
2189 * is probably looking for DCE RPC end points which we
2190 * don't support OR it could be looking to make a DFS
2193 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2195 cm_ReleaseUser(userp);
2196 smb_FreeTran2Packet(outp);
2197 return CM_ERROR_NOSUCHPATH;
2202 code = cm_NameI(cm_data.rootSCachep, pathp,
2203 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2204 userp, tidPathp, &req, &scp);
2206 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2207 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2208 userp, tidPathp, &req, &dscp);
2209 cm_FreeSpace(spacep);
2212 cm_ReleaseUser(userp);
2213 smb_FreeTran2Packet(outp);
2218 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2219 cm_ReleaseSCache(dscp);
2220 cm_ReleaseUser(userp);
2221 smb_FreeTran2Packet(outp);
2222 if ( WANTS_DFS_PATHNAMES(p) )
2223 return CM_ERROR_PATH_NOT_COVERED;
2225 return CM_ERROR_BADSHARENAME;
2227 #endif /* DFS_SUPPORT */
2229 /* otherwise, scp points to the parent directory. Do a lookup,
2230 * and truncate the file if we find it, otherwise we create the
2237 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2239 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2240 cm_ReleaseSCache(dscp);
2241 cm_ReleaseUser(userp);
2242 smb_FreeTran2Packet(outp);
2247 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2248 cm_ReleaseSCache(scp);
2249 cm_ReleaseUser(userp);
2250 smb_FreeTran2Packet(outp);
2251 if ( WANTS_DFS_PATHNAMES(p) )
2252 return CM_ERROR_PATH_NOT_COVERED;
2254 return CM_ERROR_BADSHARENAME;
2256 #endif /* DFS_SUPPORT */
2258 /* macintosh is expensive to program for it */
2259 cm_FreeSpace(spacep);
2262 /* if we get here, if code is 0, the file exists and is represented by
2263 * scp. Otherwise, we have to create it.
2266 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2269 cm_ReleaseSCache(dscp);
2270 cm_ReleaseSCache(scp);
2271 cm_ReleaseUser(userp);
2272 smb_FreeTran2Packet(outp);
2277 /* oops, file shouldn't be there */
2279 cm_ReleaseSCache(dscp);
2280 cm_ReleaseSCache(scp);
2281 cm_ReleaseUser(userp);
2282 smb_FreeTran2Packet(outp);
2283 return CM_ERROR_EXISTS;
2287 setAttr.mask = CM_ATTRMASK_LENGTH;
2288 setAttr.length.LowPart = 0;
2289 setAttr.length.HighPart = 0;
2290 code = cm_SetAttr(scp, &setAttr, userp, &req);
2291 openAction = 3; /* truncated existing file */
2294 openAction = 1; /* found existing file */
2296 else if (!(openFun & 0x10)) {
2297 /* don't create if not found */
2299 cm_ReleaseSCache(dscp);
2300 osi_assertx(scp == NULL, "null cm_scache_t");
2301 cm_ReleaseUser(userp);
2302 smb_FreeTran2Packet(outp);
2303 return CM_ERROR_NOSUCHFILE;
2306 osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2307 openAction = 2; /* created file */
2308 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2309 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2310 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2314 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2315 smb_NotifyChange(FILE_ACTION_ADDED,
2316 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2317 dscp, lastNamep, NULL, TRUE);
2318 } else if (!excl && code == CM_ERROR_EXISTS) {
2319 /* not an exclusive create, and someone else tried
2320 * creating it already, then we open it anyway. We
2321 * don't bother retrying after this, since if this next
2322 * fails, that means that the file was deleted after we
2323 * started this call.
2325 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2329 setAttr.mask = CM_ATTRMASK_LENGTH;
2330 setAttr.length.LowPart = 0;
2331 setAttr.length.HighPart = 0;
2332 code = cm_SetAttr(scp, &setAttr, userp,
2335 } /* lookup succeeded */
2339 /* we don't need this any longer */
2341 cm_ReleaseSCache(dscp);
2344 /* something went wrong creating or truncating the file */
2346 cm_ReleaseSCache(scp);
2347 cm_ReleaseUser(userp);
2348 smb_FreeTran2Packet(outp);
2352 /* make sure we're about to open a file */
2353 if (scp->fileType != CM_SCACHETYPE_FILE) {
2355 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2356 cm_scache_t * targetScp = 0;
2357 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2359 /* we have a more accurate file to use (the
2360 * target of the symbolic link). Otherwise,
2361 * we'll just use the symlink anyway.
2363 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2365 cm_ReleaseSCache(scp);
2369 if (scp->fileType != CM_SCACHETYPE_FILE) {
2370 cm_ReleaseSCache(scp);
2371 cm_ReleaseUser(userp);
2372 smb_FreeTran2Packet(outp);
2373 return CM_ERROR_ISDIR;
2377 /* now all we have to do is open the file itself */
2378 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2379 osi_assertx(fidp, "null smb_fid_t");
2382 lock_ObtainMutex(&fidp->mx);
2383 /* save a pointer to the vnode */
2384 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2386 lock_ObtainMutex(&scp->mx);
2387 scp->flags |= CM_SCACHEFLAG_SMB_FID;
2388 lock_ReleaseMutex(&scp->mx);
2391 fidp->userp = userp;
2393 /* compute open mode */
2395 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
2396 if (openMode == 1 || openMode == 2)
2397 fidp->flags |= SMB_FID_OPENWRITE;
2399 /* remember that the file was newly created */
2401 fidp->flags |= SMB_FID_CREATED;
2403 lock_ReleaseMutex(&fidp->mx);
2405 smb_ReleaseFID(fidp);
2407 cm_Open(scp, 0, userp);
2409 /* copy out remainder of the parms */
2411 outp->parmsp[parmSlot++] = fidp->fid;
2412 lock_ObtainMutex(&scp->mx);
2414 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2415 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2416 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2417 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2418 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2419 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2420 outp->parmsp[parmSlot++] = openMode;
2421 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2422 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2424 /* and the final "always present" stuff */
2425 outp->parmsp[parmSlot++] = openAction;
2426 /* next write out the "unique" ID */
2427 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2428 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2429 outp->parmsp[parmSlot++] = 0;
2430 if (returnEALength) {
2431 outp->parmsp[parmSlot++] = 0;
2432 outp->parmsp[parmSlot++] = 0;
2434 lock_ReleaseMutex(&scp->mx);
2435 outp->totalData = 0; /* total # of data bytes */
2436 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2438 smb_SendTran2Packet(vcp, outp, op);
2440 smb_FreeTran2Packet(outp);
2442 cm_ReleaseUser(userp);
2443 /* leave scp held since we put it in fidp->scp */
2447 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2450 unsigned short infolevel;
2452 infolevel = p->parmsp[0];
2454 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2456 return CM_ERROR_BAD_LEVEL;
2459 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2461 smb_tran2Packet_t *outp;
2462 smb_tran2QFSInfo_t qi;
2464 static char FSname[8] = {'A', 0, 'F', 0, 'S', 0, 0, 0};
2466 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2468 switch (p->parmsp[0]) {
2469 case SMB_INFO_ALLOCATION:
2470 responseSize = sizeof(qi.u.allocInfo);
2472 case SMB_INFO_VOLUME:
2473 responseSize = sizeof(qi.u.volumeInfo);
2475 case SMB_QUERY_FS_VOLUME_INFO:
2476 responseSize = sizeof(qi.u.FSvolumeInfo);
2478 case SMB_QUERY_FS_SIZE_INFO:
2479 responseSize = sizeof(qi.u.FSsizeInfo);
2481 case SMB_QUERY_FS_DEVICE_INFO:
2482 responseSize = sizeof(qi.u.FSdeviceInfo);
2484 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2485 responseSize = sizeof(qi.u.FSattributeInfo);
2487 case SMB_INFO_UNIX: /* CIFS Unix Info */
2488 case SMB_INFO_MACOS: /* Mac FS Info */
2490 return CM_ERROR_BADOP;
2493 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2494 switch (p->parmsp[0]) {
2495 case SMB_INFO_ALLOCATION:
2497 qi.u.allocInfo.FSID = 0;
2498 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2499 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2500 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2501 qi.u.allocInfo.bytesPerSector = 1024;
2504 case SMB_INFO_VOLUME:
2506 qi.u.volumeInfo.vsn = 1234;
2507 qi.u.volumeInfo.vnCount = 4;
2508 /* we're supposed to pad it out with zeroes to the end */
2509 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2510 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2513 case SMB_QUERY_FS_VOLUME_INFO:
2514 /* FS volume info */
2515 memset((char *)&qi.u.FSvolumeInfo.vct, 0, 4);
2516 qi.u.FSvolumeInfo.vsn = 1234;
2517 qi.u.FSvolumeInfo.vnCount = 8;
2518 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0\0", 8);
2521 case SMB_QUERY_FS_SIZE_INFO:
2523 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2524 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2525 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2526 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2527 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2528 qi.u.FSsizeInfo.bytesPerSector = 1024;
2531 case SMB_QUERY_FS_DEVICE_INFO:
2532 /* FS device info */
2533 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2534 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2537 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2538 /* FS attribute info */
2539 /* attributes, defined in WINNT.H:
2540 * FILE_CASE_SENSITIVE_SEARCH 0x1
2541 * FILE_CASE_PRESERVED_NAMES 0x2
2542 * FILE_VOLUME_QUOTAS 0x10
2543 * <no name defined> 0x4000
2544 * If bit 0x4000 is not set, Windows 95 thinks
2545 * we can't handle long (non-8.3) names,
2546 * despite our protestations to the contrary.
2548 qi.u.FSattributeInfo.attributes = 0x4003;
2549 qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
2550 qi.u.FSattributeInfo.FSnameLength = sizeof(FSname);
2551 memcpy(qi.u.FSattributeInfo.FSname, FSname, sizeof(FSname));
2555 /* copy out return data, and set corresponding sizes */
2556 outp->totalParms = 0;
2557 outp->totalData = responseSize;
2558 memcpy(outp->datap, &qi, responseSize);
2560 /* send and free the packets */
2561 smb_SendTran2Packet(vcp, outp, op);
2562 smb_FreeTran2Packet(outp);
2567 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2569 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2570 return CM_ERROR_BADOP;
2573 struct smb_ShortNameRock {
2577 size_t shortNameLen;
2580 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2583 struct smb_ShortNameRock *rockp;
2587 /* compare both names and vnodes, though probably just comparing vnodes
2588 * would be safe enough.
2590 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2592 if (ntohl(dep->fid.vnode) != rockp->vnode)
2594 /* This is the entry */
2595 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2596 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2597 return CM_ERROR_STOPNOW;
2600 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2601 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2603 struct smb_ShortNameRock rock;
2607 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2611 spacep = cm_GetSpace();
2612 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2614 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2616 cm_FreeSpace(spacep);
2621 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2622 cm_ReleaseSCache(dscp);
2623 cm_ReleaseUser(userp);
2624 return CM_ERROR_PATH_NOT_COVERED;
2626 #endif /* DFS_SUPPORT */
2628 if (!lastNamep) lastNamep = pathp;
2631 thyper.HighPart = 0;
2632 rock.shortName = shortName;
2634 rock.maskp = lastNamep;
2635 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2637 cm_ReleaseSCache(dscp);
2640 return CM_ERROR_NOSUCHFILE;
2641 if (code == CM_ERROR_STOPNOW) {
2642 *shortNameLenp = rock.shortNameLen;
2648 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2650 smb_tran2Packet_t *outp;
2653 unsigned short infoLevel;
2654 smb_tran2QPathInfo_t qpi;
2656 unsigned short attributes;
2657 unsigned long extAttributes;
2662 cm_scache_t *scp, *dscp;
2663 int scp_mx_held = 0;
2673 infoLevel = p->parmsp[0];
2674 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2676 else if (infoLevel == SMB_INFO_STANDARD)
2677 responseSize = sizeof(qpi.u.QPstandardInfo);
2678 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2679 responseSize = sizeof(qpi.u.QPeaSizeInfo);
2680 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2681 responseSize = sizeof(qpi.u.QPfileBasicInfo);
2682 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2683 responseSize = sizeof(qpi.u.QPfileStandardInfo);
2684 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2685 responseSize = sizeof(qpi.u.QPfileEaInfo);
2686 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2687 responseSize = sizeof(qpi.u.QPfileNameInfo);
2688 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
2689 responseSize = sizeof(qpi.u.QPfileAllInfo);
2690 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2691 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2693 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2694 p->opcode, infoLevel);
2695 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
2699 pathp = (char *)(&p->parmsp[3]);
2700 if (smb_StoreAnsiFilenames)
2701 OemToChar(pathp,pathp);
2702 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2703 osi_LogSaveString(smb_logp, pathp));
2705 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2707 if (infoLevel > 0x100)
2708 outp->totalParms = 2;
2710 outp->totalParms = 0;
2711 outp->totalData = responseSize;
2713 /* now, if we're at infoLevel 6, we're only being asked to check
2714 * the syntax, so we just OK things now. In particular, we're *not*
2715 * being asked to verify anything about the state of any parent dirs.
2717 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2718 smb_SendTran2Packet(vcp, outp, opx);
2719 smb_FreeTran2Packet(outp);
2723 userp = smb_GetTran2User(vcp, p);
2725 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2726 smb_FreeTran2Packet(outp);
2727 return CM_ERROR_BADSMB;
2730 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2732 cm_ReleaseUser(userp);
2733 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2734 smb_FreeTran2Packet(outp);
2739 * XXX Strange hack XXX
2741 * As of Patch 7 (13 January 98), we are having the following problem:
2742 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2743 * requests to look up "desktop.ini" in all the subdirectories.
2744 * This can cause zillions of timeouts looking up non-existent cells
2745 * and volumes, especially in the top-level directory.
2747 * We have not found any way to avoid this or work around it except
2748 * to explicitly ignore the requests for mount points that haven't
2749 * yet been evaluated and for directories that haven't yet been
2752 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2753 spacep = cm_GetSpace();
2754 smb_StripLastComponent(spacep->data, &lastComp, pathp);
2755 #ifndef SPECIAL_FOLDERS
2756 /* Make sure that lastComp is not NULL */
2758 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2759 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2763 userp, tidPathp, &req, &dscp);
2766 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2767 if ( WANTS_DFS_PATHNAMES(p) )
2768 code = CM_ERROR_PATH_NOT_COVERED;
2770 code = CM_ERROR_BADSHARENAME;
2772 #endif /* DFS_SUPPORT */
2773 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2774 code = CM_ERROR_NOSUCHFILE;
2775 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2776 cm_buf_t *bp = buf_Find(dscp, &hzero);
2782 code = CM_ERROR_NOSUCHFILE;
2784 cm_ReleaseSCache(dscp);
2786 cm_FreeSpace(spacep);
2787 cm_ReleaseUser(userp);
2788 smb_SendTran2Error(vcp, p, opx, code);
2789 smb_FreeTran2Packet(outp);
2795 #endif /* SPECIAL_FOLDERS */
2797 cm_FreeSpace(spacep);
2800 /* now do namei and stat, and copy out the info */
2801 code = cm_NameI(cm_data.rootSCachep, pathp,
2802 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2805 cm_ReleaseUser(userp);
2806 smb_SendTran2Error(vcp, p, opx, code);
2807 smb_FreeTran2Packet(outp);
2812 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2813 cm_ReleaseSCache(scp);
2814 cm_ReleaseUser(userp);
2815 if ( WANTS_DFS_PATHNAMES(p) )
2816 code = CM_ERROR_PATH_NOT_COVERED;
2818 code = CM_ERROR_BADSHARENAME;
2819 smb_SendTran2Error(vcp, p, opx, code);
2820 smb_FreeTran2Packet(outp);
2823 #endif /* DFS_SUPPORT */
2825 lock_ObtainMutex(&scp->mx);
2827 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2828 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2829 if (code) goto done;
2831 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2833 /* now we have the status in the cache entry, and everything is locked.
2834 * Marshall the output data.
2836 /* for info level 108, figure out short name */
2837 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
2838 code = cm_GetShortName(pathp, userp, &req,
2839 tidPathp, scp->fid.vnode, shortName,
2845 qpi.u.QPfileAltNameInfo.fileNameLength = (len + 1) * 2;
2846 mbstowcs((unsigned short *)qpi.u.QPfileAltNameInfo.fileName, shortName, len + 1);
2850 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2851 len = strlen(lastComp);
2852 qpi.u.QPfileNameInfo.fileNameLength = (len + 1) * 2;
2853 mbstowcs((unsigned short *)qpi.u.QPfileNameInfo.fileName, lastComp, len + 1);
2857 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2858 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2859 qpi.u.QPstandardInfo.creationDateTime = dosTime;
2860 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
2861 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
2862 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
2863 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
2864 attributes = smb_Attributes(scp);
2865 qpi.u.QPstandardInfo.attributes = attributes;
2866 qpi.u.QPstandardInfo.eaSize = 0;
2868 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2869 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2870 qpi.u.QPfileBasicInfo.creationTime = ft;
2871 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
2872 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
2873 qpi.u.QPfileBasicInfo.changeTime = ft;
2874 extAttributes = smb_ExtAttributes(scp);
2875 qpi.u.QPfileBasicInfo.attributes = extAttributes;
2876 qpi.u.QPfileBasicInfo.reserved = 0;
2878 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2879 smb_fid_t *fidp = smb_FindFIDByScache(vcp, scp);
2881 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
2882 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
2883 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
2884 qpi.u.QPfileStandardInfo.directory =
2885 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2886 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2887 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2888 qpi.u.QPfileStandardInfo.reserved = 0;
2891 lock_ReleaseMutex(&scp->mx);
2893 lock_ObtainMutex(&fidp->mx);
2894 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
2895 lock_ReleaseMutex(&fidp->mx);
2896 smb_ReleaseFID(fidp);
2898 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
2900 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2901 qpi.u.QPfileEaInfo.eaSize = 0;
2903 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
2904 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2905 qpi.u.QPfileAllInfo.creationTime = ft;
2906 qpi.u.QPfileAllInfo.lastAccessTime = ft;
2907 qpi.u.QPfileAllInfo.lastWriteTime = ft;
2908 qpi.u.QPfileAllInfo.changeTime = ft;
2909 extAttributes = smb_ExtAttributes(scp);
2910 qpi.u.QPfileAllInfo.attributes = extAttributes;
2911 qpi.u.QPfileAllInfo.allocationSize = scp->length;
2912 qpi.u.QPfileAllInfo.endOfFile = scp->length;
2913 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
2914 qpi.u.QPfileAllInfo.deletePending = 0;
2915 qpi.u.QPfileAllInfo.directory =
2916 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2917 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2918 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2919 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
2920 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
2921 qpi.u.QPfileAllInfo.eaSize = 0;
2922 qpi.u.QPfileAllInfo.accessFlags = 0;
2923 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
2924 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
2925 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
2926 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
2927 qpi.u.QPfileAllInfo.mode = 0;
2928 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
2929 len = strlen(lastComp);
2930 qpi.u.QPfileAllInfo.fileNameLength = (len + 1) * 2;
2931 mbstowcs((unsigned short *)qpi.u.QPfileAllInfo.fileName, lastComp, len + 1);
2934 /* send and free the packets */
2937 lock_ReleaseMutex(&scp->mx);
2938 cm_ReleaseSCache(scp);
2939 cm_ReleaseUser(userp);
2941 memcpy(outp->datap, &qpi, responseSize);
2942 smb_SendTran2Packet(vcp, outp, opx);
2944 smb_SendTran2Error(vcp, p, opx, code);
2946 smb_FreeTran2Packet(outp);
2951 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2954 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2955 return CM_ERROR_BADOP;
2959 unsigned short infoLevel;
2961 smb_tran2Packet_t *outp;
2962 smb_tran2QPathInfo_t *spi;
2964 cm_scache_t *scp, *dscp;
2972 infoLevel = p->parmsp[0];
2973 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
2974 if (infoLevel != SMB_INFO_STANDARD &&
2975 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
2976 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
2977 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2978 p->opcode, infoLevel);
2979 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
2983 pathp = (char *)(&p->parmsp[3]);
2984 if (smb_StoreAnsiFilenames)
2985 OemToChar(pathp,pathp);
2986 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %s", infoLevel,
2987 osi_LogSaveString(smb_logp, pathp));
2989 userp = smb_GetTran2User(vcp, p);
2991 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
2992 code = CM_ERROR_BADSMB;
2996 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2997 if (code == CM_ERROR_TIDIPC) {
2998 /* Attempt to use a TID allocated for IPC. The client
2999 * is probably looking for DCE RPC end points which we
3000 * don't support OR it could be looking to make a DFS
3003 osi_Log0(smb_logp, "Tran2Open received IPC TID");
3004 cm_ReleaseUser(userp);
3005 return CM_ERROR_NOSUCHPATH;
3009 * XXX Strange hack XXX
3011 * As of Patch 7 (13 January 98), we are having the following problem:
3012 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3013 * requests to look up "desktop.ini" in all the subdirectories.
3014 * This can cause zillions of timeouts looking up non-existent cells
3015 * and volumes, especially in the top-level directory.
3017 * We have not found any way to avoid this or work around it except
3018 * to explicitly ignore the requests for mount points that haven't
3019 * yet been evaluated and for directories that haven't yet been
3022 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3023 spacep = cm_GetSpace();
3024 smb_StripLastComponent(spacep->data, &lastComp, pathp);
3025 #ifndef SPECIAL_FOLDERS
3026 /* Make sure that lastComp is not NULL */
3028 if (stricmp(lastComp, "\\desktop.ini") == 0) {
3029 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3033 userp, tidPathp, &req, &dscp);
3036 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3037 if ( WANTS_DFS_PATHNAMES(p) )
3038 code = CM_ERROR_PATH_NOT_COVERED;
3040 code = CM_ERROR_BADSHARENAME;
3042 #endif /* DFS_SUPPORT */
3043 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3044 code = CM_ERROR_NOSUCHFILE;
3045 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3046 cm_buf_t *bp = buf_Find(dscp, &hzero);
3052 code = CM_ERROR_NOSUCHFILE;
3054 cm_ReleaseSCache(dscp);
3056 cm_FreeSpace(spacep);
3057 cm_ReleaseUser(userp);
3058 smb_SendTran2Error(vcp, p, opx, code);
3064 #endif /* SPECIAL_FOLDERS */
3066 cm_FreeSpace(spacep);
3069 /* now do namei and stat, and copy out the info */
3070 code = cm_NameI(cm_data.rootSCachep, pathp,
3071 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3073 cm_ReleaseUser(userp);
3074 smb_SendTran2Error(vcp, p, opx, code);
3078 fidp = smb_FindFIDByScache(vcp, scp);
3080 cm_ReleaseSCache(scp);
3081 cm_ReleaseUser(userp);
3082 smb_SendTran2Error(vcp, p, opx, code);
3086 lock_ObtainMutex(&fidp->mx);
3087 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
3088 lock_ReleaseMutex(&fidp->mx);
3089 cm_ReleaseSCache(scp);
3090 smb_ReleaseFID(fidp);
3091 cm_ReleaseUser(userp);
3092 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3095 lock_ReleaseMutex(&fidp->mx);
3097 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3099 outp->totalParms = 2;
3100 outp->totalData = 0;
3102 spi = (smb_tran2QPathInfo_t *)p->datap;
3103 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3106 /* lock the vnode with a callback; we need the current status
3107 * to determine what the new status is, in some cases.
3109 lock_ObtainMutex(&scp->mx);
3110 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3111 CM_SCACHESYNC_GETSTATUS
3112 | CM_SCACHESYNC_NEEDCALLBACK);
3114 lock_ReleaseMutex(&scp->mx);
3117 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3119 lock_ReleaseMutex(&scp->mx);
3120 lock_ObtainMutex(&fidp->mx);
3121 lock_ObtainMutex(&scp->mx);
3123 /* prepare for setattr call */
3124 attr.mask = CM_ATTRMASK_LENGTH;
3125 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3126 attr.length.HighPart = 0;
3128 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3129 smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3130 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3131 fidp->flags |= SMB_FID_MTIMESETDONE;
3134 if (spi->u.QPstandardInfo.attributes != 0) {
3135 if ((scp->unixModeBits & 0222)
3136 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3137 /* make a writable file read-only */
3138 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3139 attr.unixModeBits = scp->unixModeBits & ~0222;
3141 else if ((scp->unixModeBits & 0222) == 0
3142 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3143 /* make a read-only file writable */
3144 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3145 attr.unixModeBits = scp->unixModeBits | 0222;
3148 lock_ReleaseMutex(&scp->mx);
3149 lock_ReleaseMutex(&fidp->mx);
3153 code = cm_SetAttr(scp, &attr, userp, &req);
3157 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3158 /* we don't support EAs */
3159 code = CM_ERROR_INVAL;
3163 cm_ReleaseSCache(scp);
3164 cm_ReleaseUser(userp);
3165 smb_ReleaseFID(fidp);
3167 smb_SendTran2Packet(vcp, outp, opx);
3169 smb_SendTran2Error(vcp, p, opx, code);
3170 smb_FreeTran2Packet(outp);
3176 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3178 smb_tran2Packet_t *outp;
3180 unsigned long attributes;
3181 unsigned short infoLevel;
3188 smb_tran2QFileInfo_t qfi;
3195 fidp = smb_FindFID(vcp, fid, 0);
3198 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3202 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3203 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3204 smb_CloseFID(vcp, fidp, NULL, 0);
3205 smb_ReleaseFID(fidp);
3209 infoLevel = p->parmsp[1];
3210 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3211 responseSize = sizeof(qfi.u.QFbasicInfo);
3212 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3213 responseSize = sizeof(qfi.u.QFstandardInfo);
3214 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3215 responseSize = sizeof(qfi.u.QFeaInfo);
3216 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3217 responseSize = sizeof(qfi.u.QFfileNameInfo);
3219 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3220 p->opcode, infoLevel);
3221 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3222 smb_ReleaseFID(fidp);
3225 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3227 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3229 if (infoLevel > 0x100)
3230 outp->totalParms = 2;
3232 outp->totalParms = 0;
3233 outp->totalData = responseSize;
3235 userp = smb_GetTran2User(vcp, p);
3237 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3238 code = CM_ERROR_BADSMB;
3242 lock_ObtainMutex(&fidp->mx);
3243 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3245 osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3247 lock_ReleaseMutex(&fidp->mx);
3248 lock_ObtainMutex(&scp->mx);
3249 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3250 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3254 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3256 /* now we have the status in the cache entry, and everything is locked.
3257 * Marshall the output data.
3259 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3260 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3261 qfi.u.QFbasicInfo.creationTime = ft;
3262 qfi.u.QFbasicInfo.lastAccessTime = ft;
3263 qfi.u.QFbasicInfo.lastWriteTime = ft;
3264 qfi.u.QFbasicInfo.lastChangeTime = ft;
3265 attributes = smb_ExtAttributes(scp);
3266 qfi.u.QFbasicInfo.attributes = attributes;
3268 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3269 qfi.u.QFstandardInfo.allocationSize = scp->length;
3270 qfi.u.QFstandardInfo.endOfFile = scp->length;
3271 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3272 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3273 qfi.u.QFstandardInfo.directory =
3274 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3275 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3276 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3278 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3279 qfi.u.QFeaInfo.eaSize = 0;
3281 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3285 lock_ReleaseMutex(&scp->mx);
3286 lock_ObtainMutex(&fidp->mx);
3287 lock_ObtainMutex(&scp->mx);
3288 if (fidp->NTopen_wholepathp)
3289 name = fidp->NTopen_wholepathp;
3291 name = "\\"; /* probably can't happen */
3292 lock_ReleaseMutex(&fidp->mx);
3293 len = (unsigned long)strlen(name);
3294 outp->totalData = ((len+1)*2) + 4; /* this is actually what we want to return */
3295 qfi.u.QFfileNameInfo.fileNameLength = (len + 1) * 2;
3296 mbstowcs((unsigned short *)qfi.u.QFfileNameInfo.fileName, name, len + 1);
3299 /* send and free the packets */
3301 lock_ReleaseMutex(&scp->mx);
3302 cm_ReleaseSCache(scp);
3303 cm_ReleaseUser(userp);
3304 smb_ReleaseFID(fidp);
3306 memcpy(outp->datap, &qfi, responseSize);
3307 smb_SendTran2Packet(vcp, outp, opx);
3309 smb_SendTran2Error(vcp, p, opx, code);
3311 smb_FreeTran2Packet(outp);
3316 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3321 unsigned short infoLevel;
3322 smb_tran2Packet_t *outp;
3323 cm_user_t *userp = NULL;
3324 cm_scache_t *scp = NULL;
3330 fidp = smb_FindFID(vcp, fid, 0);
3333 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3337 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3338 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3339 smb_CloseFID(vcp, fidp, NULL, 0);
3340 smb_ReleaseFID(fidp);
3344 infoLevel = p->parmsp[1];
3345 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3346 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3347 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3348 p->opcode, infoLevel);
3349 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3350 smb_ReleaseFID(fidp);
3354 lock_ObtainMutex(&fidp->mx);
3355 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
3356 !(fidp->flags & SMB_FID_OPENDELETE)) {
3357 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3358 fidp, fidp->scp, fidp->flags);
3359 lock_ReleaseMutex(&fidp->mx);
3360 smb_ReleaseFID(fidp);
3361 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3364 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3365 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3366 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3367 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3368 fidp, fidp->scp, fidp->flags);
3369 lock_ReleaseMutex(&fidp->mx);
3370 smb_ReleaseFID(fidp);
3371 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3376 osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3378 lock_ReleaseMutex(&fidp->mx);
3380 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3382 outp->totalParms = 2;
3383 outp->totalData = 0;
3385 userp = smb_GetTran2User(vcp, p);
3387 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3388 code = CM_ERROR_BADSMB;
3392 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3394 unsigned int attribute;
3396 smb_tran2QFileInfo_t *sfi;
3398 sfi = (smb_tran2QFileInfo_t *)p->datap;
3400 /* lock the vnode with a callback; we need the current status
3401 * to determine what the new status is, in some cases.
3403 lock_ObtainMutex(&scp->mx);
3404 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3405 CM_SCACHESYNC_GETSTATUS
3406 | CM_SCACHESYNC_NEEDCALLBACK);
3408 lock_ReleaseMutex(&scp->mx);
3412 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3414 lock_ReleaseMutex(&scp->mx);
3415 lock_ObtainMutex(&fidp->mx);
3416 lock_ObtainMutex(&scp->mx);
3418 /* prepare for setattr call */
3421 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3422 /* when called as result of move a b, lastMod is (-1, -1).
3423 * If the check for -1 is not present, timestamp
3424 * of the resulting file will be 1969 (-1)
3426 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3427 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3428 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3429 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3430 fidp->flags |= SMB_FID_MTIMESETDONE;
3433 attribute = sfi->u.QFbasicInfo.attributes;
3434 if (attribute != 0) {
3435 if ((scp->unixModeBits & 0222)
3436 && (attribute & SMB_ATTR_READONLY) != 0) {
3437 /* make a writable file read-only */
3438 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3439 attr.unixModeBits = scp->unixModeBits & ~0222;
3441 else if ((scp->unixModeBits & 0222) == 0
3442 && (attribute & SMB_ATTR_READONLY) == 0) {
3443 /* make a read-only file writable */
3444 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3445 attr.unixModeBits = scp->unixModeBits | 0222;
3448 lock_ReleaseMutex(&scp->mx);
3449 lock_ReleaseMutex(&fidp->mx);
3453 code = cm_SetAttr(scp, &attr, userp, &req);
3457 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3458 int delflag = *((char *)(p->datap));
3459 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
3460 delflag, fidp, scp);
3461 if (*((char *)(p->datap))) { /* File is Deleted */
3462 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3465 lock_ObtainMutex(&fidp->mx);
3466 fidp->flags |= SMB_FID_DELONCLOSE;
3467 lock_ReleaseMutex(&fidp->mx);
3469 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
3475 lock_ObtainMutex(&fidp->mx);
3476 fidp->flags &= ~SMB_FID_DELONCLOSE;
3477 lock_ReleaseMutex(&fidp->mx);
3480 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3481 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3482 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3485 attr.mask = CM_ATTRMASK_LENGTH;
3486 attr.length.LowPart = size.LowPart;
3487 attr.length.HighPart = size.HighPart;
3488 code = cm_SetAttr(scp, &attr, userp, &req);
3492 cm_ReleaseSCache(scp);
3493 cm_ReleaseUser(userp);
3494 smb_ReleaseFID(fidp);
3496 smb_SendTran2Packet(vcp, outp, opx);
3498 smb_SendTran2Error(vcp, p, opx, code);
3499 smb_FreeTran2Packet(outp);
3505 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3507 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3508 return CM_ERROR_BADOP;
3512 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3514 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3515 return CM_ERROR_BADOP;
3519 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3521 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3522 return CM_ERROR_BADOP;
3526 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3528 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3529 return CM_ERROR_BADOP;
3533 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3535 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3536 return CM_ERROR_BADOP;
3540 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3542 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3543 return CM_ERROR_BADOP;
3546 struct smb_v2_referral {
3548 USHORT ReferralFlags;
3551 USHORT DfsPathOffset;
3552 USHORT DfsAlternativePathOffset;
3553 USHORT NetworkAddressOffset;
3557 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3559 /* This is a UNICODE only request (bit15 of Flags2) */
3560 /* The TID must be IPC$ */
3562 /* The documentation for the Flags response field is contradictory */
3564 /* Use Version 1 Referral Element Format */
3565 /* ServerType = 0; indicates the next server should be queried for the file */
3566 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3567 /* Node = UnicodeString of UNC path of the next share name */
3570 int maxReferralLevel = 0;
3571 char requestFileName[1024] = "";
3572 smb_tran2Packet_t *outp = 0;
3573 cm_user_t *userp = 0;
3575 CPINFO CodePageInfo;
3576 int i, nbnLen, reqLen;
3581 maxReferralLevel = p->parmsp[0];
3583 GetCPInfo(CP_ACP, &CodePageInfo);
3584 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
3585 requestFileName, 1024, NULL, NULL);
3587 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
3588 maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3590 nbnLen = strlen(cm_NetbiosName);
3591 reqLen = strlen(requestFileName);
3593 if (reqLen == nbnLen + 5 &&
3594 requestFileName[0] == '\\' &&
3595 !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3596 requestFileName[nbnLen+1] == '\\' &&
3597 (!_strnicmp("all",&requestFileName[nbnLen+2],3) ||
3598 !_strnicmp("*.",&requestFileName[nbnLen+2],2)))
3601 struct smb_v2_referral * v2ref;
3602 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
3604 sp = (USHORT *)outp->datap;
3606 sp[idx++] = reqLen; /* path consumed */
3607 sp[idx++] = 1; /* number of referrals */
3608 sp[idx++] = 0x03; /* flags */
3609 #ifdef DFS_VERSION_1
3610 sp[idx++] = 1; /* Version Number */
3611 sp[idx++] = reqLen + 4; /* Referral Size */
3612 sp[idx++] = 1; /* Type = SMB Server */
3613 sp[idx++] = 0; /* Do not strip path consumed */
3614 for ( i=0;i<=reqLen; i++ )
3615 sp[i+idx] = requestFileName[i];
3616 #else /* DFS_VERSION_2 */
3617 sp[idx++] = 2; /* Version Number */
3618 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3619 idx += (sizeof(struct smb_v2_referral) / 2);
3620 v2ref = (struct smb_v2_referral *) &sp[5];
3621 v2ref->ServerType = 1; /* SMB Server */
3622 v2ref->ReferralFlags = 0x03;
3623 v2ref->Proximity = 0; /* closest */
3624 v2ref->TimeToLive = 3600; /* seconds */
3625 v2ref->DfsPathOffset = idx * 2;
3626 v2ref->DfsAlternativePathOffset = idx * 2;
3627 v2ref->NetworkAddressOffset = 0;
3628 for ( i=0;i<=reqLen; i++ )
3629 sp[i+idx] = requestFileName[i];
3632 userp = smb_GetTran2User(vcp, p);
3634 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3635 code = CM_ERROR_BADSMB;
3640 code = CM_ERROR_NOSUCHPATH;
3645 cm_ReleaseUser(userp);
3647 smb_SendTran2Packet(vcp, outp, op);
3649 smb_SendTran2Error(vcp, p, op, code);
3651 smb_FreeTran2Packet(outp);
3654 #else /* DFS_SUPPORT */
3655 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3656 return CM_ERROR_BADOP;
3657 #endif /* DFS_SUPPORT */
3661 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3663 /* This is a UNICODE only request (bit15 of Flags2) */
3665 /* There is nothing we can do about this operation. The client is going to
3666 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3667 * Unfortunately, there is really nothing we can do about it other then log it
3668 * somewhere. Even then I don't think there is anything for us to do.
3669 * So let's return an error value.
3672 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3673 return CM_ERROR_BADOP;
3677 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3678 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3683 cm_scache_t *targetScp; /* target if scp is a symlink */
3688 unsigned short attr;
3689 unsigned long lattr;
3690 smb_dirListPatch_t *patchp;
3691 smb_dirListPatch_t *npatchp;
3693 afs_int32 mustFake = 0;
3695 code = cm_FindACLCache(dscp, userp, &rights);
3696 if (code == 0 && !(rights & PRSFS_READ))
3698 else if (code == -1) {
3699 lock_ObtainMutex(&dscp->mx);
3700 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
3701 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3702 lock_ReleaseMutex(&dscp->mx);
3703 if (code == CM_ERROR_NOACCESS) {
3711 for(patchp = *dirPatchespp; patchp; patchp =
3712 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3713 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3717 lock_ObtainMutex(&scp->mx);
3719 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3720 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3721 if (mustFake || code) {
3722 lock_ReleaseMutex(&scp->mx);
3724 dptr = patchp->dptr;
3726 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3727 errors in the client. */
3728 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3729 /* 1969-12-31 23:59:59 +00 */
3730 ft.dwHighDateTime = 0x19DB200;
3731 ft.dwLowDateTime = 0x5BB78980;
3733 /* copy to Creation Time */
3734 *((FILETIME *)dptr) = ft;
3737 /* copy to Last Access Time */
3738 *((FILETIME *)dptr) = ft;
3741 /* copy to Last Write Time */
3742 *((FILETIME *)dptr) = ft;
3745 /* copy to Change Time */
3746 *((FILETIME *)dptr) = ft;
3749 switch (scp->fileType) {
3750 case CM_SCACHETYPE_DIRECTORY:
3751 case CM_SCACHETYPE_MOUNTPOINT:
3752 case CM_SCACHETYPE_SYMLINK:
3753 case CM_SCACHETYPE_INVALID:
3754 *((u_long *)dptr) = SMB_ATTR_DIRECTORY;
3757 /* if we get here we either have a normal file
3758 * or we have a file for which we have never
3759 * received status info. In this case, we can
3760 * check the even/odd value of the entry's vnode.
3761 * even means it is to be treated as a directory
3762 * and odd means it is to be treated as a file.
3764 if (mustFake && (scp->fid.vnode & 0x1))
3765 *((u_long *)dptr) = SMB_ATTR_DIRECTORY;
3767 *((u_long *)dptr) = SMB_ATTR_NORMAL;
3770 /* merge in hidden attribute */
3771 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3772 *((u_long *)dptr) |= SMB_ATTR_HIDDEN;
3776 /* 1969-12-31 23:59:58 +00*/
3777 dosTime = 0xEBBFBF7D;
3779 /* and copy out date */
3780 shortTemp = (dosTime>>16) & 0xffff;
3781 *((u_short *)dptr) = shortTemp;
3784 /* copy out creation time */
3785 shortTemp = dosTime & 0xffff;
3786 *((u_short *)dptr) = shortTemp;
3789 /* and copy out date */
3790 shortTemp = (dosTime>>16) & 0xffff;
3791 *((u_short *)dptr) = shortTemp;
3794 /* copy out access time */
3795 shortTemp = dosTime & 0xffff;
3796 *((u_short *)dptr) = shortTemp;
3799 /* and copy out date */
3800 shortTemp = (dosTime>>16) & 0xffff;
3801 *((u_short *)dptr) = shortTemp;
3804 /* copy out mod time */
3805 shortTemp = dosTime & 0xffff;
3806 *((u_short *)dptr) = shortTemp;
3809 /* set the attribute */
3810 switch (scp->fileType) {
3811 case CM_SCACHETYPE_DIRECTORY:
3812 case CM_SCACHETYPE_MOUNTPOINT:
3813 case CM_SCACHETYPE_SYMLINK:
3814 case CM_SCACHETYPE_INVALID:
3815 attr = SMB_ATTR_DIRECTORY;
3817 attr = SMB_ATTR_NORMAL;
3819 /* merge in hidden (dot file) attribute */
3820 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3821 attr |= SMB_ATTR_HIDDEN;
3823 *dptr++ = attr & 0xff;
3824 *dptr++ = (attr >> 8) & 0xff;
3827 cm_ReleaseSCache(scp);
3831 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3833 /* now watch for a symlink */
3835 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3836 lock_ReleaseMutex(&scp->mx);
3837 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3839 /* we have a more accurate file to use (the
3840 * target of the symbolic link). Otherwise,
3841 * we'll just use the symlink anyway.
3843 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3845 cm_ReleaseSCache(scp);
3848 lock_ObtainMutex(&scp->mx);
3851 dptr = patchp->dptr;
3853 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3855 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3857 /* copy to Creation Time */
3858 *((FILETIME *)dptr) = ft;
3861 /* copy to Last Access Time */
3862 *((FILETIME *)dptr) = ft;
3865 /* copy to Last Write Time */
3866 *((FILETIME *)dptr) = ft;
3869 /* copy to Change Time */
3870 *((FILETIME *)dptr) = ft;
3873 /* Use length for both file length and alloc length */
3874 *((LARGE_INTEGER *)dptr) = scp->length;
3876 *((LARGE_INTEGER *)dptr) = scp->length;
3879 /* Copy attributes */
3880 lattr = smb_ExtAttributes(scp);
3881 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3882 if (lattr == SMB_ATTR_NORMAL)
3883 lattr = SMB_ATTR_DIRECTORY;
3885 lattr |= SMB_ATTR_DIRECTORY;
3887 /* merge in hidden (dot file) attribute */
3888 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3889 if (lattr == SMB_ATTR_NORMAL)
3890 lattr = SMB_ATTR_HIDDEN;
3892 lattr |= SMB_ATTR_HIDDEN;
3894 *((u_long *)dptr) = lattr;
3898 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3900 /* and copy out date */
3901 shortTemp = (dosTime>>16) & 0xffff;
3902 *((u_short *)dptr) = shortTemp;
3905 /* copy out creation time */
3906 shortTemp = dosTime & 0xffff;
3907 *((u_short *)dptr) = shortTemp;
3910 /* and copy out date */
3911 shortTemp = (dosTime>>16) & 0xffff;
3912 *((u_short *)dptr) = shortTemp;
3915 /* copy out access time */
3916 shortTemp = dosTime & 0xffff;
3917 *((u_short *)dptr) = shortTemp;
3920 /* and copy out date */
3921 shortTemp = (dosTime>>16) & 0xffff;
3922 *((u_short *)dptr) = shortTemp;
3925 /* copy out mod time */
3926 shortTemp = dosTime & 0xffff;
3927 *((u_short *)dptr) = shortTemp;
3930 /* copy out file length and alloc length,
3931 * using the same for both
3933 *((u_long *)dptr) = scp->length.LowPart;
3935 *((u_long *)dptr) = scp->length.LowPart;
3938 /* finally copy out attributes as short */
3939 attr = smb_Attributes(scp);
3940 /* merge in hidden (dot file) attribute */
3941 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3942 if (lattr == SMB_ATTR_NORMAL)
3943 lattr = SMB_ATTR_HIDDEN;
3945 lattr |= SMB_ATTR_HIDDEN;
3947 *dptr++ = attr & 0xff;
3948 *dptr++ = (attr >> 8) & 0xff;
3951 lock_ReleaseMutex(&scp->mx);
3952 cm_ReleaseSCache(scp);
3955 /* now free the patches */
3956 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3957 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3961 /* and mark the list as empty */
3962 *dirPatchespp = NULL;
3967 // char table for case insensitive comparison
3968 char mapCaseTable[256];
3970 VOID initUpperCaseTable(VOID)
3973 for (i = 0; i < 256; ++i)
3974 mapCaseTable[i] = toupper(i);
3975 // make '"' match '.'
3976 mapCaseTable[(int)'"'] = toupper('.');
3977 // make '<' match '*'
3978 mapCaseTable[(int)'<'] = toupper('*');
3979 // make '>' match '?'
3980 mapCaseTable[(int)'>'] = toupper('?');
3983 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3985 // Note : this procedure works recursively calling itself.
3987 // PSZ pattern : string containing metacharacters.
3988 // PSZ name : file name to be compared with 'pattern'.
3990 // BOOL : TRUE/FALSE (match/mistmatch)
3993 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
3995 PSZ pename; // points to the last 'name' character
3997 pename = name + strlen(name) - 1;
4008 if (*pattern == '\0')
4010 for (p = pename; p >= name; --p) {
4011 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
4012 !casefold && (*p == *pattern)) &&
4013 szWildCardMatchFileName(pattern + 1, p + 1, casefold))
4018 if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
4019 (!casefold && *name != *pattern))
4026 /* if all we have left are wildcards, then we match */
4027 for (;*pattern; pattern++) {
4028 if (*pattern != '*' && *pattern != '?')
4034 /* do a case-folding search of the star name mask with the name in namep.
4035 * Return 1 if we match, otherwise 0.
4037 int smb_V3MatchMask(char *namep, char *maskp, int flags)
4040 int i, j, star, qmark, casefold, retval;
4042 /* make sure we only match 8.3 names, if requested */
4043 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
4046 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
4048 /* optimize the pattern:
4049 * if there is a mixture of '?' and '*',
4050 * for example the sequence "*?*?*?*"
4051 * must be turned into the form "*"
4053 newmask = (char *)malloc(strlen(maskp)+1);
4054 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
4055 switch ( maskp[i] ) {
4067 } else if ( qmark ) {
4071 newmask[j++] = maskp[i];
4078 } else if ( qmark ) {
4082 newmask[j++] = '\0';
4084 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
4091 /* smb_ReceiveTran2SearchDir implements both
4092 * Tran2_Find_First and Tran2_Find_Next
4094 #define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
4095 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
4096 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
4097 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
4098 #define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
4100 /* this is an optimized handler for T2SearchDir that handles the case
4101 where there are no wildcards in the search path. I.e. an
4102 application is using FindFirst(Ex) to get information about a
4103 single file or directory. It will attempt to do a single lookup.
4104 If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4105 the usual mechanism.
4107 This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4109 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4113 long code = 0, code2 = 0;
4116 smb_dirListPatch_t *dirListPatchesp;
4117 smb_dirListPatch_t *curPatchp;
4118 long orbytes; /* # of bytes in this output record */
4119 long ohbytes; /* # of bytes, except file name */
4120 long onbytes; /* # of bytes in name, incl. term. null */
4121 cm_scache_t *scp = NULL;
4122 cm_scache_t *targetscp = NULL;
4123 cm_user_t *userp = NULL;
4124 char *op; /* output data ptr */
4125 char *origOp; /* original value of op */
4126 cm_space_t *spacep; /* for pathname buffer */
4127 long maxReturnData; /* max # of return data */
4128 long maxReturnParms; /* max # of return parms */
4129 long bytesInBuffer; /* # data bytes in the output buffer */
4130 char *maskp; /* mask part of path */
4134 smb_tran2Packet_t *outp; /* response packet */
4137 char shortName[13]; /* 8.3 name if needed */
4146 osi_assertx(p->opcode == 1, "invalid opcode");
4148 /* find first; obtain basic parameters from request */
4150 /* note that since we are going to failover to regular
4151 * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4152 * modify any of the input parameters here. */
4153 attribute = p->parmsp[0];
4154 maxCount = p->parmsp[1];
4155 infoLevel = p->parmsp[3];
4156 searchFlags = p->parmsp[2];
4157 pathp = ((char *) p->parmsp) + 12; /* points to path */
4159 maskp = strrchr(pathp, '\\');
4163 maskp++; /* skip over backslash */
4164 /* track if this is likely to match a lot of entries */
4166 osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%s], mask[%s]",
4167 osi_LogSaveString(smb_logp, pathp),
4168 osi_LogSaveString(smb_logp, maskp));
4170 switch ( infoLevel ) {
4171 case SMB_INFO_STANDARD:
4174 case SMB_INFO_QUERY_EA_SIZE:
4175 s = "InfoQueryEaSize";
4177 case SMB_INFO_QUERY_EAS_FROM_LIST:
4178 s = "InfoQueryEasFromList";
4180 case SMB_FIND_FILE_DIRECTORY_INFO:
4181 s = "FindFileDirectoryInfo";
4183 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4184 s = "FindFileFullDirectoryInfo";
4186 case SMB_FIND_FILE_NAMES_INFO:
4187 s = "FindFileNamesInfo";
4189 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4190 s = "FindFileBothDirectoryInfo";
4193 s = "unknownInfoLevel";
4196 osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
4199 "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4200 attribute, infoLevel, maxCount, searchFlags);
4202 if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4203 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4204 return CM_ERROR_INVAL;
4207 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4208 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4210 dirListPatchesp = NULL;
4212 maxReturnData = p->maxReturnData;
4213 maxReturnParms = 10; /* return params for findfirst, which
4214 is the only one we handle.*/
4216 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4217 if (maxReturnData > 6000)
4218 maxReturnData = 6000;
4219 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4221 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4224 osi_Log2(smb_logp, "T2SDSingle search dir count %d [%s]",
4225 maxCount, osi_LogSaveString(smb_logp, pathp));
4227 /* bail out if request looks bad */
4229 smb_FreeTran2Packet(outp);
4230 return CM_ERROR_BADSMB;
4233 userp = smb_GetTran2User(vcp, p);
4235 osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
4236 smb_FreeTran2Packet(outp);
4237 return CM_ERROR_BADSMB;
4240 /* try to get the vnode for the path name next */
4241 spacep = cm_GetSpace();
4242 smb_StripLastComponent(spacep->data, NULL, pathp);
4243 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4245 cm_ReleaseUser(userp);
4246 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4247 smb_FreeTran2Packet(outp);
4251 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4252 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4253 userp, tidPathp, &req, &scp);
4254 cm_FreeSpace(spacep);
4257 cm_ReleaseUser(userp);
4258 smb_SendTran2Error(vcp, p, opx, code);
4259 smb_FreeTran2Packet(outp);
4263 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4264 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4265 cm_ReleaseSCache(scp);
4266 cm_ReleaseUser(userp);
4267 if ( WANTS_DFS_PATHNAMES(p) )
4268 code = CM_ERROR_PATH_NOT_COVERED;
4270 code = CM_ERROR_BADSHARENAME;
4271 smb_SendTran2Error(vcp, p, opx, code);
4272 smb_FreeTran2Packet(outp);
4275 #endif /* DFS_SUPPORT */
4276 osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
4278 /* now do a single case sensitive lookup for the file in question */
4279 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
4281 /* if a case sensitive match failed, we try a case insensitive one
4283 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
4284 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
4287 if (code == 0 && targetscp->fid.vnode == 0) {
4288 cm_ReleaseSCache(targetscp);
4289 code = CM_ERROR_NOSUCHFILE;
4293 /* if we can't find the directory entry, this block will
4294 return CM_ERROR_NOSUCHFILE, which we will pass on to
4295 smb_ReceiveTran2SearchDir(). */
4296 cm_ReleaseSCache(scp);
4297 cm_ReleaseUser(userp);
4298 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4299 smb_SendTran2Error(vcp, p, opx, code);
4302 smb_FreeTran2Packet(outp);
4306 /* now that we have the target in sight, we proceed with filling
4307 up the return data. */
4309 op = origOp = outp->datap;
4312 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4313 /* skip over resume key */
4317 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4318 && targetscp->fid.vnode != 0
4319 && !cm_Is8Dot3(maskp)) {
4322 dfid.vnode = htonl(targetscp->fid.vnode);
4323 dfid.unique = htonl(targetscp->fid.unique);
4325 cm_Gen8Dot3NameInt(maskp, &dfid, shortName, &shortNameEnd);
4331 osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %s (%s)",
4332 htonl(targetscp->fid.vnode),
4333 htonl(targetscp->fid.unique),
4334 osi_LogSaveString(smb_logp, pathp),
4335 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4337 /* Eliminate entries that don't match requested attributes */
4338 if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
4339 smb_IsDotFile(maskp)) {
4341 code = CM_ERROR_NOSUCHFILE;
4342 osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
4347 if (!(attribute & SMB_ATTR_DIRECTORY) &&
4348 (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
4349 targetscp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4350 targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
4351 targetscp->fileType == CM_SCACHETYPE_INVALID)) {
4353 code = CM_ERROR_NOSUCHFILE;
4354 osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
4359 /* Check if the name will fit */
4360 if (infoLevel < 0x101)
4361 ohbytes = 23; /* pre-NT */
4362 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4363 ohbytes = 12; /* NT names only */
4365 ohbytes = 64; /* NT */
4367 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
4368 ohbytes += 26; /* Short name & length */
4370 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4371 ohbytes += 4; /* if resume key required */
4374 if (infoLevel != SMB_INFO_STANDARD
4375 && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
4376 && infoLevel != SMB_FIND_FILE_NAMES_INFO)
4377 ohbytes += 4; /* EASIZE */
4379 /* add header to name & term. null */
4380 onbytes = strlen(maskp);
4381 orbytes = ohbytes + onbytes + 1;
4383 /* now, we round up the record to a 4 byte alignment, and we make
4384 * sure that we have enough room here for even the aligned version
4385 * (so we don't have to worry about an * overflow when we pad
4386 * things out below). That's the reason for the alignment
4389 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4390 align = (4 - (orbytes & 3)) & 3;
4394 if (orbytes + align > maxReturnData) {
4396 /* even though this request is unlikely to succeed with a
4397 failover, we do it anyway. */
4398 code = CM_ERROR_NOSUCHFILE;
4399 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4404 /* this is one of the entries to use: it is not deleted and it
4405 * matches the star pattern we're looking for. Put out the name,
4406 * preceded by its length.
4408 /* First zero everything else */
4409 memset(origOp, 0, ohbytes);
4411 if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
4412 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4413 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4414 *((u_long *)(op + 8)) = onbytes;
4416 *((u_long *)(op + 60)) = onbytes;
4417 strcpy(origOp+ohbytes, maskp);
4418 if (smb_StoreAnsiFilenames)
4419 CharToOem(origOp+ohbytes, origOp+ohbytes);
4421 /* Short name if requested and needed */
4422 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4423 if (NeedShortName) {
4424 strcpy(op + 70, shortName);
4425 if (smb_StoreAnsiFilenames)
4426 CharToOem(op + 70, op + 70);
4427 *(op + 68) = (char)(shortNameEnd - shortName);
4431 /* NextEntryOffset and FileIndex */
4432 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4433 int entryOffset = orbytes + align;
4434 *((u_long *)op) = 0;
4435 *((u_long *)(op+4)) = 0;
4438 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4439 curPatchp = malloc(sizeof(*curPatchp));
4440 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4442 curPatchp->dptr = op;
4443 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4444 curPatchp->dptr += 8;
4446 if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
4447 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4449 curPatchp->flags = 0;
4452 curPatchp->fid.cell = targetscp->fid.cell;
4453 curPatchp->fid.volume = targetscp->fid.volume;
4454 curPatchp->fid.vnode = targetscp->fid.vnode;
4455 curPatchp->fid.unique = targetscp->fid.unique;
4458 curPatchp->dep = NULL;
4461 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4462 /* put out resume key */
4463 *((u_long *)origOp) = 0;
4466 /* Adjust byte ptr and count */
4467 origOp += orbytes; /* skip entire record */
4468 bytesInBuffer += orbytes;
4470 /* and pad the record out */
4471 while (--align >= 0) {
4476 /* apply the patches */
4477 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp, &req);
4479 outp->parmsp[0] = 0;
4480 outp->parmsp[1] = 1; /* number of names returned */
4481 outp->parmsp[2] = 1; /* end of search */
4482 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4483 outp->parmsp[4] = 0;
4485 outp->totalParms = 10; /* in bytes */
4487 outp->totalData = bytesInBuffer;
4489 osi_Log0(smb_logp, "T2SDSingle done.");
4491 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4493 smb_SendTran2Error(vcp, p, opx, code);
4495 smb_SendTran2Packet(vcp, outp, opx);
4500 smb_FreeTran2Packet(outp);
4501 cm_ReleaseSCache(scp);
4502 cm_ReleaseSCache(targetscp);
4503 cm_ReleaseUser(userp);
4509 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4514 long code = 0, code2 = 0;
4518 smb_dirListPatch_t *dirListPatchesp;
4519 smb_dirListPatch_t *curPatchp;
4522 long orbytes; /* # of bytes in this output record */
4523 long ohbytes; /* # of bytes, except file name */
4524 long onbytes; /* # of bytes in name, incl. term. null */
4525 osi_hyper_t dirLength;
4526 osi_hyper_t bufferOffset;
4527 osi_hyper_t curOffset;
4529 smb_dirSearch_t *dsp;
4533 cm_pageHeader_t *pageHeaderp;
4534 cm_user_t *userp = NULL;
4537 long nextEntryCookie;
4538 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4539 char *op; /* output data ptr */
4540 char *origOp; /* original value of op */
4541 cm_space_t *spacep; /* for pathname buffer */
4542 long maxReturnData; /* max # of return data */
4543 long maxReturnParms; /* max # of return parms */
4544 long bytesInBuffer; /* # data bytes in the output buffer */
4546 char *maskp; /* mask part of path */
4550 smb_tran2Packet_t *outp; /* response packet */
4553 char shortName[13]; /* 8.3 name if needed */
4565 if (p->opcode == 1) {
4566 /* find first; obtain basic parameters from request */
4567 attribute = p->parmsp[0];
4568 maxCount = p->parmsp[1];
4569 infoLevel = p->parmsp[3];
4570 searchFlags = p->parmsp[2];
4571 pathp = ((char *) p->parmsp) + 12; /* points to path */
4572 if (smb_StoreAnsiFilenames)
4573 OemToChar(pathp,pathp);
4575 maskp = strrchr(pathp, '\\');
4579 maskp++; /* skip over backslash */
4581 /* track if this is likely to match a lot of entries */
4582 starPattern = smb_V3IsStarMask(maskp);
4584 #ifndef NOFINDFIRSTOPTIMIZE
4586 /* if this is for a single directory or file, we let the
4587 optimized routine handle it. The only error it
4588 returns is CM_ERROR_NOSUCHFILE. The */
4589 code = smb_T2SearchDirSingle(vcp, p, opx);
4591 /* we only failover if we see a CM_ERROR_NOSUCHFILE */
4592 if (code != CM_ERROR_NOSUCHFILE) {
4594 /* unless we are using the BPlusTree */
4595 if (code == CM_ERROR_BPLUS_NOMATCH)
4596 code = CM_ERROR_NOSUCHFILE;
4597 #endif /* USE_BPLUS */
4604 dsp = smb_NewDirSearch(1);
4605 dsp->attribute = attribute;
4606 strcpy(dsp->mask, maskp); /* and save mask */
4609 osi_assertx(p->opcode == 2, "invalid opcode");
4610 /* find next; obtain basic parameters from request or open dir file */
4611 dsp = smb_FindDirSearch(p->parmsp[0]);
4612 maxCount = p->parmsp[1];
4613 infoLevel = p->parmsp[2];
4614 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4615 searchFlags = p->parmsp[5];
4617 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4618 p->parmsp[0], nextCookie);
4619 return CM_ERROR_BADFD;
4621 attribute = dsp->attribute;
4624 starPattern = 1; /* assume, since required a Find Next */
4627 switch ( infoLevel ) {
4628 case SMB_INFO_STANDARD:
4631 case SMB_INFO_QUERY_EA_SIZE:
4632 s = "InfoQueryEaSize";
4634 case SMB_INFO_QUERY_EAS_FROM_LIST:
4635 s = "InfoQueryEasFromList";
4637 case SMB_FIND_FILE_DIRECTORY_INFO:
4638 s = "FindFileDirectoryInfo";
4640 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4641 s = "FindFileFullDirectoryInfo";
4643 case SMB_FIND_FILE_NAMES_INFO:
4644 s = "FindFileNamesInfo";
4646 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4647 s = "FindFileBothDirectoryInfo";
4650 s = "unknownInfoLevel";
4653 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
4656 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4657 attribute, infoLevel, maxCount, searchFlags);
4659 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
4660 p->opcode, dsp->cookie, nextCookie);
4662 if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4663 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4664 smb_ReleaseDirSearch(dsp);
4665 return CM_ERROR_INVAL;
4668 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4669 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4671 dirListPatchesp = NULL;
4673 maxReturnData = p->maxReturnData;
4674 if (p->opcode == 1) /* find first */
4675 maxReturnParms = 10; /* bytes */
4677 maxReturnParms = 8; /* bytes */
4679 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4680 if (maxReturnData > 6000)
4681 maxReturnData = 6000;
4682 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4684 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4687 osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
4688 maxCount, osi_LogSaveString(smb_logp, pathp));
4690 /* bail out if request looks bad */
4691 if (p->opcode == 1 && !pathp) {
4692 smb_ReleaseDirSearch(dsp);
4693 smb_FreeTran2Packet(outp);
4694 return CM_ERROR_BADSMB;
4697 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
4698 dsp->cookie, nextCookie, attribute);
4700 userp = smb_GetTran2User(vcp, p);
4702 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
4703 smb_ReleaseDirSearch(dsp);
4704 smb_FreeTran2Packet(outp);
4705 return CM_ERROR_BADSMB;
4708 /* try to get the vnode for the path name next */
4709 lock_ObtainMutex(&dsp->mx);
4712 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4716 spacep = cm_GetSpace();
4717 smb_StripLastComponent(spacep->data, NULL, pathp);
4718 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4720 cm_ReleaseUser(userp);
4721 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4722 smb_FreeTran2Packet(outp);
4723 lock_ReleaseMutex(&dsp->mx);
4724 smb_DeleteDirSearch(dsp);
4725 smb_ReleaseDirSearch(dsp);
4728 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4729 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4730 userp, tidPathp, &req, &scp);
4731 cm_FreeSpace(spacep);
4734 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4735 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4736 cm_ReleaseSCache(scp);
4737 cm_ReleaseUser(userp);
4738 if ( WANTS_DFS_PATHNAMES(p) )
4739 code = CM_ERROR_PATH_NOT_COVERED;
4741 code = CM_ERROR_BADSHARENAME;
4742 smb_SendTran2Error(vcp, p, opx, code);
4743 smb_FreeTran2Packet(outp);
4744 lock_ReleaseMutex(&dsp->mx);
4745 smb_DeleteDirSearch(dsp);
4746 smb_ReleaseDirSearch(dsp);
4749 #endif /* DFS_SUPPORT */
4751 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4752 /* we need one hold for the entry we just stored into,
4753 * and one for our own processing. When we're done
4754 * with this function, we'll drop the one for our own
4755 * processing. We held it once from the namei call,
4756 * and so we do another hold now.
4759 lock_ObtainMutex(&scp->mx);
4760 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
4761 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4762 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4763 dsp->flags |= SMB_DIRSEARCH_BULKST;
4765 lock_ReleaseMutex(&scp->mx);
4768 lock_ReleaseMutex(&dsp->mx);
4770 cm_ReleaseUser(userp);
4771 smb_FreeTran2Packet(outp);
4772 smb_DeleteDirSearch(dsp);
4773 smb_ReleaseDirSearch(dsp);
4777 /* get the directory size */
4778 lock_ObtainMutex(&scp->mx);
4779 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4780 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4782 lock_ReleaseMutex(&scp->mx);
4783 cm_ReleaseSCache(scp);
4784 cm_ReleaseUser(userp);
4785 smb_FreeTran2Packet(outp);
4786 smb_DeleteDirSearch(dsp);
4787 smb_ReleaseDirSearch(dsp);
4791 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4794 dirLength = scp->length;
4796 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4797 curOffset.HighPart = 0;
4798 curOffset.LowPart = nextCookie;
4799 origOp = outp->datap;
4807 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4808 /* skip over resume key */
4811 /* make sure that curOffset.LowPart doesn't point to the first
4812 * 32 bytes in the 2nd through last dir page, and that it doesn't
4813 * point at the first 13 32-byte chunks in the first dir page,
4814 * since those are dir and page headers, and don't contain useful
4817 temp = curOffset.LowPart & (2048-1);
4818 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4819 /* we're in the first page */
4820 if (temp < 13*32) temp = 13*32;
4823 /* we're in a later dir page */
4824 if (temp < 32) temp = 32;
4827 /* make sure the low order 5 bits are zero */
4830 /* now put temp bits back ito curOffset.LowPart */
4831 curOffset.LowPart &= ~(2048-1);
4832 curOffset.LowPart |= temp;
4834 /* check if we've passed the dir's EOF */
4835 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4836 osi_Log0(smb_logp, "T2 search dir passed eof");
4841 /* check if we've returned all the names that will fit in the
4842 * response packet; we check return count as well as the number
4843 * of bytes requested. We check the # of bytes after we find
4844 * the dir entry, since we'll need to check its size.
4846 if (returnedNames >= maxCount) {
4847 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4848 returnedNames, maxCount);
4852 /* see if we can use the bufferp we have now; compute in which
4853 * page the current offset would be, and check whether that's
4854 * the offset of the buffer we have. If not, get the buffer.
4856 thyper.HighPart = curOffset.HighPart;
4857 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4858 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4861 buf_Release(bufferp);
4864 lock_ReleaseMutex(&scp->mx);
4865 lock_ObtainRead(&scp->bufCreateLock);
4866 code = buf_Get(scp, &thyper, &bufferp);
4867 lock_ReleaseRead(&scp->bufCreateLock);
4868 lock_ObtainMutex(&dsp->mx);
4870 /* now, if we're doing a star match, do bulk fetching
4871 * of all of the status info for files in the dir.
4874 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
4877 lock_ObtainMutex(&scp->mx);
4878 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4879 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
4880 /* Don't bulk stat if risking timeout */
4881 DWORD now = GetTickCount();
4882 if (now - req.startTime > RDRtimeout * 1000) {
4883 scp->bulkStatProgress = thyper;
4884 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4885 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4887 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4890 lock_ObtainMutex(&scp->mx);
4892 lock_ReleaseMutex(&dsp->mx);
4894 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
4898 bufferOffset = thyper;
4900 /* now get the data in the cache */
4902 code = cm_SyncOp(scp, bufferp, userp, &req,
4904 CM_SCACHESYNC_NEEDCALLBACK
4905 | CM_SCACHESYNC_READ);
4907 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
4911 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4913 if (cm_HaveBuffer(scp, bufferp, 0)) {
4914 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4918 /* otherwise, load the buffer and try again */
4919 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4922 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4923 scp, bufferp, code);
4928 buf_Release(bufferp);
4932 } /* if (wrong buffer) ... */
4934 /* now we have the buffer containing the entry we're interested
4935 * in; copy it out if it represents a non-deleted entry.
4937 entryInDir = curOffset.LowPart & (2048-1);
4938 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4940 /* page header will help tell us which entries are free. Page
4941 * header can change more often than once per buffer, since
4942 * AFS 3 dir page size may be less than (but not more than)
4943 * a buffer package buffer.
4945 /* only look intra-buffer */
4946 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4947 temp &= ~(2048 - 1); /* turn off intra-page bits */
4948 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4950 /* now determine which entry we're looking at in the page.
4951 * If it is free (there's a free bitmap at the start of the
4952 * dir), we should skip these 32 bytes.
4954 slotInPage = (entryInDir & 0x7e0) >> 5;
4955 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
4956 (1 << (slotInPage & 0x7)))) {
4957 /* this entry is free */
4958 numDirChunks = 1; /* only skip this guy */
4962 tp = bufferp->datap + entryInBuffer;
4963 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4965 /* while we're here, compute the next entry's location, too,
4966 * since we'll need it when writing out the cookie into the dir
4969 * XXXX Probably should do more sanity checking.
4971 numDirChunks = cm_NameEntries(dep->name, &onbytes);
4973 /* compute offset of cookie representing next entry */
4974 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4976 if (dep->fid.vnode == 0)
4977 goto nextEntry; /* This entry is not in use */
4979 /* Need 8.3 name? */
4981 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
4982 !cm_Is8Dot3(dep->name)) {
4983 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4987 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %s (%s)",
4988 dep->fid.vnode, dep->fid.unique,
4989 osi_LogSaveString(smb_logp, dep->name),
4990 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4992 /* When matching, we are using doing a case fold if we have a wildcard mask.
4993 * If we get a non-wildcard match, it's a lookup for a specific file.
4995 if (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
4996 (NeedShortName && smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))
4998 /* Eliminate entries that don't match requested attributes */
4999 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5000 smb_IsDotFile(dep->name)) {
5001 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5002 goto nextEntry; /* no hidden files */
5005 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5007 /* We have already done the cm_TryBulkStat above */
5008 fid.cell = scp->fid.cell;
5009 fid.volume = scp->fid.volume;
5010 fid.vnode = ntohl(dep->fid.vnode);
5011 fid.unique = ntohl(dep->fid.unique);
5012 fileType = cm_FindFileType(&fid);
5013 /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5014 * "has filetype %d", dep->name, fileType);
5016 if ( fileType == CM_SCACHETYPE_DIRECTORY ||
5017 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5018 fileType == CM_SCACHETYPE_DFSLINK ||
5019 fileType == CM_SCACHETYPE_INVALID)
5020 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5024 /* finally check if this name will fit */
5026 /* standard dir entry stuff */
5027 if (infoLevel < 0x101)
5028 ohbytes = 23; /* pre-NT */
5029 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
5030 ohbytes = 12; /* NT names only */
5032 ohbytes = 64; /* NT */
5034 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
5035 ohbytes += 26; /* Short name & length */
5037 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
5038 ohbytes += 4; /* if resume key required */
5041 if ( infoLevel != SMB_INFO_STANDARD &&
5042 infoLevel != SMB_FIND_FILE_DIRECTORY_INFO &&
5043 infoLevel != SMB_FIND_FILE_NAMES_INFO)
5044 ohbytes += 4; /* EASIZE */
5046 /* add header to name & term. null */
5047 orbytes = onbytes + ohbytes + 1;
5049 /* now, we round up the record to a 4 byte alignment,
5050 * and we make sure that we have enough room here for
5051 * even the aligned version (so we don't have to worry
5052 * about an overflow when we pad things out below).
5053 * That's the reason for the alignment arithmetic below.
5055 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5056 align = (4 - (orbytes & 3)) & 3;
5059 if (orbytes + bytesInBuffer + align > maxReturnData) {
5060 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5065 /* this is one of the entries to use: it is not deleted
5066 * and it matches the star pattern we're looking for.
5067 * Put out the name, preceded by its length.
5069 /* First zero everything else */
5070 memset(origOp, 0, ohbytes);
5072 if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
5073 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
5074 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
5075 *((u_long *)(op + 8)) = onbytes;
5077 *((u_long *)(op + 60)) = onbytes;
5078 strcpy(origOp+ohbytes, dep->name);
5079 if (smb_StoreAnsiFilenames)
5080 CharToOem(origOp+ohbytes, origOp+ohbytes);
5082 /* Short name if requested and needed */
5083 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
5084 if (NeedShortName) {
5085 strcpy(op + 70, shortName);
5086 if (smb_StoreAnsiFilenames)
5087 CharToOem(op + 70, op + 70);
5088 *(op + 68) = (char)(shortNameEnd - shortName);
5092 /* now, adjust the # of entries copied */
5095 /* NextEntryOffset and FileIndex */
5096 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
5097 int entryOffset = orbytes + align;
5098 *((u_long *)op) = entryOffset;
5099 *((u_long *)(op+4)) = nextEntryCookie;
5102 /* now we emit the attribute. This is tricky, since
5103 * we need to really stat the file to find out what
5104 * type of entry we've got. Right now, we're copying
5105 * out data from a buffer, while holding the scp
5106 * locked, so it isn't really convenient to stat
5107 * something now. We'll put in a place holder
5108 * now, and make a second pass before returning this
5109 * to get the real attributes. So, we just skip the
5110 * data for now, and adjust it later. We allocate a
5111 * patch record to make it easy to find this point
5112 * later. The replay will happen at a time when it is
5113 * safe to unlock the directory.
5115 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5116 curPatchp = malloc(sizeof(*curPatchp));
5117 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5118 curPatchp->dptr = op;
5119 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5120 curPatchp->dptr += 8;
5122 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
5123 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5126 curPatchp->flags = 0;
5128 curPatchp->fid.cell = scp->fid.cell;
5129 curPatchp->fid.volume = scp->fid.volume;
5130 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
5131 curPatchp->fid.unique = ntohl(dep->fid.unique);
5134 curPatchp->dep = dep;
5137 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5138 /* put out resume key */
5139 *((u_long *)origOp) = nextEntryCookie;
5141 /* Adjust byte ptr and count */
5142 origOp += orbytes; /* skip entire record */
5143 bytesInBuffer += orbytes;
5145 /* and pad the record out */
5146 while (--align >= 0) {
5150 } /* if we're including this name */
5151 else if (!starPattern &&
5153 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
5154 /* We were looking for exact matches, but here's an inexact one*/
5159 /* and adjust curOffset to be where the new cookie is */
5160 thyper.HighPart = 0;
5161 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5162 curOffset = LargeIntegerAdd(thyper, curOffset);
5163 } /* while copying data for dir listing */
5165 /* If we didn't get a star pattern, we did an exact match during the first pass.
5166 * If there were no exact matches found, we fail over to inexact matches by
5167 * marking the query as a star pattern (matches all case permutations), and
5168 * re-running the query.
5170 if (returnedNames == 0 && !starPattern && foundInexact) {
5171 osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
5176 /* release the mutex */
5177 lock_ReleaseMutex(&scp->mx);
5179 buf_Release(bufferp);
5183 /* apply and free last set of patches; if not doing a star match, this
5184 * will be empty, but better safe (and freeing everything) than sorry.
5186 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp, &req);
5188 /* now put out the final parameters */
5189 if (returnedNames == 0)
5191 if (p->opcode == 1) {
5193 outp->parmsp[0] = (unsigned short) dsp->cookie;
5194 outp->parmsp[1] = returnedNames;
5195 outp->parmsp[2] = eos;
5196 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5197 outp->parmsp[4] = 0;
5198 /* don't need last name to continue
5199 * search, cookie is enough. Normally,
5200 * this is the offset of the file name
5201 * of the last entry returned.
5203 outp->totalParms = 10; /* in bytes */
5207 outp->parmsp[0] = returnedNames;
5208 outp->parmsp[1] = eos;
5209 outp->parmsp[2] = 0; /* EAS error */
5210 outp->parmsp[3] = 0; /* last name, as above */
5211 outp->totalParms = 8; /* in bytes */
5214 /* return # of bytes in the buffer */
5215 outp->totalData = bytesInBuffer;
5217 /* Return error code if unsuccessful on first request */
5218 if (code == 0 && p->opcode == 1 && returnedNames == 0)
5219 code = CM_ERROR_NOSUCHFILE;
5221 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
5222 p->opcode, dsp->cookie, returnedNames, code);
5224 /* if we're supposed to close the search after this request, or if
5225 * we're supposed to close the search if we're done, and we're done,
5226 * or if something went wrong, close the search.
5228 if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
5229 (returnedNames == 0) ||
5230 ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
5232 smb_DeleteDirSearch(dsp);
5235 smb_SendTran2Error(vcp, p, opx, code);
5237 smb_SendTran2Packet(vcp, outp, opx);
5239 smb_FreeTran2Packet(outp);
5240 smb_ReleaseDirSearch(dsp);
5241 cm_ReleaseSCache(scp);
5242 cm_ReleaseUser(userp);
5246 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5249 smb_dirSearch_t *dsp;
5251 dirHandle = smb_GetSMBParm(inp, 0);
5253 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
5255 dsp = smb_FindDirSearch(dirHandle);
5258 return CM_ERROR_BADFD;
5260 /* otherwise, we have an FD to destroy */
5261 smb_DeleteDirSearch(dsp);
5262 smb_ReleaseDirSearch(dsp);
5264 /* and return results */
5265 smb_SetSMBDataLength(outp, 0);
5270 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5272 smb_SetSMBDataLength(outp, 0);
5276 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5283 cm_scache_t *dscp; /* dir we're dealing with */
5284 cm_scache_t *scp; /* file we're creating */
5286 int initialModeBits;
5296 int parmSlot; /* which parm we're dealing with */
5305 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
5306 openFun = smb_GetSMBParm(inp, 8); /* open function */
5307 excl = ((openFun & 3) == 0);
5308 trunc = ((openFun & 3) == 2); /* truncate it */
5309 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
5310 openAction = 0; /* tracks what we did */
5312 attributes = smb_GetSMBParm(inp, 5);
5313 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
5315 /* compute initial mode bits based on read-only flag in attributes */
5316 initialModeBits = 0666;
5317 if (attributes & SMB_ATTR_READONLY)
5318 initialModeBits &= ~0222;
5320 pathp = smb_GetSMBData(inp, NULL);
5321 if (smb_StoreAnsiFilenames)
5322 OemToChar(pathp,pathp);
5324 spacep = inp->spacep;
5325 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5327 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5328 /* special case magic file name for receiving IOCTL requests
5329 * (since IOCTL calls themselves aren't getting through).
5332 osi_Log0(smb_logp, "IOCTL Open");
5335 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5336 smb_SetupIoctlFid(fidp, spacep);
5338 /* set inp->fid so that later read calls in same msg can find fid */
5339 inp->fid = fidp->fid;
5341 /* copy out remainder of the parms */
5343 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5345 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
5346 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
5347 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5348 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
5349 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
5350 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5351 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5352 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5354 /* and the final "always present" stuff */
5355 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
5356 /* next write out the "unique" ID */
5357 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
5358 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
5359 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5360 smb_SetSMBDataLength(outp, 0);
5362 /* and clean up fid reference */
5363 smb_ReleaseFID(fidp);
5367 #ifdef DEBUG_VERBOSE
5369 char *hexp, *asciip;
5370 asciip = (lastNamep ? lastNamep : pathp );
5371 hexp = osi_HexifyString(asciip);
5372 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
5376 userp = smb_GetUserFromVCP(vcp, inp);
5379 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5381 cm_ReleaseUser(userp);
5382 return CM_ERROR_NOSUCHPATH;
5384 code = cm_NameI(cm_data.rootSCachep, pathp,
5385 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5386 userp, tidPathp, &req, &scp);
5389 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5390 cm_ReleaseSCache(scp);
5391 cm_ReleaseUser(userp);
5392 if ( WANTS_DFS_PATHNAMES(inp) )
5393 return CM_ERROR_PATH_NOT_COVERED;
5395 return CM_ERROR_BADSHARENAME;
5397 #endif /* DFS_SUPPORT */
5400 code = cm_NameI(cm_data.rootSCachep, spacep->data,
5401 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5402 userp, tidPathp, &req, &dscp);
5404 cm_ReleaseUser(userp);
5409 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5410 cm_ReleaseSCache(dscp);
5411 cm_ReleaseUser(userp);
5412 if ( WANTS_DFS_PATHNAMES(inp) )
5413 return CM_ERROR_PATH_NOT_COVERED;
5415 return CM_ERROR_BADSHARENAME;
5417 #endif /* DFS_SUPPORT */
5418 /* otherwise, scp points to the parent directory. Do a lookup,
5419 * and truncate the file if we find it, otherwise we create the
5426 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
5428 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5429 cm_ReleaseSCache(dscp);
5430 cm_ReleaseUser(userp);
5435 /* if we get here, if code is 0, the file exists and is represented by
5436 * scp. Otherwise, we have to create it. The dir may be represented
5437 * by dscp, or we may have found the file directly. If code is non-zero,
5441 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
5443 if (dscp) cm_ReleaseSCache(dscp);
5444 cm_ReleaseSCache(scp);
5445 cm_ReleaseUser(userp);
5450 /* oops, file shouldn't be there */
5452 cm_ReleaseSCache(dscp);
5453 cm_ReleaseSCache(scp);
5454 cm_ReleaseUser(userp);
5455 return CM_ERROR_EXISTS;
5459 setAttr.mask = CM_ATTRMASK_LENGTH;
5460 setAttr.length.LowPart = 0;
5461 setAttr.length.HighPart = 0;
5462 code = cm_SetAttr(scp, &setAttr, userp, &req);
5463 openAction = 3; /* truncated existing file */
5465 else openAction = 1; /* found existing file */
5467 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
5468 /* don't create if not found */
5469 if (dscp) cm_ReleaseSCache(dscp);
5470 cm_ReleaseUser(userp);
5471 return CM_ERROR_NOSUCHFILE;
5474 osi_assertx(dscp != NULL, "null cm_scache_t");
5475 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
5476 osi_LogSaveString(smb_logp, lastNamep));
5477 openAction = 2; /* created file */
5478 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5479 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5480 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5484 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5485 smb_NotifyChange(FILE_ACTION_ADDED,
5486 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5487 dscp, lastNamep, NULL, TRUE);
5488 } else if (!excl && code == CM_ERROR_EXISTS) {
5489 /* not an exclusive create, and someone else tried
5490 * creating it already, then we open it anyway. We
5491 * don't bother retrying after this, since if this next
5492 * fails, that means that the file was deleted after we
5493 * started this call.
5495 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5499 setAttr.mask = CM_ATTRMASK_LENGTH;
5500 setAttr.length.LowPart = 0;
5501 setAttr.length.HighPart = 0;
5502 code = cm_SetAttr(scp, &setAttr, userp, &req);
5504 } /* lookup succeeded */
5508 /* we don't need this any longer */
5510 cm_ReleaseSCache(dscp);
5513 /* something went wrong creating or truncating the file */
5515 cm_ReleaseSCache(scp);
5516 cm_ReleaseUser(userp);
5520 /* make sure we're about to open a file */
5521 if (scp->fileType != CM_SCACHETYPE_FILE) {
5522 cm_ReleaseSCache(scp);
5523 cm_ReleaseUser(userp);
5524 return CM_ERROR_ISDIR;
5527 /* now all we have to do is open the file itself */
5528 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5529 osi_assertx(fidp, "null smb_fid_t");
5532 lock_ObtainMutex(&fidp->mx);
5533 /* save a pointer to the vnode */
5535 lock_ObtainMutex(&scp->mx);
5536 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5537 lock_ReleaseMutex(&scp->mx);
5538 osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
5540 fidp->userp = userp;
5542 /* compute open mode */
5544 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5545 if (openMode == 1 || openMode == 2)
5546 fidp->flags |= SMB_FID_OPENWRITE;
5548 /* remember if the file was newly created */
5550 fidp->flags |= SMB_FID_CREATED;
5552 lock_ReleaseMutex(&fidp->mx);
5553 smb_ReleaseFID(fidp);
5555 cm_Open(scp, 0, userp);
5557 /* set inp->fid so that later read calls in same msg can find fid */
5558 inp->fid = fidp->fid;
5560 /* copy out remainder of the parms */
5562 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5563 lock_ObtainMutex(&scp->mx);
5565 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5566 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5567 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5568 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5569 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5570 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5571 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5572 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5573 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5575 /* and the final "always present" stuff */
5576 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5577 /* next write out the "unique" ID */
5578 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5579 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5580 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5581 lock_ReleaseMutex(&scp->mx);
5582 smb_SetSMBDataLength(outp, 0);
5584 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5586 cm_ReleaseUser(userp);
5587 /* leave scp held since we put it in fidp->scp */
5591 static void smb_GetLockParams(unsigned char LockType,
5593 unsigned int * ppid,
5594 LARGE_INTEGER * pOffset,
5595 LARGE_INTEGER * pLength)
5597 if (LockType & LOCKING_ANDX_LARGE_FILES) {
5599 *ppid = *((USHORT *) *buf);
5600 pOffset->HighPart = *((LONG *)(*buf + 4));
5601 pOffset->LowPart = *((DWORD *)(*buf + 8));
5602 pLength->HighPart = *((LONG *)(*buf + 12));
5603 pLength->LowPart = *((DWORD *)(*buf + 16));
5607 /* Not Large Files */
5608 *ppid = *((USHORT *) *buf);
5609 pOffset->HighPart = 0;
5610 pOffset->LowPart = *((DWORD *)(*buf + 2));
5611 pLength->HighPart = 0;
5612 pLength->LowPart = *((DWORD *)(*buf + 6));
5617 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5624 unsigned char LockType;
5625 unsigned short NumberOfUnlocks, NumberOfLocks;
5629 LARGE_INTEGER LOffset, LLength;
5630 smb_waitingLockRequest_t *wlRequest = NULL;
5631 cm_file_lock_t *lockp;
5639 fid = smb_GetSMBParm(inp, 2);
5640 fid = smb_ChainFID(fid, inp);
5642 fidp = smb_FindFID(vcp, fid, 0);
5644 return CM_ERROR_BADFD;
5646 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
5647 smb_CloseFID(vcp, fidp, NULL, 0);
5648 smb_ReleaseFID(fidp);
5649 return CM_ERROR_NOSUCHFILE;
5652 lock_ObtainMutex(&fidp->mx);
5653 if (fidp->flags & SMB_FID_IOCTL) {
5654 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
5655 lock_ReleaseMutex(&fidp->mx);
5656 smb_ReleaseFID(fidp);
5657 return CM_ERROR_BADFD;
5660 osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
5662 lock_ReleaseMutex(&fidp->mx);
5664 /* set inp->fid so that later read calls in same msg can find fid */
5667 userp = smb_GetUserFromVCP(vcp, inp);
5670 lock_ObtainMutex(&scp->mx);
5671 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5672 CM_SCACHESYNC_NEEDCALLBACK
5673 | CM_SCACHESYNC_GETSTATUS
5674 | CM_SCACHESYNC_LOCK);
5676 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
5680 LockType = smb_GetSMBParm(inp, 3) & 0xff;
5681 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
5682 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
5683 NumberOfLocks = smb_GetSMBParm(inp, 7);
5685 if (!(fidp->flags & SMB_FID_OPENWRITE) &&
5686 !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
5687 /* somebody wants exclusive locks on a file that they only
5688 opened for reading. We downgrade this to a shared lock. */
5689 osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
5690 LockType |= LOCKING_ANDX_SHARED_LOCK;
5693 if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
5694 (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
5696 /* We don't support these requests. Apparently, we can safely
5697 not deal with them too. */
5698 osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
5699 ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
5700 "LOCKING_ANDX_CANCEL_LOCK":
5701 "LOCKING_ANDX_CHANGE_LOCKTYPE"));
5702 /* No need to call osi_LogSaveString since these are string
5705 code = CM_ERROR_BADOP;
5710 op = smb_GetSMBData(inp, NULL);
5712 for (i=0; i<NumberOfUnlocks; i++) {
5713 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5715 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5717 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
5725 for (i=0; i<NumberOfLocks; i++) {
5726 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5728 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5730 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
5731 userp, &req, &lockp);
5733 if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
5734 (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
5736 code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
5737 userp, &req, &lockp);
5740 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
5741 smb_waitingLock_t * wLock;
5743 /* Put on waiting list */
5744 if(wlRequest == NULL) {
5748 LARGE_INTEGER tOffset, tLength;
5750 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
5752 osi_assertx(wlRequest != NULL, "null wlRequest");
5754 wlRequest->vcp = vcp;
5756 wlRequest->scp = scp;
5757 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
5759 wlRequest->inp = smb_CopyPacket(inp);
5760 wlRequest->outp = smb_CopyPacket(outp);
5761 wlRequest->lockType = LockType;
5762 wlRequest->timeRemaining = Timeout;
5763 wlRequest->locks = NULL;
5765 /* The waiting lock request needs to have enough
5766 information to undo all the locks in the request.
5767 We do the following to store info about locks that
5768 have already been granted. Sure, we can get most
5769 of the info from the packet, but the packet doesn't
5770 hold the result of cm_Lock call. In practice we
5771 only receive packets with one or two locks, so we
5772 are only wasting a few bytes here and there and
5773 only for a limited period of time until the waiting
5774 lock times out or is freed. */
5776 for(opt = op_locks, j=i; j > 0; j--) {
5777 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
5779 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5781 wLock = malloc(sizeof(smb_waitingLock_t));
5783 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
5786 wLock->LOffset = tOffset;
5787 wLock->LLength = tLength;
5788 wLock->lockp = NULL;
5789 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
5790 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5795 wLock = malloc(sizeof(smb_waitingLock_t));
5797 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
5800 wLock->LOffset = LOffset;
5801 wLock->LLength = LLength;
5802 wLock->lockp = lockp;
5803 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
5804 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5807 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
5815 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
5822 /* Since something went wrong with the lock number i, we now
5823 have to go ahead and release any locks acquired before the
5824 failure. All locks before lock number i (of which there
5825 are i of them) have either been successful or are waiting.
5826 Either case requires calling cm_Unlock(). */
5828 /* And purge the waiting lock */
5829 if(wlRequest != NULL) {
5830 smb_waitingLock_t * wl;
5831 smb_waitingLock_t * wlNext;
5834 for(wl = wlRequest->locks; wl; wl = wlNext) {
5836 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
5838 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
5841 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
5843 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
5846 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
5851 smb_ReleaseVC(wlRequest->vcp);
5852 cm_ReleaseSCache(wlRequest->scp);
5853 smb_FreePacket(wlRequest->inp);
5854 smb_FreePacket(wlRequest->outp);
5863 if (wlRequest != NULL) {
5865 lock_ObtainWrite(&smb_globalLock);
5866 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
5868 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
5869 lock_ReleaseWrite(&smb_globalLock);
5871 /* don't send reply immediately */
5872 outp->flags |= SMB_PACKETFLAG_NOSEND;
5875 smb_SetSMBDataLength(outp, 0);
5879 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5882 lock_ReleaseMutex(&scp->mx);
5883 cm_ReleaseSCache(scp);
5884 cm_ReleaseUser(userp);
5885 smb_ReleaseFID(fidp);
5890 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5896 afs_uint32 searchTime;
5902 fid = smb_GetSMBParm(inp, 0);
5903 fid = smb_ChainFID(fid, inp);
5905 fidp = smb_FindFID(vcp, fid, 0);
5907 return CM_ERROR_BADFD;
5909 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
5910 smb_CloseFID(vcp, fidp, NULL, 0);
5911 smb_ReleaseFID(fidp);
5912 return CM_ERROR_NOSUCHFILE;
5915 lock_ObtainMutex(&fidp->mx);
5916 if (fidp->flags & SMB_FID_IOCTL) {
5917 lock_ReleaseMutex(&fidp->mx);
5918 smb_ReleaseFID(fidp);
5919 return CM_ERROR_BADFD;
5922 osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
5924 lock_ReleaseMutex(&fidp->mx);
5926 userp = smb_GetUserFromVCP(vcp, inp);
5929 /* otherwise, stat the file */
5930 lock_ObtainMutex(&scp->mx);
5931 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5932 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5936 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5938 /* decode times. We need a search time, but the response to this
5939 * call provides the date first, not the time, as returned in the
5940 * searchTime variable. So we take the high-order bits first.
5942 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
5943 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
5944 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
5945 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
5946 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
5947 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
5948 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
5950 /* now handle file size and allocation size */
5951 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
5952 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
5953 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
5954 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
5956 /* file attribute */
5957 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
5959 /* and finalize stuff */
5960 smb_SetSMBDataLength(outp, 0);
5964 lock_ReleaseMutex(&scp->mx);
5965 cm_ReleaseSCache(scp);
5966 cm_ReleaseUser(userp);
5967 smb_ReleaseFID(fidp);
5971 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5977 afs_uint32 searchTime;
5985 fid = smb_GetSMBParm(inp, 0);
5986 fid = smb_ChainFID(fid, inp);
5988 fidp = smb_FindFID(vcp, fid, 0);
5990 return CM_ERROR_BADFD;
5992 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
5993 smb_CloseFID(vcp, fidp, NULL, 0);
5994 smb_ReleaseFID(fidp);
5995 return CM_ERROR_NOSUCHFILE;
5998 lock_ObtainMutex(&fidp->mx);
5999 if (fidp->flags & SMB_FID_IOCTL) {
6000 lock_ReleaseMutex(&fidp->mx);
6001 smb_ReleaseFID(fidp);
6002 return CM_ERROR_BADFD;
6005 osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6007 lock_ReleaseMutex(&fidp->mx);
6009 userp = smb_GetUserFromVCP(vcp, inp);
6012 /* now prepare to call cm_setattr. This message only sets various times,
6013 * and AFS only implements mtime, and we'll set the mtime if that's
6014 * requested. The others we'll ignore.
6016 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
6018 if (searchTime != 0) {
6019 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
6021 if ( unixTime != -1 ) {
6022 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
6023 attrs.clientModTime = unixTime;
6024 code = cm_SetAttr(scp, &attrs, userp, &req);
6026 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
6028 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
6034 cm_ReleaseSCache(scp);
6035 cm_ReleaseUser(userp);
6036 smb_ReleaseFID(fidp);
6040 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6043 long count, written = 0, total_written = 0;
6050 int inDataBlockCount;
6052 fd = smb_GetSMBParm(inp, 2);
6053 count = smb_GetSMBParm(inp, 10);
6055 offset.HighPart = 0;
6056 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6058 if (*inp->wctp == 14) {
6059 /* we have a request with 64-bit file offsets */
6060 #ifdef AFS_LARGEFILES
6061 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6063 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6065 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
6066 /* we shouldn't have received this op if we didn't specify
6067 largefile support */
6068 return CM_ERROR_BADOP;
6073 op = inp->data + smb_GetSMBParm(inp, 11);
6074 inDataBlockCount = count;
6076 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
6077 fd, offset.HighPart, offset.LowPart, count);
6079 fd = smb_ChainFID(fd, inp);
6080 fidp = smb_FindFID(vcp, fd, 0);
6082 return CM_ERROR_BADFD;
6084 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6085 smb_CloseFID(vcp, fidp, NULL, 0);
6086 smb_ReleaseFID(fidp);
6087 return CM_ERROR_NOSUCHFILE;
6090 lock_ObtainMutex(&fidp->mx);
6091 if (fidp->flags & SMB_FID_IOCTL) {
6092 lock_ReleaseMutex(&fidp->mx);
6093 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
6094 smb_ReleaseFID(fidp);
6097 lock_ReleaseMutex(&fidp->mx);
6098 userp = smb_GetUserFromVCP(vcp, inp);
6100 /* special case: 0 bytes transferred means there is no data
6101 transferred. A slight departure from SMB_COM_WRITE where this
6102 means that we are supposed to truncate the file at this
6107 LARGE_INTEGER LOffset;
6108 LARGE_INTEGER LLength;
6111 pid = ((smb_t *) inp)->pid;
6112 key = cm_GenerateKey(vcp->vcID, pid, fd);
6114 LOffset.HighPart = offset.HighPart;
6115 LOffset.LowPart = offset.LowPart;
6116 LLength.HighPart = 0;
6117 LLength.LowPart = count;
6120 lock_ObtainMutex(&scp->mx);
6121 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
6122 lock_ReleaseMutex(&scp->mx);
6129 * Work around bug in NT client
6131 * When copying a file, the NT client should first copy the data,
6132 * then copy the last write time. But sometimes the NT client does
6133 * these in the wrong order, so the data copies would inadvertently
6134 * cause the last write time to be overwritten. We try to detect this,
6135 * and don't set client mod time if we think that would go against the
6138 lock_ObtainMutex(&fidp->mx);
6139 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6140 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6141 fidp->scp->clientModTime = time(NULL);
6143 lock_ReleaseMutex(&fidp->mx);
6146 while ( code == 0 && count > 0 ) {
6147 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6148 if (code == 0 && written == 0)
6149 code = CM_ERROR_PARTIALWRITE;
6151 offset = LargeIntegerAdd(offset,
6152 ConvertLongToLargeInteger(written));
6154 total_written += written;
6160 /* slots 0 and 1 are reserved for request chaining and will be
6161 filled in when we return. */
6162 smb_SetSMBParm(outp, 2, total_written);
6163 smb_SetSMBParm(outp, 3, 0); /* reserved */
6164 smb_SetSMBParm(outp, 4, 0); /* reserved */
6165 smb_SetSMBParm(outp, 5, 0); /* reserved */
6166 smb_SetSMBDataLength(outp, 0);
6169 cm_ReleaseUser(userp);
6170 smb_ReleaseFID(fidp);
6175 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6179 long finalCount = 0;
6188 fd = smb_GetSMBParm(inp, 2);
6189 count = smb_GetSMBParm(inp, 5);
6190 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6192 if (*inp->wctp == 12) {
6193 /* a request with 64-bit offsets */
6194 #ifdef AFS_LARGEFILES
6195 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
6197 if (LargeIntegerLessThanZero(offset)) {
6198 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
6199 offset.HighPart, offset.LowPart);
6200 return CM_ERROR_BADSMB;
6203 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
6204 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
6205 return CM_ERROR_BADSMB;
6207 offset.HighPart = 0;
6211 offset.HighPart = 0;
6214 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
6215 fd, offset.HighPart, offset.LowPart, count);
6217 fd = smb_ChainFID(fd, inp);
6218 fidp = smb_FindFID(vcp, fd, 0);
6220 return CM_ERROR_BADFD;
6223 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6224 smb_CloseFID(vcp, fidp, NULL, 0);
6225 smb_ReleaseFID(fidp);
6226 return CM_ERROR_NOSUCHFILE;
6229 pid = ((smb_t *) inp)->pid;
6230 key = cm_GenerateKey(vcp->vcID, pid, fd);
6232 LARGE_INTEGER LOffset, LLength;
6235 LOffset.HighPart = offset.HighPart;
6236 LOffset.LowPart = offset.LowPart;
6237 LLength.HighPart = 0;
6238 LLength.LowPart = count;
6241 lock_ObtainMutex(&scp->mx);
6242 code = cm_LockCheckRead(scp, LOffset, LLength, key);
6243 lock_ReleaseMutex(&scp->mx);
6247 smb_ReleaseFID(fidp);
6251 /* set inp->fid so that later read calls in same msg can find fid */
6254 lock_ObtainMutex(&fidp->mx);
6255 if (fidp->flags & SMB_FID_IOCTL) {
6256 lock_ReleaseMutex(&fidp->mx);
6257 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
6258 smb_ReleaseFID(fidp);
6261 lock_ReleaseMutex(&fidp->mx);
6263 userp = smb_GetUserFromVCP(vcp, inp);
6265 /* 0 and 1 are reserved for request chaining, were setup by our caller,
6266 * and will be further filled in after we return.
6268 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
6269 smb_SetSMBParm(outp, 3, 0); /* resvd */
6270 smb_SetSMBParm(outp, 4, 0); /* resvd */
6271 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
6272 /* fill in #6 when we have all the parameters' space reserved */
6273 smb_SetSMBParm(outp, 7, 0); /* resv'd */
6274 smb_SetSMBParm(outp, 8, 0); /* resv'd */
6275 smb_SetSMBParm(outp, 9, 0); /* resv'd */
6276 smb_SetSMBParm(outp, 10, 0); /* resv'd */
6277 smb_SetSMBParm(outp, 11, 0); /* reserved */
6279 /* get op ptr after putting in the parms, since otherwise we don't
6280 * know where the data really is.
6282 op = smb_GetSMBData(outp, NULL);
6284 /* now fill in offset from start of SMB header to first data byte (to op) */
6285 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
6287 /* set the packet data length the count of the # of bytes */
6288 smb_SetSMBDataLength(outp, count);
6290 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6292 /* fix some things up */
6293 smb_SetSMBParm(outp, 5, finalCount);
6294 smb_SetSMBDataLength(outp, finalCount);
6296 cm_ReleaseUser(userp);
6297 smb_ReleaseFID(fidp);
6302 * Values for createDisp, copied from NTDDK.H
6304 #define FILE_SUPERSEDE 0 // (???)
6305 #define FILE_OPEN 1 // (open)
6306 #define FILE_CREATE 2 // (exclusive)
6307 #define FILE_OPEN_IF 3 // (non-exclusive)
6308 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
6309 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
6312 #define REQUEST_OPLOCK 2
6313 #define REQUEST_BATCH_OPLOCK 4
6314 #define OPEN_DIRECTORY 8
6315 #define EXTENDED_RESPONSE_REQUIRED 0x10
6317 /* CreateOptions field. */
6318 #define FILE_DIRECTORY_FILE 0x0001
6319 #define FILE_WRITE_THROUGH 0x0002
6320 #define FILE_SEQUENTIAL_ONLY 0x0004
6321 #define FILE_NON_DIRECTORY_FILE 0x0040
6322 #define FILE_NO_EA_KNOWLEDGE 0x0200
6323 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
6324 #define FILE_RANDOM_ACCESS 0x0800
6325 #define FILE_DELETE_ON_CLOSE 0x1000
6326 #define FILE_OPEN_BY_FILE_ID 0x2000
6328 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6330 char *pathp, *realPathp;
6334 cm_scache_t *dscp; /* parent dir */
6335 cm_scache_t *scp; /* file to create or open */
6336 cm_scache_t *targetScp; /* if scp is a symlink */
6340 unsigned short nameLength;
6342 unsigned int requestOpLock;
6343 unsigned int requestBatchOpLock;
6344 unsigned int mustBeDir;
6345 unsigned int extendedRespRequired;
6346 unsigned int treeCreate;
6348 unsigned int desiredAccess;
6349 unsigned int extAttributes;
6350 unsigned int createDisp;
6351 unsigned int createOptions;
6352 unsigned int shareAccess;
6353 int initialModeBits;
6354 unsigned short baseFid;
6355 smb_fid_t *baseFidp;
6357 cm_scache_t *baseDirp;
6358 unsigned short openAction;
6367 cm_lock_data_t *ldp = NULL;
6371 /* This code is very long and has a lot of if-then-else clauses
6372 * scp and dscp get reused frequently and we need to ensure that
6373 * we don't lose a reference. Start by ensuring that they are NULL.
6380 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
6381 flags = smb_GetSMBOffsetParm(inp, 3, 1)
6382 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
6383 requestOpLock = flags & REQUEST_OPLOCK;
6384 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6385 mustBeDir = flags & OPEN_DIRECTORY;
6386 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6389 * Why all of a sudden 32-bit FID?
6390 * We will reject all bits higher than 16.
6392 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
6393 return CM_ERROR_INVAL;
6394 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
6395 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
6396 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6397 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
6398 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
6399 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
6400 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
6401 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
6402 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
6403 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
6404 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
6406 /* mustBeDir is never set; createOptions directory bit seems to be
6409 if (createOptions & FILE_DIRECTORY_FILE)
6411 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6417 * compute initial mode bits based on read-only flag in
6418 * extended attributes
6420 initialModeBits = 0666;
6421 if (extAttributes & SMB_ATTR_READONLY)
6422 initialModeBits &= ~0222;
6424 pathp = smb_GetSMBData(inp, NULL);
6425 /* Sometimes path is not null-terminated, so we make a copy. */
6426 realPathp = malloc(nameLength+1);
6427 memcpy(realPathp, pathp, nameLength);
6428 realPathp[nameLength] = 0;
6429 if (smb_StoreAnsiFilenames)
6430 OemToChar(realPathp,realPathp);
6432 spacep = inp->spacep;
6433 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6435 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
6436 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
6437 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
6439 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
6440 /* special case magic file name for receiving IOCTL requests
6441 * (since IOCTL calls themselves aren't getting through).
6443 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6444 smb_SetupIoctlFid(fidp, spacep);
6445 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
6447 /* set inp->fid so that later read calls in same msg can find fid */
6448 inp->fid = fidp->fid;
6452 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6453 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6454 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
6456 memset(&ft, 0, sizeof(ft));
6457 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6458 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6459 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6460 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6461 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
6462 sz.HighPart = 0x7fff; sz.LowPart = 0;
6463 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
6464 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
6465 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6466 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6467 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
6468 smb_SetSMBDataLength(outp, 0);
6470 /* clean up fid reference */
6471 smb_ReleaseFID(fidp);
6476 #ifdef DEBUG_VERBOSE
6478 char *hexp, *asciip;
6479 asciip = (lastNamep? lastNamep : realPathp);
6480 hexp = osi_HexifyString( asciip );
6481 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
6486 userp = smb_GetUserFromVCP(vcp, inp);
6488 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
6490 return CM_ERROR_INVAL;
6495 baseDirp = cm_data.rootSCachep;
6496 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6497 if (code == CM_ERROR_TIDIPC) {
6498 /* Attempt to use a TID allocated for IPC. The client
6499 * is probably looking for DCE RPC end points which we
6500 * don't support OR it could be looking to make a DFS
6503 osi_Log0(smb_logp, "NTCreateX received IPC TID");
6506 cm_ReleaseUser(userp);
6507 return CM_ERROR_NOSUCHFILE;
6508 #endif /* DFS_SUPPORT */
6511 baseFidp = smb_FindFID(vcp, baseFid, 0);
6513 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
6515 cm_ReleaseUser(userp);
6516 return CM_ERROR_INVAL;
6519 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6521 cm_ReleaseUser(userp);
6522 smb_CloseFID(vcp, baseFidp, NULL, 0);
6523 smb_ReleaseFID(baseFidp);
6524 return CM_ERROR_NOSUCHPATH;
6527 baseDirp = baseFidp->scp;
6531 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
6533 /* compute open mode */
6535 if (desiredAccess & DELETE)
6536 fidflags |= SMB_FID_OPENDELETE;
6537 if (desiredAccess & AFS_ACCESS_READ)
6538 fidflags |= SMB_FID_OPENREAD_LISTDIR;
6539 if (desiredAccess & AFS_ACCESS_WRITE)
6540 fidflags |= SMB_FID_OPENWRITE;
6541 if (createOptions & FILE_DELETE_ON_CLOSE)
6542 fidflags |= SMB_FID_DELONCLOSE;
6543 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6544 fidflags |= SMB_FID_SEQUENTIAL;
6545 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6546 fidflags |= SMB_FID_RANDOM;
6547 if (smb_IsExecutableFileName(lastNamep))
6548 fidflags |= SMB_FID_EXECUTABLE;
6550 /* and the share mode */
6551 if (shareAccess & FILE_SHARE_READ)
6552 fidflags |= SMB_FID_SHARE_READ;
6553 if (shareAccess & FILE_SHARE_WRITE)
6554 fidflags |= SMB_FID_SHARE_WRITE;
6556 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
6559 /* For an exclusive create, we want to do a case sensitive match for the last component. */
6560 if ( createDisp == FILE_CREATE ||
6561 createDisp == FILE_OVERWRITE ||
6562 createDisp == FILE_OVERWRITE_IF) {
6563 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6564 userp, tidPathp, &req, &dscp);
6567 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6568 cm_ReleaseSCache(dscp);
6569 cm_ReleaseUser(userp);
6572 smb_ReleaseFID(baseFidp);
6573 if ( WANTS_DFS_PATHNAMES(inp) )
6574 return CM_ERROR_PATH_NOT_COVERED;
6576 return CM_ERROR_BADSHARENAME;
6578 #endif /* DFS_SUPPORT */
6579 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6581 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
6582 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6583 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6584 if (code == 0 && realDirFlag == 1) {
6585 cm_ReleaseSCache(scp);
6586 cm_ReleaseSCache(dscp);
6587 cm_ReleaseUser(userp);
6590 smb_ReleaseFID(baseFidp);
6591 return CM_ERROR_EXISTS;
6595 /* we have both scp and dscp */
6597 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6598 userp, tidPathp, &req, &scp);
6600 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6601 cm_ReleaseSCache(scp);
6602 cm_ReleaseUser(userp);
6605 smb_ReleaseFID(baseFidp);
6606 if ( WANTS_DFS_PATHNAMES(inp) )
6607 return CM_ERROR_PATH_NOT_COVERED;
6609 return CM_ERROR_BADSHARENAME;
6611 #endif /* DFS_SUPPORT */
6612 /* we might have scp but not dscp */
6618 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6619 /* look up parent directory */
6620 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
6621 * the immediate parent. We have to work our way up realPathp until we hit something that we
6625 /* we might or might not have scp */
6631 code = cm_NameI(baseDirp, spacep->data,
6632 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6633 userp, tidPathp, &req, &dscp);
6636 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6638 cm_ReleaseSCache(scp);
6639 cm_ReleaseSCache(dscp);
6640 cm_ReleaseUser(userp);
6643 smb_ReleaseFID(baseFidp);
6644 if ( WANTS_DFS_PATHNAMES(inp) )
6645 return CM_ERROR_PATH_NOT_COVERED;
6647 return CM_ERROR_BADSHARENAME;
6649 #endif /* DFS_SUPPORT */
6652 (tp = strrchr(spacep->data,'\\')) &&
6653 (createDisp == FILE_CREATE) &&
6654 (realDirFlag == 1)) {
6657 treeStartp = realPathp + (tp - spacep->data);
6659 if (*tp && !smb_IsLegalFilename(tp)) {
6660 cm_ReleaseUser(userp);
6662 smb_ReleaseFID(baseFidp);
6665 cm_ReleaseSCache(scp);
6666 return CM_ERROR_BADNTFILENAME;
6670 } while (dscp == NULL && code == 0);
6674 /* we might have scp and we might have dscp */
6677 smb_ReleaseFID(baseFidp);
6680 osi_Log0(smb_logp,"NTCreateX parent not found");
6682 cm_ReleaseSCache(scp);
6684 cm_ReleaseSCache(dscp);
6685 cm_ReleaseUser(userp);
6690 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
6691 /* A file exists where we want a directory. */
6693 cm_ReleaseSCache(scp);
6694 cm_ReleaseSCache(dscp);
6695 cm_ReleaseUser(userp);
6697 return CM_ERROR_EXISTS;
6701 lastNamep = realPathp;
6705 if (!smb_IsLegalFilename(lastNamep)) {
6707 cm_ReleaseSCache(scp);
6709 cm_ReleaseSCache(dscp);
6710 cm_ReleaseUser(userp);
6712 return CM_ERROR_BADNTFILENAME;
6715 if (!foundscp && !treeCreate) {
6716 if ( createDisp == FILE_CREATE ||
6717 createDisp == FILE_OVERWRITE ||
6718 createDisp == FILE_OVERWRITE_IF)
6720 code = cm_Lookup(dscp, lastNamep,
6721 CM_FLAG_FOLLOW, userp, &req, &scp);
6723 code = cm_Lookup(dscp, lastNamep,
6724 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6727 if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
6729 cm_ReleaseSCache(dscp);
6730 cm_ReleaseUser(userp);
6735 /* we have scp and dscp */
6737 /* we have scp but not dscp */
6739 smb_ReleaseFID(baseFidp);
6742 /* if we get here, if code is 0, the file exists and is represented by
6743 * scp. Otherwise, we have to create it. The dir may be represented
6744 * by dscp, or we may have found the file directly. If code is non-zero,
6747 if (code == 0 && !treeCreate) {
6748 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
6751 cm_ReleaseSCache(dscp);
6753 cm_ReleaseSCache(scp);
6754 cm_ReleaseUser(userp);
6759 if (createDisp == FILE_CREATE) {
6760 /* oops, file shouldn't be there */
6761 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6763 cm_ReleaseSCache(dscp);
6765 cm_ReleaseSCache(scp);
6766 cm_ReleaseUser(userp);
6768 return CM_ERROR_EXISTS;
6771 if ( createDisp == FILE_OVERWRITE ||
6772 createDisp == FILE_OVERWRITE_IF) {
6774 setAttr.mask = CM_ATTRMASK_LENGTH;
6775 setAttr.length.LowPart = 0;
6776 setAttr.length.HighPart = 0;
6777 /* now watch for a symlink */
6779 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6781 osi_assertx(dscp != NULL, "null cm_scache_t");
6782 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6784 /* we have a more accurate file to use (the
6785 * target of the symbolic link). Otherwise,
6786 * we'll just use the symlink anyway.
6788 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6790 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6791 cm_ReleaseSCache(scp);
6793 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
6796 cm_ReleaseSCache(dscp);
6798 cm_ReleaseSCache(scp);
6799 cm_ReleaseUser(userp);
6805 code = cm_SetAttr(scp, &setAttr, userp, &req);
6806 openAction = 3; /* truncated existing file */
6809 openAction = 1; /* found existing file */
6811 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6812 /* don't create if not found */
6814 cm_ReleaseSCache(dscp);
6816 cm_ReleaseSCache(scp);
6817 cm_ReleaseUser(userp);
6819 return CM_ERROR_NOSUCHFILE;
6820 } else if (realDirFlag == 0 || realDirFlag == -1) {
6821 osi_assertx(dscp != NULL, "null cm_scache_t");
6822 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
6823 osi_LogSaveString(smb_logp, lastNamep));
6824 openAction = 2; /* created file */
6825 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6826 setAttr.clientModTime = time(NULL);
6827 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
6830 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6831 smb_NotifyChange(FILE_ACTION_ADDED,
6832 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6833 dscp, lastNamep, NULL, TRUE);
6834 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6835 /* Not an exclusive create, and someone else tried
6836 * creating it already, then we open it anyway. We
6837 * don't bother retrying after this, since if this next
6838 * fails, that means that the file was deleted after we
6839 * started this call.
6841 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6844 if (createDisp == FILE_OVERWRITE_IF) {
6845 setAttr.mask = CM_ATTRMASK_LENGTH;
6846 setAttr.length.LowPart = 0;
6847 setAttr.length.HighPart = 0;
6849 /* now watch for a symlink */
6851 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6853 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6855 /* we have a more accurate file to use (the
6856 * target of the symbolic link). Otherwise,
6857 * we'll just use the symlink anyway.
6859 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6861 cm_ReleaseSCache(scp);
6865 code = cm_SetAttr(scp, &setAttr, userp, &req);
6867 } /* lookup succeeded */
6871 char *cp; /* This component */
6872 int clen = 0; /* length of component */
6873 cm_scache_t *tscp1, *tscp2;
6876 /* create directory */
6878 treeStartp = lastNamep;
6879 osi_assertx(dscp != NULL, "null cm_scache_t");
6880 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
6881 osi_LogSaveString(smb_logp, treeStartp));
6882 openAction = 2; /* created directory */
6884 /* if the request is to create the root directory
6885 * it will appear as a directory name of the nul-string
6886 * and a code of CM_ERROR_NOSUCHFILE
6888 if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
6889 code = CM_ERROR_EXISTS;
6891 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6892 setAttr.clientModTime = time(NULL);
6897 cm_HoldSCache(tscp1);
6901 tp = strchr(pp, '\\');
6904 clen = (int)strlen(cp);
6905 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
6907 clen = (int)(tp - pp);
6908 strncpy(cp,pp,clen);
6915 continue; /* the supplied path can't have consecutive slashes either , but */
6917 /* cp is the next component to be created. */
6918 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
6919 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
6920 smb_NotifyChange(FILE_ACTION_ADDED,
6921 FILE_NOTIFY_CHANGE_DIR_NAME,
6922 tscp1, cp, NULL, TRUE);
6924 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6925 /* Not an exclusive create, and someone else tried
6926 * creating it already, then we open it anyway. We
6927 * don't bother retrying after this, since if this next
6928 * fails, that means that the file was deleted after we
6929 * started this call.
6931 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
6932 userp, &req, &tscp2);
6937 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
6938 cm_ReleaseSCache(tscp1);
6939 tscp1 = tscp2; /* Newly created directory will be next parent */
6940 /* the hold is transfered to tscp1 from tscp2 */
6945 cm_ReleaseSCache(dscp);
6948 cm_ReleaseSCache(scp);
6951 * if we get here and code == 0, then scp is the last directory created, and dscp is the
6957 /* something went wrong creating or truncating the file */
6959 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6961 cm_ReleaseSCache(scp);
6963 cm_ReleaseSCache(dscp);
6964 cm_ReleaseUser(userp);
6969 /* make sure we have file vs. dir right (only applies for single component case) */
6970 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
6971 /* now watch for a symlink */
6973 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6974 cm_scache_t * targetScp = 0;
6975 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6977 /* we have a more accurate file to use (the
6978 * target of the symbolic link). Otherwise,
6979 * we'll just use the symlink anyway.
6981 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
6983 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6984 cm_ReleaseSCache(scp);
6989 if (scp->fileType != CM_SCACHETYPE_FILE) {
6991 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6993 cm_ReleaseSCache(dscp);
6994 cm_ReleaseSCache(scp);
6995 cm_ReleaseUser(userp);
6997 return CM_ERROR_ISDIR;
7001 /* (only applies to single component case) */
7002 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7004 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7005 cm_ReleaseSCache(scp);
7007 cm_ReleaseSCache(dscp);
7008 cm_ReleaseUser(userp);
7010 return CM_ERROR_NOTDIR;
7013 /* open the file itself */
7014 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7015 osi_assertx(fidp, "null smb_fid_t");
7017 /* save a reference to the user */
7019 fidp->userp = userp;
7021 /* If we are restricting sharing, we should do so with a suitable
7023 if (scp->fileType == CM_SCACHETYPE_FILE &&
7024 !(fidflags & SMB_FID_SHARE_WRITE)) {
7026 LARGE_INTEGER LOffset, LLength;
7029 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7030 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7031 LLength.HighPart = 0;
7032 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7034 /* If we are not opening the file for writing, then we don't
7035 try to get an exclusive lock. Noone else should be able to
7036 get an exclusive lock on the file anyway, although someone
7037 else can get a shared lock. */
7038 if ((fidflags & SMB_FID_SHARE_READ) ||
7039 !(fidflags & SMB_FID_OPENWRITE)) {
7040 sLockType = LOCKING_ANDX_SHARED_LOCK;
7045 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7047 lock_ObtainMutex(&scp->mx);
7048 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7049 lock_ReleaseMutex(&scp->mx);
7053 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7054 cm_ReleaseSCache(scp);
7056 cm_ReleaseSCache(dscp);
7057 cm_ReleaseUser(userp);
7058 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7059 smb_CloseFID(vcp, fidp, NULL, 0);
7060 smb_ReleaseFID(fidp);
7066 /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
7068 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7070 lock_ObtainMutex(&fidp->mx);
7071 /* save a pointer to the vnode */
7072 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
7073 lock_ObtainMutex(&scp->mx);
7074 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7075 lock_ReleaseMutex(&scp->mx);
7076 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
7078 fidp->flags = fidflags;
7080 /* remember if the file was newly created */
7082 fidp->flags |= SMB_FID_CREATED;
7084 /* save parent dir and pathname for delete or change notification */
7085 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7086 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
7087 fidp->flags |= SMB_FID_NTOPEN;
7088 fidp->NTopen_dscp = dscp;
7090 fidp->NTopen_pathp = strdup(lastNamep);
7092 fidp->NTopen_wholepathp = realPathp;
7093 lock_ReleaseMutex(&fidp->mx);
7095 /* we don't need this any longer */
7097 cm_ReleaseSCache(dscp);
7101 cm_Open(scp, 0, userp);
7103 /* set inp->fid so that later read calls in same msg can find fid */
7104 inp->fid = fidp->fid;
7108 lock_ObtainMutex(&scp->mx);
7109 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7110 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7111 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7112 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7113 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7114 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7115 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7116 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7117 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7119 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7120 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7121 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
7122 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
7123 smb_SetSMBParmByte(outp, parmSlot,
7124 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7125 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7126 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7127 smb_SetSMBDataLength(outp, 0);
7129 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
7130 LargeIntegerGreaterThanZero(fidp->scp->length) &&
7131 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
7132 cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
7133 fidp->scp->length.LowPart, fidp->scp->length.HighPart,
7136 lock_ReleaseMutex(&scp->mx);
7138 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
7139 osi_LogSaveString(smb_logp, realPathp));
7141 cm_ReleaseUser(userp);
7142 smb_ReleaseFID(fidp);
7144 /* Can't free realPathp if we get here since
7145 fidp->NTopen_wholepathp is pointing there */
7147 /* leave scp held since we put it in fidp->scp */
7152 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
7153 * Instead, ultimately, would like to use a subroutine for common code.
7155 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7157 char *pathp, *realPathp;
7161 cm_scache_t *dscp; /* parent dir */
7162 cm_scache_t *scp; /* file to create or open */
7163 cm_scache_t *targetScp; /* if scp is a symlink */
7166 unsigned long nameLength;
7168 unsigned int requestOpLock;
7169 unsigned int requestBatchOpLock;
7170 unsigned int mustBeDir;
7171 unsigned int extendedRespRequired;
7173 unsigned int desiredAccess;
7174 #ifdef DEBUG_VERBOSE
7175 unsigned int allocSize;
7177 unsigned int shareAccess;
7178 unsigned int extAttributes;
7179 unsigned int createDisp;
7180 #ifdef DEBUG_VERBOSE
7183 unsigned int createOptions;
7184 int initialModeBits;
7185 unsigned short baseFid;
7186 smb_fid_t *baseFidp;
7188 cm_scache_t *baseDirp;
7189 unsigned short openAction;
7195 int parmOffset, dataOffset;
7201 cm_lock_data_t *ldp = NULL;
7208 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7209 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7210 parmp = inp->data + parmOffset;
7211 lparmp = (ULONG *) parmp;
7214 requestOpLock = flags & REQUEST_OPLOCK;
7215 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7216 mustBeDir = flags & OPEN_DIRECTORY;
7217 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7220 * Why all of a sudden 32-bit FID?
7221 * We will reject all bits higher than 16.
7223 if (lparmp[1] & 0xFFFF0000)
7224 return CM_ERROR_INVAL;
7225 baseFid = (unsigned short)lparmp[1];
7226 desiredAccess = lparmp[2];
7227 #ifdef DEBUG_VERBOSE
7228 allocSize = lparmp[3];
7229 #endif /* DEBUG_VERSOSE */
7230 extAttributes = lparmp[5];
7231 shareAccess = lparmp[6];
7232 createDisp = lparmp[7];
7233 createOptions = lparmp[8];
7234 #ifdef DEBUG_VERBOSE
7237 nameLength = lparmp[11];
7239 #ifdef DEBUG_VERBOSE
7240 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
7241 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
7242 osi_Log1(smb_logp,"... flags[%x]",flags);
7245 /* mustBeDir is never set; createOptions directory bit seems to be
7248 if (createOptions & FILE_DIRECTORY_FILE)
7250 else if (createOptions & FILE_NON_DIRECTORY_FILE)
7256 * compute initial mode bits based on read-only flag in
7257 * extended attributes
7259 initialModeBits = 0666;
7260 if (extAttributes & SMB_ATTR_READONLY)
7261 initialModeBits &= ~0222;
7263 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
7264 /* Sometimes path is not null-terminated, so we make a copy. */
7265 realPathp = malloc(nameLength+1);
7266 memcpy(realPathp, pathp, nameLength);
7267 realPathp[nameLength] = 0;
7268 if (smb_StoreAnsiFilenames)
7269 OemToChar(realPathp,realPathp);
7271 spacep = cm_GetSpace();
7272 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
7275 * Nothing here to handle SMB_IOCTL_FILENAME.
7276 * Will add it if necessary.
7279 #ifdef DEBUG_VERBOSE
7281 char *hexp, *asciip;
7282 asciip = (lastNamep? lastNamep : realPathp);
7283 hexp = osi_HexifyString( asciip );
7284 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
7289 userp = smb_GetUserFromVCP(vcp, inp);
7291 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
7293 return CM_ERROR_INVAL;
7298 baseDirp = cm_data.rootSCachep;
7299 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7300 if (code == CM_ERROR_TIDIPC) {
7301 /* Attempt to use a TID allocated for IPC. The client
7302 * is probably looking for DCE RPC end points which we
7303 * don't support OR it could be looking to make a DFS
7306 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
7309 cm_ReleaseUser(userp);
7310 return CM_ERROR_NOSUCHPATH;
7314 baseFidp = smb_FindFID(vcp, baseFid, 0);
7316 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
7318 cm_ReleaseUser(userp);
7319 return CM_ERROR_BADFD;
7322 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7324 cm_ReleaseUser(userp);
7325 smb_CloseFID(vcp, baseFidp, NULL, 0);
7326 smb_ReleaseFID(baseFidp);
7327 return CM_ERROR_NOSUCHPATH;
7330 baseDirp = baseFidp->scp;
7334 /* compute open mode */
7336 if (desiredAccess & DELETE)
7337 fidflags |= SMB_FID_OPENDELETE;
7338 if (desiredAccess & AFS_ACCESS_READ)
7339 fidflags |= SMB_FID_OPENREAD_LISTDIR;
7340 if (desiredAccess & AFS_ACCESS_WRITE)
7341 fidflags |= SMB_FID_OPENWRITE;
7342 if (createOptions & FILE_DELETE_ON_CLOSE)
7343 fidflags |= SMB_FID_DELONCLOSE;
7344 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7345 fidflags |= SMB_FID_SEQUENTIAL;
7346 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7347 fidflags |= SMB_FID_RANDOM;
7348 if (smb_IsExecutableFileName(lastNamep))
7349 fidflags |= SMB_FID_EXECUTABLE;
7351 /* And the share mode */
7352 if (shareAccess & FILE_SHARE_READ)
7353 fidflags |= SMB_FID_SHARE_READ;
7354 if (shareAccess & FILE_SHARE_WRITE)
7355 fidflags |= SMB_FID_SHARE_WRITE;
7359 if ( createDisp == FILE_OPEN ||
7360 createDisp == FILE_OVERWRITE ||
7361 createDisp == FILE_OVERWRITE_IF) {
7362 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7363 userp, tidPathp, &req, &dscp);
7366 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7367 cm_ReleaseSCache(dscp);
7368 cm_ReleaseUser(userp);
7371 smb_ReleaseFID(baseFidp);
7372 if ( WANTS_DFS_PATHNAMES(inp) )
7373 return CM_ERROR_PATH_NOT_COVERED;
7375 return CM_ERROR_BADSHARENAME;
7377 #endif /* DFS_SUPPORT */
7378 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7380 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7381 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7382 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7383 if (code == 0 && realDirFlag == 1) {
7384 cm_ReleaseSCache(scp);
7385 cm_ReleaseSCache(dscp);
7386 cm_ReleaseUser(userp);
7389 smb_ReleaseFID(baseFidp);
7390 return CM_ERROR_EXISTS;
7396 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7397 userp, tidPathp, &req, &scp);
7399 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7400 cm_ReleaseSCache(scp);
7401 cm_ReleaseUser(userp);
7404 smb_ReleaseFID(baseFidp);
7405 if ( WANTS_DFS_PATHNAMES(inp) )
7406 return CM_ERROR_PATH_NOT_COVERED;
7408 return CM_ERROR_BADSHARENAME;
7410 #endif /* DFS_SUPPORT */
7416 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7417 /* look up parent directory */
7419 code = cm_NameI(baseDirp, spacep->data,
7420 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7421 userp, tidPathp, &req, &dscp);
7423 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7424 cm_ReleaseSCache(dscp);
7425 cm_ReleaseUser(userp);
7428 smb_ReleaseFID(baseFidp);
7429 if ( WANTS_DFS_PATHNAMES(inp) )
7430 return CM_ERROR_PATH_NOT_COVERED;
7432 return CM_ERROR_BADSHARENAME;
7434 #endif /* DFS_SUPPORT */
7438 cm_FreeSpace(spacep);
7441 smb_ReleaseFID(baseFidp);
7444 cm_ReleaseUser(userp);
7450 lastNamep = realPathp;
7454 if (!smb_IsLegalFilename(lastNamep))
7455 return CM_ERROR_BADNTFILENAME;
7458 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
7459 code = cm_Lookup(dscp, lastNamep,
7460 CM_FLAG_FOLLOW, userp, &req, &scp);
7462 code = cm_Lookup(dscp, lastNamep,
7463 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7466 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7467 cm_ReleaseSCache(dscp);
7468 cm_ReleaseUser(userp);
7475 smb_ReleaseFID(baseFidp);
7476 cm_FreeSpace(spacep);
7479 /* if we get here, if code is 0, the file exists and is represented by
7480 * scp. Otherwise, we have to create it. The dir may be represented
7481 * by dscp, or we may have found the file directly. If code is non-zero,
7485 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7488 cm_ReleaseSCache(dscp);
7489 cm_ReleaseSCache(scp);
7490 cm_ReleaseUser(userp);
7495 if (createDisp == FILE_CREATE) {
7496 /* oops, file shouldn't be there */
7497 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7499 cm_ReleaseSCache(dscp);
7500 cm_ReleaseSCache(scp);
7501 cm_ReleaseUser(userp);
7503 return CM_ERROR_EXISTS;
7506 if (createDisp == FILE_OVERWRITE ||
7507 createDisp == FILE_OVERWRITE_IF) {
7508 setAttr.mask = CM_ATTRMASK_LENGTH;
7509 setAttr.length.LowPart = 0;
7510 setAttr.length.HighPart = 0;
7512 /* now watch for a symlink */
7514 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7516 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7518 /* we have a more accurate file to use (the
7519 * target of the symbolic link). Otherwise,
7520 * we'll just use the symlink anyway.
7522 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7524 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7525 cm_ReleaseSCache(scp);
7527 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7530 cm_ReleaseSCache(dscp);
7532 cm_ReleaseSCache(scp);
7533 cm_ReleaseUser(userp);
7539 code = cm_SetAttr(scp, &setAttr, userp, &req);
7540 openAction = 3; /* truncated existing file */
7542 else openAction = 1; /* found existing file */
7544 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7545 /* don't create if not found */
7547 cm_ReleaseSCache(dscp);
7548 cm_ReleaseUser(userp);
7550 return CM_ERROR_NOSUCHFILE;
7552 else if (realDirFlag == 0 || realDirFlag == -1) {
7553 osi_assertx(dscp != NULL, "null cm_scache_t");
7554 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
7555 osi_LogSaveString(smb_logp, lastNamep));
7556 openAction = 2; /* created file */
7557 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7558 setAttr.clientModTime = time(NULL);
7559 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7563 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7564 smb_NotifyChange(FILE_ACTION_ADDED,
7565 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7566 dscp, lastNamep, NULL, TRUE);
7567 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7568 /* Not an exclusive create, and someone else tried
7569 * creating it already, then we open it anyway. We
7570 * don't bother retrying after this, since if this next
7571 * fails, that means that the file was deleted after we
7572 * started this call.
7574 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7577 if (createDisp == FILE_OVERWRITE_IF) {
7578 setAttr.mask = CM_ATTRMASK_LENGTH;
7579 setAttr.length.LowPart = 0;
7580 setAttr.length.HighPart = 0;
7582 /* now watch for a symlink */
7584 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7586 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7588 /* we have a more accurate file to use (the
7589 * target of the symbolic link). Otherwise,
7590 * we'll just use the symlink anyway.
7592 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7594 cm_ReleaseSCache(scp);
7598 code = cm_SetAttr(scp, &setAttr, userp, &req);
7600 } /* lookup succeeded */
7603 /* create directory */
7604 osi_assertx(dscp != NULL, "null cm_scache_t");
7606 "smb_ReceiveNTTranCreate creating directory %s",
7607 osi_LogSaveString(smb_logp, lastNamep));
7608 openAction = 2; /* created directory */
7609 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7610 setAttr.clientModTime = time(NULL);
7611 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
7612 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7613 smb_NotifyChange(FILE_ACTION_ADDED,
7614 FILE_NOTIFY_CHANGE_DIR_NAME,
7615 dscp, lastNamep, NULL, TRUE);
7617 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7618 /* Not an exclusive create, and someone else tried
7619 * creating it already, then we open it anyway. We
7620 * don't bother retrying after this, since if this next
7621 * fails, that means that the file was deleted after we
7622 * started this call.
7624 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7630 /* something went wrong creating or truncating the file */
7632 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7634 cm_ReleaseSCache(scp);
7635 cm_ReleaseUser(userp);
7640 /* make sure we have file vs. dir right */
7641 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7642 /* now watch for a symlink */
7644 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7646 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7648 /* we have a more accurate file to use (the
7649 * target of the symbolic link). Otherwise,
7650 * we'll just use the symlink anyway.
7652 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7655 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7656 cm_ReleaseSCache(scp);
7661 if (scp->fileType != CM_SCACHETYPE_FILE) {
7663 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7664 cm_ReleaseSCache(scp);
7665 cm_ReleaseUser(userp);
7667 return CM_ERROR_ISDIR;
7671 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7673 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7674 cm_ReleaseSCache(scp);
7675 cm_ReleaseUser(userp);
7677 return CM_ERROR_NOTDIR;
7680 /* open the file itself */
7681 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7682 osi_assertx(fidp, "null smb_fid_t");
7684 /* save a reference to the user */
7686 fidp->userp = userp;
7688 /* If we are restricting sharing, we should do so with a suitable
7690 if (scp->fileType == CM_SCACHETYPE_FILE &&
7691 !(fidflags & SMB_FID_SHARE_WRITE)) {
7693 LARGE_INTEGER LOffset, LLength;
7696 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7697 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7698 LLength.HighPart = 0;
7699 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7701 /* Similar to what we do in handling NTCreateX. We get a
7702 shared lock if we are only opening the file for reading. */
7703 if ((fidflags & SMB_FID_SHARE_READ) ||
7704 !(fidflags & SMB_FID_OPENWRITE)) {
7705 sLockType = LOCKING_ANDX_SHARED_LOCK;
7710 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7712 lock_ObtainMutex(&scp->mx);
7713 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7714 lock_ReleaseMutex(&scp->mx);
7718 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7719 cm_ReleaseSCache(scp);
7720 cm_ReleaseUser(userp);
7721 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7722 smb_CloseFID(vcp, fidp, NULL, 0);
7723 smb_ReleaseFID(fidp);
7725 return CM_ERROR_SHARING_VIOLATION;
7729 /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
7731 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7733 lock_ObtainMutex(&fidp->mx);
7734 /* save a pointer to the vnode */
7736 lock_ObtainMutex(&scp->mx);
7737 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7738 lock_ReleaseMutex(&scp->mx);
7739 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
7741 fidp->flags = fidflags;
7743 /* remember if the file was newly created */
7745 fidp->flags |= SMB_FID_CREATED;
7747 /* save parent dir and pathname for deletion or change notification */
7748 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7749 fidp->flags |= SMB_FID_NTOPEN;
7750 fidp->NTopen_dscp = dscp;
7751 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
7753 fidp->NTopen_pathp = strdup(lastNamep);
7755 fidp->NTopen_wholepathp = realPathp;
7756 lock_ReleaseMutex(&fidp->mx);
7758 /* we don't need this any longer */
7760 cm_ReleaseSCache(dscp);
7762 cm_Open(scp, 0, userp);
7764 /* set inp->fid so that later read calls in same msg can find fid */
7765 inp->fid = fidp->fid;
7767 /* check whether we are required to send an extended response */
7768 if (!extendedRespRequired) {
7770 parmOffset = 8*4 + 39;
7771 parmOffset += 1; /* pad to 4 */
7772 dataOffset = parmOffset + 70;
7776 /* Total Parameter Count */
7777 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7778 /* Total Data Count */
7779 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7780 /* Parameter Count */
7781 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7782 /* Parameter Offset */
7783 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7784 /* Parameter Displacement */
7785 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7787 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7789 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7790 /* Data Displacement */
7791 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7792 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7793 smb_SetSMBDataLength(outp, 70);
7795 lock_ObtainMutex(&scp->mx);
7796 outData = smb_GetSMBData(outp, NULL);
7797 outData++; /* round to get to parmOffset */
7798 *outData = 0; outData++; /* oplock */
7799 *outData = 0; outData++; /* reserved */
7800 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7801 *((ULONG *)outData) = openAction; outData += 4;
7802 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
7803 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7804 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
7805 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
7806 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
7807 *((FILETIME *)outData) = ft; outData += 8; /* change time */
7808 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7809 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7810 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7811 *((USHORT *)outData) = 0; outData += 2; /* filetype */
7812 *((USHORT *)outData) = 0; outData += 2; /* dev state */
7813 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7814 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7815 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7816 outData += 2; /* is a dir? */
7817 lock_ReleaseMutex(&scp->mx);
7820 parmOffset = 8*4 + 39;
7821 parmOffset += 1; /* pad to 4 */
7822 dataOffset = parmOffset + 104;
7826 /* Total Parameter Count */
7827 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7828 /* Total Data Count */
7829 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7830 /* Parameter Count */
7831 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7832 /* Parameter Offset */
7833 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7834 /* Parameter Displacement */
7835 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7837 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7839 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7840 /* Data Displacement */
7841 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7842 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7843 smb_SetSMBDataLength(outp, 105);
7845 lock_ObtainMutex(&scp->mx);
7846 outData = smb_GetSMBData(outp, NULL);
7847 outData++; /* round to get to parmOffset */
7848 *outData = 0; outData++; /* oplock */
7849 *outData = 1; outData++; /* response type */
7850 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7851 *((ULONG *)outData) = openAction; outData += 4;
7852 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
7853 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7854 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
7855 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
7856 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
7857 *((FILETIME *)outData) = ft; outData += 8; /* change time */
7858 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7859 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7860 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7861 *((USHORT *)outData) = 0; outData += 2; /* filetype */
7862 *((USHORT *)outData) = 0; outData += 2; /* dev state */
7863 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7864 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7865 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7866 outData += 1; /* is a dir? */
7867 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
7868 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
7869 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
7870 lock_ReleaseMutex(&scp->mx);
7873 lock_ObtainMutex(&scp->mx);
7874 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
7875 LargeIntegerGreaterThanZero(fidp->scp->length) &&
7876 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
7877 cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
7878 fidp->scp->length.LowPart, fidp->scp->length.HighPart,
7881 lock_ReleaseMutex(&scp->mx);
7883 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
7885 cm_ReleaseUser(userp);
7886 smb_ReleaseFID(fidp);
7888 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
7889 /* leave scp held since we put it in fidp->scp */
7893 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
7896 smb_packet_t *savedPacketp;
7898 USHORT fid, watchtree;
7902 filter = smb_GetSMBParm(inp, 19) |
7903 (smb_GetSMBParm(inp, 20) << 16);
7904 fid = smb_GetSMBParm(inp, 21);
7905 watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
7907 fidp = smb_FindFID(vcp, fid, 0);
7909 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
7910 return CM_ERROR_BADFD;
7913 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7914 smb_CloseFID(vcp, fidp, NULL, 0);
7915 smb_ReleaseFID(fidp);
7916 return CM_ERROR_NOSUCHFILE;
7919 /* Create a copy of the Directory Watch Packet to use when sending the
7920 * notification if in the future a matching change is detected.
7922 savedPacketp = smb_CopyPacket(inp);
7924 if (savedPacketp->vcp)
7925 smb_ReleaseVC(savedPacketp->vcp);
7926 savedPacketp->vcp = vcp;
7928 /* Add the watch to the list of events to send notifications for */
7929 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7930 savedPacketp->nextp = smb_Directory_Watches;
7931 smb_Directory_Watches = savedPacketp;
7932 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7935 osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%s\"",
7936 fidp, scp, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
7937 osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
7938 filter, fid, watchtree);
7939 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
7940 osi_Log0(smb_logp, " Notify Change File Name");
7941 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
7942 osi_Log0(smb_logp, " Notify Change Directory Name");
7943 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
7944 osi_Log0(smb_logp, " Notify Change Attributes");
7945 if (filter & FILE_NOTIFY_CHANGE_SIZE)
7946 osi_Log0(smb_logp, " Notify Change Size");
7947 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
7948 osi_Log0(smb_logp, " Notify Change Last Write");
7949 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
7950 osi_Log0(smb_logp, " Notify Change Last Access");
7951 if (filter & FILE_NOTIFY_CHANGE_CREATION)
7952 osi_Log0(smb_logp, " Notify Change Creation");
7953 if (filter & FILE_NOTIFY_CHANGE_EA)
7954 osi_Log0(smb_logp, " Notify Change Extended Attributes");
7955 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
7956 osi_Log0(smb_logp, " Notify Change Security");
7957 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
7958 osi_Log0(smb_logp, " Notify Change Stream Name");
7959 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
7960 osi_Log0(smb_logp, " Notify Change Stream Size");
7961 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
7962 osi_Log0(smb_logp, " Notify Change Stream Write");
7964 lock_ObtainMutex(&scp->mx);
7966 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
7968 scp->flags |= CM_SCACHEFLAG_WATCHED;
7969 lock_ReleaseMutex(&scp->mx);
7970 smb_ReleaseFID(fidp);
7972 outp->flags |= SMB_PACKETFLAG_NOSEND;
7976 unsigned char nullSecurityDesc[36] = {
7977 0x01, /* security descriptor revision */
7978 0x00, /* reserved, should be zero */
7979 0x00, 0x80, /* security descriptor control;
7980 * 0x8000 : self-relative format */
7981 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
7982 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
7983 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
7984 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
7985 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7986 /* "null SID" owner SID */
7987 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
7988 /* "null SID" group SID */
7991 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7993 int parmOffset, parmCount, dataOffset, dataCount;
8001 ULONG securityInformation;
8003 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8004 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8005 parmp = inp->data + parmOffset;
8006 sparmp = (USHORT *) parmp;
8007 lparmp = (ULONG *) parmp;
8010 securityInformation = lparmp[1];
8012 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
8013 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
8021 parmOffset = 8*4 + 39;
8022 parmOffset += 1; /* pad to 4 */
8024 dataOffset = parmOffset + parmCount;
8028 /* Total Parameter Count */
8029 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8030 /* Total Data Count */
8031 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8032 /* Parameter Count */
8033 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8034 /* Parameter Offset */
8035 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8036 /* Parameter Displacement */
8037 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8039 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8041 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8042 /* Data Displacement */
8043 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8044 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8045 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
8047 outData = smb_GetSMBData(outp, NULL);
8048 outData++; /* round to get to parmOffset */
8049 *((ULONG *)outData) = 36; outData += 4; /* length */
8051 if (maxData >= 36) {
8052 memcpy(outData, nullSecurityDesc, 36);
8056 return CM_ERROR_BUFFERTOOSMALL;
8059 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8061 unsigned short function;
8063 function = smb_GetSMBParm(inp, 18);
8065 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
8067 /* We can handle long names */
8068 if (vcp->flags & SMB_VCFLAG_USENT)
8069 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
8073 return smb_ReceiveNTTranCreate(vcp, inp, outp);
8075 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
8078 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
8081 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
8083 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
8086 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
8088 return CM_ERROR_INVAL;
8092 * smb_NotifyChange -- find relevant change notification messages and
8095 * If we don't know the file name (i.e. a callback break), filename is
8096 * NULL, and we return a zero-length list.
8098 * At present there is not a single call to smb_NotifyChange that
8099 * has the isDirectParent parameter set to FALSE.
8101 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
8102 cm_scache_t *dscp, char *filename, char *otherFilename,
8103 BOOL isDirectParent)
8105 smb_packet_t *watch, *lastWatch, *nextWatch;
8106 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
8107 char *outData, *oldOutData;
8111 BOOL twoEntries = FALSE;
8112 ULONG otherNameLen, oldParmCount = 0;
8116 /* Get ready for rename within directory */
8117 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
8119 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
8122 osi_Log4(smb_logp,"in smb_NotifyChange for file [%s] dscp [%p] notification 0x%x parent %d",
8123 osi_LogSaveString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
8125 osi_Log0(smb_logp," FILE_ACTION_NONE");
8126 if (action == FILE_ACTION_ADDED)
8127 osi_Log0(smb_logp," FILE_ACTION_ADDED");
8128 if (action == FILE_ACTION_REMOVED)
8129 osi_Log0(smb_logp," FILE_ACTION_REMOVED");
8130 if (action == FILE_ACTION_MODIFIED)
8131 osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
8132 if (action == FILE_ACTION_RENAMED_OLD_NAME)
8133 osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
8134 if (action == FILE_ACTION_RENAMED_NEW_NAME)
8135 osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
8137 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8138 watch = smb_Directory_Watches;
8140 filter = smb_GetSMBParm(watch, 19)
8141 | (smb_GetSMBParm(watch, 20) << 16);
8142 fid = smb_GetSMBParm(watch, 21);
8143 wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
8145 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
8146 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
8149 * Strange hack - bug in NT Client and NT Server that we must emulate?
8151 if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
8152 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
8154 fidp = smb_FindFID(watch->vcp, fid, 0);
8156 osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
8158 watch = watch->nextp;
8162 if (fidp->scp != dscp ||
8163 fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
8164 (filter & notifyFilter) == 0 ||
8165 (!isDirectParent && !wtree))
8167 osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
8168 smb_ReleaseFID(fidp);
8170 watch = watch->nextp;
8173 smb_ReleaseFID(fidp);
8176 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
8177 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
8178 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8179 osi_Log0(smb_logp, " Notify Change File Name");
8180 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8181 osi_Log0(smb_logp, " Notify Change Directory Name");
8182 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8183 osi_Log0(smb_logp, " Notify Change Attributes");
8184 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8185 osi_Log0(smb_logp, " Notify Change Size");
8186 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8187 osi_Log0(smb_logp, " Notify Change Last Write");
8188 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8189 osi_Log0(smb_logp, " Notify Change Last Access");
8190 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8191 osi_Log0(smb_logp, " Notify Change Creation");
8192 if (filter & FILE_NOTIFY_CHANGE_EA)
8193 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8194 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8195 osi_Log0(smb_logp, " Notify Change Security");
8196 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8197 osi_Log0(smb_logp, " Notify Change Stream Name");
8198 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8199 osi_Log0(smb_logp, " Notify Change Stream Size");
8200 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8201 osi_Log0(smb_logp, " Notify Change Stream Write");
8203 /* A watch can only be notified once. Remove it from the list */
8204 nextWatch = watch->nextp;
8205 if (watch == smb_Directory_Watches)
8206 smb_Directory_Watches = nextWatch;
8208 lastWatch->nextp = nextWatch;
8210 /* Turn off WATCHED flag in dscp */
8211 lock_ObtainMutex(&dscp->mx);
8213 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8215 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
8216 lock_ReleaseMutex(&dscp->mx);
8218 /* Convert to response packet */
8219 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
8220 #ifdef SEND_CANONICAL_PATHNAMES
8221 ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
8223 ((smb_t *) watch)->wct = 0;
8226 if (filename == NULL)
8229 nameLen = (ULONG)strlen(filename);
8230 parmCount = 3*4 + nameLen*2;
8231 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8233 otherNameLen = (ULONG)strlen(otherFilename);
8234 oldParmCount = parmCount;
8235 parmCount += 3*4 + otherNameLen*2;
8236 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8238 if (maxLen < parmCount)
8239 parmCount = 0; /* not enough room */
8241 parmOffset = 8*4 + 39;
8242 parmOffset += 1; /* pad to 4 */
8243 dataOffset = parmOffset + parmCount;
8247 /* Total Parameter Count */
8248 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8249 /* Total Data Count */
8250 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8251 /* Parameter Count */
8252 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8253 /* Parameter Offset */
8254 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
8255 /* Parameter Displacement */
8256 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8258 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8260 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
8261 /* Data Displacement */
8262 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8263 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
8264 smb_SetSMBDataLength(watch, parmCount + 1);
8266 if (parmCount != 0) {
8268 outData = smb_GetSMBData(watch, NULL);
8269 outData++; /* round to get to parmOffset */
8270 oldOutData = outData;
8271 *((DWORD *)outData) = oldParmCount; outData += 4;
8272 /* Next Entry Offset */
8273 *((DWORD *)outData) = action; outData += 4;
8275 *((DWORD *)outData) = nameLen*2; outData += 4;
8276 /* File Name Length */
8277 p = strdup(filename);
8278 if (smb_StoreAnsiFilenames)
8280 mbstowcs((WCHAR *)outData, p, nameLen);
8284 outData = oldOutData + oldParmCount;
8285 *((DWORD *)outData) = 0; outData += 4;
8286 /* Next Entry Offset */
8287 *((DWORD *)outData) = otherAction; outData += 4;
8289 *((DWORD *)outData) = otherNameLen*2;
8290 outData += 4; /* File Name Length */
8291 p = strdup(otherFilename);
8292 if (smb_StoreAnsiFilenames)
8294 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
8300 * If filename is null, we don't know the cause of the
8301 * change notification. We return zero data (see above),
8302 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
8303 * (= 0x010C). We set the error code here by hand, without
8304 * modifying wct and bcc.
8306 if (filename == NULL) {
8307 ((smb_t *) watch)->rcls = 0x0C;
8308 ((smb_t *) watch)->reh = 0x01;
8309 ((smb_t *) watch)->errLow = 0;
8310 ((smb_t *) watch)->errHigh = 0;
8311 /* Set NT Status codes flag */
8312 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8315 smb_SendPacket(watch->vcp, watch);
8316 smb_FreePacket(watch);
8319 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8322 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8324 unsigned char *replyWctp;
8325 smb_packet_t *watch, *lastWatch;
8326 USHORT fid, watchtree;
8330 osi_Log0(smb_logp, "SMB3 receive NT cancel");
8332 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8333 watch = smb_Directory_Watches;
8335 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
8336 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
8337 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
8338 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
8339 if (watch == smb_Directory_Watches)
8340 smb_Directory_Watches = watch->nextp;
8342 lastWatch->nextp = watch->nextp;
8343 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8345 /* Turn off WATCHED flag in scp */
8346 fid = smb_GetSMBParm(watch, 21);
8347 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
8349 if (vcp != watch->vcp)
8350 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
8353 fidp = smb_FindFID(vcp, fid, 0);
8355 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
8357 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
8360 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
8361 lock_ObtainMutex(&scp->mx);
8363 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8365 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
8366 lock_ReleaseMutex(&scp->mx);
8367 smb_ReleaseFID(fidp);
8369 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
8372 /* assume STATUS32; return 0xC0000120 (CANCELED) */
8373 replyWctp = watch->wctp;
8377 ((smb_t *)watch)->rcls = 0x20;
8378 ((smb_t *)watch)->reh = 0x1;
8379 ((smb_t *)watch)->errLow = 0;
8380 ((smb_t *)watch)->errHigh = 0xC0;
8381 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8382 smb_SendPacket(vcp, watch);
8383 smb_FreePacket(watch);
8387 watch = watch->nextp;
8389 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8395 * NT rename also does hard links.
8398 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
8399 #define RENAME_FLAG_HARD_LINK 0x103
8400 #define RENAME_FLAG_RENAME 0x104
8401 #define RENAME_FLAG_COPY 0x105
8403 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8405 char *oldPathp, *newPathp;
8411 attrs = smb_GetSMBParm(inp, 0);
8412 rename_type = smb_GetSMBParm(inp, 1);
8414 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
8415 osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
8416 return CM_ERROR_NOACCESS;
8419 tp = smb_GetSMBData(inp, NULL);
8420 oldPathp = smb_ParseASCIIBlock(tp, &tp);
8421 if (smb_StoreAnsiFilenames)
8422 OemToChar(oldPathp,oldPathp);
8423 newPathp = smb_ParseASCIIBlock(tp, &tp);
8424 if (smb_StoreAnsiFilenames)
8425 OemToChar(newPathp,newPathp);
8427 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
8428 osi_LogSaveString(smb_logp, oldPathp),
8429 osi_LogSaveString(smb_logp, newPathp),
8430 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
8432 if (rename_type == RENAME_FLAG_RENAME) {
8433 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
8434 } else { /* RENAME_FLAG_HARD_LINK */
8435 code = smb_Link(vcp,inp,oldPathp,newPathp);
8442 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
8445 cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
8447 smb_username_t *unp;
8450 unp = smb_FindUserByName(usern, machine, flags);
8452 lock_ObtainMutex(&unp->mx);
8453 unp->userp = cm_NewUser();
8454 lock_ReleaseMutex(&unp->mx);
8455 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
8457 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
8461 smb_ReleaseUsername(unp);