2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
15 #pragma warning(disable: 4005)
17 #define SECURITY_WIN32
29 #include <WINNT\afsreg.h>
33 extern osi_hyper_t hzero;
35 smb_packet_t *smb_Directory_Watches = NULL;
36 osi_mutex_t smb_Dir_Watch_Lock;
38 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
40 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
42 /* protected by the smb_globalLock */
43 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
45 const char **smb_ExecutableExtensions = NULL;
47 /* retrieve a held reference to a user structure corresponding to an incoming
49 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
54 uidp = smb_FindUID(vcp, inp->uid, 0);
58 up = smb_GetUserFromUID(uidp);
66 * Return boolean specifying if the path name is thought to be an
67 * executable file. For now .exe or .dll.
69 afs_uint32 smb_IsExecutableFileName(const char *name)
73 if ( smb_ExecutableExtensions == NULL || name == NULL)
76 len = (int)strlen(name);
78 for ( i=0; smb_ExecutableExtensions[i]; i++) {
79 j = len - (int)strlen(smb_ExecutableExtensions[i]);
80 if (_stricmp(smb_ExecutableExtensions[i], &name[j]) == 0)
88 * Return extended attributes.
89 * Right now, we aren't using any of the "new" bits, so this looks exactly
90 * like smb_Attributes() (see smb.c).
92 unsigned long smb_ExtAttributes(cm_scache_t *scp)
96 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
97 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
98 scp->fileType == CM_SCACHETYPE_INVALID)
100 attrs = SMB_ATTR_DIRECTORY;
101 #ifdef SPECIAL_FOLDERS
102 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
103 #endif /* SPECIAL_FOLDERS */
104 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
105 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
109 * We used to mark a file RO if it was in an RO volume, but that
110 * turns out to be impolitic in NT. See defect 10007.
113 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
114 attrs |= SMB_ATTR_READONLY; /* Read-only */
116 if ((scp->unixModeBits & 0222) == 0)
117 attrs |= SMB_ATTR_READONLY; /* Read-only */
121 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
126 int smb_V3IsStarMask(char *maskp)
130 while (tc = *maskp++)
131 if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
136 void OutputDebugF(char * format, ...) {
141 va_start( args, format );
142 len = _vscprintf( format, args ) // _vscprintf doesn't count
143 + 3; // terminating '\0' + '\n'
144 buffer = malloc( len * sizeof(char) );
145 vsprintf( buffer, format, args );
146 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buffer));
147 strcat(buffer, "\n");
148 OutputDebugString(buffer);
152 void OutputDebugHexDump(unsigned char * buffer, int len) {
155 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
157 OutputDebugF("Hexdump length [%d]",len);
159 for (i=0;i<len;i++) {
162 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
164 OutputDebugString(buf);
166 sprintf(buf,"%5x",i);
167 memset(buf+5,' ',80);
172 j = j*3 + 7 + ((j>7)?1:0);
175 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
178 j = j + 56 + ((j>7)?1:0);
180 buf[j] = (k>32 && k<127)?k:'.';
183 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
185 OutputDebugString(buf);
189 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
191 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
192 SECURITY_STATUS status, istatus;
193 CredHandle creds = {0,0};
195 SecBufferDesc secOut;
203 OutputDebugF("Negotiating Extended Security");
205 status = AcquireCredentialsHandle( NULL,
206 SMB_EXT_SEC_PACKAGE_NAME,
215 if (status != SEC_E_OK) {
216 /* Really bad. We return an empty security blob */
217 OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
222 secOut.pBuffers = &secTok;
223 secOut.ulVersion = SECBUFFER_VERSION;
225 secTok.BufferType = SECBUFFER_TOKEN;
227 secTok.pvBuffer = NULL;
229 ctx.dwLower = ctx.dwUpper = 0;
231 status = AcceptSecurityContext( &creds,
234 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
235 SECURITY_NETWORK_DREP,
242 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
243 OutputDebugF("Completing token...");
244 istatus = CompleteAuthToken(&ctx, &secOut);
245 if ( istatus != SEC_E_OK )
246 OutputDebugF("Token completion failed: %x", istatus);
249 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
250 if (secTok.pvBuffer) {
251 *secBlobLength = secTok.cbBuffer;
252 *secBlob = malloc( secTok.cbBuffer );
253 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
256 if ( status != SEC_E_OK )
257 OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
260 /* Discard partial security context */
261 DeleteSecurityContext(&ctx);
263 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
265 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
266 FreeCredentialsHandle(&creds);
272 struct smb_ext_context {
279 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
280 SECURITY_STATUS status, istatus;
284 SecBufferDesc secBufIn;
286 SecBufferDesc secBufOut;
289 struct smb_ext_context * secCtx = NULL;
290 struct smb_ext_context * newSecCtx = NULL;
291 void * assembledBlob = NULL;
292 int assembledBlobLength = 0;
295 OutputDebugF("In smb_AuthenticateUserExt");
298 *secBlobOutLength = 0;
300 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
301 secCtx = vcp->secCtx;
302 lock_ObtainMutex(&vcp->mx);
303 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
305 lock_ReleaseMutex(&vcp->mx);
309 OutputDebugF("Received incoming token:");
310 OutputDebugHexDump(secBlobIn,secBlobInLength);
314 OutputDebugF("Continuing with existing context.");
315 creds = secCtx->creds;
318 if (secCtx->partialToken) {
319 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
320 assembledBlob = malloc(assembledBlobLength);
321 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
322 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
325 status = AcquireCredentialsHandle( NULL,
326 SMB_EXT_SEC_PACKAGE_NAME,
335 if (status != SEC_E_OK) {
336 OutputDebugF("Can't acquire Credentials handle [%lX]", status);
337 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
345 secBufIn.cBuffers = 1;
346 secBufIn.pBuffers = &secTokIn;
347 secBufIn.ulVersion = SECBUFFER_VERSION;
349 secTokIn.BufferType = SECBUFFER_TOKEN;
351 secTokIn.cbBuffer = assembledBlobLength;
352 secTokIn.pvBuffer = assembledBlob;
354 secTokIn.cbBuffer = secBlobInLength;
355 secTokIn.pvBuffer = secBlobIn;
358 secBufOut.cBuffers = 1;
359 secBufOut.pBuffers = &secTokOut;
360 secBufOut.ulVersion = SECBUFFER_VERSION;
362 secTokOut.BufferType = SECBUFFER_TOKEN;
363 secTokOut.cbBuffer = 0;
364 secTokOut.pvBuffer = NULL;
366 status = AcceptSecurityContext( &creds,
367 ((secCtx)?&ctx:NULL),
369 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
370 SECURITY_NETWORK_DREP,
377 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
378 OutputDebugF("Completing token...");
379 istatus = CompleteAuthToken(&ctx, &secBufOut);
380 if ( istatus != SEC_E_OK )
381 OutputDebugF("Token completion failed: %lX", istatus);
384 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
385 OutputDebugF("Continue needed");
387 newSecCtx = malloc(sizeof(*newSecCtx));
389 newSecCtx->creds = creds;
390 newSecCtx->ctx = ctx;
391 newSecCtx->partialToken = NULL;
392 newSecCtx->partialTokenLen = 0;
394 lock_ObtainMutex( &vcp->mx );
395 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
396 vcp->secCtx = newSecCtx;
397 lock_ReleaseMutex( &vcp->mx );
399 code = CM_ERROR_GSSCONTINUE;
402 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
403 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
404 secTokOut.pvBuffer) {
405 OutputDebugF("Need to send token back to client");
407 *secBlobOutLength = secTokOut.cbBuffer;
408 *secBlobOut = malloc(secTokOut.cbBuffer);
409 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
411 OutputDebugF("Outgoing token:");
412 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
413 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
414 OutputDebugF("Incomplete message");
416 newSecCtx = malloc(sizeof(*newSecCtx));
418 newSecCtx->creds = creds;
419 newSecCtx->ctx = ctx;
420 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
421 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
422 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
424 lock_ObtainMutex( &vcp->mx );
425 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
426 vcp->secCtx = newSecCtx;
427 lock_ReleaseMutex( &vcp->mx );
429 code = CM_ERROR_GSSCONTINUE;
432 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
434 SecPkgContext_Names names;
436 OutputDebugF("Authentication completed");
437 OutputDebugF("Returned flags : [%lX]", flags);
439 if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
440 OutputDebugF("Received name [%s]", names.sUserName);
441 strcpy(usern, names.sUserName);
442 strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
443 FreeContextBuffer(names.sUserName);
445 /* Force the user to retry if the context is invalid */
446 OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
447 code = CM_ERROR_BADPASSWORD;
451 case SEC_E_INVALID_TOKEN:
452 OutputDebugF("Returning bad password :: INVALID_TOKEN");
454 case SEC_E_INVALID_HANDLE:
455 OutputDebugF("Returning bad password :: INVALID_HANDLE");
457 case SEC_E_LOGON_DENIED:
458 OutputDebugF("Returning bad password :: LOGON_DENIED");
460 case SEC_E_UNKNOWN_CREDENTIALS:
461 OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
463 case SEC_E_NO_CREDENTIALS:
464 OutputDebugF("Returning bad password :: NO_CREDENTIALS");
466 case SEC_E_CONTEXT_EXPIRED:
467 OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
469 case SEC_E_INCOMPLETE_CREDENTIALS:
470 OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
472 case SEC_E_WRONG_PRINCIPAL:
473 OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
475 case SEC_E_TIME_SKEW:
476 OutputDebugF("Returning bad password :: TIME_SKEW");
479 OutputDebugF("Returning bad password :: Status == %lX", status);
481 code = CM_ERROR_BADPASSWORD;
485 if (secCtx->partialToken) free(secCtx->partialToken);
493 if (secTokOut.pvBuffer)
494 FreeContextBuffer(secTokOut.pvBuffer);
496 if (code != CM_ERROR_GSSCONTINUE) {
497 DeleteSecurityContext(&ctx);
498 FreeCredentialsHandle(&creds);
506 #define P_RESP_LEN 128
508 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
509 So put stuff in a struct. */
510 struct Lm20AuthBlob {
511 MSV1_0_LM20_LOGON lmlogon;
512 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
513 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
514 WCHAR accountNameW[P_LEN];
515 WCHAR primaryDomainW[P_LEN];
516 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
517 TOKEN_GROUPS tgroups;
518 TOKEN_SOURCE tsource;
521 long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
524 struct Lm20AuthBlob lmAuth;
525 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
526 QUOTA_LIMITS quotaLimits;
528 ULONG lmprofilepSize;
532 OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
533 OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
535 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
536 OutputDebugF("ciPwdLength or csPwdLength is too long");
537 return CM_ERROR_BADPASSWORD;
540 memset(&lmAuth,0,sizeof(lmAuth));
542 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
544 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
545 mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
546 lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
547 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
549 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
550 mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
551 lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
552 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
554 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
555 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
556 size = MAX_COMPUTERNAME_LENGTH + 1;
557 GetComputerNameW(lmAuth.workstationW, &size);
558 lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
560 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
562 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
563 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
564 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
565 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
567 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
568 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
569 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
570 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
572 lmAuth.lmlogon.ParameterControl = 0;
574 lmAuth.tgroups.GroupCount = 0;
575 lmAuth.tgroups.Groups[0].Sid = NULL;
576 lmAuth.tgroups.Groups[0].Attributes = 0;
578 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
579 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
580 strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
582 nts = LsaLogonUser( smb_lsaHandle,
597 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
598 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
601 OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
602 OutputDebugF("Extended status is 0x%lX", ntsEx);
604 if (nts == ERROR_SUCCESS) {
606 LsaFreeReturnBuffer(lmprofilep);
607 CloseHandle(lmToken);
611 if (nts == 0xC000015BL)
612 return CM_ERROR_BADLOGONTYPE;
613 else /* our catchall is a bad password though we could be more specific */
614 return CM_ERROR_BADPASSWORD;
618 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
619 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName)
624 /* check if we have sane input */
625 if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
628 /* we could get : [accountName][domainName]
634 atsign = strchr(accountName, '@');
636 if (atsign) /* [user@domain][] -> [user@domain][domain] */
641 /* if for some reason the client doesn't know what domain to use,
642 it will either return an empty string or a '?' */
643 if (!domain[0] || domain[0] == '?')
644 /* Empty domains and empty usernames are usually sent from tokenless contexts.
645 This way such logins will get an empty username (easy to check). I don't know
646 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
647 strcpy(usern,accountName);
649 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
650 strcpy(usern,domain);
653 strncat(usern,accountName,atsign - accountName);
655 strcat(usern,accountName);
663 /* When using SMB auth, all SMB sessions have to pass through here
664 * first to authenticate the user.
666 * Caveat: If not using SMB auth, the protocol does not require
667 * sending a session setup packet, which means that we can't rely on a
668 * UID in subsequent packets. Though in practice we get one anyway.
670 /* SMB_COM_SESSION_SETUP_ANDX */
671 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
675 unsigned short newUid;
676 unsigned long caps = 0;
680 char usern[SMB_MAX_USERNAME_LENGTH];
681 char *secBlobOut = NULL;
682 int secBlobOutLength = 0;
684 /* Check for bad conns */
685 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
686 return CM_ERROR_REMOTECONN;
688 if (vcp->flags & SMB_VCFLAG_USENT) {
689 if (smb_authType == SMB_AUTH_EXTENDED) {
690 /* extended authentication */
694 OutputDebugF("NT Session Setup: Extended");
696 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
697 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
700 secBlobInLength = smb_GetSMBParm(inp, 7);
701 secBlobIn = smb_GetSMBData(inp, NULL);
703 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
705 if (code == CM_ERROR_GSSCONTINUE) {
708 smb_SetSMBParm(outp, 2, 0);
709 smb_SetSMBParm(outp, 3, secBlobOutLength);
711 tp = smb_GetSMBData(outp, NULL);
712 if (secBlobOutLength) {
713 memcpy(tp, secBlobOut, secBlobOutLength);
715 tp += secBlobOutLength;
716 cb_data += secBlobOutLength;
718 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
719 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
720 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
722 smb_SetSMBDataLength(outp, cb_data);
725 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
727 unsigned ciPwdLength, csPwdLength;
733 if (smb_authType == SMB_AUTH_NTLM)
734 OutputDebugF("NT Session Setup: NTLM");
736 OutputDebugF("NT Session Setup: None");
738 /* TODO: parse for extended auth as well */
739 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
740 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
742 tp = smb_GetSMBData(inp, &datalen);
744 OutputDebugF("Session packet data size [%d]",datalen);
751 accountName = smb_ParseString(inp, tp, &tp, 0);
752 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
754 OutputDebugF("Account Name: %s",accountName);
755 OutputDebugF("Primary Domain: %s", primaryDomain);
756 OutputDebugF("Case Sensitive Password: %s", csPwd && csPwd[0] ? "yes" : "no");
757 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
759 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
760 /* shouldn't happen */
761 code = CM_ERROR_BADSMB;
762 goto after_read_packet;
765 /* capabilities are only valid for first session packet */
766 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
767 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
770 if (smb_authType == SMB_AUTH_NTLM) {
771 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
773 OutputDebugF("LM authentication failed [%d]", code);
775 OutputDebugF("LM authentication succeeded");
779 unsigned ciPwdLength;
784 switch ( smb_authType ) {
785 case SMB_AUTH_EXTENDED:
786 OutputDebugF("V3 Session Setup: Extended");
789 OutputDebugF("V3 Session Setup: NTLM");
792 OutputDebugF("V3 Session Setup: None");
794 ciPwdLength = smb_GetSMBParm(inp, 7);
795 tp = smb_GetSMBData(inp, NULL);
799 accountName = smb_ParseString(inp, tp, &tp, 0);
800 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
802 OutputDebugF("Account Name: %s",accountName);
803 OutputDebugF("Primary Domain: %s", primaryDomain);
804 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
806 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
807 /* shouldn't happen */
808 code = CM_ERROR_BADSMB;
809 goto after_read_packet;
812 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
815 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
816 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
818 OutputDebugF("LM authentication failed [%d]", code);
820 OutputDebugF("LM authentication succeeded");
825 /* note down that we received a session setup X and set the capabilities flag */
826 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
827 lock_ObtainMutex(&vcp->mx);
828 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
829 /* for the moment we can only deal with NTSTATUS */
830 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
831 vcp->flags |= SMB_VCFLAG_STATUS32;
835 if ((caps & NTNEGOTIATE_CAPABILITY_UNICODE) && smb_UseUnicode) {
836 vcp->flags |= SMB_VCFLAG_USEUNICODE;
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) {
923 smb_SetSMBParm(outp, 3, secBlobOutLength);
925 tp = smb_GetSMBData(outp, NULL);
926 if (secBlobOutLength) {
927 memcpy(tp, secBlobOut, secBlobOutLength);
929 tp += secBlobOutLength;
930 cb_data += secBlobOutLength;
933 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
934 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
935 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
937 smb_SetSMBDataLength(outp, cb_data);
939 smb_SetSMBDataLength(outp, 0);
942 if (smb_authType == SMB_AUTH_EXTENDED) {
945 tp = smb_GetSMBData(outp, NULL);
947 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
948 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
949 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
951 smb_SetSMBDataLength(outp, cb_data);
953 smb_SetSMBDataLength(outp, 0);
960 /* SMB_COM_LOGOFF_ANDX */
961 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
965 /* find the tree and free it */
966 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
968 smb_username_t * unp;
970 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %s", uidp->userID,
971 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "));
973 lock_ObtainMutex(&uidp->mx);
974 uidp->flags |= SMB_USERFLAG_DELETE;
976 * it doesn't get deleted right away
977 * because the vcp points to it
980 lock_ReleaseMutex(&uidp->mx);
983 /* we can't do this. we get logoff messages prior to a session
984 * disconnect even though it doesn't mean the user is logging out.
985 * we need to create a new pioctl and EventLogoff handler to set
986 * SMB_USERNAMEFLAG_LOGOFF.
988 if (unp && smb_LogoffTokenTransfer) {
989 lock_ObtainMutex(&unp->mx);
990 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
991 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
992 lock_ReleaseMutex(&unp->mx);
996 smb_ReleaseUID(uidp);
999 osi_Log0(smb_logp, "SMB3 user logoffX");
1001 smb_SetSMBDataLength(outp, 0);
1005 #define SMB_SUPPORT_SEARCH_BITS 0x0001
1006 #define SMB_SHARE_IS_IN_DFS 0x0002
1008 /* SMB_COM_TREE_CONNECT_ANDX */
1009 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1012 smb_user_t *uidp = NULL;
1013 unsigned short newTid;
1014 char shareName[AFSPATHMAX];
1021 cm_user_t *userp = NULL;
1024 osi_Log0(smb_logp, "SMB3 receive tree connect");
1026 /* parse input parameters */
1027 tp = smb_GetSMBData(inp, NULL);
1028 passwordp = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1029 pathp = smb_ParseString(inp, tp, &tp, SMB_STRF_ANSIPATH);
1030 servicep = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1032 tp = strrchr(pathp, '\\');
1034 return CM_ERROR_BADSMB;
1036 strcpy(shareName, tp+1);
1038 osi_Log3(smb_logp, "Tree connect pathp[%s] shareName[%s] service[%s]",
1039 osi_LogSaveString(smb_logp, pathp),
1040 osi_LogSaveString(smb_logp, shareName),
1041 osi_LogSaveString(smb_logp, servicep));
1043 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
1045 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1048 return CM_ERROR_NOIPC;
1052 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1054 userp = smb_GetUserFromUID(uidp);
1056 lock_ObtainMutex(&vcp->mx);
1057 newTid = vcp->tidCounter++;
1058 lock_ReleaseMutex(&vcp->mx);
1060 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1063 if (!strcmp(shareName, "*."))
1064 strcpy(shareName, "all");
1065 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1068 smb_ReleaseUID(uidp);
1069 smb_ReleaseTID(tidp, FALSE);
1070 return CM_ERROR_BADSHARENAME;
1073 if (vcp->flags & SMB_VCFLAG_USENT)
1075 int policy = smb_FindShareCSCPolicy(shareName);
1078 DWORD dwAdvertiseDFS = 0, dwSize = sizeof(DWORD);
1080 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1081 0, KEY_QUERY_VALUE, &parmKey);
1082 if (code == ERROR_SUCCESS) {
1083 code = RegQueryValueEx(parmKey, "AdvertiseDFS", NULL, NULL,
1084 (BYTE *)&dwAdvertiseDFS, &dwSize);
1085 if (code != ERROR_SUCCESS)
1087 RegCloseKey (parmKey);
1089 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1090 (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
1094 smb_SetSMBParm(outp, 2, 0);
1098 smb_ReleaseUID(uidp);
1100 lock_ObtainMutex(&tidp->mx);
1101 tidp->userp = userp;
1102 tidp->pathname = sharePath;
1104 tidp->flags |= SMB_TIDFLAG_IPC;
1105 lock_ReleaseMutex(&tidp->mx);
1106 smb_ReleaseTID(tidp, FALSE);
1108 ((smb_t *)outp)->tid = newTid;
1109 ((smb_t *)inp)->tid = newTid;
1110 tp = smb_GetSMBData(outp, NULL);
1114 tp = smb_UnparseString(outp, tp, "A:", &cb_data, SMB_STRF_FORCEASCII);
1115 tp = smb_UnparseString(outp, tp, "AFS", &cb_data, 0);
1116 smb_SetSMBDataLength(outp, cb_data);
1120 tp = smb_UnparseString(outp, tp, "IPC", &cb_data, SMB_STRF_FORCEASCII);
1121 smb_SetSMBDataLength(outp, cb_data);
1124 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1128 /* must be called with global tran lock held */
1129 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1131 smb_tran2Packet_t *tp;
1134 smbp = (smb_t *) inp->data;
1135 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1136 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1142 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1143 int totalParms, int totalData)
1145 smb_tran2Packet_t *tp;
1148 smbp = (smb_t *) inp->data;
1149 tp = malloc(sizeof(*tp));
1150 memset(tp, 0, sizeof(*tp));
1153 tp->curData = tp->curParms = 0;
1154 tp->totalData = totalData;
1155 tp->totalParms = totalParms;
1156 tp->tid = smbp->tid;
1157 tp->mid = smbp->mid;
1158 tp->uid = smbp->uid;
1159 tp->pid = smbp->pid;
1160 tp->res[0] = smbp->res[0];
1161 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1162 if (totalParms != 0)
1163 tp->parmsp = malloc(totalParms);
1165 tp->datap = malloc(totalData);
1166 if (smbp->com == 0x25 || smbp->com == 0x26)
1169 tp->opcode = smb_GetSMBParm(inp, 14);
1172 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1174 if (WANTS_UNICODE(inp) && (vcp->flags & SMB_VCFLAG_USEUNICODE))
1175 tp->flags |= SMB_TRAN2PFLAG_USEUNICODE;
1180 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1181 smb_tran2Packet_t *inp, smb_packet_t *outp,
1182 int totalParms, int totalData)
1184 smb_tran2Packet_t *tp;
1185 unsigned short parmOffset;
1186 unsigned short dataOffset;
1187 unsigned short dataAlign;
1189 tp = malloc(sizeof(*tp));
1190 memset(tp, 0, sizeof(*tp));
1193 tp->curData = tp->curParms = 0;
1194 tp->totalData = totalData;
1195 tp->totalParms = totalParms;
1196 tp->oldTotalParms = totalParms;
1201 tp->res[0] = inp->res[0];
1202 tp->opcode = inp->opcode;
1206 * We calculate where the parameters and data will start.
1207 * This calculation must parallel the calculation in
1208 * smb_SendTran2Packet.
1211 parmOffset = 10*2 + 35;
1212 parmOffset++; /* round to even */
1213 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1215 dataOffset = parmOffset + totalParms;
1216 dataAlign = dataOffset & 2; /* quad-align */
1217 dataOffset += dataAlign;
1218 tp->datap = outp->data + dataOffset;
1223 /* free a tran2 packet */
1224 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1227 smb_ReleaseVC(t2p->vcp);
1230 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1236 while (t2p->stringsp) {
1240 t2p->stringsp = ns->nextp;
1246 unsigned char *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
1247 char ** chainpp, int flags)
1252 if (!(p->flags & SMB_TRAN2PFLAG_USEUNICODE))
1253 flags |= SMB_STRF_FORCEASCII;
1256 cb = p->totalParms - (inp - (unsigned char *)p->parmsp);
1257 if (inp < (unsigned char *) p->parmsp ||
1258 inp > ((unsigned char *) p->parmsp) + p->totalParms) {
1263 return smb_ParseStringBuf((unsigned char *) p->parmsp, &p->stringsp,
1264 inp, &cb, chainpp, flags);
1267 /* called with a VC, an input packet to respond to, and an error code.
1268 * sends an error response.
1270 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1271 smb_packet_t *tp, long code)
1274 unsigned short errCode;
1275 unsigned char errClass;
1276 unsigned long NTStatus;
1278 if (vcp->flags & SMB_VCFLAG_STATUS32)
1279 smb_MapNTError(code, &NTStatus);
1281 smb_MapCoreError(code, vcp, &errCode, &errClass);
1283 smb_FormatResponsePacket(vcp, NULL, tp);
1284 smbp = (smb_t *) tp;
1286 /* We can handle long names */
1287 if (vcp->flags & SMB_VCFLAG_USENT)
1288 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1290 /* now copy important fields from the tran 2 packet */
1291 smbp->com = t2p->com;
1292 smbp->tid = t2p->tid;
1293 smbp->mid = t2p->mid;
1294 smbp->pid = t2p->pid;
1295 smbp->uid = t2p->uid;
1296 smbp->res[0] = t2p->res[0];
1297 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1298 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1299 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1300 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1301 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1302 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1305 smbp->rcls = errClass;
1306 smbp->errLow = (unsigned char) (errCode & 0xff);
1307 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1311 smb_SendPacket(vcp, tp);
1314 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1317 unsigned short parmOffset;
1318 unsigned short dataOffset;
1319 unsigned short totalLength;
1320 unsigned short dataAlign;
1323 smb_FormatResponsePacket(vcp, NULL, tp);
1324 smbp = (smb_t *) tp;
1326 /* We can handle long names */
1327 if (vcp->flags & SMB_VCFLAG_USENT)
1328 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1330 /* now copy important fields from the tran 2 packet */
1331 smbp->com = t2p->com;
1332 smbp->tid = t2p->tid;
1333 smbp->mid = t2p->mid;
1334 smbp->pid = t2p->pid;
1335 smbp->uid = t2p->uid;
1336 smbp->res[0] = t2p->res[0];
1338 totalLength = 1 + t2p->totalData + t2p->totalParms;
1340 /* now add the core parameters (tran2 info) to the packet */
1341 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1342 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1343 smb_SetSMBParm(tp, 2, 0); /* reserved */
1344 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1345 parmOffset = 10*2 + 35; /* parm offset in packet */
1346 parmOffset++; /* round to even */
1347 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1348 * hdr, bcc and wct */
1349 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1350 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1351 dataOffset = parmOffset + t2p->oldTotalParms;
1352 dataAlign = dataOffset & 2; /* quad-align */
1353 dataOffset += dataAlign;
1354 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1355 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1356 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1359 datap = smb_GetSMBData(tp, NULL);
1360 *datap++ = 0; /* we rounded to even */
1362 totalLength += dataAlign;
1363 smb_SetSMBDataLength(tp, totalLength);
1365 /* next, send the datagram */
1366 smb_SendPacket(vcp, tp);
1370 /* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
1371 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1373 smb_tran2Packet_t *asp;
1386 /* We sometimes see 0 word count. What to do? */
1387 if (*inp->wctp == 0) {
1388 osi_Log0(smb_logp, "Transaction2 word count = 0");
1389 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1391 smb_SetSMBDataLength(outp, 0);
1392 smb_SendPacket(vcp, outp);
1396 totalParms = smb_GetSMBParm(inp, 0);
1397 totalData = smb_GetSMBParm(inp, 1);
1399 firstPacket = (inp->inCom == 0x25);
1401 /* find the packet we're reassembling */
1402 lock_ObtainWrite(&smb_globalLock);
1403 asp = smb_FindTran2Packet(vcp, inp);
1405 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1407 lock_ReleaseWrite(&smb_globalLock);
1409 /* now merge in this latest packet; start by looking up offsets */
1411 parmDisp = dataDisp = 0;
1412 parmOffset = smb_GetSMBParm(inp, 10);
1413 dataOffset = smb_GetSMBParm(inp, 12);
1414 parmCount = smb_GetSMBParm(inp, 9);
1415 dataCount = smb_GetSMBParm(inp, 11);
1416 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1417 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1419 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1420 totalData, dataCount, asp->maxReturnData);
1423 parmDisp = smb_GetSMBParm(inp, 4);
1424 parmOffset = smb_GetSMBParm(inp, 3);
1425 dataDisp = smb_GetSMBParm(inp, 7);
1426 dataOffset = smb_GetSMBParm(inp, 6);
1427 parmCount = smb_GetSMBParm(inp, 2);
1428 dataCount = smb_GetSMBParm(inp, 5);
1430 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1431 parmCount, dataCount);
1434 /* now copy the parms and data */
1435 if ( asp->totalParms > 0 && parmCount != 0 )
1437 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1439 if ( asp->totalData > 0 && dataCount != 0 ) {
1440 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1443 /* account for new bytes */
1444 asp->curData += dataCount;
1445 asp->curParms += parmCount;
1447 /* finally, if we're done, remove the packet from the queue and dispatch it */
1448 if (asp->totalParms > 0 &&
1449 asp->curParms > 0 &&
1450 asp->totalData <= asp->curData &&
1451 asp->totalParms <= asp->curParms) {
1452 /* we've received it all */
1453 lock_ObtainWrite(&smb_globalLock);
1454 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1455 lock_ReleaseWrite(&smb_globalLock);
1457 /* now dispatch it */
1458 rapOp = asp->parmsp[0];
1460 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1461 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1462 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1463 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
1466 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1467 code = CM_ERROR_BADOP;
1470 /* if an error is returned, we're supposed to send an error packet,
1471 * otherwise the dispatched function already did the data sending.
1472 * We give dispatched proc the responsibility since it knows how much
1473 * space to allocate.
1476 smb_SendTran2Error(vcp, asp, outp, code);
1479 /* free the input tran 2 packet */
1480 smb_FreeTran2Packet(asp);
1482 else if (firstPacket) {
1483 /* the first packet in a multi-packet request, we need to send an
1484 * ack to get more data.
1486 smb_SetSMBDataLength(outp, 0);
1487 smb_SendPacket(vcp, outp);
1493 /* ANSI versions. */
1495 #pragma pack(push, 1)
1497 typedef struct smb_rap_share_info_0 {
1498 BYTE shi0_netname[13];
1499 } smb_rap_share_info_0_t;
1501 typedef struct smb_rap_share_info_1 {
1502 BYTE shi1_netname[13];
1505 DWORD shi1_remark; /* char *shi1_remark; data offset */
1506 } smb_rap_share_info_1_t;
1508 typedef struct smb_rap_share_info_2 {
1509 BYTE shi2_netname[13];
1512 DWORD shi2_remark; /* char *shi2_remark; data offset */
1513 WORD shi2_permissions;
1515 WORD shi2_current_uses;
1516 DWORD shi2_path; /* char *shi2_path; data offset */
1517 WORD shi2_passwd[9];
1519 } smb_rap_share_info_2_t;
1521 #define SMB_RAP_MAX_SHARES 512
1523 typedef struct smb_rap_share_list {
1526 smb_rap_share_info_0_t * shares;
1527 } smb_rap_share_list_t;
1531 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1532 smb_rap_share_list_t * sp;
1537 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1538 return 0; /* skip over '.' and '..' */
1540 sp = (smb_rap_share_list_t *) vrockp;
1542 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1543 sp->shares[sp->cShare].shi0_netname[12] = 0;
1547 if (sp->cShare >= sp->maxShares)
1548 return CM_ERROR_STOPNOW;
1553 /* RAP NetShareEnumRequest */
1554 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1556 smb_tran2Packet_t *outp;
1557 unsigned short * tp;
1561 int outParmsTotal; /* total parameter bytes */
1562 int outDataTotal; /* total data bytes */
1565 DWORD allSubmount = 0;
1567 DWORD nRegShares = 0;
1568 DWORD nSharesRet = 0;
1570 HKEY hkSubmount = NULL;
1571 smb_rap_share_info_1_t * shares;
1574 char thisShare[AFSPATHMAX];
1578 smb_rap_share_list_t rootShares;
1583 tp = p->parmsp + 1; /* skip over function number (always 0) */
1588 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1589 if (strcmp(cdescp, "WrLeh"))
1590 return CM_ERROR_INVAL;
1591 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1592 if (strcmp(cdescp, "B13BWz"))
1593 return CM_ERROR_INVAL;
1599 if (infoLevel != 1) {
1600 return CM_ERROR_INVAL;
1603 /* We are supposed to use the same ASCII data structure even if
1604 Unicode is negotiated, which ultimately means that the share
1605 names that we return must be at most 13 characters in length,
1606 including the NULL terminator.
1608 The RAP specification states that shares with names longer than
1609 12 characters should not be included in the enumeration.
1610 However, since we support prefix cell references and since many
1611 cell names are going to exceed 12 characters, we lie and send
1612 the first 12 characters.
1615 /* first figure out how many shares there are */
1616 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1617 KEY_QUERY_VALUE, &hkParam);
1618 if (rv == ERROR_SUCCESS) {
1619 len = sizeof(allSubmount);
1620 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1621 (BYTE *) &allSubmount, &len);
1622 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1625 RegCloseKey (hkParam);
1628 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1629 0, KEY_QUERY_VALUE, &hkSubmount);
1630 if (rv == ERROR_SUCCESS) {
1631 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1632 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1633 if (rv != ERROR_SUCCESS)
1639 /* fetch the root shares */
1640 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1641 rootShares.cShare = 0;
1642 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1646 userp = smb_GetTran2User(vcp,p);
1648 thyper.HighPart = 0;
1651 cm_HoldSCache(cm_data.rootSCachep);
1652 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1653 cm_ReleaseSCache(cm_data.rootSCachep);
1655 cm_ReleaseUser(userp);
1657 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1659 #define REMARK_LEN 1
1660 outParmsTotal = 8; /* 4 dwords */
1661 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1662 if(outDataTotal > bufsize) {
1663 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1664 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1667 nSharesRet = nShares;
1670 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1672 /* now for the submounts */
1673 shares = (smb_rap_share_info_1_t *) outp->datap;
1674 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1676 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1679 strcpy( shares[cshare].shi1_netname, "all" );
1680 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1681 /* type and pad are zero already */
1687 for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
1688 len = sizeof(thisShare);
1689 rv = RegEnumValue(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
1690 if (rv == ERROR_SUCCESS &&
1691 strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1692 strncpy(shares[cshare].shi1_netname, thisShare,
1693 sizeof(shares->shi1_netname)-1);
1694 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1695 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1700 nShares--; /* uncount key */
1703 RegCloseKey(hkSubmount);
1706 nonrootShares = cshare;
1708 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1709 /* in case there are collisions with submounts, submounts have higher priority */
1710 for (j=0; j < nonrootShares; j++)
1711 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1714 if (j < nonrootShares) {
1715 nShares--; /* uncount */
1719 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1720 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1725 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1726 outp->parmsp[1] = 0;
1727 outp->parmsp[2] = cshare;
1728 outp->parmsp[3] = nShares;
1730 outp->totalData = (int)(cstrp - outp->datap);
1731 outp->totalParms = outParmsTotal;
1733 smb_SendTran2Packet(vcp, outp, op);
1734 smb_FreeTran2Packet(outp);
1736 free(rootShares.shares);
1741 /* RAP NetShareGetInfo */
1742 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1744 smb_tran2Packet_t *outp;
1745 unsigned short * tp;
1747 BOOL shareFound = FALSE;
1748 unsigned short infoLevel;
1749 unsigned short bufsize;
1758 cm_scache_t *scp = NULL;
1764 tp = p->parmsp + 1; /* skip over function number (always 1) */
1769 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1770 if (strcmp(cdescp, "zWrLh"))
1772 return CM_ERROR_INVAL;
1774 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1775 if (strcmp(cdescp, "B13") &&
1776 strcmp(cdescp, "B13BWz") &&
1777 strcmp(cdescp, "B13BWzWWWzB9B"))
1779 return CM_ERROR_INVAL;
1781 shareName = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1789 totalData = sizeof(smb_rap_share_info_0_t);
1790 else if(infoLevel == SMB_INFO_STANDARD)
1791 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1792 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1793 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1795 return CM_ERROR_INVAL;
1797 if(!stricmp(shareName,"all") || !strcmp(shareName,"*.")) {
1798 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1799 KEY_QUERY_VALUE, &hkParam);
1800 if (rv == ERROR_SUCCESS) {
1801 len = sizeof(allSubmount);
1802 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1803 (BYTE *) &allSubmount, &len);
1804 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1807 RegCloseKey (hkParam);
1814 userp = smb_GetTran2User(vcp, p);
1816 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
1817 return CM_ERROR_BADSMB;
1819 code = cm_NameI(cm_data.rootSCachep, shareName,
1820 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
1821 userp, NULL, &req, &scp);
1823 cm_ReleaseSCache(scp);
1826 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1827 KEY_QUERY_VALUE, &hkSubmount);
1828 if (rv == ERROR_SUCCESS) {
1829 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1830 if (rv == ERROR_SUCCESS) {
1833 RegCloseKey(hkSubmount);
1839 return CM_ERROR_BADSHARENAME;
1841 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1842 memset(outp->datap, 0, totalData);
1844 outp->parmsp[0] = 0;
1845 outp->parmsp[1] = 0;
1846 outp->parmsp[2] = totalData;
1848 if (infoLevel == 0) {
1849 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1850 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1851 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1852 } else if(infoLevel == SMB_INFO_STANDARD) {
1853 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1854 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1855 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1856 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1857 /* type and pad are already zero */
1858 } else { /* infoLevel==2 */
1859 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1860 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1861 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1862 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1863 info->shi2_permissions = ACCESS_ALL;
1864 info->shi2_max_uses = (unsigned short) -1;
1865 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
1868 outp->totalData = totalData;
1869 outp->totalParms = totalParam;
1871 smb_SendTran2Packet(vcp, outp, op);
1872 smb_FreeTran2Packet(outp);
1877 #pragma pack(push, 1)
1879 typedef struct smb_rap_wksta_info_10 {
1880 DWORD wki10_computername; /*char *wki10_computername;*/
1881 DWORD wki10_username; /* char *wki10_username; */
1882 DWORD wki10_langroup; /* char *wki10_langroup;*/
1883 BYTE wki10_ver_major;
1884 BYTE wki10_ver_minor;
1885 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1886 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1887 } smb_rap_wksta_info_10_t;
1891 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1893 smb_tran2Packet_t *outp;
1897 unsigned short * tp;
1900 smb_rap_wksta_info_10_t * info;
1904 tp = p->parmsp + 1; /* Skip over function number */
1909 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
1910 SMB_STRF_FORCEASCII);
1911 if (strcmp(cdescp, "WrLh"))
1912 return CM_ERROR_INVAL;
1913 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
1914 SMB_STRF_FORCEASCII);
1915 if (strcmp(cdescp, "zzzBBzz"))
1916 return CM_ERROR_INVAL;
1922 if (infoLevel != 10) {
1923 return CM_ERROR_INVAL;
1929 totalData = sizeof(*info) + /* info */
1930 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1931 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1932 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1933 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1934 1; /* wki10_oth_domains (null)*/
1936 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1938 memset(outp->parmsp,0,totalParams);
1939 memset(outp->datap,0,totalData);
1941 info = (smb_rap_wksta_info_10_t *) outp->datap;
1942 cstrp = (char *) (info + 1);
1944 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1945 strcpy(cstrp, smb_localNamep);
1946 cstrp += strlen(cstrp) + 1;
1948 info->wki10_username = (DWORD) (cstrp - outp->datap);
1949 uidp = smb_FindUID(vcp, p->uid, 0);
1951 lock_ObtainMutex(&uidp->mx);
1952 if(uidp->unp && uidp->unp->name)
1953 strcpy(cstrp, uidp->unp->name);
1954 lock_ReleaseMutex(&uidp->mx);
1955 smb_ReleaseUID(uidp);
1957 cstrp += strlen(cstrp) + 1;
1959 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1960 strcpy(cstrp, "WORKGROUP");
1961 cstrp += strlen(cstrp) + 1;
1963 /* TODO: Not sure what values these should take, but these work */
1964 info->wki10_ver_major = 5;
1965 info->wki10_ver_minor = 1;
1967 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1968 strcpy(cstrp, smb_ServerDomainName);
1969 cstrp += strlen(cstrp) + 1;
1971 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1972 cstrp ++; /* no other domains */
1974 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1975 outp->parmsp[2] = outp->totalData;
1976 outp->totalParms = totalParams;
1978 smb_SendTran2Packet(vcp,outp,op);
1979 smb_FreeTran2Packet(outp);
1984 #pragma pack(push, 1)
1986 typedef struct smb_rap_server_info_0 {
1988 } smb_rap_server_info_0_t;
1990 typedef struct smb_rap_server_info_1 {
1992 BYTE sv1_version_major;
1993 BYTE sv1_version_minor;
1995 DWORD sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1996 } smb_rap_server_info_1_t;
2000 char smb_ServerComment[] = "OpenAFS Client";
2001 int smb_ServerCommentLen = sizeof(smb_ServerComment);
2003 #define SMB_SV_TYPE_SERVER 0x00000002L
2004 #define SMB_SV_TYPE_NT 0x00001000L
2005 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
2007 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2009 smb_tran2Packet_t *outp;
2013 unsigned short * tp;
2016 smb_rap_server_info_0_t * info0;
2017 smb_rap_server_info_1_t * info1;
2020 tp = p->parmsp + 1; /* Skip over function number */
2025 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2026 SMB_STRF_FORCEASCII);
2027 if (strcmp(cdescp, "WrLh"))
2028 return CM_ERROR_INVAL;
2029 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2030 SMB_STRF_FORCEASCII);
2031 if (strcmp(cdescp, "B16") ||
2032 strcmp(cdescp, "B16BBDz"))
2033 return CM_ERROR_INVAL;
2039 if (infoLevel != 0 && infoLevel != 1) {
2040 return CM_ERROR_INVAL;
2046 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
2047 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
2049 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2051 memset(outp->parmsp,0,totalParams);
2052 memset(outp->datap,0,totalData);
2054 if (infoLevel == 0) {
2055 info0 = (smb_rap_server_info_0_t *) outp->datap;
2056 cstrp = (char *) (info0 + 1);
2057 strcpy(info0->sv0_name, "AFS");
2058 } else { /* infoLevel == SMB_INFO_STANDARD */
2059 info1 = (smb_rap_server_info_1_t *) outp->datap;
2060 cstrp = (char *) (info1 + 1);
2061 strcpy(info1->sv1_name, "AFS");
2064 SMB_SV_TYPE_SERVER |
2066 SMB_SV_TYPE_SERVER_NT;
2068 info1->sv1_version_major = 5;
2069 info1->sv1_version_minor = 1;
2070 info1->sv1_comment_or_master_browser = (DWORD) (cstrp - outp->datap);
2072 strcpy(cstrp, smb_ServerComment);
2074 cstrp += smb_ServerCommentLen;
2077 totalData = (DWORD)(cstrp - outp->datap);
2078 outp->totalData = min(bufsize,totalData); /* actual data size */
2079 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
2080 outp->parmsp[2] = totalData;
2081 outp->totalParms = totalParams;
2083 smb_SendTran2Packet(vcp,outp,op);
2084 smb_FreeTran2Packet(outp);
2089 /* SMB_COM_TRANSACTION2 and SMB_COM_TRANSACTION2_SECONDARY */
2090 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2092 smb_tran2Packet_t *asp;
2104 /* We sometimes see 0 word count. What to do? */
2105 if (*inp->wctp == 0) {
2106 osi_Log0(smb_logp, "Transaction2 word count = 0");
2107 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
2109 smb_SetSMBDataLength(outp, 0);
2110 smb_SendPacket(vcp, outp);
2114 totalParms = smb_GetSMBParm(inp, 0);
2115 totalData = smb_GetSMBParm(inp, 1);
2117 firstPacket = (inp->inCom == 0x32);
2119 /* find the packet we're reassembling */
2120 lock_ObtainWrite(&smb_globalLock);
2121 asp = smb_FindTran2Packet(vcp, inp);
2123 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
2125 lock_ReleaseWrite(&smb_globalLock);
2127 /* now merge in this latest packet; start by looking up offsets */
2129 parmDisp = dataDisp = 0;
2130 parmOffset = smb_GetSMBParm(inp, 10);
2131 dataOffset = smb_GetSMBParm(inp, 12);
2132 parmCount = smb_GetSMBParm(inp, 9);
2133 dataCount = smb_GetSMBParm(inp, 11);
2134 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2135 asp->maxReturnData = smb_GetSMBParm(inp, 3);
2137 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2138 totalData, dataCount, asp->maxReturnData);
2141 parmDisp = smb_GetSMBParm(inp, 4);
2142 parmOffset = smb_GetSMBParm(inp, 3);
2143 dataDisp = smb_GetSMBParm(inp, 7);
2144 dataOffset = smb_GetSMBParm(inp, 6);
2145 parmCount = smb_GetSMBParm(inp, 2);
2146 dataCount = smb_GetSMBParm(inp, 5);
2148 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2149 parmCount, dataCount);
2152 /* now copy the parms and data */
2153 if ( asp->totalParms > 0 && parmCount != 0 )
2155 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2157 if ( asp->totalData > 0 && dataCount != 0 ) {
2158 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2161 /* account for new bytes */
2162 asp->curData += dataCount;
2163 asp->curParms += parmCount;
2165 /* finally, if we're done, remove the packet from the queue and dispatch it */
2166 if (asp->totalParms > 0 &&
2167 asp->curParms > 0 &&
2168 asp->totalData <= asp->curData &&
2169 asp->totalParms <= asp->curParms) {
2170 /* we've received it all */
2171 lock_ObtainWrite(&smb_globalLock);
2172 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2173 lock_ReleaseWrite(&smb_globalLock);
2175 /* now dispatch it */
2176 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2177 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2178 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2181 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2182 code = CM_ERROR_BADOP;
2185 /* if an error is returned, we're supposed to send an error packet,
2186 * otherwise the dispatched function already did the data sending.
2187 * We give dispatched proc the responsibility since it knows how much
2188 * space to allocate.
2191 smb_SendTran2Error(vcp, asp, outp, code);
2194 /* free the input tran 2 packet */
2195 smb_FreeTran2Packet(asp);
2197 else if (firstPacket) {
2198 /* the first packet in a multi-packet request, we need to send an
2199 * ack to get more data.
2201 smb_SetSMBDataLength(outp, 0);
2202 smb_SendPacket(vcp, outp);
2209 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2212 smb_tran2Packet_t *outp;
2217 cm_scache_t *dscp; /* dir we're dealing with */
2218 cm_scache_t *scp; /* file we're creating */
2220 int initialModeBits;
2230 int parmSlot; /* which parm we're dealing with */
2231 long returnEALength;
2240 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2241 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2243 openFun = p->parmsp[6]; /* open function */
2244 excl = ((openFun & 3) == 0);
2245 trunc = ((openFun & 3) == 2); /* truncate it */
2246 openMode = (p->parmsp[1] & 0x7);
2247 openAction = 0; /* tracks what we did */
2249 attributes = p->parmsp[3];
2250 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2252 /* compute initial mode bits based on read-only flag in attributes */
2253 initialModeBits = 0666;
2254 if (attributes & SMB_ATTR_READONLY)
2255 initialModeBits &= ~0222;
2257 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
2260 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2262 spacep = cm_GetSpace();
2263 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2266 (stricmp(lastNamep, SMB_IOCTL_FILENAME) == 0 ||
2267 stricmp(lastNamep, "\\srvsvc") == 0 ||
2268 stricmp(lastNamep, "\\wkssvc") == 0 ||
2269 stricmp(lastNamep, "\\ipc$") == 0)) {
2270 /* special case magic file name for receiving IOCTL requests
2271 * (since IOCTL calls themselves aren't getting through).
2273 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2274 smb_SetupIoctlFid(fidp, spacep);
2276 /* copy out remainder of the parms */
2278 outp->parmsp[parmSlot++] = fidp->fid;
2280 outp->parmsp[parmSlot++] = 0; /* attrs */
2281 outp->parmsp[parmSlot++] = 0; /* mod time */
2282 outp->parmsp[parmSlot++] = 0;
2283 outp->parmsp[parmSlot++] = 0; /* len */
2284 outp->parmsp[parmSlot++] = 0x7fff;
2285 outp->parmsp[parmSlot++] = openMode;
2286 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2287 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2289 /* and the final "always present" stuff */
2290 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2291 /* next write out the "unique" ID */
2292 outp->parmsp[parmSlot++] = 0x1234;
2293 outp->parmsp[parmSlot++] = 0x5678;
2294 outp->parmsp[parmSlot++] = 0;
2295 if (returnEALength) {
2296 outp->parmsp[parmSlot++] = 0;
2297 outp->parmsp[parmSlot++] = 0;
2300 outp->totalData = 0;
2301 outp->totalParms = parmSlot * 2;
2303 smb_SendTran2Packet(vcp, outp, op);
2305 smb_FreeTran2Packet(outp);
2307 /* and clean up fid reference */
2308 smb_ReleaseFID(fidp);
2312 #ifdef DEBUG_VERBOSE
2314 char *hexp, *asciip;
2315 asciip = (lastNamep ? lastNamep : pathp);
2316 hexp = osi_HexifyString( asciip );
2317 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2322 userp = smb_GetTran2User(vcp, p);
2323 /* In the off chance that userp is NULL, we log and abandon */
2325 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2326 smb_FreeTran2Packet(outp);
2327 return CM_ERROR_BADSMB;
2330 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2331 if (code == CM_ERROR_TIDIPC) {
2332 /* Attempt to use a TID allocated for IPC. The client
2333 * is probably looking for DCE RPC end points which we
2334 * don't support OR it could be looking to make a DFS
2337 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2339 cm_ReleaseUser(userp);
2340 smb_FreeTran2Packet(outp);
2341 return CM_ERROR_NOSUCHPATH;
2346 code = cm_NameI(cm_data.rootSCachep, pathp,
2347 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2348 userp, tidPathp, &req, &scp);
2350 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2351 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2352 userp, tidPathp, &req, &dscp);
2353 cm_FreeSpace(spacep);
2356 cm_ReleaseUser(userp);
2357 smb_FreeTran2Packet(outp);
2362 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2363 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
2364 cm_ReleaseSCache(dscp);
2365 cm_ReleaseUser(userp);
2366 smb_FreeTran2Packet(outp);
2367 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2368 return CM_ERROR_PATH_NOT_COVERED;
2370 return CM_ERROR_BADSHARENAME;
2372 #endif /* DFS_SUPPORT */
2374 /* otherwise, scp points to the parent directory. Do a lookup,
2375 * and truncate the file if we find it, otherwise we create the
2382 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2384 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2385 cm_ReleaseSCache(dscp);
2386 cm_ReleaseUser(userp);
2387 smb_FreeTran2Packet(outp);
2392 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2393 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2394 cm_ReleaseSCache(scp);
2395 cm_ReleaseUser(userp);
2396 smb_FreeTran2Packet(outp);
2397 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2398 return CM_ERROR_PATH_NOT_COVERED;
2400 return CM_ERROR_BADSHARENAME;
2402 #endif /* DFS_SUPPORT */
2404 /* macintosh is expensive to program for it */
2405 cm_FreeSpace(spacep);
2408 /* if we get here, if code is 0, the file exists and is represented by
2409 * scp. Otherwise, we have to create it.
2412 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2415 cm_ReleaseSCache(dscp);
2416 cm_ReleaseSCache(scp);
2417 cm_ReleaseUser(userp);
2418 smb_FreeTran2Packet(outp);
2423 /* oops, file shouldn't be there */
2425 cm_ReleaseSCache(dscp);
2426 cm_ReleaseSCache(scp);
2427 cm_ReleaseUser(userp);
2428 smb_FreeTran2Packet(outp);
2429 return CM_ERROR_EXISTS;
2433 setAttr.mask = CM_ATTRMASK_LENGTH;
2434 setAttr.length.LowPart = 0;
2435 setAttr.length.HighPart = 0;
2436 code = cm_SetAttr(scp, &setAttr, userp, &req);
2437 openAction = 3; /* truncated existing file */
2440 openAction = 1; /* found existing file */
2442 else if (!(openFun & 0x10)) {
2443 /* don't create if not found */
2445 cm_ReleaseSCache(dscp);
2446 osi_assertx(scp == NULL, "null cm_scache_t");
2447 cm_ReleaseUser(userp);
2448 smb_FreeTran2Packet(outp);
2449 return CM_ERROR_NOSUCHFILE;
2452 osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2453 openAction = 2; /* created file */
2454 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2455 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2456 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2460 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2461 smb_NotifyChange(FILE_ACTION_ADDED,
2462 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2463 dscp, lastNamep, NULL, TRUE);
2464 } else if (!excl && code == CM_ERROR_EXISTS) {
2465 /* not an exclusive create, and someone else tried
2466 * creating it already, then we open it anyway. We
2467 * don't bother retrying after this, since if this next
2468 * fails, that means that the file was deleted after we
2469 * started this call.
2471 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2475 setAttr.mask = CM_ATTRMASK_LENGTH;
2476 setAttr.length.LowPart = 0;
2477 setAttr.length.HighPart = 0;
2478 code = cm_SetAttr(scp, &setAttr, userp,
2481 } /* lookup succeeded */
2485 /* we don't need this any longer */
2487 cm_ReleaseSCache(dscp);
2490 /* something went wrong creating or truncating the file */
2492 cm_ReleaseSCache(scp);
2493 cm_ReleaseUser(userp);
2494 smb_FreeTran2Packet(outp);
2498 /* make sure we're about to open a file */
2499 if (scp->fileType != CM_SCACHETYPE_FILE) {
2501 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2502 cm_scache_t * targetScp = 0;
2503 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2505 /* we have a more accurate file to use (the
2506 * target of the symbolic link). Otherwise,
2507 * we'll just use the symlink anyway.
2509 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2511 cm_ReleaseSCache(scp);
2515 if (scp->fileType != CM_SCACHETYPE_FILE) {
2516 cm_ReleaseSCache(scp);
2517 cm_ReleaseUser(userp);
2518 smb_FreeTran2Packet(outp);
2519 return CM_ERROR_ISDIR;
2523 /* now all we have to do is open the file itself */
2524 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2525 osi_assertx(fidp, "null smb_fid_t");
2528 lock_ObtainMutex(&fidp->mx);
2529 /* save a pointer to the vnode */
2530 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2532 lock_ObtainWrite(&scp->rw);
2533 scp->flags |= CM_SCACHEFLAG_SMB_FID;
2534 lock_ReleaseWrite(&scp->rw);
2537 fidp->userp = userp;
2539 /* compute open mode */
2541 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
2542 if (openMode == 1 || openMode == 2)
2543 fidp->flags |= SMB_FID_OPENWRITE;
2545 /* remember that the file was newly created */
2547 fidp->flags |= SMB_FID_CREATED;
2549 lock_ReleaseMutex(&fidp->mx);
2551 smb_ReleaseFID(fidp);
2553 cm_Open(scp, 0, userp);
2555 /* copy out remainder of the parms */
2557 outp->parmsp[parmSlot++] = fidp->fid;
2558 lock_ObtainRead(&scp->rw);
2560 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2561 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2562 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2563 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2564 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2565 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2566 outp->parmsp[parmSlot++] = openMode;
2567 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2568 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2570 /* and the final "always present" stuff */
2571 outp->parmsp[parmSlot++] = openAction;
2572 /* next write out the "unique" ID */
2573 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2574 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2575 outp->parmsp[parmSlot++] = 0;
2576 if (returnEALength) {
2577 outp->parmsp[parmSlot++] = 0;
2578 outp->parmsp[parmSlot++] = 0;
2580 lock_ReleaseRead(&scp->rw);
2581 outp->totalData = 0; /* total # of data bytes */
2582 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2584 smb_SendTran2Packet(vcp, outp, op);
2586 smb_FreeTran2Packet(outp);
2588 cm_ReleaseUser(userp);
2589 /* leave scp held since we put it in fidp->scp */
2593 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2596 unsigned short infolevel;
2598 infolevel = p->parmsp[0];
2600 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2602 return CM_ERROR_BAD_LEVEL;
2605 /* TRANS2_QUERY_FS_INFORMATION */
2606 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2608 smb_tran2Packet_t *outp;
2609 smb_tran2QFSInfo_t qi;
2613 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2615 switch (p->parmsp[0]) {
2616 case SMB_INFO_ALLOCATION:
2618 responseSize = sizeof(qi.u.allocInfo);
2620 qi.u.allocInfo.FSID = 0;
2621 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2622 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2623 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2624 qi.u.allocInfo.bytesPerSector = 1024;
2627 case SMB_INFO_VOLUME:
2629 qi.u.volumeInfo.vsn = 1234; /* Volume serial number */
2630 qi.u.volumeInfo.vnCount = 4; /* Number of characters in label (AFS\0)*/
2632 /* we're supposed to pad it out with zeroes to the end */
2633 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2634 smb_UnparseString(op, qi.u.volumeInfo.label, "AFS", &sz, 0);
2636 responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
2639 case SMB_QUERY_FS_VOLUME_INFO:
2640 /* FS volume info */
2641 responseSize = sizeof(qi.u.FSvolumeInfo);
2644 FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
2645 memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
2648 qi.u.FSvolumeInfo.vsn = 1234;
2649 qi.u.FSvolumeInfo.vnCount = 8; /* This is always in Unicode */
2650 memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
2653 case SMB_QUERY_FS_SIZE_INFO:
2655 responseSize = sizeof(qi.u.FSsizeInfo);
2657 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2658 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2659 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2660 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2661 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2662 qi.u.FSsizeInfo.bytesPerSector = 1024;
2665 case SMB_QUERY_FS_DEVICE_INFO:
2666 /* FS device info */
2667 responseSize = sizeof(qi.u.FSdeviceInfo);
2669 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2670 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2673 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2674 /* FS attribute info */
2676 /* attributes, defined in WINNT.H:
2677 * FILE_CASE_SENSITIVE_SEARCH 0x1
2678 * FILE_CASE_PRESERVED_NAMES 0x2
2679 * FILE_VOLUME_QUOTAS 0x10
2680 * <no name defined> 0x4000
2681 * If bit 0x4000 is not set, Windows 95 thinks
2682 * we can't handle long (non-8.3) names,
2683 * despite our protestations to the contrary.
2685 qi.u.FSattributeInfo.attributes = 0x4003;
2686 /* The maxCompLength is supposed to be in bytes */
2688 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2689 qi.u.FSattributeInfo.maxCompLength = MAX_PATH * sizeof(wchar_t);
2692 qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
2696 smb_UnparseString(op, qi.u.FSattributeInfo.FSname, "AFS", &sz, 0);
2697 qi.u.FSattributeInfo.FSnameLength = sz;
2700 sizeof(qi.u.FSattributeInfo.attributes) +
2701 sizeof(qi.u.FSattributeInfo.maxCompLength) +
2702 sizeof(qi.u.FSattributeInfo.FSnameLength) +
2707 case SMB_INFO_UNIX: /* CIFS Unix Info */
2708 case SMB_INFO_MACOS: /* Mac FS Info */
2710 return CM_ERROR_BADOP;
2713 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2715 /* copy out return data, and set corresponding sizes */
2716 outp->totalParms = 0;
2717 outp->totalData = responseSize;
2718 memcpy(outp->datap, &qi, responseSize);
2720 /* send and free the packets */
2721 smb_SendTran2Packet(vcp, outp, op);
2722 smb_FreeTran2Packet(outp);
2727 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2729 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2730 return CM_ERROR_BADOP;
2733 struct smb_ShortNameRock {
2737 size_t shortNameLen;
2740 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2743 struct smb_ShortNameRock *rockp;
2747 /* compare both names and vnodes, though probably just comparing vnodes
2748 * would be safe enough.
2750 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2752 if (ntohl(dep->fid.vnode) != rockp->vnode)
2754 /* This is the entry */
2755 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2756 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2757 return CM_ERROR_STOPNOW;
2760 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2761 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2763 struct smb_ShortNameRock rock;
2767 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2771 spacep = cm_GetSpace();
2772 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2774 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2776 cm_FreeSpace(spacep);
2781 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2782 cm_ReleaseSCache(dscp);
2783 cm_ReleaseUser(userp);
2785 return CM_ERROR_PATH_NOT_COVERED;
2787 #endif /* DFS_SUPPORT */
2789 if (!lastNamep) lastNamep = pathp;
2792 thyper.HighPart = 0;
2793 rock.shortName = shortName;
2795 rock.maskp = lastNamep;
2796 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2798 cm_ReleaseSCache(dscp);
2801 return CM_ERROR_NOSUCHFILE;
2802 if (code == CM_ERROR_STOPNOW) {
2803 *shortNameLenp = rock.shortNameLen;
2809 /* TRANS2_QUERY_PATH_INFORMATION */
2810 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2812 smb_tran2Packet_t *outp;
2815 unsigned short infoLevel;
2816 smb_tran2QPathInfo_t qpi;
2818 unsigned short attributes;
2819 unsigned long extAttributes;
2824 cm_scache_t *scp, *dscp;
2825 int scp_mx_held = 0;
2835 infoLevel = p->parmsp[0];
2836 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2838 else if (infoLevel == SMB_INFO_STANDARD)
2839 responseSize = sizeof(qpi.u.QPstandardInfo);
2840 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2841 responseSize = sizeof(qpi.u.QPeaSizeInfo);
2842 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2843 responseSize = sizeof(qpi.u.QPfileBasicInfo);
2844 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2845 responseSize = sizeof(qpi.u.QPfileStandardInfo);
2846 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2847 responseSize = sizeof(qpi.u.QPfileEaInfo);
2848 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2849 responseSize = sizeof(qpi.u.QPfileNameInfo);
2850 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
2851 responseSize = sizeof(qpi.u.QPfileAllInfo);
2852 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2853 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2855 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2856 p->opcode, infoLevel);
2857 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
2861 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
2862 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2863 osi_LogSaveString(smb_logp, pathp));
2865 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2867 if (infoLevel > 0x100)
2868 outp->totalParms = 2;
2870 outp->totalParms = 0;
2871 outp->totalData = responseSize;
2873 /* now, if we're at infoLevel 6, we're only being asked to check
2874 * the syntax, so we just OK things now. In particular, we're *not*
2875 * being asked to verify anything about the state of any parent dirs.
2877 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2878 smb_SendTran2Packet(vcp, outp, opx);
2879 smb_FreeTran2Packet(outp);
2883 userp = smb_GetTran2User(vcp, p);
2885 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2886 smb_FreeTran2Packet(outp);
2887 return CM_ERROR_BADSMB;
2890 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2892 cm_ReleaseUser(userp);
2893 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2894 smb_FreeTran2Packet(outp);
2899 * XXX Strange hack XXX
2901 * As of Patch 7 (13 January 98), we are having the following problem:
2902 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2903 * requests to look up "desktop.ini" in all the subdirectories.
2904 * This can cause zillions of timeouts looking up non-existent cells
2905 * and volumes, especially in the top-level directory.
2907 * We have not found any way to avoid this or work around it except
2908 * to explicitly ignore the requests for mount points that haven't
2909 * yet been evaluated and for directories that haven't yet been
2912 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2913 spacep = cm_GetSpace();
2914 smb_StripLastComponent(spacep->data, &lastComp, pathp);
2915 #ifndef SPECIAL_FOLDERS
2916 /* Make sure that lastComp is not NULL */
2918 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2919 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2923 userp, tidPathp, &req, &dscp);
2926 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2927 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
2928 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2929 code = CM_ERROR_PATH_NOT_COVERED;
2931 code = CM_ERROR_BADSHARENAME;
2933 #endif /* DFS_SUPPORT */
2934 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2935 code = CM_ERROR_NOSUCHFILE;
2936 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2937 cm_buf_t *bp = buf_Find(dscp, &hzero);
2943 code = CM_ERROR_NOSUCHFILE;
2945 cm_ReleaseSCache(dscp);
2947 cm_FreeSpace(spacep);
2948 cm_ReleaseUser(userp);
2949 smb_SendTran2Error(vcp, p, opx, code);
2950 smb_FreeTran2Packet(outp);
2956 #endif /* SPECIAL_FOLDERS */
2958 cm_FreeSpace(spacep);
2961 /* now do namei and stat, and copy out the info */
2962 code = cm_NameI(cm_data.rootSCachep, pathp,
2963 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2966 cm_ReleaseUser(userp);
2967 smb_SendTran2Error(vcp, p, opx, code);
2968 smb_FreeTran2Packet(outp);
2973 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2974 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
2975 cm_ReleaseSCache(scp);
2976 cm_ReleaseUser(userp);
2977 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2978 code = CM_ERROR_PATH_NOT_COVERED;
2980 code = CM_ERROR_BADSHARENAME;
2981 smb_SendTran2Error(vcp, p, opx, code);
2982 smb_FreeTran2Packet(outp);
2985 #endif /* DFS_SUPPORT */
2987 lock_ObtainWrite(&scp->rw);
2989 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2990 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2991 if (code) goto done;
2993 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2995 lock_ConvertWToR(&scp->rw);
2999 /* now we have the status in the cache entry, and everything is locked.
3000 * Marshall the output data.
3002 /* for info level 108, figure out short name */
3003 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3004 code = cm_GetShortName(pathp, userp, &req,
3005 tidPathp, scp->fid.vnode, shortName,
3011 smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, 0);
3012 qpi.u.QPfileAltNameInfo.fileNameLength = len;
3016 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3017 smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, 0);
3018 qpi.u.QPfileNameInfo.fileNameLength = len;
3022 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3023 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3024 qpi.u.QPstandardInfo.creationDateTime = dosTime;
3025 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3026 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3027 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3028 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3029 attributes = smb_Attributes(scp);
3030 qpi.u.QPstandardInfo.attributes = attributes;
3031 qpi.u.QPstandardInfo.eaSize = 0;
3033 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3034 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3035 qpi.u.QPfileBasicInfo.creationTime = ft;
3036 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3037 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3038 qpi.u.QPfileBasicInfo.changeTime = ft;
3039 extAttributes = smb_ExtAttributes(scp);
3040 qpi.u.QPfileBasicInfo.attributes = extAttributes;
3041 qpi.u.QPfileBasicInfo.reserved = 0;
3043 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3044 smb_fid_t *fidp = smb_FindFIDByScache(vcp, scp);
3046 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3047 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3048 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3049 qpi.u.QPfileStandardInfo.directory =
3050 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3051 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3052 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3053 qpi.u.QPfileStandardInfo.reserved = 0;
3056 lock_ReleaseRead(&scp->rw);
3058 lock_ObtainMutex(&fidp->mx);
3059 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3060 lock_ReleaseMutex(&fidp->mx);
3061 smb_ReleaseFID(fidp);
3063 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3065 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3066 qpi.u.QPfileEaInfo.eaSize = 0;
3068 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3069 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3070 qpi.u.QPfileAllInfo.creationTime = ft;
3071 qpi.u.QPfileAllInfo.lastAccessTime = ft;
3072 qpi.u.QPfileAllInfo.lastWriteTime = ft;
3073 qpi.u.QPfileAllInfo.changeTime = ft;
3074 extAttributes = smb_ExtAttributes(scp);
3075 qpi.u.QPfileAllInfo.attributes = extAttributes;
3076 qpi.u.QPfileAllInfo.allocationSize = scp->length;
3077 qpi.u.QPfileAllInfo.endOfFile = scp->length;
3078 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3079 qpi.u.QPfileAllInfo.deletePending = 0;
3080 qpi.u.QPfileAllInfo.directory =
3081 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3082 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3083 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3084 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
3085 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
3086 qpi.u.QPfileAllInfo.eaSize = 0;
3087 qpi.u.QPfileAllInfo.accessFlags = 0;
3088 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
3089 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
3090 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3091 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3092 qpi.u.QPfileAllInfo.mode = 0;
3093 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3095 smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, 0);
3096 qpi.u.QPfileAllInfo.fileNameLength = len;
3099 /* send and free the packets */
3102 lock_ReleaseRead(&scp->rw);
3103 cm_ReleaseSCache(scp);
3104 cm_ReleaseUser(userp);
3106 memcpy(outp->datap, &qpi, responseSize);
3107 smb_SendTran2Packet(vcp, outp, opx);
3109 smb_SendTran2Error(vcp, p, opx, code);
3111 smb_FreeTran2Packet(outp);
3116 /* TRANS2_SET_PATH_INFORMATION */
3117 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3120 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
3121 return CM_ERROR_BADOP;
3125 unsigned short infoLevel;
3127 smb_tran2Packet_t *outp;
3128 smb_tran2QPathInfo_t *spi;
3130 cm_scache_t *scp, *dscp;
3138 infoLevel = p->parmsp[0];
3139 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
3140 if (infoLevel != SMB_INFO_STANDARD &&
3141 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
3142 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
3143 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3144 p->opcode, infoLevel);
3145 smb_SendTran2Error(vcp, p, opx,
3146 infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3150 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3152 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %s", infoLevel,
3153 osi_LogSaveString(smb_logp, pathp));
3155 userp = smb_GetTran2User(vcp, p);
3157 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3158 code = CM_ERROR_BADSMB;
3162 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3163 if (code == CM_ERROR_TIDIPC) {
3164 /* Attempt to use a TID allocated for IPC. The client
3165 * is probably looking for DCE RPC end points which we
3166 * don't support OR it could be looking to make a DFS
3169 osi_Log0(smb_logp, "Tran2Open received IPC TID");
3170 cm_ReleaseUser(userp);
3171 return CM_ERROR_NOSUCHPATH;
3175 * XXX Strange hack XXX
3177 * As of Patch 7 (13 January 98), we are having the following problem:
3178 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3179 * requests to look up "desktop.ini" in all the subdirectories.
3180 * This can cause zillions of timeouts looking up non-existent cells
3181 * and volumes, especially in the top-level directory.
3183 * We have not found any way to avoid this or work around it except
3184 * to explicitly ignore the requests for mount points that haven't
3185 * yet been evaluated and for directories that haven't yet been
3188 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3189 spacep = cm_GetSpace();
3190 smb_StripLastComponent(spacep->data, &lastComp, pathp);
3191 #ifndef SPECIAL_FOLDERS
3192 /* Make sure that lastComp is not NULL */
3194 if (stricmp(lastComp, "\\desktop.ini") == 0) {
3195 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3199 userp, tidPathp, &req, &dscp);
3202 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3203 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
3204 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3205 code = CM_ERROR_PATH_NOT_COVERED;
3207 code = CM_ERROR_BADSHARENAME;
3209 #endif /* DFS_SUPPORT */
3210 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3211 code = CM_ERROR_NOSUCHFILE;
3212 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3213 cm_buf_t *bp = buf_Find(dscp, &hzero);
3219 code = CM_ERROR_NOSUCHFILE;
3221 cm_ReleaseSCache(dscp);
3223 cm_FreeSpace(spacep);
3224 cm_ReleaseUser(userp);
3225 smb_SendTran2Error(vcp, p, opx, code);
3231 #endif /* SPECIAL_FOLDERS */
3233 cm_FreeSpace(spacep);
3236 /* now do namei and stat, and copy out the info */
3237 code = cm_NameI(cm_data.rootSCachep, pathp,
3238 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3240 cm_ReleaseUser(userp);
3241 smb_SendTran2Error(vcp, p, opx, code);
3245 fidp = smb_FindFIDByScache(vcp, scp);
3247 cm_ReleaseSCache(scp);
3248 cm_ReleaseUser(userp);
3249 smb_SendTran2Error(vcp, p, opx, code);
3253 lock_ObtainMutex(&fidp->mx);
3254 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
3255 lock_ReleaseMutex(&fidp->mx);
3256 cm_ReleaseSCache(scp);
3257 smb_ReleaseFID(fidp);
3258 cm_ReleaseUser(userp);
3259 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3262 lock_ReleaseMutex(&fidp->mx);
3264 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3266 outp->totalParms = 2;
3267 outp->totalData = 0;
3269 spi = (smb_tran2QPathInfo_t *)p->datap;
3270 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3273 /* lock the vnode with a callback; we need the current status
3274 * to determine what the new status is, in some cases.
3276 lock_ObtainWrite(&scp->rw);
3277 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3278 CM_SCACHESYNC_GETSTATUS
3279 | CM_SCACHESYNC_NEEDCALLBACK);
3281 lock_ReleaseWrite(&scp->rw);
3284 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3286 lock_ReleaseWrite(&scp->rw);
3287 lock_ObtainMutex(&fidp->mx);
3288 lock_ObtainRead(&scp->rw);
3290 /* prepare for setattr call */
3291 attr.mask = CM_ATTRMASK_LENGTH;
3292 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3293 attr.length.HighPart = 0;
3295 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3296 smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3297 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3298 fidp->flags |= SMB_FID_MTIMESETDONE;
3301 if (spi->u.QPstandardInfo.attributes != 0) {
3302 if ((scp->unixModeBits & 0222)
3303 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3304 /* make a writable file read-only */
3305 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3306 attr.unixModeBits = scp->unixModeBits & ~0222;
3308 else if ((scp->unixModeBits & 0222) == 0
3309 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3310 /* make a read-only file writable */
3311 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3312 attr.unixModeBits = scp->unixModeBits | 0222;
3315 lock_ReleaseRead(&scp->rw);
3316 lock_ReleaseMutex(&fidp->mx);
3320 code = cm_SetAttr(scp, &attr, userp, &req);
3324 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3325 /* we don't support EAs */
3326 code = CM_ERROR_EAS_NOT_SUPPORTED;
3330 cm_ReleaseSCache(scp);
3331 cm_ReleaseUser(userp);
3332 smb_ReleaseFID(fidp);
3334 smb_SendTran2Packet(vcp, outp, opx);
3336 smb_SendTran2Error(vcp, p, opx, code);
3337 smb_FreeTran2Packet(outp);
3343 /* TRANS2_QUERY_FILE_INFORMATION */
3344 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3346 smb_tran2Packet_t *outp;
3348 unsigned long attributes;
3349 unsigned short infoLevel;
3356 smb_tran2QFileInfo_t qfi;
3364 fidp = smb_FindFID(vcp, fid, 0);
3367 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3371 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3372 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3373 smb_CloseFID(vcp, fidp, NULL, 0);
3374 smb_ReleaseFID(fidp);
3378 infoLevel = p->parmsp[1];
3379 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3380 responseSize = sizeof(qfi.u.QFbasicInfo);
3381 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3382 responseSize = sizeof(qfi.u.QFstandardInfo);
3383 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3384 responseSize = sizeof(qfi.u.QFeaInfo);
3385 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3386 responseSize = sizeof(qfi.u.QFfileNameInfo);
3388 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3389 p->opcode, infoLevel);
3390 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3391 smb_ReleaseFID(fidp);
3394 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3396 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3398 if (infoLevel > 0x100)
3399 outp->totalParms = 2;
3401 outp->totalParms = 0;
3402 outp->totalData = responseSize;
3404 userp = smb_GetTran2User(vcp, p);
3406 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3407 code = CM_ERROR_BADSMB;
3411 lock_ObtainMutex(&fidp->mx);
3412 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3414 osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3416 lock_ReleaseMutex(&fidp->mx);
3417 lock_ObtainWrite(&scp->rw);
3418 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3419 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3423 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3425 lock_ConvertWToR(&scp->rw);
3428 /* now we have the status in the cache entry, and everything is locked.
3429 * Marshall the output data.
3431 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3432 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3433 qfi.u.QFbasicInfo.creationTime = ft;
3434 qfi.u.QFbasicInfo.lastAccessTime = ft;
3435 qfi.u.QFbasicInfo.lastWriteTime = ft;
3436 qfi.u.QFbasicInfo.lastChangeTime = ft;
3437 attributes = smb_ExtAttributes(scp);
3438 qfi.u.QFbasicInfo.attributes = attributes;
3440 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3441 qfi.u.QFstandardInfo.allocationSize = scp->length;
3442 qfi.u.QFstandardInfo.endOfFile = scp->length;
3443 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3444 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3445 qfi.u.QFstandardInfo.directory =
3446 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3447 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3448 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3450 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3451 qfi.u.QFeaInfo.eaSize = 0;
3453 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3457 lock_ReleaseRead(&scp->rw);
3458 lock_ObtainMutex(&fidp->mx);
3459 lock_ObtainRead(&scp->rw);
3460 if (fidp->NTopen_wholepathp)
3461 name = fidp->NTopen_wholepathp;
3463 name = "\\"; /* probably can't happen */
3464 lock_ReleaseMutex(&fidp->mx);
3466 smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, 0);
3467 outp->totalData = len + 4; /* this is actually what we want to return */
3468 qfi.u.QFfileNameInfo.fileNameLength = len;
3471 /* send and free the packets */
3474 lock_ReleaseRead(&scp->rw);
3476 lock_ReleaseWrite(&scp->rw);
3477 cm_ReleaseSCache(scp);
3478 cm_ReleaseUser(userp);
3479 smb_ReleaseFID(fidp);
3481 memcpy(outp->datap, &qfi, responseSize);
3482 smb_SendTran2Packet(vcp, outp, opx);
3484 smb_SendTran2Error(vcp, p, opx, code);
3486 smb_FreeTran2Packet(outp);
3492 /* TRANS2_SET_FILE_INFORMATION */
3493 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3498 unsigned short infoLevel;
3499 smb_tran2Packet_t *outp;
3500 cm_user_t *userp = NULL;
3501 cm_scache_t *scp = NULL;
3507 fidp = smb_FindFID(vcp, fid, 0);
3510 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3514 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3515 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3516 smb_CloseFID(vcp, fidp, NULL, 0);
3517 smb_ReleaseFID(fidp);
3521 infoLevel = p->parmsp[1];
3522 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3523 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3524 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3525 p->opcode, infoLevel);
3526 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3527 smb_ReleaseFID(fidp);
3531 lock_ObtainMutex(&fidp->mx);
3532 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
3533 !(fidp->flags & SMB_FID_OPENDELETE)) {
3534 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3535 fidp, fidp->scp, fidp->flags);
3536 lock_ReleaseMutex(&fidp->mx);
3537 smb_ReleaseFID(fidp);
3538 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3541 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3542 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3543 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3544 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3545 fidp, fidp->scp, fidp->flags);
3546 lock_ReleaseMutex(&fidp->mx);
3547 smb_ReleaseFID(fidp);
3548 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3553 osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3555 lock_ReleaseMutex(&fidp->mx);
3557 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3559 outp->totalParms = 2;
3560 outp->totalData = 0;
3562 userp = smb_GetTran2User(vcp, p);
3564 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3565 code = CM_ERROR_BADSMB;
3569 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3571 unsigned int attribute;
3573 smb_tran2QFileInfo_t *sfi;
3575 sfi = (smb_tran2QFileInfo_t *)p->datap;
3577 /* lock the vnode with a callback; we need the current status
3578 * to determine what the new status is, in some cases.
3580 lock_ObtainWrite(&scp->rw);
3581 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3582 CM_SCACHESYNC_GETSTATUS
3583 | CM_SCACHESYNC_NEEDCALLBACK);
3585 lock_ReleaseWrite(&scp->rw);
3589 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3591 lock_ReleaseWrite(&scp->rw);
3592 lock_ObtainMutex(&fidp->mx);
3593 lock_ObtainRead(&scp->rw);
3595 /* prepare for setattr call */
3598 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3599 /* when called as result of move a b, lastMod is (-1, -1).
3600 * If the check for -1 is not present, timestamp
3601 * of the resulting file will be 1969 (-1)
3603 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3604 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3605 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3606 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3607 fidp->flags |= SMB_FID_MTIMESETDONE;
3610 attribute = sfi->u.QFbasicInfo.attributes;
3611 if (attribute != 0) {
3612 if ((scp->unixModeBits & 0222)
3613 && (attribute & SMB_ATTR_READONLY) != 0) {
3614 /* make a writable file read-only */
3615 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3616 attr.unixModeBits = scp->unixModeBits & ~0222;
3618 else if ((scp->unixModeBits & 0222) == 0
3619 && (attribute & SMB_ATTR_READONLY) == 0) {
3620 /* make a read-only file writable */
3621 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3622 attr.unixModeBits = scp->unixModeBits | 0222;
3625 lock_ReleaseRead(&scp->rw);
3626 lock_ReleaseMutex(&fidp->mx);
3630 code = cm_SetAttr(scp, &attr, userp, &req);
3634 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3635 int delflag = *((char *)(p->datap));
3636 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
3637 delflag, fidp, scp);
3638 if (*((char *)(p->datap))) { /* File is Deleted */
3639 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3642 lock_ObtainMutex(&fidp->mx);
3643 fidp->flags |= SMB_FID_DELONCLOSE;
3644 lock_ReleaseMutex(&fidp->mx);
3646 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
3652 lock_ObtainMutex(&fidp->mx);
3653 fidp->flags &= ~SMB_FID_DELONCLOSE;
3654 lock_ReleaseMutex(&fidp->mx);
3657 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3658 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3659 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3662 attr.mask = CM_ATTRMASK_LENGTH;
3663 attr.length.LowPart = size.LowPart;
3664 attr.length.HighPart = size.HighPart;
3665 code = cm_SetAttr(scp, &attr, userp, &req);
3669 cm_ReleaseSCache(scp);
3670 cm_ReleaseUser(userp);
3671 smb_ReleaseFID(fidp);
3673 smb_SendTran2Packet(vcp, outp, opx);
3675 smb_SendTran2Error(vcp, p, opx, code);
3676 smb_FreeTran2Packet(outp);
3683 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3685 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3686 return CM_ERROR_BADOP;
3691 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3693 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3694 return CM_ERROR_BADOP;
3697 /* TRANS2_FIND_NOTIFY_FIRST */
3699 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3701 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3702 return CM_ERROR_BADOP;
3705 /* TRANS2_FIND_NOTIFY_NEXT */
3707 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3709 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3710 return CM_ERROR_BADOP;
3713 /* TRANS2_CREATE_DIRECTORY */
3715 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3717 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3718 return CM_ERROR_BADOP;
3721 /* TRANS2_SESSION_SETUP */
3723 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3725 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3726 return CM_ERROR_BADOP;
3729 struct smb_v2_referral {
3731 USHORT ReferralFlags;
3734 USHORT DfsPathOffset;
3735 USHORT DfsAlternativePathOffset;
3736 USHORT NetworkAddressOffset;
3739 /* TRANS2_GET_DFS_REFERRAL */
3741 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3743 /* This is a UNICODE only request (bit15 of Flags2) */
3744 /* The TID must be IPC$ */
3746 /* The documentation for the Flags response field is contradictory */
3748 /* Use Version 1 Referral Element Format */
3749 /* ServerType = 0; indicates the next server should be queried for the file */
3750 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3751 /* Node = UnicodeString of UNC path of the next share name */
3754 int maxReferralLevel = 0;
3755 char requestFileName[1024] = "";
3756 char referralPath[1024] = "";
3757 smb_tran2Packet_t *outp = 0;
3758 cm_user_t *userp = 0;
3759 cm_scache_t *scp = 0;
3760 cm_scache_t *dscp = 0;
3762 CPINFO CodePageInfo;
3763 int i, nbnLen, reqLen, refLen;
3768 maxReferralLevel = p->parmsp[0];
3770 GetCPInfo(CP_ACP, &CodePageInfo);
3771 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
3772 requestFileName, 1024, NULL, NULL);
3774 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
3775 maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3777 nbnLen = (int)strlen(cm_NetbiosName);
3778 reqLen = (int)strlen(requestFileName);
3780 if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
3781 !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3782 requestFileName[nbnLen+1] == '\\')
3786 if (!_strnicmp("all",&requestFileName[nbnLen+2],3) ||
3787 !_strnicmp("*.",&requestFileName[nbnLen+2],2))
3790 strcpy(referralPath, requestFileName);
3793 userp = smb_GetTran2User(vcp, p);
3795 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3796 code = CM_ERROR_BADSMB;
3801 * We have a requested path. Check to see if it is something
3804 * But be careful because the name that we might be searching
3805 * for might be a known name with the final character stripped
3808 code = cm_NameI(cm_data.rootSCachep, &requestFileName[nbnLen+2],
3809 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
3810 userp, NULL, &req, &scp);
3814 strcpy(referralPath, requestFileName);
3816 } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
3818 char pathName[1024];
3819 char *lastComponent;
3821 * we have a msdfs link somewhere in the path
3822 * we should figure out where in the path the link is.
3825 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%s]", requestFileName);
3827 strcpy(temp, &requestFileName[nbnLen+2]);
3831 cm_ReleaseSCache(dscp);
3835 cm_ReleaseSCache(scp);
3838 smb_StripLastComponent(pathName, &lastComponent, temp);
3840 code = cm_NameI(cm_data.rootSCachep, pathName,
3841 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3842 userp, NULL, &req, &dscp);
3844 code = cm_NameI(dscp, ++lastComponent,
3846 userp, NULL, &req, &scp);
3847 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK)
3850 } while (code == CM_ERROR_PATH_NOT_COVERED);
3852 /* scp should now be the DfsLink we are looking for */
3854 /* figure out how much of the input path was used */
3855 reqLen = (int)(nbnLen+2 + strlen(pathName) + 1 + strlen(lastComponent));
3857 strcpy(referralPath, &scp->mountPointStringp[strlen("msdfs:")]);
3858 refLen = (int)strlen(referralPath);
3862 char shareName[MAX_PATH + 1];
3864 /* we may have a sharename that is a volume reference */
3866 for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
3872 if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
3873 code = cm_NameI(cm_data.rootSCachep, "",
3874 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
3875 userp, p, &req, &scp);
3880 strcpy(referralPath, requestFileName);
3890 struct smb_v2_referral * v2ref;
3891 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (refLen + 8));
3893 sp = (USHORT *)outp->datap;
3895 sp[idx++] = reqLen; /* path consumed */
3896 sp[idx++] = 1; /* number of referrals */
3897 sp[idx++] = 0x03; /* flags */
3898 #ifdef DFS_VERSION_1
3899 sp[idx++] = 1; /* Version Number */
3900 sp[idx++] = refLen + 4; /* Referral Size */
3901 sp[idx++] = 1; /* Type = SMB Server */
3902 sp[idx++] = 0; /* Do not strip path consumed */
3903 for ( i=0;i<=refLen; i++ )
3904 sp[i+idx] = referralPath[i];
3905 #else /* DFS_VERSION_2 */
3906 sp[idx++] = 2; /* Version Number */
3907 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3908 idx += (sizeof(struct smb_v2_referral) / 2);
3909 v2ref = (struct smb_v2_referral *) &sp[5];
3910 v2ref->ServerType = 1; /* SMB Server */
3911 v2ref->ReferralFlags = 0x03;
3912 v2ref->Proximity = 0; /* closest */
3913 v2ref->TimeToLive = 3600; /* seconds */
3914 v2ref->DfsPathOffset = idx * 2;
3915 v2ref->DfsAlternativePathOffset = idx * 2;
3916 v2ref->NetworkAddressOffset = 0;
3917 for ( i=0;i<=refLen; i++ )
3918 sp[i+idx] = referralPath[i];
3922 code = CM_ERROR_NOSUCHPATH;
3927 cm_ReleaseSCache(dscp);
3929 cm_ReleaseSCache(scp);
3931 cm_ReleaseUser(userp);
3933 smb_SendTran2Packet(vcp, outp, op);
3935 smb_SendTran2Error(vcp, p, op, code);
3937 smb_FreeTran2Packet(outp);
3940 #else /* DFS_SUPPORT */
3941 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3942 return CM_ERROR_NOSUCHDEVICE;
3943 #endif /* DFS_SUPPORT */
3946 /* TRANS2_REPORT_DFS_INCONSISTENCY */
3948 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3950 /* This is a UNICODE only request (bit15 of Flags2) */
3952 /* There is nothing we can do about this operation. The client is going to
3953 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3954 * Unfortunately, there is really nothing we can do about it other then log it
3955 * somewhere. Even then I don't think there is anything for us to do.
3956 * So let's return an error value.
3959 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3960 return CM_ERROR_BADOP;
3964 smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
3965 char * tidPathp, char * relPathp,
3966 int infoLevel, cm_user_t *userp,
3971 cm_scache_t *targetScp; /* target if scp is a symlink */
3974 unsigned short attr;
3975 unsigned long lattr;
3976 smb_dirListPatch_t *patchp;
3977 smb_dirListPatch_t *npatchp;
3979 afs_int32 mustFake = 0;
3980 char path[AFSPATHMAX];
3982 code = cm_FindACLCache(dscp, userp, &rights);
3983 if (code == 0 && !(rights & PRSFS_READ))
3985 else if (code == -1) {
3986 lock_ObtainWrite(&dscp->rw);
3987 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
3988 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3989 lock_ReleaseWrite(&dscp->rw);
3990 if (code == CM_ERROR_NOACCESS) {
3998 for(patchp = *dirPatchespp; patchp; patchp =
3999 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4000 snprintf(path, AFSPATHMAX, "%s\\%s", relPathp ? relPathp : "", patchp->dep->name);
4001 reqp->relPathp = path;
4002 reqp->tidPathp = tidPathp;
4004 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4005 reqp->relPathp = reqp->tidPathp = NULL;
4009 lock_ObtainWrite(&scp->rw);
4011 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
4012 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4013 if (mustFake || code) {
4014 lock_ReleaseWrite(&scp->rw);
4016 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4017 errors in the client. */
4018 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4019 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4021 /* 1969-12-31 23:59:59 +00 */
4022 ft.dwHighDateTime = 0x19DB200;
4023 ft.dwLowDateTime = 0x5BB78980;
4025 /* copy to Creation Time */
4026 fa->creationTime = ft;
4027 fa->lastAccessTime = ft;
4028 fa->lastWriteTime = ft;
4029 fa->lastChangeTime = ft;
4031 switch (scp->fileType) {
4032 case CM_SCACHETYPE_DIRECTORY:
4033 case CM_SCACHETYPE_MOUNTPOINT:
4034 case CM_SCACHETYPE_SYMLINK:
4035 case CM_SCACHETYPE_INVALID:
4036 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4039 /* if we get here we either have a normal file
4040 * or we have a file for which we have never
4041 * received status info. In this case, we can
4042 * check the even/odd value of the entry's vnode.
4043 * even means it is to be treated as a directory
4044 * and odd means it is to be treated as a file.
4046 if (mustFake && (scp->fid.vnode & 0x1))
4047 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4049 fa->extFileAttributes = SMB_ATTR_NORMAL;
4052 /* merge in hidden attribute */
4053 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4054 fa->extFileAttributes |= SMB_ATTR_HIDDEN;
4057 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4059 /* 1969-12-31 23:59:58 +00*/
4060 dosTime = 0xEBBFBF7D;
4062 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4063 fa->lastAccessDateTime = fa->creationDateTime;
4064 fa->lastWriteDateTime = fa->creationDateTime;
4066 /* set the attribute */
4067 switch (scp->fileType) {
4068 case CM_SCACHETYPE_DIRECTORY:
4069 case CM_SCACHETYPE_MOUNTPOINT:
4070 case CM_SCACHETYPE_SYMLINK:
4071 case CM_SCACHETYPE_INVALID:
4072 fa->attributes = SMB_ATTR_DIRECTORY;
4074 fa->attributes = SMB_ATTR_NORMAL;
4076 /* merge in hidden (dot file) attribute */
4077 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4078 fa->attributes |= SMB_ATTR_HIDDEN;
4082 cm_ReleaseSCache(scp);
4086 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4088 /* now watch for a symlink */
4090 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
4091 lock_ReleaseWrite(&scp->rw);
4092 snprintf(path, AFSPATHMAX, "%s\\%s", relPathp ? relPathp : "", patchp->dep->name);
4093 reqp->relPathp = path;
4094 reqp->tidPathp = tidPathp;
4095 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
4096 reqp->relPathp = reqp->tidPathp = NULL;
4098 /* we have a more accurate file to use (the
4099 * target of the symbolic link). Otherwise,
4100 * we'll just use the symlink anyway.
4102 osi_Log2(smb_logp, "symlink vp %x to vp %x",
4104 cm_ReleaseSCache(scp);
4107 lock_ObtainWrite(&scp->rw);
4110 lock_ConvertWToR(&scp->rw);
4112 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4113 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4116 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4118 fa->creationTime = ft;
4119 fa->lastAccessTime = ft;
4120 fa->lastWriteTime = ft;
4121 fa->lastChangeTime = ft;
4123 /* Use length for both file length and alloc length */
4124 fa->endOfFile = scp->length;
4125 fa->allocationSize = scp->length;
4127 /* Copy attributes */
4128 lattr = smb_ExtAttributes(scp);
4129 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK ||
4130 code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4131 if (lattr == SMB_ATTR_NORMAL)
4132 lattr = SMB_ATTR_DIRECTORY;
4134 lattr |= SMB_ATTR_DIRECTORY;
4136 /* merge in hidden (dot file) attribute */
4137 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4138 if (lattr == SMB_ATTR_NORMAL)
4139 lattr = SMB_ATTR_HIDDEN;
4141 lattr |= SMB_ATTR_HIDDEN;
4144 fa->extFileAttributes = lattr;
4146 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4149 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4151 fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
4152 fa->lastAccessDateTime = fa->creationDateTime;
4153 fa->lastWriteDateTime = fa->creationDateTime;
4155 /* copy out file length and alloc length,
4156 * using the same for both
4158 fa->dataSize = scp->length.LowPart;
4159 fa->allocationSize = scp->length.LowPart;
4161 /* finally copy out attributes as short */
4162 attr = smb_Attributes(scp);
4163 /* merge in hidden (dot file) attribute */
4164 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4165 if (lattr == SMB_ATTR_NORMAL)
4166 lattr = SMB_ATTR_HIDDEN;
4168 lattr |= SMB_ATTR_HIDDEN;
4170 fa->attributes = attr;
4173 lock_ReleaseRead(&scp->rw);
4174 cm_ReleaseSCache(scp);
4177 /* now free the patches */
4178 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4179 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4183 /* and mark the list as empty */
4184 *dirPatchespp = NULL;
4189 // char table for case insensitive comparison
4190 char mapCaseTable[256];
4192 VOID initUpperCaseTable(VOID)
4195 for (i = 0; i < 256; ++i)
4196 mapCaseTable[i] = toupper(i);
4197 // make '"' match '.'
4198 mapCaseTable[(int)'"'] = toupper('.');
4199 // make '<' match '*'
4200 mapCaseTable[(int)'<'] = toupper('*');
4201 // make '>' match '?'
4202 mapCaseTable[(int)'>'] = toupper('?');
4205 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
4207 // Note : this procedure works recursively calling itself.
4209 // PSZ pattern : string containing metacharacters.
4210 // PSZ name : file name to be compared with 'pattern'.
4212 // BOOL : TRUE/FALSE (match/mistmatch)
4215 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
4217 PSZ pename; // points to the last 'name' character
4219 pename = name + strlen(name) - 1;
4230 if (*pattern == '\0')
4232 for (p = pename; p >= name; --p) {
4233 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
4234 !casefold && (*p == *pattern)) &&
4235 szWildCardMatchFileName(pattern + 1, p + 1, casefold))
4240 if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
4241 (!casefold && *name != *pattern))
4248 /* if all we have left are wildcards, then we match */
4249 for (;*pattern; pattern++) {
4250 if (*pattern != '*' && *pattern != '?')
4256 /* do a case-folding search of the star name mask with the name in namep.
4257 * Return 1 if we match, otherwise 0.
4259 int smb_V3MatchMask(char *namep, char *maskp, int flags)
4262 int i, j, star, qmark, casefold, retval;
4264 /* make sure we only match 8.3 names, if requested */
4265 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
4268 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
4270 /* optimize the pattern:
4271 * if there is a mixture of '?' and '*',
4272 * for example the sequence "*?*?*?*"
4273 * must be turned into the form "*"
4275 newmask = (char *)malloc(strlen(maskp)+1);
4276 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
4277 switch ( maskp[i] ) {
4289 } else if ( qmark ) {
4293 newmask[j++] = maskp[i];
4300 } else if ( qmark ) {
4304 newmask[j++] = '\0';
4306 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
4313 /* smb_ReceiveTran2SearchDir implements both
4314 * Tran2_Find_First and Tran2_Find_Next
4316 #define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
4317 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
4318 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
4319 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
4320 #define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
4322 /* this is an optimized handler for T2SearchDir that handles the case
4323 where there are no wildcards in the search path. I.e. an
4324 application is using FindFirst(Ex) to get information about a
4325 single file or directory. It will attempt to do a single lookup.
4326 If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4327 the usual mechanism.
4329 This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4331 TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
4333 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4337 long code = 0, code2 = 0;
4340 smb_dirListPatch_t *dirListPatchesp;
4341 smb_dirListPatch_t *curPatchp;
4342 size_t orbytes; /* # of bytes in this output record */
4343 size_t ohbytes; /* # of bytes, except file name */
4344 size_t onbytes; /* # of bytes in name, incl. term. null */
4345 cm_scache_t *scp = NULL;
4346 cm_scache_t *targetscp = NULL;
4347 cm_user_t *userp = NULL;
4348 char *op; /* output data ptr */
4349 char *origOp; /* original value of op */
4350 cm_space_t *spacep; /* for pathname buffer */
4351 unsigned long maxReturnData; /* max # of return data */
4352 long maxReturnParms; /* max # of return parms */
4353 long bytesInBuffer; /* # data bytes in the output buffer */
4354 char *maskp; /* mask part of path */
4358 smb_tran2Packet_t *outp; /* response packet */
4361 char shortName[13]; /* 8.3 name if needed */
4364 cm_dirEntry_t * dep = NULL;
4367 void * attrp = NULL;
4368 smb_tran2Find_t * fp;
4373 osi_assertx(p->opcode == 1, "invalid opcode");
4375 /* find first; obtain basic parameters from request */
4377 /* note that since we are going to failover to regular
4378 * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4379 * modify any of the input parameters here. */
4380 attribute = p->parmsp[0];
4381 maxCount = p->parmsp[1];
4382 infoLevel = p->parmsp[3];
4383 searchFlags = p->parmsp[2];
4384 pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4386 maskp = strrchr(pathp, '\\');
4390 maskp++; /* skip over backslash */
4391 /* track if this is likely to match a lot of entries */
4393 osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%s], mask[%s]",
4394 osi_LogSaveString(smb_logp, pathp),
4395 osi_LogSaveString(smb_logp, maskp));
4397 switch ( infoLevel ) {
4398 case SMB_INFO_STANDARD:
4400 ohbytes = sizeof(fp->u.FstandardInfo);
4403 case SMB_INFO_QUERY_EA_SIZE:
4404 ohbytes = sizeof(fp->u.FeaSizeInfo);
4405 s = "InfoQueryEaSize";
4408 case SMB_INFO_QUERY_EAS_FROM_LIST:
4409 ohbytes = sizeof(fp->u.FeasFromListInfo);
4410 s = "InfoQueryEasFromList";
4413 case SMB_FIND_FILE_DIRECTORY_INFO:
4414 s = "FindFileDirectoryInfo";
4415 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4418 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4419 s = "FindFileFullDirectoryInfo";
4420 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4423 case SMB_FIND_FILE_NAMES_INFO:
4424 s = "FindFileNamesInfo";
4425 ohbytes = sizeof(fp->u.FfileNamesInfo);
4428 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4429 s = "FindFileBothDirectoryInfo";
4430 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4434 s = "unknownInfoLevel";
4438 osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
4441 "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4442 attribute, infoLevel, maxCount, searchFlags);
4445 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4446 return CM_ERROR_INVAL;
4449 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4450 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4452 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4455 dirListPatchesp = NULL;
4457 maxReturnData = p->maxReturnData;
4458 maxReturnParms = 10; /* return params for findfirst, which
4459 is the only one we handle.*/
4461 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4462 if (maxReturnData > 6000)
4463 maxReturnData = 6000;
4464 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4466 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4469 osi_Log2(smb_logp, "T2SDSingle search dir count %d [%s]",
4470 maxCount, osi_LogSaveString(smb_logp, pathp));
4472 /* bail out if request looks bad */
4474 smb_FreeTran2Packet(outp);
4475 return CM_ERROR_BADSMB;
4478 userp = smb_GetTran2User(vcp, p);
4480 osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
4481 smb_FreeTran2Packet(outp);
4482 return CM_ERROR_BADSMB;
4485 /* try to get the vnode for the path name next */
4486 spacep = cm_GetSpace();
4487 smb_StripLastComponent(spacep->data, NULL, pathp);
4488 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4490 cm_ReleaseUser(userp);
4491 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4492 smb_FreeTran2Packet(outp);
4496 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4497 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4498 userp, tidPathp, &req, &scp);
4499 cm_FreeSpace(spacep);
4502 cm_ReleaseUser(userp);
4503 smb_SendTran2Error(vcp, p, opx, code);
4504 smb_FreeTran2Packet(outp);
4508 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4509 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4510 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
4511 cm_ReleaseSCache(scp);
4512 cm_ReleaseUser(userp);
4513 if ( WANTS_DFS_PATHNAMES(p) || pnc )
4514 code = CM_ERROR_PATH_NOT_COVERED;
4516 code = CM_ERROR_BADSHARENAME;
4517 smb_SendTran2Error(vcp, p, opx, code);
4518 smb_FreeTran2Packet(outp);
4521 #endif /* DFS_SUPPORT */
4522 osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
4524 /* now do a single case sensitive lookup for the file in question */
4525 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
4527 /* if a case sensitive match failed, we try a case insensitive one
4529 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
4530 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
4533 if (code == 0 && targetscp->fid.vnode == 0) {
4534 cm_ReleaseSCache(targetscp);
4535 code = CM_ERROR_NOSUCHFILE;
4539 /* if we can't find the directory entry, this block will
4540 return CM_ERROR_NOSUCHFILE, which we will pass on to
4541 smb_ReceiveTran2SearchDir(). */
4542 cm_ReleaseSCache(scp);
4543 cm_ReleaseUser(userp);
4544 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4545 smb_SendTran2Error(vcp, p, opx, code);
4548 smb_FreeTran2Packet(outp);
4552 /* now that we have the target in sight, we proceed with filling
4553 up the return data. */
4555 op = origOp = outp->datap;
4558 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4559 /* skip over resume key */
4563 fp = (smb_tran2Find_t *) op;
4565 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4566 && targetscp->fid.vnode != 0
4567 && !cm_Is8Dot3(maskp)) {
4570 dfid.vnode = htonl(targetscp->fid.vnode);
4571 dfid.unique = htonl(targetscp->fid.unique);
4573 cm_Gen8Dot3NameInt(maskp, &dfid, shortName, &shortNameEnd);
4579 osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %s (%s)",
4580 htonl(targetscp->fid.vnode),
4581 htonl(targetscp->fid.unique),
4582 osi_LogSaveString(smb_logp, pathp),
4583 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4585 /* Eliminate entries that don't match requested attributes */
4586 if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
4587 smb_IsDotFile(maskp)) {
4589 code = CM_ERROR_NOSUCHFILE;
4590 osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
4595 if (!(attribute & SMB_ATTR_DIRECTORY) &&
4596 (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
4597 targetscp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4598 targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
4599 targetscp->fileType == CM_SCACHETYPE_INVALID)) {
4601 code = CM_ERROR_NOSUCHFILE;
4602 osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
4607 /* add header to name & term. null */
4609 smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH);
4610 orbytes = ohbytes + onbytes;
4612 /* now, we round up the record to a 4 byte alignment, and we make
4613 * sure that we have enough room here for even the aligned version
4614 * (so we don't have to worry about an * overflow when we pad
4615 * things out below). That's the reason for the alignment
4618 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4619 align = (4 - (orbytes & 3)) & 3;
4623 if (orbytes + align > maxReturnData) {
4625 /* even though this request is unlikely to succeed with a
4626 failover, we do it anyway. */
4627 code = CM_ERROR_NOSUCHFILE;
4628 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4633 /* this is one of the entries to use: it is not deleted and it
4634 * matches the star pattern we're looking for. Put out the name,
4635 * preceded by its length.
4637 /* First zero everything else */
4638 memset(origOp, 0, orbytes);
4641 smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH);
4643 switch (infoLevel) {
4644 case SMB_INFO_STANDARD:
4645 fp->u.FstandardInfo.fileNameLength = onbytes;
4646 attrp = &fp->u.FstandardInfo.fileAttrs;
4649 case SMB_INFO_QUERY_EA_SIZE:
4650 fp->u.FeaSizeInfo.fileNameLength = onbytes;
4651 attrp = &fp->u.FeaSizeInfo.fileAttrs;
4652 fp->u.FeaSizeInfo.eaSize = 0;
4655 case SMB_INFO_QUERY_EAS_FROM_LIST:
4656 fp->u.FeasFromListInfo.fileNameLength = onbytes;
4657 attrp = &fp->u.FeasFromListInfo.fileAttrs;
4658 fp->u.FeasFromListInfo.eaSize = 0;
4661 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4662 if (NeedShortName) {
4666 nchars = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS,
4668 fp->u.FfileBothDirectoryInfo.shortName,
4669 sizeof(fp->u.FfileBothDirectoryInfo.shortName) / sizeof(wchar_t));
4671 fp->u.FfileBothDirectoryInfo.shortNameLength = (nchars - 1)*sizeof(wchar_t);
4673 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
4674 fp->u.FfileBothDirectoryInfo.reserved = 0;
4676 strcpy(fp->u.FfileBothDirectoryInfo.shortName,
4678 fp->u.FfileBothDirectoryInfo.shortNameLength = strlen(shortName);
4683 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4684 fp->u.FfileFullDirectoryInfo.eaSize = 0;
4687 case SMB_FIND_FILE_DIRECTORY_INFO:
4688 fp->u.FfileDirectoryInfo.nextEntryOffset = 0;
4689 fp->u.FfileDirectoryInfo.fileIndex = 0;
4690 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
4691 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
4694 case SMB_FIND_FILE_NAMES_INFO:
4695 fp->u.FfileNamesInfo.nextEntryOffset = 0;
4696 fp->u.FfileNamesInfo.fileIndex = 0;
4697 fp->u.FfileNamesInfo.fileNameLength = onbytes;
4701 /* we shouldn't hit this case */
4702 osi_assertx(FALSE, "Unknown query type");
4705 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4706 osi_assert(attrp != NULL);
4708 curPatchp = malloc(sizeof(*curPatchp));
4709 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4711 curPatchp->dptr = attrp;
4713 if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
4714 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4716 curPatchp->flags = 0;
4719 cm_SetFid(&curPatchp->fid, targetscp->fid.cell, targetscp->fid.volume, targetscp->fid.vnode, targetscp->fid.unique);
4722 dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+strlen(maskp));
4723 strcpy(dep->name, maskp);
4724 dep->fid.vnode = targetscp->fid.vnode;
4725 dep->fid.unique = targetscp->fid.unique;
4726 curPatchp->dep = dep;
4729 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4730 /* put out resume key */
4731 *((u_long *)origOp) = 0;
4734 /* Adjust byte ptr and count */
4735 origOp += orbytes; /* skip entire record */
4736 bytesInBuffer += orbytes;
4738 /* and pad the record out */
4739 while (--align >= 0) {
4744 /* apply the patches */
4745 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->data, infoLevel, userp, &req);
4747 outp->parmsp[0] = 0;
4748 outp->parmsp[1] = 1; /* number of names returned */
4749 outp->parmsp[2] = 1; /* end of search */
4750 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4751 outp->parmsp[4] = 0;
4753 outp->totalParms = 10; /* in bytes */
4755 outp->totalData = bytesInBuffer;
4757 osi_Log0(smb_logp, "T2SDSingle done.");
4759 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4761 smb_SendTran2Error(vcp, p, opx, code);
4763 smb_SendTran2Packet(vcp, outp, opx);
4768 smb_FreeTran2Packet(outp);
4772 cm_ReleaseSCache(scp);
4773 cm_ReleaseSCache(targetscp);
4774 cm_ReleaseUser(userp);
4780 /* TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2 */
4781 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4786 long code = 0, code2 = 0;
4788 cm_dirEntry_t *dep = 0;
4790 smb_dirListPatch_t *dirListPatchesp = 0;
4791 smb_dirListPatch_t *curPatchp = 0;
4794 size_t orbytes; /* # of bytes in this output record */
4795 size_t ohbytes; /* # of bytes, except file name */
4796 size_t onbytes; /* # of bytes in name, incl. term. null */
4797 osi_hyper_t dirLength;
4798 osi_hyper_t bufferOffset;
4799 osi_hyper_t curOffset;
4801 smb_dirSearch_t *dsp;
4805 cm_pageHeader_t *pageHeaderp;
4806 cm_user_t *userp = NULL;
4809 long nextEntryCookie;
4810 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4811 char *op; /* output data ptr */
4812 char *origOp; /* original value of op */
4813 cm_space_t *spacep; /* for pathname buffer */
4814 unsigned long maxReturnData; /* max # of return data */
4815 unsigned long maxReturnParms; /* max # of return parms */
4816 long bytesInBuffer; /* # data bytes in the output buffer */
4818 char *maskp; /* mask part of path */
4822 smb_tran2Packet_t *outp; /* response packet */
4825 char shortName[13]; /* 8.3 name if needed */
4834 smb_tran2Find_t * fp;
4839 if (p->opcode == 1) {
4840 /* find first; obtain basic parameters from request */
4841 attribute = p->parmsp[0];
4842 maxCount = p->parmsp[1];
4843 infoLevel = p->parmsp[3];
4844 searchFlags = p->parmsp[2];
4845 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4847 maskp = strrchr(pathp, '\\');
4851 maskp++; /* skip over backslash */
4853 /* track if this is likely to match a lot of entries */
4854 starPattern = smb_V3IsStarMask(maskp);
4856 #ifndef NOFINDFIRSTOPTIMIZE
4858 /* if this is for a single directory or file, we let the
4859 optimized routine handle it. The only error it
4860 returns is CM_ERROR_NOSUCHFILE. The */
4861 code = smb_T2SearchDirSingle(vcp, p, opx);
4863 /* we only failover if we see a CM_ERROR_NOSUCHFILE */
4864 if (code != CM_ERROR_NOSUCHFILE) {
4866 /* unless we are using the BPlusTree */
4867 if (code == CM_ERROR_BPLUS_NOMATCH)
4868 code = CM_ERROR_NOSUCHFILE;
4869 #endif /* USE_BPLUS */
4873 #endif /* NOFINDFIRSTOPTIMIZE */
4876 dsp = smb_NewDirSearch(1);
4877 dsp->attribute = attribute;
4878 strcpy(dsp->mask, maskp); /* and save mask */
4881 osi_assertx(p->opcode == 2, "invalid opcode");
4882 /* find next; obtain basic parameters from request or open dir file */
4883 dsp = smb_FindDirSearch(p->parmsp[0]);
4884 maxCount = p->parmsp[1];
4885 infoLevel = p->parmsp[2];
4886 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4887 searchFlags = p->parmsp[5];
4889 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4890 p->parmsp[0], nextCookie);
4891 return CM_ERROR_BADFD;
4893 attribute = dsp->attribute;
4896 starPattern = 1; /* assume, since required a Find Next */
4899 switch ( infoLevel ) {
4900 case SMB_INFO_STANDARD:
4902 ohbytes = sizeof(fp->u.FstandardInfo);
4905 case SMB_INFO_QUERY_EA_SIZE:
4906 ohbytes = sizeof(fp->u.FeaSizeInfo);
4907 s = "InfoQueryEaSize";
4910 case SMB_INFO_QUERY_EAS_FROM_LIST:
4911 ohbytes = sizeof(fp->u.FeasFromListInfo);
4912 s = "InfoQueryEasFromList";
4915 case SMB_FIND_FILE_DIRECTORY_INFO:
4916 s = "FindFileDirectoryInfo";
4917 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4920 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4921 s = "FindFileFullDirectoryInfo";
4922 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4925 case SMB_FIND_FILE_NAMES_INFO:
4926 s = "FindFileNamesInfo";
4927 ohbytes = sizeof(fp->u.FfileNamesInfo);
4930 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4931 s = "FindFileBothDirectoryInfo";
4932 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4936 s = "unknownInfoLevel";
4940 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
4943 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4944 attribute, infoLevel, maxCount, searchFlags);
4946 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
4947 p->opcode, dsp->cookie, nextCookie);
4950 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4951 smb_ReleaseDirSearch(dsp);
4952 return CM_ERROR_INVAL;
4955 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4956 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4958 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4961 dirListPatchesp = NULL;
4963 maxReturnData = p->maxReturnData;
4964 if (p->opcode == 1) /* find first */
4965 maxReturnParms = 10; /* bytes */
4967 maxReturnParms = 8; /* bytes */
4969 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4970 if (maxReturnData > 6000)
4971 maxReturnData = 6000;
4972 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4974 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4977 osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
4978 maxCount, osi_LogSaveString(smb_logp, pathp));
4980 /* bail out if request looks bad */
4981 if (p->opcode == 1 && !pathp) {
4982 smb_ReleaseDirSearch(dsp);
4983 smb_FreeTran2Packet(outp);
4984 return CM_ERROR_BADSMB;
4987 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
4988 dsp->cookie, nextCookie, attribute);
4990 userp = smb_GetTran2User(vcp, p);
4992 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
4993 smb_ReleaseDirSearch(dsp);
4994 smb_FreeTran2Packet(outp);
4995 return CM_ERROR_BADSMB;
4998 /* try to get the vnode for the path name next */
4999 lock_ObtainMutex(&dsp->mx);
5002 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5006 spacep = cm_GetSpace();
5007 smb_StripLastComponent(spacep->data, NULL, pathp);
5008 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
5010 cm_ReleaseUser(userp);
5011 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
5012 smb_FreeTran2Packet(outp);
5013 lock_ReleaseMutex(&dsp->mx);
5014 smb_DeleteDirSearch(dsp);
5015 smb_ReleaseDirSearch(dsp);
5019 strcpy(dsp->tidPath, tidPathp ? tidPathp : "/");
5020 strcpy(dsp->relPath, spacep->data);
5022 code = cm_NameI(cm_data.rootSCachep, spacep->data,
5023 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5024 userp, tidPathp, &req, &scp);
5025 cm_FreeSpace(spacep);
5028 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
5029 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5030 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
5031 cm_ReleaseSCache(scp);
5032 cm_ReleaseUser(userp);
5033 if ( WANTS_DFS_PATHNAMES(p) || pnc )
5034 code = CM_ERROR_PATH_NOT_COVERED;
5036 code = CM_ERROR_BADSHARENAME;
5037 smb_SendTran2Error(vcp, p, opx, code);
5038 smb_FreeTran2Packet(outp);
5039 lock_ReleaseMutex(&dsp->mx);
5040 smb_DeleteDirSearch(dsp);
5041 smb_ReleaseDirSearch(dsp);
5044 #endif /* DFS_SUPPORT */
5046 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5047 /* we need one hold for the entry we just stored into,
5048 * and one for our own processing. When we're done
5049 * with this function, we'll drop the one for our own
5050 * processing. We held it once from the namei call,
5051 * and so we do another hold now.
5054 lock_ObtainWrite(&scp->rw);
5055 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
5056 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
5057 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
5058 dsp->flags |= SMB_DIRSEARCH_BULKST;
5060 lock_ReleaseWrite(&scp->rw);
5063 lock_ReleaseMutex(&dsp->mx);
5065 cm_ReleaseUser(userp);
5066 smb_FreeTran2Packet(outp);
5067 smb_DeleteDirSearch(dsp);
5068 smb_ReleaseDirSearch(dsp);
5072 /* get the directory size */
5073 lock_ObtainWrite(&scp->rw);
5074 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5075 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5077 lock_ReleaseWrite(&scp->rw);
5078 cm_ReleaseSCache(scp);
5079 cm_ReleaseUser(userp);
5080 smb_FreeTran2Packet(outp);
5081 smb_DeleteDirSearch(dsp);
5082 smb_ReleaseDirSearch(dsp);
5086 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5089 dirLength = scp->length;
5091 bufferOffset.LowPart = bufferOffset.HighPart = 0;
5092 curOffset.HighPart = 0;
5093 curOffset.LowPart = nextCookie;
5094 origOp = outp->datap;
5102 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5103 /* skip over resume key */
5106 fp = (smb_tran2Find_t *) op;
5108 /* make sure that curOffset.LowPart doesn't point to the first
5109 * 32 bytes in the 2nd through last dir page, and that it doesn't
5110 * point at the first 13 32-byte chunks in the first dir page,
5111 * since those are dir and page headers, and don't contain useful
5114 temp = curOffset.LowPart & (2048-1);
5115 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5116 /* we're in the first page */
5117 if (temp < 13*32) temp = 13*32;
5120 /* we're in a later dir page */
5121 if (temp < 32) temp = 32;
5124 /* make sure the low order 5 bits are zero */
5127 /* now put temp bits back ito curOffset.LowPart */
5128 curOffset.LowPart &= ~(2048-1);
5129 curOffset.LowPart |= temp;
5131 /* check if we've passed the dir's EOF */
5132 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
5133 osi_Log0(smb_logp, "T2 search dir passed eof");
5138 /* check if we've returned all the names that will fit in the
5139 * response packet; we check return count as well as the number
5140 * of bytes requested. We check the # of bytes after we find
5141 * the dir entry, since we'll need to check its size.
5143 if (returnedNames >= maxCount) {
5144 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
5145 returnedNames, maxCount);
5149 /* see if we can use the bufferp we have now; compute in which
5150 * page the current offset would be, and check whether that's
5151 * the offset of the buffer we have. If not, get the buffer.
5153 thyper.HighPart = curOffset.HighPart;
5154 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5155 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5158 buf_Release(bufferp);
5161 lock_ReleaseWrite(&scp->rw);
5162 code = buf_Get(scp, &thyper, &bufferp);
5163 lock_ObtainMutex(&dsp->mx);
5165 /* now, if we're doing a star match, do bulk fetching
5166 * of all of the status info for files in the dir.
5169 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, infoLevel, userp, &req);
5171 lock_ObtainWrite(&scp->rw);
5172 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
5173 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
5174 /* Don't bulk stat if risking timeout */
5175 DWORD now = GetTickCount();
5176 if (now - req.startTime > RDRtimeout * 1000) {
5177 scp->bulkStatProgress = thyper;
5178 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
5179 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
5181 code = cm_TryBulkStat(scp, &thyper, userp, &req);
5184 lock_ObtainWrite(&scp->rw);
5186 lock_ReleaseMutex(&dsp->mx);
5188 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
5192 bufferOffset = thyper;
5194 /* now get the data in the cache */
5196 code = cm_SyncOp(scp, bufferp, userp, &req,
5198 CM_SCACHESYNC_NEEDCALLBACK
5199 | CM_SCACHESYNC_READ);
5201 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5205 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5207 if (cm_HaveBuffer(scp, bufferp, 0)) {
5208 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5212 /* otherwise, load the buffer and try again */
5213 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5216 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5217 scp, bufferp, code);
5222 buf_Release(bufferp);
5226 } /* if (wrong buffer) ... */
5228 /* now we have the buffer containing the entry we're interested
5229 * in; copy it out if it represents a non-deleted entry.
5231 entryInDir = curOffset.LowPart & (2048-1);
5232 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5234 /* page header will help tell us which entries are free. Page
5235 * header can change more often than once per buffer, since
5236 * AFS 3 dir page size may be less than (but not more than)
5237 * a buffer package buffer.
5239 /* only look intra-buffer */
5240 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5241 temp &= ~(2048 - 1); /* turn off intra-page bits */
5242 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5244 /* now determine which entry we're looking at in the page.
5245 * If it is free (there's a free bitmap at the start of the
5246 * dir), we should skip these 32 bytes.
5248 slotInPage = (entryInDir & 0x7e0) >> 5;
5249 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5250 (1 << (slotInPage & 0x7)))) {
5251 /* this entry is free */
5252 numDirChunks = 1; /* only skip this guy */
5256 tp = bufferp->datap + entryInBuffer;
5257 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5259 /* while we're here, compute the next entry's location, too,
5260 * since we'll need it when writing out the cookie into the dir
5263 * XXXX Probably should do more sanity checking.
5265 numDirChunks = cm_NameEntries(dep->name, &onbytes);
5267 /* compute offset of cookie representing next entry */
5268 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5270 if (dep->fid.vnode == 0)
5271 goto nextEntry; /* This entry is not in use */
5273 /* Need 8.3 name? */
5275 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
5276 !cm_Is8Dot3(dep->name)) {
5277 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5281 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %s (%s)",
5282 dep->fid.vnode, dep->fid.unique,
5283 osi_LogSaveString(smb_logp, dep->name),
5284 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
5286 /* When matching, we are using doing a case fold if we have a wildcard mask.
5287 * If we get a non-wildcard match, it's a lookup for a specific file.
5289 if (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5290 (NeedShortName && smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))
5292 /* Eliminate entries that don't match requested attributes */
5293 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5294 smb_IsDotFile(dep->name)) {
5295 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5296 goto nextEntry; /* no hidden files */
5299 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5301 /* We have already done the cm_TryBulkStat above */
5302 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5303 fileType = cm_FindFileType(&fid);
5304 /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5305 * "has filetype %d", dep->name, fileType);
5307 if ( fileType == CM_SCACHETYPE_DIRECTORY ||
5308 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5309 fileType == CM_SCACHETYPE_DFSLINK ||
5310 fileType == CM_SCACHETYPE_INVALID)
5311 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5315 /* finally check if this name will fit */
5317 smb_UnparseString(opx, NULL, dep->name, &onbytes, SMB_STRF_ANSIPATH);
5318 orbytes = ohbytes + onbytes;
5320 /* now, we round up the record to a 4 byte alignment,
5321 * and we make sure that we have enough room here for
5322 * even the aligned version (so we don't have to worry
5323 * about an overflow when we pad things out below).
5324 * That's the reason for the alignment arithmetic below.
5326 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5327 align = (4 - (orbytes & 3)) & 3;
5331 if (orbytes + bytesInBuffer + align > maxReturnData) {
5332 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5337 /* this is one of the entries to use: it is not deleted
5338 * and it matches the star pattern we're looking for.
5339 * Put out the name, preceded by its length.
5341 /* First zero everything else */
5342 memset(origOp, 0, orbytes);
5345 smb_UnparseString(opx, origOp + ohbytes, dep->name, &onbytes, SMB_STRF_ANSIPATH);
5347 switch (infoLevel) {
5348 case SMB_INFO_STANDARD:
5349 fp->u.FstandardInfo.fileNameLength = onbytes;
5350 attrp = &fp->u.FstandardInfo.fileAttrs;
5353 case SMB_INFO_QUERY_EA_SIZE:
5354 fp->u.FeaSizeInfo.fileNameLength = onbytes;
5355 attrp = &fp->u.FeaSizeInfo.fileAttrs;
5356 fp->u.FeaSizeInfo.eaSize = 0;
5359 case SMB_INFO_QUERY_EAS_FROM_LIST:
5360 fp->u.FeasFromListInfo.fileNameLength = onbytes;
5361 attrp = &fp->u.FeasFromListInfo.fileAttrs;
5362 fp->u.FeasFromListInfo.eaSize = 0;
5365 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5366 if (NeedShortName) {
5370 nchars = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS,
5372 fp->u.FfileBothDirectoryInfo.shortName,
5373 sizeof(fp->u.FfileBothDirectoryInfo.shortName) / sizeof(wchar_t));
5375 fp->u.FfileBothDirectoryInfo.shortNameLength = (nchars - 1)*sizeof(wchar_t);
5377 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5378 fp->u.FfileBothDirectoryInfo.reserved = 0;
5380 strcpy(fp->u.FfileBothDirectoryInfo.shortName,
5382 fp->u.FfileBothDirectoryInfo.shortNameLength = strlen(shortName);
5387 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5388 fp->u.FfileFullDirectoryInfo.eaSize = 0;
5391 case SMB_FIND_FILE_DIRECTORY_INFO:
5392 fp->u.FfileDirectoryInfo.nextEntryOffset = orbytes + align;
5393 fp->u.FfileDirectoryInfo.fileIndex = nextEntryCookie;
5394 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5395 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5398 case SMB_FIND_FILE_NAMES_INFO:
5399 fp->u.FfileNamesInfo.nextEntryOffset = orbytes + align;
5400 fp->u.FfileNamesInfo.fileIndex = nextEntryCookie;
5401 fp->u.FfileNamesInfo.fileNameLength = onbytes;
5406 /* we shouldn't hit this case */
5407 osi_assertx(FALSE, "Unknown query type");
5410 /* now, adjust the # of entries copied */
5413 /* now we emit the attribute. This is tricky, since
5414 * we need to really stat the file to find out what
5415 * type of entry we've got. Right now, we're copying
5416 * out data from a buffer, while holding the scp
5417 * locked, so it isn't really convenient to stat
5418 * something now. We'll put in a place holder
5419 * now, and make a second pass before returning this
5420 * to get the real attributes. So, we just skip the
5421 * data for now, and adjust it later. We allocate a
5422 * patch record to make it easy to find this point
5423 * later. The replay will happen at a time when it is
5424 * safe to unlock the directory.
5426 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5427 osi_assert(attrp != NULL);
5428 curPatchp = malloc(sizeof(*curPatchp));
5429 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5430 curPatchp->dptr = attrp;
5432 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
5433 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5435 curPatchp->flags = 0;
5438 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5441 curPatchp->dep = dep;
5444 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5445 /* put out resume key */
5446 *((u_long *)origOp) = nextEntryCookie;
5448 /* Adjust byte ptr and count */
5449 origOp += orbytes; /* skip entire record */
5450 bytesInBuffer += orbytes;
5452 /* and pad the record out */
5453 while (align-- > 0) {
5457 } /* if we're including this name */
5458 else if (!starPattern &&
5460 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
5461 /* We were looking for exact matches, but here's an inexact one*/
5466 /* and adjust curOffset to be where the new cookie is */
5467 thyper.HighPart = 0;
5468 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5469 curOffset = LargeIntegerAdd(thyper, curOffset);
5470 } /* while copying data for dir listing */
5472 /* If we didn't get a star pattern, we did an exact match during the first pass.
5473 * If there were no exact matches found, we fail over to inexact matches by
5474 * marking the query as a star pattern (matches all case permutations), and
5475 * re-running the query.
5477 if (returnedNames == 0 && !starPattern && foundInexact) {
5478 osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
5483 /* release the mutex */
5484 lock_ReleaseWrite(&scp->rw);
5486 buf_Release(bufferp);
5490 /* apply and free last set of patches; if not doing a star match, this
5491 * will be empty, but better safe (and freeing everything) than sorry.
5493 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5494 dsp->relPath, infoLevel, userp, &req);
5496 /* now put out the final parameters */
5497 if (returnedNames == 0)
5499 if (p->opcode == 1) {
5501 outp->parmsp[0] = (unsigned short) dsp->cookie;
5502 outp->parmsp[1] = returnedNames;
5503 outp->parmsp[2] = eos;
5504 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5505 outp->parmsp[4] = 0;
5506 /* don't need last name to continue
5507 * search, cookie is enough. Normally,
5508 * this is the offset of the file name
5509 * of the last entry returned.
5511 outp->totalParms = 10; /* in bytes */
5515 outp->parmsp[0] = returnedNames;
5516 outp->parmsp[1] = eos;
5517 outp->parmsp[2] = 0; /* EAS error */
5518 outp->parmsp[3] = 0; /* last name, as above */
5519 outp->totalParms = 8; /* in bytes */
5522 /* return # of bytes in the buffer */
5523 outp->totalData = bytesInBuffer;
5525 /* Return error code if unsuccessful on first request */
5526 if (code == 0 && p->opcode == 1 && returnedNames == 0)
5527 code = CM_ERROR_NOSUCHFILE;
5529 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
5530 p->opcode, dsp->cookie, returnedNames, code);
5532 /* if we're supposed to close the search after this request, or if
5533 * we're supposed to close the search if we're done, and we're done,
5534 * or if something went wrong, close the search.
5536 if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
5537 (returnedNames == 0) ||
5538 ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
5540 smb_DeleteDirSearch(dsp);
5543 smb_SendTran2Error(vcp, p, opx, code);
5545 smb_SendTran2Packet(vcp, outp, opx);
5547 smb_FreeTran2Packet(outp);
5548 smb_ReleaseDirSearch(dsp);
5549 cm_ReleaseSCache(scp);
5550 cm_ReleaseUser(userp);
5554 /* SMB_COM_FIND_CLOSE2 */
5555 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5558 smb_dirSearch_t *dsp;
5560 dirHandle = smb_GetSMBParm(inp, 0);
5562 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
5564 dsp = smb_FindDirSearch(dirHandle);
5567 return CM_ERROR_BADFD;
5569 /* otherwise, we have an FD to destroy */
5570 smb_DeleteDirSearch(dsp);
5571 smb_ReleaseDirSearch(dsp);
5573 /* and return results */
5574 smb_SetSMBDataLength(outp, 0);
5580 /* SMB_COM_FIND_NOTIFY_CLOSE */
5581 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5583 smb_SetSMBDataLength(outp, 0);
5587 /* SMB_COM_OPEN_ANDX */
5588 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5595 cm_scache_t *dscp; /* dir we're dealing with */
5596 cm_scache_t *scp; /* file we're creating */
5598 int initialModeBits;
5602 unsigned long dosTime;
5608 int parmSlot; /* which parm we're dealing with */
5617 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
5618 openFun = smb_GetSMBParm(inp, 8); /* open function */
5619 excl = ((openFun & 3) == 0);
5620 trunc = ((openFun & 3) == 2); /* truncate it */
5621 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
5622 openAction = 0; /* tracks what we did */
5624 attributes = smb_GetSMBParm(inp, 5);
5625 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
5627 /* compute initial mode bits based on read-only flag in attributes */
5628 initialModeBits = 0666;
5629 if (attributes & SMB_ATTR_READONLY)
5630 initialModeBits &= ~0222;
5632 pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
5635 spacep = inp->spacep;
5636 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5639 (stricmp(lastNamep, SMB_IOCTL_FILENAME) == 0 ||
5640 stricmp(lastNamep, "\\srvsvc") == 0 ||
5641 stricmp(lastNamep, "\\wkssvc") == 0 ||
5642 stricmp(lastNamep, "ipc$") == 0)) {
5643 /* special case magic file name for receiving IOCTL requests
5644 * (since IOCTL calls themselves aren't getting through).
5647 osi_Log0(smb_logp, "IOCTL Open");
5650 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5651 smb_SetupIoctlFid(fidp, spacep);
5653 /* set inp->fid so that later read calls in same msg can find fid */
5654 inp->fid = fidp->fid;
5656 /* copy out remainder of the parms */
5658 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5660 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
5661 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
5662 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5663 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
5664 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
5665 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5666 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5667 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5669 /* and the final "always present" stuff */
5670 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
5671 /* next write out the "unique" ID */
5672 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
5673 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
5674 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5675 smb_SetSMBDataLength(outp, 0);
5677 /* and clean up fid reference */
5678 smb_ReleaseFID(fidp);
5682 #ifdef DEBUG_VERBOSE
5684 char *hexp, *asciip;
5685 asciip = (lastNamep ? lastNamep : pathp );
5686 hexp = osi_HexifyString(asciip);
5687 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
5691 userp = smb_GetUserFromVCP(vcp, inp);
5694 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5696 cm_ReleaseUser(userp);
5697 return CM_ERROR_NOSUCHPATH;
5699 code = cm_NameI(cm_data.rootSCachep, pathp,
5700 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5701 userp, tidPathp, &req, &scp);
5704 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5705 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5706 cm_ReleaseSCache(scp);
5707 cm_ReleaseUser(userp);
5708 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5709 return CM_ERROR_PATH_NOT_COVERED;
5711 return CM_ERROR_BADSHARENAME;
5713 #endif /* DFS_SUPPORT */
5716 code = cm_NameI(cm_data.rootSCachep, spacep->data,
5717 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5718 userp, tidPathp, &req, &dscp);
5720 cm_ReleaseUser(userp);
5725 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5726 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
5727 cm_ReleaseSCache(dscp);
5728 cm_ReleaseUser(userp);
5729 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5730 return CM_ERROR_PATH_NOT_COVERED;
5732 return CM_ERROR_BADSHARENAME;
5734 #endif /* DFS_SUPPORT */
5735 /* otherwise, scp points to the parent directory. Do a lookup,
5736 * and truncate the file if we find it, otherwise we create the
5743 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
5745 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5746 cm_ReleaseSCache(dscp);
5747 cm_ReleaseUser(userp);
5752 /* if we get here, if code is 0, the file exists and is represented by
5753 * scp. Otherwise, we have to create it. The dir may be represented
5754 * by dscp, or we may have found the file directly. If code is non-zero,
5758 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
5760 if (dscp) cm_ReleaseSCache(dscp);
5761 cm_ReleaseSCache(scp);
5762 cm_ReleaseUser(userp);
5767 /* oops, file shouldn't be there */
5769 cm_ReleaseSCache(dscp);
5770 cm_ReleaseSCache(scp);
5771 cm_ReleaseUser(userp);
5772 return CM_ERROR_EXISTS;
5776 setAttr.mask = CM_ATTRMASK_LENGTH;
5777 setAttr.length.LowPart = 0;
5778 setAttr.length.HighPart = 0;
5779 code = cm_SetAttr(scp, &setAttr, userp, &req);
5780 openAction = 3; /* truncated existing file */
5782 else openAction = 1; /* found existing file */
5784 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
5785 /* don't create if not found */
5786 if (dscp) cm_ReleaseSCache(dscp);
5787 cm_ReleaseUser(userp);
5788 return CM_ERROR_NOSUCHFILE;
5791 osi_assertx(dscp != NULL, "null cm_scache_t");
5792 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
5793 osi_LogSaveString(smb_logp, lastNamep));
5794 openAction = 2; /* created file */
5795 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5796 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5797 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5801 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5802 smb_NotifyChange(FILE_ACTION_ADDED,
5803 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5804 dscp, lastNamep, NULL, TRUE);
5805 } else if (!excl && code == CM_ERROR_EXISTS) {
5806 /* not an exclusive create, and someone else tried
5807 * creating it already, then we open it anyway. We
5808 * don't bother retrying after this, since if this next
5809 * fails, that means that the file was deleted after we
5810 * started this call.
5812 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5816 setAttr.mask = CM_ATTRMASK_LENGTH;
5817 setAttr.length.LowPart = 0;
5818 setAttr.length.HighPart = 0;
5819 code = cm_SetAttr(scp, &setAttr, userp, &req);
5821 } /* lookup succeeded */
5825 /* we don't need this any longer */
5827 cm_ReleaseSCache(dscp);
5830 /* something went wrong creating or truncating the file */
5832 cm_ReleaseSCache(scp);
5833 cm_ReleaseUser(userp);
5837 /* make sure we're about to open a file */
5838 if (scp->fileType != CM_SCACHETYPE_FILE) {
5839 cm_ReleaseSCache(scp);
5840 cm_ReleaseUser(userp);
5841 return CM_ERROR_ISDIR;
5844 /* now all we have to do is open the file itself */
5845 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5846 osi_assertx(fidp, "null smb_fid_t");
5849 lock_ObtainMutex(&fidp->mx);
5850 /* save a pointer to the vnode */
5852 lock_ObtainWrite(&scp->rw);
5853 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5854 lock_ReleaseWrite(&scp->rw);
5855 osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
5857 fidp->userp = userp;
5859 /* compute open mode */
5861 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5862 if (openMode == 1 || openMode == 2)
5863 fidp->flags |= SMB_FID_OPENWRITE;
5865 /* remember if the file was newly created */
5867 fidp->flags |= SMB_FID_CREATED;
5869 lock_ReleaseMutex(&fidp->mx);
5870 smb_ReleaseFID(fidp);
5872 cm_Open(scp, 0, userp);
5874 /* set inp->fid so that later read calls in same msg can find fid */
5875 inp->fid = fidp->fid;
5877 /* copy out remainder of the parms */
5879 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5880 lock_ObtainRead(&scp->rw);
5882 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5883 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5884 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5885 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5886 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5887 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5888 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5889 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5890 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5892 /* and the final "always present" stuff */
5893 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5894 /* next write out the "unique" ID */
5895 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5896 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5897 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5898 lock_ReleaseRead(&scp->rw);
5899 smb_SetSMBDataLength(outp, 0);
5901 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5903 cm_ReleaseUser(userp);
5904 /* leave scp held since we put it in fidp->scp */
5908 static void smb_GetLockParams(unsigned char LockType,
5910 unsigned int * ppid,
5911 LARGE_INTEGER * pOffset,
5912 LARGE_INTEGER * pLength)
5914 if (LockType & LOCKING_ANDX_LARGE_FILES) {
5916 *ppid = *((USHORT *) *buf);
5917 pOffset->HighPart = *((LONG *)(*buf + 4));
5918 pOffset->LowPart = *((DWORD *)(*buf + 8));
5919 pLength->HighPart = *((LONG *)(*buf + 12));
5920 pLength->LowPart = *((DWORD *)(*buf + 16));
5924 /* Not Large Files */
5925 *ppid = *((USHORT *) *buf);
5926 pOffset->HighPart = 0;
5927 pOffset->LowPart = *((DWORD *)(*buf + 2));
5928 pLength->HighPart = 0;
5929 pLength->LowPart = *((DWORD *)(*buf + 6));
5934 /* SMB_COM_LOCKING_ANDX */
5935 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5942 unsigned char LockType;
5943 unsigned short NumberOfUnlocks, NumberOfLocks;
5947 LARGE_INTEGER LOffset, LLength;
5948 smb_waitingLockRequest_t *wlRequest = NULL;
5949 cm_file_lock_t *lockp;
5957 fid = smb_GetSMBParm(inp, 2);
5958 fid = smb_ChainFID(fid, inp);
5960 fidp = smb_FindFID(vcp, fid, 0);
5962 return CM_ERROR_BADFD;
5964 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
5965 smb_CloseFID(vcp, fidp, NULL, 0);
5966 smb_ReleaseFID(fidp);
5967 return CM_ERROR_NOSUCHFILE;
5970 lock_ObtainMutex(&fidp->mx);
5971 if (fidp->flags & SMB_FID_IOCTL) {
5972 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
5973 lock_ReleaseMutex(&fidp->mx);
5974 smb_ReleaseFID(fidp);
5975 return CM_ERROR_BADFD;
5978 osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
5980 lock_ReleaseMutex(&fidp->mx);
5982 /* set inp->fid so that later read calls in same msg can find fid */
5985 userp = smb_GetUserFromVCP(vcp, inp);
5988 lock_ObtainWrite(&scp->rw);
5989 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5990 CM_SCACHESYNC_NEEDCALLBACK
5991 | CM_SCACHESYNC_GETSTATUS
5992 | CM_SCACHESYNC_LOCK);
5994 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
5998 LockType = smb_GetSMBParm(inp, 3) & 0xff;
5999 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
6000 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
6001 NumberOfLocks = smb_GetSMBParm(inp, 7);
6003 if (!(fidp->flags & SMB_FID_OPENWRITE) &&
6004 !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
6005 /* somebody wants exclusive locks on a file that they only
6006 opened for reading. We downgrade this to a shared lock. */
6007 osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
6008 LockType |= LOCKING_ANDX_SHARED_LOCK;
6011 if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
6012 /* AFS does not support atomic changes of lock types from read or write and vice-versa */
6013 osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]");
6014 code = CM_ERROR_BADOP;
6019 op = smb_GetSMBData(inp, NULL);
6021 if (LockType & LOCKING_ANDX_CANCEL_LOCK) {
6022 /* Cancel outstanding lock requests */
6023 smb_waitingLock_t * wl;
6025 for (i=0; i<NumberOfLocks; i++) {
6026 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6028 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6030 lock_ObtainWrite(&smb_globalLock);
6031 for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
6033 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
6034 if (wl->key == key && LargeIntegerEqualTo(wl->LOffset, LOffset) &&
6035 LargeIntegerEqualTo(wl->LLength, LLength)) {
6036 wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
6037 goto found_lock_request;
6042 lock_ReleaseWrite(&smb_globalLock);
6045 smb_SetSMBDataLength(outp, 0);
6050 for (i=0; i<NumberOfUnlocks; i++) {
6051 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6053 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6055 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
6063 for (i=0; i<NumberOfLocks; i++) {
6064 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6066 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6068 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
6069 userp, &req, &lockp);
6071 if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
6072 (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
6074 code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
6075 userp, &req, &lockp);
6078 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
6079 smb_waitingLock_t * wLock;
6081 /* Put on waiting list */
6082 if(wlRequest == NULL) {
6086 LARGE_INTEGER tOffset, tLength;
6088 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
6090 osi_assertx(wlRequest != NULL, "null wlRequest");
6092 wlRequest->vcp = vcp;
6094 wlRequest->scp = scp;
6095 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
6097 wlRequest->inp = smb_CopyPacket(inp);
6098 wlRequest->outp = smb_CopyPacket(outp);
6099 wlRequest->lockType = LockType;
6100 wlRequest->msTimeout = Timeout;
6101 wlRequest->start_t = osi_Time();
6102 wlRequest->locks = NULL;
6104 /* The waiting lock request needs to have enough
6105 information to undo all the locks in the request.
6106 We do the following to store info about locks that
6107 have already been granted. Sure, we can get most
6108 of the info from the packet, but the packet doesn't
6109 hold the result of cm_Lock call. In practice we
6110 only receive packets with one or two locks, so we
6111 are only wasting a few bytes here and there and
6112 only for a limited period of time until the waiting
6113 lock times out or is freed. */
6115 for(opt = op_locks, j=i; j > 0; j--) {
6116 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
6118 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6120 wLock = malloc(sizeof(smb_waitingLock_t));
6122 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6125 wLock->LOffset = tOffset;
6126 wLock->LLength = tLength;
6127 wLock->lockp = NULL;
6128 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
6129 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6134 wLock = malloc(sizeof(smb_waitingLock_t));
6136 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6139 wLock->LOffset = LOffset;
6140 wLock->LLength = LLength;
6141 wLock->lockp = lockp;
6142 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
6143 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6146 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
6154 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
6161 /* Since something went wrong with the lock number i, we now
6162 have to go ahead and release any locks acquired before the
6163 failure. All locks before lock number i (of which there
6164 are i of them) have either been successful or are waiting.
6165 Either case requires calling cm_Unlock(). */
6167 /* And purge the waiting lock */
6168 if(wlRequest != NULL) {
6169 smb_waitingLock_t * wl;
6170 smb_waitingLock_t * wlNext;
6173 for(wl = wlRequest->locks; wl; wl = wlNext) {
6175 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
6177 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
6180 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
6182 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
6185 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
6190 smb_ReleaseVC(wlRequest->vcp);
6191 cm_ReleaseSCache(wlRequest->scp);
6192 smb_FreePacket(wlRequest->inp);
6193 smb_FreePacket(wlRequest->outp);
6202 if (wlRequest != NULL) {
6204 lock_ObtainWrite(&smb_globalLock);
6205 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
6207 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
6208 lock_ReleaseWrite(&smb_globalLock);
6210 /* don't send reply immediately */
6211 outp->flags |= SMB_PACKETFLAG_NOSEND;
6214 smb_SetSMBDataLength(outp, 0);
6218 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
6221 lock_ReleaseWrite(&scp->rw);
6222 cm_ReleaseSCache(scp);
6223 cm_ReleaseUser(userp);
6224 smb_ReleaseFID(fidp);
6229 /* SMB_COM_QUERY_INFORMATION2 */
6230 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6236 afs_uint32 searchTime;
6243 fid = smb_GetSMBParm(inp, 0);
6244 fid = smb_ChainFID(fid, inp);
6246 fidp = smb_FindFID(vcp, fid, 0);
6248 return CM_ERROR_BADFD;
6250 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6251 smb_CloseFID(vcp, fidp, NULL, 0);
6252 smb_ReleaseFID(fidp);
6253 return CM_ERROR_NOSUCHFILE;
6256 lock_ObtainMutex(&fidp->mx);
6257 if (fidp->flags & SMB_FID_IOCTL) {
6258 lock_ReleaseMutex(&fidp->mx);
6259 smb_ReleaseFID(fidp);
6260 return CM_ERROR_BADFD;
6263 osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6265 lock_ReleaseMutex(&fidp->mx);
6267 userp = smb_GetUserFromVCP(vcp, inp);
6270 /* otherwise, stat the file */
6271 lock_ObtainWrite(&scp->rw);
6272 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6273 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6277 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6279 lock_ConvertWToR(&scp->rw);
6281 /* decode times. We need a search time, but the response to this
6282 * call provides the date first, not the time, as returned in the
6283 * searchTime variable. So we take the high-order bits first.
6285 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
6286 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
6287 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
6288 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
6289 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
6290 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
6291 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
6293 /* now handle file size and allocation size */
6294 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
6295 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
6296 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
6297 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
6299 /* file attribute */
6300 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
6302 /* and finalize stuff */
6303 smb_SetSMBDataLength(outp, 0);
6308 lock_ReleaseRead(&scp->rw);
6310 lock_ReleaseWrite(&scp->rw);
6311 cm_ReleaseSCache(scp);
6312 cm_ReleaseUser(userp);
6313 smb_ReleaseFID(fidp);
6317 /* SMB_COM_SET_INFORMATION2 */
6318 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6324 afs_uint32 searchTime;
6332 fid = smb_GetSMBParm(inp, 0);
6333 fid = smb_ChainFID(fid, inp);
6335 fidp = smb_FindFID(vcp, fid, 0);
6337 return CM_ERROR_BADFD;
6339 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6340 smb_CloseFID(vcp, fidp, NULL, 0);
6341 smb_ReleaseFID(fidp);
6342 return CM_ERROR_NOSUCHFILE;
6345 lock_ObtainMutex(&fidp->mx);
6346 if (fidp->flags & SMB_FID_IOCTL) {
6347 lock_ReleaseMutex(&fidp->mx);
6348 smb_ReleaseFID(fidp);
6349 return CM_ERROR_BADFD;
6352 osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6354 lock_ReleaseMutex(&fidp->mx);
6356 userp = smb_GetUserFromVCP(vcp, inp);
6359 /* now prepare to call cm_setattr. This message only sets various times,
6360 * and AFS only implements mtime, and we'll set the mtime if that's
6361 * requested. The others we'll ignore.
6363 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
6365 if (searchTime != 0) {
6366 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
6368 if ( unixTime != -1 ) {
6369 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
6370 attrs.clientModTime = unixTime;
6371 code = cm_SetAttr(scp, &attrs, userp, &req);
6373 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
6375 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
6381 cm_ReleaseSCache(scp);
6382 cm_ReleaseUser(userp);
6383 smb_ReleaseFID(fidp);
6387 /* SMB_COM_WRITE_ANDX */
6388 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6391 long count, written = 0, total_written = 0;
6395 smb_t *smbp = (smb_t*) inp;
6399 int inDataBlockCount;
6401 fd = smb_GetSMBParm(inp, 2);
6402 count = smb_GetSMBParm(inp, 10);
6404 offset.HighPart = 0;
6405 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6407 if (*inp->wctp == 14) {
6408 /* we have a request with 64-bit file offsets */
6409 #ifdef AFS_LARGEFILES
6410 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6412 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6414 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
6415 /* we shouldn't have received this op if we didn't specify
6416 largefile support */
6417 return CM_ERROR_BADOP;
6422 op = inp->data + smb_GetSMBParm(inp, 11);
6423 inDataBlockCount = count;
6425 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
6426 fd, offset.HighPart, offset.LowPart, count);
6428 fd = smb_ChainFID(fd, inp);
6429 fidp = smb_FindFID(vcp, fd, 0);
6431 return CM_ERROR_BADFD;
6433 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6434 smb_CloseFID(vcp, fidp, NULL, 0);
6435 smb_ReleaseFID(fidp);
6436 return CM_ERROR_NOSUCHFILE;
6439 lock_ObtainMutex(&fidp->mx);
6440 if (fidp->flags & SMB_FID_IOCTL) {
6441 lock_ReleaseMutex(&fidp->mx);
6442 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
6443 smb_ReleaseFID(fidp);
6446 lock_ReleaseMutex(&fidp->mx);
6447 userp = smb_GetUserFromVCP(vcp, inp);
6449 /* special case: 0 bytes transferred means there is no data
6450 transferred. A slight departure from SMB_COM_WRITE where this
6451 means that we are supposed to truncate the file at this
6456 LARGE_INTEGER LOffset;
6457 LARGE_INTEGER LLength;
6461 key = cm_GenerateKey(vcp->vcID, pid, fd);
6463 LOffset.HighPart = offset.HighPart;
6464 LOffset.LowPart = offset.LowPart;
6465 LLength.HighPart = 0;
6466 LLength.LowPart = count;
6469 lock_ObtainWrite(&scp->rw);
6470 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
6471 lock_ReleaseWrite(&scp->rw);
6478 * Work around bug in NT client
6480 * When copying a file, the NT client should first copy the data,
6481 * then copy the last write time. But sometimes the NT client does
6482 * these in the wrong order, so the data copies would inadvertently
6483 * cause the last write time to be overwritten. We try to detect this,
6484 * and don't set client mod time if we think that would go against the
6487 lock_ObtainMutex(&fidp->mx);
6488 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6489 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6490 fidp->scp->clientModTime = time(NULL);
6492 lock_ReleaseMutex(&fidp->mx);
6495 while ( code == 0 && count > 0 ) {
6496 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6497 if (code == 0 && written == 0)
6498 code = CM_ERROR_PARTIALWRITE;
6500 offset = LargeIntegerAdd(offset,
6501 ConvertLongToLargeInteger(written));
6503 total_written += written;
6507 /* slots 0 and 1 are reserved for request chaining and will be
6508 filled in when we return. */
6509 smb_SetSMBParm(outp, 2, total_written);
6510 smb_SetSMBParm(outp, 3, 0); /* reserved */
6511 smb_SetSMBParm(outp, 4, 0); /* reserved */
6512 smb_SetSMBParm(outp, 5, 0); /* reserved */
6513 smb_SetSMBDataLength(outp, 0);
6516 cm_ReleaseUser(userp);
6517 smb_ReleaseFID(fidp);
6522 /* SMB_COM_READ_ANDX */
6523 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6527 long finalCount = 0;
6531 smb_t *smbp = (smb_t*) inp;
6537 fd = smb_GetSMBParm(inp, 2);
6538 count = smb_GetSMBParm(inp, 5);
6539 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6541 if (*inp->wctp == 12) {
6542 /* a request with 64-bit offsets */
6543 #ifdef AFS_LARGEFILES
6544 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
6546 if (LargeIntegerLessThanZero(offset)) {
6547 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
6548 offset.HighPart, offset.LowPart);
6549 return CM_ERROR_BADSMB;
6552 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
6553 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
6554 return CM_ERROR_BADSMB;
6556 offset.HighPart = 0;
6560 offset.HighPart = 0;
6563 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
6564 fd, offset.HighPart, offset.LowPart, count);
6566 fd = smb_ChainFID(fd, inp);
6567 fidp = smb_FindFID(vcp, fd, 0);
6569 return CM_ERROR_BADFD;
6572 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6573 smb_CloseFID(vcp, fidp, NULL, 0);
6574 smb_ReleaseFID(fidp);
6575 return CM_ERROR_NOSUCHFILE;
6579 key = cm_GenerateKey(vcp->vcID, pid, fd);
6581 LARGE_INTEGER LOffset, LLength;
6584 LOffset.HighPart = offset.HighPart;
6585 LOffset.LowPart = offset.LowPart;
6586 LLength.HighPart = 0;
6587 LLength.LowPart = count;
6590 lock_ObtainWrite(&scp->rw);
6591 code = cm_LockCheckRead(scp, LOffset, LLength, key);
6592 lock_ReleaseWrite(&scp->rw);
6596 smb_ReleaseFID(fidp);
6600 /* set inp->fid so that later read calls in same msg can find fid */
6603 lock_ObtainMutex(&fidp->mx);
6604 if (fidp->flags & SMB_FID_IOCTL) {
6605 lock_ReleaseMutex(&fidp->mx);
6606 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
6607 smb_ReleaseFID(fidp);
6610 lock_ReleaseMutex(&fidp->mx);
6612 userp = smb_GetUserFromVCP(vcp, inp);
6614 /* 0 and 1 are reserved for request chaining, were setup by our caller,
6615 * and will be further filled in after we return.
6617 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
6618 smb_SetSMBParm(outp, 3, 0); /* resvd */
6619 smb_SetSMBParm(outp, 4, 0); /* resvd */
6620 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
6621 /* fill in #6 when we have all the parameters' space reserved */
6622 smb_SetSMBParm(outp, 7, 0); /* resv'd */
6623 smb_SetSMBParm(outp, 8, 0); /* resv'd */
6624 smb_SetSMBParm(outp, 9, 0); /* resv'd */
6625 smb_SetSMBParm(outp, 10, 0); /* resv'd */
6626 smb_SetSMBParm(outp, 11, 0); /* reserved */
6628 /* get op ptr after putting in the parms, since otherwise we don't
6629 * know where the data really is.
6631 op = smb_GetSMBData(outp, NULL);
6633 /* now fill in offset from start of SMB header to first data byte (to op) */
6634 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
6636 /* set the packet data length the count of the # of bytes */
6637 smb_SetSMBDataLength(outp, count);
6639 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6641 /* fix some things up */
6642 smb_SetSMBParm(outp, 5, finalCount);
6643 smb_SetSMBDataLength(outp, finalCount);
6645 cm_ReleaseUser(userp);
6646 smb_ReleaseFID(fidp);
6651 * Values for createDisp, copied from NTDDK.H
6653 #define FILE_SUPERSEDE 0 // (???)
6654 #define FILE_OPEN 1 // (open)
6655 #define FILE_CREATE 2 // (exclusive)
6656 #define FILE_OPEN_IF 3 // (non-exclusive)
6657 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
6658 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
6661 #define REQUEST_OPLOCK 2
6662 #define REQUEST_BATCH_OPLOCK 4
6663 #define OPEN_DIRECTORY 8
6664 #define EXTENDED_RESPONSE_REQUIRED 0x10
6666 /* CreateOptions field. */
6667 #define FILE_DIRECTORY_FILE 0x0001
6668 #define FILE_WRITE_THROUGH 0x0002
6669 #define FILE_SEQUENTIAL_ONLY 0x0004
6670 #define FILE_NON_DIRECTORY_FILE 0x0040
6671 #define FILE_NO_EA_KNOWLEDGE 0x0200
6672 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
6673 #define FILE_RANDOM_ACCESS 0x0800
6674 #define FILE_DELETE_ON_CLOSE 0x1000
6675 #define FILE_OPEN_BY_FILE_ID 0x2000
6677 /* SMB_COM_NT_CREATE_ANDX */
6678 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6680 char *pathp, *realPathp;
6684 cm_scache_t *dscp; /* parent dir */
6685 cm_scache_t *scp; /* file to create or open */
6686 cm_scache_t *targetScp; /* if scp is a symlink */
6690 unsigned short nameLength;
6692 unsigned int requestOpLock;
6693 unsigned int requestBatchOpLock;
6694 unsigned int mustBeDir;
6695 unsigned int extendedRespRequired;
6696 unsigned int treeCreate;
6698 unsigned int desiredAccess;
6699 unsigned int extAttributes;
6700 unsigned int createDisp;
6701 unsigned int createOptions;
6702 unsigned int shareAccess;
6703 int initialModeBits;
6704 unsigned short baseFid;
6705 smb_fid_t *baseFidp;
6707 cm_scache_t *baseDirp;
6708 unsigned short openAction;
6717 cm_lock_data_t *ldp = NULL;
6721 /* This code is very long and has a lot of if-then-else clauses
6722 * scp and dscp get reused frequently and we need to ensure that
6723 * we don't lose a reference. Start by ensuring that they are NULL.
6730 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
6731 flags = smb_GetSMBOffsetParm(inp, 3, 1)
6732 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
6733 requestOpLock = flags & REQUEST_OPLOCK;
6734 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6735 mustBeDir = flags & OPEN_DIRECTORY;
6736 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6739 * Why all of a sudden 32-bit FID?
6740 * We will reject all bits higher than 16.
6742 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
6743 return CM_ERROR_INVAL;
6744 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
6745 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
6746 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6747 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
6748 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
6749 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
6750 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
6751 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
6752 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
6753 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
6754 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
6756 /* mustBeDir is never set; createOptions directory bit seems to be
6759 if (createOptions & FILE_DIRECTORY_FILE)
6761 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6767 * compute initial mode bits based on read-only flag in
6768 * extended attributes
6770 initialModeBits = 0666;
6771 if (extAttributes & SMB_ATTR_READONLY)
6772 initialModeBits &= ~0222;
6774 pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
6775 NULL, SMB_STRF_ANSIPATH);
6777 /* Sometimes path is not null-terminated, so we make a copy. */
6778 realPathp = malloc(nameLength+1);
6779 memcpy(realPathp, pathp, nameLength);
6780 realPathp[nameLength] = 0;
6782 spacep = inp->spacep;
6783 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6785 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
6786 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
6787 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
6790 (stricmp(lastNamep, SMB_IOCTL_FILENAME) == 0 ||
6791 stricmp(lastNamep, "\\srvsvc") == 0 ||
6792 stricmp(lastNamep, "\\wkssvc") == 0 ||
6793 stricmp(lastNamep, "ipc$") == 0)) {
6794 /* special case magic file name for receiving IOCTL requests
6795 * (since IOCTL calls themselves aren't getting through).
6797 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6798 smb_SetupIoctlFid(fidp, spacep);
6799 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
6801 /* set inp->fid so that later read calls in same msg can find fid */
6802 inp->fid = fidp->fid;
6806 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6807 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6808 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
6810 memset(&ft, 0, sizeof(ft));
6811 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6812 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6813 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6814 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6815 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
6816 sz.HighPart = 0x7fff; sz.LowPart = 0;
6817 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
6818 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
6819 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6820 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6821 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
6822 smb_SetSMBDataLength(outp, 0);
6824 /* clean up fid reference */
6825 smb_ReleaseFID(fidp);
6830 #ifdef DEBUG_VERBOSE
6832 char *hexp, *asciip;
6833 asciip = (lastNamep? lastNamep : realPathp);
6834 hexp = osi_HexifyString( asciip );
6835 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
6840 userp = smb_GetUserFromVCP(vcp, inp);
6842 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
6844 return CM_ERROR_INVAL;
6849 baseDirp = cm_data.rootSCachep;
6850 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6851 if (code == CM_ERROR_TIDIPC) {
6852 /* Attempt to use a TID allocated for IPC. The client
6853 * is probably looking for DCE RPC end points which we
6854 * don't support OR it could be looking to make a DFS
6857 osi_Log0(smb_logp, "NTCreateX received IPC TID");
6860 cm_ReleaseUser(userp);
6861 return CM_ERROR_NOSUCHFILE;
6862 #endif /* DFS_SUPPORT */
6865 baseFidp = smb_FindFID(vcp, baseFid, 0);
6867 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
6869 cm_ReleaseUser(userp);
6870 return CM_ERROR_INVAL;
6873 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6875 cm_ReleaseUser(userp);
6876 smb_CloseFID(vcp, baseFidp, NULL, 0);
6877 smb_ReleaseFID(baseFidp);
6878 return CM_ERROR_NOSUCHPATH;
6881 baseDirp = baseFidp->scp;
6885 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
6887 /* compute open mode */
6889 if (desiredAccess & DELETE)
6890 fidflags |= SMB_FID_OPENDELETE;
6891 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
6892 fidflags |= SMB_FID_OPENREAD_LISTDIR;
6893 if (desiredAccess & AFS_ACCESS_WRITE)
6894 fidflags |= SMB_FID_OPENWRITE;
6895 if (createOptions & FILE_DELETE_ON_CLOSE)
6896 fidflags |= SMB_FID_DELONCLOSE;
6897 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6898 fidflags |= SMB_FID_SEQUENTIAL;
6899 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6900 fidflags |= SMB_FID_RANDOM;
6901 if (smb_IsExecutableFileName(lastNamep))
6902 fidflags |= SMB_FID_EXECUTABLE;
6904 /* and the share mode */
6905 if (shareAccess & FILE_SHARE_READ)
6906 fidflags |= SMB_FID_SHARE_READ;
6907 if (shareAccess & FILE_SHARE_WRITE)
6908 fidflags |= SMB_FID_SHARE_WRITE;
6910 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
6913 /* For an exclusive create, we want to do a case sensitive match for the last component. */
6914 if ( createDisp == FILE_CREATE ||
6915 createDisp == FILE_OVERWRITE ||
6916 createDisp == FILE_OVERWRITE_IF) {
6917 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6918 userp, tidPathp, &req, &dscp);
6921 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6922 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
6923 cm_ReleaseSCache(dscp);
6924 cm_ReleaseUser(userp);
6927 smb_ReleaseFID(baseFidp);
6928 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6929 return CM_ERROR_PATH_NOT_COVERED;
6931 return CM_ERROR_BADSHARENAME;
6933 #endif /* DFS_SUPPORT */
6934 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6936 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
6937 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6938 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6939 if (code == 0 && realDirFlag == 1) {
6940 cm_ReleaseSCache(scp);
6941 cm_ReleaseSCache(dscp);
6942 cm_ReleaseUser(userp);
6945 smb_ReleaseFID(baseFidp);
6946 return CM_ERROR_EXISTS;
6950 /* we have both scp and dscp */
6952 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6953 userp, tidPathp, &req, &scp);
6955 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6956 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
6957 cm_ReleaseSCache(scp);
6958 cm_ReleaseUser(userp);
6961 smb_ReleaseFID(baseFidp);
6962 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6963 return CM_ERROR_PATH_NOT_COVERED;
6965 return CM_ERROR_BADSHARENAME;
6967 #endif /* DFS_SUPPORT */
6968 /* we might have scp but not dscp */
6974 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6975 /* look up parent directory */
6976 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
6977 * the immediate parent. We have to work our way up realPathp until we hit something that we
6981 /* we might or might not have scp */
6987 code = cm_NameI(baseDirp, spacep->data,
6988 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6989 userp, tidPathp, &req, &dscp);
6992 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6993 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
6995 cm_ReleaseSCache(scp);
6996 cm_ReleaseSCache(dscp);
6997 cm_ReleaseUser(userp);
7000 smb_ReleaseFID(baseFidp);
7001 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7002 return CM_ERROR_PATH_NOT_COVERED;
7004 return CM_ERROR_BADSHARENAME;
7006 #endif /* DFS_SUPPORT */
7009 (tp = strrchr(spacep->data,'\\')) &&
7010 (createDisp == FILE_CREATE) &&
7011 (realDirFlag == 1)) {
7014 treeStartp = realPathp + (tp - spacep->data);
7016 if (*tp && !smb_IsLegalFilename(tp)) {
7017 cm_ReleaseUser(userp);
7019 smb_ReleaseFID(baseFidp);
7022 cm_ReleaseSCache(scp);
7023 return CM_ERROR_BADNTFILENAME;
7027 } while (dscp == NULL && code == 0);
7031 /* we might have scp and we might have dscp */
7034 smb_ReleaseFID(baseFidp);
7037 osi_Log0(smb_logp,"NTCreateX parent not found");
7039 cm_ReleaseSCache(scp);
7041 cm_ReleaseSCache(dscp);
7042 cm_ReleaseUser(userp);
7047 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
7048 /* A file exists where we want a directory. */
7050 cm_ReleaseSCache(scp);
7051 cm_ReleaseSCache(dscp);
7052 cm_ReleaseUser(userp);
7054 return CM_ERROR_EXISTS;
7058 lastNamep = realPathp;
7062 if (!smb_IsLegalFilename(lastNamep)) {
7064 cm_ReleaseSCache(scp);
7066 cm_ReleaseSCache(dscp);
7067 cm_ReleaseUser(userp);
7069 return CM_ERROR_BADNTFILENAME;
7072 if (!foundscp && !treeCreate) {
7073 if ( createDisp == FILE_CREATE ||
7074 createDisp == FILE_OVERWRITE ||
7075 createDisp == FILE_OVERWRITE_IF)
7077 code = cm_Lookup(dscp, lastNamep,
7078 CM_FLAG_FOLLOW, userp, &req, &scp);
7080 code = cm_Lookup(dscp, lastNamep,
7081 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7084 if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
7086 cm_ReleaseSCache(dscp);
7087 cm_ReleaseUser(userp);
7092 /* we have scp and dscp */
7094 /* we have scp but not dscp */
7096 smb_ReleaseFID(baseFidp);
7099 /* if we get here, if code is 0, the file exists and is represented by
7100 * scp. Otherwise, we have to create it. The dir may be represented
7101 * by dscp, or we may have found the file directly. If code is non-zero,
7104 if (code == 0 && !treeCreate) {
7105 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7108 cm_ReleaseSCache(dscp);
7110 cm_ReleaseSCache(scp);
7111 cm_ReleaseUser(userp);
7116 if (createDisp == FILE_CREATE) {
7117 /* oops, file shouldn't be there */
7118 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7120 cm_ReleaseSCache(dscp);
7122 cm_ReleaseSCache(scp);
7123 cm_ReleaseUser(userp);
7125 return CM_ERROR_EXISTS;
7128 if ( createDisp == FILE_OVERWRITE ||
7129 createDisp == FILE_OVERWRITE_IF) {
7131 setAttr.mask = CM_ATTRMASK_LENGTH;
7132 setAttr.length.LowPart = 0;
7133 setAttr.length.HighPart = 0;
7134 /* now watch for a symlink */
7136 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7138 osi_assertx(dscp != NULL, "null cm_scache_t");
7139 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7141 /* we have a more accurate file to use (the
7142 * target of the symbolic link). Otherwise,
7143 * we'll just use the symlink anyway.
7145 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7147 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7148 cm_ReleaseSCache(scp);
7150 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7153 cm_ReleaseSCache(dscp);
7155 cm_ReleaseSCache(scp);
7156 cm_ReleaseUser(userp);
7162 code = cm_SetAttr(scp, &setAttr, userp, &req);
7163 openAction = 3; /* truncated existing file */
7166 openAction = 1; /* found existing file */
7168 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7169 /* don't create if not found */
7171 cm_ReleaseSCache(dscp);
7173 cm_ReleaseSCache(scp);
7174 cm_ReleaseUser(userp);
7176 return CM_ERROR_NOSUCHFILE;
7177 } else if (realDirFlag == 0 || realDirFlag == -1) {
7178 osi_assertx(dscp != NULL, "null cm_scache_t");
7179 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
7180 osi_LogSaveString(smb_logp, lastNamep));
7181 openAction = 2; /* created file */
7182 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7183 setAttr.clientModTime = time(NULL);
7184 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
7187 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7188 smb_NotifyChange(FILE_ACTION_ADDED,
7189 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7190 dscp, lastNamep, NULL, TRUE);
7191 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7192 /* Not an exclusive create, and someone else tried
7193 * creating it already, then we open it anyway. We
7194 * don't bother retrying after this, since if this next
7195 * fails, that means that the file was deleted after we
7196 * started this call.
7198 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7201 if (createDisp == FILE_OVERWRITE_IF) {
7202 setAttr.mask = CM_ATTRMASK_LENGTH;
7203 setAttr.length.LowPart = 0;
7204 setAttr.length.HighPart = 0;
7206 /* now watch for a symlink */
7208 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7210 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7212 /* we have a more accurate file to use (the
7213 * target of the symbolic link). Otherwise,
7214 * we'll just use the symlink anyway.
7216 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7218 cm_ReleaseSCache(scp);
7222 code = cm_SetAttr(scp, &setAttr, userp, &req);
7224 } /* lookup succeeded */
7228 char *cp; /* This component */
7229 int clen = 0; /* length of component */
7230 cm_scache_t *tscp1, *tscp2;
7233 /* create directory */
7235 treeStartp = lastNamep;
7236 osi_assertx(dscp != NULL, "null cm_scache_t");
7237 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
7238 osi_LogSaveString(smb_logp, treeStartp));
7239 openAction = 2; /* created directory */
7241 /* if the request is to create the root directory
7242 * it will appear as a directory name of the nul-string
7243 * and a code of CM_ERROR_NOSUCHFILE
7245 if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
7246 code = CM_ERROR_EXISTS;
7248 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7249 setAttr.clientModTime = time(NULL);
7254 cm_HoldSCache(tscp1);
7258 tp = strchr(pp, '\\');
7261 clen = (int)strlen(cp);
7262 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
7264 clen = (int)(tp - pp);
7265 strncpy(cp,pp,clen);
7272 continue; /* the supplied path can't have consecutive slashes either , but */
7274 /* cp is the next component to be created. */
7275 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
7276 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
7277 smb_NotifyChange(FILE_ACTION_ADDED,
7278 FILE_NOTIFY_CHANGE_DIR_NAME,
7279 tscp1, cp, NULL, TRUE);
7281 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7282 /* Not an exclusive create, and someone else tried
7283 * creating it already, then we open it anyway. We
7284 * don't bother retrying after this, since if this next
7285 * fails, that means that the file was deleted after we
7286 * started this call.
7288 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
7289 userp, &req, &tscp2);
7294 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
7295 cm_ReleaseSCache(tscp1);
7296 tscp1 = tscp2; /* Newly created directory will be next parent */
7297 /* the hold is transfered to tscp1 from tscp2 */
7302 cm_ReleaseSCache(dscp);
7305 cm_ReleaseSCache(scp);
7308 * if we get here and code == 0, then scp is the last directory created, and dscp is the
7314 /* something went wrong creating or truncating the file */
7316 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7318 cm_ReleaseSCache(scp);
7320 cm_ReleaseSCache(dscp);
7321 cm_ReleaseUser(userp);
7326 /* make sure we have file vs. dir right (only applies for single component case) */
7327 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7328 /* now watch for a symlink */
7330 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7331 cm_scache_t * targetScp = 0;
7332 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7334 /* we have a more accurate file to use (the
7335 * target of the symbolic link). Otherwise,
7336 * we'll just use the symlink anyway.
7338 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
7340 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7341 cm_ReleaseSCache(scp);
7346 if (scp->fileType != CM_SCACHETYPE_FILE) {
7348 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7350 cm_ReleaseSCache(dscp);
7351 cm_ReleaseSCache(scp);
7352 cm_ReleaseUser(userp);
7354 return CM_ERROR_ISDIR;
7358 /* (only applies to single component case) */
7359 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7361 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7362 cm_ReleaseSCache(scp);
7364 cm_ReleaseSCache(dscp);
7365 cm_ReleaseUser(userp);
7367 return CM_ERROR_NOTDIR;
7370 /* open the file itself */
7371 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7372 osi_assertx(fidp, "null smb_fid_t");
7374 /* save a reference to the user */
7376 fidp->userp = userp;
7378 /* If we are restricting sharing, we should do so with a suitable
7380 if (scp->fileType == CM_SCACHETYPE_FILE &&
7381 !(fidflags & SMB_FID_SHARE_WRITE)) {
7383 LARGE_INTEGER LOffset, LLength;
7386 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7387 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7388 LLength.HighPart = 0;
7389 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7391 /* If we are not opening the file for writing, then we don't
7392 try to get an exclusive lock. No one else should be able to
7393 get an exclusive lock on the file anyway, although someone
7394 else can get a shared lock. */
7395 if ((fidflags & SMB_FID_SHARE_READ) ||
7396 !(fidflags & SMB_FID_OPENWRITE)) {
7397 sLockType = LOCKING_ANDX_SHARED_LOCK;
7402 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7404 lock_ObtainWrite(&scp->rw);
7405 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7406 lock_ReleaseWrite(&scp->rw);
7410 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7411 cm_ReleaseSCache(scp);
7413 cm_ReleaseSCache(dscp);
7414 cm_ReleaseUser(userp);
7415 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7416 smb_CloseFID(vcp, fidp, NULL, 0);
7417 smb_ReleaseFID(fidp);
7423 /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
7425 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7427 lock_ObtainMutex(&fidp->mx);
7428 /* save a pointer to the vnode */
7429 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
7430 lock_ObtainWrite(&scp->rw);
7431 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7432 lock_ReleaseWrite(&scp->rw);
7433 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
7435 fidp->flags = fidflags;
7437 /* remember if the file was newly created */
7439 fidp->flags |= SMB_FID_CREATED;
7441 /* save parent dir and pathname for delete or change notification */
7442 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7443 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
7444 fidp->flags |= SMB_FID_NTOPEN;
7445 fidp->NTopen_dscp = dscp;
7447 fidp->NTopen_pathp = strdup(lastNamep);
7449 fidp->NTopen_wholepathp = realPathp;
7450 lock_ReleaseMutex(&fidp->mx);
7452 /* we don't need this any longer */
7454 cm_ReleaseSCache(dscp);
7458 cm_Open(scp, 0, userp);
7460 /* set inp->fid so that later read calls in same msg can find fid */
7461 inp->fid = fidp->fid;
7465 lock_ObtainRead(&scp->rw);
7466 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7467 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7468 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7469 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7470 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7471 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7472 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7473 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7474 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7476 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7477 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7478 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
7479 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
7480 smb_SetSMBParmByte(outp, parmSlot,
7481 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7482 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7483 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7484 smb_SetSMBDataLength(outp, 0);
7486 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
7487 LargeIntegerGreaterThanZero(fidp->scp->length) &&
7488 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
7489 cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
7490 fidp->scp->length.LowPart, fidp->scp->length.HighPart,
7493 lock_ReleaseRead(&scp->rw);
7495 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
7496 osi_LogSaveString(smb_logp, realPathp));
7498 cm_ReleaseUser(userp);
7499 smb_ReleaseFID(fidp);
7501 /* Can't free realPathp if we get here since
7502 fidp->NTopen_wholepathp is pointing there */
7504 /* leave scp held since we put it in fidp->scp */
7509 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
7510 * Instead, ultimately, would like to use a subroutine for common code.
7513 /* NT_TRANSACT_CREATE (SMB_COM_NT_TRANSACT) */
7514 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7516 char *pathp, *realPathp;
7520 cm_scache_t *dscp; /* parent dir */
7521 cm_scache_t *scp; /* file to create or open */
7522 cm_scache_t *targetScp; /* if scp is a symlink */
7525 unsigned long nameLength;
7527 unsigned int requestOpLock;
7528 unsigned int requestBatchOpLock;
7529 unsigned int mustBeDir;
7530 unsigned int extendedRespRequired;
7532 unsigned int desiredAccess;
7533 #ifdef DEBUG_VERBOSE
7534 unsigned int allocSize;
7536 unsigned int shareAccess;
7537 unsigned int extAttributes;
7538 unsigned int createDisp;
7539 #ifdef DEBUG_VERBOSE
7542 unsigned int createOptions;
7543 int initialModeBits;
7544 unsigned short baseFid;
7545 smb_fid_t *baseFidp;
7547 cm_scache_t *baseDirp;
7548 unsigned short openAction;
7554 int parmOffset, dataOffset;
7560 cm_lock_data_t *ldp = NULL;
7567 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7568 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7569 parmp = inp->data + parmOffset;
7570 lparmp = (ULONG *) parmp;
7573 requestOpLock = flags & REQUEST_OPLOCK;
7574 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7575 mustBeDir = flags & OPEN_DIRECTORY;
7576 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7579 * Why all of a sudden 32-bit FID?
7580 * We will reject all bits higher than 16.
7582 if (lparmp[1] & 0xFFFF0000)
7583 return CM_ERROR_INVAL;
7584 baseFid = (unsigned short)lparmp[1];
7585 desiredAccess = lparmp[2];
7586 #ifdef DEBUG_VERBOSE
7587 allocSize = lparmp[3];
7588 #endif /* DEBUG_VERSOSE */
7589 extAttributes = lparmp[5];
7590 shareAccess = lparmp[6];
7591 createDisp = lparmp[7];
7592 createOptions = lparmp[8];
7593 #ifdef DEBUG_VERBOSE
7596 nameLength = lparmp[11];
7598 #ifdef DEBUG_VERBOSE
7599 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
7600 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
7601 osi_Log1(smb_logp,"... flags[%x]",flags);
7604 /* mustBeDir is never set; createOptions directory bit seems to be
7607 if (createOptions & FILE_DIRECTORY_FILE)
7609 else if (createOptions & FILE_NON_DIRECTORY_FILE)
7615 * compute initial mode bits based on read-only flag in
7616 * extended attributes
7618 initialModeBits = 0666;
7619 if (extAttributes & SMB_ATTR_READONLY)
7620 initialModeBits &= ~0222;
7622 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
7623 pathp = smb_ParseStringCch(inp, pathp, nameLength, NULL, SMB_STRF_ANSIPATH);
7624 /* Sometimes path is not null-terminated, so we make a copy. */
7625 realPathp = malloc(nameLength+1);
7626 memcpy(realPathp, pathp, nameLength);
7627 realPathp[nameLength] = 0;
7628 spacep = cm_GetSpace();
7629 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
7632 * Nothing here to handle SMB_IOCTL_FILENAME.
7633 * Will add it if necessary.
7636 #ifdef DEBUG_VERBOSE
7638 char *hexp, *asciip;
7639 asciip = (lastNamep? lastNamep : realPathp);
7640 hexp = osi_HexifyString( asciip );
7641 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
7646 userp = smb_GetUserFromVCP(vcp, inp);
7648 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
7650 return CM_ERROR_INVAL;
7655 baseDirp = cm_data.rootSCachep;
7656 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7657 if (code == CM_ERROR_TIDIPC) {
7658 /* Attempt to use a TID allocated for IPC. The client
7659 * is probably looking for DCE RPC end points which we
7660 * don't support OR it could be looking to make a DFS
7663 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
7666 cm_ReleaseUser(userp);
7667 return CM_ERROR_NOSUCHPATH;
7671 baseFidp = smb_FindFID(vcp, baseFid, 0);
7673 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
7675 cm_ReleaseUser(userp);
7676 return CM_ERROR_BADFD;
7679 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7681 cm_ReleaseUser(userp);
7682 smb_CloseFID(vcp, baseFidp, NULL, 0);
7683 smb_ReleaseFID(baseFidp);
7684 return CM_ERROR_NOSUCHPATH;
7687 baseDirp = baseFidp->scp;
7691 /* compute open mode */
7693 if (desiredAccess & DELETE)
7694 fidflags |= SMB_FID_OPENDELETE;
7695 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
7696 fidflags |= SMB_FID_OPENREAD_LISTDIR;
7697 if (desiredAccess & AFS_ACCESS_WRITE)
7698 fidflags |= SMB_FID_OPENWRITE;
7699 if (createOptions & FILE_DELETE_ON_CLOSE)
7700 fidflags |= SMB_FID_DELONCLOSE;
7701 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7702 fidflags |= SMB_FID_SEQUENTIAL;
7703 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7704 fidflags |= SMB_FID_RANDOM;
7705 if (smb_IsExecutableFileName(lastNamep))
7706 fidflags |= SMB_FID_EXECUTABLE;
7708 /* And the share mode */
7709 if (shareAccess & FILE_SHARE_READ)
7710 fidflags |= SMB_FID_SHARE_READ;
7711 if (shareAccess & FILE_SHARE_WRITE)
7712 fidflags |= SMB_FID_SHARE_WRITE;
7716 if ( createDisp == FILE_OPEN ||
7717 createDisp == FILE_OVERWRITE ||
7718 createDisp == FILE_OVERWRITE_IF) {
7719 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7720 userp, tidPathp, &req, &dscp);
7723 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7724 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
7725 cm_ReleaseSCache(dscp);
7726 cm_ReleaseUser(userp);
7729 smb_ReleaseFID(baseFidp);
7730 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7731 return CM_ERROR_PATH_NOT_COVERED;
7733 return CM_ERROR_BADSHARENAME;
7735 #endif /* DFS_SUPPORT */
7736 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7738 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7739 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7740 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7741 if (code == 0 && realDirFlag == 1) {
7742 cm_ReleaseSCache(scp);
7743 cm_ReleaseSCache(dscp);
7744 cm_ReleaseUser(userp);
7747 smb_ReleaseFID(baseFidp);
7748 return CM_ERROR_EXISTS;
7754 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7755 userp, tidPathp, &req, &scp);
7757 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7758 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7759 cm_ReleaseSCache(scp);
7760 cm_ReleaseUser(userp);
7763 smb_ReleaseFID(baseFidp);
7764 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7765 return CM_ERROR_PATH_NOT_COVERED;
7767 return CM_ERROR_BADSHARENAME;
7769 #endif /* DFS_SUPPORT */
7775 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7776 /* look up parent directory */
7778 code = cm_NameI(baseDirp, spacep->data,
7779 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7780 userp, tidPathp, &req, &dscp);
7782 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7783 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
7784 cm_ReleaseSCache(dscp);
7785 cm_ReleaseUser(userp);
7788 smb_ReleaseFID(baseFidp);
7789 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7790 return CM_ERROR_PATH_NOT_COVERED;
7792 return CM_ERROR_BADSHARENAME;
7794 #endif /* DFS_SUPPORT */
7798 cm_FreeSpace(spacep);
7801 smb_ReleaseFID(baseFidp);
7804 cm_ReleaseUser(userp);
7810 lastNamep = realPathp;
7814 if (!smb_IsLegalFilename(lastNamep))
7815 return CM_ERROR_BADNTFILENAME;
7818 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
7819 code = cm_Lookup(dscp, lastNamep,
7820 CM_FLAG_FOLLOW, userp, &req, &scp);
7822 code = cm_Lookup(dscp, lastNamep,
7823 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7826 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7827 cm_ReleaseSCache(dscp);
7828 cm_ReleaseUser(userp);
7835 smb_ReleaseFID(baseFidp);
7836 cm_FreeSpace(spacep);
7839 /* if we get here, if code is 0, the file exists and is represented by
7840 * scp. Otherwise, we have to create it. The dir may be represented
7841 * by dscp, or we may have found the file directly. If code is non-zero,
7845 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7848 cm_ReleaseSCache(dscp);
7849 cm_ReleaseSCache(scp);
7850 cm_ReleaseUser(userp);
7855 if (createDisp == FILE_CREATE) {
7856 /* oops, file shouldn't be there */
7857 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7859 cm_ReleaseSCache(dscp);
7860 cm_ReleaseSCache(scp);
7861 cm_ReleaseUser(userp);
7863 return CM_ERROR_EXISTS;
7866 if (createDisp == FILE_OVERWRITE ||
7867 createDisp == FILE_OVERWRITE_IF) {
7868 setAttr.mask = CM_ATTRMASK_LENGTH;
7869 setAttr.length.LowPart = 0;
7870 setAttr.length.HighPart = 0;
7872 /* now watch for a symlink */
7874 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7876 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7878 /* we have a more accurate file to use (the
7879 * target of the symbolic link). Otherwise,
7880 * we'll just use the symlink anyway.
7882 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7884 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7885 cm_ReleaseSCache(scp);
7887 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7890 cm_ReleaseSCache(dscp);
7892 cm_ReleaseSCache(scp);
7893 cm_ReleaseUser(userp);
7899 code = cm_SetAttr(scp, &setAttr, userp, &req);
7900 openAction = 3; /* truncated existing file */
7902 else openAction = 1; /* found existing file */
7904 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7905 /* don't create if not found */
7907 cm_ReleaseSCache(dscp);
7908 cm_ReleaseUser(userp);
7910 return CM_ERROR_NOSUCHFILE;
7912 else if (realDirFlag == 0 || realDirFlag == -1) {
7913 osi_assertx(dscp != NULL, "null cm_scache_t");
7914 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
7915 osi_LogSaveString(smb_logp, lastNamep));
7916 openAction = 2; /* created file */
7917 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7918 setAttr.clientModTime = time(NULL);
7919 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7923 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7924 smb_NotifyChange(FILE_ACTION_ADDED,
7925 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7926 dscp, lastNamep, NULL, TRUE);
7927 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7928 /* Not an exclusive create, and someone else tried
7929 * creating it already, then we open it anyway. We
7930 * don't bother retrying after this, since if this next
7931 * fails, that means that the file was deleted after we
7932 * started this call.
7934 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7937 if (createDisp == FILE_OVERWRITE_IF) {
7938 setAttr.mask = CM_ATTRMASK_LENGTH;
7939 setAttr.length.LowPart = 0;
7940 setAttr.length.HighPart = 0;
7942 /* now watch for a symlink */
7944 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7946 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7948 /* we have a more accurate file to use (the
7949 * target of the symbolic link). Otherwise,
7950 * we'll just use the symlink anyway.
7952 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7954 cm_ReleaseSCache(scp);
7958 code = cm_SetAttr(scp, &setAttr, userp, &req);
7960 } /* lookup succeeded */
7963 /* create directory */
7964 osi_assertx(dscp != NULL, "null cm_scache_t");
7966 "smb_ReceiveNTTranCreate creating directory %s",
7967 osi_LogSaveString(smb_logp, lastNamep));
7968 openAction = 2; /* created directory */
7969 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7970 setAttr.clientModTime = time(NULL);
7971 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
7972 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7973 smb_NotifyChange(FILE_ACTION_ADDED,
7974 FILE_NOTIFY_CHANGE_DIR_NAME,
7975 dscp, lastNamep, NULL, TRUE);
7977 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7978 /* Not an exclusive create, and someone else tried
7979 * creating it already, then we open it anyway. We
7980 * don't bother retrying after this, since if this next
7981 * fails, that means that the file was deleted after we
7982 * started this call.
7984 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7990 /* something went wrong creating or truncating the file */
7992 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7994 cm_ReleaseSCache(scp);
7995 cm_ReleaseUser(userp);
8000 /* make sure we have file vs. dir right */
8001 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
8002 /* now watch for a symlink */
8004 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8006 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8008 /* we have a more accurate file to use (the
8009 * target of the symbolic link). Otherwise,
8010 * we'll just use the symlink anyway.
8012 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8015 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8016 cm_ReleaseSCache(scp);
8021 if (scp->fileType != CM_SCACHETYPE_FILE) {
8023 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8024 cm_ReleaseSCache(scp);
8025 cm_ReleaseUser(userp);
8027 return CM_ERROR_ISDIR;
8031 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8033 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8034 cm_ReleaseSCache(scp);
8035 cm_ReleaseUser(userp);
8037 return CM_ERROR_NOTDIR;
8040 /* open the file itself */
8041 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8042 osi_assertx(fidp, "null smb_fid_t");
8044 /* save a reference to the user */
8046 fidp->userp = userp;
8048 /* If we are restricting sharing, we should do so with a suitable
8050 if (scp->fileType == CM_SCACHETYPE_FILE &&
8051 !(fidflags & SMB_FID_SHARE_WRITE)) {
8053 LARGE_INTEGER LOffset, LLength;
8056 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8057 LOffset.LowPart = SMB_FID_QLOCK_LOW;
8058 LLength.HighPart = 0;
8059 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8061 /* Similar to what we do in handling NTCreateX. We get a
8062 shared lock if we are only opening the file for reading. */
8063 if ((fidflags & SMB_FID_SHARE_READ) ||
8064 !(fidflags & SMB_FID_OPENWRITE)) {
8065 sLockType = LOCKING_ANDX_SHARED_LOCK;
8070 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8072 lock_ObtainWrite(&scp->rw);
8073 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8074 lock_ReleaseWrite(&scp->rw);
8078 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8079 cm_ReleaseSCache(scp);
8080 cm_ReleaseUser(userp);
8081 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
8082 smb_CloseFID(vcp, fidp, NULL, 0);
8083 smb_ReleaseFID(fidp);
8085 return CM_ERROR_SHARING_VIOLATION;
8089 /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
8091 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8093 lock_ObtainMutex(&fidp->mx);
8094 /* save a pointer to the vnode */
8096 lock_ObtainWrite(&scp->rw);
8097 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8098 lock_ReleaseWrite(&scp->rw);
8099 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
8101 fidp->flags = fidflags;
8103 /* remember if the file was newly created */
8105 fidp->flags |= SMB_FID_CREATED;
8107 /* save parent dir and pathname for deletion or change notification */
8108 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8109 fidp->flags |= SMB_FID_NTOPEN;
8110 fidp->NTopen_dscp = dscp;
8111 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
8113 fidp->NTopen_pathp = strdup(lastNamep);
8115 fidp->NTopen_wholepathp = realPathp;
8116 lock_ReleaseMutex(&fidp->mx);
8118 /* we don't need this any longer */
8120 cm_ReleaseSCache(dscp);
8122 cm_Open(scp, 0, userp);
8124 /* set inp->fid so that later read calls in same msg can find fid */
8125 inp->fid = fidp->fid;
8127 /* check whether we are required to send an extended response */
8128 if (!extendedRespRequired) {
8130 parmOffset = 8*4 + 39;
8131 parmOffset += 1; /* pad to 4 */
8132 dataOffset = parmOffset + 70;
8136 /* Total Parameter Count */
8137 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8138 /* Total Data Count */
8139 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8140 /* Parameter Count */
8141 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8142 /* Parameter Offset */
8143 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8144 /* Parameter Displacement */
8145 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8147 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8149 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8150 /* Data Displacement */
8151 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8152 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8153 smb_SetSMBDataLength(outp, 70);
8155 lock_ObtainRead(&scp->rw);
8156 outData = smb_GetSMBData(outp, NULL);
8157 outData++; /* round to get to parmOffset */
8158 *outData = 0; outData++; /* oplock */
8159 *outData = 0; outData++; /* reserved */
8160 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8161 *((ULONG *)outData) = openAction; outData += 4;
8162 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8163 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8164 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8165 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8166 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8167 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8168 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8169 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8170 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8171 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8172 *((USHORT *)outData) = 0; outData += 2; /* dev state */
8173 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8174 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8175 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8176 outData += 2; /* is a dir? */
8179 parmOffset = 8*4 + 39;
8180 parmOffset += 1; /* pad to 4 */
8181 dataOffset = parmOffset + 104;
8185 /* Total Parameter Count */
8186 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8187 /* Total Data Count */
8188 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8189 /* Parameter Count */
8190 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8191 /* Parameter Offset */
8192 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8193 /* Parameter Displacement */
8194 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8196 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8198 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8199 /* Data Displacement */
8200 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8201 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8202 smb_SetSMBDataLength(outp, 105);
8204 lock_ObtainRead(&scp->rw);
8205 outData = smb_GetSMBData(outp, NULL);
8206 outData++; /* round to get to parmOffset */
8207 *outData = 0; outData++; /* oplock */
8208 *outData = 1; outData++; /* response type */
8209 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8210 *((ULONG *)outData) = openAction; outData += 4;
8211 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8212 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8213 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8214 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8215 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8216 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8217 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8218 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8219 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8220 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8221 *((USHORT *)outData) = 0; outData += 2; /* dev state */
8222 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8223 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8224 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8225 outData += 1; /* is a dir? */
8226 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
8227 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
8228 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
8231 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
8232 LargeIntegerGreaterThanZero(fidp->scp->length) &&
8233 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
8234 cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
8235 fidp->scp->length.LowPart, fidp->scp->length.HighPart,
8238 lock_ReleaseRead(&scp->rw);
8240 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
8242 cm_ReleaseUser(userp);
8243 smb_ReleaseFID(fidp);
8245 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
8246 /* leave scp held since we put it in fidp->scp */
8250 /* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
8251 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
8254 smb_packet_t *savedPacketp;
8256 USHORT fid, watchtree;
8260 filter = smb_GetSMBParm(inp, 19) |
8261 (smb_GetSMBParm(inp, 20) << 16);
8262 fid = smb_GetSMBParm(inp, 21);
8263 watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
8265 fidp = smb_FindFID(vcp, fid, 0);
8267 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
8268 return CM_ERROR_BADFD;
8271 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8272 smb_CloseFID(vcp, fidp, NULL, 0);
8273 smb_ReleaseFID(fidp);
8274 return CM_ERROR_NOSUCHFILE;
8277 /* Create a copy of the Directory Watch Packet to use when sending the
8278 * notification if in the future a matching change is detected.
8280 savedPacketp = smb_CopyPacket(inp);
8282 if (savedPacketp->vcp)
8283 smb_ReleaseVC(savedPacketp->vcp);
8284 savedPacketp->vcp = vcp;
8286 /* Add the watch to the list of events to send notifications for */
8287 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8288 savedPacketp->nextp = smb_Directory_Watches;
8289 smb_Directory_Watches = savedPacketp;
8290 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8293 osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%s\"",
8294 fidp, scp, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
8295 osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
8296 filter, fid, watchtree);
8297 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8298 osi_Log0(smb_logp, " Notify Change File Name");
8299 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8300 osi_Log0(smb_logp, " Notify Change Directory Name");
8301 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8302 osi_Log0(smb_logp, " Notify Change Attributes");
8303 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8304 osi_Log0(smb_logp, " Notify Change Size");
8305 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8306 osi_Log0(smb_logp, " Notify Change Last Write");
8307 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8308 osi_Log0(smb_logp, " Notify Change Last Access");
8309 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8310 osi_Log0(smb_logp, " Notify Change Creation");
8311 if (filter & FILE_NOTIFY_CHANGE_EA)
8312 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8313 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8314 osi_Log0(smb_logp, " Notify Change Security");
8315 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8316 osi_Log0(smb_logp, " Notify Change Stream Name");
8317 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8318 osi_Log0(smb_logp, " Notify Change Stream Size");
8319 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8320 osi_Log0(smb_logp, " Notify Change Stream Write");
8322 lock_ObtainWrite(&scp->rw);
8324 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
8326 scp->flags |= CM_SCACHEFLAG_WATCHED;
8327 lock_ReleaseWrite(&scp->rw);
8328 smb_ReleaseFID(fidp);
8330 outp->flags |= SMB_PACKETFLAG_NOSEND;
8334 unsigned char nullSecurityDesc[36] = {
8335 0x01, /* security descriptor revision */
8336 0x00, /* reserved, should be zero */
8337 0x00, 0x80, /* security descriptor control;
8338 * 0x8000 : self-relative format */
8339 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
8340 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
8341 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
8342 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
8343 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8344 /* "null SID" owner SID */
8345 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
8346 /* "null SID" group SID */
8349 /* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
8350 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8352 int parmOffset, parmCount, dataOffset, dataCount;
8360 ULONG securityInformation;
8362 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8363 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8364 parmp = inp->data + parmOffset;
8365 sparmp = (USHORT *) parmp;
8366 lparmp = (ULONG *) parmp;
8369 securityInformation = lparmp[1];
8371 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
8372 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
8380 parmOffset = 8*4 + 39;
8381 parmOffset += 1; /* pad to 4 */
8383 dataOffset = parmOffset + parmCount;
8387 /* Total Parameter Count */
8388 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8389 /* Total Data Count */
8390 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8391 /* Parameter Count */
8392 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8393 /* Parameter Offset */
8394 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8395 /* Parameter Displacement */
8396 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8398 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8400 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8401 /* Data Displacement */
8402 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8403 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8404 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
8406 outData = smb_GetSMBData(outp, NULL);
8407 outData++; /* round to get to parmOffset */
8408 *((ULONG *)outData) = 36; outData += 4; /* length */
8410 if (maxData >= 36) {
8411 memcpy(outData, nullSecurityDesc, 36);
8415 return CM_ERROR_BUFFERTOOSMALL;
8418 /* SMB_COM_NT_TRANSACT
8420 SMB_COM_NT_TRANSACT_SECONDARY should also be handled here.
8422 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8424 unsigned short function;
8426 function = smb_GetSMBParm(inp, 18);
8428 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
8430 /* We can handle long names */
8431 if (vcp->flags & SMB_VCFLAG_USENT)
8432 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
8435 case 1: /* NT_TRANSACT_CREATE */
8436 return smb_ReceiveNTTranCreate(vcp, inp, outp);
8437 case 2: /* NT_TRANSACT_IOCTL */
8438 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
8440 case 3: /* NT_TRANSACT_SET_SECURITY_DESC */
8441 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
8443 case 4: /* NT_TRANSACT_NOTIFY_CHANGE */
8444 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
8445 case 5: /* NT_TRANSACT_RENAME */
8446 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
8448 case 6: /* NT_TRANSACT_QUERY_SECURITY_DESC */
8449 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
8451 osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
8454 osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
8457 return CM_ERROR_INVAL;
8461 * smb_NotifyChange -- find relevant change notification messages and
8464 * If we don't know the file name (i.e. a callback break), filename is
8465 * NULL, and we return a zero-length list.
8467 * At present there is not a single call to smb_NotifyChange that
8468 * has the isDirectParent parameter set to FALSE.
8470 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
8471 cm_scache_t *dscp, char *filename, char *otherFilename,
8472 BOOL isDirectParent)
8474 smb_packet_t *watch, *lastWatch, *nextWatch;
8475 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
8476 char *outData, *oldOutData;
8480 BOOL twoEntries = FALSE;
8481 ULONG otherNameLen, oldParmCount = 0;
8485 /* Get ready for rename within directory */
8486 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
8488 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
8491 osi_Log4(smb_logp,"in smb_NotifyChange for file [%s] dscp [%p] notification 0x%x parent %d",
8492 osi_LogSaveString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
8494 osi_Log0(smb_logp," FILE_ACTION_NONE");
8495 if (action == FILE_ACTION_ADDED)
8496 osi_Log0(smb_logp," FILE_ACTION_ADDED");
8497 if (action == FILE_ACTION_REMOVED)
8498 osi_Log0(smb_logp," FILE_ACTION_REMOVED");
8499 if (action == FILE_ACTION_MODIFIED)
8500 osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
8501 if (action == FILE_ACTION_RENAMED_OLD_NAME)
8502 osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
8503 if (action == FILE_ACTION_RENAMED_NEW_NAME)
8504 osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
8506 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8507 watch = smb_Directory_Watches;
8509 filter = smb_GetSMBParm(watch, 19)
8510 | (smb_GetSMBParm(watch, 20) << 16);
8511 fid = smb_GetSMBParm(watch, 21);
8512 wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
8514 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
8515 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
8518 * Strange hack - bug in NT Client and NT Server that we must emulate?
8520 if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
8521 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
8523 fidp = smb_FindFID(watch->vcp, fid, 0);
8525 osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
8527 watch = watch->nextp;
8531 if (fidp->scp != dscp ||
8532 fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
8533 (filter & notifyFilter) == 0 ||
8534 (!isDirectParent && !wtree))
8536 osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
8537 smb_ReleaseFID(fidp);
8539 watch = watch->nextp;
8542 smb_ReleaseFID(fidp);
8545 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
8546 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
8547 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8548 osi_Log0(smb_logp, " Notify Change File Name");
8549 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8550 osi_Log0(smb_logp, " Notify Change Directory Name");
8551 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8552 osi_Log0(smb_logp, " Notify Change Attributes");
8553 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8554 osi_Log0(smb_logp, " Notify Change Size");
8555 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8556 osi_Log0(smb_logp, " Notify Change Last Write");
8557 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8558 osi_Log0(smb_logp, " Notify Change Last Access");
8559 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8560 osi_Log0(smb_logp, " Notify Change Creation");
8561 if (filter & FILE_NOTIFY_CHANGE_EA)
8562 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8563 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8564 osi_Log0(smb_logp, " Notify Change Security");
8565 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8566 osi_Log0(smb_logp, " Notify Change Stream Name");
8567 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8568 osi_Log0(smb_logp, " Notify Change Stream Size");
8569 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8570 osi_Log0(smb_logp, " Notify Change Stream Write");
8572 /* A watch can only be notified once. Remove it from the list */
8573 nextWatch = watch->nextp;
8574 if (watch == smb_Directory_Watches)
8575 smb_Directory_Watches = nextWatch;
8577 lastWatch->nextp = nextWatch;
8579 /* Turn off WATCHED flag in dscp */
8580 lock_ObtainWrite(&dscp->rw);
8582 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8584 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
8585 lock_ReleaseWrite(&dscp->rw);
8587 /* Convert to response packet */
8588 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
8589 #ifdef SEND_CANONICAL_PATHNAMES
8590 ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
8592 ((smb_t *) watch)->wct = 0;
8595 if (filename == NULL)
8598 nameLen = (ULONG)strlen(filename);
8599 parmCount = 3*4 + nameLen*2;
8600 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8602 otherNameLen = (ULONG)strlen(otherFilename);
8603 oldParmCount = parmCount;
8604 parmCount += 3*4 + otherNameLen*2;
8605 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8607 if (maxLen < parmCount)
8608 parmCount = 0; /* not enough room */
8610 parmOffset = 8*4 + 39;
8611 parmOffset += 1; /* pad to 4 */
8612 dataOffset = parmOffset + parmCount;
8616 /* Total Parameter Count */
8617 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8618 /* Total Data Count */
8619 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8620 /* Parameter Count */
8621 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8622 /* Parameter Offset */
8623 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
8624 /* Parameter Displacement */
8625 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8627 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8629 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
8630 /* Data Displacement */
8631 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8632 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
8633 smb_SetSMBDataLength(watch, parmCount + 1);
8635 if (parmCount != 0) {
8637 outData = smb_GetSMBData(watch, NULL);
8638 outData++; /* round to get to parmOffset */
8639 oldOutData = outData;
8640 *((DWORD *)outData) = oldParmCount; outData += 4;
8641 /* Next Entry Offset */
8642 *((DWORD *)outData) = action; outData += 4;
8644 *((DWORD *)outData) = nameLen*2; outData += 4;
8645 /* File Name Length */
8646 p = strdup(filename);
8647 if (smb_StoreAnsiFilenames)
8649 mbstowcs((WCHAR *)outData, p, nameLen);
8653 outData = oldOutData + oldParmCount;
8654 *((DWORD *)outData) = 0; outData += 4;
8655 /* Next Entry Offset */
8656 *((DWORD *)outData) = otherAction; outData += 4;
8658 *((DWORD *)outData) = otherNameLen*2;
8659 outData += 4; /* File Name Length */
8660 p = strdup(otherFilename);
8661 if (smb_StoreAnsiFilenames)
8663 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
8669 * If filename is null, we don't know the cause of the
8670 * change notification. We return zero data (see above),
8671 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
8672 * (= 0x010C). We set the error code here by hand, without
8673 * modifying wct and bcc.
8675 if (filename == NULL) {
8676 ((smb_t *) watch)->rcls = 0x0C;
8677 ((smb_t *) watch)->reh = 0x01;
8678 ((smb_t *) watch)->errLow = 0;
8679 ((smb_t *) watch)->errHigh = 0;
8680 /* Set NT Status codes flag */
8681 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8684 smb_SendPacket(watch->vcp, watch);
8685 smb_FreePacket(watch);
8688 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8691 /* SMB_COM_NT_CANCEL */
8692 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8694 unsigned char *replyWctp;
8695 smb_packet_t *watch, *lastWatch;
8696 USHORT fid, watchtree;
8700 osi_Log0(smb_logp, "SMB3 receive NT cancel");
8702 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8703 watch = smb_Directory_Watches;
8705 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
8706 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
8707 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
8708 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
8709 if (watch == smb_Directory_Watches)
8710 smb_Directory_Watches = watch->nextp;
8712 lastWatch->nextp = watch->nextp;
8713 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8715 /* Turn off WATCHED flag in scp */
8716 fid = smb_GetSMBParm(watch, 21);
8717 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
8719 if (vcp != watch->vcp)
8720 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
8723 fidp = smb_FindFID(vcp, fid, 0);
8725 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
8727 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
8730 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
8731 lock_ObtainWrite(&scp->rw);
8733 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8735 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
8736 lock_ReleaseWrite(&scp->rw);
8737 smb_ReleaseFID(fidp);
8739 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
8742 /* assume STATUS32; return 0xC0000120 (CANCELED) */
8743 replyWctp = watch->wctp;
8747 ((smb_t *)watch)->rcls = 0x20;
8748 ((smb_t *)watch)->reh = 0x1;
8749 ((smb_t *)watch)->errLow = 0;
8750 ((smb_t *)watch)->errHigh = 0xC0;
8751 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8752 smb_SendPacket(vcp, watch);
8753 smb_FreePacket(watch);
8757 watch = watch->nextp;
8759 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8765 * NT rename also does hard links.
8768 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
8769 #define RENAME_FLAG_HARD_LINK 0x103
8770 #define RENAME_FLAG_RENAME 0x104
8771 #define RENAME_FLAG_COPY 0x105
8773 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8775 char *oldPathp, *newPathp;
8781 attrs = smb_GetSMBParm(inp, 0);
8782 rename_type = smb_GetSMBParm(inp, 1);
8784 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
8785 osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
8786 return CM_ERROR_NOACCESS;
8789 tp = smb_GetSMBData(inp, NULL);
8790 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
8791 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
8793 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
8794 osi_LogSaveString(smb_logp, oldPathp),
8795 osi_LogSaveString(smb_logp, newPathp),
8796 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
8798 if (rename_type == RENAME_FLAG_RENAME) {
8799 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
8800 } else { /* RENAME_FLAG_HARD_LINK */
8801 code = smb_Link(vcp,inp,oldPathp,newPathp);
8808 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
8811 cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
8813 smb_username_t *unp;
8816 unp = smb_FindUserByName(usern, machine, flags);
8818 lock_ObtainMutex(&unp->mx);
8819 unp->userp = cm_NewUser();
8820 lock_ReleaseMutex(&unp->mx);
8821 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
8823 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
8827 smb_ReleaseUsername(unp);