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>
34 extern osi_hyper_t hzero;
36 smb_packet_t *smb_Directory_Watches = NULL;
37 osi_mutex_t smb_Dir_Watch_Lock;
39 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
41 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
43 /* protected by the smb_globalLock */
44 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
46 const char **smb_ExecutableExtensions = NULL;
48 /* retrieve a held reference to a user structure corresponding to an incoming
50 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
55 uidp = smb_FindUID(vcp, inp->uid, 0);
59 up = smb_GetUserFromUID(uidp);
67 * Return boolean specifying if the path name is thought to be an
68 * executable file. For now .exe or .dll.
70 afs_uint32 smb_IsExecutableFileName(const char *name)
74 if ( smb_ExecutableExtensions == NULL || name == NULL)
77 len = (int)strlen(name);
79 for ( i=0; smb_ExecutableExtensions[i]; i++) {
80 j = len - (int)strlen(smb_ExecutableExtensions[i]);
81 if (cm_stricmp_utf8N(smb_ExecutableExtensions[i], &name[j]) == 0)
89 * Return extended attributes.
90 * Right now, we aren't using any of the "new" bits, so this looks exactly
91 * like smb_Attributes() (see smb.c).
93 unsigned long smb_ExtAttributes(cm_scache_t *scp)
97 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
98 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
99 scp->fileType == CM_SCACHETYPE_INVALID)
101 attrs = SMB_ATTR_DIRECTORY;
102 #ifdef SPECIAL_FOLDERS
103 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
104 #endif /* SPECIAL_FOLDERS */
105 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
106 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
110 * We used to mark a file RO if it was in an RO volume, but that
111 * turns out to be impolitic in NT. See defect 10007.
114 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
115 attrs |= SMB_ATTR_READONLY; /* Read-only */
117 if ((scp->unixModeBits & 0222) == 0)
118 attrs |= SMB_ATTR_READONLY; /* Read-only */
122 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
127 int smb_V3IsStarMask(char *maskp)
131 while (tc = *maskp++)
132 if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
137 void OutputDebugF(char * format, ...) {
142 va_start( args, format );
143 len = _vscprintf( format, args ) // _vscprintf doesn't count
144 + 3; // terminating '\0' + '\n'
145 buffer = malloc( len * sizeof(char) );
146 vsprintf( buffer, format, args );
147 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buffer));
148 strcat(buffer, "\n");
149 OutputDebugString(buffer);
153 void OutputDebugHexDump(unsigned char * buffer, int len) {
156 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
158 OutputDebugF("Hexdump length [%d]",len);
160 for (i=0;i<len;i++) {
163 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
165 OutputDebugString(buf);
167 sprintf(buf,"%5x",i);
168 memset(buf+5,' ',80);
173 j = j*3 + 7 + ((j>7)?1:0);
176 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
179 j = j + 56 + ((j>7)?1:0);
181 buf[j] = (k>32 && k<127)?k:'.';
184 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
186 OutputDebugString(buf);
190 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
192 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
193 SECURITY_STATUS status, istatus;
194 CredHandle creds = {0,0};
196 SecBufferDesc secOut;
204 OutputDebugF("Negotiating Extended Security");
206 status = AcquireCredentialsHandle( NULL,
207 SMB_EXT_SEC_PACKAGE_NAME,
216 if (status != SEC_E_OK) {
217 /* Really bad. We return an empty security blob */
218 OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
223 secOut.pBuffers = &secTok;
224 secOut.ulVersion = SECBUFFER_VERSION;
226 secTok.BufferType = SECBUFFER_TOKEN;
228 secTok.pvBuffer = NULL;
230 ctx.dwLower = ctx.dwUpper = 0;
232 status = AcceptSecurityContext( &creds,
235 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
236 SECURITY_NETWORK_DREP,
243 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
244 OutputDebugF("Completing token...");
245 istatus = CompleteAuthToken(&ctx, &secOut);
246 if ( istatus != SEC_E_OK )
247 OutputDebugF("Token completion failed: %x", istatus);
250 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
251 if (secTok.pvBuffer) {
252 *secBlobLength = secTok.cbBuffer;
253 *secBlob = malloc( secTok.cbBuffer );
254 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
257 if ( status != SEC_E_OK )
258 OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
261 /* Discard partial security context */
262 DeleteSecurityContext(&ctx);
264 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
266 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
267 FreeCredentialsHandle(&creds);
273 struct smb_ext_context {
280 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
281 SECURITY_STATUS status, istatus;
285 SecBufferDesc secBufIn;
287 SecBufferDesc secBufOut;
290 struct smb_ext_context * secCtx = NULL;
291 struct smb_ext_context * newSecCtx = NULL;
292 void * assembledBlob = NULL;
293 int assembledBlobLength = 0;
296 OutputDebugF("In smb_AuthenticateUserExt");
299 *secBlobOutLength = 0;
301 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
302 secCtx = vcp->secCtx;
303 lock_ObtainMutex(&vcp->mx);
304 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
306 lock_ReleaseMutex(&vcp->mx);
310 OutputDebugF("Received incoming token:");
311 OutputDebugHexDump(secBlobIn,secBlobInLength);
315 OutputDebugF("Continuing with existing context.");
316 creds = secCtx->creds;
319 if (secCtx->partialToken) {
320 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
321 assembledBlob = malloc(assembledBlobLength);
322 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
323 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
326 status = AcquireCredentialsHandle( NULL,
327 SMB_EXT_SEC_PACKAGE_NAME,
336 if (status != SEC_E_OK) {
337 OutputDebugF("Can't acquire Credentials handle [%lX]", status);
338 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
346 secBufIn.cBuffers = 1;
347 secBufIn.pBuffers = &secTokIn;
348 secBufIn.ulVersion = SECBUFFER_VERSION;
350 secTokIn.BufferType = SECBUFFER_TOKEN;
352 secTokIn.cbBuffer = assembledBlobLength;
353 secTokIn.pvBuffer = assembledBlob;
355 secTokIn.cbBuffer = secBlobInLength;
356 secTokIn.pvBuffer = secBlobIn;
359 secBufOut.cBuffers = 1;
360 secBufOut.pBuffers = &secTokOut;
361 secBufOut.ulVersion = SECBUFFER_VERSION;
363 secTokOut.BufferType = SECBUFFER_TOKEN;
364 secTokOut.cbBuffer = 0;
365 secTokOut.pvBuffer = NULL;
367 status = AcceptSecurityContext( &creds,
368 ((secCtx)?&ctx:NULL),
370 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
371 SECURITY_NETWORK_DREP,
378 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
379 OutputDebugF("Completing token...");
380 istatus = CompleteAuthToken(&ctx, &secBufOut);
381 if ( istatus != SEC_E_OK )
382 OutputDebugF("Token completion failed: %lX", istatus);
385 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
386 OutputDebugF("Continue needed");
388 newSecCtx = malloc(sizeof(*newSecCtx));
390 newSecCtx->creds = creds;
391 newSecCtx->ctx = ctx;
392 newSecCtx->partialToken = NULL;
393 newSecCtx->partialTokenLen = 0;
395 lock_ObtainMutex( &vcp->mx );
396 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
397 vcp->secCtx = newSecCtx;
398 lock_ReleaseMutex( &vcp->mx );
400 code = CM_ERROR_GSSCONTINUE;
403 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
404 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
405 secTokOut.pvBuffer) {
406 OutputDebugF("Need to send token back to client");
408 *secBlobOutLength = secTokOut.cbBuffer;
409 *secBlobOut = malloc(secTokOut.cbBuffer);
410 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
412 OutputDebugF("Outgoing token:");
413 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
414 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
415 OutputDebugF("Incomplete message");
417 newSecCtx = malloc(sizeof(*newSecCtx));
419 newSecCtx->creds = creds;
420 newSecCtx->ctx = ctx;
421 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
422 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
423 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
425 lock_ObtainMutex( &vcp->mx );
426 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
427 vcp->secCtx = newSecCtx;
428 lock_ReleaseMutex( &vcp->mx );
430 code = CM_ERROR_GSSCONTINUE;
433 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
435 SecPkgContext_Names names;
437 OutputDebugF("Authentication completed");
438 OutputDebugF("Returned flags : [%lX]", flags);
440 if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
441 OutputDebugF("Received name [%s]", names.sUserName);
442 strcpy(usern, names.sUserName);
443 strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
444 FreeContextBuffer(names.sUserName);
446 /* Force the user to retry if the context is invalid */
447 OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
448 code = CM_ERROR_BADPASSWORD;
452 case SEC_E_INVALID_TOKEN:
453 OutputDebugF("Returning bad password :: INVALID_TOKEN");
455 case SEC_E_INVALID_HANDLE:
456 OutputDebugF("Returning bad password :: INVALID_HANDLE");
458 case SEC_E_LOGON_DENIED:
459 OutputDebugF("Returning bad password :: LOGON_DENIED");
461 case SEC_E_UNKNOWN_CREDENTIALS:
462 OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
464 case SEC_E_NO_CREDENTIALS:
465 OutputDebugF("Returning bad password :: NO_CREDENTIALS");
467 case SEC_E_CONTEXT_EXPIRED:
468 OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
470 case SEC_E_INCOMPLETE_CREDENTIALS:
471 OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
473 case SEC_E_WRONG_PRINCIPAL:
474 OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
476 case SEC_E_TIME_SKEW:
477 OutputDebugF("Returning bad password :: TIME_SKEW");
480 OutputDebugF("Returning bad password :: Status == %lX", status);
482 code = CM_ERROR_BADPASSWORD;
486 if (secCtx->partialToken) free(secCtx->partialToken);
494 if (secTokOut.pvBuffer)
495 FreeContextBuffer(secTokOut.pvBuffer);
497 if (code != CM_ERROR_GSSCONTINUE) {
498 DeleteSecurityContext(&ctx);
499 FreeCredentialsHandle(&creds);
507 #define P_RESP_LEN 128
509 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
510 So put stuff in a struct. */
511 struct Lm20AuthBlob {
512 MSV1_0_LM20_LOGON lmlogon;
513 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
514 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
515 WCHAR accountNameW[P_LEN];
516 WCHAR primaryDomainW[P_LEN];
517 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
518 TOKEN_GROUPS tgroups;
519 TOKEN_SOURCE tsource;
522 long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
525 struct Lm20AuthBlob lmAuth;
526 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
527 QUOTA_LIMITS quotaLimits;
529 ULONG lmprofilepSize;
533 OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
534 OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
536 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
537 OutputDebugF("ciPwdLength or csPwdLength is too long");
538 return CM_ERROR_BADPASSWORD;
541 memset(&lmAuth,0,sizeof(lmAuth));
543 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
545 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
546 mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
547 lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
548 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
550 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
551 mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
552 lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
553 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
555 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
556 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
557 size = MAX_COMPUTERNAME_LENGTH + 1;
558 GetComputerNameW(lmAuth.workstationW, &size);
559 lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
561 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
563 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
564 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
565 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
566 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
568 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
569 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
570 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
571 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
573 lmAuth.lmlogon.ParameterControl = 0;
575 lmAuth.tgroups.GroupCount = 0;
576 lmAuth.tgroups.Groups[0].Sid = NULL;
577 lmAuth.tgroups.Groups[0].Attributes = 0;
579 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
580 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
581 strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
583 nts = LsaLogonUser( smb_lsaHandle,
598 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
599 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
602 OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
603 OutputDebugF("Extended status is 0x%lX", ntsEx);
605 if (nts == ERROR_SUCCESS) {
607 LsaFreeReturnBuffer(lmprofilep);
608 CloseHandle(lmToken);
612 if (nts == 0xC000015BL)
613 return CM_ERROR_BADLOGONTYPE;
614 else /* our catchall is a bad password though we could be more specific */
615 return CM_ERROR_BADPASSWORD;
619 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
620 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName)
625 /* check if we have sane input */
626 if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
629 /* we could get : [accountName][domainName]
635 atsign = strchr(accountName, '@');
637 if (atsign) /* [user@domain][] -> [user@domain][domain] */
642 /* if for some reason the client doesn't know what domain to use,
643 it will either return an empty string or a '?' */
644 if (!domain[0] || domain[0] == '?')
645 /* Empty domains and empty usernames are usually sent from tokenless contexts.
646 This way such logins will get an empty username (easy to check). I don't know
647 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
648 strcpy(usern,accountName);
650 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
651 strcpy(usern,domain);
654 strncat(usern,accountName,atsign - accountName);
656 strcat(usern,accountName);
664 /* When using SMB auth, all SMB sessions have to pass through here
665 * first to authenticate the user.
667 * Caveat: If not using SMB auth, the protocol does not require
668 * sending a session setup packet, which means that we can't rely on a
669 * UID in subsequent packets. Though in practice we get one anyway.
671 /* SMB_COM_SESSION_SETUP_ANDX */
672 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
676 unsigned short newUid;
677 unsigned long caps = 0;
681 char usern[SMB_MAX_USERNAME_LENGTH];
682 char *secBlobOut = NULL;
683 int secBlobOutLength = 0;
685 /* Check for bad conns */
686 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
687 return CM_ERROR_REMOTECONN;
689 if (vcp->flags & SMB_VCFLAG_USENT) {
690 if (smb_authType == SMB_AUTH_EXTENDED) {
691 /* extended authentication */
695 OutputDebugF("NT Session Setup: Extended");
697 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
698 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
701 secBlobInLength = smb_GetSMBParm(inp, 7);
702 secBlobIn = smb_GetSMBData(inp, NULL);
704 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
706 if (code == CM_ERROR_GSSCONTINUE) {
709 smb_SetSMBParm(outp, 2, 0);
710 smb_SetSMBParm(outp, 3, secBlobOutLength);
712 tp = smb_GetSMBData(outp, NULL);
713 if (secBlobOutLength) {
714 memcpy(tp, secBlobOut, secBlobOutLength);
716 tp += secBlobOutLength;
717 cb_data += secBlobOutLength;
719 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
720 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
721 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
723 smb_SetSMBDataLength(outp, cb_data);
726 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
728 unsigned ciPwdLength, csPwdLength;
734 if (smb_authType == SMB_AUTH_NTLM)
735 OutputDebugF("NT Session Setup: NTLM");
737 OutputDebugF("NT Session Setup: None");
739 /* TODO: parse for extended auth as well */
740 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
741 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
743 tp = smb_GetSMBData(inp, &datalen);
745 OutputDebugF("Session packet data size [%d]",datalen);
752 accountName = smb_ParseString(inp, tp, &tp, 0);
753 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
755 OutputDebugF("Account Name: %s",accountName);
756 OutputDebugF("Primary Domain: %s", primaryDomain);
757 OutputDebugF("Case Sensitive Password: %s", csPwd && csPwd[0] ? "yes" : "no");
758 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
760 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
761 /* shouldn't happen */
762 code = CM_ERROR_BADSMB;
763 goto after_read_packet;
766 /* capabilities are only valid for first session packet */
767 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
768 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
771 if (smb_authType == SMB_AUTH_NTLM) {
772 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
774 OutputDebugF("LM authentication failed [%d]", code);
776 OutputDebugF("LM authentication succeeded");
780 unsigned ciPwdLength;
785 switch ( smb_authType ) {
786 case SMB_AUTH_EXTENDED:
787 OutputDebugF("V3 Session Setup: Extended");
790 OutputDebugF("V3 Session Setup: NTLM");
793 OutputDebugF("V3 Session Setup: None");
795 ciPwdLength = smb_GetSMBParm(inp, 7);
796 tp = smb_GetSMBData(inp, NULL);
800 accountName = smb_ParseString(inp, tp, &tp, 0);
801 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
803 OutputDebugF("Account Name: %s",accountName);
804 OutputDebugF("Primary Domain: %s", primaryDomain);
805 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
807 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
808 /* shouldn't happen */
809 code = CM_ERROR_BADSMB;
810 goto after_read_packet;
813 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
816 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
817 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
819 OutputDebugF("LM authentication failed [%d]", code);
821 OutputDebugF("LM authentication succeeded");
826 /* note down that we received a session setup X and set the capabilities flag */
827 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
828 lock_ObtainMutex(&vcp->mx);
829 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
830 /* for the moment we can only deal with NTSTATUS */
831 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
832 vcp->flags |= SMB_VCFLAG_STATUS32;
836 if ((caps & NTNEGOTIATE_CAPABILITY_UNICODE) && smb_UseUnicode) {
837 vcp->flags |= SMB_VCFLAG_USEUNICODE;
840 lock_ReleaseMutex(&vcp->mx);
843 /* code would be non-zero if there was an authentication failure.
844 Ideally we would like to invalidate the uid for this session or break
845 early to avoid accidently stealing someone else's tokens. */
851 OutputDebugF("Received username=[%s]", usern);
853 /* On Windows 2000, this function appears to be called more often than
854 it is expected to be called. This resulted in multiple smb_user_t
855 records existing all for the same user session which results in all
856 of the users tokens disappearing.
858 To avoid this problem, we look for an existing smb_user_t record
859 based on the users name, and use that one if we find it.
862 uidp = smb_FindUserByNameThisSession(vcp, usern);
863 if (uidp) { /* already there, so don't create a new one */
865 newUid = uidp->userID;
866 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
867 vcp->lana,vcp->lsn,newUid);
868 smb_ReleaseUID(uidp);
873 /* do a global search for the username/machine name pair */
874 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
875 lock_ObtainMutex(&unp->mx);
876 if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
877 /* clear the afslogon flag so that the tickets can now
878 * be freed when the refCount returns to zero.
880 unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
882 lock_ReleaseMutex(&unp->mx);
884 /* Create a new UID and cm_user_t structure */
887 userp = cm_NewUser();
888 cm_HoldUserVCRef(userp);
889 lock_ObtainMutex(&vcp->mx);
890 if (!vcp->uidCounter)
891 vcp->uidCounter++; /* handle unlikely wraparounds */
892 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
893 lock_ReleaseMutex(&vcp->mx);
895 /* Create a new smb_user_t structure and connect them up */
896 lock_ObtainMutex(&unp->mx);
898 lock_ReleaseMutex(&unp->mx);
900 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
902 lock_ObtainMutex(&uidp->mx);
904 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
905 lock_ReleaseMutex(&uidp->mx);
906 smb_ReleaseUID(uidp);
910 /* Return UID to the client */
911 ((smb_t *)outp)->uid = newUid;
912 /* Also to the next chained message */
913 ((smb_t *)inp)->uid = newUid;
915 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
916 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
918 smb_SetSMBParm(outp, 2, 0);
920 if (vcp->flags & SMB_VCFLAG_USENT) {
921 if (smb_authType == SMB_AUTH_EXTENDED) {
924 smb_SetSMBParm(outp, 3, secBlobOutLength);
926 tp = smb_GetSMBData(outp, NULL);
927 if (secBlobOutLength) {
928 memcpy(tp, secBlobOut, secBlobOutLength);
930 tp += secBlobOutLength;
931 cb_data += secBlobOutLength;
934 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
935 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
936 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
938 smb_SetSMBDataLength(outp, cb_data);
940 smb_SetSMBDataLength(outp, 0);
943 if (smb_authType == SMB_AUTH_EXTENDED) {
946 tp = smb_GetSMBData(outp, NULL);
948 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
949 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
950 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
952 smb_SetSMBDataLength(outp, cb_data);
954 smb_SetSMBDataLength(outp, 0);
961 /* SMB_COM_LOGOFF_ANDX */
962 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
966 /* find the tree and free it */
967 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
969 smb_username_t * unp;
971 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %s", uidp->userID,
972 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "));
974 lock_ObtainMutex(&uidp->mx);
975 uidp->flags |= SMB_USERFLAG_DELETE;
977 * it doesn't get deleted right away
978 * because the vcp points to it
981 lock_ReleaseMutex(&uidp->mx);
984 /* we can't do this. we get logoff messages prior to a session
985 * disconnect even though it doesn't mean the user is logging out.
986 * we need to create a new pioctl and EventLogoff handler to set
987 * SMB_USERNAMEFLAG_LOGOFF.
989 if (unp && smb_LogoffTokenTransfer) {
990 lock_ObtainMutex(&unp->mx);
991 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
992 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
993 lock_ReleaseMutex(&unp->mx);
997 smb_ReleaseUID(uidp);
1000 osi_Log0(smb_logp, "SMB3 user logoffX");
1002 smb_SetSMBDataLength(outp, 0);
1006 #define SMB_SUPPORT_SEARCH_BITS 0x0001
1007 #define SMB_SHARE_IS_IN_DFS 0x0002
1009 /* SMB_COM_TREE_CONNECT_ANDX */
1010 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1013 smb_user_t *uidp = NULL;
1014 unsigned short newTid;
1015 char shareName[AFSPATHMAX];
1022 cm_user_t *userp = NULL;
1025 osi_Log0(smb_logp, "SMB3 receive tree connect");
1027 /* parse input parameters */
1028 tp = smb_GetSMBData(inp, NULL);
1029 passwordp = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1030 pathp = smb_ParseString(inp, tp, &tp, SMB_STRF_ANSIPATH);
1031 servicep = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1033 tp = strrchr(pathp, '\\');
1035 return CM_ERROR_BADSMB;
1037 strcpy(shareName, tp+1);
1039 osi_Log3(smb_logp, "Tree connect pathp[%s] shareName[%s] service[%s]",
1040 osi_LogSaveString(smb_logp, pathp),
1041 osi_LogSaveString(smb_logp, shareName),
1042 osi_LogSaveString(smb_logp, servicep));
1044 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
1046 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1049 return CM_ERROR_NOIPC;
1053 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1055 userp = smb_GetUserFromUID(uidp);
1057 lock_ObtainMutex(&vcp->mx);
1058 newTid = vcp->tidCounter++;
1059 lock_ReleaseMutex(&vcp->mx);
1061 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1064 if (!strcmp(shareName, "*."))
1065 strcpy(shareName, "all");
1066 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1069 smb_ReleaseUID(uidp);
1070 smb_ReleaseTID(tidp, FALSE);
1071 return CM_ERROR_BADSHARENAME;
1074 if (vcp->flags & SMB_VCFLAG_USENT)
1076 int policy = smb_FindShareCSCPolicy(shareName);
1079 DWORD dwAdvertiseDFS = 0, dwSize = sizeof(DWORD);
1081 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1082 0, KEY_QUERY_VALUE, &parmKey);
1083 if (code == ERROR_SUCCESS) {
1084 code = RegQueryValueEx(parmKey, "AdvertiseDFS", NULL, NULL,
1085 (BYTE *)&dwAdvertiseDFS, &dwSize);
1086 if (code != ERROR_SUCCESS)
1088 RegCloseKey (parmKey);
1090 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1091 (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
1095 smb_SetSMBParm(outp, 2, 0);
1099 smb_ReleaseUID(uidp);
1101 lock_ObtainMutex(&tidp->mx);
1102 tidp->userp = userp;
1103 tidp->pathname = sharePath;
1105 tidp->flags |= SMB_TIDFLAG_IPC;
1106 lock_ReleaseMutex(&tidp->mx);
1107 smb_ReleaseTID(tidp, FALSE);
1109 ((smb_t *)outp)->tid = newTid;
1110 ((smb_t *)inp)->tid = newTid;
1111 tp = smb_GetSMBData(outp, NULL);
1115 tp = smb_UnparseString(outp, tp, "A:", &cb_data, SMB_STRF_FORCEASCII);
1116 tp = smb_UnparseString(outp, tp, "AFS", &cb_data, 0);
1117 smb_SetSMBDataLength(outp, cb_data);
1121 tp = smb_UnparseString(outp, tp, "IPC", &cb_data, SMB_STRF_FORCEASCII);
1122 smb_SetSMBDataLength(outp, cb_data);
1125 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1129 /* must be called with global tran lock held */
1130 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1132 smb_tran2Packet_t *tp;
1135 smbp = (smb_t *) inp->data;
1136 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1137 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1143 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1144 int totalParms, int totalData)
1146 smb_tran2Packet_t *tp;
1149 smbp = (smb_t *) inp->data;
1150 tp = malloc(sizeof(*tp));
1151 memset(tp, 0, sizeof(*tp));
1154 tp->curData = tp->curParms = 0;
1155 tp->totalData = totalData;
1156 tp->totalParms = totalParms;
1157 tp->tid = smbp->tid;
1158 tp->mid = smbp->mid;
1159 tp->uid = smbp->uid;
1160 tp->pid = smbp->pid;
1161 tp->res[0] = smbp->res[0];
1162 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1163 if (totalParms != 0)
1164 tp->parmsp = malloc(totalParms);
1166 tp->datap = malloc(totalData);
1167 if (smbp->com == 0x25 || smbp->com == 0x26)
1170 tp->opcode = smb_GetSMBParm(inp, 14);
1173 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1175 if (WANTS_UNICODE(inp) && (vcp->flags & SMB_VCFLAG_USEUNICODE))
1176 tp->flags |= SMB_TRAN2PFLAG_USEUNICODE;
1181 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1182 smb_tran2Packet_t *inp, smb_packet_t *outp,
1183 int totalParms, int totalData)
1185 smb_tran2Packet_t *tp;
1186 unsigned short parmOffset;
1187 unsigned short dataOffset;
1188 unsigned short dataAlign;
1190 tp = malloc(sizeof(*tp));
1191 memset(tp, 0, sizeof(*tp));
1194 tp->curData = tp->curParms = 0;
1195 tp->totalData = totalData;
1196 tp->totalParms = totalParms;
1197 tp->oldTotalParms = totalParms;
1202 tp->res[0] = inp->res[0];
1203 tp->opcode = inp->opcode;
1207 * We calculate where the parameters and data will start.
1208 * This calculation must parallel the calculation in
1209 * smb_SendTran2Packet.
1212 parmOffset = 10*2 + 35;
1213 parmOffset++; /* round to even */
1214 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1216 dataOffset = parmOffset + totalParms;
1217 dataAlign = dataOffset & 2; /* quad-align */
1218 dataOffset += dataAlign;
1219 tp->datap = outp->data + dataOffset;
1224 /* free a tran2 packet */
1225 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1228 smb_ReleaseVC(t2p->vcp);
1231 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1237 while (t2p->stringsp) {
1241 t2p->stringsp = ns->nextp;
1247 unsigned char *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
1248 char ** chainpp, int flags)
1253 if (!(p->flags & SMB_TRAN2PFLAG_USEUNICODE))
1254 flags |= SMB_STRF_FORCEASCII;
1257 cb = p->totalParms - (inp - (unsigned char *)p->parmsp);
1258 if (inp < (unsigned char *) p->parmsp ||
1259 inp > ((unsigned char *) p->parmsp) + p->totalParms) {
1260 #ifdef DEBUG_UNICODE
1266 return smb_ParseStringBuf((unsigned char *) p->parmsp, &p->stringsp,
1267 inp, &cb, chainpp, flags);
1270 /* called with a VC, an input packet to respond to, and an error code.
1271 * sends an error response.
1273 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1274 smb_packet_t *tp, long code)
1277 unsigned short errCode;
1278 unsigned char errClass;
1279 unsigned long NTStatus;
1281 if (vcp->flags & SMB_VCFLAG_STATUS32)
1282 smb_MapNTError(code, &NTStatus);
1284 smb_MapCoreError(code, vcp, &errCode, &errClass);
1286 smb_FormatResponsePacket(vcp, NULL, tp);
1287 smbp = (smb_t *) tp;
1289 /* We can handle long names */
1290 if (vcp->flags & SMB_VCFLAG_USENT)
1291 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1293 /* now copy important fields from the tran 2 packet */
1294 smbp->com = t2p->com;
1295 smbp->tid = t2p->tid;
1296 smbp->mid = t2p->mid;
1297 smbp->pid = t2p->pid;
1298 smbp->uid = t2p->uid;
1299 smbp->res[0] = t2p->res[0];
1300 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1301 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1302 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1303 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1304 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1305 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1308 smbp->rcls = errClass;
1309 smbp->errLow = (unsigned char) (errCode & 0xff);
1310 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1314 smb_SendPacket(vcp, tp);
1317 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1320 unsigned short parmOffset;
1321 unsigned short dataOffset;
1322 unsigned short totalLength;
1323 unsigned short dataAlign;
1326 smb_FormatResponsePacket(vcp, NULL, tp);
1327 smbp = (smb_t *) tp;
1329 /* We can handle long names */
1330 if (vcp->flags & SMB_VCFLAG_USENT)
1331 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1333 /* now copy important fields from the tran 2 packet */
1334 smbp->com = t2p->com;
1335 smbp->tid = t2p->tid;
1336 smbp->mid = t2p->mid;
1337 smbp->pid = t2p->pid;
1338 smbp->uid = t2p->uid;
1339 smbp->res[0] = t2p->res[0];
1341 totalLength = 1 + t2p->totalData + t2p->totalParms;
1343 /* now add the core parameters (tran2 info) to the packet */
1344 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1345 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1346 smb_SetSMBParm(tp, 2, 0); /* reserved */
1347 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1348 parmOffset = 10*2 + 35; /* parm offset in packet */
1349 parmOffset++; /* round to even */
1350 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1351 * hdr, bcc and wct */
1352 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1353 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1354 dataOffset = parmOffset + t2p->oldTotalParms;
1355 dataAlign = dataOffset & 2; /* quad-align */
1356 dataOffset += dataAlign;
1357 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1358 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1359 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1362 datap = smb_GetSMBData(tp, NULL);
1363 *datap++ = 0; /* we rounded to even */
1365 totalLength += dataAlign;
1366 smb_SetSMBDataLength(tp, totalLength);
1368 /* next, send the datagram */
1369 smb_SendPacket(vcp, tp);
1373 /* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
1374 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1376 smb_tran2Packet_t *asp;
1389 /* We sometimes see 0 word count. What to do? */
1390 if (*inp->wctp == 0) {
1391 osi_Log0(smb_logp, "Transaction2 word count = 0");
1392 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1394 smb_SetSMBDataLength(outp, 0);
1395 smb_SendPacket(vcp, outp);
1399 totalParms = smb_GetSMBParm(inp, 0);
1400 totalData = smb_GetSMBParm(inp, 1);
1402 firstPacket = (inp->inCom == 0x25);
1404 /* find the packet we're reassembling */
1405 lock_ObtainWrite(&smb_globalLock);
1406 asp = smb_FindTran2Packet(vcp, inp);
1408 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1410 lock_ReleaseWrite(&smb_globalLock);
1412 /* now merge in this latest packet; start by looking up offsets */
1414 parmDisp = dataDisp = 0;
1415 parmOffset = smb_GetSMBParm(inp, 10);
1416 dataOffset = smb_GetSMBParm(inp, 12);
1417 parmCount = smb_GetSMBParm(inp, 9);
1418 dataCount = smb_GetSMBParm(inp, 11);
1419 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1420 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1422 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1423 totalData, dataCount, asp->maxReturnData);
1426 parmDisp = smb_GetSMBParm(inp, 4);
1427 parmOffset = smb_GetSMBParm(inp, 3);
1428 dataDisp = smb_GetSMBParm(inp, 7);
1429 dataOffset = smb_GetSMBParm(inp, 6);
1430 parmCount = smb_GetSMBParm(inp, 2);
1431 dataCount = smb_GetSMBParm(inp, 5);
1433 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1434 parmCount, dataCount);
1437 /* now copy the parms and data */
1438 if ( asp->totalParms > 0 && parmCount != 0 )
1440 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1442 if ( asp->totalData > 0 && dataCount != 0 ) {
1443 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1446 /* account for new bytes */
1447 asp->curData += dataCount;
1448 asp->curParms += parmCount;
1450 /* finally, if we're done, remove the packet from the queue and dispatch it */
1451 if (asp->totalParms > 0 &&
1452 asp->curParms > 0 &&
1453 asp->totalData <= asp->curData &&
1454 asp->totalParms <= asp->curParms) {
1455 /* we've received it all */
1456 lock_ObtainWrite(&smb_globalLock);
1457 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1458 lock_ReleaseWrite(&smb_globalLock);
1460 /* now dispatch it */
1461 rapOp = asp->parmsp[0];
1463 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1464 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1465 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1466 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
1469 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1470 code = CM_ERROR_BADOP;
1473 /* if an error is returned, we're supposed to send an error packet,
1474 * otherwise the dispatched function already did the data sending.
1475 * We give dispatched proc the responsibility since it knows how much
1476 * space to allocate.
1479 smb_SendTran2Error(vcp, asp, outp, code);
1482 /* free the input tran 2 packet */
1483 smb_FreeTran2Packet(asp);
1485 else if (firstPacket) {
1486 /* the first packet in a multi-packet request, we need to send an
1487 * ack to get more data.
1489 smb_SetSMBDataLength(outp, 0);
1490 smb_SendPacket(vcp, outp);
1496 /* ANSI versions. */
1498 #pragma pack(push, 1)
1500 typedef struct smb_rap_share_info_0 {
1501 BYTE shi0_netname[13];
1502 } smb_rap_share_info_0_t;
1504 typedef struct smb_rap_share_info_1 {
1505 BYTE shi1_netname[13];
1508 DWORD shi1_remark; /* char *shi1_remark; data offset */
1509 } smb_rap_share_info_1_t;
1511 typedef struct smb_rap_share_info_2 {
1512 BYTE shi2_netname[13];
1515 DWORD shi2_remark; /* char *shi2_remark; data offset */
1516 WORD shi2_permissions;
1518 WORD shi2_current_uses;
1519 DWORD shi2_path; /* char *shi2_path; data offset */
1520 WORD shi2_passwd[9];
1522 } smb_rap_share_info_2_t;
1524 #define SMB_RAP_MAX_SHARES 512
1526 typedef struct smb_rap_share_list {
1529 smb_rap_share_info_0_t * shares;
1530 } smb_rap_share_list_t;
1534 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1535 smb_rap_share_list_t * sp;
1536 char name[MAX_PATH];
1538 cm_NormalizeUtf8String(dep->name, -1, name, sizeof(name)/sizeof(char));
1540 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1541 return 0; /* skip over '.' and '..' */
1543 sp = (smb_rap_share_list_t *) vrockp;
1545 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1546 sp->shares[sp->cShare].shi0_netname[12] = 0;
1550 if (sp->cShare >= sp->maxShares)
1551 return CM_ERROR_STOPNOW;
1556 /* RAP NetShareEnumRequest */
1557 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1559 smb_tran2Packet_t *outp;
1560 unsigned short * tp;
1564 int outParmsTotal; /* total parameter bytes */
1565 int outDataTotal; /* total data bytes */
1568 DWORD allSubmount = 0;
1570 DWORD nRegShares = 0;
1571 DWORD nSharesRet = 0;
1573 HKEY hkSubmount = NULL;
1574 smb_rap_share_info_1_t * shares;
1577 char thisShare[AFSPATHMAX];
1581 smb_rap_share_list_t rootShares;
1586 tp = p->parmsp + 1; /* skip over function number (always 0) */
1591 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1592 if (strcmp(cdescp, "WrLeh"))
1593 return CM_ERROR_INVAL;
1594 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1595 if (strcmp(cdescp, "B13BWz"))
1596 return CM_ERROR_INVAL;
1602 if (infoLevel != 1) {
1603 return CM_ERROR_INVAL;
1606 /* We are supposed to use the same ASCII data structure even if
1607 Unicode is negotiated, which ultimately means that the share
1608 names that we return must be at most 13 characters in length,
1609 including the NULL terminator.
1611 The RAP specification states that shares with names longer than
1612 12 characters should not be included in the enumeration.
1613 However, since we support prefix cell references and since many
1614 cell names are going to exceed 12 characters, we lie and send
1615 the first 12 characters.
1618 /* first figure out how many shares there are */
1619 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1620 KEY_QUERY_VALUE, &hkParam);
1621 if (rv == ERROR_SUCCESS) {
1622 len = sizeof(allSubmount);
1623 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1624 (BYTE *) &allSubmount, &len);
1625 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1628 RegCloseKey (hkParam);
1631 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1632 0, KEY_QUERY_VALUE, &hkSubmount);
1633 if (rv == ERROR_SUCCESS) {
1634 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1635 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1636 if (rv != ERROR_SUCCESS)
1642 /* fetch the root shares */
1643 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1644 rootShares.cShare = 0;
1645 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1649 userp = smb_GetTran2User(vcp,p);
1651 thyper.HighPart = 0;
1654 cm_HoldSCache(cm_data.rootSCachep);
1655 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1656 cm_ReleaseSCache(cm_data.rootSCachep);
1658 cm_ReleaseUser(userp);
1660 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1662 #define REMARK_LEN 1
1663 outParmsTotal = 8; /* 4 dwords */
1664 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1665 if(outDataTotal > bufsize) {
1666 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1667 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1670 nSharesRet = nShares;
1673 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1675 /* now for the submounts */
1676 shares = (smb_rap_share_info_1_t *) outp->datap;
1677 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1679 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1682 strcpy( shares[cshare].shi1_netname, "all" );
1683 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1684 /* type and pad are zero already */
1690 for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
1691 len = sizeof(thisShare);
1692 rv = RegEnumValue(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
1693 if (rv == ERROR_SUCCESS &&
1694 strlen(thisShare) && (!allSubmount || cm_stricmp_utf8N(thisShare,"all"))) {
1695 strncpy(shares[cshare].shi1_netname, thisShare,
1696 sizeof(shares->shi1_netname)-1);
1697 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1698 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1703 nShares--; /* uncount key */
1706 RegCloseKey(hkSubmount);
1709 nonrootShares = cshare;
1711 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1712 /* in case there are collisions with submounts, submounts have higher priority */
1713 for (j=0; j < nonrootShares; j++)
1714 if (!cm_stricmp_utf8(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1717 if (j < nonrootShares) {
1718 nShares--; /* uncount */
1722 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1723 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1728 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1729 outp->parmsp[1] = 0;
1730 outp->parmsp[2] = cshare;
1731 outp->parmsp[3] = nShares;
1733 outp->totalData = (int)(cstrp - outp->datap);
1734 outp->totalParms = outParmsTotal;
1736 smb_SendTran2Packet(vcp, outp, op);
1737 smb_FreeTran2Packet(outp);
1739 free(rootShares.shares);
1744 /* RAP NetShareGetInfo */
1745 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1747 smb_tran2Packet_t *outp;
1748 unsigned short * tp;
1750 BOOL shareFound = FALSE;
1751 unsigned short infoLevel;
1752 unsigned short bufsize;
1761 cm_scache_t *scp = NULL;
1767 tp = p->parmsp + 1; /* skip over function number (always 1) */
1772 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1773 if (strcmp(cdescp, "zWrLh"))
1775 return CM_ERROR_INVAL;
1777 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1778 if (strcmp(cdescp, "B13") &&
1779 strcmp(cdescp, "B13BWz") &&
1780 strcmp(cdescp, "B13BWzWWWzB9B"))
1782 return CM_ERROR_INVAL;
1784 shareName = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1792 totalData = sizeof(smb_rap_share_info_0_t);
1793 else if(infoLevel == SMB_INFO_STANDARD)
1794 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1795 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1796 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1798 return CM_ERROR_INVAL;
1800 if(!cm_stricmp_utf8N(shareName,"all") || !strcmp(shareName,"*.")) {
1801 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1802 KEY_QUERY_VALUE, &hkParam);
1803 if (rv == ERROR_SUCCESS) {
1804 len = sizeof(allSubmount);
1805 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1806 (BYTE *) &allSubmount, &len);
1807 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1810 RegCloseKey (hkParam);
1817 userp = smb_GetTran2User(vcp, p);
1819 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
1820 return CM_ERROR_BADSMB;
1822 code = cm_NameI(cm_data.rootSCachep, shareName,
1823 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
1824 userp, NULL, &req, &scp);
1826 cm_ReleaseSCache(scp);
1829 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1830 KEY_QUERY_VALUE, &hkSubmount);
1831 if (rv == ERROR_SUCCESS) {
1832 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1833 if (rv == ERROR_SUCCESS) {
1836 RegCloseKey(hkSubmount);
1842 return CM_ERROR_BADSHARENAME;
1844 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1845 memset(outp->datap, 0, totalData);
1847 outp->parmsp[0] = 0;
1848 outp->parmsp[1] = 0;
1849 outp->parmsp[2] = totalData;
1851 if (infoLevel == 0) {
1852 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1853 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1854 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1855 } else if(infoLevel == SMB_INFO_STANDARD) {
1856 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1857 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1858 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1859 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1860 /* type and pad are already zero */
1861 } else { /* infoLevel==2 */
1862 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1863 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1864 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1865 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1866 info->shi2_permissions = ACCESS_ALL;
1867 info->shi2_max_uses = (unsigned short) -1;
1868 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
1871 outp->totalData = totalData;
1872 outp->totalParms = totalParam;
1874 smb_SendTran2Packet(vcp, outp, op);
1875 smb_FreeTran2Packet(outp);
1880 #pragma pack(push, 1)
1882 typedef struct smb_rap_wksta_info_10 {
1883 DWORD wki10_computername; /*char *wki10_computername;*/
1884 DWORD wki10_username; /* char *wki10_username; */
1885 DWORD wki10_langroup; /* char *wki10_langroup;*/
1886 BYTE wki10_ver_major;
1887 BYTE wki10_ver_minor;
1888 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1889 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1890 } smb_rap_wksta_info_10_t;
1894 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1896 smb_tran2Packet_t *outp;
1900 unsigned short * tp;
1903 smb_rap_wksta_info_10_t * info;
1907 tp = p->parmsp + 1; /* Skip over function number */
1912 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
1913 SMB_STRF_FORCEASCII);
1914 if (strcmp(cdescp, "WrLh"))
1915 return CM_ERROR_INVAL;
1916 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
1917 SMB_STRF_FORCEASCII);
1918 if (strcmp(cdescp, "zzzBBzz"))
1919 return CM_ERROR_INVAL;
1925 if (infoLevel != 10) {
1926 return CM_ERROR_INVAL;
1932 totalData = sizeof(*info) + /* info */
1933 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1934 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1935 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1936 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1937 1; /* wki10_oth_domains (null)*/
1939 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1941 memset(outp->parmsp,0,totalParams);
1942 memset(outp->datap,0,totalData);
1944 info = (smb_rap_wksta_info_10_t *) outp->datap;
1945 cstrp = (char *) (info + 1);
1947 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1948 strcpy(cstrp, smb_localNamep);
1949 cstrp += strlen(cstrp) + 1;
1951 info->wki10_username = (DWORD) (cstrp - outp->datap);
1952 uidp = smb_FindUID(vcp, p->uid, 0);
1954 lock_ObtainMutex(&uidp->mx);
1955 if(uidp->unp && uidp->unp->name)
1956 strcpy(cstrp, uidp->unp->name);
1957 lock_ReleaseMutex(&uidp->mx);
1958 smb_ReleaseUID(uidp);
1960 cstrp += strlen(cstrp) + 1;
1962 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1963 strcpy(cstrp, "WORKGROUP");
1964 cstrp += strlen(cstrp) + 1;
1966 /* TODO: Not sure what values these should take, but these work */
1967 info->wki10_ver_major = 5;
1968 info->wki10_ver_minor = 1;
1970 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1971 strcpy(cstrp, smb_ServerDomainName);
1972 cstrp += strlen(cstrp) + 1;
1974 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1975 cstrp ++; /* no other domains */
1977 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1978 outp->parmsp[2] = outp->totalData;
1979 outp->totalParms = totalParams;
1981 smb_SendTran2Packet(vcp,outp,op);
1982 smb_FreeTran2Packet(outp);
1987 #pragma pack(push, 1)
1989 typedef struct smb_rap_server_info_0 {
1991 } smb_rap_server_info_0_t;
1993 typedef struct smb_rap_server_info_1 {
1995 BYTE sv1_version_major;
1996 BYTE sv1_version_minor;
1998 DWORD sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1999 } smb_rap_server_info_1_t;
2003 char smb_ServerComment[] = "OpenAFS Client";
2004 int smb_ServerCommentLen = sizeof(smb_ServerComment);
2006 #define SMB_SV_TYPE_SERVER 0x00000002L
2007 #define SMB_SV_TYPE_NT 0x00001000L
2008 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
2010 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2012 smb_tran2Packet_t *outp;
2016 unsigned short * tp;
2019 smb_rap_server_info_0_t * info0;
2020 smb_rap_server_info_1_t * info1;
2023 tp = p->parmsp + 1; /* Skip over function number */
2028 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2029 SMB_STRF_FORCEASCII);
2030 if (strcmp(cdescp, "WrLh"))
2031 return CM_ERROR_INVAL;
2032 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2033 SMB_STRF_FORCEASCII);
2034 if (strcmp(cdescp, "B16") ||
2035 strcmp(cdescp, "B16BBDz"))
2036 return CM_ERROR_INVAL;
2042 if (infoLevel != 0 && infoLevel != 1) {
2043 return CM_ERROR_INVAL;
2049 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
2050 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
2052 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2054 memset(outp->parmsp,0,totalParams);
2055 memset(outp->datap,0,totalData);
2057 if (infoLevel == 0) {
2058 info0 = (smb_rap_server_info_0_t *) outp->datap;
2059 cstrp = (char *) (info0 + 1);
2060 strcpy(info0->sv0_name, "AFS");
2061 } else { /* infoLevel == SMB_INFO_STANDARD */
2062 info1 = (smb_rap_server_info_1_t *) outp->datap;
2063 cstrp = (char *) (info1 + 1);
2064 strcpy(info1->sv1_name, "AFS");
2067 SMB_SV_TYPE_SERVER |
2069 SMB_SV_TYPE_SERVER_NT;
2071 info1->sv1_version_major = 5;
2072 info1->sv1_version_minor = 1;
2073 info1->sv1_comment_or_master_browser = (DWORD) (cstrp - outp->datap);
2075 strcpy(cstrp, smb_ServerComment);
2077 cstrp += smb_ServerCommentLen;
2080 totalData = (DWORD)(cstrp - outp->datap);
2081 outp->totalData = min(bufsize,totalData); /* actual data size */
2082 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
2083 outp->parmsp[2] = totalData;
2084 outp->totalParms = totalParams;
2086 smb_SendTran2Packet(vcp,outp,op);
2087 smb_FreeTran2Packet(outp);
2092 /* SMB_COM_TRANSACTION2 and SMB_COM_TRANSACTION2_SECONDARY */
2093 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2095 smb_tran2Packet_t *asp;
2107 /* We sometimes see 0 word count. What to do? */
2108 if (*inp->wctp == 0) {
2109 osi_Log0(smb_logp, "Transaction2 word count = 0");
2110 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
2112 smb_SetSMBDataLength(outp, 0);
2113 smb_SendPacket(vcp, outp);
2117 totalParms = smb_GetSMBParm(inp, 0);
2118 totalData = smb_GetSMBParm(inp, 1);
2120 firstPacket = (inp->inCom == 0x32);
2122 /* find the packet we're reassembling */
2123 lock_ObtainWrite(&smb_globalLock);
2124 asp = smb_FindTran2Packet(vcp, inp);
2126 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
2128 lock_ReleaseWrite(&smb_globalLock);
2130 /* now merge in this latest packet; start by looking up offsets */
2132 parmDisp = dataDisp = 0;
2133 parmOffset = smb_GetSMBParm(inp, 10);
2134 dataOffset = smb_GetSMBParm(inp, 12);
2135 parmCount = smb_GetSMBParm(inp, 9);
2136 dataCount = smb_GetSMBParm(inp, 11);
2137 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2138 asp->maxReturnData = smb_GetSMBParm(inp, 3);
2140 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2141 totalData, dataCount, asp->maxReturnData);
2144 parmDisp = smb_GetSMBParm(inp, 4);
2145 parmOffset = smb_GetSMBParm(inp, 3);
2146 dataDisp = smb_GetSMBParm(inp, 7);
2147 dataOffset = smb_GetSMBParm(inp, 6);
2148 parmCount = smb_GetSMBParm(inp, 2);
2149 dataCount = smb_GetSMBParm(inp, 5);
2151 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2152 parmCount, dataCount);
2155 /* now copy the parms and data */
2156 if ( asp->totalParms > 0 && parmCount != 0 )
2158 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2160 if ( asp->totalData > 0 && dataCount != 0 ) {
2161 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2164 /* account for new bytes */
2165 asp->curData += dataCount;
2166 asp->curParms += parmCount;
2168 /* finally, if we're done, remove the packet from the queue and dispatch it */
2169 if (asp->totalParms > 0 &&
2170 asp->curParms > 0 &&
2171 asp->totalData <= asp->curData &&
2172 asp->totalParms <= asp->curParms) {
2173 /* we've received it all */
2174 lock_ObtainWrite(&smb_globalLock);
2175 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2176 lock_ReleaseWrite(&smb_globalLock);
2178 /* now dispatch it */
2179 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2180 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2181 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2184 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2185 code = CM_ERROR_BADOP;
2188 /* if an error is returned, we're supposed to send an error packet,
2189 * otherwise the dispatched function already did the data sending.
2190 * We give dispatched proc the responsibility since it knows how much
2191 * space to allocate.
2194 smb_SendTran2Error(vcp, asp, outp, code);
2197 /* free the input tran 2 packet */
2198 smb_FreeTran2Packet(asp);
2200 else if (firstPacket) {
2201 /* the first packet in a multi-packet request, we need to send an
2202 * ack to get more data.
2204 smb_SetSMBDataLength(outp, 0);
2205 smb_SendPacket(vcp, outp);
2212 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2215 smb_tran2Packet_t *outp;
2220 cm_scache_t *dscp; /* dir we're dealing with */
2221 cm_scache_t *scp; /* file we're creating */
2223 int initialModeBits;
2233 int parmSlot; /* which parm we're dealing with */
2234 long returnEALength;
2243 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2244 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2246 openFun = p->parmsp[6]; /* open function */
2247 excl = ((openFun & 3) == 0);
2248 trunc = ((openFun & 3) == 2); /* truncate it */
2249 openMode = (p->parmsp[1] & 0x7);
2250 openAction = 0; /* tracks what we did */
2252 attributes = p->parmsp[3];
2253 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2255 /* compute initial mode bits based on read-only flag in attributes */
2256 initialModeBits = 0666;
2257 if (attributes & SMB_ATTR_READONLY)
2258 initialModeBits &= ~0222;
2260 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
2263 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2265 spacep = cm_GetSpace();
2266 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2269 (cm_stricmp_utf8N(lastNamep, SMB_IOCTL_FILENAME) == 0 ||
2270 cm_stricmp_utf8N(lastNamep, "\\srvsvc") == 0 ||
2271 cm_stricmp_utf8N(lastNamep, "\\wkssvc") == 0 ||
2272 cm_stricmp_utf8N(lastNamep, "\\ipc$") == 0)) {
2273 /* special case magic file name for receiving IOCTL requests
2274 * (since IOCTL calls themselves aren't getting through).
2276 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2277 smb_SetupIoctlFid(fidp, spacep);
2279 /* copy out remainder of the parms */
2281 outp->parmsp[parmSlot++] = fidp->fid;
2283 outp->parmsp[parmSlot++] = 0; /* attrs */
2284 outp->parmsp[parmSlot++] = 0; /* mod time */
2285 outp->parmsp[parmSlot++] = 0;
2286 outp->parmsp[parmSlot++] = 0; /* len */
2287 outp->parmsp[parmSlot++] = 0x7fff;
2288 outp->parmsp[parmSlot++] = openMode;
2289 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2290 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2292 /* and the final "always present" stuff */
2293 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2294 /* next write out the "unique" ID */
2295 outp->parmsp[parmSlot++] = 0x1234;
2296 outp->parmsp[parmSlot++] = 0x5678;
2297 outp->parmsp[parmSlot++] = 0;
2298 if (returnEALength) {
2299 outp->parmsp[parmSlot++] = 0;
2300 outp->parmsp[parmSlot++] = 0;
2303 outp->totalData = 0;
2304 outp->totalParms = parmSlot * 2;
2306 smb_SendTran2Packet(vcp, outp, op);
2308 smb_FreeTran2Packet(outp);
2310 /* and clean up fid reference */
2311 smb_ReleaseFID(fidp);
2315 #ifdef DEBUG_VERBOSE
2317 char *hexp, *asciip;
2318 asciip = (lastNamep ? lastNamep : pathp);
2319 hexp = osi_HexifyString( asciip );
2320 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2325 userp = smb_GetTran2User(vcp, p);
2326 /* In the off chance that userp is NULL, we log and abandon */
2328 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2329 smb_FreeTran2Packet(outp);
2330 return CM_ERROR_BADSMB;
2333 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2334 if (code == CM_ERROR_TIDIPC) {
2335 /* Attempt to use a TID allocated for IPC. The client
2336 * is probably looking for DCE RPC end points which we
2337 * don't support OR it could be looking to make a DFS
2340 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2342 cm_ReleaseUser(userp);
2343 smb_FreeTran2Packet(outp);
2344 return CM_ERROR_NOSUCHPATH;
2349 code = cm_NameI(cm_data.rootSCachep, pathp,
2350 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2351 userp, tidPathp, &req, &scp);
2353 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2354 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2355 userp, tidPathp, &req, &dscp);
2356 cm_FreeSpace(spacep);
2359 cm_ReleaseUser(userp);
2360 smb_FreeTran2Packet(outp);
2365 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2366 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
2367 cm_ReleaseSCache(dscp);
2368 cm_ReleaseUser(userp);
2369 smb_FreeTran2Packet(outp);
2370 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2371 return CM_ERROR_PATH_NOT_COVERED;
2373 return CM_ERROR_BADSHARENAME;
2375 #endif /* DFS_SUPPORT */
2377 /* otherwise, scp points to the parent directory. Do a lookup,
2378 * and truncate the file if we find it, otherwise we create the
2385 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2387 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2388 cm_ReleaseSCache(dscp);
2389 cm_ReleaseUser(userp);
2390 smb_FreeTran2Packet(outp);
2395 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2396 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2397 cm_ReleaseSCache(scp);
2398 cm_ReleaseUser(userp);
2399 smb_FreeTran2Packet(outp);
2400 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2401 return CM_ERROR_PATH_NOT_COVERED;
2403 return CM_ERROR_BADSHARENAME;
2405 #endif /* DFS_SUPPORT */
2407 /* macintosh is expensive to program for it */
2408 cm_FreeSpace(spacep);
2411 /* if we get here, if code is 0, the file exists and is represented by
2412 * scp. Otherwise, we have to create it.
2415 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2418 cm_ReleaseSCache(dscp);
2419 cm_ReleaseSCache(scp);
2420 cm_ReleaseUser(userp);
2421 smb_FreeTran2Packet(outp);
2426 /* oops, file shouldn't be there */
2428 cm_ReleaseSCache(dscp);
2429 cm_ReleaseSCache(scp);
2430 cm_ReleaseUser(userp);
2431 smb_FreeTran2Packet(outp);
2432 return CM_ERROR_EXISTS;
2436 setAttr.mask = CM_ATTRMASK_LENGTH;
2437 setAttr.length.LowPart = 0;
2438 setAttr.length.HighPart = 0;
2439 code = cm_SetAttr(scp, &setAttr, userp, &req);
2440 openAction = 3; /* truncated existing file */
2443 openAction = 1; /* found existing file */
2445 else if (!(openFun & 0x10)) {
2446 /* don't create if not found */
2448 cm_ReleaseSCache(dscp);
2449 osi_assertx(scp == NULL, "null cm_scache_t");
2450 cm_ReleaseUser(userp);
2451 smb_FreeTran2Packet(outp);
2452 return CM_ERROR_NOSUCHFILE;
2455 osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2456 openAction = 2; /* created file */
2457 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2458 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2459 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2463 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2464 smb_NotifyChange(FILE_ACTION_ADDED,
2465 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2466 dscp, lastNamep, NULL, TRUE);
2467 } else if (!excl && code == CM_ERROR_EXISTS) {
2468 /* not an exclusive create, and someone else tried
2469 * creating it already, then we open it anyway. We
2470 * don't bother retrying after this, since if this next
2471 * fails, that means that the file was deleted after we
2472 * started this call.
2474 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2478 setAttr.mask = CM_ATTRMASK_LENGTH;
2479 setAttr.length.LowPart = 0;
2480 setAttr.length.HighPart = 0;
2481 code = cm_SetAttr(scp, &setAttr, userp,
2484 } /* lookup succeeded */
2488 /* we don't need this any longer */
2490 cm_ReleaseSCache(dscp);
2493 /* something went wrong creating or truncating the file */
2495 cm_ReleaseSCache(scp);
2496 cm_ReleaseUser(userp);
2497 smb_FreeTran2Packet(outp);
2501 /* make sure we're about to open a file */
2502 if (scp->fileType != CM_SCACHETYPE_FILE) {
2504 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2505 cm_scache_t * targetScp = 0;
2506 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2508 /* we have a more accurate file to use (the
2509 * target of the symbolic link). Otherwise,
2510 * we'll just use the symlink anyway.
2512 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2514 cm_ReleaseSCache(scp);
2518 if (scp->fileType != CM_SCACHETYPE_FILE) {
2519 cm_ReleaseSCache(scp);
2520 cm_ReleaseUser(userp);
2521 smb_FreeTran2Packet(outp);
2522 return CM_ERROR_ISDIR;
2526 /* now all we have to do is open the file itself */
2527 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2528 osi_assertx(fidp, "null smb_fid_t");
2531 lock_ObtainMutex(&fidp->mx);
2532 /* save a pointer to the vnode */
2533 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2535 lock_ObtainWrite(&scp->rw);
2536 scp->flags |= CM_SCACHEFLAG_SMB_FID;
2537 lock_ReleaseWrite(&scp->rw);
2540 fidp->userp = userp;
2542 /* compute open mode */
2544 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
2545 if (openMode == 1 || openMode == 2)
2546 fidp->flags |= SMB_FID_OPENWRITE;
2548 /* remember that the file was newly created */
2550 fidp->flags |= SMB_FID_CREATED;
2552 lock_ReleaseMutex(&fidp->mx);
2554 smb_ReleaseFID(fidp);
2556 cm_Open(scp, 0, userp);
2558 /* copy out remainder of the parms */
2560 outp->parmsp[parmSlot++] = fidp->fid;
2561 lock_ObtainRead(&scp->rw);
2563 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2564 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2565 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2566 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2567 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2568 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2569 outp->parmsp[parmSlot++] = openMode;
2570 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2571 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2573 /* and the final "always present" stuff */
2574 outp->parmsp[parmSlot++] = openAction;
2575 /* next write out the "unique" ID */
2576 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2577 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2578 outp->parmsp[parmSlot++] = 0;
2579 if (returnEALength) {
2580 outp->parmsp[parmSlot++] = 0;
2581 outp->parmsp[parmSlot++] = 0;
2583 lock_ReleaseRead(&scp->rw);
2584 outp->totalData = 0; /* total # of data bytes */
2585 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2587 smb_SendTran2Packet(vcp, outp, op);
2589 smb_FreeTran2Packet(outp);
2591 cm_ReleaseUser(userp);
2592 /* leave scp held since we put it in fidp->scp */
2596 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2599 unsigned short infolevel;
2601 infolevel = p->parmsp[0];
2603 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2605 return CM_ERROR_BAD_LEVEL;
2608 /* TRANS2_QUERY_FS_INFORMATION */
2609 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2611 smb_tran2Packet_t *outp;
2612 smb_tran2QFSInfo_t qi;
2616 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2618 switch (p->parmsp[0]) {
2619 case SMB_INFO_ALLOCATION:
2621 responseSize = sizeof(qi.u.allocInfo);
2623 qi.u.allocInfo.FSID = 0;
2624 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2625 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2626 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2627 qi.u.allocInfo.bytesPerSector = 1024;
2630 case SMB_INFO_VOLUME:
2632 qi.u.volumeInfo.vsn = 1234; /* Volume serial number */
2633 qi.u.volumeInfo.vnCount = 4; /* Number of characters in label (AFS\0)*/
2635 /* we're supposed to pad it out with zeroes to the end */
2636 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2637 smb_UnparseString(op, qi.u.volumeInfo.label, "AFS", &sz, 0);
2639 responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
2642 case SMB_QUERY_FS_VOLUME_INFO:
2643 /* FS volume info */
2644 responseSize = sizeof(qi.u.FSvolumeInfo);
2647 FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
2648 memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
2651 qi.u.FSvolumeInfo.vsn = 1234;
2652 qi.u.FSvolumeInfo.vnCount = 8; /* This is always in Unicode */
2653 memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
2656 case SMB_QUERY_FS_SIZE_INFO:
2658 responseSize = sizeof(qi.u.FSsizeInfo);
2660 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2661 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2662 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2663 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2664 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2665 qi.u.FSsizeInfo.bytesPerSector = 1024;
2668 case SMB_QUERY_FS_DEVICE_INFO:
2669 /* FS device info */
2670 responseSize = sizeof(qi.u.FSdeviceInfo);
2672 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2673 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2676 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2677 /* FS attribute info */
2679 /* attributes, defined in WINNT.H:
2680 * FILE_CASE_SENSITIVE_SEARCH 0x1
2681 * FILE_CASE_PRESERVED_NAMES 0x2
2682 * FILE_VOLUME_QUOTAS 0x10
2683 * <no name defined> 0x4000
2684 * If bit 0x4000 is not set, Windows 95 thinks
2685 * we can't handle long (non-8.3) names,
2686 * despite our protestations to the contrary.
2688 qi.u.FSattributeInfo.attributes = 0x4003;
2689 /* The maxCompLength is supposed to be in bytes */
2691 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2692 qi.u.FSattributeInfo.maxCompLength = MAX_PATH * sizeof(wchar_t);
2695 qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
2699 smb_UnparseString(op, qi.u.FSattributeInfo.FSname, "AFS", &sz, 0);
2700 qi.u.FSattributeInfo.FSnameLength = sz;
2703 sizeof(qi.u.FSattributeInfo.attributes) +
2704 sizeof(qi.u.FSattributeInfo.maxCompLength) +
2705 sizeof(qi.u.FSattributeInfo.FSnameLength) +
2710 case SMB_INFO_UNIX: /* CIFS Unix Info */
2711 case SMB_INFO_MACOS: /* Mac FS Info */
2713 return CM_ERROR_BADOP;
2716 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2718 /* copy out return data, and set corresponding sizes */
2719 outp->totalParms = 0;
2720 outp->totalData = responseSize;
2721 memcpy(outp->datap, &qi, responseSize);
2723 /* send and free the packets */
2724 smb_SendTran2Packet(vcp, outp, op);
2725 smb_FreeTran2Packet(outp);
2730 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2732 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2733 return CM_ERROR_BADOP;
2736 struct smb_ShortNameRock {
2740 size_t shortNameLen;
2743 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2746 struct smb_ShortNameRock *rockp;
2747 char normName[MAX_PATH];
2752 cm_NormalizeUtf8String(dep->name, -1, normName, sizeof(normName)/sizeof(char));
2754 /* compare both names and vnodes, though probably just comparing vnodes
2755 * would be safe enough.
2757 if (cm_stricmp_utf8(normName, rockp->maskp) != 0)
2759 if (ntohl(dep->fid.vnode) != rockp->vnode)
2762 /* This is the entry */
2763 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2764 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2766 return CM_ERROR_STOPNOW;
2769 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2770 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2772 struct smb_ShortNameRock rock;
2776 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2780 spacep = cm_GetSpace();
2781 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2783 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2785 cm_FreeSpace(spacep);
2790 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2791 cm_ReleaseSCache(dscp);
2792 cm_ReleaseUser(userp);
2796 return CM_ERROR_PATH_NOT_COVERED;
2798 #endif /* DFS_SUPPORT */
2800 if (!lastNamep) lastNamep = pathp;
2803 thyper.HighPart = 0;
2804 rock.shortName = shortName;
2806 rock.maskp = lastNamep;
2807 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2809 cm_ReleaseSCache(dscp);
2812 return CM_ERROR_NOSUCHFILE;
2813 if (code == CM_ERROR_STOPNOW) {
2814 *shortNameLenp = rock.shortNameLen;
2820 /* TRANS2_QUERY_PATH_INFORMATION */
2821 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2823 smb_tran2Packet_t *outp;
2826 unsigned short infoLevel;
2827 smb_tran2QPathInfo_t qpi;
2829 unsigned short attributes;
2830 unsigned long extAttributes;
2835 cm_scache_t *scp, *dscp;
2836 int scp_mx_held = 0;
2846 infoLevel = p->parmsp[0];
2847 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2849 else if (infoLevel == SMB_INFO_STANDARD)
2850 responseSize = sizeof(qpi.u.QPstandardInfo);
2851 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2852 responseSize = sizeof(qpi.u.QPeaSizeInfo);
2853 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2854 responseSize = sizeof(qpi.u.QPfileBasicInfo);
2855 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2856 responseSize = sizeof(qpi.u.QPfileStandardInfo);
2857 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2858 responseSize = sizeof(qpi.u.QPfileEaInfo);
2859 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2860 responseSize = sizeof(qpi.u.QPfileNameInfo);
2861 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
2862 responseSize = sizeof(qpi.u.QPfileAllInfo);
2863 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2864 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2866 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2867 p->opcode, infoLevel);
2868 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
2872 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
2873 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2874 osi_LogSaveString(smb_logp, pathp));
2876 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2878 if (infoLevel > 0x100)
2879 outp->totalParms = 2;
2881 outp->totalParms = 0;
2882 outp->totalData = responseSize;
2884 /* now, if we're at infoLevel 6, we're only being asked to check
2885 * the syntax, so we just OK things now. In particular, we're *not*
2886 * being asked to verify anything about the state of any parent dirs.
2888 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2889 smb_SendTran2Packet(vcp, outp, opx);
2890 smb_FreeTran2Packet(outp);
2894 userp = smb_GetTran2User(vcp, p);
2896 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2897 smb_FreeTran2Packet(outp);
2898 return CM_ERROR_BADSMB;
2901 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2903 cm_ReleaseUser(userp);
2904 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2905 smb_FreeTran2Packet(outp);
2910 * XXX Strange hack XXX
2912 * As of Patch 7 (13 January 98), we are having the following problem:
2913 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2914 * requests to look up "desktop.ini" in all the subdirectories.
2915 * This can cause zillions of timeouts looking up non-existent cells
2916 * and volumes, especially in the top-level directory.
2918 * We have not found any way to avoid this or work around it except
2919 * to explicitly ignore the requests for mount points that haven't
2920 * yet been evaluated and for directories that haven't yet been
2923 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2924 spacep = cm_GetSpace();
2925 smb_StripLastComponent(spacep->data, &lastComp, pathp);
2926 #ifndef SPECIAL_FOLDERS
2927 /* Make sure that lastComp is not NULL */
2929 if (cm_stricmp_utf8N(lastComp, "\\desktop.ini") == 0) {
2930 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2934 userp, tidPathp, &req, &dscp);
2937 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2938 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
2939 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2940 code = CM_ERROR_PATH_NOT_COVERED;
2942 code = CM_ERROR_BADSHARENAME;
2944 #endif /* DFS_SUPPORT */
2945 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2946 code = CM_ERROR_NOSUCHFILE;
2947 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2948 cm_buf_t *bp = buf_Find(dscp, &hzero);
2954 code = CM_ERROR_NOSUCHFILE;
2956 cm_ReleaseSCache(dscp);
2958 cm_FreeSpace(spacep);
2959 cm_ReleaseUser(userp);
2960 smb_SendTran2Error(vcp, p, opx, code);
2961 smb_FreeTran2Packet(outp);
2967 #endif /* SPECIAL_FOLDERS */
2969 cm_FreeSpace(spacep);
2972 /* now do namei and stat, and copy out the info */
2973 code = cm_NameI(cm_data.rootSCachep, pathp,
2974 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2977 cm_ReleaseUser(userp);
2978 smb_SendTran2Error(vcp, p, opx, code);
2979 smb_FreeTran2Packet(outp);
2984 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2985 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
2986 cm_ReleaseSCache(scp);
2987 cm_ReleaseUser(userp);
2988 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2989 code = CM_ERROR_PATH_NOT_COVERED;
2991 code = CM_ERROR_BADSHARENAME;
2992 smb_SendTran2Error(vcp, p, opx, code);
2993 smb_FreeTran2Packet(outp);
2996 #endif /* DFS_SUPPORT */
2998 lock_ObtainWrite(&scp->rw);
3000 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3001 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3002 if (code) goto done;
3004 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3006 lock_ConvertWToR(&scp->rw);
3010 /* now we have the status in the cache entry, and everything is locked.
3011 * Marshall the output data.
3013 /* for info level 108, figure out short name */
3014 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3015 code = cm_GetShortName(pathp, userp, &req,
3016 tidPathp, scp->fid.vnode, shortName,
3022 smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, 0);
3023 qpi.u.QPfileAltNameInfo.fileNameLength = len;
3027 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3028 smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, 0);
3029 qpi.u.QPfileNameInfo.fileNameLength = len;
3033 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3034 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3035 qpi.u.QPstandardInfo.creationDateTime = dosTime;
3036 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3037 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3038 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3039 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3040 attributes = smb_Attributes(scp);
3041 qpi.u.QPstandardInfo.attributes = attributes;
3042 qpi.u.QPstandardInfo.eaSize = 0;
3044 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3045 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3046 qpi.u.QPfileBasicInfo.creationTime = ft;
3047 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3048 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3049 qpi.u.QPfileBasicInfo.changeTime = ft;
3050 extAttributes = smb_ExtAttributes(scp);
3051 qpi.u.QPfileBasicInfo.attributes = extAttributes;
3052 qpi.u.QPfileBasicInfo.reserved = 0;
3054 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3055 smb_fid_t *fidp = smb_FindFIDByScache(vcp, scp);
3057 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3058 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3059 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3060 qpi.u.QPfileStandardInfo.directory =
3061 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3062 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3063 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3064 qpi.u.QPfileStandardInfo.reserved = 0;
3067 lock_ReleaseRead(&scp->rw);
3069 lock_ObtainMutex(&fidp->mx);
3070 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3071 lock_ReleaseMutex(&fidp->mx);
3072 smb_ReleaseFID(fidp);
3074 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3076 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3077 qpi.u.QPfileEaInfo.eaSize = 0;
3079 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3080 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3081 qpi.u.QPfileAllInfo.creationTime = ft;
3082 qpi.u.QPfileAllInfo.lastAccessTime = ft;
3083 qpi.u.QPfileAllInfo.lastWriteTime = ft;
3084 qpi.u.QPfileAllInfo.changeTime = ft;
3085 extAttributes = smb_ExtAttributes(scp);
3086 qpi.u.QPfileAllInfo.attributes = extAttributes;
3087 qpi.u.QPfileAllInfo.allocationSize = scp->length;
3088 qpi.u.QPfileAllInfo.endOfFile = scp->length;
3089 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3090 qpi.u.QPfileAllInfo.deletePending = 0;
3091 qpi.u.QPfileAllInfo.directory =
3092 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3093 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3094 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3095 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
3096 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
3097 qpi.u.QPfileAllInfo.eaSize = 0;
3098 qpi.u.QPfileAllInfo.accessFlags = 0;
3099 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
3100 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
3101 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3102 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3103 qpi.u.QPfileAllInfo.mode = 0;
3104 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3106 smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, 0);
3107 qpi.u.QPfileAllInfo.fileNameLength = len;
3110 /* send and free the packets */
3113 lock_ReleaseRead(&scp->rw);
3114 cm_ReleaseSCache(scp);
3115 cm_ReleaseUser(userp);
3117 memcpy(outp->datap, &qpi, responseSize);
3118 smb_SendTran2Packet(vcp, outp, opx);
3120 smb_SendTran2Error(vcp, p, opx, code);
3122 smb_FreeTran2Packet(outp);
3127 /* TRANS2_SET_PATH_INFORMATION */
3128 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3131 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
3132 return CM_ERROR_BADOP;
3136 unsigned short infoLevel;
3138 smb_tran2Packet_t *outp;
3139 smb_tran2QPathInfo_t *spi;
3141 cm_scache_t *scp, *dscp;
3149 infoLevel = p->parmsp[0];
3150 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
3151 if (infoLevel != SMB_INFO_STANDARD &&
3152 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
3153 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
3154 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3155 p->opcode, infoLevel);
3156 smb_SendTran2Error(vcp, p, opx,
3157 infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3161 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3163 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %s", infoLevel,
3164 osi_LogSaveString(smb_logp, pathp));
3166 userp = smb_GetTran2User(vcp, p);
3168 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3169 code = CM_ERROR_BADSMB;
3173 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3174 if (code == CM_ERROR_TIDIPC) {
3175 /* Attempt to use a TID allocated for IPC. The client
3176 * is probably looking for DCE RPC end points which we
3177 * don't support OR it could be looking to make a DFS
3180 osi_Log0(smb_logp, "Tran2Open received IPC TID");
3181 cm_ReleaseUser(userp);
3182 return CM_ERROR_NOSUCHPATH;
3186 * XXX Strange hack XXX
3188 * As of Patch 7 (13 January 98), we are having the following problem:
3189 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3190 * requests to look up "desktop.ini" in all the subdirectories.
3191 * This can cause zillions of timeouts looking up non-existent cells
3192 * and volumes, especially in the top-level directory.
3194 * We have not found any way to avoid this or work around it except
3195 * to explicitly ignore the requests for mount points that haven't
3196 * yet been evaluated and for directories that haven't yet been
3199 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3200 spacep = cm_GetSpace();
3201 smb_StripLastComponent(spacep->data, &lastComp, pathp);
3202 #ifndef SPECIAL_FOLDERS
3203 /* Make sure that lastComp is not NULL */
3205 if (cm_stricmp_utf8N(lastComp, "\\desktop.ini") == 0) {
3206 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3210 userp, tidPathp, &req, &dscp);
3213 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3214 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
3215 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3216 code = CM_ERROR_PATH_NOT_COVERED;
3218 code = CM_ERROR_BADSHARENAME;
3220 #endif /* DFS_SUPPORT */
3221 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3222 code = CM_ERROR_NOSUCHFILE;
3223 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3224 cm_buf_t *bp = buf_Find(dscp, &hzero);
3230 code = CM_ERROR_NOSUCHFILE;
3232 cm_ReleaseSCache(dscp);
3234 cm_FreeSpace(spacep);
3235 cm_ReleaseUser(userp);
3236 smb_SendTran2Error(vcp, p, opx, code);
3242 #endif /* SPECIAL_FOLDERS */
3244 cm_FreeSpace(spacep);
3247 /* now do namei and stat, and copy out the info */
3248 code = cm_NameI(cm_data.rootSCachep, pathp,
3249 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3251 cm_ReleaseUser(userp);
3252 smb_SendTran2Error(vcp, p, opx, code);
3256 fidp = smb_FindFIDByScache(vcp, scp);
3258 cm_ReleaseSCache(scp);
3259 cm_ReleaseUser(userp);
3260 smb_SendTran2Error(vcp, p, opx, code);
3264 lock_ObtainMutex(&fidp->mx);
3265 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
3266 lock_ReleaseMutex(&fidp->mx);
3267 cm_ReleaseSCache(scp);
3268 smb_ReleaseFID(fidp);
3269 cm_ReleaseUser(userp);
3270 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3273 lock_ReleaseMutex(&fidp->mx);
3275 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3277 outp->totalParms = 2;
3278 outp->totalData = 0;
3280 spi = (smb_tran2QPathInfo_t *)p->datap;
3281 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3284 /* lock the vnode with a callback; we need the current status
3285 * to determine what the new status is, in some cases.
3287 lock_ObtainWrite(&scp->rw);
3288 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3289 CM_SCACHESYNC_GETSTATUS
3290 | CM_SCACHESYNC_NEEDCALLBACK);
3292 lock_ReleaseWrite(&scp->rw);
3295 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3297 lock_ReleaseWrite(&scp->rw);
3298 lock_ObtainMutex(&fidp->mx);
3299 lock_ObtainRead(&scp->rw);
3301 /* prepare for setattr call */
3302 attr.mask = CM_ATTRMASK_LENGTH;
3303 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3304 attr.length.HighPart = 0;
3306 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3307 smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3308 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3309 fidp->flags |= SMB_FID_MTIMESETDONE;
3312 if (spi->u.QPstandardInfo.attributes != 0) {
3313 if ((scp->unixModeBits & 0222)
3314 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3315 /* make a writable file read-only */
3316 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3317 attr.unixModeBits = scp->unixModeBits & ~0222;
3319 else if ((scp->unixModeBits & 0222) == 0
3320 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3321 /* make a read-only file writable */
3322 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3323 attr.unixModeBits = scp->unixModeBits | 0222;
3326 lock_ReleaseRead(&scp->rw);
3327 lock_ReleaseMutex(&fidp->mx);
3331 code = cm_SetAttr(scp, &attr, userp, &req);
3335 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3336 /* we don't support EAs */
3337 code = CM_ERROR_EAS_NOT_SUPPORTED;
3341 cm_ReleaseSCache(scp);
3342 cm_ReleaseUser(userp);
3343 smb_ReleaseFID(fidp);
3345 smb_SendTran2Packet(vcp, outp, opx);
3347 smb_SendTran2Error(vcp, p, opx, code);
3348 smb_FreeTran2Packet(outp);
3354 /* TRANS2_QUERY_FILE_INFORMATION */
3355 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3357 smb_tran2Packet_t *outp;
3359 unsigned long attributes;
3360 unsigned short infoLevel;
3367 smb_tran2QFileInfo_t qfi;
3375 fidp = smb_FindFID(vcp, fid, 0);
3378 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3382 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3383 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3384 smb_CloseFID(vcp, fidp, NULL, 0);
3385 smb_ReleaseFID(fidp);
3389 infoLevel = p->parmsp[1];
3390 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3391 responseSize = sizeof(qfi.u.QFbasicInfo);
3392 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3393 responseSize = sizeof(qfi.u.QFstandardInfo);
3394 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3395 responseSize = sizeof(qfi.u.QFeaInfo);
3396 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3397 responseSize = sizeof(qfi.u.QFfileNameInfo);
3399 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3400 p->opcode, infoLevel);
3401 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3402 smb_ReleaseFID(fidp);
3405 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3407 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3409 if (infoLevel > 0x100)
3410 outp->totalParms = 2;
3412 outp->totalParms = 0;
3413 outp->totalData = responseSize;
3415 userp = smb_GetTran2User(vcp, p);
3417 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3418 code = CM_ERROR_BADSMB;
3422 lock_ObtainMutex(&fidp->mx);
3423 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3425 osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3427 lock_ReleaseMutex(&fidp->mx);
3428 lock_ObtainWrite(&scp->rw);
3429 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3430 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3434 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3436 lock_ConvertWToR(&scp->rw);
3439 /* now we have the status in the cache entry, and everything is locked.
3440 * Marshall the output data.
3442 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3443 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3444 qfi.u.QFbasicInfo.creationTime = ft;
3445 qfi.u.QFbasicInfo.lastAccessTime = ft;
3446 qfi.u.QFbasicInfo.lastWriteTime = ft;
3447 qfi.u.QFbasicInfo.lastChangeTime = ft;
3448 attributes = smb_ExtAttributes(scp);
3449 qfi.u.QFbasicInfo.attributes = attributes;
3451 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3452 qfi.u.QFstandardInfo.allocationSize = scp->length;
3453 qfi.u.QFstandardInfo.endOfFile = scp->length;
3454 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3455 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3456 qfi.u.QFstandardInfo.directory =
3457 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3458 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3459 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3461 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3462 qfi.u.QFeaInfo.eaSize = 0;
3464 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3468 lock_ReleaseRead(&scp->rw);
3469 lock_ObtainMutex(&fidp->mx);
3470 lock_ObtainRead(&scp->rw);
3471 if (fidp->NTopen_wholepathp)
3472 name = fidp->NTopen_wholepathp;
3474 name = "\\"; /* probably can't happen */
3475 lock_ReleaseMutex(&fidp->mx);
3477 smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, 0);
3478 outp->totalData = len + 4; /* this is actually what we want to return */
3479 qfi.u.QFfileNameInfo.fileNameLength = len;
3482 /* send and free the packets */
3485 lock_ReleaseRead(&scp->rw);
3487 lock_ReleaseWrite(&scp->rw);
3488 cm_ReleaseSCache(scp);
3489 cm_ReleaseUser(userp);
3490 smb_ReleaseFID(fidp);
3492 memcpy(outp->datap, &qfi, responseSize);
3493 smb_SendTran2Packet(vcp, outp, opx);
3495 smb_SendTran2Error(vcp, p, opx, code);
3497 smb_FreeTran2Packet(outp);
3503 /* TRANS2_SET_FILE_INFORMATION */
3504 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3509 unsigned short infoLevel;
3510 smb_tran2Packet_t *outp;
3511 cm_user_t *userp = NULL;
3512 cm_scache_t *scp = NULL;
3518 fidp = smb_FindFID(vcp, fid, 0);
3521 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3525 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3526 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3527 smb_CloseFID(vcp, fidp, NULL, 0);
3528 smb_ReleaseFID(fidp);
3532 infoLevel = p->parmsp[1];
3533 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3534 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3535 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3536 p->opcode, infoLevel);
3537 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3538 smb_ReleaseFID(fidp);
3542 lock_ObtainMutex(&fidp->mx);
3543 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
3544 !(fidp->flags & SMB_FID_OPENDELETE)) {
3545 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3546 fidp, fidp->scp, fidp->flags);
3547 lock_ReleaseMutex(&fidp->mx);
3548 smb_ReleaseFID(fidp);
3549 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3552 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3553 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3554 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3555 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3556 fidp, fidp->scp, fidp->flags);
3557 lock_ReleaseMutex(&fidp->mx);
3558 smb_ReleaseFID(fidp);
3559 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3564 osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3566 lock_ReleaseMutex(&fidp->mx);
3568 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3570 outp->totalParms = 2;
3571 outp->totalData = 0;
3573 userp = smb_GetTran2User(vcp, p);
3575 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3576 code = CM_ERROR_BADSMB;
3580 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3582 unsigned int attribute;
3584 smb_tran2QFileInfo_t *sfi;
3586 sfi = (smb_tran2QFileInfo_t *)p->datap;
3588 /* lock the vnode with a callback; we need the current status
3589 * to determine what the new status is, in some cases.
3591 lock_ObtainWrite(&scp->rw);
3592 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3593 CM_SCACHESYNC_GETSTATUS
3594 | CM_SCACHESYNC_NEEDCALLBACK);
3596 lock_ReleaseWrite(&scp->rw);
3600 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3602 lock_ReleaseWrite(&scp->rw);
3603 lock_ObtainMutex(&fidp->mx);
3604 lock_ObtainRead(&scp->rw);
3606 /* prepare for setattr call */
3609 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3610 /* when called as result of move a b, lastMod is (-1, -1).
3611 * If the check for -1 is not present, timestamp
3612 * of the resulting file will be 1969 (-1)
3614 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3615 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3616 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3617 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3618 fidp->flags |= SMB_FID_MTIMESETDONE;
3621 attribute = sfi->u.QFbasicInfo.attributes;
3622 if (attribute != 0) {
3623 if ((scp->unixModeBits & 0222)
3624 && (attribute & SMB_ATTR_READONLY) != 0) {
3625 /* make a writable file read-only */
3626 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3627 attr.unixModeBits = scp->unixModeBits & ~0222;
3629 else if ((scp->unixModeBits & 0222) == 0
3630 && (attribute & SMB_ATTR_READONLY) == 0) {
3631 /* make a read-only file writable */
3632 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3633 attr.unixModeBits = scp->unixModeBits | 0222;
3636 lock_ReleaseRead(&scp->rw);
3637 lock_ReleaseMutex(&fidp->mx);
3641 code = cm_SetAttr(scp, &attr, userp, &req);
3645 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3646 int delflag = *((char *)(p->datap));
3647 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
3648 delflag, fidp, scp);
3649 if (*((char *)(p->datap))) { /* File is Deleted */
3650 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3653 lock_ObtainMutex(&fidp->mx);
3654 fidp->flags |= SMB_FID_DELONCLOSE;
3655 lock_ReleaseMutex(&fidp->mx);
3657 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
3663 lock_ObtainMutex(&fidp->mx);
3664 fidp->flags &= ~SMB_FID_DELONCLOSE;
3665 lock_ReleaseMutex(&fidp->mx);
3668 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3669 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3670 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3673 attr.mask = CM_ATTRMASK_LENGTH;
3674 attr.length.LowPart = size.LowPart;
3675 attr.length.HighPart = size.HighPart;
3676 code = cm_SetAttr(scp, &attr, userp, &req);
3680 cm_ReleaseSCache(scp);
3681 cm_ReleaseUser(userp);
3682 smb_ReleaseFID(fidp);
3684 smb_SendTran2Packet(vcp, outp, opx);
3686 smb_SendTran2Error(vcp, p, opx, code);
3687 smb_FreeTran2Packet(outp);
3694 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3696 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3697 return CM_ERROR_BADOP;
3702 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3704 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3705 return CM_ERROR_BADOP;
3708 /* TRANS2_FIND_NOTIFY_FIRST */
3710 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3712 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3713 return CM_ERROR_BADOP;
3716 /* TRANS2_FIND_NOTIFY_NEXT */
3718 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3720 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3721 return CM_ERROR_BADOP;
3724 /* TRANS2_CREATE_DIRECTORY */
3726 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3728 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3729 return CM_ERROR_BADOP;
3732 /* TRANS2_SESSION_SETUP */
3734 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3736 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3737 return CM_ERROR_BADOP;
3740 struct smb_v2_referral {
3742 USHORT ReferralFlags;
3745 USHORT DfsPathOffset;
3746 USHORT DfsAlternativePathOffset;
3747 USHORT NetworkAddressOffset;
3750 /* TRANS2_GET_DFS_REFERRAL */
3752 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3754 /* This is a UNICODE only request (bit15 of Flags2) */
3755 /* The TID must be IPC$ */
3757 /* The documentation for the Flags response field is contradictory */
3759 /* Use Version 1 Referral Element Format */
3760 /* ServerType = 0; indicates the next server should be queried for the file */
3761 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3762 /* Node = UnicodeString of UNC path of the next share name */
3765 int maxReferralLevel = 0;
3766 char requestFileName[1024] = "";
3767 char referralPath[1024] = "";
3768 smb_tran2Packet_t *outp = 0;
3769 cm_user_t *userp = 0;
3770 cm_scache_t *scp = 0;
3771 cm_scache_t *dscp = 0;
3773 CPINFO CodePageInfo;
3774 int i, nbnLen, reqLen, refLen;
3779 maxReferralLevel = p->parmsp[0];
3781 GetCPInfo(CP_ACP, &CodePageInfo);
3782 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
3783 requestFileName, 1024, NULL, NULL);
3785 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
3786 maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3788 nbnLen = (int)strlen(cm_NetbiosName);
3789 reqLen = (int)strlen(requestFileName);
3791 if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
3792 !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3793 requestFileName[nbnLen+1] == '\\')
3797 if (!_strnicmp("all",&requestFileName[nbnLen+2],3) ||
3798 !_strnicmp("*.",&requestFileName[nbnLen+2],2))
3801 strcpy(referralPath, requestFileName);
3804 userp = smb_GetTran2User(vcp, p);
3806 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3807 code = CM_ERROR_BADSMB;
3812 * We have a requested path. Check to see if it is something
3815 * But be careful because the name that we might be searching
3816 * for might be a known name with the final character stripped
3819 code = cm_NameI(cm_data.rootSCachep, &requestFileName[nbnLen+2],
3820 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
3821 userp, NULL, &req, &scp);
3825 strcpy(referralPath, requestFileName);
3827 } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
3829 char pathName[1024];
3830 char *lastComponent;
3832 * we have a msdfs link somewhere in the path
3833 * we should figure out where in the path the link is.
3836 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%s]", requestFileName);
3838 strcpy(temp, &requestFileName[nbnLen+2]);
3842 cm_ReleaseSCache(dscp);
3846 cm_ReleaseSCache(scp);
3849 smb_StripLastComponent(pathName, &lastComponent, temp);
3851 code = cm_NameI(cm_data.rootSCachep, pathName,
3852 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3853 userp, NULL, &req, &dscp);
3855 code = cm_NameI(dscp, ++lastComponent,
3857 userp, NULL, &req, &scp);
3858 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK)
3861 } while (code == CM_ERROR_PATH_NOT_COVERED);
3863 /* scp should now be the DfsLink we are looking for */
3865 /* figure out how much of the input path was used */
3866 reqLen = (int)(nbnLen+2 + strlen(pathName) + 1 + strlen(lastComponent));
3868 strcpy(referralPath, &scp->mountPointStringp[strlen("msdfs:")]);
3869 refLen = (int)strlen(referralPath);
3873 char shareName[MAX_PATH + 1];
3875 /* we may have a sharename that is a volume reference */
3877 for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
3883 if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
3884 code = cm_NameI(cm_data.rootSCachep, "",
3885 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
3886 userp, p, &req, &scp);
3891 strcpy(referralPath, requestFileName);
3901 struct smb_v2_referral * v2ref;
3902 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (refLen + 8));
3904 sp = (USHORT *)outp->datap;
3906 sp[idx++] = reqLen; /* path consumed */
3907 sp[idx++] = 1; /* number of referrals */
3908 sp[idx++] = 0x03; /* flags */
3909 #ifdef DFS_VERSION_1
3910 sp[idx++] = 1; /* Version Number */
3911 sp[idx++] = refLen + 4; /* Referral Size */
3912 sp[idx++] = 1; /* Type = SMB Server */
3913 sp[idx++] = 0; /* Do not strip path consumed */
3914 for ( i=0;i<=refLen; i++ )
3915 sp[i+idx] = referralPath[i];
3916 #else /* DFS_VERSION_2 */
3917 sp[idx++] = 2; /* Version Number */
3918 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3919 idx += (sizeof(struct smb_v2_referral) / 2);
3920 v2ref = (struct smb_v2_referral *) &sp[5];
3921 v2ref->ServerType = 1; /* SMB Server */
3922 v2ref->ReferralFlags = 0x03;
3923 v2ref->Proximity = 0; /* closest */
3924 v2ref->TimeToLive = 3600; /* seconds */
3925 v2ref->DfsPathOffset = idx * 2;
3926 v2ref->DfsAlternativePathOffset = idx * 2;
3927 v2ref->NetworkAddressOffset = 0;
3928 for ( i=0;i<=refLen; i++ )
3929 sp[i+idx] = referralPath[i];
3933 code = CM_ERROR_NOSUCHPATH;
3938 cm_ReleaseSCache(dscp);
3940 cm_ReleaseSCache(scp);
3942 cm_ReleaseUser(userp);
3944 smb_SendTran2Packet(vcp, outp, op);
3946 smb_SendTran2Error(vcp, p, op, code);
3948 smb_FreeTran2Packet(outp);
3951 #else /* DFS_SUPPORT */
3952 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3953 return CM_ERROR_NOSUCHDEVICE;
3954 #endif /* DFS_SUPPORT */
3957 /* TRANS2_REPORT_DFS_INCONSISTENCY */
3959 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3961 /* This is a UNICODE only request (bit15 of Flags2) */
3963 /* There is nothing we can do about this operation. The client is going to
3964 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3965 * Unfortunately, there is really nothing we can do about it other then log it
3966 * somewhere. Even then I don't think there is anything for us to do.
3967 * So let's return an error value.
3970 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3971 return CM_ERROR_BADOP;
3975 smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
3976 char * tidPathp, char * relPathp,
3977 int infoLevel, cm_user_t *userp,
3982 cm_scache_t *targetScp; /* target if scp is a symlink */
3985 unsigned short attr;
3986 unsigned long lattr;
3987 smb_dirListPatch_t *patchp;
3988 smb_dirListPatch_t *npatchp;
3990 afs_int32 mustFake = 0;
3991 char path[AFSPATHMAX];
3993 code = cm_FindACLCache(dscp, userp, &rights);
3994 if (code == 0 && !(rights & PRSFS_READ))
3996 else if (code == -1) {
3997 lock_ObtainWrite(&dscp->rw);
3998 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
3999 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4000 lock_ReleaseWrite(&dscp->rw);
4001 if (code == CM_ERROR_NOACCESS) {
4009 for(patchp = *dirPatchespp; patchp; patchp =
4010 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4011 snprintf(path, AFSPATHMAX, "%s\\%s", relPathp ? relPathp : "", patchp->dep->name);
4012 reqp->relPathp = path;
4013 reqp->tidPathp = tidPathp;
4015 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4016 reqp->relPathp = reqp->tidPathp = NULL;
4020 lock_ObtainWrite(&scp->rw);
4022 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
4023 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4024 if (mustFake || code) {
4025 lock_ReleaseWrite(&scp->rw);
4027 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4028 errors in the client. */
4029 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4030 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4032 /* 1969-12-31 23:59:59 +00 */
4033 ft.dwHighDateTime = 0x19DB200;
4034 ft.dwLowDateTime = 0x5BB78980;
4036 /* copy to Creation Time */
4037 fa->creationTime = ft;
4038 fa->lastAccessTime = ft;
4039 fa->lastWriteTime = ft;
4040 fa->lastChangeTime = ft;
4042 switch (scp->fileType) {
4043 case CM_SCACHETYPE_DIRECTORY:
4044 case CM_SCACHETYPE_MOUNTPOINT:
4045 case CM_SCACHETYPE_SYMLINK:
4046 case CM_SCACHETYPE_INVALID:
4047 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4050 /* if we get here we either have a normal file
4051 * or we have a file for which we have never
4052 * received status info. In this case, we can
4053 * check the even/odd value of the entry's vnode.
4054 * even means it is to be treated as a directory
4055 * and odd means it is to be treated as a file.
4057 if (mustFake && (scp->fid.vnode & 0x1))
4058 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4060 fa->extFileAttributes = SMB_ATTR_NORMAL;
4063 /* merge in hidden attribute */
4064 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4065 fa->extFileAttributes |= SMB_ATTR_HIDDEN;
4068 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4070 /* 1969-12-31 23:59:58 +00*/
4071 dosTime = 0xEBBFBF7D;
4073 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4074 fa->lastAccessDateTime = fa->creationDateTime;
4075 fa->lastWriteDateTime = fa->creationDateTime;
4077 /* set the attribute */
4078 switch (scp->fileType) {
4079 case CM_SCACHETYPE_DIRECTORY:
4080 case CM_SCACHETYPE_MOUNTPOINT:
4081 case CM_SCACHETYPE_SYMLINK:
4082 case CM_SCACHETYPE_INVALID:
4083 fa->attributes = SMB_ATTR_DIRECTORY;
4085 fa->attributes = SMB_ATTR_NORMAL;
4087 /* merge in hidden (dot file) attribute */
4088 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4089 fa->attributes |= SMB_ATTR_HIDDEN;
4093 cm_ReleaseSCache(scp);
4097 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4099 /* now watch for a symlink */
4101 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
4102 lock_ReleaseWrite(&scp->rw);
4103 snprintf(path, AFSPATHMAX, "%s\\%s", relPathp ? relPathp : "", patchp->dep->name);
4104 reqp->relPathp = path;
4105 reqp->tidPathp = tidPathp;
4106 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
4107 reqp->relPathp = reqp->tidPathp = NULL;
4109 /* we have a more accurate file to use (the
4110 * target of the symbolic link). Otherwise,
4111 * we'll just use the symlink anyway.
4113 osi_Log2(smb_logp, "symlink vp %x to vp %x",
4115 cm_ReleaseSCache(scp);
4118 lock_ObtainWrite(&scp->rw);
4121 lock_ConvertWToR(&scp->rw);
4123 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4124 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4127 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4129 fa->creationTime = ft;
4130 fa->lastAccessTime = ft;
4131 fa->lastWriteTime = ft;
4132 fa->lastChangeTime = ft;
4134 /* Use length for both file length and alloc length */
4135 fa->endOfFile = scp->length;
4136 fa->allocationSize = scp->length;
4138 /* Copy attributes */
4139 lattr = smb_ExtAttributes(scp);
4140 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK ||
4141 code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4142 if (lattr == SMB_ATTR_NORMAL)
4143 lattr = SMB_ATTR_DIRECTORY;
4145 lattr |= SMB_ATTR_DIRECTORY;
4147 /* merge in hidden (dot file) attribute */
4148 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4149 if (lattr == SMB_ATTR_NORMAL)
4150 lattr = SMB_ATTR_HIDDEN;
4152 lattr |= SMB_ATTR_HIDDEN;
4155 fa->extFileAttributes = lattr;
4157 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4160 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4162 fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
4163 fa->lastAccessDateTime = fa->creationDateTime;
4164 fa->lastWriteDateTime = fa->creationDateTime;
4166 /* copy out file length and alloc length,
4167 * using the same for both
4169 fa->dataSize = scp->length.LowPart;
4170 fa->allocationSize = scp->length.LowPart;
4172 /* finally copy out attributes as short */
4173 attr = smb_Attributes(scp);
4174 /* merge in hidden (dot file) attribute */
4175 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4176 if (lattr == SMB_ATTR_NORMAL)
4177 lattr = SMB_ATTR_HIDDEN;
4179 lattr |= SMB_ATTR_HIDDEN;
4181 fa->attributes = attr;
4184 lock_ReleaseRead(&scp->rw);
4185 cm_ReleaseSCache(scp);
4188 /* now free the patches */
4189 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4190 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4194 /* and mark the list as empty */
4195 *dirPatchespp = NULL;
4200 // char table for case insensitive comparison
4201 char mapCaseTable[256];
4203 VOID initUpperCaseTable(VOID)
4206 for (i = 0; i < 256; ++i)
4207 mapCaseTable[i] = toupper(i);
4208 // make '"' match '.'
4209 mapCaseTable[(int)'"'] = toupper('.');
4210 // make '<' match '*'
4211 mapCaseTable[(int)'<'] = toupper('*');
4212 // make '>' match '?'
4213 mapCaseTable[(int)'>'] = toupper('?');
4216 /*! \brief Compare 'pattern' (containing metacharacters '*' and '?') with the file name 'name'.
4218 \note This procedure works recursively calling itself.
4220 \param[in] pattern string containing metacharacters.
4221 \param[in] name File name to be compared with 'pattern'.
4223 \return BOOL : TRUE/FALSE (match/mistmatch)
4226 szWildCardMatchFileName(char * pattern, char * name, int casefold)
4228 char upattern[MAX_PATH];
4229 char uname[MAX_PATH];
4231 char * pename; // points to the last 'name' character
4233 char * pattern_next;
4236 StringCbCopyA(upattern, sizeof(upattern), pattern);
4237 strupr_utf8(upattern, sizeof(upattern));
4240 StringCbCopyA(uname, sizeof(uname), name);
4241 strupr_utf8(uname, sizeof(uname));
4244 /* The following translations all work on single byte
4246 for (p=pattern; *p; p++) {
4247 if (*p == '"') *p = '.'; continue;
4248 if (*p == '<') *p = '*'; continue;
4249 if (*p == '>') *p = '?'; continue;
4252 for (p=name; *p; p++) {
4253 if (*p == '"') *p = '.'; continue;
4254 if (*p == '<') *p = '*'; continue;
4255 if (*p == '>') *p = '?'; continue;
4259 pename = char_prev_utf8(name + strlen(name));
4264 pattern = char_next_utf8(pattern);
4267 name = char_next_utf8(name);
4271 pattern = char_next_utf8(pattern);
4272 if (*pattern == '\0')
4275 pattern_next = char_next_utf8(pattern);
4277 for (p = pename; p >= name; p = char_prev_utf8(p)) {
4278 if (*p == *pattern &&
4279 szWildCardMatchFileName(pattern_next,
4280 char_next_utf8(p), FALSE))
4286 if (*name != *pattern)
4288 pattern = char_next_utf8(pattern);
4289 name = char_next_utf8(name);
4294 /* if all we have left are wildcards, then we match */
4295 for (;*pattern; pattern = char_next_utf8(pattern)) {
4296 if (*pattern != '*' && *pattern != '?')
4302 /* do a case-folding search of the star name mask with the name in namep.
4303 * Return 1 if we match, otherwise 0.
4305 int smb_V3MatchMask(char *namep, char *maskp, int flags)
4308 int i, j, star, qmark, casefold, retval;
4310 /* make sure we only match 8.3 names, if requested */
4311 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
4314 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
4316 /* optimize the pattern:
4317 * if there is a mixture of '?' and '*',
4318 * for example the sequence "*?*?*?*"
4319 * must be turned into the form "*"
4321 newmask = (char *)malloc(strlen(maskp)+1);
4322 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
4323 switch ( maskp[i] ) {
4335 } else if ( qmark ) {
4339 newmask[j++] = maskp[i];
4346 } else if ( qmark ) {
4350 newmask[j++] = '\0';
4352 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
4359 /* smb_ReceiveTran2SearchDir implements both
4360 * Tran2_Find_First and Tran2_Find_Next
4362 #define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
4363 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
4364 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
4365 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
4366 #define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
4368 /* this is an optimized handler for T2SearchDir that handles the case
4369 where there are no wildcards in the search path. I.e. an
4370 application is using FindFirst(Ex) to get information about a
4371 single file or directory. It will attempt to do a single lookup.
4372 If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4373 the usual mechanism.
4375 This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4377 TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
4379 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4383 long code = 0, code2 = 0;
4386 smb_dirListPatch_t *dirListPatchesp;
4387 smb_dirListPatch_t *curPatchp;
4388 size_t orbytes; /* # of bytes in this output record */
4389 size_t ohbytes; /* # of bytes, except file name */
4390 size_t onbytes; /* # of bytes in name, incl. term. null */
4391 cm_scache_t *scp = NULL;
4392 cm_scache_t *targetscp = NULL;
4393 cm_user_t *userp = NULL;
4394 char *op; /* output data ptr */
4395 char *origOp; /* original value of op */
4396 cm_space_t *spacep; /* for pathname buffer */
4397 unsigned long maxReturnData; /* max # of return data */
4398 long maxReturnParms; /* max # of return parms */
4399 long bytesInBuffer; /* # data bytes in the output buffer */
4400 char *maskp; /* mask part of path */
4404 smb_tran2Packet_t *outp; /* response packet */
4407 char shortName[13]; /* 8.3 name if needed */
4410 cm_dirEntry_t * dep = NULL;
4413 void * attrp = NULL;
4414 smb_tran2Find_t * fp;
4419 osi_assertx(p->opcode == 1, "invalid opcode");
4421 /* find first; obtain basic parameters from request */
4423 /* note that since we are going to failover to regular
4424 * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4425 * modify any of the input parameters here. */
4426 attribute = p->parmsp[0];
4427 maxCount = p->parmsp[1];
4428 infoLevel = p->parmsp[3];
4429 searchFlags = p->parmsp[2];
4430 pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4432 maskp = strrchr(pathp, '\\');
4436 maskp++; /* skip over backslash */
4437 /* track if this is likely to match a lot of entries */
4439 osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%s], mask[%s]",
4440 osi_LogSaveString(smb_logp, pathp),
4441 osi_LogSaveString(smb_logp, maskp));
4443 switch ( infoLevel ) {
4444 case SMB_INFO_STANDARD:
4446 ohbytes = sizeof(fp->u.FstandardInfo);
4449 case SMB_INFO_QUERY_EA_SIZE:
4450 ohbytes = sizeof(fp->u.FeaSizeInfo);
4451 s = "InfoQueryEaSize";
4454 case SMB_INFO_QUERY_EAS_FROM_LIST:
4455 ohbytes = sizeof(fp->u.FeasFromListInfo);
4456 s = "InfoQueryEasFromList";
4459 case SMB_FIND_FILE_DIRECTORY_INFO:
4460 s = "FindFileDirectoryInfo";
4461 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4464 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4465 s = "FindFileFullDirectoryInfo";
4466 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4469 case SMB_FIND_FILE_NAMES_INFO:
4470 s = "FindFileNamesInfo";
4471 ohbytes = sizeof(fp->u.FfileNamesInfo);
4474 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4475 s = "FindFileBothDirectoryInfo";
4476 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4480 s = "unknownInfoLevel";
4484 osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
4487 "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4488 attribute, infoLevel, maxCount, searchFlags);
4491 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4492 return CM_ERROR_INVAL;
4495 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4496 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4498 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4501 dirListPatchesp = NULL;
4503 maxReturnData = p->maxReturnData;
4504 maxReturnParms = 10; /* return params for findfirst, which
4505 is the only one we handle.*/
4507 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4508 if (maxReturnData > 6000)
4509 maxReturnData = 6000;
4510 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4512 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4515 osi_Log2(smb_logp, "T2SDSingle search dir count %d [%s]",
4516 maxCount, osi_LogSaveString(smb_logp, pathp));
4518 /* bail out if request looks bad */
4520 smb_FreeTran2Packet(outp);
4521 return CM_ERROR_BADSMB;
4524 userp = smb_GetTran2User(vcp, p);
4526 osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
4527 smb_FreeTran2Packet(outp);
4528 return CM_ERROR_BADSMB;
4531 /* try to get the vnode for the path name next */
4532 spacep = cm_GetSpace();
4533 smb_StripLastComponent(spacep->data, NULL, pathp);
4534 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4536 cm_ReleaseUser(userp);
4537 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4538 smb_FreeTran2Packet(outp);
4542 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4543 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4544 userp, tidPathp, &req, &scp);
4545 cm_FreeSpace(spacep);
4548 cm_ReleaseUser(userp);
4549 smb_SendTran2Error(vcp, p, opx, code);
4550 smb_FreeTran2Packet(outp);
4554 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4555 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4556 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
4557 cm_ReleaseSCache(scp);
4558 cm_ReleaseUser(userp);
4559 if ( WANTS_DFS_PATHNAMES(p) || pnc )
4560 code = CM_ERROR_PATH_NOT_COVERED;
4562 code = CM_ERROR_BADSHARENAME;
4563 smb_SendTran2Error(vcp, p, opx, code);
4564 smb_FreeTran2Packet(outp);
4567 #endif /* DFS_SUPPORT */
4568 osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
4570 /* now do a single case sensitive lookup for the file in question */
4571 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
4573 /* if a case sensitive match failed, we try a case insensitive one
4575 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
4576 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
4579 if (code == 0 && targetscp->fid.vnode == 0) {
4580 cm_ReleaseSCache(targetscp);
4581 code = CM_ERROR_NOSUCHFILE;
4585 /* if we can't find the directory entry, this block will
4586 return CM_ERROR_NOSUCHFILE, which we will pass on to
4587 smb_ReceiveTran2SearchDir(). */
4588 cm_ReleaseSCache(scp);
4589 cm_ReleaseUser(userp);
4590 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4591 smb_SendTran2Error(vcp, p, opx, code);
4594 smb_FreeTran2Packet(outp);
4598 /* now that we have the target in sight, we proceed with filling
4599 up the return data. */
4601 op = origOp = outp->datap;
4604 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4605 /* skip over resume key */
4609 fp = (smb_tran2Find_t *) op;
4611 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4612 && targetscp->fid.vnode != 0
4613 && !cm_Is8Dot3(maskp)) {
4616 dfid.vnode = htonl(targetscp->fid.vnode);
4617 dfid.unique = htonl(targetscp->fid.unique);
4619 cm_Gen8Dot3NameInt(maskp, &dfid, shortName, &shortNameEnd);
4625 osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %s (%s)",
4626 htonl(targetscp->fid.vnode),
4627 htonl(targetscp->fid.unique),
4628 osi_LogSaveString(smb_logp, pathp),
4629 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4631 /* Eliminate entries that don't match requested attributes */
4632 if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
4633 smb_IsDotFile(maskp)) {
4635 code = CM_ERROR_NOSUCHFILE;
4636 osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
4641 if (!(attribute & SMB_ATTR_DIRECTORY) &&
4642 (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
4643 targetscp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4644 targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
4645 targetscp->fileType == CM_SCACHETYPE_INVALID)) {
4647 code = CM_ERROR_NOSUCHFILE;
4648 osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
4653 /* add header to name & term. null */
4655 smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH);
4656 orbytes = ohbytes + onbytes;
4658 /* now, we round up the record to a 4 byte alignment, and we make
4659 * sure that we have enough room here for even the aligned version
4660 * (so we don't have to worry about an * overflow when we pad
4661 * things out below). That's the reason for the alignment
4664 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4665 align = (4 - (orbytes & 3)) & 3;
4669 if (orbytes + align > maxReturnData) {
4671 /* even though this request is unlikely to succeed with a
4672 failover, we do it anyway. */
4673 code = CM_ERROR_NOSUCHFILE;
4674 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4679 /* this is one of the entries to use: it is not deleted and it
4680 * matches the star pattern we're looking for. Put out the name,
4681 * preceded by its length.
4683 /* First zero everything else */
4684 memset(origOp, 0, orbytes);
4687 smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH);
4689 switch (infoLevel) {
4690 case SMB_INFO_STANDARD:
4691 fp->u.FstandardInfo.fileNameLength = onbytes;
4692 attrp = &fp->u.FstandardInfo.fileAttrs;
4695 case SMB_INFO_QUERY_EA_SIZE:
4696 fp->u.FeaSizeInfo.fileNameLength = onbytes;
4697 attrp = &fp->u.FeaSizeInfo.fileAttrs;
4698 fp->u.FeaSizeInfo.eaSize = 0;
4701 case SMB_INFO_QUERY_EAS_FROM_LIST:
4702 fp->u.FeasFromListInfo.fileNameLength = onbytes;
4703 attrp = &fp->u.FeasFromListInfo.fileAttrs;
4704 fp->u.FeasFromListInfo.eaSize = 0;
4707 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4708 if (NeedShortName) {
4712 nchars = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS,
4714 fp->u.FfileBothDirectoryInfo.shortName,
4715 sizeof(fp->u.FfileBothDirectoryInfo.shortName) / sizeof(wchar_t));
4717 fp->u.FfileBothDirectoryInfo.shortNameLength = (nchars - 1)*sizeof(wchar_t);
4719 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
4720 fp->u.FfileBothDirectoryInfo.reserved = 0;
4722 strcpy(fp->u.FfileBothDirectoryInfo.shortName,
4724 fp->u.FfileBothDirectoryInfo.shortNameLength = strlen(shortName);
4729 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4730 fp->u.FfileFullDirectoryInfo.eaSize = 0;
4733 case SMB_FIND_FILE_DIRECTORY_INFO:
4734 fp->u.FfileDirectoryInfo.nextEntryOffset = 0;
4735 fp->u.FfileDirectoryInfo.fileIndex = 0;
4736 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
4737 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
4740 case SMB_FIND_FILE_NAMES_INFO:
4741 fp->u.FfileNamesInfo.nextEntryOffset = 0;
4742 fp->u.FfileNamesInfo.fileIndex = 0;
4743 fp->u.FfileNamesInfo.fileNameLength = onbytes;
4747 /* we shouldn't hit this case */
4748 osi_assertx(FALSE, "Unknown query type");
4751 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4752 osi_assert(attrp != NULL);
4754 curPatchp = malloc(sizeof(*curPatchp));
4755 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4757 curPatchp->dptr = attrp;
4759 if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
4760 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4762 curPatchp->flags = 0;
4765 cm_SetFid(&curPatchp->fid, targetscp->fid.cell, targetscp->fid.volume, targetscp->fid.vnode, targetscp->fid.unique);
4768 dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+strlen(maskp));
4769 strcpy(dep->name, maskp);
4770 dep->fid.vnode = targetscp->fid.vnode;
4771 dep->fid.unique = targetscp->fid.unique;
4772 curPatchp->dep = dep;
4775 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4776 /* put out resume key */
4777 *((u_long *)origOp) = 0;
4780 /* Adjust byte ptr and count */
4781 origOp += orbytes; /* skip entire record */
4782 bytesInBuffer += orbytes;
4784 /* and pad the record out */
4785 while (--align >= 0) {
4790 /* apply the patches */
4791 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->data, infoLevel, userp, &req);
4793 outp->parmsp[0] = 0;
4794 outp->parmsp[1] = 1; /* number of names returned */
4795 outp->parmsp[2] = 1; /* end of search */
4796 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4797 outp->parmsp[4] = 0;
4799 outp->totalParms = 10; /* in bytes */
4801 outp->totalData = bytesInBuffer;
4803 osi_Log0(smb_logp, "T2SDSingle done.");
4805 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4807 smb_SendTran2Error(vcp, p, opx, code);
4809 smb_SendTran2Packet(vcp, outp, opx);
4814 smb_FreeTran2Packet(outp);
4818 cm_ReleaseSCache(scp);
4819 cm_ReleaseSCache(targetscp);
4820 cm_ReleaseUser(userp);
4826 /* TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2 */
4827 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4832 long code = 0, code2 = 0;
4834 cm_dirEntry_t *dep = 0;
4836 smb_dirListPatch_t *dirListPatchesp = 0;
4837 smb_dirListPatch_t *curPatchp = 0;
4840 size_t orbytes; /* # of bytes in this output record */
4841 size_t ohbytes; /* # of bytes, except file name */
4842 size_t onbytes; /* # of bytes in name, incl. term. null */
4843 osi_hyper_t dirLength;
4844 osi_hyper_t bufferOffset;
4845 osi_hyper_t curOffset;
4847 smb_dirSearch_t *dsp;
4851 cm_pageHeader_t *pageHeaderp;
4852 cm_user_t *userp = NULL;
4855 long nextEntryCookie;
4856 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4857 char *op; /* output data ptr */
4858 char *origOp; /* original value of op */
4859 cm_space_t *spacep; /* for pathname buffer */
4860 unsigned long maxReturnData; /* max # of return data */
4861 unsigned long maxReturnParms; /* max # of return parms */
4862 long bytesInBuffer; /* # data bytes in the output buffer */
4864 char *maskp; /* mask part of path */
4868 smb_tran2Packet_t *outp; /* response packet */
4871 char shortName[13]; /* 8.3 name if needed */
4880 smb_tran2Find_t * fp;
4885 if (p->opcode == 1) {
4886 /* find first; obtain basic parameters from request */
4887 attribute = p->parmsp[0];
4888 maxCount = p->parmsp[1];
4889 infoLevel = p->parmsp[3];
4890 searchFlags = p->parmsp[2];
4891 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4893 maskp = strrchr(pathp, '\\');
4897 maskp++; /* skip over backslash */
4899 /* track if this is likely to match a lot of entries */
4900 starPattern = smb_V3IsStarMask(maskp);
4902 #ifndef NOFINDFIRSTOPTIMIZE
4904 /* if this is for a single directory or file, we let the
4905 optimized routine handle it. The only error it
4906 returns is CM_ERROR_NOSUCHFILE. The */
4907 code = smb_T2SearchDirSingle(vcp, p, opx);
4909 /* we only failover if we see a CM_ERROR_NOSUCHFILE */
4910 if (code != CM_ERROR_NOSUCHFILE) {
4912 /* unless we are using the BPlusTree */
4913 if (code == CM_ERROR_BPLUS_NOMATCH)
4914 code = CM_ERROR_NOSUCHFILE;
4915 #endif /* USE_BPLUS */
4919 #endif /* NOFINDFIRSTOPTIMIZE */
4922 dsp = smb_NewDirSearch(1);
4923 dsp->attribute = attribute;
4924 strcpy(dsp->mask, maskp); /* and save mask */
4927 osi_assertx(p->opcode == 2, "invalid opcode");
4928 /* find next; obtain basic parameters from request or open dir file */
4929 dsp = smb_FindDirSearch(p->parmsp[0]);
4930 maxCount = p->parmsp[1];
4931 infoLevel = p->parmsp[2];
4932 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4933 searchFlags = p->parmsp[5];
4935 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4936 p->parmsp[0], nextCookie);
4937 return CM_ERROR_BADFD;
4939 attribute = dsp->attribute;
4942 starPattern = 1; /* assume, since required a Find Next */
4945 switch ( infoLevel ) {
4946 case SMB_INFO_STANDARD:
4948 ohbytes = sizeof(fp->u.FstandardInfo);
4951 case SMB_INFO_QUERY_EA_SIZE:
4952 ohbytes = sizeof(fp->u.FeaSizeInfo);
4953 s = "InfoQueryEaSize";
4956 case SMB_INFO_QUERY_EAS_FROM_LIST:
4957 ohbytes = sizeof(fp->u.FeasFromListInfo);
4958 s = "InfoQueryEasFromList";
4961 case SMB_FIND_FILE_DIRECTORY_INFO:
4962 s = "FindFileDirectoryInfo";
4963 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4966 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4967 s = "FindFileFullDirectoryInfo";
4968 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4971 case SMB_FIND_FILE_NAMES_INFO:
4972 s = "FindFileNamesInfo";
4973 ohbytes = sizeof(fp->u.FfileNamesInfo);
4976 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4977 s = "FindFileBothDirectoryInfo";
4978 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4982 s = "unknownInfoLevel";
4986 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
4989 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4990 attribute, infoLevel, maxCount, searchFlags);
4992 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
4993 p->opcode, dsp->cookie, nextCookie);
4996 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4997 smb_ReleaseDirSearch(dsp);
4998 return CM_ERROR_INVAL;
5001 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5002 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
5004 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5007 dirListPatchesp = NULL;
5009 maxReturnData = p->maxReturnData;
5010 if (p->opcode == 1) /* find first */
5011 maxReturnParms = 10; /* bytes */
5013 maxReturnParms = 8; /* bytes */
5015 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
5016 if (maxReturnData > 6000)
5017 maxReturnData = 6000;
5018 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
5020 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
5023 osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
5024 maxCount, osi_LogSaveString(smb_logp, pathp));
5026 /* bail out if request looks bad */
5027 if (p->opcode == 1 && !pathp) {
5028 smb_ReleaseDirSearch(dsp);
5029 smb_FreeTran2Packet(outp);
5030 return CM_ERROR_BADSMB;
5033 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
5034 dsp->cookie, nextCookie, attribute);
5036 userp = smb_GetTran2User(vcp, p);
5038 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
5039 smb_ReleaseDirSearch(dsp);
5040 smb_FreeTran2Packet(outp);
5041 return CM_ERROR_BADSMB;
5044 /* try to get the vnode for the path name next */
5045 lock_ObtainMutex(&dsp->mx);
5048 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5052 spacep = cm_GetSpace();
5053 smb_StripLastComponent(spacep->data, NULL, pathp);
5054 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
5056 cm_ReleaseUser(userp);
5057 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
5058 smb_FreeTran2Packet(outp);
5059 lock_ReleaseMutex(&dsp->mx);
5060 smb_DeleteDirSearch(dsp);
5061 smb_ReleaseDirSearch(dsp);
5065 strcpy(dsp->tidPath, tidPathp ? tidPathp : "/");
5066 strcpy(dsp->relPath, spacep->data);
5068 code = cm_NameI(cm_data.rootSCachep, spacep->data,
5069 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5070 userp, tidPathp, &req, &scp);
5071 cm_FreeSpace(spacep);
5074 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
5075 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5076 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
5077 cm_ReleaseSCache(scp);
5078 cm_ReleaseUser(userp);
5079 if ( WANTS_DFS_PATHNAMES(p) || pnc )
5080 code = CM_ERROR_PATH_NOT_COVERED;
5082 code = CM_ERROR_BADSHARENAME;
5083 smb_SendTran2Error(vcp, p, opx, code);
5084 smb_FreeTran2Packet(outp);
5085 lock_ReleaseMutex(&dsp->mx);
5086 smb_DeleteDirSearch(dsp);
5087 smb_ReleaseDirSearch(dsp);
5090 #endif /* DFS_SUPPORT */
5092 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5093 /* we need one hold for the entry we just stored into,
5094 * and one for our own processing. When we're done
5095 * with this function, we'll drop the one for our own
5096 * processing. We held it once from the namei call,
5097 * and so we do another hold now.
5100 lock_ObtainWrite(&scp->rw);
5101 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
5102 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
5103 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
5104 dsp->flags |= SMB_DIRSEARCH_BULKST;
5106 lock_ReleaseWrite(&scp->rw);
5109 lock_ReleaseMutex(&dsp->mx);
5111 cm_ReleaseUser(userp);
5112 smb_FreeTran2Packet(outp);
5113 smb_DeleteDirSearch(dsp);
5114 smb_ReleaseDirSearch(dsp);
5118 /* get the directory size */
5119 lock_ObtainWrite(&scp->rw);
5120 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5121 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5123 lock_ReleaseWrite(&scp->rw);
5124 cm_ReleaseSCache(scp);
5125 cm_ReleaseUser(userp);
5126 smb_FreeTran2Packet(outp);
5127 smb_DeleteDirSearch(dsp);
5128 smb_ReleaseDirSearch(dsp);
5132 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5135 dirLength = scp->length;
5137 bufferOffset.LowPart = bufferOffset.HighPart = 0;
5138 curOffset.HighPart = 0;
5139 curOffset.LowPart = nextCookie;
5140 origOp = outp->datap;
5147 char normName[MAX_PATH]; /* Normalized name */
5150 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5151 /* skip over resume key */
5154 fp = (smb_tran2Find_t *) op;
5156 /* make sure that curOffset.LowPart doesn't point to the first
5157 * 32 bytes in the 2nd through last dir page, and that it doesn't
5158 * point at the first 13 32-byte chunks in the first dir page,
5159 * since those are dir and page headers, and don't contain useful
5162 temp = curOffset.LowPart & (2048-1);
5163 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5164 /* we're in the first page */
5165 if (temp < 13*32) temp = 13*32;
5168 /* we're in a later dir page */
5169 if (temp < 32) temp = 32;
5172 /* make sure the low order 5 bits are zero */
5175 /* now put temp bits back ito curOffset.LowPart */
5176 curOffset.LowPart &= ~(2048-1);
5177 curOffset.LowPart |= temp;
5179 /* check if we've passed the dir's EOF */
5180 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
5181 osi_Log0(smb_logp, "T2 search dir passed eof");
5186 /* check if we've returned all the names that will fit in the
5187 * response packet; we check return count as well as the number
5188 * of bytes requested. We check the # of bytes after we find
5189 * the dir entry, since we'll need to check its size.
5191 if (returnedNames >= maxCount) {
5192 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
5193 returnedNames, maxCount);
5197 /* see if we can use the bufferp we have now; compute in which
5198 * page the current offset would be, and check whether that's
5199 * the offset of the buffer we have. If not, get the buffer.
5201 thyper.HighPart = curOffset.HighPart;
5202 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5203 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5206 buf_Release(bufferp);
5209 lock_ReleaseWrite(&scp->rw);
5210 code = buf_Get(scp, &thyper, &bufferp);
5211 lock_ObtainMutex(&dsp->mx);
5213 /* now, if we're doing a star match, do bulk fetching
5214 * of all of the status info for files in the dir.
5217 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, infoLevel, userp, &req);
5219 lock_ObtainWrite(&scp->rw);
5220 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
5221 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
5222 /* Don't bulk stat if risking timeout */
5223 DWORD now = GetTickCount();
5224 if (now - req.startTime > RDRtimeout * 1000) {
5225 scp->bulkStatProgress = thyper;
5226 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
5227 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
5229 code = cm_TryBulkStat(scp, &thyper, userp, &req);
5232 lock_ObtainWrite(&scp->rw);
5234 lock_ReleaseMutex(&dsp->mx);
5236 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
5240 bufferOffset = thyper;
5242 /* now get the data in the cache */
5244 code = cm_SyncOp(scp, bufferp, userp, &req,
5246 CM_SCACHESYNC_NEEDCALLBACK
5247 | CM_SCACHESYNC_READ);
5249 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5253 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5255 if (cm_HaveBuffer(scp, bufferp, 0)) {
5256 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5260 /* otherwise, load the buffer and try again */
5261 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5264 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5265 scp, bufferp, code);
5270 buf_Release(bufferp);
5274 } /* if (wrong buffer) ... */
5276 /* now we have the buffer containing the entry we're interested
5277 * in; copy it out if it represents a non-deleted entry.
5279 entryInDir = curOffset.LowPart & (2048-1);
5280 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5282 /* page header will help tell us which entries are free. Page
5283 * header can change more often than once per buffer, since
5284 * AFS 3 dir page size may be less than (but not more than)
5285 * a buffer package buffer.
5287 /* only look intra-buffer */
5288 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5289 temp &= ~(2048 - 1); /* turn off intra-page bits */
5290 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5292 /* now determine which entry we're looking at in the page.
5293 * If it is free (there's a free bitmap at the start of the
5294 * dir), we should skip these 32 bytes.
5296 slotInPage = (entryInDir & 0x7e0) >> 5;
5297 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5298 (1 << (slotInPage & 0x7)))) {
5299 /* this entry is free */
5300 numDirChunks = 1; /* only skip this guy */
5304 tp = bufferp->datap + entryInBuffer;
5305 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5307 /* while we're here, compute the next entry's location, too,
5308 * since we'll need it when writing out the cookie into the dir
5311 * XXXX Probably should do more sanity checking.
5313 numDirChunks = cm_NameEntries(dep->name, &onbytes);
5315 /* compute offset of cookie representing next entry */
5316 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5318 if (dep->fid.vnode == 0)
5319 goto nextEntry; /* This entry is not in use */
5321 cm_NormalizeUtf8String(dep->name, -1, normName, sizeof(normName)/sizeof(char));
5323 /* Need 8.3 name? */
5325 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
5326 !cm_Is8Dot3(dep->name)) {
5327 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5331 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %s (%s)",
5332 dep->fid.vnode, dep->fid.unique,
5333 osi_LogSaveString(smb_logp, normName),
5334 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
5336 /* When matching, we are using doing a case fold if we have a wildcard mask.
5337 * If we get a non-wildcard match, it's a lookup for a specific file.
5339 if (smb_V3MatchMask(normName, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5340 (NeedShortName && smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))
5342 /* Eliminate entries that don't match requested attributes */
5343 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5344 smb_IsDotFile(normName)) {
5345 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5346 goto nextEntry; /* no hidden files */
5349 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5351 /* We have already done the cm_TryBulkStat above */
5352 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5353 fileType = cm_FindFileType(&fid);
5354 /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5355 * "has filetype %d", dep->name, fileType);
5357 if ( fileType == CM_SCACHETYPE_DIRECTORY ||
5358 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5359 fileType == CM_SCACHETYPE_DFSLINK ||
5360 fileType == CM_SCACHETYPE_INVALID)
5361 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5365 /* finally check if this name will fit */
5367 smb_UnparseString(opx, NULL, normName, &onbytes, SMB_STRF_ANSIPATH);
5368 orbytes = ohbytes + onbytes;
5370 /* now, we round up the record to a 4 byte alignment,
5371 * and we make sure that we have enough room here for
5372 * even the aligned version (so we don't have to worry
5373 * about an overflow when we pad things out below).
5374 * That's the reason for the alignment arithmetic below.
5376 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5377 align = (4 - (orbytes & 3)) & 3;
5381 if (orbytes + bytesInBuffer + align > maxReturnData) {
5382 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5387 /* this is one of the entries to use: it is not deleted
5388 * and it matches the star pattern we're looking for.
5389 * Put out the name, preceded by its length.
5391 /* First zero everything else */
5392 memset(origOp, 0, orbytes);
5395 smb_UnparseString(opx, origOp + ohbytes, normName, &onbytes, SMB_STRF_ANSIPATH);
5397 switch (infoLevel) {
5398 case SMB_INFO_STANDARD:
5399 fp->u.FstandardInfo.fileNameLength = onbytes;
5400 attrp = &fp->u.FstandardInfo.fileAttrs;
5403 case SMB_INFO_QUERY_EA_SIZE:
5404 fp->u.FeaSizeInfo.fileNameLength = onbytes;
5405 attrp = &fp->u.FeaSizeInfo.fileAttrs;
5406 fp->u.FeaSizeInfo.eaSize = 0;
5409 case SMB_INFO_QUERY_EAS_FROM_LIST:
5410 fp->u.FeasFromListInfo.fileNameLength = onbytes;
5411 attrp = &fp->u.FeasFromListInfo.fileAttrs;
5412 fp->u.FeasFromListInfo.eaSize = 0;
5415 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5416 if (NeedShortName) {
5420 nchars = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS,
5422 fp->u.FfileBothDirectoryInfo.shortName,
5423 sizeof(fp->u.FfileBothDirectoryInfo.shortName) / sizeof(wchar_t));
5425 fp->u.FfileBothDirectoryInfo.shortNameLength = (nchars - 1)*sizeof(wchar_t);
5427 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5428 fp->u.FfileBothDirectoryInfo.reserved = 0;
5430 strcpy(fp->u.FfileBothDirectoryInfo.shortName,
5432 fp->u.FfileBothDirectoryInfo.shortNameLength = strlen(shortName);
5437 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5438 fp->u.FfileFullDirectoryInfo.eaSize = 0;
5441 case SMB_FIND_FILE_DIRECTORY_INFO:
5442 fp->u.FfileDirectoryInfo.nextEntryOffset = orbytes + align;
5443 fp->u.FfileDirectoryInfo.fileIndex = nextEntryCookie;
5444 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5445 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5448 case SMB_FIND_FILE_NAMES_INFO:
5449 fp->u.FfileNamesInfo.nextEntryOffset = orbytes + align;
5450 fp->u.FfileNamesInfo.fileIndex = nextEntryCookie;
5451 fp->u.FfileNamesInfo.fileNameLength = onbytes;
5456 /* we shouldn't hit this case */
5457 osi_assertx(FALSE, "Unknown query type");
5460 /* now, adjust the # of entries copied */
5463 /* now we emit the attribute. This is tricky, since
5464 * we need to really stat the file to find out what
5465 * type of entry we've got. Right now, we're copying
5466 * out data from a buffer, while holding the scp
5467 * locked, so it isn't really convenient to stat
5468 * something now. We'll put in a place holder
5469 * now, and make a second pass before returning this
5470 * to get the real attributes. So, we just skip the
5471 * data for now, and adjust it later. We allocate a
5472 * patch record to make it easy to find this point
5473 * later. The replay will happen at a time when it is
5474 * safe to unlock the directory.
5476 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5477 osi_assert(attrp != NULL);
5478 curPatchp = malloc(sizeof(*curPatchp));
5479 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5480 curPatchp->dptr = attrp;
5482 if (smb_hideDotFiles && smb_IsDotFile(normName)) {
5483 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5485 curPatchp->flags = 0;
5488 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5491 curPatchp->dep = dep;
5494 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5495 /* put out resume key */
5496 *((u_long *)origOp) = nextEntryCookie;
5498 /* Adjust byte ptr and count */
5499 origOp += orbytes; /* skip entire record */
5500 bytesInBuffer += orbytes;
5502 /* and pad the record out */
5503 while (align-- > 0) {
5507 } /* if we're including this name */
5508 else if (!starPattern &&
5510 smb_V3MatchMask(normName, maskp, CM_FLAG_CASEFOLD)) {
5511 /* We were looking for exact matches, but here's an inexact one*/
5516 /* and adjust curOffset to be where the new cookie is */
5517 thyper.HighPart = 0;
5518 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5519 curOffset = LargeIntegerAdd(thyper, curOffset);
5520 } /* while copying data for dir listing */
5522 /* If we didn't get a star pattern, we did an exact match during the first pass.
5523 * If there were no exact matches found, we fail over to inexact matches by
5524 * marking the query as a star pattern (matches all case permutations), and
5525 * re-running the query.
5527 if (returnedNames == 0 && !starPattern && foundInexact) {
5528 osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
5533 /* release the mutex */
5534 lock_ReleaseWrite(&scp->rw);
5536 buf_Release(bufferp);
5540 /* apply and free last set of patches; if not doing a star match, this
5541 * will be empty, but better safe (and freeing everything) than sorry.
5543 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5544 dsp->relPath, infoLevel, userp, &req);
5546 /* now put out the final parameters */
5547 if (returnedNames == 0)
5549 if (p->opcode == 1) {
5551 outp->parmsp[0] = (unsigned short) dsp->cookie;
5552 outp->parmsp[1] = returnedNames;
5553 outp->parmsp[2] = eos;
5554 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5555 outp->parmsp[4] = 0;
5556 /* don't need last name to continue
5557 * search, cookie is enough. Normally,
5558 * this is the offset of the file name
5559 * of the last entry returned.
5561 outp->totalParms = 10; /* in bytes */
5565 outp->parmsp[0] = returnedNames;
5566 outp->parmsp[1] = eos;
5567 outp->parmsp[2] = 0; /* EAS error */
5568 outp->parmsp[3] = 0; /* last name, as above */
5569 outp->totalParms = 8; /* in bytes */
5572 /* return # of bytes in the buffer */
5573 outp->totalData = bytesInBuffer;
5575 /* Return error code if unsuccessful on first request */
5576 if (code == 0 && p->opcode == 1 && returnedNames == 0)
5577 code = CM_ERROR_NOSUCHFILE;
5579 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
5580 p->opcode, dsp->cookie, returnedNames, code);
5582 /* if we're supposed to close the search after this request, or if
5583 * we're supposed to close the search if we're done, and we're done,
5584 * or if something went wrong, close the search.
5586 if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
5587 (returnedNames == 0) ||
5588 ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
5590 smb_DeleteDirSearch(dsp);
5593 smb_SendTran2Error(vcp, p, opx, code);
5595 smb_SendTran2Packet(vcp, outp, opx);
5597 smb_FreeTran2Packet(outp);
5598 smb_ReleaseDirSearch(dsp);
5599 cm_ReleaseSCache(scp);
5600 cm_ReleaseUser(userp);
5604 /* SMB_COM_FIND_CLOSE2 */
5605 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5608 smb_dirSearch_t *dsp;
5610 dirHandle = smb_GetSMBParm(inp, 0);
5612 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
5614 dsp = smb_FindDirSearch(dirHandle);
5617 return CM_ERROR_BADFD;
5619 /* otherwise, we have an FD to destroy */
5620 smb_DeleteDirSearch(dsp);
5621 smb_ReleaseDirSearch(dsp);
5623 /* and return results */
5624 smb_SetSMBDataLength(outp, 0);
5630 /* SMB_COM_FIND_NOTIFY_CLOSE */
5631 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5633 smb_SetSMBDataLength(outp, 0);
5637 /* SMB_COM_OPEN_ANDX */
5638 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5645 cm_scache_t *dscp; /* dir we're dealing with */
5646 cm_scache_t *scp; /* file we're creating */
5648 int initialModeBits;
5652 unsigned long dosTime;
5658 int parmSlot; /* which parm we're dealing with */
5667 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
5668 openFun = smb_GetSMBParm(inp, 8); /* open function */
5669 excl = ((openFun & 3) == 0);
5670 trunc = ((openFun & 3) == 2); /* truncate it */
5671 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
5672 openAction = 0; /* tracks what we did */
5674 attributes = smb_GetSMBParm(inp, 5);
5675 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
5677 /* compute initial mode bits based on read-only flag in attributes */
5678 initialModeBits = 0666;
5679 if (attributes & SMB_ATTR_READONLY)
5680 initialModeBits &= ~0222;
5682 pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
5685 spacep = inp->spacep;
5686 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5689 (cm_stricmp_utf8N(lastNamep, SMB_IOCTL_FILENAME) == 0 ||
5690 cm_stricmp_utf8N(lastNamep, "\\srvsvc") == 0 ||
5691 cm_stricmp_utf8N(lastNamep, "\\wkssvc") == 0 ||
5692 cm_stricmp_utf8N(lastNamep, "ipc$") == 0)) {
5693 /* special case magic file name for receiving IOCTL requests
5694 * (since IOCTL calls themselves aren't getting through).
5697 osi_Log0(smb_logp, "IOCTL Open");
5700 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5701 smb_SetupIoctlFid(fidp, spacep);
5703 /* set inp->fid so that later read calls in same msg can find fid */
5704 inp->fid = fidp->fid;
5706 /* copy out remainder of the parms */
5708 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5710 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
5711 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
5712 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5713 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
5714 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
5715 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5716 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5717 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5719 /* and the final "always present" stuff */
5720 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
5721 /* next write out the "unique" ID */
5722 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
5723 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
5724 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5725 smb_SetSMBDataLength(outp, 0);
5727 /* and clean up fid reference */
5728 smb_ReleaseFID(fidp);
5732 #ifdef DEBUG_VERBOSE
5734 char *hexp, *asciip;
5735 asciip = (lastNamep ? lastNamep : pathp );
5736 hexp = osi_HexifyString(asciip);
5737 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
5741 userp = smb_GetUserFromVCP(vcp, inp);
5744 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5746 cm_ReleaseUser(userp);
5747 return CM_ERROR_NOSUCHPATH;
5749 code = cm_NameI(cm_data.rootSCachep, pathp,
5750 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5751 userp, tidPathp, &req, &scp);
5754 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5755 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5756 cm_ReleaseSCache(scp);
5757 cm_ReleaseUser(userp);
5758 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5759 return CM_ERROR_PATH_NOT_COVERED;
5761 return CM_ERROR_BADSHARENAME;
5763 #endif /* DFS_SUPPORT */
5766 code = cm_NameI(cm_data.rootSCachep, spacep->data,
5767 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5768 userp, tidPathp, &req, &dscp);
5770 cm_ReleaseUser(userp);
5775 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5776 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
5777 cm_ReleaseSCache(dscp);
5778 cm_ReleaseUser(userp);
5779 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5780 return CM_ERROR_PATH_NOT_COVERED;
5782 return CM_ERROR_BADSHARENAME;
5784 #endif /* DFS_SUPPORT */
5785 /* otherwise, scp points to the parent directory. Do a lookup,
5786 * and truncate the file if we find it, otherwise we create the
5793 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
5795 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5796 cm_ReleaseSCache(dscp);
5797 cm_ReleaseUser(userp);
5802 /* if we get here, if code is 0, the file exists and is represented by
5803 * scp. Otherwise, we have to create it. The dir may be represented
5804 * by dscp, or we may have found the file directly. If code is non-zero,
5808 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
5810 if (dscp) cm_ReleaseSCache(dscp);
5811 cm_ReleaseSCache(scp);
5812 cm_ReleaseUser(userp);
5817 /* oops, file shouldn't be there */
5819 cm_ReleaseSCache(dscp);
5820 cm_ReleaseSCache(scp);
5821 cm_ReleaseUser(userp);
5822 return CM_ERROR_EXISTS;
5826 setAttr.mask = CM_ATTRMASK_LENGTH;
5827 setAttr.length.LowPart = 0;
5828 setAttr.length.HighPart = 0;
5829 code = cm_SetAttr(scp, &setAttr, userp, &req);
5830 openAction = 3; /* truncated existing file */
5832 else openAction = 1; /* found existing file */
5834 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
5835 /* don't create if not found */
5836 if (dscp) cm_ReleaseSCache(dscp);
5837 cm_ReleaseUser(userp);
5838 return CM_ERROR_NOSUCHFILE;
5841 osi_assertx(dscp != NULL, "null cm_scache_t");
5842 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
5843 osi_LogSaveString(smb_logp, lastNamep));
5844 openAction = 2; /* created file */
5845 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5846 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5847 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5851 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5852 smb_NotifyChange(FILE_ACTION_ADDED,
5853 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5854 dscp, lastNamep, NULL, TRUE);
5855 } else if (!excl && code == CM_ERROR_EXISTS) {
5856 /* not an exclusive create, and someone else tried
5857 * creating it already, then we open it anyway. We
5858 * don't bother retrying after this, since if this next
5859 * fails, that means that the file was deleted after we
5860 * started this call.
5862 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5866 setAttr.mask = CM_ATTRMASK_LENGTH;
5867 setAttr.length.LowPart = 0;
5868 setAttr.length.HighPart = 0;
5869 code = cm_SetAttr(scp, &setAttr, userp, &req);
5871 } /* lookup succeeded */
5875 /* we don't need this any longer */
5877 cm_ReleaseSCache(dscp);
5880 /* something went wrong creating or truncating the file */
5882 cm_ReleaseSCache(scp);
5883 cm_ReleaseUser(userp);
5887 /* make sure we're about to open a file */
5888 if (scp->fileType != CM_SCACHETYPE_FILE) {
5889 cm_ReleaseSCache(scp);
5890 cm_ReleaseUser(userp);
5891 return CM_ERROR_ISDIR;
5894 /* now all we have to do is open the file itself */
5895 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5896 osi_assertx(fidp, "null smb_fid_t");
5899 lock_ObtainMutex(&fidp->mx);
5900 /* save a pointer to the vnode */
5902 lock_ObtainWrite(&scp->rw);
5903 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5904 lock_ReleaseWrite(&scp->rw);
5905 osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
5907 fidp->userp = userp;
5909 /* compute open mode */
5911 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5912 if (openMode == 1 || openMode == 2)
5913 fidp->flags |= SMB_FID_OPENWRITE;
5915 /* remember if the file was newly created */
5917 fidp->flags |= SMB_FID_CREATED;
5919 lock_ReleaseMutex(&fidp->mx);
5920 smb_ReleaseFID(fidp);
5922 cm_Open(scp, 0, userp);
5924 /* set inp->fid so that later read calls in same msg can find fid */
5925 inp->fid = fidp->fid;
5927 /* copy out remainder of the parms */
5929 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5930 lock_ObtainRead(&scp->rw);
5932 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5933 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5934 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5935 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5936 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5937 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5938 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5939 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5940 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5942 /* and the final "always present" stuff */
5943 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5944 /* next write out the "unique" ID */
5945 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5946 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5947 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5948 lock_ReleaseRead(&scp->rw);
5949 smb_SetSMBDataLength(outp, 0);
5951 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5953 cm_ReleaseUser(userp);
5954 /* leave scp held since we put it in fidp->scp */
5958 static void smb_GetLockParams(unsigned char LockType,
5960 unsigned int * ppid,
5961 LARGE_INTEGER * pOffset,
5962 LARGE_INTEGER * pLength)
5964 if (LockType & LOCKING_ANDX_LARGE_FILES) {
5966 *ppid = *((USHORT *) *buf);
5967 pOffset->HighPart = *((LONG *)(*buf + 4));
5968 pOffset->LowPart = *((DWORD *)(*buf + 8));
5969 pLength->HighPart = *((LONG *)(*buf + 12));
5970 pLength->LowPart = *((DWORD *)(*buf + 16));
5974 /* Not Large Files */
5975 *ppid = *((USHORT *) *buf);
5976 pOffset->HighPart = 0;
5977 pOffset->LowPart = *((DWORD *)(*buf + 2));
5978 pLength->HighPart = 0;
5979 pLength->LowPart = *((DWORD *)(*buf + 6));
5984 /* SMB_COM_LOCKING_ANDX */
5985 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5992 unsigned char LockType;
5993 unsigned short NumberOfUnlocks, NumberOfLocks;
5997 LARGE_INTEGER LOffset, LLength;
5998 smb_waitingLockRequest_t *wlRequest = NULL;
5999 cm_file_lock_t *lockp;
6007 fid = smb_GetSMBParm(inp, 2);
6008 fid = smb_ChainFID(fid, inp);
6010 fidp = smb_FindFID(vcp, fid, 0);
6012 return CM_ERROR_BADFD;
6014 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6015 smb_CloseFID(vcp, fidp, NULL, 0);
6016 smb_ReleaseFID(fidp);
6017 return CM_ERROR_NOSUCHFILE;
6020 lock_ObtainMutex(&fidp->mx);
6021 if (fidp->flags & SMB_FID_IOCTL) {
6022 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
6023 lock_ReleaseMutex(&fidp->mx);
6024 smb_ReleaseFID(fidp);
6025 return CM_ERROR_BADFD;
6028 osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
6030 lock_ReleaseMutex(&fidp->mx);
6032 /* set inp->fid so that later read calls in same msg can find fid */
6035 userp = smb_GetUserFromVCP(vcp, inp);
6038 lock_ObtainWrite(&scp->rw);
6039 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6040 CM_SCACHESYNC_NEEDCALLBACK
6041 | CM_SCACHESYNC_GETSTATUS
6042 | CM_SCACHESYNC_LOCK);
6044 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
6048 LockType = smb_GetSMBParm(inp, 3) & 0xff;
6049 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
6050 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
6051 NumberOfLocks = smb_GetSMBParm(inp, 7);
6053 if (!(fidp->flags & SMB_FID_OPENWRITE) &&
6054 !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
6055 /* somebody wants exclusive locks on a file that they only
6056 opened for reading. We downgrade this to a shared lock. */
6057 osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
6058 LockType |= LOCKING_ANDX_SHARED_LOCK;
6061 if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
6062 /* AFS does not support atomic changes of lock types from read or write and vice-versa */
6063 osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]");
6064 code = CM_ERROR_BADOP;
6069 op = smb_GetSMBData(inp, NULL);
6071 if (LockType & LOCKING_ANDX_CANCEL_LOCK) {
6072 /* Cancel outstanding lock requests */
6073 smb_waitingLock_t * wl;
6075 for (i=0; i<NumberOfLocks; i++) {
6076 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6078 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6080 lock_ObtainWrite(&smb_globalLock);
6081 for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
6083 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
6084 if (wl->key == key && LargeIntegerEqualTo(wl->LOffset, LOffset) &&
6085 LargeIntegerEqualTo(wl->LLength, LLength)) {
6086 wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
6087 goto found_lock_request;
6092 lock_ReleaseWrite(&smb_globalLock);
6095 smb_SetSMBDataLength(outp, 0);
6100 for (i=0; i<NumberOfUnlocks; i++) {
6101 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6103 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6105 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
6113 for (i=0; i<NumberOfLocks; i++) {
6114 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6116 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6118 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
6119 userp, &req, &lockp);
6121 if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
6122 (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
6124 code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
6125 userp, &req, &lockp);
6128 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
6129 smb_waitingLock_t * wLock;
6131 /* Put on waiting list */
6132 if(wlRequest == NULL) {
6136 LARGE_INTEGER tOffset, tLength;
6138 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
6140 osi_assertx(wlRequest != NULL, "null wlRequest");
6142 wlRequest->vcp = vcp;
6144 wlRequest->scp = scp;
6145 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
6147 wlRequest->inp = smb_CopyPacket(inp);
6148 wlRequest->outp = smb_CopyPacket(outp);
6149 wlRequest->lockType = LockType;
6150 wlRequest->msTimeout = Timeout;
6151 wlRequest->start_t = osi_Time();
6152 wlRequest->locks = NULL;
6154 /* The waiting lock request needs to have enough
6155 information to undo all the locks in the request.
6156 We do the following to store info about locks that
6157 have already been granted. Sure, we can get most
6158 of the info from the packet, but the packet doesn't
6159 hold the result of cm_Lock call. In practice we
6160 only receive packets with one or two locks, so we
6161 are only wasting a few bytes here and there and
6162 only for a limited period of time until the waiting
6163 lock times out or is freed. */
6165 for(opt = op_locks, j=i; j > 0; j--) {
6166 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
6168 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6170 wLock = malloc(sizeof(smb_waitingLock_t));
6172 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6175 wLock->LOffset = tOffset;
6176 wLock->LLength = tLength;
6177 wLock->lockp = NULL;
6178 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
6179 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6184 wLock = malloc(sizeof(smb_waitingLock_t));
6186 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6189 wLock->LOffset = LOffset;
6190 wLock->LLength = LLength;
6191 wLock->lockp = lockp;
6192 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
6193 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6196 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
6204 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
6211 /* Since something went wrong with the lock number i, we now
6212 have to go ahead and release any locks acquired before the
6213 failure. All locks before lock number i (of which there
6214 are i of them) have either been successful or are waiting.
6215 Either case requires calling cm_Unlock(). */
6217 /* And purge the waiting lock */
6218 if(wlRequest != NULL) {
6219 smb_waitingLock_t * wl;
6220 smb_waitingLock_t * wlNext;
6223 for(wl = wlRequest->locks; wl; wl = wlNext) {
6225 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
6227 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
6230 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
6232 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
6235 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
6240 smb_ReleaseVC(wlRequest->vcp);
6241 cm_ReleaseSCache(wlRequest->scp);
6242 smb_FreePacket(wlRequest->inp);
6243 smb_FreePacket(wlRequest->outp);
6252 if (wlRequest != NULL) {
6254 lock_ObtainWrite(&smb_globalLock);
6255 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
6257 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
6258 lock_ReleaseWrite(&smb_globalLock);
6260 /* don't send reply immediately */
6261 outp->flags |= SMB_PACKETFLAG_NOSEND;
6264 smb_SetSMBDataLength(outp, 0);
6268 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
6271 lock_ReleaseWrite(&scp->rw);
6272 cm_ReleaseSCache(scp);
6273 cm_ReleaseUser(userp);
6274 smb_ReleaseFID(fidp);
6279 /* SMB_COM_QUERY_INFORMATION2 */
6280 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6286 afs_uint32 searchTime;
6293 fid = smb_GetSMBParm(inp, 0);
6294 fid = smb_ChainFID(fid, inp);
6296 fidp = smb_FindFID(vcp, fid, 0);
6298 return CM_ERROR_BADFD;
6300 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6301 smb_CloseFID(vcp, fidp, NULL, 0);
6302 smb_ReleaseFID(fidp);
6303 return CM_ERROR_NOSUCHFILE;
6306 lock_ObtainMutex(&fidp->mx);
6307 if (fidp->flags & SMB_FID_IOCTL) {
6308 lock_ReleaseMutex(&fidp->mx);
6309 smb_ReleaseFID(fidp);
6310 return CM_ERROR_BADFD;
6313 osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6315 lock_ReleaseMutex(&fidp->mx);
6317 userp = smb_GetUserFromVCP(vcp, inp);
6320 /* otherwise, stat the file */
6321 lock_ObtainWrite(&scp->rw);
6322 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6323 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6327 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6329 lock_ConvertWToR(&scp->rw);
6331 /* decode times. We need a search time, but the response to this
6332 * call provides the date first, not the time, as returned in the
6333 * searchTime variable. So we take the high-order bits first.
6335 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
6336 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
6337 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
6338 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
6339 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
6340 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
6341 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
6343 /* now handle file size and allocation size */
6344 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
6345 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
6346 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
6347 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
6349 /* file attribute */
6350 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
6352 /* and finalize stuff */
6353 smb_SetSMBDataLength(outp, 0);
6358 lock_ReleaseRead(&scp->rw);
6360 lock_ReleaseWrite(&scp->rw);
6361 cm_ReleaseSCache(scp);
6362 cm_ReleaseUser(userp);
6363 smb_ReleaseFID(fidp);
6367 /* SMB_COM_SET_INFORMATION2 */
6368 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6374 afs_uint32 searchTime;
6382 fid = smb_GetSMBParm(inp, 0);
6383 fid = smb_ChainFID(fid, inp);
6385 fidp = smb_FindFID(vcp, fid, 0);
6387 return CM_ERROR_BADFD;
6389 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6390 smb_CloseFID(vcp, fidp, NULL, 0);
6391 smb_ReleaseFID(fidp);
6392 return CM_ERROR_NOSUCHFILE;
6395 lock_ObtainMutex(&fidp->mx);
6396 if (fidp->flags & SMB_FID_IOCTL) {
6397 lock_ReleaseMutex(&fidp->mx);
6398 smb_ReleaseFID(fidp);
6399 return CM_ERROR_BADFD;
6402 osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6404 lock_ReleaseMutex(&fidp->mx);
6406 userp = smb_GetUserFromVCP(vcp, inp);
6409 /* now prepare to call cm_setattr. This message only sets various times,
6410 * and AFS only implements mtime, and we'll set the mtime if that's
6411 * requested. The others we'll ignore.
6413 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
6415 if (searchTime != 0) {
6416 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
6418 if ( unixTime != -1 ) {
6419 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
6420 attrs.clientModTime = unixTime;
6421 code = cm_SetAttr(scp, &attrs, userp, &req);
6423 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
6425 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
6431 cm_ReleaseSCache(scp);
6432 cm_ReleaseUser(userp);
6433 smb_ReleaseFID(fidp);
6437 /* SMB_COM_WRITE_ANDX */
6438 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6441 long count, written = 0, total_written = 0;
6445 smb_t *smbp = (smb_t*) inp;
6449 int inDataBlockCount;
6451 fd = smb_GetSMBParm(inp, 2);
6452 count = smb_GetSMBParm(inp, 10);
6454 offset.HighPart = 0;
6455 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6457 if (*inp->wctp == 14) {
6458 /* we have a request with 64-bit file offsets */
6459 #ifdef AFS_LARGEFILES
6460 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6462 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6464 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
6465 /* we shouldn't have received this op if we didn't specify
6466 largefile support */
6467 return CM_ERROR_BADOP;
6472 op = inp->data + smb_GetSMBParm(inp, 11);
6473 inDataBlockCount = count;
6475 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
6476 fd, offset.HighPart, offset.LowPart, count);
6478 fd = smb_ChainFID(fd, inp);
6479 fidp = smb_FindFID(vcp, fd, 0);
6481 return CM_ERROR_BADFD;
6483 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6484 smb_CloseFID(vcp, fidp, NULL, 0);
6485 smb_ReleaseFID(fidp);
6486 return CM_ERROR_NOSUCHFILE;
6489 lock_ObtainMutex(&fidp->mx);
6490 if (fidp->flags & SMB_FID_IOCTL) {
6491 lock_ReleaseMutex(&fidp->mx);
6492 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
6493 smb_ReleaseFID(fidp);
6496 lock_ReleaseMutex(&fidp->mx);
6497 userp = smb_GetUserFromVCP(vcp, inp);
6499 /* special case: 0 bytes transferred means there is no data
6500 transferred. A slight departure from SMB_COM_WRITE where this
6501 means that we are supposed to truncate the file at this
6506 LARGE_INTEGER LOffset;
6507 LARGE_INTEGER LLength;
6511 key = cm_GenerateKey(vcp->vcID, pid, fd);
6513 LOffset.HighPart = offset.HighPart;
6514 LOffset.LowPart = offset.LowPart;
6515 LLength.HighPart = 0;
6516 LLength.LowPart = count;
6519 lock_ObtainWrite(&scp->rw);
6520 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
6521 lock_ReleaseWrite(&scp->rw);
6528 * Work around bug in NT client
6530 * When copying a file, the NT client should first copy the data,
6531 * then copy the last write time. But sometimes the NT client does
6532 * these in the wrong order, so the data copies would inadvertently
6533 * cause the last write time to be overwritten. We try to detect this,
6534 * and don't set client mod time if we think that would go against the
6537 lock_ObtainMutex(&fidp->mx);
6538 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6539 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6540 fidp->scp->clientModTime = time(NULL);
6542 lock_ReleaseMutex(&fidp->mx);
6545 while ( code == 0 && count > 0 ) {
6546 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6547 if (code == 0 && written == 0)
6548 code = CM_ERROR_PARTIALWRITE;
6550 offset = LargeIntegerAdd(offset,
6551 ConvertLongToLargeInteger(written));
6553 total_written += written;
6557 /* slots 0 and 1 are reserved for request chaining and will be
6558 filled in when we return. */
6559 smb_SetSMBParm(outp, 2, total_written);
6560 smb_SetSMBParm(outp, 3, 0); /* reserved */
6561 smb_SetSMBParm(outp, 4, 0); /* reserved */
6562 smb_SetSMBParm(outp, 5, 0); /* reserved */
6563 smb_SetSMBDataLength(outp, 0);
6566 cm_ReleaseUser(userp);
6567 smb_ReleaseFID(fidp);
6572 /* SMB_COM_READ_ANDX */
6573 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6577 long finalCount = 0;
6581 smb_t *smbp = (smb_t*) inp;
6587 fd = smb_GetSMBParm(inp, 2);
6588 count = smb_GetSMBParm(inp, 5);
6589 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6591 if (*inp->wctp == 12) {
6592 /* a request with 64-bit offsets */
6593 #ifdef AFS_LARGEFILES
6594 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
6596 if (LargeIntegerLessThanZero(offset)) {
6597 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
6598 offset.HighPart, offset.LowPart);
6599 return CM_ERROR_BADSMB;
6602 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
6603 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
6604 return CM_ERROR_BADSMB;
6606 offset.HighPart = 0;
6610 offset.HighPart = 0;
6613 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
6614 fd, offset.HighPart, offset.LowPart, count);
6616 fd = smb_ChainFID(fd, inp);
6617 fidp = smb_FindFID(vcp, fd, 0);
6619 return CM_ERROR_BADFD;
6622 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6623 smb_CloseFID(vcp, fidp, NULL, 0);
6624 smb_ReleaseFID(fidp);
6625 return CM_ERROR_NOSUCHFILE;
6629 key = cm_GenerateKey(vcp->vcID, pid, fd);
6631 LARGE_INTEGER LOffset, LLength;
6634 LOffset.HighPart = offset.HighPart;
6635 LOffset.LowPart = offset.LowPart;
6636 LLength.HighPart = 0;
6637 LLength.LowPart = count;
6640 lock_ObtainWrite(&scp->rw);
6641 code = cm_LockCheckRead(scp, LOffset, LLength, key);
6642 lock_ReleaseWrite(&scp->rw);
6646 smb_ReleaseFID(fidp);
6650 /* set inp->fid so that later read calls in same msg can find fid */
6653 lock_ObtainMutex(&fidp->mx);
6654 if (fidp->flags & SMB_FID_IOCTL) {
6655 lock_ReleaseMutex(&fidp->mx);
6656 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
6657 smb_ReleaseFID(fidp);
6660 lock_ReleaseMutex(&fidp->mx);
6662 userp = smb_GetUserFromVCP(vcp, inp);
6664 /* 0 and 1 are reserved for request chaining, were setup by our caller,
6665 * and will be further filled in after we return.
6667 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
6668 smb_SetSMBParm(outp, 3, 0); /* resvd */
6669 smb_SetSMBParm(outp, 4, 0); /* resvd */
6670 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
6671 /* fill in #6 when we have all the parameters' space reserved */
6672 smb_SetSMBParm(outp, 7, 0); /* resv'd */
6673 smb_SetSMBParm(outp, 8, 0); /* resv'd */
6674 smb_SetSMBParm(outp, 9, 0); /* resv'd */
6675 smb_SetSMBParm(outp, 10, 0); /* resv'd */
6676 smb_SetSMBParm(outp, 11, 0); /* reserved */
6678 /* get op ptr after putting in the parms, since otherwise we don't
6679 * know where the data really is.
6681 op = smb_GetSMBData(outp, NULL);
6683 /* now fill in offset from start of SMB header to first data byte (to op) */
6684 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
6686 /* set the packet data length the count of the # of bytes */
6687 smb_SetSMBDataLength(outp, count);
6689 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6691 /* fix some things up */
6692 smb_SetSMBParm(outp, 5, finalCount);
6693 smb_SetSMBDataLength(outp, finalCount);
6695 cm_ReleaseUser(userp);
6696 smb_ReleaseFID(fidp);
6701 * Values for createDisp, copied from NTDDK.H
6703 #define FILE_SUPERSEDE 0 // (???)
6704 #define FILE_OPEN 1 // (open)
6705 #define FILE_CREATE 2 // (exclusive)
6706 #define FILE_OPEN_IF 3 // (non-exclusive)
6707 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
6708 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
6711 #define REQUEST_OPLOCK 2
6712 #define REQUEST_BATCH_OPLOCK 4
6713 #define OPEN_DIRECTORY 8
6714 #define EXTENDED_RESPONSE_REQUIRED 0x10
6716 /* CreateOptions field. */
6717 #define FILE_DIRECTORY_FILE 0x0001
6718 #define FILE_WRITE_THROUGH 0x0002
6719 #define FILE_SEQUENTIAL_ONLY 0x0004
6720 #define FILE_NON_DIRECTORY_FILE 0x0040
6721 #define FILE_NO_EA_KNOWLEDGE 0x0200
6722 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
6723 #define FILE_RANDOM_ACCESS 0x0800
6724 #define FILE_DELETE_ON_CLOSE 0x1000
6725 #define FILE_OPEN_BY_FILE_ID 0x2000
6727 /* SMB_COM_NT_CREATE_ANDX */
6728 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6730 char *pathp, *realPathp;
6734 cm_scache_t *dscp; /* parent dir */
6735 cm_scache_t *scp; /* file to create or open */
6736 cm_scache_t *targetScp; /* if scp is a symlink */
6740 unsigned short nameLength;
6742 unsigned int requestOpLock;
6743 unsigned int requestBatchOpLock;
6744 unsigned int mustBeDir;
6745 unsigned int extendedRespRequired;
6746 unsigned int treeCreate;
6748 unsigned int desiredAccess;
6749 unsigned int extAttributes;
6750 unsigned int createDisp;
6751 unsigned int createOptions;
6752 unsigned int shareAccess;
6753 int initialModeBits;
6754 unsigned short baseFid;
6755 smb_fid_t *baseFidp;
6757 cm_scache_t *baseDirp;
6758 unsigned short openAction;
6767 cm_lock_data_t *ldp = NULL;
6771 /* This code is very long and has a lot of if-then-else clauses
6772 * scp and dscp get reused frequently and we need to ensure that
6773 * we don't lose a reference. Start by ensuring that they are NULL.
6780 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
6781 flags = smb_GetSMBOffsetParm(inp, 3, 1)
6782 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
6783 requestOpLock = flags & REQUEST_OPLOCK;
6784 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6785 mustBeDir = flags & OPEN_DIRECTORY;
6786 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6789 * Why all of a sudden 32-bit FID?
6790 * We will reject all bits higher than 16.
6792 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
6793 return CM_ERROR_INVAL;
6794 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
6795 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
6796 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6797 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
6798 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
6799 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
6800 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
6801 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
6802 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
6803 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
6804 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
6806 /* mustBeDir is never set; createOptions directory bit seems to be
6809 if (createOptions & FILE_DIRECTORY_FILE)
6811 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6817 * compute initial mode bits based on read-only flag in
6818 * extended attributes
6820 initialModeBits = 0666;
6821 if (extAttributes & SMB_ATTR_READONLY)
6822 initialModeBits &= ~0222;
6824 pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
6825 NULL, SMB_STRF_ANSIPATH);
6827 /* Sometimes path is not null-terminated, so we make a copy. */
6828 realPathp = malloc(nameLength+1);
6829 memcpy(realPathp, pathp, nameLength);
6830 realPathp[nameLength] = 0;
6832 spacep = inp->spacep;
6833 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6835 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
6836 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
6837 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
6840 (cm_stricmp_utf8N(lastNamep, SMB_IOCTL_FILENAME) == 0 ||
6841 cm_stricmp_utf8N(lastNamep, "\\srvsvc") == 0 ||
6842 cm_stricmp_utf8N(lastNamep, "\\wkssvc") == 0 ||
6843 cm_stricmp_utf8N(lastNamep, "ipc$") == 0)) {
6844 /* special case magic file name for receiving IOCTL requests
6845 * (since IOCTL calls themselves aren't getting through).
6847 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6848 smb_SetupIoctlFid(fidp, spacep);
6849 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
6851 /* set inp->fid so that later read calls in same msg can find fid */
6852 inp->fid = fidp->fid;
6856 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6857 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6858 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
6860 memset(&ft, 0, sizeof(ft));
6861 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6862 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6863 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6864 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6865 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
6866 sz.HighPart = 0x7fff; sz.LowPart = 0;
6867 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
6868 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
6869 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6870 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6871 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
6872 smb_SetSMBDataLength(outp, 0);
6874 /* clean up fid reference */
6875 smb_ReleaseFID(fidp);
6880 #ifdef DEBUG_VERBOSE
6882 char *hexp, *asciip;
6883 asciip = (lastNamep? lastNamep : realPathp);
6884 hexp = osi_HexifyString( asciip );
6885 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
6890 userp = smb_GetUserFromVCP(vcp, inp);
6892 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
6894 return CM_ERROR_INVAL;
6899 baseDirp = cm_data.rootSCachep;
6900 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6901 if (code == CM_ERROR_TIDIPC) {
6902 /* Attempt to use a TID allocated for IPC. The client
6903 * is probably looking for DCE RPC end points which we
6904 * don't support OR it could be looking to make a DFS
6907 osi_Log0(smb_logp, "NTCreateX received IPC TID");
6910 cm_ReleaseUser(userp);
6911 return CM_ERROR_NOSUCHFILE;
6912 #endif /* DFS_SUPPORT */
6915 baseFidp = smb_FindFID(vcp, baseFid, 0);
6917 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
6919 cm_ReleaseUser(userp);
6920 return CM_ERROR_INVAL;
6923 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6925 cm_ReleaseUser(userp);
6926 smb_CloseFID(vcp, baseFidp, NULL, 0);
6927 smb_ReleaseFID(baseFidp);
6928 return CM_ERROR_NOSUCHPATH;
6931 baseDirp = baseFidp->scp;
6935 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
6937 /* compute open mode */
6939 if (desiredAccess & DELETE)
6940 fidflags |= SMB_FID_OPENDELETE;
6941 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
6942 fidflags |= SMB_FID_OPENREAD_LISTDIR;
6943 if (desiredAccess & AFS_ACCESS_WRITE)
6944 fidflags |= SMB_FID_OPENWRITE;
6945 if (createOptions & FILE_DELETE_ON_CLOSE)
6946 fidflags |= SMB_FID_DELONCLOSE;
6947 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6948 fidflags |= SMB_FID_SEQUENTIAL;
6949 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6950 fidflags |= SMB_FID_RANDOM;
6951 if (smb_IsExecutableFileName(lastNamep))
6952 fidflags |= SMB_FID_EXECUTABLE;
6954 /* and the share mode */
6955 if (shareAccess & FILE_SHARE_READ)
6956 fidflags |= SMB_FID_SHARE_READ;
6957 if (shareAccess & FILE_SHARE_WRITE)
6958 fidflags |= SMB_FID_SHARE_WRITE;
6960 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
6963 /* For an exclusive create, we want to do a case sensitive match for the last component. */
6964 if ( createDisp == FILE_CREATE ||
6965 createDisp == FILE_OVERWRITE ||
6966 createDisp == FILE_OVERWRITE_IF) {
6967 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6968 userp, tidPathp, &req, &dscp);
6971 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6972 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
6973 cm_ReleaseSCache(dscp);
6974 cm_ReleaseUser(userp);
6977 smb_ReleaseFID(baseFidp);
6978 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6979 return CM_ERROR_PATH_NOT_COVERED;
6981 return CM_ERROR_BADSHARENAME;
6983 #endif /* DFS_SUPPORT */
6984 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6986 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
6987 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6988 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6989 if (code == 0 && realDirFlag == 1) {
6990 cm_ReleaseSCache(scp);
6991 cm_ReleaseSCache(dscp);
6992 cm_ReleaseUser(userp);
6995 smb_ReleaseFID(baseFidp);
6996 return CM_ERROR_EXISTS;
7000 /* we have both scp and dscp */
7002 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7003 userp, tidPathp, &req, &scp);
7005 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7006 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7007 cm_ReleaseSCache(scp);
7008 cm_ReleaseUser(userp);
7011 smb_ReleaseFID(baseFidp);
7012 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7013 return CM_ERROR_PATH_NOT_COVERED;
7015 return CM_ERROR_BADSHARENAME;
7017 #endif /* DFS_SUPPORT */
7018 /* we might have scp but not dscp */
7024 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7025 /* look up parent directory */
7026 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
7027 * the immediate parent. We have to work our way up realPathp until we hit something that we
7031 /* we might or might not have scp */
7037 code = cm_NameI(baseDirp, spacep->data,
7038 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7039 userp, tidPathp, &req, &dscp);
7042 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7043 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
7045 cm_ReleaseSCache(scp);
7046 cm_ReleaseSCache(dscp);
7047 cm_ReleaseUser(userp);
7050 smb_ReleaseFID(baseFidp);
7051 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7052 return CM_ERROR_PATH_NOT_COVERED;
7054 return CM_ERROR_BADSHARENAME;
7056 #endif /* DFS_SUPPORT */
7059 (tp = strrchr(spacep->data,'\\')) &&
7060 (createDisp == FILE_CREATE) &&
7061 (realDirFlag == 1)) {
7064 treeStartp = realPathp + (tp - spacep->data);
7066 if (*tp && !smb_IsLegalFilename(tp)) {
7067 cm_ReleaseUser(userp);
7069 smb_ReleaseFID(baseFidp);
7072 cm_ReleaseSCache(scp);
7073 return CM_ERROR_BADNTFILENAME;
7077 } while (dscp == NULL && code == 0);
7081 /* we might have scp and we might have dscp */
7084 smb_ReleaseFID(baseFidp);
7087 osi_Log0(smb_logp,"NTCreateX parent not found");
7089 cm_ReleaseSCache(scp);
7091 cm_ReleaseSCache(dscp);
7092 cm_ReleaseUser(userp);
7097 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
7098 /* A file exists where we want a directory. */
7100 cm_ReleaseSCache(scp);
7101 cm_ReleaseSCache(dscp);
7102 cm_ReleaseUser(userp);
7104 return CM_ERROR_EXISTS;
7108 lastNamep = realPathp;
7112 if (!smb_IsLegalFilename(lastNamep)) {
7114 cm_ReleaseSCache(scp);
7116 cm_ReleaseSCache(dscp);
7117 cm_ReleaseUser(userp);
7119 return CM_ERROR_BADNTFILENAME;
7122 if (!foundscp && !treeCreate) {
7123 if ( createDisp == FILE_CREATE ||
7124 createDisp == FILE_OVERWRITE ||
7125 createDisp == FILE_OVERWRITE_IF)
7127 code = cm_Lookup(dscp, lastNamep,
7128 CM_FLAG_FOLLOW, userp, &req, &scp);
7130 code = cm_Lookup(dscp, lastNamep,
7131 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7134 if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
7136 cm_ReleaseSCache(dscp);
7137 cm_ReleaseUser(userp);
7142 /* we have scp and dscp */
7144 /* we have scp but not dscp */
7146 smb_ReleaseFID(baseFidp);
7149 /* if we get here, if code is 0, the file exists and is represented by
7150 * scp. Otherwise, we have to create it. The dir may be represented
7151 * by dscp, or we may have found the file directly. If code is non-zero,
7154 if (code == 0 && !treeCreate) {
7155 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7158 cm_ReleaseSCache(dscp);
7160 cm_ReleaseSCache(scp);
7161 cm_ReleaseUser(userp);
7166 if (createDisp == FILE_CREATE) {
7167 /* oops, file shouldn't be there */
7168 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7170 cm_ReleaseSCache(dscp);
7172 cm_ReleaseSCache(scp);
7173 cm_ReleaseUser(userp);
7175 return CM_ERROR_EXISTS;
7178 if ( createDisp == FILE_OVERWRITE ||
7179 createDisp == FILE_OVERWRITE_IF) {
7181 setAttr.mask = CM_ATTRMASK_LENGTH;
7182 setAttr.length.LowPart = 0;
7183 setAttr.length.HighPart = 0;
7184 /* now watch for a symlink */
7186 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7188 osi_assertx(dscp != NULL, "null cm_scache_t");
7189 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7191 /* we have a more accurate file to use (the
7192 * target of the symbolic link). Otherwise,
7193 * we'll just use the symlink anyway.
7195 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7197 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7198 cm_ReleaseSCache(scp);
7200 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7203 cm_ReleaseSCache(dscp);
7205 cm_ReleaseSCache(scp);
7206 cm_ReleaseUser(userp);
7212 code = cm_SetAttr(scp, &setAttr, userp, &req);
7213 openAction = 3; /* truncated existing file */
7216 openAction = 1; /* found existing file */
7218 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7219 /* don't create if not found */
7221 cm_ReleaseSCache(dscp);
7223 cm_ReleaseSCache(scp);
7224 cm_ReleaseUser(userp);
7226 return CM_ERROR_NOSUCHFILE;
7227 } else if (realDirFlag == 0 || realDirFlag == -1) {
7228 osi_assertx(dscp != NULL, "null cm_scache_t");
7229 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
7230 osi_LogSaveString(smb_logp, lastNamep));
7231 openAction = 2; /* created file */
7232 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7233 setAttr.clientModTime = time(NULL);
7234 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
7237 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7238 smb_NotifyChange(FILE_ACTION_ADDED,
7239 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7240 dscp, lastNamep, NULL, TRUE);
7241 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7242 /* Not an exclusive create, and someone else tried
7243 * creating it already, then we open it anyway. We
7244 * don't bother retrying after this, since if this next
7245 * fails, that means that the file was deleted after we
7246 * started this call.
7248 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7251 if (createDisp == FILE_OVERWRITE_IF) {
7252 setAttr.mask = CM_ATTRMASK_LENGTH;
7253 setAttr.length.LowPart = 0;
7254 setAttr.length.HighPart = 0;
7256 /* now watch for a symlink */
7258 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7260 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7262 /* we have a more accurate file to use (the
7263 * target of the symbolic link). Otherwise,
7264 * we'll just use the symlink anyway.
7266 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7268 cm_ReleaseSCache(scp);
7272 code = cm_SetAttr(scp, &setAttr, userp, &req);
7274 } /* lookup succeeded */
7278 char *cp; /* This component */
7279 int clen = 0; /* length of component */
7280 cm_scache_t *tscp1, *tscp2;
7283 /* create directory */
7285 treeStartp = lastNamep;
7286 osi_assertx(dscp != NULL, "null cm_scache_t");
7287 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
7288 osi_LogSaveString(smb_logp, treeStartp));
7289 openAction = 2; /* created directory */
7291 /* if the request is to create the root directory
7292 * it will appear as a directory name of the nul-string
7293 * and a code of CM_ERROR_NOSUCHFILE
7295 if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
7296 code = CM_ERROR_EXISTS;
7298 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7299 setAttr.clientModTime = time(NULL);
7304 cm_HoldSCache(tscp1);
7308 tp = strchr(pp, '\\');
7311 clen = (int)strlen(cp);
7312 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
7314 clen = (int)(tp - pp);
7315 strncpy(cp,pp,clen);
7322 continue; /* the supplied path can't have consecutive slashes either , but */
7324 /* cp is the next component to be created. */
7325 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
7326 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
7327 smb_NotifyChange(FILE_ACTION_ADDED,
7328 FILE_NOTIFY_CHANGE_DIR_NAME,
7329 tscp1, cp, NULL, TRUE);
7331 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7332 /* Not an exclusive create, and someone else tried
7333 * creating it already, then we open it anyway. We
7334 * don't bother retrying after this, since if this next
7335 * fails, that means that the file was deleted after we
7336 * started this call.
7338 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
7339 userp, &req, &tscp2);
7344 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
7345 cm_ReleaseSCache(tscp1);
7346 tscp1 = tscp2; /* Newly created directory will be next parent */
7347 /* the hold is transfered to tscp1 from tscp2 */
7352 cm_ReleaseSCache(dscp);
7355 cm_ReleaseSCache(scp);
7358 * if we get here and code == 0, then scp is the last directory created, and dscp is the
7364 /* something went wrong creating or truncating the file */
7366 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7368 cm_ReleaseSCache(scp);
7370 cm_ReleaseSCache(dscp);
7371 cm_ReleaseUser(userp);
7376 /* make sure we have file vs. dir right (only applies for single component case) */
7377 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7378 /* now watch for a symlink */
7380 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7381 cm_scache_t * targetScp = 0;
7382 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7384 /* we have a more accurate file to use (the
7385 * target of the symbolic link). Otherwise,
7386 * we'll just use the symlink anyway.
7388 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
7390 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7391 cm_ReleaseSCache(scp);
7396 if (scp->fileType != CM_SCACHETYPE_FILE) {
7398 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7400 cm_ReleaseSCache(dscp);
7401 cm_ReleaseSCache(scp);
7402 cm_ReleaseUser(userp);
7404 return CM_ERROR_ISDIR;
7408 /* (only applies to single component case) */
7409 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7411 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7412 cm_ReleaseSCache(scp);
7414 cm_ReleaseSCache(dscp);
7415 cm_ReleaseUser(userp);
7417 return CM_ERROR_NOTDIR;
7420 /* open the file itself */
7421 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7422 osi_assertx(fidp, "null smb_fid_t");
7424 /* save a reference to the user */
7426 fidp->userp = userp;
7428 /* If we are restricting sharing, we should do so with a suitable
7430 if (scp->fileType == CM_SCACHETYPE_FILE &&
7431 !(fidflags & SMB_FID_SHARE_WRITE)) {
7433 LARGE_INTEGER LOffset, LLength;
7436 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7437 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7438 LLength.HighPart = 0;
7439 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7441 /* If we are not opening the file for writing, then we don't
7442 try to get an exclusive lock. No one else should be able to
7443 get an exclusive lock on the file anyway, although someone
7444 else can get a shared lock. */
7445 if ((fidflags & SMB_FID_SHARE_READ) ||
7446 !(fidflags & SMB_FID_OPENWRITE)) {
7447 sLockType = LOCKING_ANDX_SHARED_LOCK;
7452 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7454 lock_ObtainWrite(&scp->rw);
7455 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7456 lock_ReleaseWrite(&scp->rw);
7460 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7461 cm_ReleaseSCache(scp);
7463 cm_ReleaseSCache(dscp);
7464 cm_ReleaseUser(userp);
7465 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7466 smb_CloseFID(vcp, fidp, NULL, 0);
7467 smb_ReleaseFID(fidp);
7473 /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
7475 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7477 lock_ObtainMutex(&fidp->mx);
7478 /* save a pointer to the vnode */
7479 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
7480 lock_ObtainWrite(&scp->rw);
7481 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7482 lock_ReleaseWrite(&scp->rw);
7483 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
7485 fidp->flags = fidflags;
7487 /* remember if the file was newly created */
7489 fidp->flags |= SMB_FID_CREATED;
7491 /* save parent dir and pathname for delete or change notification */
7492 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7493 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
7494 fidp->flags |= SMB_FID_NTOPEN;
7495 fidp->NTopen_dscp = dscp;
7497 fidp->NTopen_pathp = strdup(lastNamep);
7499 fidp->NTopen_wholepathp = realPathp;
7500 lock_ReleaseMutex(&fidp->mx);
7502 /* we don't need this any longer */
7504 cm_ReleaseSCache(dscp);
7508 cm_Open(scp, 0, userp);
7510 /* set inp->fid so that later read calls in same msg can find fid */
7511 inp->fid = fidp->fid;
7515 lock_ObtainRead(&scp->rw);
7516 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7517 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7518 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7519 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7520 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7521 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7522 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7523 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7524 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7526 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7527 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7528 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
7529 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
7530 smb_SetSMBParmByte(outp, parmSlot,
7531 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7532 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7533 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7534 smb_SetSMBDataLength(outp, 0);
7536 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
7537 LargeIntegerGreaterThanZero(fidp->scp->length) &&
7538 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
7539 cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
7540 fidp->scp->length.LowPart, fidp->scp->length.HighPart,
7543 lock_ReleaseRead(&scp->rw);
7545 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
7546 osi_LogSaveString(smb_logp, realPathp));
7548 cm_ReleaseUser(userp);
7549 smb_ReleaseFID(fidp);
7551 /* Can't free realPathp if we get here since
7552 fidp->NTopen_wholepathp is pointing there */
7554 /* leave scp held since we put it in fidp->scp */
7559 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
7560 * Instead, ultimately, would like to use a subroutine for common code.
7563 /* NT_TRANSACT_CREATE (SMB_COM_NT_TRANSACT) */
7564 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7566 char *pathp, *realPathp;
7570 cm_scache_t *dscp; /* parent dir */
7571 cm_scache_t *scp; /* file to create or open */
7572 cm_scache_t *targetScp; /* if scp is a symlink */
7575 unsigned long nameLength;
7577 unsigned int requestOpLock;
7578 unsigned int requestBatchOpLock;
7579 unsigned int mustBeDir;
7580 unsigned int extendedRespRequired;
7582 unsigned int desiredAccess;
7583 #ifdef DEBUG_VERBOSE
7584 unsigned int allocSize;
7586 unsigned int shareAccess;
7587 unsigned int extAttributes;
7588 unsigned int createDisp;
7589 #ifdef DEBUG_VERBOSE
7592 unsigned int createOptions;
7593 int initialModeBits;
7594 unsigned short baseFid;
7595 smb_fid_t *baseFidp;
7597 cm_scache_t *baseDirp;
7598 unsigned short openAction;
7604 int parmOffset, dataOffset;
7610 cm_lock_data_t *ldp = NULL;
7617 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7618 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7619 parmp = inp->data + parmOffset;
7620 lparmp = (ULONG *) parmp;
7623 requestOpLock = flags & REQUEST_OPLOCK;
7624 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7625 mustBeDir = flags & OPEN_DIRECTORY;
7626 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7629 * Why all of a sudden 32-bit FID?
7630 * We will reject all bits higher than 16.
7632 if (lparmp[1] & 0xFFFF0000)
7633 return CM_ERROR_INVAL;
7634 baseFid = (unsigned short)lparmp[1];
7635 desiredAccess = lparmp[2];
7636 #ifdef DEBUG_VERBOSE
7637 allocSize = lparmp[3];
7638 #endif /* DEBUG_VERSOSE */
7639 extAttributes = lparmp[5];
7640 shareAccess = lparmp[6];
7641 createDisp = lparmp[7];
7642 createOptions = lparmp[8];
7643 #ifdef DEBUG_VERBOSE
7646 nameLength = lparmp[11];
7648 #ifdef DEBUG_VERBOSE
7649 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
7650 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
7651 osi_Log1(smb_logp,"... flags[%x]",flags);
7654 /* mustBeDir is never set; createOptions directory bit seems to be
7657 if (createOptions & FILE_DIRECTORY_FILE)
7659 else if (createOptions & FILE_NON_DIRECTORY_FILE)
7665 * compute initial mode bits based on read-only flag in
7666 * extended attributes
7668 initialModeBits = 0666;
7669 if (extAttributes & SMB_ATTR_READONLY)
7670 initialModeBits &= ~0222;
7672 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
7673 pathp = smb_ParseStringCch(inp, pathp, nameLength, NULL, SMB_STRF_ANSIPATH);
7674 /* Sometimes path is not null-terminated, so we make a copy. */
7675 realPathp = malloc(nameLength+1);
7676 memcpy(realPathp, pathp, nameLength);
7677 realPathp[nameLength] = 0;
7678 spacep = cm_GetSpace();
7679 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
7682 * Nothing here to handle SMB_IOCTL_FILENAME.
7683 * Will add it if necessary.
7686 #ifdef DEBUG_VERBOSE
7688 char *hexp, *asciip;
7689 asciip = (lastNamep? lastNamep : realPathp);
7690 hexp = osi_HexifyString( asciip );
7691 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
7696 userp = smb_GetUserFromVCP(vcp, inp);
7698 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
7700 return CM_ERROR_INVAL;
7705 baseDirp = cm_data.rootSCachep;
7706 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7707 if (code == CM_ERROR_TIDIPC) {
7708 /* Attempt to use a TID allocated for IPC. The client
7709 * is probably looking for DCE RPC end points which we
7710 * don't support OR it could be looking to make a DFS
7713 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
7716 cm_ReleaseUser(userp);
7717 return CM_ERROR_NOSUCHPATH;
7721 baseFidp = smb_FindFID(vcp, baseFid, 0);
7723 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
7725 cm_ReleaseUser(userp);
7726 return CM_ERROR_BADFD;
7729 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7731 cm_ReleaseUser(userp);
7732 smb_CloseFID(vcp, baseFidp, NULL, 0);
7733 smb_ReleaseFID(baseFidp);
7734 return CM_ERROR_NOSUCHPATH;
7737 baseDirp = baseFidp->scp;
7741 /* compute open mode */
7743 if (desiredAccess & DELETE)
7744 fidflags |= SMB_FID_OPENDELETE;
7745 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
7746 fidflags |= SMB_FID_OPENREAD_LISTDIR;
7747 if (desiredAccess & AFS_ACCESS_WRITE)
7748 fidflags |= SMB_FID_OPENWRITE;
7749 if (createOptions & FILE_DELETE_ON_CLOSE)
7750 fidflags |= SMB_FID_DELONCLOSE;
7751 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7752 fidflags |= SMB_FID_SEQUENTIAL;
7753 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7754 fidflags |= SMB_FID_RANDOM;
7755 if (smb_IsExecutableFileName(lastNamep))
7756 fidflags |= SMB_FID_EXECUTABLE;
7758 /* And the share mode */
7759 if (shareAccess & FILE_SHARE_READ)
7760 fidflags |= SMB_FID_SHARE_READ;
7761 if (shareAccess & FILE_SHARE_WRITE)
7762 fidflags |= SMB_FID_SHARE_WRITE;
7766 if ( createDisp == FILE_OPEN ||
7767 createDisp == FILE_OVERWRITE ||
7768 createDisp == FILE_OVERWRITE_IF) {
7769 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7770 userp, tidPathp, &req, &dscp);
7773 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7774 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
7775 cm_ReleaseSCache(dscp);
7776 cm_ReleaseUser(userp);
7779 smb_ReleaseFID(baseFidp);
7780 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7781 return CM_ERROR_PATH_NOT_COVERED;
7783 return CM_ERROR_BADSHARENAME;
7785 #endif /* DFS_SUPPORT */
7786 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7788 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7789 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7790 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7791 if (code == 0 && realDirFlag == 1) {
7792 cm_ReleaseSCache(scp);
7793 cm_ReleaseSCache(dscp);
7794 cm_ReleaseUser(userp);
7797 smb_ReleaseFID(baseFidp);
7798 return CM_ERROR_EXISTS;
7804 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7805 userp, tidPathp, &req, &scp);
7807 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7808 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7809 cm_ReleaseSCache(scp);
7810 cm_ReleaseUser(userp);
7813 smb_ReleaseFID(baseFidp);
7814 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7815 return CM_ERROR_PATH_NOT_COVERED;
7817 return CM_ERROR_BADSHARENAME;
7819 #endif /* DFS_SUPPORT */
7825 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7826 /* look up parent directory */
7828 code = cm_NameI(baseDirp, spacep->data,
7829 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7830 userp, tidPathp, &req, &dscp);
7832 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7833 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
7834 cm_ReleaseSCache(dscp);
7835 cm_ReleaseUser(userp);
7838 smb_ReleaseFID(baseFidp);
7839 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7840 return CM_ERROR_PATH_NOT_COVERED;
7842 return CM_ERROR_BADSHARENAME;
7844 #endif /* DFS_SUPPORT */
7848 cm_FreeSpace(spacep);
7851 smb_ReleaseFID(baseFidp);
7854 cm_ReleaseUser(userp);
7860 lastNamep = realPathp;
7864 if (!smb_IsLegalFilename(lastNamep))
7865 return CM_ERROR_BADNTFILENAME;
7868 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
7869 code = cm_Lookup(dscp, lastNamep,
7870 CM_FLAG_FOLLOW, userp, &req, &scp);
7872 code = cm_Lookup(dscp, lastNamep,
7873 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7876 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7877 cm_ReleaseSCache(dscp);
7878 cm_ReleaseUser(userp);
7885 smb_ReleaseFID(baseFidp);
7886 cm_FreeSpace(spacep);
7889 /* if we get here, if code is 0, the file exists and is represented by
7890 * scp. Otherwise, we have to create it. The dir may be represented
7891 * by dscp, or we may have found the file directly. If code is non-zero,
7895 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7898 cm_ReleaseSCache(dscp);
7899 cm_ReleaseSCache(scp);
7900 cm_ReleaseUser(userp);
7905 if (createDisp == FILE_CREATE) {
7906 /* oops, file shouldn't be there */
7907 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7909 cm_ReleaseSCache(dscp);
7910 cm_ReleaseSCache(scp);
7911 cm_ReleaseUser(userp);
7913 return CM_ERROR_EXISTS;
7916 if (createDisp == FILE_OVERWRITE ||
7917 createDisp == FILE_OVERWRITE_IF) {
7918 setAttr.mask = CM_ATTRMASK_LENGTH;
7919 setAttr.length.LowPart = 0;
7920 setAttr.length.HighPart = 0;
7922 /* now watch for a symlink */
7924 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7926 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7928 /* we have a more accurate file to use (the
7929 * target of the symbolic link). Otherwise,
7930 * we'll just use the symlink anyway.
7932 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7934 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7935 cm_ReleaseSCache(scp);
7937 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7940 cm_ReleaseSCache(dscp);
7942 cm_ReleaseSCache(scp);
7943 cm_ReleaseUser(userp);
7949 code = cm_SetAttr(scp, &setAttr, userp, &req);
7950 openAction = 3; /* truncated existing file */
7952 else openAction = 1; /* found existing file */
7954 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7955 /* don't create if not found */
7957 cm_ReleaseSCache(dscp);
7958 cm_ReleaseUser(userp);
7960 return CM_ERROR_NOSUCHFILE;
7962 else if (realDirFlag == 0 || realDirFlag == -1) {
7963 osi_assertx(dscp != NULL, "null cm_scache_t");
7964 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
7965 osi_LogSaveString(smb_logp, lastNamep));
7966 openAction = 2; /* created file */
7967 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7968 setAttr.clientModTime = time(NULL);
7969 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7973 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7974 smb_NotifyChange(FILE_ACTION_ADDED,
7975 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7976 dscp, lastNamep, NULL, TRUE);
7977 } else if (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,
7987 if (createDisp == FILE_OVERWRITE_IF) {
7988 setAttr.mask = CM_ATTRMASK_LENGTH;
7989 setAttr.length.LowPart = 0;
7990 setAttr.length.HighPart = 0;
7992 /* now watch for a symlink */
7994 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7996 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7998 /* we have a more accurate file to use (the
7999 * target of the symbolic link). Otherwise,
8000 * we'll just use the symlink anyway.
8002 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8004 cm_ReleaseSCache(scp);
8008 code = cm_SetAttr(scp, &setAttr, userp, &req);
8010 } /* lookup succeeded */
8013 /* create directory */
8014 osi_assertx(dscp != NULL, "null cm_scache_t");
8016 "smb_ReceiveNTTranCreate creating directory %s",
8017 osi_LogSaveString(smb_logp, lastNamep));
8018 openAction = 2; /* created directory */
8019 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8020 setAttr.clientModTime = time(NULL);
8021 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
8022 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8023 smb_NotifyChange(FILE_ACTION_ADDED,
8024 FILE_NOTIFY_CHANGE_DIR_NAME,
8025 dscp, lastNamep, NULL, TRUE);
8027 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
8028 /* Not an exclusive create, and someone else tried
8029 * creating it already, then we open it anyway. We
8030 * don't bother retrying after this, since if this next
8031 * fails, that means that the file was deleted after we
8032 * started this call.
8034 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8040 /* something went wrong creating or truncating the file */
8042 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8044 cm_ReleaseSCache(scp);
8045 cm_ReleaseUser(userp);
8050 /* make sure we have file vs. dir right */
8051 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
8052 /* now watch for a symlink */
8054 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8056 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8058 /* we have a more accurate file to use (the
8059 * target of the symbolic link). Otherwise,
8060 * we'll just use the symlink anyway.
8062 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8065 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8066 cm_ReleaseSCache(scp);
8071 if (scp->fileType != CM_SCACHETYPE_FILE) {
8073 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8074 cm_ReleaseSCache(scp);
8075 cm_ReleaseUser(userp);
8077 return CM_ERROR_ISDIR;
8081 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8083 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8084 cm_ReleaseSCache(scp);
8085 cm_ReleaseUser(userp);
8087 return CM_ERROR_NOTDIR;
8090 /* open the file itself */
8091 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8092 osi_assertx(fidp, "null smb_fid_t");
8094 /* save a reference to the user */
8096 fidp->userp = userp;
8098 /* If we are restricting sharing, we should do so with a suitable
8100 if (scp->fileType == CM_SCACHETYPE_FILE &&
8101 !(fidflags & SMB_FID_SHARE_WRITE)) {
8103 LARGE_INTEGER LOffset, LLength;
8106 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8107 LOffset.LowPart = SMB_FID_QLOCK_LOW;
8108 LLength.HighPart = 0;
8109 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8111 /* Similar to what we do in handling NTCreateX. We get a
8112 shared lock if we are only opening the file for reading. */
8113 if ((fidflags & SMB_FID_SHARE_READ) ||
8114 !(fidflags & SMB_FID_OPENWRITE)) {
8115 sLockType = LOCKING_ANDX_SHARED_LOCK;
8120 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8122 lock_ObtainWrite(&scp->rw);
8123 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8124 lock_ReleaseWrite(&scp->rw);
8128 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8129 cm_ReleaseSCache(scp);
8130 cm_ReleaseUser(userp);
8131 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
8132 smb_CloseFID(vcp, fidp, NULL, 0);
8133 smb_ReleaseFID(fidp);
8135 return CM_ERROR_SHARING_VIOLATION;
8139 /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
8141 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8143 lock_ObtainMutex(&fidp->mx);
8144 /* save a pointer to the vnode */
8146 lock_ObtainWrite(&scp->rw);
8147 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8148 lock_ReleaseWrite(&scp->rw);
8149 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
8151 fidp->flags = fidflags;
8153 /* remember if the file was newly created */
8155 fidp->flags |= SMB_FID_CREATED;
8157 /* save parent dir and pathname for deletion or change notification */
8158 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8159 fidp->flags |= SMB_FID_NTOPEN;
8160 fidp->NTopen_dscp = dscp;
8161 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
8163 fidp->NTopen_pathp = strdup(lastNamep);
8165 fidp->NTopen_wholepathp = realPathp;
8166 lock_ReleaseMutex(&fidp->mx);
8168 /* we don't need this any longer */
8170 cm_ReleaseSCache(dscp);
8172 cm_Open(scp, 0, userp);
8174 /* set inp->fid so that later read calls in same msg can find fid */
8175 inp->fid = fidp->fid;
8177 /* check whether we are required to send an extended response */
8178 if (!extendedRespRequired) {
8180 parmOffset = 8*4 + 39;
8181 parmOffset += 1; /* pad to 4 */
8182 dataOffset = parmOffset + 70;
8186 /* Total Parameter Count */
8187 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8188 /* Total Data Count */
8189 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8190 /* Parameter Count */
8191 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8192 /* Parameter Offset */
8193 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8194 /* Parameter Displacement */
8195 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8197 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8199 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8200 /* Data Displacement */
8201 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8202 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8203 smb_SetSMBDataLength(outp, 70);
8205 lock_ObtainRead(&scp->rw);
8206 outData = smb_GetSMBData(outp, NULL);
8207 outData++; /* round to get to parmOffset */
8208 *outData = 0; outData++; /* oplock */
8209 *outData = 0; outData++; /* reserved */
8210 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8211 *((ULONG *)outData) = openAction; outData += 4;
8212 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8213 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8214 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8215 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8216 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8217 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8218 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8219 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8220 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8221 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8222 *((USHORT *)outData) = 0; outData += 2; /* dev state */
8223 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8224 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8225 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8226 outData += 2; /* is a dir? */
8229 parmOffset = 8*4 + 39;
8230 parmOffset += 1; /* pad to 4 */
8231 dataOffset = parmOffset + 104;
8235 /* Total Parameter Count */
8236 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8237 /* Total Data Count */
8238 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8239 /* Parameter Count */
8240 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8241 /* Parameter Offset */
8242 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8243 /* Parameter Displacement */
8244 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8246 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8248 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8249 /* Data Displacement */
8250 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8251 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8252 smb_SetSMBDataLength(outp, 105);
8254 lock_ObtainRead(&scp->rw);
8255 outData = smb_GetSMBData(outp, NULL);
8256 outData++; /* round to get to parmOffset */
8257 *outData = 0; outData++; /* oplock */
8258 *outData = 1; outData++; /* response type */
8259 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8260 *((ULONG *)outData) = openAction; outData += 4;
8261 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8262 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8263 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8264 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8265 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8266 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8267 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8268 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8269 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8270 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8271 *((USHORT *)outData) = 0; outData += 2; /* dev state */
8272 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8273 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8274 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8275 outData += 1; /* is a dir? */
8276 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
8277 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
8278 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
8281 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
8282 LargeIntegerGreaterThanZero(fidp->scp->length) &&
8283 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
8284 cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
8285 fidp->scp->length.LowPart, fidp->scp->length.HighPart,
8288 lock_ReleaseRead(&scp->rw);
8290 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
8292 cm_ReleaseUser(userp);
8293 smb_ReleaseFID(fidp);
8295 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
8296 /* leave scp held since we put it in fidp->scp */
8300 /* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
8301 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
8304 smb_packet_t *savedPacketp;
8306 USHORT fid, watchtree;
8310 filter = smb_GetSMBParm(inp, 19) |
8311 (smb_GetSMBParm(inp, 20) << 16);
8312 fid = smb_GetSMBParm(inp, 21);
8313 watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
8315 fidp = smb_FindFID(vcp, fid, 0);
8317 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
8318 return CM_ERROR_BADFD;
8321 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8322 smb_CloseFID(vcp, fidp, NULL, 0);
8323 smb_ReleaseFID(fidp);
8324 return CM_ERROR_NOSUCHFILE;
8327 /* Create a copy of the Directory Watch Packet to use when sending the
8328 * notification if in the future a matching change is detected.
8330 savedPacketp = smb_CopyPacket(inp);
8332 if (savedPacketp->vcp)
8333 smb_ReleaseVC(savedPacketp->vcp);
8334 savedPacketp->vcp = vcp;
8336 /* Add the watch to the list of events to send notifications for */
8337 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8338 savedPacketp->nextp = smb_Directory_Watches;
8339 smb_Directory_Watches = savedPacketp;
8340 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8343 osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%s\"",
8344 fidp, scp, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
8345 osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
8346 filter, fid, watchtree);
8347 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8348 osi_Log0(smb_logp, " Notify Change File Name");
8349 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8350 osi_Log0(smb_logp, " Notify Change Directory Name");
8351 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8352 osi_Log0(smb_logp, " Notify Change Attributes");
8353 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8354 osi_Log0(smb_logp, " Notify Change Size");
8355 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8356 osi_Log0(smb_logp, " Notify Change Last Write");
8357 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8358 osi_Log0(smb_logp, " Notify Change Last Access");
8359 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8360 osi_Log0(smb_logp, " Notify Change Creation");
8361 if (filter & FILE_NOTIFY_CHANGE_EA)
8362 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8363 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8364 osi_Log0(smb_logp, " Notify Change Security");
8365 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8366 osi_Log0(smb_logp, " Notify Change Stream Name");
8367 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8368 osi_Log0(smb_logp, " Notify Change Stream Size");
8369 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8370 osi_Log0(smb_logp, " Notify Change Stream Write");
8372 lock_ObtainWrite(&scp->rw);
8374 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
8376 scp->flags |= CM_SCACHEFLAG_WATCHED;
8377 lock_ReleaseWrite(&scp->rw);
8378 smb_ReleaseFID(fidp);
8380 outp->flags |= SMB_PACKETFLAG_NOSEND;
8384 unsigned char nullSecurityDesc[36] = {
8385 0x01, /* security descriptor revision */
8386 0x00, /* reserved, should be zero */
8387 0x00, 0x80, /* security descriptor control;
8388 * 0x8000 : self-relative format */
8389 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
8390 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
8391 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
8392 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
8393 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8394 /* "null SID" owner SID */
8395 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
8396 /* "null SID" group SID */
8399 /* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
8400 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8402 int parmOffset, parmCount, dataOffset, dataCount;
8410 ULONG securityInformation;
8412 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8413 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8414 parmp = inp->data + parmOffset;
8415 sparmp = (USHORT *) parmp;
8416 lparmp = (ULONG *) parmp;
8419 securityInformation = lparmp[1];
8421 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
8422 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
8430 parmOffset = 8*4 + 39;
8431 parmOffset += 1; /* pad to 4 */
8433 dataOffset = parmOffset + parmCount;
8437 /* Total Parameter Count */
8438 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8439 /* Total Data Count */
8440 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8441 /* Parameter Count */
8442 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8443 /* Parameter Offset */
8444 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8445 /* Parameter Displacement */
8446 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8448 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8450 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8451 /* Data Displacement */
8452 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8453 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8454 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
8456 outData = smb_GetSMBData(outp, NULL);
8457 outData++; /* round to get to parmOffset */
8458 *((ULONG *)outData) = 36; outData += 4; /* length */
8460 if (maxData >= 36) {
8461 memcpy(outData, nullSecurityDesc, 36);
8465 return CM_ERROR_BUFFERTOOSMALL;
8468 /* SMB_COM_NT_TRANSACT
8470 SMB_COM_NT_TRANSACT_SECONDARY should also be handled here.
8472 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8474 unsigned short function;
8476 function = smb_GetSMBParm(inp, 18);
8478 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
8480 /* We can handle long names */
8481 if (vcp->flags & SMB_VCFLAG_USENT)
8482 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
8485 case 1: /* NT_TRANSACT_CREATE */
8486 return smb_ReceiveNTTranCreate(vcp, inp, outp);
8487 case 2: /* NT_TRANSACT_IOCTL */
8488 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
8490 case 3: /* NT_TRANSACT_SET_SECURITY_DESC */
8491 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
8493 case 4: /* NT_TRANSACT_NOTIFY_CHANGE */
8494 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
8495 case 5: /* NT_TRANSACT_RENAME */
8496 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
8498 case 6: /* NT_TRANSACT_QUERY_SECURITY_DESC */
8499 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
8501 osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
8504 osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
8507 return CM_ERROR_INVAL;
8511 * smb_NotifyChange -- find relevant change notification messages and
8514 * If we don't know the file name (i.e. a callback break), filename is
8515 * NULL, and we return a zero-length list.
8517 * At present there is not a single call to smb_NotifyChange that
8518 * has the isDirectParent parameter set to FALSE.
8520 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
8521 cm_scache_t *dscp, char *filename, char *otherFilename,
8522 BOOL isDirectParent)
8524 smb_packet_t *watch, *lastWatch, *nextWatch;
8525 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
8526 char *outData, *oldOutData;
8530 BOOL twoEntries = FALSE;
8531 ULONG otherNameLen, oldParmCount = 0;
8535 /* Get ready for rename within directory */
8536 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
8538 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
8541 osi_Log4(smb_logp,"in smb_NotifyChange for file [%s] dscp [%p] notification 0x%x parent %d",
8542 osi_LogSaveString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
8544 osi_Log0(smb_logp," FILE_ACTION_NONE");
8545 if (action == FILE_ACTION_ADDED)
8546 osi_Log0(smb_logp," FILE_ACTION_ADDED");
8547 if (action == FILE_ACTION_REMOVED)
8548 osi_Log0(smb_logp," FILE_ACTION_REMOVED");
8549 if (action == FILE_ACTION_MODIFIED)
8550 osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
8551 if (action == FILE_ACTION_RENAMED_OLD_NAME)
8552 osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
8553 if (action == FILE_ACTION_RENAMED_NEW_NAME)
8554 osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
8556 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8557 watch = smb_Directory_Watches;
8559 filter = smb_GetSMBParm(watch, 19)
8560 | (smb_GetSMBParm(watch, 20) << 16);
8561 fid = smb_GetSMBParm(watch, 21);
8562 wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
8564 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
8565 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
8568 * Strange hack - bug in NT Client and NT Server that we must emulate?
8570 if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
8571 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
8573 fidp = smb_FindFID(watch->vcp, fid, 0);
8575 osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
8577 watch = watch->nextp;
8581 if (fidp->scp != dscp ||
8582 fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
8583 (filter & notifyFilter) == 0 ||
8584 (!isDirectParent && !wtree))
8586 osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
8587 smb_ReleaseFID(fidp);
8589 watch = watch->nextp;
8592 smb_ReleaseFID(fidp);
8595 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
8596 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
8597 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8598 osi_Log0(smb_logp, " Notify Change File Name");
8599 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8600 osi_Log0(smb_logp, " Notify Change Directory Name");
8601 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8602 osi_Log0(smb_logp, " Notify Change Attributes");
8603 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8604 osi_Log0(smb_logp, " Notify Change Size");
8605 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8606 osi_Log0(smb_logp, " Notify Change Last Write");
8607 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8608 osi_Log0(smb_logp, " Notify Change Last Access");
8609 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8610 osi_Log0(smb_logp, " Notify Change Creation");
8611 if (filter & FILE_NOTIFY_CHANGE_EA)
8612 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8613 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8614 osi_Log0(smb_logp, " Notify Change Security");
8615 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8616 osi_Log0(smb_logp, " Notify Change Stream Name");
8617 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8618 osi_Log0(smb_logp, " Notify Change Stream Size");
8619 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8620 osi_Log0(smb_logp, " Notify Change Stream Write");
8622 /* A watch can only be notified once. Remove it from the list */
8623 nextWatch = watch->nextp;
8624 if (watch == smb_Directory_Watches)
8625 smb_Directory_Watches = nextWatch;
8627 lastWatch->nextp = nextWatch;
8629 /* Turn off WATCHED flag in dscp */
8630 lock_ObtainWrite(&dscp->rw);
8632 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8634 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
8635 lock_ReleaseWrite(&dscp->rw);
8637 /* Convert to response packet */
8638 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
8639 #ifdef SEND_CANONICAL_PATHNAMES
8640 ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
8642 ((smb_t *) watch)->wct = 0;
8645 if (filename == NULL)
8648 nameLen = (ULONG)strlen(filename);
8649 parmCount = 3*4 + nameLen*2;
8650 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8652 otherNameLen = (ULONG)strlen(otherFilename);
8653 oldParmCount = parmCount;
8654 parmCount += 3*4 + otherNameLen*2;
8655 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8657 if (maxLen < parmCount)
8658 parmCount = 0; /* not enough room */
8660 parmOffset = 8*4 + 39;
8661 parmOffset += 1; /* pad to 4 */
8662 dataOffset = parmOffset + parmCount;
8666 /* Total Parameter Count */
8667 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8668 /* Total Data Count */
8669 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8670 /* Parameter Count */
8671 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8672 /* Parameter Offset */
8673 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
8674 /* Parameter Displacement */
8675 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8677 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8679 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
8680 /* Data Displacement */
8681 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8682 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
8683 smb_SetSMBDataLength(watch, parmCount + 1);
8685 if (parmCount != 0) {
8687 outData = smb_GetSMBData(watch, NULL);
8688 outData++; /* round to get to parmOffset */
8689 oldOutData = outData;
8690 *((DWORD *)outData) = oldParmCount; outData += 4;
8691 /* Next Entry Offset */
8692 *((DWORD *)outData) = action; outData += 4;
8694 *((DWORD *)outData) = nameLen*2; outData += 4;
8695 /* File Name Length */
8696 p = strdup(filename);
8697 if (smb_StoreAnsiFilenames)
8699 mbstowcs((WCHAR *)outData, p, nameLen);
8703 outData = oldOutData + oldParmCount;
8704 *((DWORD *)outData) = 0; outData += 4;
8705 /* Next Entry Offset */
8706 *((DWORD *)outData) = otherAction; outData += 4;
8708 *((DWORD *)outData) = otherNameLen*2;
8709 outData += 4; /* File Name Length */
8710 p = strdup(otherFilename);
8711 if (smb_StoreAnsiFilenames)
8713 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
8719 * If filename is null, we don't know the cause of the
8720 * change notification. We return zero data (see above),
8721 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
8722 * (= 0x010C). We set the error code here by hand, without
8723 * modifying wct and bcc.
8725 if (filename == NULL) {
8726 ((smb_t *) watch)->rcls = 0x0C;
8727 ((smb_t *) watch)->reh = 0x01;
8728 ((smb_t *) watch)->errLow = 0;
8729 ((smb_t *) watch)->errHigh = 0;
8730 /* Set NT Status codes flag */
8731 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8734 smb_SendPacket(watch->vcp, watch);
8735 smb_FreePacket(watch);
8738 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8741 /* SMB_COM_NT_CANCEL */
8742 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8744 unsigned char *replyWctp;
8745 smb_packet_t *watch, *lastWatch;
8746 USHORT fid, watchtree;
8750 osi_Log0(smb_logp, "SMB3 receive NT cancel");
8752 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8753 watch = smb_Directory_Watches;
8755 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
8756 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
8757 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
8758 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
8759 if (watch == smb_Directory_Watches)
8760 smb_Directory_Watches = watch->nextp;
8762 lastWatch->nextp = watch->nextp;
8763 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8765 /* Turn off WATCHED flag in scp */
8766 fid = smb_GetSMBParm(watch, 21);
8767 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
8769 if (vcp != watch->vcp)
8770 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
8773 fidp = smb_FindFID(vcp, fid, 0);
8775 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
8777 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
8780 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
8781 lock_ObtainWrite(&scp->rw);
8783 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8785 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
8786 lock_ReleaseWrite(&scp->rw);
8787 smb_ReleaseFID(fidp);
8789 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
8792 /* assume STATUS32; return 0xC0000120 (CANCELED) */
8793 replyWctp = watch->wctp;
8797 ((smb_t *)watch)->rcls = 0x20;
8798 ((smb_t *)watch)->reh = 0x1;
8799 ((smb_t *)watch)->errLow = 0;
8800 ((smb_t *)watch)->errHigh = 0xC0;
8801 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8802 smb_SendPacket(vcp, watch);
8803 smb_FreePacket(watch);
8807 watch = watch->nextp;
8809 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8815 * NT rename also does hard links.
8818 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
8819 #define RENAME_FLAG_HARD_LINK 0x103
8820 #define RENAME_FLAG_RENAME 0x104
8821 #define RENAME_FLAG_COPY 0x105
8823 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8825 char *oldPathp, *newPathp;
8831 attrs = smb_GetSMBParm(inp, 0);
8832 rename_type = smb_GetSMBParm(inp, 1);
8834 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
8835 osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
8836 return CM_ERROR_NOACCESS;
8839 tp = smb_GetSMBData(inp, NULL);
8840 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
8841 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
8843 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
8844 osi_LogSaveString(smb_logp, oldPathp),
8845 osi_LogSaveString(smb_logp, newPathp),
8846 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
8848 if (rename_type == RENAME_FLAG_RENAME) {
8849 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
8850 } else { /* RENAME_FLAG_HARD_LINK */
8851 code = smb_Link(vcp,inp,oldPathp,newPathp);
8858 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
8861 cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
8863 smb_username_t *unp;
8866 unp = smb_FindUserByName(usern, machine, flags);
8868 lock_ObtainMutex(&unp->mx);
8869 unp->userp = cm_NewUser();
8870 lock_ReleaseMutex(&unp->mx);
8871 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
8873 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
8877 smb_ReleaseUsername(unp);