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 clientchar_t **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 clientchar_t *name)
74 if ( smb_ExecutableExtensions == NULL || name == NULL)
77 len = (int)cm_ClientStrLen(name);
79 for ( i=0; smb_ExecutableExtensions[i]; i++) {
80 j = len - (int)cm_ClientStrLen(smb_ExecutableExtensions[i]);
81 if (cm_ClientStrCmpI(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;
107 } else if (scp->fid.vnode & 0x1)
108 attrs = SMB_ATTR_DIRECTORY;
113 * We used to mark a file RO if it was in an RO volume, but that
114 * turns out to be impolitic in NT. See defect 10007.
117 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
118 attrs |= SMB_ATTR_READONLY; /* Read-only */
120 if ((scp->unixModeBits & 0222) == 0)
121 attrs |= SMB_ATTR_READONLY; /* Read-only */
125 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
130 int smb_V3IsStarMask(clientchar_t *maskp)
134 while (tc = *maskp++)
135 if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
140 void OutputDebugF(clientchar_t * format, ...) {
142 clientchar_t vbuffer[1024];
144 va_start( args, format );
145 cm_ClientStrPrintfV(vbuffer, lengthof(vbuffer), format, args);
146 osi_Log1(smb_logp, "%S", osi_LogSaveClientString(smb_logp, vbuffer));
147 cm_ClientStrCat(vbuffer, lengthof(vbuffer), _C("\n"));
148 OutputDebugStringW(vbuffer);
151 void OutputDebugHexDump(unsigned char * buffer, int len) {
154 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
156 OutputDebugF(_C("Hexdump length [%d]"),len);
158 for (i=0;i<len;i++) {
161 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
162 StringCchCatA(buf, lengthof(buf), "\r\n");
163 OutputDebugString(buf);
165 StringCchPrintfA(buf, lengthof(buf), "%5x", i);
166 memset(buf+5,' ',80);
171 j = j*3 + 7 + ((j>7)?1:0);
174 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
177 j = j + 56 + ((j>7)?1:0);
179 buf[j] = (k>32 && k<127)?k:'.';
182 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
183 StringCchCatA(buf, lengthof(buf), "\r\n");
184 OutputDebugString(buf);
188 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
190 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
191 SECURITY_STATUS status, istatus;
192 CredHandle creds = {0,0};
194 SecBufferDesc secOut;
202 OutputDebugF(_C("Negotiating Extended Security"));
204 status = AcquireCredentialsHandle( NULL,
205 SMB_EXT_SEC_PACKAGE_NAME,
214 if (status != SEC_E_OK) {
215 /* Really bad. We return an empty security blob */
216 OutputDebugF(_C("AcquireCredentialsHandle failed with %lX"), status);
221 secOut.pBuffers = &secTok;
222 secOut.ulVersion = SECBUFFER_VERSION;
224 secTok.BufferType = SECBUFFER_TOKEN;
226 secTok.pvBuffer = NULL;
228 ctx.dwLower = ctx.dwUpper = 0;
230 status = AcceptSecurityContext( &creds,
233 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
234 SECURITY_NETWORK_DREP,
241 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
242 OutputDebugF(_C("Completing token..."));
243 istatus = CompleteAuthToken(&ctx, &secOut);
244 if ( istatus != SEC_E_OK )
245 OutputDebugF(_C("Token completion failed: %x"), istatus);
248 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
249 if (secTok.pvBuffer) {
250 *secBlobLength = secTok.cbBuffer;
251 *secBlob = malloc( secTok.cbBuffer );
252 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
255 if ( status != SEC_E_OK )
256 OutputDebugF(_C("AcceptSecurityContext status != CONTINUE %lX"), status);
259 /* Discard partial security context */
260 DeleteSecurityContext(&ctx);
262 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
264 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
265 FreeCredentialsHandle(&creds);
271 struct smb_ext_context {
278 long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern,
279 char * secBlobIn, int secBlobInLength,
280 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(_C("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(_C("Received incoming token:"));
311 OutputDebugHexDump(secBlobIn,secBlobInLength);
315 OutputDebugF(_C("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(_C("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(_C("Completing token..."));
380 istatus = CompleteAuthToken(&ctx, &secBufOut);
381 if ( istatus != SEC_E_OK )
382 OutputDebugF(_C("Token completion failed: %lX"), istatus);
385 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
386 OutputDebugF(_C("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(_C("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(_C("Outgoing token:"));
413 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
414 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
415 OutputDebugF(_C("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_NamesW names;
437 OutputDebugF(_C("Authentication completed"));
438 OutputDebugF(_C("Returned flags : [%lX]"), flags);
440 if (!QueryContextAttributesW(&ctx, SECPKG_ATTR_NAMES, &names)) {
441 OutputDebugF(_C("Received name [%s]"), names.sUserName);
442 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, names.sUserName);
443 cm_ClientStrLwr(usern); /* in tandem with smb_GetNormalizedUsername */
444 FreeContextBuffer(names.sUserName);
446 /* Force the user to retry if the context is invalid */
447 OutputDebugF(_C("QueryContextAttributes Names failed [%x]"), GetLastError());
448 code = CM_ERROR_BADPASSWORD;
452 case SEC_E_INVALID_TOKEN:
453 OutputDebugF(_C("Returning bad password :: INVALID_TOKEN"));
455 case SEC_E_INVALID_HANDLE:
456 OutputDebugF(_C("Returning bad password :: INVALID_HANDLE"));
458 case SEC_E_LOGON_DENIED:
459 OutputDebugF(_C("Returning bad password :: LOGON_DENIED"));
461 case SEC_E_UNKNOWN_CREDENTIALS:
462 OutputDebugF(_C("Returning bad password :: UNKNOWN_CREDENTIALS"));
464 case SEC_E_NO_CREDENTIALS:
465 OutputDebugF(_C("Returning bad password :: NO_CREDENTIALS"));
467 case SEC_E_CONTEXT_EXPIRED:
468 OutputDebugF(_C("Returning bad password :: CONTEXT_EXPIRED"));
470 case SEC_E_INCOMPLETE_CREDENTIALS:
471 OutputDebugF(_C("Returning bad password :: INCOMPLETE_CREDENTIALS"));
473 case SEC_E_WRONG_PRINCIPAL:
474 OutputDebugF(_C("Returning bad password :: WRONG_PRINCIPAL"));
476 case SEC_E_TIME_SKEW:
477 OutputDebugF(_C("Returning bad password :: TIME_SKEW"));
480 OutputDebugF(_C("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, clientchar_t * accountName, clientchar_t * 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(_C("In smb_AuthenticateUser for user [%s] domain [%s]"), accountName, primaryDomain);
534 OutputDebugF(_C("ciPwdLength is %d and csPwdLength is %d"), ciPwdLength, csPwdLength);
536 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
537 OutputDebugF(_C("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 cm_ClientStringToUtf16(primaryDomain, -1, lmAuth.primaryDomainW, 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 cm_ClientStringToUtf16(accountName, -1, lmAuth.accountNameW, 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;
580 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
582 lmAuth.tsource.SourceIdentifier.HighPart = 0;
584 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
585 StringCchCopyA(lmAuth.tsource.SourceName, lengthof(lmAuth.tsource.SourceName),
586 "OpenAFS"); /* 8 char limit */
588 nts = LsaLogonUser( smb_lsaHandle,
603 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
604 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
607 OutputDebugF(_C("Return from LsaLogonUser is 0x%lX"), nts);
608 OutputDebugF(_C("Extended status is 0x%lX"), ntsEx);
610 if (nts == ERROR_SUCCESS) {
612 LsaFreeReturnBuffer(lmprofilep);
613 CloseHandle(lmToken);
617 if (nts == 0xC000015BL)
618 return CM_ERROR_BADLOGONTYPE;
619 else /* our catchall is a bad password though we could be more specific */
620 return CM_ERROR_BADPASSWORD;
624 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
625 long smb_GetNormalizedUsername(clientchar_t * usern, const clientchar_t * accountName, const clientchar_t * domainName)
627 clientchar_t * atsign;
628 const clientchar_t * domain;
630 /* check if we have sane input */
631 if ((cm_ClientStrLen(accountName) + cm_ClientStrLen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
634 /* we could get : [accountName][domainName]
640 atsign = cm_ClientStrChr(accountName, '@');
642 if (atsign) /* [user@domain][] -> [user@domain][domain] */
647 /* if for some reason the client doesn't know what domain to use,
648 it will either return an empty string or a '?' */
649 if (!domain[0] || domain[0] == '?')
650 /* Empty domains and empty usernames are usually sent from tokenless contexts.
651 This way such logins will get an empty username (easy to check). I don't know
652 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
653 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, accountName);
655 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
656 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, domain);
657 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, _C("\\"));
659 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
661 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
664 cm_ClientStrLwr(usern);
669 /* When using SMB auth, all SMB sessions have to pass through here
670 * first to authenticate the user.
672 * Caveat: If not using SMB auth, the protocol does not require
673 * sending a session setup packet, which means that we can't rely on a
674 * UID in subsequent packets. Though in practice we get one anyway.
676 /* SMB_COM_SESSION_SETUP_ANDX */
677 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
681 unsigned short newUid;
682 unsigned long caps = 0;
684 clientchar_t *s1 = _C(" ");
686 clientchar_t usern[SMB_MAX_USERNAME_LENGTH];
687 char *secBlobOut = NULL;
688 int secBlobOutLength = 0;
690 /* Check for bad conns */
691 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
692 return CM_ERROR_REMOTECONN;
694 if (vcp->flags & SMB_VCFLAG_USENT) {
695 if (smb_authType == SMB_AUTH_EXTENDED) {
696 /* extended authentication */
700 OutputDebugF(_C("NT Session Setup: Extended"));
702 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
703 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
706 secBlobInLength = smb_GetSMBParm(inp, 7);
707 secBlobIn = smb_GetSMBData(inp, NULL);
709 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
711 if (code == CM_ERROR_GSSCONTINUE) {
714 smb_SetSMBParm(outp, 2, 0);
715 smb_SetSMBParm(outp, 3, secBlobOutLength);
717 tp = smb_GetSMBData(outp, NULL);
718 if (secBlobOutLength) {
719 memcpy(tp, secBlobOut, secBlobOutLength);
721 tp += secBlobOutLength;
722 cb_data += secBlobOutLength;
724 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
725 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
726 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
728 smb_SetSMBDataLength(outp, cb_data);
731 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
733 unsigned ciPwdLength, csPwdLength;
735 clientchar_t *accountName;
736 clientchar_t *primaryDomain;
739 if (smb_authType == SMB_AUTH_NTLM)
740 OutputDebugF(_C("NT Session Setup: NTLM"));
742 OutputDebugF(_C("NT Session Setup: None"));
744 /* TODO: parse for extended auth as well */
745 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
746 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
748 tp = smb_GetSMBData(inp, &datalen);
750 OutputDebugF(_C("Session packet data size [%d]"),datalen);
757 accountName = smb_ParseString(inp, tp, &tp, 0);
758 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
760 OutputDebugF(_C("Account Name: %s"),accountName);
761 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
762 OutputDebugF(_C("Case Sensitive Password: %s"),
763 csPwd && csPwd[0] ? _C("yes") : _C("no"));
764 OutputDebugF(_C("Case Insensitive Password: %s"),
765 ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
767 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
768 /* shouldn't happen */
769 code = CM_ERROR_BADSMB;
770 goto after_read_packet;
773 /* capabilities are only valid for first session packet */
774 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
775 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
778 if (smb_authType == SMB_AUTH_NTLM) {
779 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
781 OutputDebugF(_C("LM authentication failed [%d]"), code);
783 OutputDebugF(_C("LM authentication succeeded"));
787 unsigned ciPwdLength;
789 clientchar_t *accountName;
790 clientchar_t *primaryDomain;
792 switch ( smb_authType ) {
793 case SMB_AUTH_EXTENDED:
794 OutputDebugF(_C("V3 Session Setup: Extended"));
797 OutputDebugF(_C("V3 Session Setup: NTLM"));
800 OutputDebugF(_C("V3 Session Setup: None"));
802 ciPwdLength = smb_GetSMBParm(inp, 7);
803 tp = smb_GetSMBData(inp, NULL);
807 accountName = smb_ParseString(inp, tp, &tp, 0);
808 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
810 OutputDebugF(_C("Account Name: %s"),accountName);
811 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
812 OutputDebugF(_C("Case Insensitive Password: %s"), ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
814 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
815 /* shouldn't happen */
816 code = CM_ERROR_BADSMB;
817 goto after_read_packet;
820 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
823 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
824 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
826 OutputDebugF(_C("LM authentication failed [%d]"), code);
828 OutputDebugF(_C("LM authentication succeeded"));
833 /* note down that we received a session setup X and set the capabilities flag */
834 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
835 lock_ObtainMutex(&vcp->mx);
836 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
837 /* for the moment we can only deal with NTSTATUS */
838 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
839 vcp->flags |= SMB_VCFLAG_STATUS32;
843 if ((caps & NTNEGOTIATE_CAPABILITY_UNICODE) && smb_UseUnicode) {
844 vcp->flags |= SMB_VCFLAG_USEUNICODE;
847 lock_ReleaseMutex(&vcp->mx);
850 /* code would be non-zero if there was an authentication failure.
851 Ideally we would like to invalidate the uid for this session or break
852 early to avoid accidently stealing someone else's tokens. */
858 OutputDebugF(_C("Received username=[%s]"), usern);
860 /* On Windows 2000, this function appears to be called more often than
861 it is expected to be called. This resulted in multiple smb_user_t
862 records existing all for the same user session which results in all
863 of the users tokens disappearing.
865 To avoid this problem, we look for an existing smb_user_t record
866 based on the users name, and use that one if we find it.
869 uidp = smb_FindUserByNameThisSession(vcp, usern);
870 if (uidp) { /* already there, so don't create a new one */
872 newUid = uidp->userID;
873 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
874 vcp->lana,vcp->lsn,newUid);
875 smb_ReleaseUID(uidp);
880 /* do a global search for the username/machine name pair */
881 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
882 lock_ObtainMutex(&unp->mx);
883 if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
884 /* clear the afslogon flag so that the tickets can now
885 * be freed when the refCount returns to zero.
887 unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
889 lock_ReleaseMutex(&unp->mx);
891 /* Create a new UID and cm_user_t structure */
894 userp = cm_NewUser();
895 cm_HoldUserVCRef(userp);
896 lock_ObtainMutex(&vcp->mx);
897 if (!vcp->uidCounter)
898 vcp->uidCounter++; /* handle unlikely wraparounds */
899 newUid = (cm_ClientStrLen(usern)==0)?0:vcp->uidCounter++;
900 lock_ReleaseMutex(&vcp->mx);
902 /* Create a new smb_user_t structure and connect them up */
903 lock_ObtainMutex(&unp->mx);
905 lock_ReleaseMutex(&unp->mx);
907 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
909 lock_ObtainMutex(&uidp->mx);
911 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
912 lock_ReleaseMutex(&uidp->mx);
913 smb_ReleaseUID(uidp);
917 /* Return UID to the client */
918 ((smb_t *)outp)->uid = newUid;
919 /* Also to the next chained message */
920 ((smb_t *)inp)->uid = newUid;
922 osi_Log3(smb_logp, "SMB3 session setup name %S creating ID %d%S",
923 osi_LogSaveClientString(smb_logp, usern), newUid,
924 osi_LogSaveClientString(smb_logp, s1));
926 smb_SetSMBParm(outp, 2, 0);
928 if (vcp->flags & SMB_VCFLAG_USENT) {
929 if (smb_authType == SMB_AUTH_EXTENDED) {
932 smb_SetSMBParm(outp, 3, secBlobOutLength);
934 tp = smb_GetSMBData(outp, NULL);
935 if (secBlobOutLength) {
936 memcpy(tp, secBlobOut, secBlobOutLength);
938 tp += secBlobOutLength;
939 cb_data += secBlobOutLength;
942 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
943 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
944 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
946 smb_SetSMBDataLength(outp, cb_data);
948 smb_SetSMBDataLength(outp, 0);
951 if (smb_authType == SMB_AUTH_EXTENDED) {
954 tp = smb_GetSMBData(outp, NULL);
956 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
957 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
958 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
960 smb_SetSMBDataLength(outp, cb_data);
962 smb_SetSMBDataLength(outp, 0);
969 /* SMB_COM_LOGOFF_ANDX */
970 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
974 /* find the tree and free it */
975 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
977 smb_username_t * unp;
979 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %S", uidp->userID,
980 osi_LogSaveClientString(smb_logp, (uidp->unp) ? uidp->unp->name: _C(" ")));
982 lock_ObtainMutex(&uidp->mx);
983 uidp->flags |= SMB_USERFLAG_DELETE;
985 * it doesn't get deleted right away
986 * because the vcp points to it
989 lock_ReleaseMutex(&uidp->mx);
992 /* we can't do this. we get logoff messages prior to a session
993 * disconnect even though it doesn't mean the user is logging out.
994 * we need to create a new pioctl and EventLogoff handler to set
995 * SMB_USERNAMEFLAG_LOGOFF.
997 if (unp && smb_LogoffTokenTransfer) {
998 lock_ObtainMutex(&unp->mx);
999 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
1000 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
1001 lock_ReleaseMutex(&unp->mx);
1005 smb_ReleaseUID(uidp);
1008 osi_Log0(smb_logp, "SMB3 user logoffX");
1010 smb_SetSMBDataLength(outp, 0);
1014 #define SMB_SUPPORT_SEARCH_BITS 0x0001
1015 #define SMB_SHARE_IS_IN_DFS 0x0002
1017 /* SMB_COM_TREE_CONNECT_ANDX */
1018 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1021 smb_user_t *uidp = NULL;
1022 unsigned short newTid;
1023 clientchar_t shareName[AFSPATHMAX];
1024 clientchar_t *sharePath;
1027 clientchar_t *slashp;
1028 clientchar_t *pathp;
1029 clientchar_t *passwordp;
1030 clientchar_t *servicep;
1031 cm_user_t *userp = NULL;
1034 osi_Log0(smb_logp, "SMB3 receive tree connect");
1036 /* parse input parameters */
1037 tp = smb_GetSMBData(inp, NULL);
1038 passwordp = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1039 pathp = smb_ParseString(inp, tp, &tp, SMB_STRF_ANSIPATH);
1040 servicep = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1042 slashp = cm_ClientStrRChr(pathp, '\\');
1044 return CM_ERROR_BADSMB;
1046 cm_ClientStrCpy(shareName, lengthof(shareName), slashp+1);
1048 osi_Log3(smb_logp, "Tree connect pathp[%S] shareName[%S] service[%S]",
1049 osi_LogSaveClientString(smb_logp, pathp),
1050 osi_LogSaveClientString(smb_logp, shareName),
1051 osi_LogSaveClientString(smb_logp, servicep));
1053 if (cm_ClientStrCmp(servicep, _C("IPC")) == 0 ||
1054 cm_ClientStrCmp(shareName, _C("IPC$")) == 0) {
1056 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1059 return CM_ERROR_NOIPC;
1063 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1065 userp = smb_GetUserFromUID(uidp);
1067 lock_ObtainMutex(&vcp->mx);
1068 newTid = vcp->tidCounter++;
1069 lock_ReleaseMutex(&vcp->mx);
1071 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1074 if (!cm_ClientStrCmp(shareName, _C("*.")))
1075 cm_ClientStrCpy(shareName, lengthof(shareName), _C("all"));
1076 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1079 smb_ReleaseUID(uidp);
1080 smb_ReleaseTID(tidp, FALSE);
1081 return CM_ERROR_BADSHARENAME;
1084 if (vcp->flags & SMB_VCFLAG_USENT)
1086 int policy = smb_FindShareCSCPolicy(shareName);
1089 DWORD dwAdvertiseDFS = 0, dwSize = sizeof(DWORD);
1091 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1092 0, KEY_QUERY_VALUE, &parmKey);
1093 if (code == ERROR_SUCCESS) {
1094 code = RegQueryValueEx(parmKey, "AdvertiseDFS", NULL, NULL,
1095 (BYTE *)&dwAdvertiseDFS, &dwSize);
1096 if (code != ERROR_SUCCESS)
1098 RegCloseKey (parmKey);
1100 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1101 (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
1105 smb_SetSMBParm(outp, 2, 0);
1109 smb_ReleaseUID(uidp);
1111 lock_ObtainMutex(&tidp->mx);
1112 tidp->userp = userp;
1113 tidp->pathname = sharePath;
1115 tidp->flags |= SMB_TIDFLAG_IPC;
1116 lock_ReleaseMutex(&tidp->mx);
1117 smb_ReleaseTID(tidp, FALSE);
1119 ((smb_t *)outp)->tid = newTid;
1120 ((smb_t *)inp)->tid = newTid;
1121 tp = smb_GetSMBData(outp, NULL);
1125 tp = smb_UnparseString(outp, tp, _C("A:"), &cb_data, SMB_STRF_FORCEASCII);
1126 tp = smb_UnparseString(outp, tp, _C("AFS"), &cb_data, 0);
1127 smb_SetSMBDataLength(outp, cb_data);
1131 tp = smb_UnparseString(outp, tp, _C("IPC"), &cb_data, SMB_STRF_FORCEASCII);
1132 smb_SetSMBDataLength(outp, cb_data);
1135 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1139 /* must be called with global tran lock held */
1140 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1142 smb_tran2Packet_t *tp;
1145 smbp = (smb_t *) inp->data;
1146 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1147 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1153 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1154 int totalParms, int totalData)
1156 smb_tran2Packet_t *tp;
1159 smbp = (smb_t *) inp->data;
1160 tp = malloc(sizeof(*tp));
1161 memset(tp, 0, sizeof(*tp));
1164 tp->curData = tp->curParms = 0;
1165 tp->totalData = totalData;
1166 tp->totalParms = totalParms;
1167 tp->tid = smbp->tid;
1168 tp->mid = smbp->mid;
1169 tp->uid = smbp->uid;
1170 tp->pid = smbp->pid;
1171 tp->res[0] = smbp->res[0];
1172 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1173 if (totalParms != 0)
1174 tp->parmsp = malloc(totalParms);
1176 tp->datap = malloc(totalData);
1177 if (smbp->com == 0x25 || smbp->com == 0x26)
1180 tp->opcode = smb_GetSMBParm(inp, 14);
1183 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1185 if (WANTS_UNICODE(inp) && (vcp->flags & SMB_VCFLAG_USEUNICODE))
1186 tp->flags |= SMB_TRAN2PFLAG_USEUNICODE;
1191 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1192 smb_tran2Packet_t *inp, smb_packet_t *outp,
1193 int totalParms, int totalData)
1195 smb_tran2Packet_t *tp;
1196 unsigned short parmOffset;
1197 unsigned short dataOffset;
1198 unsigned short dataAlign;
1200 tp = malloc(sizeof(*tp));
1201 memset(tp, 0, sizeof(*tp));
1204 tp->curData = tp->curParms = 0;
1205 tp->totalData = totalData;
1206 tp->totalParms = totalParms;
1207 tp->oldTotalParms = totalParms;
1212 tp->res[0] = inp->res[0];
1213 tp->opcode = inp->opcode;
1217 * We calculate where the parameters and data will start.
1218 * This calculation must parallel the calculation in
1219 * smb_SendTran2Packet.
1222 parmOffset = 10*2 + 35;
1223 parmOffset++; /* round to even */
1224 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1226 dataOffset = parmOffset + totalParms;
1227 dataAlign = dataOffset & 2; /* quad-align */
1228 dataOffset += dataAlign;
1229 tp->datap = outp->data + dataOffset;
1234 /* free a tran2 packet */
1235 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1238 smb_ReleaseVC(t2p->vcp);
1241 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1247 while (t2p->stringsp) {
1251 t2p->stringsp = ns->nextp;
1257 clientchar_t *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
1258 char ** chainpp, int flags)
1263 if (!(p->flags & SMB_TRAN2PFLAG_USEUNICODE))
1264 flags |= SMB_STRF_FORCEASCII;
1267 cb = p->totalParms - (inp - (char *)p->parmsp);
1268 if (inp < (char *) p->parmsp ||
1269 inp >= ((char *) p->parmsp) + p->totalParms) {
1270 #ifdef DEBUG_UNICODE
1276 return smb_ParseStringBuf((unsigned char *) p->parmsp, &p->stringsp,
1277 inp, &cb, chainpp, flags);
1280 /* called with a VC, an input packet to respond to, and an error code.
1281 * sends an error response.
1283 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1284 smb_packet_t *tp, long code)
1287 unsigned short errCode;
1288 unsigned char errClass;
1289 unsigned long NTStatus;
1291 if (vcp->flags & SMB_VCFLAG_STATUS32)
1292 smb_MapNTError(code, &NTStatus);
1294 smb_MapCoreError(code, vcp, &errCode, &errClass);
1296 smb_FormatResponsePacket(vcp, NULL, tp);
1297 smbp = (smb_t *) tp;
1299 /* We can handle long names */
1300 if (vcp->flags & SMB_VCFLAG_USENT)
1301 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1303 /* now copy important fields from the tran 2 packet */
1304 smbp->com = t2p->com;
1305 smbp->tid = t2p->tid;
1306 smbp->mid = t2p->mid;
1307 smbp->pid = t2p->pid;
1308 smbp->uid = t2p->uid;
1309 smbp->res[0] = t2p->res[0];
1310 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1311 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1312 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1313 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1314 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1315 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1318 smbp->rcls = errClass;
1319 smbp->errLow = (unsigned char) (errCode & 0xff);
1320 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1324 smb_SendPacket(vcp, tp);
1327 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1330 unsigned short parmOffset;
1331 unsigned short dataOffset;
1332 unsigned short totalLength;
1333 unsigned short dataAlign;
1336 smb_FormatResponsePacket(vcp, NULL, tp);
1337 smbp = (smb_t *) tp;
1339 /* We can handle long names */
1340 if (vcp->flags & SMB_VCFLAG_USENT)
1341 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1343 /* now copy important fields from the tran 2 packet */
1344 smbp->com = t2p->com;
1345 smbp->tid = t2p->tid;
1346 smbp->mid = t2p->mid;
1347 smbp->pid = t2p->pid;
1348 smbp->uid = t2p->uid;
1349 smbp->res[0] = t2p->res[0];
1351 totalLength = 1 + t2p->totalData + t2p->totalParms;
1353 /* now add the core parameters (tran2 info) to the packet */
1354 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1355 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1356 smb_SetSMBParm(tp, 2, 0); /* reserved */
1357 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1358 parmOffset = 10*2 + 35; /* parm offset in packet */
1359 parmOffset++; /* round to even */
1360 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1361 * hdr, bcc and wct */
1362 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1363 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1364 dataOffset = parmOffset + t2p->oldTotalParms;
1365 dataAlign = dataOffset & 2; /* quad-align */
1366 dataOffset += dataAlign;
1367 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1368 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1369 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1372 datap = smb_GetSMBData(tp, NULL);
1373 *datap++ = 0; /* we rounded to even */
1375 totalLength += dataAlign;
1376 smb_SetSMBDataLength(tp, totalLength);
1378 /* next, send the datagram */
1379 smb_SendPacket(vcp, tp);
1383 /* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
1384 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1386 smb_tran2Packet_t *asp;
1399 /* We sometimes see 0 word count. What to do? */
1400 if (*inp->wctp == 0) {
1401 osi_Log0(smb_logp, "Transaction2 word count = 0");
1402 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1404 smb_SetSMBDataLength(outp, 0);
1405 smb_SendPacket(vcp, outp);
1409 totalParms = smb_GetSMBParm(inp, 0);
1410 totalData = smb_GetSMBParm(inp, 1);
1412 firstPacket = (inp->inCom == 0x25);
1414 /* find the packet we're reassembling */
1415 lock_ObtainWrite(&smb_globalLock);
1416 asp = smb_FindTran2Packet(vcp, inp);
1418 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1420 lock_ReleaseWrite(&smb_globalLock);
1422 /* now merge in this latest packet; start by looking up offsets */
1424 parmDisp = dataDisp = 0;
1425 parmOffset = smb_GetSMBParm(inp, 10);
1426 dataOffset = smb_GetSMBParm(inp, 12);
1427 parmCount = smb_GetSMBParm(inp, 9);
1428 dataCount = smb_GetSMBParm(inp, 11);
1429 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1430 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1432 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1433 totalData, dataCount, asp->maxReturnData);
1436 parmDisp = smb_GetSMBParm(inp, 4);
1437 parmOffset = smb_GetSMBParm(inp, 3);
1438 dataDisp = smb_GetSMBParm(inp, 7);
1439 dataOffset = smb_GetSMBParm(inp, 6);
1440 parmCount = smb_GetSMBParm(inp, 2);
1441 dataCount = smb_GetSMBParm(inp, 5);
1443 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1444 parmCount, dataCount);
1447 /* now copy the parms and data */
1448 if ( asp->totalParms > 0 && parmCount != 0 )
1450 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1452 if ( asp->totalData > 0 && dataCount != 0 ) {
1453 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1456 /* account for new bytes */
1457 asp->curData += dataCount;
1458 asp->curParms += parmCount;
1460 /* finally, if we're done, remove the packet from the queue and dispatch it */
1461 if (asp->totalParms > 0 &&
1462 asp->curParms > 0 &&
1463 asp->totalData <= asp->curData &&
1464 asp->totalParms <= asp->curParms) {
1465 /* we've received it all */
1466 lock_ObtainWrite(&smb_globalLock);
1467 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1468 lock_ReleaseWrite(&smb_globalLock);
1470 /* now dispatch it */
1471 rapOp = asp->parmsp[0];
1473 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1474 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1475 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1476 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
1479 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1480 code = CM_ERROR_BADOP;
1483 /* if an error is returned, we're supposed to send an error packet,
1484 * otherwise the dispatched function already did the data sending.
1485 * We give dispatched proc the responsibility since it knows how much
1486 * space to allocate.
1489 smb_SendTran2Error(vcp, asp, outp, code);
1492 /* free the input tran 2 packet */
1493 smb_FreeTran2Packet(asp);
1495 else if (firstPacket) {
1496 /* the first packet in a multi-packet request, we need to send an
1497 * ack to get more data.
1499 smb_SetSMBDataLength(outp, 0);
1500 smb_SendPacket(vcp, outp);
1506 /* ANSI versions. */
1508 #pragma pack(push, 1)
1510 typedef struct smb_rap_share_info_0 {
1511 BYTE shi0_netname[13];
1512 } smb_rap_share_info_0_t;
1514 typedef struct smb_rap_share_info_1 {
1515 BYTE shi1_netname[13];
1518 DWORD shi1_remark; /* char *shi1_remark; data offset */
1519 } smb_rap_share_info_1_t;
1521 typedef struct smb_rap_share_info_2 {
1522 BYTE shi2_netname[13];
1525 DWORD shi2_remark; /* char *shi2_remark; data offset */
1526 WORD shi2_permissions;
1528 WORD shi2_current_uses;
1529 DWORD shi2_path; /* char *shi2_path; data offset */
1530 WORD shi2_passwd[9];
1532 } smb_rap_share_info_2_t;
1534 #define SMB_RAP_MAX_SHARES 512
1536 typedef struct smb_rap_share_list {
1539 smb_rap_share_info_0_t * shares;
1540 } smb_rap_share_list_t;
1544 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1545 smb_rap_share_list_t * sp;
1547 if (dep->name[0] == '.' && (!dep->name[1] || (dep->name[1] == '.' && !dep->name[2])))
1548 return 0; /* skip over '.' and '..' */
1550 sp = (smb_rap_share_list_t *) vrockp;
1552 strncpy(sp->shares[sp->cShare].shi0_netname, dep->name, 12);
1553 sp->shares[sp->cShare].shi0_netname[12] = 0;
1557 if (sp->cShare >= sp->maxShares)
1558 return CM_ERROR_STOPNOW;
1563 /* RAP NetShareEnumRequest */
1564 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1566 smb_tran2Packet_t *outp;
1567 unsigned short * tp;
1571 int outParmsTotal; /* total parameter bytes */
1572 int outDataTotal; /* total data bytes */
1575 DWORD allSubmount = 0;
1577 DWORD nRegShares = 0;
1578 DWORD nSharesRet = 0;
1580 HKEY hkSubmount = NULL;
1581 smb_rap_share_info_1_t * shares;
1584 clientchar_t thisShare[AFSPATHMAX];
1588 smb_rap_share_list_t rootShares;
1593 tp = p->parmsp + 1; /* skip over function number (always 0) */
1596 clientchar_t * cdescp;
1598 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1599 if (cm_ClientStrCmp(cdescp, _C("WrLeh")))
1600 return CM_ERROR_INVAL;
1601 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1602 if (cm_ClientStrCmp(cdescp, _C("B13BWz")))
1603 return CM_ERROR_INVAL;
1609 if (infoLevel != 1) {
1610 return CM_ERROR_INVAL;
1613 /* We are supposed to use the same ASCII data structure even if
1614 Unicode is negotiated, which ultimately means that the share
1615 names that we return must be at most 13 characters in length,
1616 including the NULL terminator.
1618 The RAP specification states that shares with names longer than
1619 12 characters should not be included in the enumeration.
1620 However, since we support prefix cell references and since many
1621 cell names are going to exceed 12 characters, we lie and send
1622 the first 12 characters.
1625 /* first figure out how many shares there are */
1626 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1627 KEY_QUERY_VALUE, &hkParam);
1628 if (rv == ERROR_SUCCESS) {
1629 len = sizeof(allSubmount);
1630 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1631 (BYTE *) &allSubmount, &len);
1632 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1635 RegCloseKey (hkParam);
1638 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1639 0, KEY_QUERY_VALUE, &hkSubmount);
1640 if (rv == ERROR_SUCCESS) {
1641 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1642 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1643 if (rv != ERROR_SUCCESS)
1649 /* fetch the root shares */
1650 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1651 rootShares.cShare = 0;
1652 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1656 userp = smb_GetTran2User(vcp,p);
1658 thyper.HighPart = 0;
1661 cm_HoldSCache(cm_data.rootSCachep);
1662 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1663 cm_ReleaseSCache(cm_data.rootSCachep);
1665 cm_ReleaseUser(userp);
1667 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1669 #define REMARK_LEN 1
1670 outParmsTotal = 8; /* 4 dwords */
1671 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1672 if(outDataTotal > bufsize) {
1673 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1674 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1677 nSharesRet = nShares;
1680 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1682 /* now for the submounts */
1683 shares = (smb_rap_share_info_1_t *) outp->datap;
1684 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1686 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1689 StringCchCopyA(shares[cshare].shi1_netname,
1690 lengthof(shares[cshare].shi1_netname), "all" );
1691 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1692 /* type and pad are zero already */
1698 for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
1699 len = sizeof(thisShare);
1700 rv = RegEnumValueW(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
1701 if (rv == ERROR_SUCCESS &&
1702 cm_ClientStrLen(thisShare) &&
1703 (!allSubmount || cm_ClientStrCmpI(thisShare,_C("all")))) {
1704 cm_ClientStringToUtf8(thisShare, -1, shares[cshare].shi1_netname,
1705 lengthof( shares[cshare].shi1_netname ));
1706 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1707 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1712 nShares--; /* uncount key */
1715 RegCloseKey(hkSubmount);
1718 nonrootShares = cshare;
1720 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1721 /* in case there are collisions with submounts, submounts have
1723 for (j=0; j < nonrootShares; j++)
1724 if (!cm_stricmp_utf8(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1727 if (j < nonrootShares) {
1728 nShares--; /* uncount */
1732 StringCchCopyA(shares[cshare].shi1_netname, lengthof(shares[cshare].shi1_netname),
1733 rootShares.shares[i].shi0_netname);
1734 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1739 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1740 outp->parmsp[1] = 0;
1741 outp->parmsp[2] = cshare;
1742 outp->parmsp[3] = nShares;
1744 outp->totalData = (int)(cstrp - outp->datap);
1745 outp->totalParms = outParmsTotal;
1747 smb_SendTran2Packet(vcp, outp, op);
1748 smb_FreeTran2Packet(outp);
1750 free(rootShares.shares);
1755 /* RAP NetShareGetInfo */
1756 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1758 smb_tran2Packet_t *outp;
1759 unsigned short * tp;
1760 clientchar_t * shareName;
1761 BOOL shareFound = FALSE;
1762 unsigned short infoLevel;
1763 unsigned short bufsize;
1772 cm_scache_t *scp = NULL;
1778 tp = p->parmsp + 1; /* skip over function number (always 1) */
1781 clientchar_t * cdescp;
1783 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1784 if (cm_ClientStrCmp(cdescp, _C("zWrLh")))
1786 return CM_ERROR_INVAL;
1788 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1789 if (cm_ClientStrCmp(cdescp, _C("B13")) &&
1790 cm_ClientStrCmp(cdescp, _C("B13BWz")) &&
1791 cm_ClientStrCmp(cdescp, _C("B13BWzWWWzB9B")))
1793 return CM_ERROR_INVAL;
1795 shareName = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1803 totalData = sizeof(smb_rap_share_info_0_t);
1804 else if(infoLevel == SMB_INFO_STANDARD)
1805 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1806 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1807 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1809 return CM_ERROR_INVAL;
1811 if(!cm_ClientStrCmpI(shareName, _C("all")) || !cm_ClientStrCmp(shareName,_C("*."))) {
1812 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1813 KEY_QUERY_VALUE, &hkParam);
1814 if (rv == ERROR_SUCCESS) {
1815 len = sizeof(allSubmount);
1816 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1817 (BYTE *) &allSubmount, &len);
1818 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1821 RegCloseKey (hkParam);
1828 userp = smb_GetTran2User(vcp, p);
1830 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
1831 return CM_ERROR_BADSMB;
1833 code = cm_NameI(cm_data.rootSCachep, shareName,
1834 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
1835 userp, NULL, &req, &scp);
1837 cm_ReleaseSCache(scp);
1840 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1841 KEY_QUERY_VALUE, &hkSubmount);
1842 if (rv == ERROR_SUCCESS) {
1843 rv = RegQueryValueExW(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1844 if (rv == ERROR_SUCCESS) {
1847 RegCloseKey(hkSubmount);
1853 return CM_ERROR_BADSHARENAME;
1855 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1856 memset(outp->datap, 0, totalData);
1858 outp->parmsp[0] = 0;
1859 outp->parmsp[1] = 0;
1860 outp->parmsp[2] = totalData;
1862 if (infoLevel == 0) {
1863 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1864 cm_ClientStringToUtf8(shareName, -1, info->shi0_netname,
1865 lengthof(info->shi0_netname));
1866 } else if(infoLevel == SMB_INFO_STANDARD) {
1867 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1868 cm_ClientStringToUtf8(shareName, -1, info->shi1_netname, lengthof(info->shi1_netname));
1869 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1870 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1871 /* type and pad are already zero */
1872 } else { /* infoLevel==2 */
1873 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1874 cm_ClientStringToUtf8(shareName, -1, info->shi2_netname, lengthof(info->shi2_netname));
1875 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1876 info->shi2_permissions = ACCESS_ALL;
1877 info->shi2_max_uses = (unsigned short) -1;
1878 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
1881 outp->totalData = totalData;
1882 outp->totalParms = totalParam;
1884 smb_SendTran2Packet(vcp, outp, op);
1885 smb_FreeTran2Packet(outp);
1890 #pragma pack(push, 1)
1892 typedef struct smb_rap_wksta_info_10 {
1893 DWORD wki10_computername; /*char *wki10_computername;*/
1894 DWORD wki10_username; /* char *wki10_username; */
1895 DWORD wki10_langroup; /* char *wki10_langroup;*/
1896 BYTE wki10_ver_major;
1897 BYTE wki10_ver_minor;
1898 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1899 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1900 } smb_rap_wksta_info_10_t;
1904 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1906 smb_tran2Packet_t *outp;
1910 unsigned short * tp;
1913 smb_rap_wksta_info_10_t * info;
1917 tp = p->parmsp + 1; /* Skip over function number */
1920 clientchar_t * cdescp;
1922 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
1923 SMB_STRF_FORCEASCII);
1924 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
1925 return CM_ERROR_INVAL;
1927 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
1928 SMB_STRF_FORCEASCII);
1929 if (cm_ClientStrCmp(cdescp, _C("zzzBBzz")))
1930 return CM_ERROR_INVAL;
1936 if (infoLevel != 10) {
1937 return CM_ERROR_INVAL;
1943 totalData = sizeof(*info) + /* info */
1944 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1945 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1946 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1947 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1948 1; /* wki10_oth_domains (null)*/
1950 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1952 memset(outp->parmsp,0,totalParams);
1953 memset(outp->datap,0,totalData);
1955 info = (smb_rap_wksta_info_10_t *) outp->datap;
1956 cstrp = (char *) (info + 1);
1958 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1959 StringCbCopyA(cstrp, totalData, smb_localNamep);
1960 cstrp += strlen(cstrp) + 1;
1962 info->wki10_username = (DWORD) (cstrp - outp->datap);
1963 uidp = smb_FindUID(vcp, p->uid, 0);
1965 lock_ObtainMutex(&uidp->mx);
1966 if(uidp->unp && uidp->unp->name)
1967 cm_ClientStringToUtf8(uidp->unp->name, -1,
1968 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
1969 lock_ReleaseMutex(&uidp->mx);
1970 smb_ReleaseUID(uidp);
1972 cstrp += strlen(cstrp) + 1;
1974 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1975 StringCbCopyA(cstrp, totalData - (cstrp - outp->datap)*sizeof(char), "WORKGROUP");
1976 cstrp += strlen(cstrp) + 1;
1978 /* TODO: Not sure what values these should take, but these work */
1979 info->wki10_ver_major = 5;
1980 info->wki10_ver_minor = 1;
1982 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1983 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
1984 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
1985 cstrp += strlen(cstrp) + 1;
1987 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1988 cstrp ++; /* no other domains */
1990 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1991 outp->parmsp[2] = outp->totalData;
1992 outp->totalParms = totalParams;
1994 smb_SendTran2Packet(vcp,outp,op);
1995 smb_FreeTran2Packet(outp);
2000 #pragma pack(push, 1)
2002 typedef struct smb_rap_server_info_0 {
2004 } smb_rap_server_info_0_t;
2006 typedef struct smb_rap_server_info_1 {
2008 BYTE sv1_version_major;
2009 BYTE sv1_version_minor;
2011 DWORD sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
2012 } smb_rap_server_info_1_t;
2016 char smb_ServerComment[] = "OpenAFS Client";
2017 int smb_ServerCommentLen = sizeof(smb_ServerComment);
2019 #define SMB_SV_TYPE_SERVER 0x00000002L
2020 #define SMB_SV_TYPE_NT 0x00001000L
2021 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
2023 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2025 smb_tran2Packet_t *outp;
2029 unsigned short * tp;
2032 smb_rap_server_info_0_t * info0;
2033 smb_rap_server_info_1_t * info1;
2036 tp = p->parmsp + 1; /* Skip over function number */
2039 clientchar_t * cdescp;
2041 cdescp = smb_ParseStringT2Parm(p, (unsigned char *) tp, (char **) &tp,
2042 SMB_STRF_FORCEASCII);
2043 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2044 return CM_ERROR_INVAL;
2045 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2046 SMB_STRF_FORCEASCII);
2047 if (cm_ClientStrCmp(cdescp, _C("B16")) ||
2048 cm_ClientStrCmp(cdescp, _C("B16BBDz")))
2049 return CM_ERROR_INVAL;
2055 if (infoLevel != 0 && infoLevel != 1) {
2056 return CM_ERROR_INVAL;
2062 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
2063 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
2065 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2067 memset(outp->parmsp,0,totalParams);
2068 memset(outp->datap,0,totalData);
2070 if (infoLevel == 0) {
2071 info0 = (smb_rap_server_info_0_t *) outp->datap;
2072 cstrp = (char *) (info0 + 1);
2073 StringCchCopyA(info0->sv0_name, lengthof(info0->sv0_name), "AFS");
2074 } else { /* infoLevel == SMB_INFO_STANDARD */
2075 info1 = (smb_rap_server_info_1_t *) outp->datap;
2076 cstrp = (char *) (info1 + 1);
2077 StringCchCopyA(info1->sv1_name, lengthof(info1->sv1_name), "AFS");
2080 SMB_SV_TYPE_SERVER |
2082 SMB_SV_TYPE_SERVER_NT;
2084 info1->sv1_version_major = 5;
2085 info1->sv1_version_minor = 1;
2086 info1->sv1_comment_or_master_browser = (DWORD) (cstrp - outp->datap);
2088 StringCbCopyA(cstrp, smb_ServerCommentLen, smb_ServerComment);
2090 cstrp += smb_ServerCommentLen / sizeof(char);
2093 totalData = (DWORD)(cstrp - outp->datap);
2094 outp->totalData = min(bufsize,totalData); /* actual data size */
2095 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
2096 outp->parmsp[2] = totalData;
2097 outp->totalParms = totalParams;
2099 smb_SendTran2Packet(vcp,outp,op);
2100 smb_FreeTran2Packet(outp);
2105 /* SMB_COM_TRANSACTION2 and SMB_COM_TRANSACTION2_SECONDARY */
2106 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2108 smb_tran2Packet_t *asp;
2120 /* We sometimes see 0 word count. What to do? */
2121 if (*inp->wctp == 0) {
2122 osi_Log0(smb_logp, "Transaction2 word count = 0");
2123 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
2125 smb_SetSMBDataLength(outp, 0);
2126 smb_SendPacket(vcp, outp);
2130 totalParms = smb_GetSMBParm(inp, 0);
2131 totalData = smb_GetSMBParm(inp, 1);
2133 firstPacket = (inp->inCom == 0x32);
2135 /* find the packet we're reassembling */
2136 lock_ObtainWrite(&smb_globalLock);
2137 asp = smb_FindTran2Packet(vcp, inp);
2139 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
2141 lock_ReleaseWrite(&smb_globalLock);
2143 /* now merge in this latest packet; start by looking up offsets */
2145 parmDisp = dataDisp = 0;
2146 parmOffset = smb_GetSMBParm(inp, 10);
2147 dataOffset = smb_GetSMBParm(inp, 12);
2148 parmCount = smb_GetSMBParm(inp, 9);
2149 dataCount = smb_GetSMBParm(inp, 11);
2150 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2151 asp->maxReturnData = smb_GetSMBParm(inp, 3);
2153 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2154 totalData, dataCount, asp->maxReturnData);
2157 parmDisp = smb_GetSMBParm(inp, 4);
2158 parmOffset = smb_GetSMBParm(inp, 3);
2159 dataDisp = smb_GetSMBParm(inp, 7);
2160 dataOffset = smb_GetSMBParm(inp, 6);
2161 parmCount = smb_GetSMBParm(inp, 2);
2162 dataCount = smb_GetSMBParm(inp, 5);
2164 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2165 parmCount, dataCount);
2168 /* now copy the parms and data */
2169 if ( asp->totalParms > 0 && parmCount != 0 )
2171 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2173 if ( asp->totalData > 0 && dataCount != 0 ) {
2174 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2177 /* account for new bytes */
2178 asp->curData += dataCount;
2179 asp->curParms += parmCount;
2181 /* finally, if we're done, remove the packet from the queue and dispatch it */
2182 if (asp->totalParms > 0 &&
2183 asp->curParms > 0 &&
2184 asp->totalData <= asp->curData &&
2185 asp->totalParms <= asp->curParms) {
2186 /* we've received it all */
2187 lock_ObtainWrite(&smb_globalLock);
2188 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2189 lock_ReleaseWrite(&smb_globalLock);
2191 /* now dispatch it */
2192 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2193 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2194 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2197 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2198 code = CM_ERROR_BADOP;
2201 /* if an error is returned, we're supposed to send an error packet,
2202 * otherwise the dispatched function already did the data sending.
2203 * We give dispatched proc the responsibility since it knows how much
2204 * space to allocate.
2207 smb_SendTran2Error(vcp, asp, outp, code);
2210 /* free the input tran 2 packet */
2211 smb_FreeTran2Packet(asp);
2213 else if (firstPacket) {
2214 /* the first packet in a multi-packet request, we need to send an
2215 * ack to get more data.
2217 smb_SetSMBDataLength(outp, 0);
2218 smb_SendPacket(vcp, outp);
2225 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2227 clientchar_t *pathp;
2228 smb_tran2Packet_t *outp;
2233 cm_scache_t *dscp; /* dir we're dealing with */
2234 cm_scache_t *scp; /* file we're creating */
2236 int initialModeBits;
2239 clientchar_t *lastNamep;
2246 int parmSlot; /* which parm we're dealing with */
2247 long returnEALength;
2248 clientchar_t *tidPathp;
2256 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2257 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2259 openFun = p->parmsp[6]; /* open function */
2260 excl = ((openFun & 3) == 0);
2261 trunc = ((openFun & 3) == 2); /* truncate it */
2262 openMode = (p->parmsp[1] & 0x7);
2263 openAction = 0; /* tracks what we did */
2265 attributes = p->parmsp[3];
2266 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2268 /* compute initial mode bits based on read-only flag in attributes */
2269 initialModeBits = 0666;
2270 if (attributes & SMB_ATTR_READONLY)
2271 initialModeBits &= ~0222;
2273 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
2276 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2278 spacep = cm_GetSpace();
2279 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2282 (cm_ClientStrCmpI(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
2283 cm_ClientStrCmpI(lastNamep, _C("\\srvsvc")) == 0 ||
2284 cm_ClientStrCmpI(lastNamep, _C("\\wkssvc")) == 0 ||
2285 cm_ClientStrCmpI(lastNamep, _C("\\ipc$")) == 0)) {
2286 /* special case magic file name for receiving IOCTL requests
2287 * (since IOCTL calls themselves aren't getting through).
2289 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2290 smb_SetupIoctlFid(fidp, spacep);
2292 /* copy out remainder of the parms */
2294 outp->parmsp[parmSlot++] = fidp->fid;
2296 outp->parmsp[parmSlot++] = 0; /* attrs */
2297 outp->parmsp[parmSlot++] = 0; /* mod time */
2298 outp->parmsp[parmSlot++] = 0;
2299 outp->parmsp[parmSlot++] = 0; /* len */
2300 outp->parmsp[parmSlot++] = 0x7fff;
2301 outp->parmsp[parmSlot++] = openMode;
2302 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2303 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2305 /* and the final "always present" stuff */
2306 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2307 /* next write out the "unique" ID */
2308 outp->parmsp[parmSlot++] = 0x1234;
2309 outp->parmsp[parmSlot++] = 0x5678;
2310 outp->parmsp[parmSlot++] = 0;
2311 if (returnEALength) {
2312 outp->parmsp[parmSlot++] = 0;
2313 outp->parmsp[parmSlot++] = 0;
2316 outp->totalData = 0;
2317 outp->totalParms = parmSlot * 2;
2319 smb_SendTran2Packet(vcp, outp, op);
2321 smb_FreeTran2Packet(outp);
2323 /* and clean up fid reference */
2324 smb_ReleaseFID(fidp);
2328 #ifdef DEBUG_VERBOSE
2330 char *hexp, *asciip;
2331 asciip = (lastNamep ? lastNamep : pathp);
2332 hexp = osi_HexifyString( asciip );
2333 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2338 userp = smb_GetTran2User(vcp, p);
2339 /* In the off chance that userp is NULL, we log and abandon */
2341 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2342 smb_FreeTran2Packet(outp);
2343 return CM_ERROR_BADSMB;
2346 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2347 if (code == CM_ERROR_TIDIPC) {
2348 /* Attempt to use a TID allocated for IPC. The client
2349 * is probably looking for DCE RPC end points which we
2350 * don't support OR it could be looking to make a DFS
2353 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2355 cm_ReleaseUser(userp);
2356 smb_FreeTran2Packet(outp);
2357 return CM_ERROR_NOSUCHPATH;
2362 code = cm_NameI(cm_data.rootSCachep, pathp,
2363 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2364 userp, tidPathp, &req, &scp);
2366 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2367 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2368 userp, tidPathp, &req, &dscp);
2369 cm_FreeSpace(spacep);
2372 cm_ReleaseUser(userp);
2373 smb_FreeTran2Packet(outp);
2378 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2379 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2380 (clientchar_t*) spacep->data);
2381 cm_ReleaseSCache(dscp);
2382 cm_ReleaseUser(userp);
2383 smb_FreeTran2Packet(outp);
2384 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2385 return CM_ERROR_PATH_NOT_COVERED;
2387 return CM_ERROR_BADSHARENAME;
2389 #endif /* DFS_SUPPORT */
2391 /* otherwise, scp points to the parent directory. Do a lookup,
2392 * and truncate the file if we find it, otherwise we create the
2399 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2401 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2402 cm_ReleaseSCache(dscp);
2403 cm_ReleaseUser(userp);
2404 smb_FreeTran2Packet(outp);
2409 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2410 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2411 cm_ReleaseSCache(scp);
2412 cm_ReleaseUser(userp);
2413 smb_FreeTran2Packet(outp);
2414 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2415 return CM_ERROR_PATH_NOT_COVERED;
2417 return CM_ERROR_BADSHARENAME;
2419 #endif /* DFS_SUPPORT */
2421 /* macintosh is expensive to program for it */
2422 cm_FreeSpace(spacep);
2425 /* if we get here, if code is 0, the file exists and is represented by
2426 * scp. Otherwise, we have to create it.
2429 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2432 cm_ReleaseSCache(dscp);
2433 cm_ReleaseSCache(scp);
2434 cm_ReleaseUser(userp);
2435 smb_FreeTran2Packet(outp);
2440 /* oops, file shouldn't be there */
2442 cm_ReleaseSCache(dscp);
2443 cm_ReleaseSCache(scp);
2444 cm_ReleaseUser(userp);
2445 smb_FreeTran2Packet(outp);
2446 return CM_ERROR_EXISTS;
2450 setAttr.mask = CM_ATTRMASK_LENGTH;
2451 setAttr.length.LowPart = 0;
2452 setAttr.length.HighPart = 0;
2453 code = cm_SetAttr(scp, &setAttr, userp, &req);
2454 openAction = 3; /* truncated existing file */
2457 openAction = 1; /* found existing file */
2459 else if (!(openFun & 0x10)) {
2460 /* don't create if not found */
2462 cm_ReleaseSCache(dscp);
2463 osi_assertx(scp == NULL, "null cm_scache_t");
2464 cm_ReleaseUser(userp);
2465 smb_FreeTran2Packet(outp);
2466 return CM_ERROR_NOSUCHFILE;
2469 osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2470 openAction = 2; /* created file */
2471 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2472 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2473 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2477 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2478 smb_NotifyChange(FILE_ACTION_ADDED,
2479 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2480 dscp, lastNamep, NULL, TRUE);
2481 } else if (!excl && code == CM_ERROR_EXISTS) {
2482 /* not an exclusive create, and someone else tried
2483 * creating it already, then we open it anyway. We
2484 * don't bother retrying after this, since if this next
2485 * fails, that means that the file was deleted after we
2486 * started this call.
2488 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2492 setAttr.mask = CM_ATTRMASK_LENGTH;
2493 setAttr.length.LowPart = 0;
2494 setAttr.length.HighPart = 0;
2495 code = cm_SetAttr(scp, &setAttr, userp,
2498 } /* lookup succeeded */
2502 /* we don't need this any longer */
2504 cm_ReleaseSCache(dscp);
2507 /* something went wrong creating or truncating the file */
2509 cm_ReleaseSCache(scp);
2510 cm_ReleaseUser(userp);
2511 smb_FreeTran2Packet(outp);
2515 /* make sure we're about to open a file */
2516 if (scp->fileType != CM_SCACHETYPE_FILE) {
2518 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2519 cm_scache_t * targetScp = 0;
2520 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2522 /* we have a more accurate file to use (the
2523 * target of the symbolic link). Otherwise,
2524 * we'll just use the symlink anyway.
2526 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2528 cm_ReleaseSCache(scp);
2532 if (scp->fileType != CM_SCACHETYPE_FILE) {
2533 cm_ReleaseSCache(scp);
2534 cm_ReleaseUser(userp);
2535 smb_FreeTran2Packet(outp);
2536 return CM_ERROR_ISDIR;
2540 /* now all we have to do is open the file itself */
2541 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2542 osi_assertx(fidp, "null smb_fid_t");
2545 lock_ObtainMutex(&fidp->mx);
2546 /* save a pointer to the vnode */
2547 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2549 lock_ObtainWrite(&scp->rw);
2550 scp->flags |= CM_SCACHEFLAG_SMB_FID;
2551 lock_ReleaseWrite(&scp->rw);
2554 fidp->userp = userp;
2556 /* compute open mode */
2558 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
2559 if (openMode == 1 || openMode == 2)
2560 fidp->flags |= SMB_FID_OPENWRITE;
2562 /* remember that the file was newly created */
2564 fidp->flags |= SMB_FID_CREATED;
2566 lock_ReleaseMutex(&fidp->mx);
2568 smb_ReleaseFID(fidp);
2570 cm_Open(scp, 0, userp);
2572 /* copy out remainder of the parms */
2574 outp->parmsp[parmSlot++] = fidp->fid;
2575 lock_ObtainRead(&scp->rw);
2577 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2578 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2579 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2580 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2581 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2582 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2583 outp->parmsp[parmSlot++] = openMode;
2584 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2585 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2587 /* and the final "always present" stuff */
2588 outp->parmsp[parmSlot++] = openAction;
2589 /* next write out the "unique" ID */
2590 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2591 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2592 outp->parmsp[parmSlot++] = 0;
2593 if (returnEALength) {
2594 outp->parmsp[parmSlot++] = 0;
2595 outp->parmsp[parmSlot++] = 0;
2597 lock_ReleaseRead(&scp->rw);
2598 outp->totalData = 0; /* total # of data bytes */
2599 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2601 smb_SendTran2Packet(vcp, outp, op);
2603 smb_FreeTran2Packet(outp);
2605 cm_ReleaseUser(userp);
2606 /* leave scp held since we put it in fidp->scp */
2610 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2613 unsigned short infolevel;
2615 infolevel = p->parmsp[0];
2617 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2619 return CM_ERROR_BAD_LEVEL;
2622 /* TRANS2_QUERY_FS_INFORMATION */
2623 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2625 smb_tran2Packet_t *outp;
2626 smb_tran2QFSInfo_t qi;
2630 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2632 switch (p->parmsp[0]) {
2633 case SMB_INFO_ALLOCATION:
2635 responseSize = sizeof(qi.u.allocInfo);
2637 qi.u.allocInfo.FSID = 0;
2638 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2639 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2640 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2641 qi.u.allocInfo.bytesPerSector = 1024;
2644 case SMB_INFO_VOLUME:
2646 qi.u.volumeInfo.vsn = 1234; /* Volume serial number */
2647 qi.u.volumeInfo.vnCount = 4; /* Number of characters in label (AFS\0)*/
2649 /* we're supposed to pad it out with zeroes to the end */
2650 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2651 smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
2653 responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
2656 case SMB_QUERY_FS_VOLUME_INFO:
2657 /* FS volume info */
2658 responseSize = sizeof(qi.u.FSvolumeInfo);
2661 FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
2662 memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
2665 qi.u.FSvolumeInfo.vsn = 1234;
2666 qi.u.FSvolumeInfo.vnCount = 8; /* This is always in Unicode */
2667 memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
2670 case SMB_QUERY_FS_SIZE_INFO:
2672 responseSize = sizeof(qi.u.FSsizeInfo);
2674 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2675 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2676 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2677 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2678 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2679 qi.u.FSsizeInfo.bytesPerSector = 1024;
2682 case SMB_QUERY_FS_DEVICE_INFO:
2683 /* FS device info */
2684 responseSize = sizeof(qi.u.FSdeviceInfo);
2686 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2687 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2690 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2691 /* FS attribute info */
2693 /* attributes, defined in WINNT.H:
2694 * FILE_CASE_SENSITIVE_SEARCH 0x1
2695 * FILE_CASE_PRESERVED_NAMES 0x2
2696 * FILE_VOLUME_QUOTAS 0x10
2697 * <no name defined> 0x4000
2698 * If bit 0x4000 is not set, Windows 95 thinks
2699 * we can't handle long (non-8.3) names,
2700 * despite our protestations to the contrary.
2702 qi.u.FSattributeInfo.attributes = 0x4003;
2703 /* The maxCompLength is supposed to be in bytes */
2705 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2706 qi.u.FSattributeInfo.maxCompLength = MAX_PATH * sizeof(wchar_t);
2709 qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
2713 smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
2714 qi.u.FSattributeInfo.FSnameLength = sz;
2717 sizeof(qi.u.FSattributeInfo.attributes) +
2718 sizeof(qi.u.FSattributeInfo.maxCompLength) +
2719 sizeof(qi.u.FSattributeInfo.FSnameLength) +
2724 case SMB_INFO_UNIX: /* CIFS Unix Info */
2725 case SMB_INFO_MACOS: /* Mac FS Info */
2727 return CM_ERROR_BADOP;
2730 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2732 /* copy out return data, and set corresponding sizes */
2733 outp->totalParms = 0;
2734 outp->totalData = responseSize;
2735 memcpy(outp->datap, &qi, responseSize);
2737 /* send and free the packets */
2738 smb_SendTran2Packet(vcp, outp, op);
2739 smb_FreeTran2Packet(outp);
2744 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2746 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2747 return CM_ERROR_BADOP;
2750 struct smb_ShortNameRock {
2751 clientchar_t *maskp;
2753 clientchar_t *shortName;
2754 size_t shortNameLen;
2757 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2760 struct smb_ShortNameRock *rockp;
2761 normchar_t normName[MAX_PATH];
2762 clientchar_t *shortNameEnd;
2766 cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t));
2768 /* compare both names and vnodes, though probably just comparing vnodes
2769 * would be safe enough.
2771 if (cm_NormStrCmpI(normName, rockp->maskp) != 0)
2773 if (ntohl(dep->fid.vnode) != rockp->vnode)
2776 /* This is the entry */
2777 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2778 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2780 return CM_ERROR_STOPNOW;
2783 long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
2784 clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
2786 struct smb_ShortNameRock rock;
2787 clientchar_t *lastNamep;
2790 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2794 spacep = cm_GetSpace();
2795 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2797 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2798 caseFold, userp, tidPathp,
2800 cm_FreeSpace(spacep);
2805 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2806 cm_ReleaseSCache(dscp);
2807 cm_ReleaseUser(userp);
2811 return CM_ERROR_PATH_NOT_COVERED;
2813 #endif /* DFS_SUPPORT */
2815 if (!lastNamep) lastNamep = pathp;
2818 thyper.HighPart = 0;
2819 rock.shortName = shortName;
2821 rock.maskp = lastNamep;
2822 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2824 cm_ReleaseSCache(dscp);
2827 return CM_ERROR_NOSUCHFILE;
2828 if (code == CM_ERROR_STOPNOW) {
2829 *shortNameLenp = rock.shortNameLen;
2835 /* TRANS2_QUERY_PATH_INFORMATION */
2836 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2838 smb_tran2Packet_t *outp;
2841 unsigned short infoLevel;
2842 smb_tran2QPathInfo_t qpi;
2844 unsigned short attributes;
2845 unsigned long extAttributes;
2846 clientchar_t shortName[13];
2850 cm_scache_t *scp, *dscp;
2851 int scp_rw_held = 0;
2854 clientchar_t *pathp;
2855 clientchar_t *tidPathp;
2856 clientchar_t *lastComp;
2861 infoLevel = p->parmsp[0];
2862 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2864 else if (infoLevel == SMB_INFO_STANDARD)
2865 responseSize = sizeof(qpi.u.QPstandardInfo);
2866 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2867 responseSize = sizeof(qpi.u.QPeaSizeInfo);
2868 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2869 responseSize = sizeof(qpi.u.QPfileBasicInfo);
2870 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2871 responseSize = sizeof(qpi.u.QPfileStandardInfo);
2872 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2873 responseSize = sizeof(qpi.u.QPfileEaInfo);
2874 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2875 responseSize = sizeof(qpi.u.QPfileNameInfo);
2876 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
2877 responseSize = sizeof(qpi.u.QPfileAllInfo);
2878 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2879 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2881 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2882 p->opcode, infoLevel);
2883 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
2887 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
2888 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %S", infoLevel,
2889 osi_LogSaveClientString(smb_logp, pathp));
2891 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2893 if (infoLevel > 0x100)
2894 outp->totalParms = 2;
2896 outp->totalParms = 0;
2897 outp->totalData = responseSize;
2899 /* now, if we're at infoLevel 6, we're only being asked to check
2900 * the syntax, so we just OK things now. In particular, we're *not*
2901 * being asked to verify anything about the state of any parent dirs.
2903 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2904 smb_SendTran2Packet(vcp, outp, opx);
2905 smb_FreeTran2Packet(outp);
2909 userp = smb_GetTran2User(vcp, p);
2911 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2912 smb_FreeTran2Packet(outp);
2913 return CM_ERROR_BADSMB;
2916 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2918 cm_ReleaseUser(userp);
2919 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2920 smb_FreeTran2Packet(outp);
2925 * XXX Strange hack XXX
2927 * As of Patch 7 (13 January 98), we are having the following problem:
2928 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2929 * requests to look up "desktop.ini" in all the subdirectories.
2930 * This can cause zillions of timeouts looking up non-existent cells
2931 * and volumes, especially in the top-level directory.
2933 * We have not found any way to avoid this or work around it except
2934 * to explicitly ignore the requests for mount points that haven't
2935 * yet been evaluated and for directories that haven't yet been
2938 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2939 spacep = cm_GetSpace();
2940 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
2941 #ifndef SPECIAL_FOLDERS
2942 /* Make sure that lastComp is not NULL */
2944 if (cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
2945 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2949 userp, tidPathp, &req, &dscp);
2952 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2953 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2955 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2956 code = CM_ERROR_PATH_NOT_COVERED;
2958 code = CM_ERROR_BADSHARENAME;
2960 #endif /* DFS_SUPPORT */
2961 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2962 code = CM_ERROR_NOSUCHFILE;
2963 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2964 cm_buf_t *bp = buf_Find(dscp, &hzero);
2970 code = CM_ERROR_NOSUCHFILE;
2972 cm_ReleaseSCache(dscp);
2974 cm_FreeSpace(spacep);
2975 cm_ReleaseUser(userp);
2976 smb_SendTran2Error(vcp, p, opx, code);
2977 smb_FreeTran2Packet(outp);
2983 #endif /* SPECIAL_FOLDERS */
2985 cm_FreeSpace(spacep);
2988 /* now do namei and stat, and copy out the info */
2989 code = cm_NameI(cm_data.rootSCachep, pathp,
2990 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2993 cm_ReleaseUser(userp);
2994 smb_SendTran2Error(vcp, p, opx, code);
2995 smb_FreeTran2Packet(outp);
3000 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3001 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3002 cm_ReleaseSCache(scp);
3003 cm_ReleaseUser(userp);
3004 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3005 code = CM_ERROR_PATH_NOT_COVERED;
3007 code = CM_ERROR_BADSHARENAME;
3008 smb_SendTran2Error(vcp, p, opx, code);
3009 smb_FreeTran2Packet(outp);
3012 #endif /* DFS_SUPPORT */
3014 lock_ObtainWrite(&scp->rw);
3016 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3017 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3021 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3023 lock_ConvertWToR(&scp->rw);
3028 /* now we have the status in the cache entry, and everything is locked.
3029 * Marshall the output data.
3031 /* for info level 108, figure out short name */
3032 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3033 code = cm_GetShortName(pathp, userp, &req,
3034 tidPathp, scp->fid.vnode, shortName,
3040 smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
3041 qpi.u.QPfileAltNameInfo.fileNameLength = len;
3045 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3046 smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3047 qpi.u.QPfileNameInfo.fileNameLength = len;
3051 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3052 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3053 qpi.u.QPstandardInfo.creationDateTime = dosTime;
3054 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3055 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3056 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3057 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3058 attributes = smb_Attributes(scp);
3059 qpi.u.QPstandardInfo.attributes = attributes;
3060 qpi.u.QPstandardInfo.eaSize = 0;
3062 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3063 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3064 qpi.u.QPfileBasicInfo.creationTime = ft;
3065 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3066 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3067 qpi.u.QPfileBasicInfo.changeTime = ft;
3068 extAttributes = smb_ExtAttributes(scp);
3069 qpi.u.QPfileBasicInfo.attributes = extAttributes;
3070 qpi.u.QPfileBasicInfo.reserved = 0;
3072 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3073 smb_fid_t *fidp = smb_FindFIDByScache(vcp, scp);
3075 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3076 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3077 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3078 qpi.u.QPfileStandardInfo.directory =
3079 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3080 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3081 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3082 qpi.u.QPfileStandardInfo.reserved = 0;
3085 lock_ReleaseRead(&scp->rw);
3087 lock_ObtainMutex(&fidp->mx);
3088 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3089 lock_ReleaseMutex(&fidp->mx);
3090 smb_ReleaseFID(fidp);
3092 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3094 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3095 qpi.u.QPfileEaInfo.eaSize = 0;
3097 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3098 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3099 qpi.u.QPfileAllInfo.creationTime = ft;
3100 qpi.u.QPfileAllInfo.lastAccessTime = ft;
3101 qpi.u.QPfileAllInfo.lastWriteTime = ft;
3102 qpi.u.QPfileAllInfo.changeTime = ft;
3103 extAttributes = smb_ExtAttributes(scp);
3104 qpi.u.QPfileAllInfo.attributes = extAttributes;
3105 qpi.u.QPfileAllInfo.allocationSize = scp->length;
3106 qpi.u.QPfileAllInfo.endOfFile = scp->length;
3107 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3108 qpi.u.QPfileAllInfo.deletePending = 0;
3109 qpi.u.QPfileAllInfo.directory =
3110 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3111 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3112 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3113 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
3114 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
3115 qpi.u.QPfileAllInfo.eaSize = 0;
3116 qpi.u.QPfileAllInfo.accessFlags = 0;
3117 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
3118 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
3119 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3120 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3121 qpi.u.QPfileAllInfo.mode = 0;
3122 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3124 smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3125 qpi.u.QPfileAllInfo.fileNameLength = len;
3128 /* send and free the packets */
3130 switch (scp_rw_held) {
3132 lock_ReleaseRead(&scp->rw);
3135 lock_ReleaseWrite(&scp->rw);
3139 cm_ReleaseSCache(scp);
3140 cm_ReleaseUser(userp);
3142 memcpy(outp->datap, &qpi, responseSize);
3143 smb_SendTran2Packet(vcp, outp, opx);
3145 smb_SendTran2Error(vcp, p, opx, code);
3147 smb_FreeTran2Packet(outp);
3152 /* TRANS2_SET_PATH_INFORMATION */
3153 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3156 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
3157 return CM_ERROR_BADOP;
3161 unsigned short infoLevel;
3162 clientchar_t * pathp;
3163 smb_tran2Packet_t *outp;
3164 smb_tran2QPathInfo_t *spi;
3166 cm_scache_t *scp, *dscp;
3169 clientchar_t *tidPathp;
3170 clientchar_t *lastComp;
3174 infoLevel = p->parmsp[0];
3175 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
3176 if (infoLevel != SMB_INFO_STANDARD &&
3177 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
3178 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
3179 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3180 p->opcode, infoLevel);
3181 smb_SendTran2Error(vcp, p, opx,
3182 infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3186 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3188 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
3189 osi_LogSaveClientString(smb_logp, pathp));
3191 userp = smb_GetTran2User(vcp, p);
3193 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3194 code = CM_ERROR_BADSMB;
3198 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3199 if (code == CM_ERROR_TIDIPC) {
3200 /* Attempt to use a TID allocated for IPC. The client
3201 * is probably looking for DCE RPC end points which we
3202 * don't support OR it could be looking to make a DFS
3205 osi_Log0(smb_logp, "Tran2Open received IPC TID");
3206 cm_ReleaseUser(userp);
3207 return CM_ERROR_NOSUCHPATH;
3211 * XXX Strange hack XXX
3213 * As of Patch 7 (13 January 98), we are having the following problem:
3214 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3215 * requests to look up "desktop.ini" in all the subdirectories.
3216 * This can cause zillions of timeouts looking up non-existent cells
3217 * and volumes, especially in the top-level directory.
3219 * We have not found any way to avoid this or work around it except
3220 * to explicitly ignore the requests for mount points that haven't
3221 * yet been evaluated and for directories that haven't yet been
3224 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3225 spacep = cm_GetSpace();
3226 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3227 #ifndef SPECIAL_FOLDERS
3228 /* Make sure that lastComp is not NULL */
3230 if (cm_ClientStrCmpI(lastComp, _C("\\desktop.ini")) == 0) {
3231 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3235 userp, tidPathp, &req, &dscp);
3238 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3239 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3241 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3242 code = CM_ERROR_PATH_NOT_COVERED;
3244 code = CM_ERROR_BADSHARENAME;
3246 #endif /* DFS_SUPPORT */
3247 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3248 code = CM_ERROR_NOSUCHFILE;
3249 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3250 cm_buf_t *bp = buf_Find(dscp, &hzero);
3256 code = CM_ERROR_NOSUCHFILE;
3258 cm_ReleaseSCache(dscp);
3260 cm_FreeSpace(spacep);
3261 cm_ReleaseUser(userp);
3262 smb_SendTran2Error(vcp, p, opx, code);
3268 #endif /* SPECIAL_FOLDERS */
3270 cm_FreeSpace(spacep);
3273 /* now do namei and stat, and copy out the info */
3274 code = cm_NameI(cm_data.rootSCachep, pathp,
3275 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3277 cm_ReleaseUser(userp);
3278 smb_SendTran2Error(vcp, p, opx, code);
3282 fidp = smb_FindFIDByScache(vcp, scp);
3284 cm_ReleaseSCache(scp);
3285 cm_ReleaseUser(userp);
3286 smb_SendTran2Error(vcp, p, opx, code);
3290 lock_ObtainMutex(&fidp->mx);
3291 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
3292 lock_ReleaseMutex(&fidp->mx);
3293 cm_ReleaseSCache(scp);
3294 smb_ReleaseFID(fidp);
3295 cm_ReleaseUser(userp);
3296 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3299 lock_ReleaseMutex(&fidp->mx);
3301 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3303 outp->totalParms = 2;
3304 outp->totalData = 0;
3306 spi = (smb_tran2QPathInfo_t *)p->datap;
3307 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3310 /* lock the vnode with a callback; we need the current status
3311 * to determine what the new status is, in some cases.
3313 lock_ObtainWrite(&scp->rw);
3314 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3315 CM_SCACHESYNC_GETSTATUS
3316 | CM_SCACHESYNC_NEEDCALLBACK);
3318 lock_ReleaseWrite(&scp->rw);
3321 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3323 lock_ReleaseWrite(&scp->rw);
3324 lock_ObtainMutex(&fidp->mx);
3325 lock_ObtainRead(&scp->rw);
3327 /* prepare for setattr call */
3328 attr.mask = CM_ATTRMASK_LENGTH;
3329 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3330 attr.length.HighPart = 0;
3332 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3333 smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3334 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3335 fidp->flags |= SMB_FID_MTIMESETDONE;
3338 if (spi->u.QPstandardInfo.attributes != 0) {
3339 if ((scp->unixModeBits & 0222)
3340 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3341 /* make a writable file read-only */
3342 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3343 attr.unixModeBits = scp->unixModeBits & ~0222;
3345 else if ((scp->unixModeBits & 0222) == 0
3346 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3347 /* make a read-only file writable */
3348 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3349 attr.unixModeBits = scp->unixModeBits | 0222;
3352 lock_ReleaseRead(&scp->rw);
3353 lock_ReleaseMutex(&fidp->mx);
3357 code = cm_SetAttr(scp, &attr, userp, &req);
3361 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3362 /* we don't support EAs */
3363 code = CM_ERROR_EAS_NOT_SUPPORTED;
3367 cm_ReleaseSCache(scp);
3368 cm_ReleaseUser(userp);
3369 smb_ReleaseFID(fidp);
3371 smb_SendTran2Packet(vcp, outp, opx);
3373 smb_SendTran2Error(vcp, p, opx, code);
3374 smb_FreeTran2Packet(outp);
3380 /* TRANS2_QUERY_FILE_INFORMATION */
3381 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3383 smb_tran2Packet_t *outp;
3385 unsigned long attributes;
3386 unsigned short infoLevel;
3393 smb_tran2QFileInfo_t qfi;
3401 fidp = smb_FindFID(vcp, fid, 0);
3404 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3408 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3409 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3410 smb_CloseFID(vcp, fidp, NULL, 0);
3411 smb_ReleaseFID(fidp);
3415 infoLevel = p->parmsp[1];
3416 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3417 responseSize = sizeof(qfi.u.QFbasicInfo);
3418 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3419 responseSize = sizeof(qfi.u.QFstandardInfo);
3420 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3421 responseSize = sizeof(qfi.u.QFeaInfo);
3422 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3423 responseSize = sizeof(qfi.u.QFfileNameInfo);
3425 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3426 p->opcode, infoLevel);
3427 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3428 smb_ReleaseFID(fidp);
3431 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3433 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3435 if (infoLevel > 0x100)
3436 outp->totalParms = 2;
3438 outp->totalParms = 0;
3439 outp->totalData = responseSize;
3441 userp = smb_GetTran2User(vcp, p);
3443 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3444 code = CM_ERROR_BADSMB;
3448 lock_ObtainMutex(&fidp->mx);
3449 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3451 osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3453 lock_ReleaseMutex(&fidp->mx);
3454 lock_ObtainWrite(&scp->rw);
3455 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3456 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3460 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3462 lock_ConvertWToR(&scp->rw);
3465 /* now we have the status in the cache entry, and everything is locked.
3466 * Marshall the output data.
3468 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3469 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3470 qfi.u.QFbasicInfo.creationTime = ft;
3471 qfi.u.QFbasicInfo.lastAccessTime = ft;
3472 qfi.u.QFbasicInfo.lastWriteTime = ft;
3473 qfi.u.QFbasicInfo.lastChangeTime = ft;
3474 attributes = smb_ExtAttributes(scp);
3475 qfi.u.QFbasicInfo.attributes = attributes;
3477 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3478 qfi.u.QFstandardInfo.allocationSize = scp->length;
3479 qfi.u.QFstandardInfo.endOfFile = scp->length;
3480 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3481 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3482 qfi.u.QFstandardInfo.directory =
3483 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3484 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3485 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3487 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3488 qfi.u.QFeaInfo.eaSize = 0;
3490 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3494 lock_ReleaseRead(&scp->rw);
3495 lock_ObtainMutex(&fidp->mx);
3496 lock_ObtainRead(&scp->rw);
3497 if (fidp->NTopen_wholepathp)
3498 name = fidp->NTopen_wholepathp;
3500 name = _C("\\"); /* probably can't happen */
3501 lock_ReleaseMutex(&fidp->mx);
3503 smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, SMB_STRF_IGNORENUL);
3504 outp->totalData = len + 4; /* this is actually what we want to return */
3505 qfi.u.QFfileNameInfo.fileNameLength = len;
3508 /* send and free the packets */
3511 lock_ReleaseRead(&scp->rw);
3513 lock_ReleaseWrite(&scp->rw);
3514 cm_ReleaseSCache(scp);
3515 cm_ReleaseUser(userp);
3516 smb_ReleaseFID(fidp);
3518 memcpy(outp->datap, &qfi, responseSize);
3519 smb_SendTran2Packet(vcp, outp, opx);
3521 smb_SendTran2Error(vcp, p, opx, code);
3523 smb_FreeTran2Packet(outp);
3529 /* TRANS2_SET_FILE_INFORMATION */
3530 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3535 unsigned short infoLevel;
3536 smb_tran2Packet_t *outp;
3537 cm_user_t *userp = NULL;
3538 cm_scache_t *scp = NULL;
3544 fidp = smb_FindFID(vcp, fid, 0);
3547 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3551 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3552 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3553 smb_CloseFID(vcp, fidp, NULL, 0);
3554 smb_ReleaseFID(fidp);
3558 infoLevel = p->parmsp[1];
3559 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3560 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3561 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3562 p->opcode, infoLevel);
3563 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3564 smb_ReleaseFID(fidp);
3568 lock_ObtainMutex(&fidp->mx);
3569 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
3570 !(fidp->flags & SMB_FID_OPENDELETE)) {
3571 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3572 fidp, fidp->scp, fidp->flags);
3573 lock_ReleaseMutex(&fidp->mx);
3574 smb_ReleaseFID(fidp);
3575 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3578 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3579 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3580 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3581 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3582 fidp, fidp->scp, fidp->flags);
3583 lock_ReleaseMutex(&fidp->mx);
3584 smb_ReleaseFID(fidp);
3585 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3590 osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3592 lock_ReleaseMutex(&fidp->mx);
3594 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3596 outp->totalParms = 2;
3597 outp->totalData = 0;
3599 userp = smb_GetTran2User(vcp, p);
3601 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3602 code = CM_ERROR_BADSMB;
3606 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3608 unsigned int attribute;
3610 smb_tran2QFileInfo_t *sfi;
3612 sfi = (smb_tran2QFileInfo_t *)p->datap;
3614 /* lock the vnode with a callback; we need the current status
3615 * to determine what the new status is, in some cases.
3617 lock_ObtainWrite(&scp->rw);
3618 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3619 CM_SCACHESYNC_GETSTATUS
3620 | CM_SCACHESYNC_NEEDCALLBACK);
3622 lock_ReleaseWrite(&scp->rw);
3626 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3628 lock_ReleaseWrite(&scp->rw);
3629 lock_ObtainMutex(&fidp->mx);
3630 lock_ObtainRead(&scp->rw);
3632 /* prepare for setattr call */
3635 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3636 /* when called as result of move a b, lastMod is (-1, -1).
3637 * If the check for -1 is not present, timestamp
3638 * of the resulting file will be 1969 (-1)
3640 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3641 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3642 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3643 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3644 fidp->flags |= SMB_FID_MTIMESETDONE;
3647 attribute = sfi->u.QFbasicInfo.attributes;
3648 if (attribute != 0) {
3649 if ((scp->unixModeBits & 0222)
3650 && (attribute & SMB_ATTR_READONLY) != 0) {
3651 /* make a writable file read-only */
3652 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3653 attr.unixModeBits = scp->unixModeBits & ~0222;
3655 else if ((scp->unixModeBits & 0222) == 0
3656 && (attribute & SMB_ATTR_READONLY) == 0) {
3657 /* make a read-only file writable */
3658 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3659 attr.unixModeBits = scp->unixModeBits | 0222;
3662 lock_ReleaseRead(&scp->rw);
3663 lock_ReleaseMutex(&fidp->mx);
3667 code = cm_SetAttr(scp, &attr, userp, &req);
3671 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3672 int delflag = *((char *)(p->datap));
3673 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
3674 delflag, fidp, scp);
3675 if (*((char *)(p->datap))) { /* File is Deleted */
3676 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3679 lock_ObtainMutex(&fidp->mx);
3680 fidp->flags |= SMB_FID_DELONCLOSE;
3681 lock_ReleaseMutex(&fidp->mx);
3683 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
3689 lock_ObtainMutex(&fidp->mx);
3690 fidp->flags &= ~SMB_FID_DELONCLOSE;
3691 lock_ReleaseMutex(&fidp->mx);
3694 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3695 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3696 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3699 attr.mask = CM_ATTRMASK_LENGTH;
3700 attr.length.LowPart = size.LowPart;
3701 attr.length.HighPart = size.HighPart;
3702 code = cm_SetAttr(scp, &attr, userp, &req);
3706 cm_ReleaseSCache(scp);
3707 cm_ReleaseUser(userp);
3708 smb_ReleaseFID(fidp);
3710 smb_SendTran2Packet(vcp, outp, opx);
3712 smb_SendTran2Error(vcp, p, opx, code);
3713 smb_FreeTran2Packet(outp);
3720 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3722 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3723 return CM_ERROR_BADOP;
3728 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3730 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3731 return CM_ERROR_BADOP;
3734 /* TRANS2_FIND_NOTIFY_FIRST */
3736 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3738 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3739 return CM_ERROR_BADOP;
3742 /* TRANS2_FIND_NOTIFY_NEXT */
3744 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3746 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3747 return CM_ERROR_BADOP;
3750 /* TRANS2_CREATE_DIRECTORY */
3752 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3754 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3755 return CM_ERROR_BADOP;
3758 /* TRANS2_SESSION_SETUP */
3760 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3762 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3763 return CM_ERROR_BADOP;
3766 struct smb_v2_referral {
3768 USHORT ReferralFlags;
3771 USHORT DfsPathOffset;
3772 USHORT DfsAlternativePathOffset;
3773 USHORT NetworkAddressOffset;
3776 /* TRANS2_GET_DFS_REFERRAL */
3778 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3780 /* This is a UNICODE only request (bit15 of Flags2) */
3781 /* The TID must be IPC$ */
3783 /* The documentation for the Flags response field is contradictory */
3785 /* Use Version 1 Referral Element Format */
3786 /* ServerType = 0; indicates the next server should be queried for the file */
3787 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3788 /* Node = UnicodeString of UNC path of the next share name */
3791 int maxReferralLevel = 0;
3792 clientchar_t requestFileName[1024] = _C("");
3793 clientchar_t referralPath[1024] = _C("");
3794 smb_tran2Packet_t *outp = 0;
3795 cm_user_t *userp = 0;
3796 cm_scache_t *scp = 0;
3797 cm_scache_t *dscp = 0;
3799 CPINFO CodePageInfo;
3800 int i, nbnLen, reqLen, refLen;
3805 maxReferralLevel = p->parmsp[0];
3807 GetCPInfo(CP_ACP, &CodePageInfo);
3808 cm_Utf16ToClientString(&p->parmsp[1], -1, requestFileName, lengthof(requestFileName));
3810 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%S]",
3811 maxReferralLevel, osi_LogSaveClientString(smb_logp, requestFileName));
3813 nbnLen = (int)cm_ClientStrLen(cm_NetbiosNameC);
3814 reqLen = (int)cm_ClientStrLen(requestFileName);
3816 if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
3817 !cm_ClientStrCmpNI(cm_NetbiosNameC, &requestFileName[1], nbnLen) &&
3818 requestFileName[nbnLen+1] == '\\')
3822 if (!cm_ClientStrCmpNI(_C("all"), &requestFileName[nbnLen+2], 3) ||
3823 !cm_ClientStrCmpNI(_C("*."), &requestFileName[nbnLen+2], 2)) {
3825 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
3828 userp = smb_GetTran2User(vcp, p);
3830 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3831 code = CM_ERROR_BADSMB;
3836 * We have a requested path. Check to see if it is something
3839 * But be careful because the name that we might be searching
3840 * for might be a known name with the final character stripped
3843 code = cm_NameI(cm_data.rootSCachep, &requestFileName[nbnLen+2],
3844 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
3845 userp, NULL, &req, &scp);
3849 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
3851 } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
3852 clientchar_t temp[1024];
3853 clientchar_t pathName[1024];
3854 clientchar_t *lastComponent;
3856 * we have a msdfs link somewhere in the path
3857 * we should figure out where in the path the link is.
3860 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%S]", requestFileName);
3862 cm_ClientStrCpy(temp, lengthof(temp), &requestFileName[nbnLen+2]);
3866 cm_ReleaseSCache(dscp);
3870 cm_ReleaseSCache(scp);
3873 smb_StripLastComponent(pathName, &lastComponent, temp);
3875 code = cm_NameI(cm_data.rootSCachep, pathName,
3876 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3877 userp, NULL, &req, &dscp);
3879 code = cm_NameI(dscp, ++lastComponent,
3881 userp, NULL, &req, &scp);
3882 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK)
3885 } while (code == CM_ERROR_PATH_NOT_COVERED);
3887 /* scp should now be the DfsLink we are looking for */
3889 /* figure out how much of the input path was used */
3890 reqLen = (int)(nbnLen+2 + cm_ClientStrLen(pathName) + 1 + cm_ClientStrLen(lastComponent));
3892 cm_FsStringToClientString(&scp->mountPointStringp[strlen("msdfs:")], -1,
3893 referralPath, lengthof(referralPath));
3894 refLen = (int)cm_ClientStrLen(referralPath);
3898 clientchar_t shareName[MAX_PATH + 1];
3899 clientchar_t *p, *q;
3900 /* we may have a sharename that is a volume reference */
3902 for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
3908 if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
3909 code = cm_NameI(cm_data.rootSCachep, _C(""),
3910 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
3911 userp, p, &req, &scp);
3916 cm_ClientStrCpy(referralPath, lengthof(referralPath),
3927 struct smb_v2_referral * v2ref;
3928 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (refLen + 8));
3930 sp = (USHORT *)outp->datap;
3932 sp[idx++] = reqLen; /* path consumed */
3933 sp[idx++] = 1; /* number of referrals */
3934 sp[idx++] = 0x03; /* flags */
3935 #ifdef DFS_VERSION_1
3936 sp[idx++] = 1; /* Version Number */
3937 sp[idx++] = refLen + 4; /* Referral Size */
3938 sp[idx++] = 1; /* Type = SMB Server */
3939 sp[idx++] = 0; /* Do not strip path consumed */
3940 for ( i=0;i<=refLen; i++ )
3941 sp[i+idx] = referralPath[i];
3942 #else /* DFS_VERSION_2 */
3943 sp[idx++] = 2; /* Version Number */
3944 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3945 idx += (sizeof(struct smb_v2_referral) / 2);
3946 v2ref = (struct smb_v2_referral *) &sp[5];
3947 v2ref->ServerType = 1; /* SMB Server */
3948 v2ref->ReferralFlags = 0x03;
3949 v2ref->Proximity = 0; /* closest */
3950 v2ref->TimeToLive = 3600; /* seconds */
3951 v2ref->DfsPathOffset = idx * 2;
3952 v2ref->DfsAlternativePathOffset = idx * 2;
3953 v2ref->NetworkAddressOffset = 0;
3954 for ( i=0;i<=refLen; i++ )
3955 sp[i+idx] = referralPath[i];
3959 code = CM_ERROR_NOSUCHPATH;
3964 cm_ReleaseSCache(dscp);
3966 cm_ReleaseSCache(scp);
3968 cm_ReleaseUser(userp);
3970 smb_SendTran2Packet(vcp, outp, op);
3972 smb_SendTran2Error(vcp, p, op, code);
3974 smb_FreeTran2Packet(outp);
3977 #else /* DFS_SUPPORT */
3978 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3979 return CM_ERROR_NOSUCHDEVICE;
3980 #endif /* DFS_SUPPORT */
3983 /* TRANS2_REPORT_DFS_INCONSISTENCY */
3985 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3987 /* This is a UNICODE only request (bit15 of Flags2) */
3989 /* There is nothing we can do about this operation. The client is going to
3990 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3991 * Unfortunately, there is really nothing we can do about it other then log it
3992 * somewhere. Even then I don't think there is anything for us to do.
3993 * So let's return an error value.
3996 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3997 return CM_ERROR_BADOP;
4001 smb_ApplyV3DirListPatches(cm_scache_t *dscp, smb_dirListPatch_t **dirPatchespp,
4002 clientchar_t * tidPathp, clientchar_t * relPathp,
4003 int infoLevel, cm_user_t *userp, cm_req_t *reqp)
4007 cm_scache_t *targetScp; /* target if scp is a symlink */
4010 unsigned short attr;
4011 unsigned long lattr;
4012 smb_dirListPatch_t *patchp;
4013 smb_dirListPatch_t *npatchp;
4015 afs_int32 mustFake = 0;
4016 clientchar_t path[AFSPATHMAX];
4018 code = cm_FindACLCache(dscp, userp, &rights);
4020 lock_ObtainWrite(&dscp->rw);
4021 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4022 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4024 cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4025 lock_ReleaseWrite(&dscp->rw);
4026 if (code == CM_ERROR_NOACCESS) {
4034 if (!mustFake) { /* Bulk Stat */
4036 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4038 memset(bsp, 0, sizeof(cm_bulkStat_t));
4040 for (patchp = *dirPatchespp, count=0;
4042 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4043 cm_scache_t *tscp = NULL;
4046 code = cm_GetSCache(&patchp->fid, &tscp, userp, reqp);
4048 if (lock_TryWrite(&tscp->rw)) {
4049 /* we have an entry that we can look at */
4050 #ifdef AFS_FREELANCE_CLIENT
4051 if (dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID && dscp->fid.volume == AFS_FAKE_ROOT_VOL_ID) {
4052 code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
4053 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4055 cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4057 lock_ReleaseWrite(&tscp->rw);
4058 cm_ReleaseSCache(tscp);
4061 #endif /* AFS_FREELANCE_CLIENT */
4062 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4063 /* we have a callback on it. Don't bother
4064 * fetching this stat entry, since we're happy
4065 * with the info we have.
4067 lock_ReleaseWrite(&tscp->rw);
4068 cm_ReleaseSCache(tscp);
4071 lock_ReleaseWrite(&tscp->rw);
4073 cm_ReleaseSCache(tscp);
4077 bsp->fids[i].Volume = patchp->fid.volume;
4078 bsp->fids[i].Vnode = patchp->fid.vnode;
4079 bsp->fids[i].Unique = patchp->fid.unique;
4081 if (bsp->counter == AFSCBMAX) {
4082 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4083 memset(bsp, 0, sizeof(cm_bulkStat_t));
4087 if (bsp->counter > 0)
4088 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4093 for( patchp = *dirPatchespp;
4095 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4096 cm_ClientStrPrintfN(path, lengthof(path),_C("%s\\%S"),
4097 relPathp ? relPathp : _C(""), patchp->dep->name);
4098 reqp->relPathp = path;
4099 reqp->tidPathp = tidPathp;
4101 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4102 reqp->relPathp = reqp->tidPathp = NULL;
4106 lock_ObtainWrite(&scp->rw);
4107 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4108 lock_ReleaseWrite(&scp->rw);
4110 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4111 errors in the client. */
4112 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4113 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4115 /* 1969-12-31 23:59:59 +00 */
4116 ft.dwHighDateTime = 0x19DB200;
4117 ft.dwLowDateTime = 0x5BB78980;
4119 /* copy to Creation Time */
4120 fa->creationTime = ft;
4121 fa->lastAccessTime = ft;
4122 fa->lastWriteTime = ft;
4123 fa->lastChangeTime = ft;
4125 switch (scp->fileType) {
4126 case CM_SCACHETYPE_DIRECTORY:
4127 case CM_SCACHETYPE_MOUNTPOINT:
4128 case CM_SCACHETYPE_SYMLINK:
4129 case CM_SCACHETYPE_INVALID:
4130 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4133 /* if we get here we either have a normal file
4134 * or we have a file for which we have never
4135 * received status info. In this case, we can
4136 * check the even/odd value of the entry's vnode.
4137 * even means it is to be treated as a directory
4138 * and odd means it is to be treated as a file.
4140 if (mustFake && (scp->fid.vnode & 0x1))
4141 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4143 fa->extFileAttributes = SMB_ATTR_NORMAL;
4145 /* merge in hidden attribute */
4146 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4147 fa->extFileAttributes |= SMB_ATTR_HIDDEN;
4150 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4152 /* 1969-12-31 23:59:58 +00*/
4153 dosTime = 0xEBBFBF7D;
4155 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4156 fa->lastAccessDateTime = fa->creationDateTime;
4157 fa->lastWriteDateTime = fa->creationDateTime;
4159 /* set the attribute */
4160 switch (scp->fileType) {
4161 case CM_SCACHETYPE_DIRECTORY:
4162 case CM_SCACHETYPE_MOUNTPOINT:
4163 case CM_SCACHETYPE_SYMLINK:
4164 case CM_SCACHETYPE_INVALID:
4165 fa->attributes = SMB_ATTR_DIRECTORY;
4168 /* if we get here we either have a normal file
4169 * or we have a file for which we have never
4170 * received status info. In this case, we can
4171 * check the even/odd value of the entry's vnode.
4172 * even means it is to be treated as a directory
4173 * and odd means it is to be treated as a file.
4175 if (mustFake && (scp->fid.vnode & 0x1))
4176 fa->attributes = SMB_ATTR_DIRECTORY;
4178 fa->attributes = SMB_ATTR_NORMAL;
4181 /* merge in hidden (dot file) attribute */
4182 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4183 fa->attributes |= SMB_ATTR_HIDDEN;
4187 cm_ReleaseSCache(scp);
4191 /* now watch for a symlink */
4193 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
4194 lock_ReleaseWrite(&scp->rw);
4195 cm_ClientStrPrintfN(path, lengthof(path), _C("%s\\%S"),
4196 relPathp ? relPathp : _C(""), patchp->dep->name);
4197 reqp->relPathp = path;
4198 reqp->tidPathp = tidPathp;
4199 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
4200 reqp->relPathp = reqp->tidPathp = NULL;
4202 /* we have a more accurate file to use (the
4203 * target of the symbolic link). Otherwise,
4204 * we'll just use the symlink anyway.
4206 osi_Log2(smb_logp, "symlink vp %x to vp %x",
4208 cm_ReleaseSCache(scp);
4211 lock_ObtainWrite(&scp->rw);
4214 lock_ConvertWToR(&scp->rw);
4216 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4217 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4220 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4222 fa->creationTime = ft;
4223 fa->lastAccessTime = ft;
4224 fa->lastWriteTime = ft;
4225 fa->lastChangeTime = ft;
4227 /* Use length for both file length and alloc length */
4228 fa->endOfFile = scp->length;
4229 fa->allocationSize = scp->length;
4231 /* Copy attributes */
4232 lattr = smb_ExtAttributes(scp);
4233 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK ||
4234 code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4235 if (lattr == SMB_ATTR_NORMAL)
4236 lattr = SMB_ATTR_DIRECTORY;
4238 lattr |= SMB_ATTR_DIRECTORY;
4240 /* merge in hidden (dot file) attribute */
4241 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4242 if (lattr == SMB_ATTR_NORMAL)
4243 lattr = SMB_ATTR_HIDDEN;
4245 lattr |= SMB_ATTR_HIDDEN;
4248 fa->extFileAttributes = lattr;
4250 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4253 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4255 fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
4256 fa->lastAccessDateTime = fa->creationDateTime;
4257 fa->lastWriteDateTime = fa->creationDateTime;
4259 /* copy out file length and alloc length,
4260 * using the same for both
4262 fa->dataSize = scp->length.LowPart;
4263 fa->allocationSize = scp->length.LowPart;
4265 /* finally copy out attributes as short */
4266 attr = smb_Attributes(scp);
4267 /* merge in hidden (dot file) attribute */
4268 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4269 if (lattr == SMB_ATTR_NORMAL)
4270 lattr = SMB_ATTR_HIDDEN;
4272 lattr |= SMB_ATTR_HIDDEN;
4274 fa->attributes = attr;
4277 lock_ReleaseRead(&scp->rw);
4278 cm_ReleaseSCache(scp);
4281 /* now free the patches */
4282 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4283 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4287 /* and mark the list as empty */
4288 *dirPatchespp = NULL;
4294 /* smb_ReceiveTran2SearchDir implements both
4295 * Tran2_Find_First and Tran2_Find_Next
4297 #define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
4298 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
4299 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
4300 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
4301 #define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
4303 /* this is an optimized handler for T2SearchDir that handles the case
4304 where there are no wildcards in the search path. I.e. an
4305 application is using FindFirst(Ex) to get information about a
4306 single file or directory. It will attempt to do a single lookup.
4307 If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4308 the usual mechanism.
4310 This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4312 TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
4314 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4318 long code = 0, code2 = 0;
4319 clientchar_t *pathp = 0;
4321 smb_dirListPatch_t *dirListPatchesp;
4322 smb_dirListPatch_t *curPatchp;
4323 size_t orbytes; /* # of bytes in this output record */
4324 size_t ohbytes; /* # of bytes, except file name */
4325 size_t onbytes; /* # of bytes in name, incl. term. null */
4326 cm_scache_t *scp = NULL;
4327 cm_scache_t *targetscp = NULL;
4328 cm_user_t *userp = NULL;
4329 char *op; /* output data ptr */
4330 char *origOp; /* original value of op */
4331 cm_space_t *spacep; /* for pathname buffer */
4332 unsigned long maxReturnData; /* max # of return data */
4333 long maxReturnParms; /* max # of return parms */
4334 long bytesInBuffer; /* # data bytes in the output buffer */
4335 clientchar_t *maskp; /* mask part of path */
4339 smb_tran2Packet_t *outp; /* response packet */
4340 clientchar_t *tidPathp = 0;
4342 clientchar_t shortName[13]; /* 8.3 name if needed */
4344 clientchar_t *shortNameEnd;
4345 cm_dirEntry_t * dep = NULL;
4348 void * attrp = NULL;
4349 smb_tran2Find_t * fp;
4354 osi_assertx(p->opcode == 1, "invalid opcode");
4356 /* find first; obtain basic parameters from request */
4358 /* note that since we are going to failover to regular
4359 * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4360 * modify any of the input parameters here. */
4361 attribute = p->parmsp[0];
4362 maxCount = p->parmsp[1];
4363 infoLevel = p->parmsp[3];
4364 searchFlags = p->parmsp[2];
4365 pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4367 maskp = cm_ClientStrRChr(pathp, '\\');
4371 maskp++; /* skip over backslash */
4372 /* track if this is likely to match a lot of entries */
4374 osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%S], mask[%S]",
4375 osi_LogSaveClientString(smb_logp, pathp),
4376 osi_LogSaveClientString(smb_logp, maskp));
4378 switch ( infoLevel ) {
4379 case SMB_INFO_STANDARD:
4381 ohbytes = sizeof(fp->u.FstandardInfo);
4384 case SMB_INFO_QUERY_EA_SIZE:
4385 ohbytes = sizeof(fp->u.FeaSizeInfo);
4386 s = "InfoQueryEaSize";
4389 case SMB_INFO_QUERY_EAS_FROM_LIST:
4390 ohbytes = sizeof(fp->u.FeasFromListInfo);
4391 s = "InfoQueryEasFromList";
4394 case SMB_FIND_FILE_DIRECTORY_INFO:
4395 s = "FindFileDirectoryInfo";
4396 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4399 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4400 s = "FindFileFullDirectoryInfo";
4401 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4404 case SMB_FIND_FILE_NAMES_INFO:
4405 s = "FindFileNamesInfo";
4406 ohbytes = sizeof(fp->u.FfileNamesInfo);
4409 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4410 s = "FindFileBothDirectoryInfo";
4411 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4415 s = "unknownInfoLevel";
4419 osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
4422 "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4423 attribute, infoLevel, maxCount, searchFlags);
4426 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4427 return CM_ERROR_INVAL;
4430 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4431 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4433 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4436 dirListPatchesp = NULL;
4438 maxReturnData = p->maxReturnData;
4439 maxReturnParms = 10; /* return params for findfirst, which
4440 is the only one we handle.*/
4442 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4445 osi_Log2(smb_logp, "T2SDSingle search dir count %d [%S]",
4446 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4448 /* bail out if request looks bad */
4450 smb_FreeTran2Packet(outp);
4451 return CM_ERROR_BADSMB;
4454 userp = smb_GetTran2User(vcp, p);
4456 osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
4457 smb_FreeTran2Packet(outp);
4458 return CM_ERROR_BADSMB;
4461 /* try to get the vnode for the path name next */
4462 spacep = cm_GetSpace();
4463 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4464 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4466 cm_ReleaseUser(userp);
4467 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4468 smb_FreeTran2Packet(outp);
4472 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4473 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4474 userp, tidPathp, &req, &scp);
4475 cm_FreeSpace(spacep);
4478 cm_ReleaseUser(userp);
4479 smb_SendTran2Error(vcp, p, opx, code);
4480 smb_FreeTran2Packet(outp);
4484 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4485 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4486 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
4487 cm_ReleaseSCache(scp);
4488 cm_ReleaseUser(userp);
4489 if ( WANTS_DFS_PATHNAMES(p) || pnc )
4490 code = CM_ERROR_PATH_NOT_COVERED;
4492 code = CM_ERROR_BADSHARENAME;
4493 smb_SendTran2Error(vcp, p, opx, code);
4494 smb_FreeTran2Packet(outp);
4497 #endif /* DFS_SUPPORT */
4498 osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
4500 /* now do a single case sensitive lookup for the file in question */
4501 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
4503 /* if a case sensitive match failed, we try a case insensitive one
4505 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
4506 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
4509 if (code == 0 && targetscp->fid.vnode == 0) {
4510 cm_ReleaseSCache(targetscp);
4511 code = CM_ERROR_NOSUCHFILE;
4515 /* if we can't find the directory entry, this block will
4516 return CM_ERROR_NOSUCHFILE, which we will pass on to
4517 smb_ReceiveTran2SearchDir(). */
4518 cm_ReleaseSCache(scp);
4519 cm_ReleaseUser(userp);
4520 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4521 smb_SendTran2Error(vcp, p, opx, code);
4524 smb_FreeTran2Packet(outp);
4528 /* now that we have the target in sight, we proceed with filling
4529 up the return data. */
4531 op = origOp = outp->datap;
4534 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4535 /* skip over resume key */
4539 fp = (smb_tran2Find_t *) op;
4541 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4542 && targetscp->fid.vnode != 0
4543 && !cm_Is8Dot3(maskp)) {
4546 dfid.vnode = htonl(targetscp->fid.vnode);
4547 dfid.unique = htonl(targetscp->fid.unique);
4549 cm_Gen8Dot3NameIntW(maskp, &dfid, shortName, &shortNameEnd);
4555 osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %S (%S)",
4556 htonl(targetscp->fid.vnode),
4557 htonl(targetscp->fid.unique),
4558 osi_LogSaveClientString(smb_logp, pathp),
4559 (NeedShortName)? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
4561 /* Eliminate entries that don't match requested attributes */
4562 if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
4563 smb_IsDotFile(maskp)) {
4565 code = CM_ERROR_NOSUCHFILE;
4566 osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
4571 if (!(attribute & SMB_ATTR_DIRECTORY) &&
4572 (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
4573 targetscp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4574 targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
4575 targetscp->fileType == CM_SCACHETYPE_INVALID)) {
4577 code = CM_ERROR_NOSUCHFILE;
4578 osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
4583 /* add header to name & term. null */
4585 smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
4586 orbytes = ohbytes + onbytes;
4588 /* now, we round up the record to a 4 byte alignment, and we make
4589 * sure that we have enough room here for even the aligned version
4590 * (so we don't have to worry about an * overflow when we pad
4591 * things out below). That's the reason for the alignment
4594 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4595 align = (4 - (orbytes & 3)) & 3;
4599 if (orbytes + align > maxReturnData) {
4601 /* even though this request is unlikely to succeed with a
4602 failover, we do it anyway. */
4603 code = CM_ERROR_NOSUCHFILE;
4604 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4609 /* this is one of the entries to use: it is not deleted and it
4610 * matches the star pattern we're looking for. Put out the name,
4611 * preceded by its length.
4613 /* First zero everything else */
4614 memset(origOp, 0, orbytes);
4617 smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
4619 switch (infoLevel) {
4620 case SMB_INFO_STANDARD:
4621 fp->u.FstandardInfo.fileNameLength = onbytes;
4622 attrp = &fp->u.FstandardInfo.fileAttrs;
4625 case SMB_INFO_QUERY_EA_SIZE:
4626 fp->u.FeaSizeInfo.fileNameLength = onbytes;
4627 attrp = &fp->u.FeaSizeInfo.fileAttrs;
4628 fp->u.FeaSizeInfo.eaSize = 0;
4631 case SMB_INFO_QUERY_EAS_FROM_LIST:
4632 fp->u.FeasFromListInfo.fileNameLength = onbytes;
4633 attrp = &fp->u.FeasFromListInfo.fileAttrs;
4634 fp->u.FeasFromListInfo.eaSize = 0;
4637 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4638 if (NeedShortName) {
4642 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
4643 fp->u.FfileBothDirectoryInfo.shortName,
4644 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
4646 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
4648 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
4649 fp->u.FfileBothDirectoryInfo.reserved = 0;
4651 strcpy(fp->u.FfileBothDirectoryInfo.shortName,
4653 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
4658 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4659 fp->u.FfileFullDirectoryInfo.eaSize = 0;
4662 case SMB_FIND_FILE_DIRECTORY_INFO:
4663 fp->u.FfileDirectoryInfo.nextEntryOffset = 0;
4664 fp->u.FfileDirectoryInfo.fileIndex = 0;
4665 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
4666 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
4669 case SMB_FIND_FILE_NAMES_INFO:
4670 fp->u.FfileNamesInfo.nextEntryOffset = 0;
4671 fp->u.FfileNamesInfo.fileIndex = 0;
4672 fp->u.FfileNamesInfo.fileNameLength = onbytes;
4676 /* we shouldn't hit this case */
4677 osi_assertx(FALSE, "Unknown query type");
4680 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4681 osi_assert(attrp != NULL);
4683 curPatchp = malloc(sizeof(*curPatchp));
4684 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4686 curPatchp->dptr = attrp;
4688 if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
4689 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4691 curPatchp->flags = 0;
4694 cm_SetFid(&curPatchp->fid, targetscp->fid.cell, targetscp->fid.volume, targetscp->fid.vnode, targetscp->fid.unique);
4698 int namelen = cm_ClientStringToFsString(maskp, -1, NULL, 0);
4699 dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+namelen);
4700 cm_ClientStringToFsString(maskp, -1, dep->name, namelen);
4702 dep->fid.vnode = targetscp->fid.vnode;
4703 dep->fid.unique = targetscp->fid.unique;
4704 curPatchp->dep = dep;
4707 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4708 /* put out resume key */
4709 *((u_long *)origOp) = 0;
4712 /* Adjust byte ptr and count */
4713 origOp += orbytes; /* skip entire record */
4714 bytesInBuffer += orbytes;
4716 /* and pad the record out */
4717 while (--align >= 0) {
4722 /* apply the patches */
4723 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->wdata, infoLevel, userp, &req);
4725 outp->parmsp[0] = 0;
4726 outp->parmsp[1] = 1; /* number of names returned */
4727 outp->parmsp[2] = 1; /* end of search */
4728 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4729 outp->parmsp[4] = 0;
4731 outp->totalParms = 10; /* in bytes */
4733 outp->totalData = bytesInBuffer;
4735 osi_Log0(smb_logp, "T2SDSingle done.");
4737 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4739 smb_SendTran2Error(vcp, p, opx, code);
4741 smb_SendTran2Packet(vcp, outp, opx);
4746 smb_FreeTran2Packet(outp);
4750 cm_ReleaseSCache(scp);
4751 cm_ReleaseSCache(targetscp);
4752 cm_ReleaseUser(userp);
4758 /* TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2 */
4759 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4764 long code = 0, code2 = 0;
4765 clientchar_t *pathp;
4766 cm_dirEntry_t *dep = 0;
4768 smb_dirListPatch_t *dirListPatchesp = 0;
4769 smb_dirListPatch_t *curPatchp = 0;
4772 size_t orbytes; /* # of bytes in this output record */
4773 size_t ohbytes; /* # of bytes, except file name */
4774 size_t onbytes; /* # of bytes in name, incl. term. null */
4775 osi_hyper_t dirLength;
4776 osi_hyper_t bufferOffset;
4777 osi_hyper_t curOffset;
4779 smb_dirSearch_t *dsp;
4783 cm_pageHeader_t *pageHeaderp;
4784 cm_user_t *userp = NULL;
4787 long nextEntryCookie;
4788 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4789 char *op; /* output data ptr */
4790 char *origOp; /* original value of op */
4791 cm_space_t *spacep; /* for pathname buffer */
4792 unsigned long maxReturnData; /* max # of return data */
4793 unsigned long maxReturnParms; /* max # of return parms */
4794 long bytesInBuffer; /* # data bytes in the output buffer */
4796 clientchar_t *maskp; /* mask part of path */
4800 smb_tran2Packet_t *outp; /* response packet */
4801 clientchar_t *tidPathp;
4803 clientchar_t shortName[13]; /* 8.3 name if needed */
4806 clientchar_t *shortNameEnd;
4812 smb_tran2Find_t * fp;
4817 if (p->opcode == 1) {
4818 /* find first; obtain basic parameters from request */
4819 attribute = p->parmsp[0];
4820 maxCount = p->parmsp[1];
4821 infoLevel = p->parmsp[3];
4822 searchFlags = p->parmsp[2];
4823 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4825 maskp = cm_ClientStrRChr(pathp, '\\');
4829 maskp++; /* skip over backslash */
4831 /* track if this is likely to match a lot of entries */
4832 starPattern = smb_V3IsStarMask(maskp);
4834 #ifndef NOFINDFIRSTOPTIMIZE
4836 /* if this is for a single directory or file, we let the
4837 optimized routine handle it. The only error it
4838 returns is CM_ERROR_NOSUCHFILE. The */
4839 code = smb_T2SearchDirSingle(vcp, p, opx);
4841 /* we only failover if we see a CM_ERROR_NOSUCHFILE */
4842 if (code != CM_ERROR_NOSUCHFILE) {
4844 /* unless we are using the BPlusTree */
4845 if (code == CM_ERROR_BPLUS_NOMATCH)
4846 code = CM_ERROR_NOSUCHFILE;
4847 #endif /* USE_BPLUS */
4851 #endif /* NOFINDFIRSTOPTIMIZE */
4854 dsp = smb_NewDirSearch(1);
4855 dsp->attribute = attribute;
4856 cm_ClientStrCpy(dsp->mask, lengthof(dsp->mask), maskp); /* and save mask */
4859 osi_assertx(p->opcode == 2, "invalid opcode");
4860 /* find next; obtain basic parameters from request or open dir file */
4861 dsp = smb_FindDirSearch(p->parmsp[0]);
4862 maxCount = p->parmsp[1];
4863 infoLevel = p->parmsp[2];
4864 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4865 searchFlags = p->parmsp[5];
4867 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4868 p->parmsp[0], nextCookie);
4869 return CM_ERROR_BADFD;
4871 attribute = dsp->attribute;
4874 starPattern = 1; /* assume, since required a Find Next */
4877 switch ( infoLevel ) {
4878 case SMB_INFO_STANDARD:
4880 ohbytes = sizeof(fp->u.FstandardInfo);
4883 case SMB_INFO_QUERY_EA_SIZE:
4884 ohbytes = sizeof(fp->u.FeaSizeInfo);
4885 s = "InfoQueryEaSize";
4888 case SMB_INFO_QUERY_EAS_FROM_LIST:
4889 ohbytes = sizeof(fp->u.FeasFromListInfo);
4890 s = "InfoQueryEasFromList";
4893 case SMB_FIND_FILE_DIRECTORY_INFO:
4894 s = "FindFileDirectoryInfo";
4895 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4898 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4899 s = "FindFileFullDirectoryInfo";
4900 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4903 case SMB_FIND_FILE_NAMES_INFO:
4904 s = "FindFileNamesInfo";
4905 ohbytes = sizeof(fp->u.FfileNamesInfo);
4908 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4909 s = "FindFileBothDirectoryInfo";
4910 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4914 s = "unknownInfoLevel";
4918 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
4921 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4922 attribute, infoLevel, maxCount, searchFlags);
4924 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
4925 p->opcode, dsp->cookie, nextCookie);
4928 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4929 smb_ReleaseDirSearch(dsp);
4930 return CM_ERROR_INVAL;
4933 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4934 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4936 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4939 dirListPatchesp = NULL;
4941 maxReturnData = p->maxReturnData;
4942 if (p->opcode == 1) /* find first */
4943 maxReturnParms = 10; /* bytes */
4945 maxReturnParms = 8; /* bytes */
4947 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4953 osi_Log2(smb_logp, "T2 receive search dir count %d [%S]",
4954 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4956 /* bail out if request looks bad */
4957 if (p->opcode == 1 && !pathp) {
4958 smb_ReleaseDirSearch(dsp);
4959 smb_FreeTran2Packet(outp);
4960 return CM_ERROR_BADSMB;
4963 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
4964 dsp->cookie, nextCookie, attribute);
4966 userp = smb_GetTran2User(vcp, p);
4968 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
4969 smb_ReleaseDirSearch(dsp);
4970 smb_FreeTran2Packet(outp);
4971 return CM_ERROR_BADSMB;
4974 /* try to get the vnode for the path name next */
4975 lock_ObtainMutex(&dsp->mx);
4978 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4982 spacep = cm_GetSpace();
4983 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4984 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4986 cm_ReleaseUser(userp);
4987 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4988 smb_FreeTran2Packet(outp);
4989 lock_ReleaseMutex(&dsp->mx);
4990 smb_DeleteDirSearch(dsp);
4991 smb_ReleaseDirSearch(dsp);
4995 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4996 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4998 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4999 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5000 userp, tidPathp, &req, &scp);
5001 cm_FreeSpace(spacep);
5004 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
5005 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5006 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
5007 cm_ReleaseSCache(scp);
5008 cm_ReleaseUser(userp);
5009 if ( WANTS_DFS_PATHNAMES(p) || pnc )
5010 code = CM_ERROR_PATH_NOT_COVERED;
5012 code = CM_ERROR_BADSHARENAME;
5013 smb_SendTran2Error(vcp, p, opx, code);
5014 smb_FreeTran2Packet(outp);
5015 lock_ReleaseMutex(&dsp->mx);
5016 smb_DeleteDirSearch(dsp);
5017 smb_ReleaseDirSearch(dsp);
5020 #endif /* DFS_SUPPORT */
5022 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5023 /* we need one hold for the entry we just stored into,
5024 * and one for our own processing. When we're done
5025 * with this function, we'll drop the one for our own
5026 * processing. We held it once from the namei call,
5027 * and so we do another hold now.
5030 dsp->flags |= SMB_DIRSEARCH_BULKST;
5033 lock_ReleaseMutex(&dsp->mx);
5035 cm_ReleaseUser(userp);
5036 smb_FreeTran2Packet(outp);
5037 smb_DeleteDirSearch(dsp);
5038 smb_ReleaseDirSearch(dsp);
5042 /* get the directory size */
5043 lock_ObtainWrite(&scp->rw);
5044 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5045 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5047 lock_ReleaseWrite(&scp->rw);
5048 cm_ReleaseSCache(scp);
5049 cm_ReleaseUser(userp);
5050 smb_FreeTran2Packet(outp);
5051 smb_DeleteDirSearch(dsp);
5052 smb_ReleaseDirSearch(dsp);
5056 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5059 dirLength = scp->length;
5061 bufferOffset.LowPart = bufferOffset.HighPart = 0;
5062 curOffset.HighPart = 0;
5063 curOffset.LowPart = nextCookie;
5064 origOp = outp->datap;
5071 normchar_t normName[MAX_PATH]; /* Normalized name */
5072 clientchar_t cfileName[MAX_PATH]; /* Non-normalized name */
5075 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5076 /* skip over resume key */
5079 fp = (smb_tran2Find_t *) op;
5081 /* make sure that curOffset.LowPart doesn't point to the first
5082 * 32 bytes in the 2nd through last dir page, and that it doesn't
5083 * point at the first 13 32-byte chunks in the first dir page,
5084 * since those are dir and page headers, and don't contain useful
5087 temp = curOffset.LowPart & (2048-1);
5088 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5089 /* we're in the first page */
5090 if (temp < 13*32) temp = 13*32;
5093 /* we're in a later dir page */
5094 if (temp < 32) temp = 32;
5097 /* make sure the low order 5 bits are zero */
5100 /* now put temp bits back ito curOffset.LowPart */
5101 curOffset.LowPart &= ~(2048-1);
5102 curOffset.LowPart |= temp;
5104 /* check if we've passed the dir's EOF */
5105 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
5106 osi_Log0(smb_logp, "T2 search dir passed eof");
5111 /* check if we've returned all the names that will fit in the
5112 * response packet; we check return count as well as the number
5113 * of bytes requested. We check the # of bytes after we find
5114 * the dir entry, since we'll need to check its size.
5116 if (returnedNames >= maxCount) {
5117 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
5118 returnedNames, maxCount);
5122 /* when we have obtained as many entries as can be processed in
5123 * a single Bulk Status call to the file server, apply the dir listing
5126 if (returnedNames > 0 && returnedNames % AFSCBMAX == 0) {
5127 lock_ReleaseWrite(&scp->rw);
5128 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5129 dsp->relPath, infoLevel, userp, &req);
5130 lock_ObtainWrite(&scp->rw);
5132 /* Then check to see if we have time left to process more entries */
5133 if (GetTickCount() - req.startTime > (RDRtimeout - 15) * 1000) {
5134 osi_Log0(smb_logp, "T2 search dir RDRtimeout exceeded");
5138 /* see if we can use the bufferp we have now; compute in which
5139 * page the current offset would be, and check whether that's
5140 * the offset of the buffer we have. If not, get the buffer.
5142 thyper.HighPart = curOffset.HighPart;
5143 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5144 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5147 buf_Release(bufferp);
5150 lock_ReleaseWrite(&scp->rw);
5151 code = buf_Get(scp, &thyper, &bufferp);
5152 lock_ObtainWrite(&scp->rw);
5154 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
5158 bufferOffset = thyper;
5160 /* now get the data in the cache */
5162 code = cm_SyncOp(scp, bufferp, userp, &req,
5164 CM_SCACHESYNC_NEEDCALLBACK
5165 | CM_SCACHESYNC_READ);
5167 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5171 if (cm_HaveBuffer(scp, bufferp, 0)) {
5172 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5173 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5177 /* otherwise, load the buffer and try again */
5178 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5180 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5182 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5183 scp, bufferp, code);
5188 buf_Release(bufferp);
5192 } /* if (wrong buffer) ... */
5194 /* now we have the buffer containing the entry we're interested
5195 * in; copy it out if it represents a non-deleted entry.
5197 entryInDir = curOffset.LowPart & (2048-1);
5198 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5200 /* page header will help tell us which entries are free. Page
5201 * header can change more often than once per buffer, since
5202 * AFS 3 dir page size may be less than (but not more than)
5203 * a buffer package buffer.
5205 /* only look intra-buffer */
5206 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5207 temp &= ~(2048 - 1); /* turn off intra-page bits */
5208 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5210 /* now determine which entry we're looking at in the page.
5211 * If it is free (there's a free bitmap at the start of the
5212 * dir), we should skip these 32 bytes.
5214 slotInPage = (entryInDir & 0x7e0) >> 5;
5215 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5216 (1 << (slotInPage & 0x7)))) {
5217 /* this entry is free */
5218 numDirChunks = 1; /* only skip this guy */
5222 tp = bufferp->datap + entryInBuffer;
5223 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5225 /* while we're here, compute the next entry's location, too,
5226 * since we'll need it when writing out the cookie into the dir
5229 * XXXX Probably should do more sanity checking.
5231 numDirChunks = cm_NameEntries(dep->name, &onbytes);
5233 /* compute offset of cookie representing next entry */
5234 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5236 if (dep->fid.vnode == 0)
5237 goto nextEntry; /* This entry is not in use */
5239 cm_FsStringToClientString(dep->name, -1, cfileName, lengthof(cfileName));
5240 cm_ClientStringToNormString(cfileName, -1, normName, lengthof(normName));
5242 /* Need 8.3 name? */
5244 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
5245 !cm_Is8Dot3(cfileName)) {
5246 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5250 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %S (%S)",
5251 dep->fid.vnode, dep->fid.unique,
5252 osi_LogSaveClientString(smb_logp, cfileName),
5253 NeedShortName ? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
5255 /* When matching, we are using doing a case fold if we have a wildcard mask.
5256 * If we get a non-wildcard match, it's a lookup for a specific file.
5258 if (cm_MatchMask(normName, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5259 (NeedShortName && cm_MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))
5261 /* Eliminate entries that don't match requested attributes */
5262 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5263 smb_IsDotFile(cfileName)) {
5264 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5265 goto nextEntry; /* no hidden files */
5268 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5270 /* We have already done the cm_TryBulkStat above */
5271 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume,
5272 ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5273 fileType = cm_FindFileType(&fid);
5274 /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5275 * "has filetype %d", dep->name, fileType);
5277 if ( fileType == CM_SCACHETYPE_DIRECTORY ||
5278 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5279 fileType == CM_SCACHETYPE_DFSLINK ||
5280 fileType == CM_SCACHETYPE_INVALID)
5281 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5285 /* finally check if this name will fit */
5287 smb_UnparseString(opx, NULL, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5288 orbytes = ohbytes + onbytes;
5290 /* now, we round up the record to a 4 byte alignment,
5291 * and we make sure that we have enough room here for
5292 * even the aligned version (so we don't have to worry
5293 * about an overflow when we pad things out below).
5294 * That's the reason for the alignment arithmetic below.
5296 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5297 align = (4 - (orbytes & 3)) & 3;
5301 if (orbytes + bytesInBuffer + align > maxReturnData) {
5302 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5307 /* this is one of the entries to use: it is not deleted
5308 * and it matches the star pattern we're looking for.
5309 * Put out the name, preceded by its length.
5311 /* First zero everything else */
5312 memset(origOp, 0, orbytes);
5315 smb_UnparseString(opx, origOp + ohbytes, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5317 switch (infoLevel) {
5318 case SMB_INFO_STANDARD:
5319 fp->u.FstandardInfo.fileNameLength = onbytes;
5320 attrp = &fp->u.FstandardInfo.fileAttrs;
5323 case SMB_INFO_QUERY_EA_SIZE:
5324 fp->u.FeaSizeInfo.fileNameLength = onbytes;
5325 attrp = &fp->u.FeaSizeInfo.fileAttrs;
5326 fp->u.FeaSizeInfo.eaSize = 0;
5329 case SMB_INFO_QUERY_EAS_FROM_LIST:
5330 fp->u.FeasFromListInfo.fileNameLength = onbytes;
5331 attrp = &fp->u.FeasFromListInfo.fileAttrs;
5332 fp->u.FeasFromListInfo.eaSize = 0;
5335 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5336 if (NeedShortName) {
5340 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
5341 fp->u.FfileBothDirectoryInfo.shortName,
5342 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
5344 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
5346 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5347 fp->u.FfileBothDirectoryInfo.reserved = 0;
5349 cm_ClientStrCpy(fp->u.FfileBothDirectoryInfo.shortName,
5350 lengthof(fp->u.FfileBothDirectoryInfo.shortName),
5352 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
5357 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5358 fp->u.FfileFullDirectoryInfo.eaSize = 0;
5361 case SMB_FIND_FILE_DIRECTORY_INFO:
5362 fp->u.FfileDirectoryInfo.nextEntryOffset = orbytes + align;
5363 fp->u.FfileDirectoryInfo.fileIndex = nextEntryCookie;
5364 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5365 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5368 case SMB_FIND_FILE_NAMES_INFO:
5369 fp->u.FfileNamesInfo.nextEntryOffset = orbytes + align;
5370 fp->u.FfileNamesInfo.fileIndex = nextEntryCookie;
5371 fp->u.FfileNamesInfo.fileNameLength = onbytes;
5376 /* we shouldn't hit this case */
5377 osi_assertx(FALSE, "Unknown query type");
5380 /* now, adjust the # of entries copied */
5383 /* now we emit the attribute. This is tricky, since
5384 * we need to really stat the file to find out what
5385 * type of entry we've got. Right now, we're copying
5386 * out data from a buffer, while holding the scp
5387 * locked, so it isn't really convenient to stat
5388 * something now. We'll put in a place holder
5389 * now, and make a second pass before returning this
5390 * to get the real attributes. So, we just skip the
5391 * data for now, and adjust it later. We allocate a
5392 * patch record to make it easy to find this point
5393 * later. The replay will happen at a time when it is
5394 * safe to unlock the directory.
5396 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5397 osi_assert(attrp != NULL);
5398 curPatchp = malloc(sizeof(*curPatchp));
5399 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5400 curPatchp->dptr = attrp;
5402 if (smb_hideDotFiles && smb_IsDotFile(cfileName)) {
5403 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5405 curPatchp->flags = 0;
5408 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5411 curPatchp->dep = dep;
5414 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5415 /* put out resume key */
5416 *((u_long *)origOp) = nextEntryCookie;
5418 /* Adjust byte ptr and count */
5419 origOp += orbytes; /* skip entire record */
5420 bytesInBuffer += orbytes;
5422 /* and pad the record out */
5423 while (align-- > 0) {
5427 } /* if we're including this name */
5428 else if (!starPattern &&
5430 cm_MatchMask(normName, maskp, CM_FLAG_CASEFOLD)) {
5431 /* We were looking for exact matches, but here's an inexact one*/
5436 /* and adjust curOffset to be where the new cookie is */
5437 thyper.HighPart = 0;
5438 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5439 curOffset = LargeIntegerAdd(thyper, curOffset);
5440 } /* while copying data for dir listing */
5442 /* If we didn't get a star pattern, we did an exact match during the first pass.
5443 * If there were no exact matches found, we fail over to inexact matches by
5444 * marking the query as a star pattern (matches all case permutations), and
5445 * re-running the query.
5447 if (returnedNames == 0 && !starPattern && foundInexact) {
5448 osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
5453 /* release the mutex */
5454 lock_ReleaseWrite(&scp->rw);
5456 buf_Release(bufferp);
5461 * Finally, process whatever entries we have left.
5463 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5464 dsp->relPath, infoLevel, userp, &req);
5466 /* now put out the final parameters */
5467 if (returnedNames == 0)
5469 if (p->opcode == 1) {
5471 outp->parmsp[0] = (unsigned short) dsp->cookie;
5472 outp->parmsp[1] = returnedNames;
5473 outp->parmsp[2] = eos;
5474 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5475 outp->parmsp[4] = 0;
5476 /* don't need last name to continue
5477 * search, cookie is enough. Normally,
5478 * this is the offset of the file name
5479 * of the last entry returned.
5481 outp->totalParms = 10; /* in bytes */
5485 outp->parmsp[0] = returnedNames;
5486 outp->parmsp[1] = eos;
5487 outp->parmsp[2] = 0; /* EAS error */
5488 outp->parmsp[3] = 0; /* last name, as above */
5489 outp->totalParms = 8; /* in bytes */
5492 /* return # of bytes in the buffer */
5493 outp->totalData = bytesInBuffer;
5495 /* Return error code if unsuccessful on first request */
5496 if (code == 0 && p->opcode == 1 && returnedNames == 0)
5497 code = CM_ERROR_NOSUCHFILE;
5499 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
5500 p->opcode, dsp->cookie, returnedNames, code);
5502 /* if we're supposed to close the search after this request, or if
5503 * we're supposed to close the search if we're done, and we're done,
5504 * or if something went wrong, close the search.
5506 if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
5507 (returnedNames == 0) ||
5508 ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
5510 smb_DeleteDirSearch(dsp);
5513 smb_SendTran2Error(vcp, p, opx, code);
5515 smb_SendTran2Packet(vcp, outp, opx);
5517 smb_FreeTran2Packet(outp);
5518 smb_ReleaseDirSearch(dsp);
5519 cm_ReleaseSCache(scp);
5520 cm_ReleaseUser(userp);
5524 /* SMB_COM_FIND_CLOSE2 */
5525 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5528 smb_dirSearch_t *dsp;
5530 dirHandle = smb_GetSMBParm(inp, 0);
5532 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
5534 dsp = smb_FindDirSearch(dirHandle);
5537 return CM_ERROR_BADFD;
5539 /* otherwise, we have an FD to destroy */
5540 smb_DeleteDirSearch(dsp);
5541 smb_ReleaseDirSearch(dsp);
5543 /* and return results */
5544 smb_SetSMBDataLength(outp, 0);
5550 /* SMB_COM_FIND_NOTIFY_CLOSE */
5551 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5553 smb_SetSMBDataLength(outp, 0);
5557 /* SMB_COM_OPEN_ANDX */
5558 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5560 clientchar_t *pathp;
5565 cm_scache_t *dscp; /* dir we're dealing with */
5566 cm_scache_t *scp; /* file we're creating */
5568 int initialModeBits;
5571 clientchar_t *lastNamep;
5572 unsigned long dosTime;
5578 int parmSlot; /* which parm we're dealing with */
5579 clientchar_t *tidPathp;
5587 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
5588 openFun = smb_GetSMBParm(inp, 8); /* open function */
5589 excl = ((openFun & 3) == 0);
5590 trunc = ((openFun & 3) == 2); /* truncate it */
5591 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
5592 openAction = 0; /* tracks what we did */
5594 attributes = smb_GetSMBParm(inp, 5);
5595 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
5597 /* compute initial mode bits based on read-only flag in attributes */
5598 initialModeBits = 0666;
5599 if (attributes & SMB_ATTR_READONLY)
5600 initialModeBits &= ~0222;
5602 pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
5605 spacep = inp->spacep;
5606 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5609 (cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
5610 cm_ClientStrCmpIA(lastNamep, _C("\\srvsvc")) == 0 ||
5611 cm_ClientStrCmpIA(lastNamep, _C("\\wkssvc")) == 0 ||
5612 cm_ClientStrCmpIA(lastNamep, _C("ipc$")) == 0)) {
5613 /* special case magic file name for receiving IOCTL requests
5614 * (since IOCTL calls themselves aren't getting through).
5617 osi_Log0(smb_logp, "IOCTL Open");
5620 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5621 smb_SetupIoctlFid(fidp, spacep);
5623 /* set inp->fid so that later read calls in same msg can find fid */
5624 inp->fid = fidp->fid;
5626 /* copy out remainder of the parms */
5628 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5630 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
5631 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
5632 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5633 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
5634 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
5635 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5636 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5637 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5639 /* and the final "always present" stuff */
5640 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
5641 /* next write out the "unique" ID */
5642 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
5643 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
5644 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5645 smb_SetSMBDataLength(outp, 0);
5647 /* and clean up fid reference */
5648 smb_ReleaseFID(fidp);
5652 #ifdef DEBUG_VERBOSE
5654 char *hexp, *asciip;
5655 asciip = (lastNamep ? lastNamep : pathp );
5656 hexp = osi_HexifyString(asciip);
5657 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
5661 userp = smb_GetUserFromVCP(vcp, inp);
5664 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5666 cm_ReleaseUser(userp);
5667 return CM_ERROR_NOSUCHPATH;
5669 code = cm_NameI(cm_data.rootSCachep, pathp,
5670 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5671 userp, tidPathp, &req, &scp);
5674 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5675 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5676 cm_ReleaseSCache(scp);
5677 cm_ReleaseUser(userp);
5678 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5679 return CM_ERROR_PATH_NOT_COVERED;
5681 return CM_ERROR_BADSHARENAME;
5683 #endif /* DFS_SUPPORT */
5686 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
5687 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5688 userp, tidPathp, &req, &dscp);
5690 cm_ReleaseUser(userp);
5695 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5696 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5698 cm_ReleaseSCache(dscp);
5699 cm_ReleaseUser(userp);
5700 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5701 return CM_ERROR_PATH_NOT_COVERED;
5703 return CM_ERROR_BADSHARENAME;
5705 #endif /* DFS_SUPPORT */
5706 /* otherwise, scp points to the parent directory. Do a lookup,
5707 * and truncate the file if we find it, otherwise we create the
5714 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
5716 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5717 cm_ReleaseSCache(dscp);
5718 cm_ReleaseUser(userp);
5723 /* if we get here, if code is 0, the file exists and is represented by
5724 * scp. Otherwise, we have to create it. The dir may be represented
5725 * by dscp, or we may have found the file directly. If code is non-zero,
5729 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
5731 if (dscp) cm_ReleaseSCache(dscp);
5732 cm_ReleaseSCache(scp);
5733 cm_ReleaseUser(userp);
5738 /* oops, file shouldn't be there */
5740 cm_ReleaseSCache(dscp);
5741 cm_ReleaseSCache(scp);
5742 cm_ReleaseUser(userp);
5743 return CM_ERROR_EXISTS;
5747 setAttr.mask = CM_ATTRMASK_LENGTH;
5748 setAttr.length.LowPart = 0;
5749 setAttr.length.HighPart = 0;
5750 code = cm_SetAttr(scp, &setAttr, userp, &req);
5751 openAction = 3; /* truncated existing file */
5753 else openAction = 1; /* found existing file */
5755 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
5756 /* don't create if not found */
5757 if (dscp) cm_ReleaseSCache(dscp);
5758 cm_ReleaseUser(userp);
5759 return CM_ERROR_NOSUCHFILE;
5762 osi_assertx(dscp != NULL, "null cm_scache_t");
5763 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %S",
5764 osi_LogSaveClientString(smb_logp, lastNamep));
5765 openAction = 2; /* created file */
5766 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5767 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5768 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5772 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5773 smb_NotifyChange(FILE_ACTION_ADDED,
5774 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5775 dscp, lastNamep, NULL, TRUE);
5776 } else if (!excl && code == CM_ERROR_EXISTS) {
5777 /* not an exclusive create, and someone else tried
5778 * creating it already, then we open it anyway. We
5779 * don't bother retrying after this, since if this next
5780 * fails, that means that the file was deleted after we
5781 * started this call.
5783 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5787 setAttr.mask = CM_ATTRMASK_LENGTH;
5788 setAttr.length.LowPart = 0;
5789 setAttr.length.HighPart = 0;
5790 code = cm_SetAttr(scp, &setAttr, userp, &req);
5792 } /* lookup succeeded */
5796 /* we don't need this any longer */
5798 cm_ReleaseSCache(dscp);
5801 /* something went wrong creating or truncating the file */
5803 cm_ReleaseSCache(scp);
5804 cm_ReleaseUser(userp);
5808 /* make sure we're about to open a file */
5809 if (scp->fileType != CM_SCACHETYPE_FILE) {
5810 cm_ReleaseSCache(scp);
5811 cm_ReleaseUser(userp);
5812 return CM_ERROR_ISDIR;
5815 /* now all we have to do is open the file itself */
5816 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5817 osi_assertx(fidp, "null smb_fid_t");
5820 lock_ObtainMutex(&fidp->mx);
5821 /* save a pointer to the vnode */
5823 lock_ObtainWrite(&scp->rw);
5824 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5825 lock_ReleaseWrite(&scp->rw);
5826 osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
5828 fidp->userp = userp;
5830 /* compute open mode */
5832 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5833 if (openMode == 1 || openMode == 2)
5834 fidp->flags |= SMB_FID_OPENWRITE;
5836 /* remember if the file was newly created */
5838 fidp->flags |= SMB_FID_CREATED;
5840 lock_ReleaseMutex(&fidp->mx);
5841 smb_ReleaseFID(fidp);
5843 cm_Open(scp, 0, userp);
5845 /* set inp->fid so that later read calls in same msg can find fid */
5846 inp->fid = fidp->fid;
5848 /* copy out remainder of the parms */
5850 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5851 lock_ObtainRead(&scp->rw);
5853 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5854 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5855 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5856 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5857 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5858 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5859 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5860 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5861 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5863 /* and the final "always present" stuff */
5864 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5865 /* next write out the "unique" ID */
5866 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5867 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5868 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5869 lock_ReleaseRead(&scp->rw);
5870 smb_SetSMBDataLength(outp, 0);
5872 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5874 cm_ReleaseUser(userp);
5875 /* leave scp held since we put it in fidp->scp */
5879 static void smb_GetLockParams(unsigned char LockType,
5881 unsigned int * ppid,
5882 LARGE_INTEGER * pOffset,
5883 LARGE_INTEGER * pLength)
5885 if (LockType & LOCKING_ANDX_LARGE_FILES) {
5887 *ppid = *((USHORT *) *buf);
5888 pOffset->HighPart = *((LONG *)(*buf + 4));
5889 pOffset->LowPart = *((DWORD *)(*buf + 8));
5890 pLength->HighPart = *((LONG *)(*buf + 12));
5891 pLength->LowPart = *((DWORD *)(*buf + 16));
5895 /* Not Large Files */
5896 *ppid = *((USHORT *) *buf);
5897 pOffset->HighPart = 0;
5898 pOffset->LowPart = *((DWORD *)(*buf + 2));
5899 pLength->HighPart = 0;
5900 pLength->LowPart = *((DWORD *)(*buf + 6));
5905 /* SMB_COM_LOCKING_ANDX */
5906 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5913 unsigned char LockType;
5914 unsigned short NumberOfUnlocks, NumberOfLocks;
5918 LARGE_INTEGER LOffset, LLength;
5919 smb_waitingLockRequest_t *wlRequest = NULL;
5920 cm_file_lock_t *lockp;
5928 fid = smb_GetSMBParm(inp, 2);
5929 fid = smb_ChainFID(fid, inp);
5931 fidp = smb_FindFID(vcp, fid, 0);
5933 return CM_ERROR_BADFD;
5935 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
5936 smb_CloseFID(vcp, fidp, NULL, 0);
5937 smb_ReleaseFID(fidp);
5938 return CM_ERROR_NOSUCHFILE;
5941 lock_ObtainMutex(&fidp->mx);
5942 if (fidp->flags & SMB_FID_IOCTL) {
5943 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
5944 lock_ReleaseMutex(&fidp->mx);
5945 smb_ReleaseFID(fidp);
5946 return CM_ERROR_BADFD;
5949 osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
5951 lock_ReleaseMutex(&fidp->mx);
5953 /* set inp->fid so that later read calls in same msg can find fid */
5956 userp = smb_GetUserFromVCP(vcp, inp);
5959 lock_ObtainWrite(&scp->rw);
5960 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5961 CM_SCACHESYNC_NEEDCALLBACK
5962 | CM_SCACHESYNC_GETSTATUS
5963 | CM_SCACHESYNC_LOCK);
5965 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
5969 LockType = smb_GetSMBParm(inp, 3) & 0xff;
5970 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
5971 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
5972 NumberOfLocks = smb_GetSMBParm(inp, 7);
5974 if (!(fidp->flags & SMB_FID_OPENWRITE) &&
5975 !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
5976 /* somebody wants exclusive locks on a file that they only
5977 opened for reading. We downgrade this to a shared lock. */
5978 osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
5979 LockType |= LOCKING_ANDX_SHARED_LOCK;
5982 if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
5983 /* AFS does not support atomic changes of lock types from read or write and vice-versa */
5984 osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]");
5985 code = CM_ERROR_BADOP;
5990 op = smb_GetSMBData(inp, NULL);
5992 if (LockType & LOCKING_ANDX_CANCEL_LOCK) {
5993 /* Cancel outstanding lock requests */
5994 smb_waitingLock_t * wl;
5996 for (i=0; i<NumberOfLocks; i++) {
5997 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5999 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6001 lock_ObtainWrite(&smb_globalLock);
6002 for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
6004 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
6005 if (wl->key == key && LargeIntegerEqualTo(wl->LOffset, LOffset) &&
6006 LargeIntegerEqualTo(wl->LLength, LLength)) {
6007 wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
6008 goto found_lock_request;
6013 lock_ReleaseWrite(&smb_globalLock);
6016 smb_SetSMBDataLength(outp, 0);
6021 for (i=0; i<NumberOfUnlocks; i++) {
6022 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6024 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6026 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
6034 for (i=0; i<NumberOfLocks; i++) {
6035 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6037 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6039 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
6040 userp, &req, &lockp);
6042 if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
6043 (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
6045 code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
6046 userp, &req, &lockp);
6049 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
6050 smb_waitingLock_t * wLock;
6052 /* Put on waiting list */
6053 if(wlRequest == NULL) {
6057 LARGE_INTEGER tOffset, tLength;
6059 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
6061 osi_assertx(wlRequest != NULL, "null wlRequest");
6063 wlRequest->vcp = vcp;
6065 wlRequest->scp = scp;
6066 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
6068 wlRequest->inp = smb_CopyPacket(inp);
6069 wlRequest->outp = smb_CopyPacket(outp);
6070 wlRequest->lockType = LockType;
6071 wlRequest->msTimeout = Timeout;
6072 wlRequest->start_t = osi_Time();
6073 wlRequest->locks = NULL;
6075 /* The waiting lock request needs to have enough
6076 information to undo all the locks in the request.
6077 We do the following to store info about locks that
6078 have already been granted. Sure, we can get most
6079 of the info from the packet, but the packet doesn't
6080 hold the result of cm_Lock call. In practice we
6081 only receive packets with one or two locks, so we
6082 are only wasting a few bytes here and there and
6083 only for a limited period of time until the waiting
6084 lock times out or is freed. */
6086 for(opt = op_locks, j=i; j > 0; j--) {
6087 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
6089 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6091 wLock = malloc(sizeof(smb_waitingLock_t));
6093 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6096 wLock->LOffset = tOffset;
6097 wLock->LLength = tLength;
6098 wLock->lockp = NULL;
6099 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
6100 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6105 wLock = malloc(sizeof(smb_waitingLock_t));
6107 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6110 wLock->LOffset = LOffset;
6111 wLock->LLength = LLength;
6112 wLock->lockp = lockp;
6113 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
6114 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6117 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
6125 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
6132 /* Since something went wrong with the lock number i, we now
6133 have to go ahead and release any locks acquired before the
6134 failure. All locks before lock number i (of which there
6135 are i of them) have either been successful or are waiting.
6136 Either case requires calling cm_Unlock(). */
6138 /* And purge the waiting lock */
6139 if(wlRequest != NULL) {
6140 smb_waitingLock_t * wl;
6141 smb_waitingLock_t * wlNext;
6144 for(wl = wlRequest->locks; wl; wl = wlNext) {
6146 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
6148 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
6151 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
6153 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
6156 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
6161 smb_ReleaseVC(wlRequest->vcp);
6162 cm_ReleaseSCache(wlRequest->scp);
6163 smb_FreePacket(wlRequest->inp);
6164 smb_FreePacket(wlRequest->outp);
6173 if (wlRequest != NULL) {
6175 lock_ObtainWrite(&smb_globalLock);
6176 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
6178 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
6179 lock_ReleaseWrite(&smb_globalLock);
6181 /* don't send reply immediately */
6182 outp->flags |= SMB_PACKETFLAG_NOSEND;
6185 smb_SetSMBDataLength(outp, 0);
6189 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
6192 lock_ReleaseWrite(&scp->rw);
6193 cm_ReleaseSCache(scp);
6194 cm_ReleaseUser(userp);
6195 smb_ReleaseFID(fidp);
6200 /* SMB_COM_QUERY_INFORMATION2 */
6201 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6207 afs_uint32 searchTime;
6214 fid = smb_GetSMBParm(inp, 0);
6215 fid = smb_ChainFID(fid, inp);
6217 fidp = smb_FindFID(vcp, fid, 0);
6219 return CM_ERROR_BADFD;
6221 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6222 smb_CloseFID(vcp, fidp, NULL, 0);
6223 smb_ReleaseFID(fidp);
6224 return CM_ERROR_NOSUCHFILE;
6227 lock_ObtainMutex(&fidp->mx);
6228 if (fidp->flags & SMB_FID_IOCTL) {
6229 lock_ReleaseMutex(&fidp->mx);
6230 smb_ReleaseFID(fidp);
6231 return CM_ERROR_BADFD;
6234 osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6236 lock_ReleaseMutex(&fidp->mx);
6238 userp = smb_GetUserFromVCP(vcp, inp);
6241 /* otherwise, stat the file */
6242 lock_ObtainWrite(&scp->rw);
6243 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6244 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6248 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6250 lock_ConvertWToR(&scp->rw);
6253 /* decode times. We need a search time, but the response to this
6254 * call provides the date first, not the time, as returned in the
6255 * searchTime variable. So we take the high-order bits first.
6257 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
6258 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
6259 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
6260 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
6261 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
6262 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
6263 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
6265 /* now handle file size and allocation size */
6266 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
6267 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
6268 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
6269 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
6271 /* file attribute */
6272 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
6274 /* and finalize stuff */
6275 smb_SetSMBDataLength(outp, 0);
6280 lock_ReleaseRead(&scp->rw);
6282 lock_ReleaseWrite(&scp->rw);
6283 cm_ReleaseSCache(scp);
6284 cm_ReleaseUser(userp);
6285 smb_ReleaseFID(fidp);
6289 /* SMB_COM_SET_INFORMATION2 */
6290 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6296 afs_uint32 searchTime;
6304 fid = smb_GetSMBParm(inp, 0);
6305 fid = smb_ChainFID(fid, inp);
6307 fidp = smb_FindFID(vcp, fid, 0);
6309 return CM_ERROR_BADFD;
6311 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6312 smb_CloseFID(vcp, fidp, NULL, 0);
6313 smb_ReleaseFID(fidp);
6314 return CM_ERROR_NOSUCHFILE;
6317 lock_ObtainMutex(&fidp->mx);
6318 if (fidp->flags & SMB_FID_IOCTL) {
6319 lock_ReleaseMutex(&fidp->mx);
6320 smb_ReleaseFID(fidp);
6321 return CM_ERROR_BADFD;
6324 osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6326 lock_ReleaseMutex(&fidp->mx);
6328 userp = smb_GetUserFromVCP(vcp, inp);
6331 /* now prepare to call cm_setattr. This message only sets various times,
6332 * and AFS only implements mtime, and we'll set the mtime if that's
6333 * requested. The others we'll ignore.
6335 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
6337 if (searchTime != 0) {
6338 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
6340 if ( unixTime != -1 ) {
6341 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
6342 attrs.clientModTime = unixTime;
6343 code = cm_SetAttr(scp, &attrs, userp, &req);
6345 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
6347 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
6353 cm_ReleaseSCache(scp);
6354 cm_ReleaseUser(userp);
6355 smb_ReleaseFID(fidp);
6359 /* SMB_COM_WRITE_ANDX */
6360 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6363 long count, written = 0, total_written = 0;
6367 smb_t *smbp = (smb_t*) inp;
6371 int inDataBlockCount;
6373 fd = smb_GetSMBParm(inp, 2);
6374 count = smb_GetSMBParm(inp, 10);
6376 offset.HighPart = 0;
6377 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6379 if (*inp->wctp == 14) {
6380 /* we have a request with 64-bit file offsets */
6381 #ifdef AFS_LARGEFILES
6382 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6384 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6386 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
6387 /* we shouldn't have received this op if we didn't specify
6388 largefile support */
6389 return CM_ERROR_BADOP;
6394 op = inp->data + smb_GetSMBParm(inp, 11);
6395 inDataBlockCount = count;
6397 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
6398 fd, offset.HighPart, offset.LowPart, count);
6400 fd = smb_ChainFID(fd, inp);
6401 fidp = smb_FindFID(vcp, fd, 0);
6403 return CM_ERROR_BADFD;
6405 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6406 smb_CloseFID(vcp, fidp, NULL, 0);
6407 smb_ReleaseFID(fidp);
6408 return CM_ERROR_NOSUCHFILE;
6411 lock_ObtainMutex(&fidp->mx);
6412 if (fidp->flags & SMB_FID_IOCTL) {
6413 lock_ReleaseMutex(&fidp->mx);
6414 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
6415 smb_ReleaseFID(fidp);
6418 lock_ReleaseMutex(&fidp->mx);
6419 userp = smb_GetUserFromVCP(vcp, inp);
6421 /* special case: 0 bytes transferred means there is no data
6422 transferred. A slight departure from SMB_COM_WRITE where this
6423 means that we are supposed to truncate the file at this
6428 LARGE_INTEGER LOffset;
6429 LARGE_INTEGER LLength;
6433 key = cm_GenerateKey(vcp->vcID, pid, fd);
6435 LOffset.HighPart = offset.HighPart;
6436 LOffset.LowPart = offset.LowPart;
6437 LLength.HighPart = 0;
6438 LLength.LowPart = count;
6441 lock_ObtainWrite(&scp->rw);
6442 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
6443 lock_ReleaseWrite(&scp->rw);
6450 * Work around bug in NT client
6452 * When copying a file, the NT client should first copy the data,
6453 * then copy the last write time. But sometimes the NT client does
6454 * these in the wrong order, so the data copies would inadvertently
6455 * cause the last write time to be overwritten. We try to detect this,
6456 * and don't set client mod time if we think that would go against the
6459 lock_ObtainMutex(&fidp->mx);
6460 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6461 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6462 fidp->scp->clientModTime = time(NULL);
6464 lock_ReleaseMutex(&fidp->mx);
6467 while ( code == 0 && count > 0 ) {
6468 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6469 if (code == 0 && written == 0)
6470 code = CM_ERROR_PARTIALWRITE;
6472 offset = LargeIntegerAdd(offset,
6473 ConvertLongToLargeInteger(written));
6475 total_written += written;
6479 /* slots 0 and 1 are reserved for request chaining and will be
6480 filled in when we return. */
6481 smb_SetSMBParm(outp, 2, total_written);
6482 smb_SetSMBParm(outp, 3, 0); /* reserved */
6483 smb_SetSMBParm(outp, 4, 0); /* reserved */
6484 smb_SetSMBParm(outp, 5, 0); /* reserved */
6485 smb_SetSMBDataLength(outp, 0);
6488 cm_ReleaseUser(userp);
6489 smb_ReleaseFID(fidp);
6494 /* SMB_COM_READ_ANDX */
6495 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6499 long finalCount = 0;
6503 smb_t *smbp = (smb_t*) inp;
6509 fd = smb_GetSMBParm(inp, 2);
6510 count = smb_GetSMBParm(inp, 5);
6511 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6513 if (*inp->wctp == 12) {
6514 /* a request with 64-bit offsets */
6515 #ifdef AFS_LARGEFILES
6516 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
6518 if (LargeIntegerLessThanZero(offset)) {
6519 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
6520 offset.HighPart, offset.LowPart);
6521 return CM_ERROR_BADSMB;
6524 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
6525 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
6526 return CM_ERROR_BADSMB;
6528 offset.HighPart = 0;
6532 offset.HighPart = 0;
6535 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
6536 fd, offset.HighPart, offset.LowPart, count);
6538 fd = smb_ChainFID(fd, inp);
6539 fidp = smb_FindFID(vcp, fd, 0);
6541 return CM_ERROR_BADFD;
6544 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6545 smb_CloseFID(vcp, fidp, NULL, 0);
6546 smb_ReleaseFID(fidp);
6547 return CM_ERROR_NOSUCHFILE;
6551 key = cm_GenerateKey(vcp->vcID, pid, fd);
6553 LARGE_INTEGER LOffset, LLength;
6556 LOffset.HighPart = offset.HighPart;
6557 LOffset.LowPart = offset.LowPart;
6558 LLength.HighPart = 0;
6559 LLength.LowPart = count;
6562 lock_ObtainWrite(&scp->rw);
6563 code = cm_LockCheckRead(scp, LOffset, LLength, key);
6564 lock_ReleaseWrite(&scp->rw);
6568 smb_ReleaseFID(fidp);
6572 /* set inp->fid so that later read calls in same msg can find fid */
6575 lock_ObtainMutex(&fidp->mx);
6576 if (fidp->flags & SMB_FID_IOCTL) {
6577 lock_ReleaseMutex(&fidp->mx);
6578 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
6579 smb_ReleaseFID(fidp);
6582 lock_ReleaseMutex(&fidp->mx);
6584 userp = smb_GetUserFromVCP(vcp, inp);
6586 /* 0 and 1 are reserved for request chaining, were setup by our caller,
6587 * and will be further filled in after we return.
6589 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
6590 smb_SetSMBParm(outp, 3, 0); /* resvd */
6591 smb_SetSMBParm(outp, 4, 0); /* resvd */
6592 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
6593 /* fill in #6 when we have all the parameters' space reserved */
6594 smb_SetSMBParm(outp, 7, 0); /* resv'd */
6595 smb_SetSMBParm(outp, 8, 0); /* resv'd */
6596 smb_SetSMBParm(outp, 9, 0); /* resv'd */
6597 smb_SetSMBParm(outp, 10, 0); /* resv'd */
6598 smb_SetSMBParm(outp, 11, 0); /* reserved */
6600 /* get op ptr after putting in the parms, since otherwise we don't
6601 * know where the data really is.
6603 op = smb_GetSMBData(outp, NULL);
6605 /* now fill in offset from start of SMB header to first data byte (to op) */
6606 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
6608 /* set the packet data length the count of the # of bytes */
6609 smb_SetSMBDataLength(outp, count);
6611 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6613 /* fix some things up */
6614 smb_SetSMBParm(outp, 5, finalCount);
6615 smb_SetSMBDataLength(outp, finalCount);
6617 cm_ReleaseUser(userp);
6618 smb_ReleaseFID(fidp);
6623 * Values for createDisp, copied from NTDDK.H
6625 #define FILE_SUPERSEDE 0 // (???)
6626 #define FILE_OPEN 1 // (open)
6627 #define FILE_CREATE 2 // (exclusive)
6628 #define FILE_OPEN_IF 3 // (non-exclusive)
6629 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
6630 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
6633 #define REQUEST_OPLOCK 2
6634 #define REQUEST_BATCH_OPLOCK 4
6635 #define OPEN_DIRECTORY 8
6636 #define EXTENDED_RESPONSE_REQUIRED 0x10
6638 /* CreateOptions field. */
6639 #define FILE_DIRECTORY_FILE 0x0001
6640 #define FILE_WRITE_THROUGH 0x0002
6641 #define FILE_SEQUENTIAL_ONLY 0x0004
6642 #define FILE_NON_DIRECTORY_FILE 0x0040
6643 #define FILE_NO_EA_KNOWLEDGE 0x0200
6644 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
6645 #define FILE_RANDOM_ACCESS 0x0800
6646 #define FILE_DELETE_ON_CLOSE 0x1000
6647 #define FILE_OPEN_BY_FILE_ID 0x2000
6649 /* SMB_COM_NT_CREATE_ANDX */
6650 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6652 clientchar_t *pathp, *realPathp;
6656 cm_scache_t *dscp; /* parent dir */
6657 cm_scache_t *scp; /* file to create or open */
6658 cm_scache_t *targetScp; /* if scp is a symlink */
6660 clientchar_t *lastNamep;
6661 clientchar_t *treeStartp;
6662 unsigned short nameLength;
6664 unsigned int requestOpLock;
6665 unsigned int requestBatchOpLock;
6666 unsigned int mustBeDir;
6667 unsigned int extendedRespRequired;
6668 unsigned int treeCreate;
6670 unsigned int desiredAccess;
6671 unsigned int extAttributes;
6672 unsigned int createDisp;
6673 unsigned int createOptions;
6674 unsigned int shareAccess;
6675 int initialModeBits;
6676 unsigned short baseFid;
6677 smb_fid_t *baseFidp;
6679 cm_scache_t *baseDirp;
6680 unsigned short openAction;
6685 clientchar_t *tidPathp;
6689 cm_lock_data_t *ldp = NULL;
6693 /* This code is very long and has a lot of if-then-else clauses
6694 * scp and dscp get reused frequently and we need to ensure that
6695 * we don't lose a reference. Start by ensuring that they are NULL.
6702 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
6703 flags = smb_GetSMBOffsetParm(inp, 3, 1)
6704 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
6705 requestOpLock = flags & REQUEST_OPLOCK;
6706 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6707 mustBeDir = flags & OPEN_DIRECTORY;
6708 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6711 * Why all of a sudden 32-bit FID?
6712 * We will reject all bits higher than 16.
6714 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
6715 return CM_ERROR_INVAL;
6716 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
6717 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
6718 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6719 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
6720 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
6721 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
6722 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
6723 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
6724 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
6725 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
6726 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
6728 /* mustBeDir is never set; createOptions directory bit seems to be
6731 if (createOptions & FILE_DIRECTORY_FILE)
6733 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6739 * compute initial mode bits based on read-only flag in
6740 * extended attributes
6742 initialModeBits = 0666;
6743 if (extAttributes & SMB_ATTR_READONLY)
6744 initialModeBits &= ~0222;
6746 pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
6747 NULL, SMB_STRF_ANSIPATH);
6749 /* Sometimes path is not null-terminated, so we make a copy. */
6750 realPathp = malloc(nameLength+sizeof(clientchar_t));
6751 memcpy(realPathp, pathp, nameLength+sizeof(clientchar_t));
6752 realPathp[nameLength/sizeof(clientchar_t)] = 0;
6754 spacep = inp->spacep;
6755 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
6757 osi_Log1(smb_logp,"NTCreateX for [%S]",osi_LogSaveClientString(smb_logp,realPathp));
6758 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
6759 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%S]", shareAccess, flags, osi_LogSaveClientString(smb_logp,(lastNamep?lastNamep:_C("null"))));
6762 (cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
6763 cm_ClientStrCmpIA(lastNamep, _C("\\srvsvc")) == 0 ||
6764 cm_ClientStrCmpIA(lastNamep, _C("\\wkssvc")) == 0 ||
6765 cm_ClientStrCmpIA(lastNamep, _C("ipc$")) == 0)) {
6766 /* special case magic file name for receiving IOCTL requests
6767 * (since IOCTL calls themselves aren't getting through).
6769 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6770 smb_SetupIoctlFid(fidp, spacep);
6771 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
6773 /* set inp->fid so that later read calls in same msg can find fid */
6774 inp->fid = fidp->fid;
6778 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6779 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6780 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
6782 memset(&ft, 0, sizeof(ft));
6783 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6784 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6785 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6786 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6787 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
6788 sz.HighPart = 0x7fff; sz.LowPart = 0;
6789 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
6790 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
6791 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6792 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6793 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
6794 smb_SetSMBDataLength(outp, 0);
6796 /* clean up fid reference */
6797 smb_ReleaseFID(fidp);
6802 #ifdef DEBUG_VERBOSE
6804 char *hexp, *asciip;
6805 asciip = (lastNamep? lastNamep : realPathp);
6806 hexp = osi_HexifyString( asciip );
6807 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
6812 userp = smb_GetUserFromVCP(vcp, inp);
6814 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
6816 return CM_ERROR_INVAL;
6821 baseDirp = cm_data.rootSCachep;
6822 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6823 if (code == CM_ERROR_TIDIPC) {
6824 /* Attempt to use a TID allocated for IPC. The client
6825 * is probably looking for DCE RPC end points which we
6826 * don't support OR it could be looking to make a DFS
6829 osi_Log0(smb_logp, "NTCreateX received IPC TID");
6832 cm_ReleaseUser(userp);
6833 return CM_ERROR_NOSUCHFILE;
6834 #endif /* DFS_SUPPORT */
6837 baseFidp = smb_FindFID(vcp, baseFid, 0);
6839 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
6841 cm_ReleaseUser(userp);
6842 return CM_ERROR_INVAL;
6845 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6847 cm_ReleaseUser(userp);
6848 smb_CloseFID(vcp, baseFidp, NULL, 0);
6849 smb_ReleaseFID(baseFidp);
6850 return CM_ERROR_NOSUCHPATH;
6853 baseDirp = baseFidp->scp;
6857 osi_Log1(smb_logp, "NTCreateX tidPathp=[%S]", (tidPathp==NULL)?_C("null"): osi_LogSaveClientString(smb_logp,tidPathp));
6859 /* compute open mode */
6861 if (desiredAccess & DELETE)
6862 fidflags |= SMB_FID_OPENDELETE;
6863 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
6864 fidflags |= SMB_FID_OPENREAD_LISTDIR;
6865 if (desiredAccess & AFS_ACCESS_WRITE)
6866 fidflags |= SMB_FID_OPENWRITE;
6867 if (createOptions & FILE_DELETE_ON_CLOSE)
6868 fidflags |= SMB_FID_DELONCLOSE;
6869 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6870 fidflags |= SMB_FID_SEQUENTIAL;
6871 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6872 fidflags |= SMB_FID_RANDOM;
6873 if (smb_IsExecutableFileName(lastNamep))
6874 fidflags |= SMB_FID_EXECUTABLE;
6876 /* and the share mode */
6877 if (shareAccess & FILE_SHARE_READ)
6878 fidflags |= SMB_FID_SHARE_READ;
6879 if (shareAccess & FILE_SHARE_WRITE)
6880 fidflags |= SMB_FID_SHARE_WRITE;
6882 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
6885 /* For an exclusive create, we want to do a case sensitive match for the last component. */
6886 if ( createDisp == FILE_CREATE ||
6887 createDisp == FILE_OVERWRITE ||
6888 createDisp == FILE_OVERWRITE_IF) {
6889 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6890 userp, tidPathp, &req, &dscp);
6893 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6894 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
6896 cm_ReleaseSCache(dscp);
6897 cm_ReleaseUser(userp);
6900 smb_ReleaseFID(baseFidp);
6901 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6902 return CM_ERROR_PATH_NOT_COVERED;
6904 return CM_ERROR_BADSHARENAME;
6906 #endif /* DFS_SUPPORT */
6907 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6909 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
6910 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6911 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6912 if (code == 0 && realDirFlag == 1) {
6913 cm_ReleaseSCache(scp);
6914 cm_ReleaseSCache(dscp);
6915 cm_ReleaseUser(userp);
6918 smb_ReleaseFID(baseFidp);
6919 return CM_ERROR_EXISTS;
6923 /* we have both scp and dscp */
6925 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6926 userp, tidPathp, &req, &scp);
6928 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6929 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
6930 cm_ReleaseSCache(scp);
6931 cm_ReleaseUser(userp);
6934 smb_ReleaseFID(baseFidp);
6935 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6936 return CM_ERROR_PATH_NOT_COVERED;
6938 return CM_ERROR_BADSHARENAME;
6940 #endif /* DFS_SUPPORT */
6941 /* we might have scp but not dscp */
6947 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6948 /* look up parent directory */
6949 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
6950 * the immediate parent. We have to work our way up realPathp until we hit something that we
6954 /* we might or might not have scp */
6960 code = cm_NameI(baseDirp, spacep->wdata,
6961 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6962 userp, tidPathp, &req, &dscp);
6965 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6966 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
6969 cm_ReleaseSCache(scp);
6970 cm_ReleaseSCache(dscp);
6971 cm_ReleaseUser(userp);
6974 smb_ReleaseFID(baseFidp);
6975 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6976 return CM_ERROR_PATH_NOT_COVERED;
6978 return CM_ERROR_BADSHARENAME;
6980 #endif /* DFS_SUPPORT */
6983 (tp = cm_ClientStrRChr(spacep->wdata, '\\')) &&
6984 (createDisp == FILE_CREATE) &&
6985 (realDirFlag == 1)) {
6988 treeStartp = realPathp + (tp - spacep->wdata);
6990 if (*tp && !smb_IsLegalFilename(tp)) {
6991 cm_ReleaseUser(userp);
6993 smb_ReleaseFID(baseFidp);
6996 cm_ReleaseSCache(scp);
6997 return CM_ERROR_BADNTFILENAME;
7001 } while (dscp == NULL && code == 0);
7005 /* we might have scp and we might have dscp */
7008 smb_ReleaseFID(baseFidp);
7011 osi_Log0(smb_logp,"NTCreateX parent not found");
7013 cm_ReleaseSCache(scp);
7015 cm_ReleaseSCache(dscp);
7016 cm_ReleaseUser(userp);
7021 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
7022 /* A file exists where we want a directory. */
7024 cm_ReleaseSCache(scp);
7025 cm_ReleaseSCache(dscp);
7026 cm_ReleaseUser(userp);
7028 return CM_ERROR_EXISTS;
7032 lastNamep = realPathp;
7036 if (!smb_IsLegalFilename(lastNamep)) {
7038 cm_ReleaseSCache(scp);
7040 cm_ReleaseSCache(dscp);
7041 cm_ReleaseUser(userp);
7043 return CM_ERROR_BADNTFILENAME;
7046 if (!foundscp && !treeCreate) {
7047 if ( createDisp == FILE_CREATE ||
7048 createDisp == FILE_OVERWRITE ||
7049 createDisp == FILE_OVERWRITE_IF)
7051 code = cm_Lookup(dscp, lastNamep,
7052 CM_FLAG_FOLLOW, userp, &req, &scp);
7054 code = cm_Lookup(dscp, lastNamep,
7055 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7058 if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
7060 cm_ReleaseSCache(dscp);
7061 cm_ReleaseUser(userp);
7066 /* we have scp and dscp */
7068 /* we have scp but not dscp */
7070 smb_ReleaseFID(baseFidp);
7073 /* if we get here, if code is 0, the file exists and is represented by
7074 * scp. Otherwise, we have to create it. The dir may be represented
7075 * by dscp, or we may have found the file directly. If code is non-zero,
7078 if (code == 0 && !treeCreate) {
7079 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7082 cm_ReleaseSCache(dscp);
7084 cm_ReleaseSCache(scp);
7085 cm_ReleaseUser(userp);
7090 if (createDisp == FILE_CREATE) {
7091 /* oops, file shouldn't be there */
7092 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7094 cm_ReleaseSCache(dscp);
7096 cm_ReleaseSCache(scp);
7097 cm_ReleaseUser(userp);
7099 return CM_ERROR_EXISTS;
7102 if ( createDisp == FILE_OVERWRITE ||
7103 createDisp == FILE_OVERWRITE_IF) {
7105 setAttr.mask = CM_ATTRMASK_LENGTH;
7106 setAttr.length.LowPart = 0;
7107 setAttr.length.HighPart = 0;
7108 /* now watch for a symlink */
7110 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7112 osi_assertx(dscp != NULL, "null cm_scache_t");
7113 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7115 /* we have a more accurate file to use (the
7116 * target of the symbolic link). Otherwise,
7117 * we'll just use the symlink anyway.
7119 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7121 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7122 cm_ReleaseSCache(scp);
7124 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7127 cm_ReleaseSCache(dscp);
7129 cm_ReleaseSCache(scp);
7130 cm_ReleaseUser(userp);
7136 code = cm_SetAttr(scp, &setAttr, userp, &req);
7137 openAction = 3; /* truncated existing file */
7140 openAction = 1; /* found existing file */
7142 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7143 /* don't create if not found */
7145 cm_ReleaseSCache(dscp);
7147 cm_ReleaseSCache(scp);
7148 cm_ReleaseUser(userp);
7150 return CM_ERROR_NOSUCHFILE;
7151 } else if (realDirFlag == 0 || realDirFlag == -1) {
7152 osi_assertx(dscp != NULL, "null cm_scache_t");
7153 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %S",
7154 osi_LogSaveClientString(smb_logp, lastNamep));
7155 openAction = 2; /* created file */
7156 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7157 setAttr.clientModTime = time(NULL);
7158 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
7161 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7162 smb_NotifyChange(FILE_ACTION_ADDED,
7163 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7164 dscp, lastNamep, NULL, TRUE);
7165 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7166 /* Not an exclusive create, and someone else tried
7167 * creating it already, then we open it anyway. We
7168 * don't bother retrying after this, since if this next
7169 * fails, that means that the file was deleted after we
7170 * started this call.
7172 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7175 if (createDisp == FILE_OVERWRITE_IF) {
7176 setAttr.mask = CM_ATTRMASK_LENGTH;
7177 setAttr.length.LowPart = 0;
7178 setAttr.length.HighPart = 0;
7180 /* now watch for a symlink */
7182 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7184 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7186 /* we have a more accurate file to use (the
7187 * target of the symbolic link). Otherwise,
7188 * we'll just use the symlink anyway.
7190 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7192 cm_ReleaseSCache(scp);
7196 code = cm_SetAttr(scp, &setAttr, userp, &req);
7198 } /* lookup succeeded */
7201 clientchar_t *tp, *pp;
7202 clientchar_t *cp; /* This component */
7203 int clen = 0; /* length of component */
7204 cm_scache_t *tscp1, *tscp2;
7207 /* create directory */
7209 treeStartp = lastNamep;
7210 osi_assertx(dscp != NULL, "null cm_scache_t");
7211 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%S]",
7212 osi_LogSaveClientString(smb_logp, treeStartp));
7213 openAction = 2; /* created directory */
7215 /* if the request is to create the root directory
7216 * it will appear as a directory name of the nul-string
7217 * and a code of CM_ERROR_NOSUCHFILE
7219 if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
7220 code = CM_ERROR_EXISTS;
7222 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7223 setAttr.clientModTime = time(NULL);
7228 cm_HoldSCache(tscp1);
7232 tp = cm_ClientStrChr(pp, '\\');
7234 cm_ClientStrCpy(cp, lengthof(spacep->wdata) - (cp - spacep->wdata), pp);
7235 clen = (int)cm_ClientStrLen(cp);
7236 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
7238 clen = (int)(tp - pp);
7239 cm_ClientStrCpyN(cp, lengthof(spacep->wdata) - (cp - spacep->wdata),
7247 continue; /* the supplied path can't have consecutive slashes either , but */
7249 /* cp is the next component to be created. */
7250 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req, NULL);
7251 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
7252 smb_NotifyChange(FILE_ACTION_ADDED,
7253 FILE_NOTIFY_CHANGE_DIR_NAME,
7254 tscp1, cp, NULL, TRUE);
7256 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7257 /* Not an exclusive create, and someone else tried
7258 * creating it already, then we open it anyway. We
7259 * don't bother retrying after this, since if this next
7260 * fails, that means that the file was deleted after we
7261 * started this call.
7263 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
7264 userp, &req, &tscp2);
7269 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
7270 cm_ReleaseSCache(tscp1);
7271 tscp1 = tscp2; /* Newly created directory will be next parent */
7272 /* the hold is transfered to tscp1 from tscp2 */
7277 cm_ReleaseSCache(dscp);
7280 cm_ReleaseSCache(scp);
7283 * if we get here and code == 0, then scp is the last directory created, and dscp is the
7289 /* something went wrong creating or truncating the file */
7291 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7293 cm_ReleaseSCache(scp);
7295 cm_ReleaseSCache(dscp);
7296 cm_ReleaseUser(userp);
7301 /* make sure we have file vs. dir right (only applies for single component case) */
7302 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7303 /* now watch for a symlink */
7305 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7306 cm_scache_t * targetScp = 0;
7307 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7309 /* we have a more accurate file to use (the
7310 * target of the symbolic link). Otherwise,
7311 * we'll just use the symlink anyway.
7313 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
7315 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7316 cm_ReleaseSCache(scp);
7321 if (scp->fileType != CM_SCACHETYPE_FILE) {
7323 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7325 cm_ReleaseSCache(dscp);
7326 cm_ReleaseSCache(scp);
7327 cm_ReleaseUser(userp);
7329 return CM_ERROR_ISDIR;
7333 /* (only applies to single component case) */
7334 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7336 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7337 cm_ReleaseSCache(scp);
7339 cm_ReleaseSCache(dscp);
7340 cm_ReleaseUser(userp);
7342 return CM_ERROR_NOTDIR;
7345 /* open the file itself */
7346 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7347 osi_assertx(fidp, "null smb_fid_t");
7349 /* save a reference to the user */
7351 fidp->userp = userp;
7353 /* If we are restricting sharing, we should do so with a suitable
7355 if (scp->fileType == CM_SCACHETYPE_FILE &&
7356 !(fidflags & SMB_FID_SHARE_WRITE)) {
7358 LARGE_INTEGER LOffset, LLength;
7361 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7362 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7363 LLength.HighPart = 0;
7364 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7366 /* If we are not opening the file for writing, then we don't
7367 try to get an exclusive lock. No one else should be able to
7368 get an exclusive lock on the file anyway, although someone
7369 else can get a shared lock. */
7370 if ((fidflags & SMB_FID_SHARE_READ) ||
7371 !(fidflags & SMB_FID_OPENWRITE)) {
7372 sLockType = LOCKING_ANDX_SHARED_LOCK;
7377 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7379 lock_ObtainWrite(&scp->rw);
7380 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7381 lock_ReleaseWrite(&scp->rw);
7385 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7386 cm_ReleaseSCache(scp);
7388 cm_ReleaseSCache(dscp);
7389 cm_ReleaseUser(userp);
7390 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7391 smb_CloseFID(vcp, fidp, NULL, 0);
7392 smb_ReleaseFID(fidp);
7398 /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
7400 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7402 lock_ObtainMutex(&fidp->mx);
7403 /* save a pointer to the vnode */
7404 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
7405 lock_ObtainWrite(&scp->rw);
7406 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7407 lock_ReleaseWrite(&scp->rw);
7408 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
7410 fidp->flags = fidflags;
7412 /* remember if the file was newly created */
7414 fidp->flags |= SMB_FID_CREATED;
7416 /* save parent dir and pathname for delete or change notification */
7417 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7418 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
7419 fidp->flags |= SMB_FID_NTOPEN;
7420 fidp->NTopen_dscp = dscp;
7422 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
7424 fidp->NTopen_wholepathp = realPathp;
7425 lock_ReleaseMutex(&fidp->mx);
7427 /* we don't need this any longer */
7429 cm_ReleaseSCache(dscp);
7433 cm_Open(scp, 0, userp);
7435 /* set inp->fid so that later read calls in same msg can find fid */
7436 inp->fid = fidp->fid;
7440 lock_ObtainRead(&scp->rw);
7441 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7442 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7443 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7444 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7445 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7446 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7447 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7448 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7449 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7451 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7452 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7453 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
7454 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
7455 smb_SetSMBParmByte(outp, parmSlot,
7456 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7457 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7458 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7459 smb_SetSMBDataLength(outp, 0);
7461 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
7462 LargeIntegerGreaterThanZero(fidp->scp->length) &&
7463 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
7464 cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
7465 fidp->scp->length.LowPart, fidp->scp->length.HighPart,
7468 lock_ReleaseRead(&scp->rw);
7470 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %S", fidp->fid,
7471 osi_LogSaveClientString(smb_logp, realPathp));
7473 cm_ReleaseUser(userp);
7474 smb_ReleaseFID(fidp);
7476 /* Can't free realPathp if we get here since
7477 fidp->NTopen_wholepathp is pointing there */
7479 /* leave scp held since we put it in fidp->scp */
7484 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
7485 * Instead, ultimately, would like to use a subroutine for common code.
7488 /* NT_TRANSACT_CREATE (SMB_COM_NT_TRANSACT) */
7489 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7491 clientchar_t *pathp, *realPathp;
7495 cm_scache_t *dscp; /* parent dir */
7496 cm_scache_t *scp; /* file to create or open */
7497 cm_scache_t *targetScp; /* if scp is a symlink */
7499 clientchar_t *lastNamep;
7500 unsigned long nameLength;
7502 unsigned int requestOpLock;
7503 unsigned int requestBatchOpLock;
7504 unsigned int mustBeDir;
7505 unsigned int extendedRespRequired;
7507 unsigned int desiredAccess;
7508 #ifdef DEBUG_VERBOSE
7509 unsigned int allocSize;
7511 unsigned int shareAccess;
7512 unsigned int extAttributes;
7513 unsigned int createDisp;
7514 #ifdef DEBUG_VERBOSE
7517 unsigned int createOptions;
7518 int initialModeBits;
7519 unsigned short baseFid;
7520 smb_fid_t *baseFidp;
7522 cm_scache_t *baseDirp;
7523 unsigned short openAction;
7527 clientchar_t *tidPathp;
7529 int parmOffset, dataOffset;
7535 cm_lock_data_t *ldp = NULL;
7542 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7543 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7544 parmp = inp->data + parmOffset;
7545 lparmp = (ULONG *) parmp;
7548 requestOpLock = flags & REQUEST_OPLOCK;
7549 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7550 mustBeDir = flags & OPEN_DIRECTORY;
7551 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7554 * Why all of a sudden 32-bit FID?
7555 * We will reject all bits higher than 16.
7557 if (lparmp[1] & 0xFFFF0000)
7558 return CM_ERROR_INVAL;
7559 baseFid = (unsigned short)lparmp[1];
7560 desiredAccess = lparmp[2];
7561 #ifdef DEBUG_VERBOSE
7562 allocSize = lparmp[3];
7563 #endif /* DEBUG_VERSOSE */
7564 extAttributes = lparmp[5];
7565 shareAccess = lparmp[6];
7566 createDisp = lparmp[7];
7567 createOptions = lparmp[8];
7568 #ifdef DEBUG_VERBOSE
7571 nameLength = lparmp[11];
7573 #ifdef DEBUG_VERBOSE
7574 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
7575 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
7576 osi_Log1(smb_logp,"... flags[%x]",flags);
7579 /* mustBeDir is never set; createOptions directory bit seems to be
7582 if (createOptions & FILE_DIRECTORY_FILE)
7584 else if (createOptions & FILE_NON_DIRECTORY_FILE)
7590 * compute initial mode bits based on read-only flag in
7591 * extended attributes
7593 initialModeBits = 0666;
7594 if (extAttributes & SMB_ATTR_READONLY)
7595 initialModeBits &= ~0222;
7597 pathp = smb_ParseStringCch(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
7598 nameLength, NULL, SMB_STRF_ANSIPATH);
7599 /* Sometimes path is not null-terminated, so we make a copy. */
7600 realPathp = malloc((nameLength+1) * sizeof(clientchar_t));
7601 memcpy(realPathp, pathp, nameLength * sizeof(clientchar_t));
7602 realPathp[nameLength] = 0;
7603 spacep = cm_GetSpace();
7604 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
7607 * Nothing here to handle SMB_IOCTL_FILENAME.
7608 * Will add it if necessary.
7611 #ifdef DEBUG_VERBOSE
7613 char *hexp, *asciip;
7614 asciip = (lastNamep? lastNamep : realPathp);
7615 hexp = osi_HexifyString( asciip );
7616 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
7621 userp = smb_GetUserFromVCP(vcp, inp);
7623 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
7625 return CM_ERROR_INVAL;
7630 baseDirp = cm_data.rootSCachep;
7631 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7632 if (code == CM_ERROR_TIDIPC) {
7633 /* Attempt to use a TID allocated for IPC. The client
7634 * is probably looking for DCE RPC end points which we
7635 * don't support OR it could be looking to make a DFS
7638 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
7641 cm_ReleaseUser(userp);
7642 return CM_ERROR_NOSUCHPATH;
7646 baseFidp = smb_FindFID(vcp, baseFid, 0);
7648 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
7650 cm_ReleaseUser(userp);
7651 return CM_ERROR_BADFD;
7654 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7656 cm_ReleaseUser(userp);
7657 smb_CloseFID(vcp, baseFidp, NULL, 0);
7658 smb_ReleaseFID(baseFidp);
7659 return CM_ERROR_NOSUCHPATH;
7662 baseDirp = baseFidp->scp;
7666 /* compute open mode */
7668 if (desiredAccess & DELETE)
7669 fidflags |= SMB_FID_OPENDELETE;
7670 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
7671 fidflags |= SMB_FID_OPENREAD_LISTDIR;
7672 if (desiredAccess & AFS_ACCESS_WRITE)
7673 fidflags |= SMB_FID_OPENWRITE;
7674 if (createOptions & FILE_DELETE_ON_CLOSE)
7675 fidflags |= SMB_FID_DELONCLOSE;
7676 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7677 fidflags |= SMB_FID_SEQUENTIAL;
7678 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7679 fidflags |= SMB_FID_RANDOM;
7680 if (smb_IsExecutableFileName(lastNamep))
7681 fidflags |= SMB_FID_EXECUTABLE;
7683 /* And the share mode */
7684 if (shareAccess & FILE_SHARE_READ)
7685 fidflags |= SMB_FID_SHARE_READ;
7686 if (shareAccess & FILE_SHARE_WRITE)
7687 fidflags |= SMB_FID_SHARE_WRITE;
7691 if ( createDisp == FILE_OPEN ||
7692 createDisp == FILE_OVERWRITE ||
7693 createDisp == FILE_OVERWRITE_IF) {
7694 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7695 userp, tidPathp, &req, &dscp);
7698 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7699 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7700 cm_ReleaseSCache(dscp);
7701 cm_ReleaseUser(userp);
7704 smb_ReleaseFID(baseFidp);
7705 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7706 return CM_ERROR_PATH_NOT_COVERED;
7708 return CM_ERROR_BADSHARENAME;
7710 #endif /* DFS_SUPPORT */
7711 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7713 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7714 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7715 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7716 if (code == 0 && realDirFlag == 1) {
7717 cm_ReleaseSCache(scp);
7718 cm_ReleaseSCache(dscp);
7719 cm_ReleaseUser(userp);
7722 smb_ReleaseFID(baseFidp);
7723 return CM_ERROR_EXISTS;
7729 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7730 userp, tidPathp, &req, &scp);
7732 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7733 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7734 cm_ReleaseSCache(scp);
7735 cm_ReleaseUser(userp);
7738 smb_ReleaseFID(baseFidp);
7739 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7740 return CM_ERROR_PATH_NOT_COVERED;
7742 return CM_ERROR_BADSHARENAME;
7744 #endif /* DFS_SUPPORT */
7750 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7751 /* look up parent directory */
7753 code = cm_NameI(baseDirp, spacep->wdata,
7754 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7755 userp, tidPathp, &req, &dscp);
7757 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7758 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7759 cm_ReleaseSCache(dscp);
7760 cm_ReleaseUser(userp);
7763 smb_ReleaseFID(baseFidp);
7764 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7765 return CM_ERROR_PATH_NOT_COVERED;
7767 return CM_ERROR_BADSHARENAME;
7769 #endif /* DFS_SUPPORT */
7773 cm_FreeSpace(spacep);
7776 smb_ReleaseFID(baseFidp);
7779 cm_ReleaseUser(userp);
7785 lastNamep = realPathp;
7789 if (!smb_IsLegalFilename(lastNamep))
7790 return CM_ERROR_BADNTFILENAME;
7793 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
7794 code = cm_Lookup(dscp, lastNamep,
7795 CM_FLAG_FOLLOW, userp, &req, &scp);
7797 code = cm_Lookup(dscp, lastNamep,
7798 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7801 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7802 cm_ReleaseSCache(dscp);
7803 cm_ReleaseUser(userp);
7810 smb_ReleaseFID(baseFidp);
7811 cm_FreeSpace(spacep);
7814 /* if we get here, if code is 0, the file exists and is represented by
7815 * scp. Otherwise, we have to create it. The dir may be represented
7816 * by dscp, or we may have found the file directly. If code is non-zero,
7820 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7823 cm_ReleaseSCache(dscp);
7824 cm_ReleaseSCache(scp);
7825 cm_ReleaseUser(userp);
7830 if (createDisp == FILE_CREATE) {
7831 /* oops, file shouldn't be there */
7832 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7834 cm_ReleaseSCache(dscp);
7835 cm_ReleaseSCache(scp);
7836 cm_ReleaseUser(userp);
7838 return CM_ERROR_EXISTS;
7841 if (createDisp == FILE_OVERWRITE ||
7842 createDisp == FILE_OVERWRITE_IF) {
7843 setAttr.mask = CM_ATTRMASK_LENGTH;
7844 setAttr.length.LowPart = 0;
7845 setAttr.length.HighPart = 0;
7847 /* now watch for a symlink */
7849 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7851 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7853 /* we have a more accurate file to use (the
7854 * target of the symbolic link). Otherwise,
7855 * we'll just use the symlink anyway.
7857 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7859 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7860 cm_ReleaseSCache(scp);
7862 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7865 cm_ReleaseSCache(dscp);
7867 cm_ReleaseSCache(scp);
7868 cm_ReleaseUser(userp);
7874 code = cm_SetAttr(scp, &setAttr, userp, &req);
7875 openAction = 3; /* truncated existing file */
7877 else openAction = 1; /* found existing file */
7879 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7880 /* don't create if not found */
7882 cm_ReleaseSCache(dscp);
7883 cm_ReleaseUser(userp);
7885 return CM_ERROR_NOSUCHFILE;
7887 else if (realDirFlag == 0 || realDirFlag == -1) {
7888 osi_assertx(dscp != NULL, "null cm_scache_t");
7889 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %S",
7890 osi_LogSaveClientString(smb_logp, lastNamep));
7891 openAction = 2; /* created file */
7892 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7893 setAttr.clientModTime = time(NULL);
7894 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7898 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7899 smb_NotifyChange(FILE_ACTION_ADDED,
7900 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7901 dscp, lastNamep, NULL, TRUE);
7902 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7903 /* Not an exclusive create, and someone else tried
7904 * creating it already, then we open it anyway. We
7905 * don't bother retrying after this, since if this next
7906 * fails, that means that the file was deleted after we
7907 * started this call.
7909 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7912 if (createDisp == FILE_OVERWRITE_IF) {
7913 setAttr.mask = CM_ATTRMASK_LENGTH;
7914 setAttr.length.LowPart = 0;
7915 setAttr.length.HighPart = 0;
7917 /* now watch for a symlink */
7919 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7921 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7923 /* we have a more accurate file to use (the
7924 * target of the symbolic link). Otherwise,
7925 * we'll just use the symlink anyway.
7927 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7929 cm_ReleaseSCache(scp);
7933 code = cm_SetAttr(scp, &setAttr, userp, &req);
7935 } /* lookup succeeded */
7938 /* create directory */
7939 osi_assertx(dscp != NULL, "null cm_scache_t");
7941 "smb_ReceiveNTTranCreate creating directory %S",
7942 osi_LogSaveClientString(smb_logp, lastNamep));
7943 openAction = 2; /* created directory */
7944 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7945 setAttr.clientModTime = time(NULL);
7946 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
7947 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7948 smb_NotifyChange(FILE_ACTION_ADDED,
7949 FILE_NOTIFY_CHANGE_DIR_NAME,
7950 dscp, lastNamep, NULL, TRUE);
7952 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7953 /* Not an exclusive create, and someone else tried
7954 * creating it already, then we open it anyway. We
7955 * don't bother retrying after this, since if this next
7956 * fails, that means that the file was deleted after we
7957 * started this call.
7959 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7965 /* something went wrong creating or truncating the file */
7967 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7969 cm_ReleaseSCache(scp);
7970 cm_ReleaseUser(userp);
7975 /* make sure we have file vs. dir right */
7976 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7977 /* now watch for a symlink */
7979 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7981 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7983 /* we have a more accurate file to use (the
7984 * target of the symbolic link). Otherwise,
7985 * we'll just use the symlink anyway.
7987 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7990 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7991 cm_ReleaseSCache(scp);
7996 if (scp->fileType != CM_SCACHETYPE_FILE) {
7998 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7999 cm_ReleaseSCache(scp);
8000 cm_ReleaseUser(userp);
8002 return CM_ERROR_ISDIR;
8006 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8008 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8009 cm_ReleaseSCache(scp);
8010 cm_ReleaseUser(userp);
8012 return CM_ERROR_NOTDIR;
8015 /* open the file itself */
8016 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8017 osi_assertx(fidp, "null smb_fid_t");
8019 /* save a reference to the user */
8021 fidp->userp = userp;
8023 /* If we are restricting sharing, we should do so with a suitable
8025 if (scp->fileType == CM_SCACHETYPE_FILE &&
8026 !(fidflags & SMB_FID_SHARE_WRITE)) {
8028 LARGE_INTEGER LOffset, LLength;
8031 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8032 LOffset.LowPart = SMB_FID_QLOCK_LOW;
8033 LLength.HighPart = 0;
8034 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8036 /* Similar to what we do in handling NTCreateX. We get a
8037 shared lock if we are only opening the file for reading. */
8038 if ((fidflags & SMB_FID_SHARE_READ) ||
8039 !(fidflags & SMB_FID_OPENWRITE)) {
8040 sLockType = LOCKING_ANDX_SHARED_LOCK;
8045 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8047 lock_ObtainWrite(&scp->rw);
8048 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8049 lock_ReleaseWrite(&scp->rw);
8053 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8054 cm_ReleaseSCache(scp);
8055 cm_ReleaseUser(userp);
8056 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
8057 smb_CloseFID(vcp, fidp, NULL, 0);
8058 smb_ReleaseFID(fidp);
8060 return CM_ERROR_SHARING_VIOLATION;
8064 /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
8066 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8068 lock_ObtainMutex(&fidp->mx);
8069 /* save a pointer to the vnode */
8071 lock_ObtainWrite(&scp->rw);
8072 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8073 lock_ReleaseWrite(&scp->rw);
8074 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
8076 fidp->flags = fidflags;
8078 /* remember if the file was newly created */
8080 fidp->flags |= SMB_FID_CREATED;
8082 /* save parent dir and pathname for deletion or change notification */
8083 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8084 fidp->flags |= SMB_FID_NTOPEN;
8085 fidp->NTopen_dscp = dscp;
8086 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
8088 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
8090 fidp->NTopen_wholepathp = realPathp;
8091 lock_ReleaseMutex(&fidp->mx);
8093 /* we don't need this any longer */
8095 cm_ReleaseSCache(dscp);
8097 cm_Open(scp, 0, userp);
8099 /* set inp->fid so that later read calls in same msg can find fid */
8100 inp->fid = fidp->fid;
8102 /* check whether we are required to send an extended response */
8103 if (!extendedRespRequired) {
8105 parmOffset = 8*4 + 39;
8106 parmOffset += 1; /* pad to 4 */
8107 dataOffset = parmOffset + 70;
8111 /* Total Parameter Count */
8112 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8113 /* Total Data Count */
8114 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8115 /* Parameter Count */
8116 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8117 /* Parameter Offset */
8118 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8119 /* Parameter Displacement */
8120 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8122 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8124 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8125 /* Data Displacement */
8126 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8127 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8128 smb_SetSMBDataLength(outp, 70);
8130 lock_ObtainRead(&scp->rw);
8131 outData = smb_GetSMBData(outp, NULL);
8132 outData++; /* round to get to parmOffset */
8133 *outData = 0; outData++; /* oplock */
8134 *outData = 0; outData++; /* reserved */
8135 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8136 *((ULONG *)outData) = openAction; outData += 4;
8137 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8138 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8139 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8140 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8141 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8142 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8143 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8144 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8145 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8146 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8147 *((USHORT *)outData) = 0; outData += 2; /* dev state */
8148 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8149 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8150 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8151 outData += 2; /* is a dir? */
8154 parmOffset = 8*4 + 39;
8155 parmOffset += 1; /* pad to 4 */
8156 dataOffset = parmOffset + 104;
8160 /* Total Parameter Count */
8161 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8162 /* Total Data Count */
8163 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8164 /* Parameter Count */
8165 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8166 /* Parameter Offset */
8167 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8168 /* Parameter Displacement */
8169 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8171 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8173 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8174 /* Data Displacement */
8175 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8176 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8177 smb_SetSMBDataLength(outp, 105);
8179 lock_ObtainRead(&scp->rw);
8180 outData = smb_GetSMBData(outp, NULL);
8181 outData++; /* round to get to parmOffset */
8182 *outData = 0; outData++; /* oplock */
8183 *outData = 1; outData++; /* response type */
8184 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8185 *((ULONG *)outData) = openAction; outData += 4;
8186 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8187 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8188 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8189 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8190 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8191 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8192 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8193 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8194 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8195 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8196 *((USHORT *)outData) = 0; outData += 2; /* dev state */
8197 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8198 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8199 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8200 outData += 1; /* is a dir? */
8201 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
8202 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
8203 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
8206 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
8207 LargeIntegerGreaterThanZero(fidp->scp->length) &&
8208 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
8209 cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
8210 fidp->scp->length.LowPart, fidp->scp->length.HighPart,
8213 lock_ReleaseRead(&scp->rw);
8215 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
8217 cm_ReleaseUser(userp);
8218 smb_ReleaseFID(fidp);
8220 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
8221 /* leave scp held since we put it in fidp->scp */
8225 /* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
8226 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
8229 smb_packet_t *savedPacketp;
8231 USHORT fid, watchtree;
8235 filter = smb_GetSMBParm(inp, 19) |
8236 (smb_GetSMBParm(inp, 20) << 16);
8237 fid = smb_GetSMBParm(inp, 21);
8238 watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
8240 fidp = smb_FindFID(vcp, fid, 0);
8242 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
8243 return CM_ERROR_BADFD;
8246 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8247 smb_CloseFID(vcp, fidp, NULL, 0);
8248 smb_ReleaseFID(fidp);
8249 return CM_ERROR_NOSUCHFILE;
8252 /* Create a copy of the Directory Watch Packet to use when sending the
8253 * notification if in the future a matching change is detected.
8255 savedPacketp = smb_CopyPacket(inp);
8256 if (vcp != savedPacketp->vcp) {
8258 if (savedPacketp->vcp)
8259 smb_ReleaseVC(savedPacketp->vcp);
8260 savedPacketp->vcp = vcp;
8263 /* Add the watch to the list of events to send notifications for */
8264 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8265 savedPacketp->nextp = smb_Directory_Watches;
8266 smb_Directory_Watches = savedPacketp;
8267 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8270 osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%S\"",
8271 fidp, scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp));
8272 osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
8273 filter, fid, watchtree);
8274 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8275 osi_Log0(smb_logp, " Notify Change File Name");
8276 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8277 osi_Log0(smb_logp, " Notify Change Directory Name");
8278 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8279 osi_Log0(smb_logp, " Notify Change Attributes");
8280 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8281 osi_Log0(smb_logp, " Notify Change Size");
8282 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8283 osi_Log0(smb_logp, " Notify Change Last Write");
8284 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8285 osi_Log0(smb_logp, " Notify Change Last Access");
8286 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8287 osi_Log0(smb_logp, " Notify Change Creation");
8288 if (filter & FILE_NOTIFY_CHANGE_EA)
8289 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8290 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8291 osi_Log0(smb_logp, " Notify Change Security");
8292 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8293 osi_Log0(smb_logp, " Notify Change Stream Name");
8294 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8295 osi_Log0(smb_logp, " Notify Change Stream Size");
8296 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8297 osi_Log0(smb_logp, " Notify Change Stream Write");
8299 lock_ObtainWrite(&scp->rw);
8301 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
8303 scp->flags |= CM_SCACHEFLAG_WATCHED;
8304 lock_ReleaseWrite(&scp->rw);
8305 smb_ReleaseFID(fidp);
8307 outp->flags |= SMB_PACKETFLAG_NOSEND;
8311 unsigned char nullSecurityDesc[36] = {
8312 0x01, /* security descriptor revision */
8313 0x00, /* reserved, should be zero */
8314 0x00, 0x80, /* security descriptor control;
8315 * 0x8000 : self-relative format */
8316 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
8317 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
8318 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
8319 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
8320 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8321 /* "null SID" owner SID */
8322 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
8323 /* "null SID" group SID */
8326 /* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
8327 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8329 int parmOffset, parmCount, dataOffset, dataCount;
8337 ULONG securityInformation;
8339 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8340 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8341 parmp = inp->data + parmOffset;
8342 sparmp = (USHORT *) parmp;
8343 lparmp = (ULONG *) parmp;
8346 securityInformation = lparmp[1];
8348 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
8349 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
8357 parmOffset = 8*4 + 39;
8358 parmOffset += 1; /* pad to 4 */
8360 dataOffset = parmOffset + parmCount;
8364 /* Total Parameter Count */
8365 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8366 /* Total Data Count */
8367 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8368 /* Parameter Count */
8369 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8370 /* Parameter Offset */
8371 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8372 /* Parameter Displacement */
8373 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8375 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8377 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8378 /* Data Displacement */
8379 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8380 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8381 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
8383 outData = smb_GetSMBData(outp, NULL);
8384 outData++; /* round to get to parmOffset */
8385 *((ULONG *)outData) = 36; outData += 4; /* length */
8387 if (maxData >= 36) {
8388 memcpy(outData, nullSecurityDesc, 36);
8392 return CM_ERROR_BUFFERTOOSMALL;
8395 /* SMB_COM_NT_TRANSACT
8397 SMB_COM_NT_TRANSACT_SECONDARY should also be handled here.
8399 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8401 unsigned short function;
8403 function = smb_GetSMBParm(inp, 18);
8405 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
8407 /* We can handle long names */
8408 if (vcp->flags & SMB_VCFLAG_USENT)
8409 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
8412 case 1: /* NT_TRANSACT_CREATE */
8413 return smb_ReceiveNTTranCreate(vcp, inp, outp);
8414 case 2: /* NT_TRANSACT_IOCTL */
8415 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
8417 case 3: /* NT_TRANSACT_SET_SECURITY_DESC */
8418 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
8420 case 4: /* NT_TRANSACT_NOTIFY_CHANGE */
8421 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
8422 case 5: /* NT_TRANSACT_RENAME */
8423 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
8425 case 6: /* NT_TRANSACT_QUERY_SECURITY_DESC */
8426 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
8428 osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
8431 osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
8434 return CM_ERROR_INVAL;
8438 * smb_NotifyChange -- find relevant change notification messages and
8441 * If we don't know the file name (i.e. a callback break), filename is
8442 * NULL, and we return a zero-length list.
8444 * At present there is not a single call to smb_NotifyChange that
8445 * has the isDirectParent parameter set to FALSE.
8447 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
8448 cm_scache_t *dscp, clientchar_t *filename, clientchar_t *otherFilename,
8449 BOOL isDirectParent)
8451 smb_packet_t *watch, *lastWatch, *nextWatch;
8452 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen = 0;
8453 char *outData, *oldOutData;
8457 BOOL twoEntries = FALSE;
8458 ULONG otherNameLen, oldParmCount = 0;
8462 /* Get ready for rename within directory */
8463 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
8465 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
8468 osi_Log4(smb_logp,"in smb_NotifyChange for file [%S] dscp [%p] notification 0x%x parent %d",
8469 osi_LogSaveClientString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
8471 osi_Log0(smb_logp," FILE_ACTION_NONE");
8472 if (action == FILE_ACTION_ADDED)
8473 osi_Log0(smb_logp," FILE_ACTION_ADDED");
8474 if (action == FILE_ACTION_REMOVED)
8475 osi_Log0(smb_logp," FILE_ACTION_REMOVED");
8476 if (action == FILE_ACTION_MODIFIED)
8477 osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
8478 if (action == FILE_ACTION_RENAMED_OLD_NAME)
8479 osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
8480 if (action == FILE_ACTION_RENAMED_NEW_NAME)
8481 osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
8483 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8484 watch = smb_Directory_Watches;
8486 filter = smb_GetSMBParm(watch, 19)
8487 | (smb_GetSMBParm(watch, 20) << 16);
8488 fid = smb_GetSMBParm(watch, 21);
8489 wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
8491 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
8492 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
8495 * Strange hack - bug in NT Client and NT Server that we must emulate?
8497 if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
8498 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
8500 fidp = smb_FindFID(watch->vcp, fid, 0);
8502 osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
8504 watch = watch->nextp;
8508 if (fidp->scp != dscp ||
8509 fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
8510 (filter & notifyFilter) == 0 ||
8511 (!isDirectParent && !wtree))
8513 osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
8514 smb_ReleaseFID(fidp);
8516 watch = watch->nextp;
8519 smb_ReleaseFID(fidp);
8522 "Sending Change Notification for fid %d filter 0x%x wtree %d file %S",
8523 fid, filter, wtree, osi_LogSaveClientString(smb_logp, filename));
8524 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8525 osi_Log0(smb_logp, " Notify Change File Name");
8526 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8527 osi_Log0(smb_logp, " Notify Change Directory Name");
8528 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8529 osi_Log0(smb_logp, " Notify Change Attributes");
8530 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8531 osi_Log0(smb_logp, " Notify Change Size");
8532 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8533 osi_Log0(smb_logp, " Notify Change Last Write");
8534 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8535 osi_Log0(smb_logp, " Notify Change Last Access");
8536 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8537 osi_Log0(smb_logp, " Notify Change Creation");
8538 if (filter & FILE_NOTIFY_CHANGE_EA)
8539 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8540 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8541 osi_Log0(smb_logp, " Notify Change Security");
8542 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8543 osi_Log0(smb_logp, " Notify Change Stream Name");
8544 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8545 osi_Log0(smb_logp, " Notify Change Stream Size");
8546 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8547 osi_Log0(smb_logp, " Notify Change Stream Write");
8549 /* A watch can only be notified once. Remove it from the list */
8550 nextWatch = watch->nextp;
8551 if (watch == smb_Directory_Watches)
8552 smb_Directory_Watches = nextWatch;
8554 lastWatch->nextp = nextWatch;
8556 /* Turn off WATCHED flag in dscp */
8557 lock_ObtainWrite(&dscp->rw);
8559 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8561 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
8562 lock_ReleaseWrite(&dscp->rw);
8564 /* Convert to response packet */
8565 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
8566 #ifdef SEND_CANONICAL_PATHNAMES
8567 ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
8569 ((smb_t *) watch)->wct = 0;
8572 if (filename == NULL) {
8575 nameLen = (ULONG)cm_ClientStrLen(filename);
8576 parmCount = 3*4 + nameLen*2;
8577 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8579 otherNameLen = (ULONG)cm_ClientStrLen(otherFilename);
8580 oldParmCount = parmCount;
8581 parmCount += 3*4 + otherNameLen*2;
8582 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8584 if (maxLen < parmCount)
8585 parmCount = 0; /* not enough room */
8587 parmOffset = 8*4 + 39;
8588 parmOffset += 1; /* pad to 4 */
8589 dataOffset = parmOffset + parmCount;
8593 /* Total Parameter Count */
8594 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8595 /* Total Data Count */
8596 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8597 /* Parameter Count */
8598 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8599 /* Parameter Offset */
8600 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
8601 /* Parameter Displacement */
8602 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8604 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8606 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
8607 /* Data Displacement */
8608 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8609 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
8610 smb_SetSMBDataLength(watch, parmCount + 1);
8612 if (parmCount != 0) {
8613 outData = smb_GetSMBData(watch, NULL);
8614 outData++; /* round to get to parmOffset */
8615 oldOutData = outData;
8616 *((DWORD *)outData) = oldParmCount; outData += 4;
8617 /* Next Entry Offset */
8618 *((DWORD *)outData) = action; outData += 4;
8620 *((DWORD *)outData) = nameLen*2; outData += 4;
8621 /* File Name Length */
8623 smb_UnparseString(watch, outData, filename, NULL, 0);
8627 outData = oldOutData + oldParmCount;
8628 *((DWORD *)outData) = 0; outData += 4;
8629 /* Next Entry Offset */
8630 *((DWORD *)outData) = otherAction; outData += 4;
8632 *((DWORD *)outData) = otherNameLen*2;
8633 outData += 4; /* File Name Length */
8634 smb_UnparseString(watch, outData, otherFilename, NULL, 0);
8639 * If filename is null, we don't know the cause of the
8640 * change notification. We return zero data (see above),
8641 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
8642 * (= 0x010C). We set the error code here by hand, without
8643 * modifying wct and bcc.
8645 if (filename == NULL) {
8646 ((smb_t *) watch)->rcls = 0x0C;
8647 ((smb_t *) watch)->reh = 0x01;
8648 ((smb_t *) watch)->errLow = 0;
8649 ((smb_t *) watch)->errHigh = 0;
8650 /* Set NT Status codes flag */
8651 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8654 smb_SendPacket(watch->vcp, watch);
8655 smb_FreePacket(watch);
8658 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8661 /* SMB_COM_NT_CANCEL */
8662 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8664 unsigned char *replyWctp;
8665 smb_packet_t *watch, *lastWatch;
8666 USHORT fid, watchtree;
8670 osi_Log0(smb_logp, "SMB3 receive NT cancel");
8672 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8673 watch = smb_Directory_Watches;
8675 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
8676 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
8677 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
8678 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
8679 if (watch == smb_Directory_Watches)
8680 smb_Directory_Watches = watch->nextp;
8682 lastWatch->nextp = watch->nextp;
8683 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8685 /* Turn off WATCHED flag in scp */
8686 fid = smb_GetSMBParm(watch, 21);
8687 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
8689 if (vcp != watch->vcp)
8690 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
8693 fidp = smb_FindFID(vcp, fid, 0);
8695 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %S",
8697 (fidp ? osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp) :_C("")));
8700 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
8701 lock_ObtainWrite(&scp->rw);
8703 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8705 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
8706 lock_ReleaseWrite(&scp->rw);
8707 smb_ReleaseFID(fidp);
8709 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
8712 /* assume STATUS32; return 0xC0000120 (CANCELED) */
8713 replyWctp = watch->wctp;
8717 ((smb_t *)watch)->rcls = 0x20;
8718 ((smb_t *)watch)->reh = 0x1;
8719 ((smb_t *)watch)->errLow = 0;
8720 ((smb_t *)watch)->errHigh = 0xC0;
8721 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8722 smb_SendPacket(vcp, watch);
8723 smb_FreePacket(watch);
8727 watch = watch->nextp;
8729 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8735 * NT rename also does hard links.
8738 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
8739 #define RENAME_FLAG_HARD_LINK 0x103
8740 #define RENAME_FLAG_RENAME 0x104
8741 #define RENAME_FLAG_COPY 0x105
8743 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8745 clientchar_t *oldPathp, *newPathp;
8751 attrs = smb_GetSMBParm(inp, 0);
8752 rename_type = smb_GetSMBParm(inp, 1);
8754 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
8755 osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
8756 return CM_ERROR_NOACCESS;
8759 tp = smb_GetSMBData(inp, NULL);
8760 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
8761 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
8763 osi_Log3(smb_logp, "NTRename for [%S]->[%S] type [%s]",
8764 osi_LogSaveClientString(smb_logp, oldPathp),
8765 osi_LogSaveClientString(smb_logp, newPathp),
8766 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
8768 if (rename_type == RENAME_FLAG_RENAME) {
8769 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
8770 } else { /* RENAME_FLAG_HARD_LINK */
8771 code = smb_Link(vcp,inp,oldPathp,newPathp);
8778 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
8781 cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
8783 smb_username_t *unp;
8786 unp = smb_FindUserByName(usern, machine, flags);
8788 lock_ObtainMutex(&unp->mx);
8789 unp->userp = cm_NewUser();
8790 lock_ReleaseMutex(&unp->mx);
8791 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
8793 osi_Log2(smb_logp,"smb_FindCMUserByName Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
8797 smb_ReleaseUsername(unp);