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;
2119 DWORD oldTime, newTime;
2121 /* We sometimes see 0 word count. What to do? */
2122 if (*inp->wctp == 0) {
2123 osi_Log0(smb_logp, "Transaction2 word count = 0");
2124 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
2126 smb_SetSMBDataLength(outp, 0);
2127 smb_SendPacket(vcp, outp);
2131 totalParms = smb_GetSMBParm(inp, 0);
2132 totalData = smb_GetSMBParm(inp, 1);
2134 firstPacket = (inp->inCom == 0x32);
2136 /* find the packet we're reassembling */
2137 lock_ObtainWrite(&smb_globalLock);
2138 asp = smb_FindTran2Packet(vcp, inp);
2140 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
2142 lock_ReleaseWrite(&smb_globalLock);
2144 /* now merge in this latest packet; start by looking up offsets */
2146 parmDisp = dataDisp = 0;
2147 parmOffset = smb_GetSMBParm(inp, 10);
2148 dataOffset = smb_GetSMBParm(inp, 12);
2149 parmCount = smb_GetSMBParm(inp, 9);
2150 dataCount = smb_GetSMBParm(inp, 11);
2151 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2152 asp->maxReturnData = smb_GetSMBParm(inp, 3);
2154 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2155 totalData, dataCount, asp->maxReturnData);
2158 parmDisp = smb_GetSMBParm(inp, 4);
2159 parmOffset = smb_GetSMBParm(inp, 3);
2160 dataDisp = smb_GetSMBParm(inp, 7);
2161 dataOffset = smb_GetSMBParm(inp, 6);
2162 parmCount = smb_GetSMBParm(inp, 2);
2163 dataCount = smb_GetSMBParm(inp, 5);
2165 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2166 parmCount, dataCount);
2169 /* now copy the parms and data */
2170 if ( asp->totalParms > 0 && parmCount != 0 )
2172 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2174 if ( asp->totalData > 0 && dataCount != 0 ) {
2175 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2178 /* account for new bytes */
2179 asp->curData += dataCount;
2180 asp->curParms += parmCount;
2182 /* finally, if we're done, remove the packet from the queue and dispatch it */
2183 if (asp->totalParms > 0 &&
2184 asp->curParms > 0 &&
2185 asp->totalData <= asp->curData &&
2186 asp->totalParms <= asp->curParms) {
2187 /* we've received it all */
2188 lock_ObtainWrite(&smb_globalLock);
2189 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2190 lock_ReleaseWrite(&smb_globalLock);
2192 oldTime = GetTickCount();
2194 /* now dispatch it */
2195 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2196 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2197 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2200 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2201 code = CM_ERROR_BADOP;
2204 /* if an error is returned, we're supposed to send an error packet,
2205 * otherwise the dispatched function already did the data sending.
2206 * We give dispatched proc the responsibility since it knows how much
2207 * space to allocate.
2210 smb_SendTran2Error(vcp, asp, outp, code);
2213 newTime = GetTickCount();
2214 if (newTime - oldTime > 45000) {
2217 clientchar_t *treepath = NULL; /* do not free */
2218 clientchar_t *pathname = NULL;
2219 cm_fid_t afid = {0,0,0,0,0};
2221 uidp = smb_FindUID(vcp, asp->uid, 0);
2222 smb_LookupTIDPath(vcp, asp->tid, &treepath);
2223 fidp = smb_FindFID(vcp, inp->fid, 0);
2225 if (fidp && fidp->NTopen_pathp)
2226 pathname = fidp->NTopen_pathp;
2227 else if (inp->stringsp->wdata)
2228 pathname = inp->stringsp->wdata;
2230 if (fidp && fidp->scp)
2231 afid = fidp->scp->fid;
2233 afsi_log("Request %s duration %d ms user %S tid \"%S\" path? \"%S\" afid (%d.%d.%d.%d)",
2234 myCrt_2Dispatch(asp->opcode), newTime - oldTime,
2235 uidp ? uidp->unp->name : NULL,
2238 afid.cell, afid.volume, afid.vnode, afid.unique);
2241 smb_ReleaseUID(uidp);
2243 smb_ReleaseFID(fidp);
2246 /* free the input tran 2 packet */
2247 smb_FreeTran2Packet(asp);
2249 else if (firstPacket) {
2250 /* the first packet in a multi-packet request, we need to send an
2251 * ack to get more data.
2253 smb_SetSMBDataLength(outp, 0);
2254 smb_SendPacket(vcp, outp);
2261 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2263 clientchar_t *pathp;
2264 smb_tran2Packet_t *outp;
2269 cm_scache_t *dscp; /* dir we're dealing with */
2270 cm_scache_t *scp; /* file we're creating */
2272 int initialModeBits;
2275 clientchar_t *lastNamep;
2282 int parmSlot; /* which parm we're dealing with */
2283 long returnEALength;
2284 clientchar_t *tidPathp;
2292 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2293 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2295 openFun = p->parmsp[6]; /* open function */
2296 excl = ((openFun & 3) == 0);
2297 trunc = ((openFun & 3) == 2); /* truncate it */
2298 openMode = (p->parmsp[1] & 0x7);
2299 openAction = 0; /* tracks what we did */
2301 attributes = p->parmsp[3];
2302 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2304 /* compute initial mode bits based on read-only flag in attributes */
2305 initialModeBits = 0666;
2306 if (attributes & SMB_ATTR_READONLY)
2307 initialModeBits &= ~0222;
2309 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
2312 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2314 spacep = cm_GetSpace();
2315 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2318 (cm_ClientStrCmpI(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
2319 cm_ClientStrCmpI(lastNamep, _C("\\srvsvc")) == 0 ||
2320 cm_ClientStrCmpI(lastNamep, _C("\\wkssvc")) == 0 ||
2321 cm_ClientStrCmpI(lastNamep, _C("\\ipc$")) == 0)) {
2322 /* special case magic file name for receiving IOCTL requests
2323 * (since IOCTL calls themselves aren't getting through).
2325 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2326 smb_SetupIoctlFid(fidp, spacep);
2328 /* copy out remainder of the parms */
2330 outp->parmsp[parmSlot++] = fidp->fid;
2332 outp->parmsp[parmSlot++] = 0; /* attrs */
2333 outp->parmsp[parmSlot++] = 0; /* mod time */
2334 outp->parmsp[parmSlot++] = 0;
2335 outp->parmsp[parmSlot++] = 0; /* len */
2336 outp->parmsp[parmSlot++] = 0x7fff;
2337 outp->parmsp[parmSlot++] = openMode;
2338 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2339 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2341 /* and the final "always present" stuff */
2342 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2343 /* next write out the "unique" ID */
2344 outp->parmsp[parmSlot++] = 0x1234;
2345 outp->parmsp[parmSlot++] = 0x5678;
2346 outp->parmsp[parmSlot++] = 0;
2347 if (returnEALength) {
2348 outp->parmsp[parmSlot++] = 0;
2349 outp->parmsp[parmSlot++] = 0;
2352 outp->totalData = 0;
2353 outp->totalParms = parmSlot * 2;
2355 smb_SendTran2Packet(vcp, outp, op);
2357 smb_FreeTran2Packet(outp);
2359 /* and clean up fid reference */
2360 smb_ReleaseFID(fidp);
2364 if (!cm_IsValidClientString(pathp)) {
2366 clientchar_t * hexp;
2368 hexp = cm_GetRawCharsAlloc(pathp, -1);
2369 osi_Log1(smb_logp, "Tran2Open rejecting invalid name. [%S]",
2370 osi_LogSaveClientString(smb_logp, hexp));
2374 osi_Log0(smb_logp, "Tran2Open rejecting invalid name");
2376 smb_FreeTran2Packet(outp);
2377 return CM_ERROR_BADNTFILENAME;
2380 #ifdef DEBUG_VERBOSE
2382 char *hexp, *asciip;
2383 asciip = (lastNamep ? lastNamep : pathp);
2384 hexp = osi_HexifyString( asciip );
2385 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2390 userp = smb_GetTran2User(vcp, p);
2391 /* In the off chance that userp is NULL, we log and abandon */
2393 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2394 smb_FreeTran2Packet(outp);
2395 return CM_ERROR_BADSMB;
2398 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2399 if (code == CM_ERROR_TIDIPC) {
2400 /* Attempt to use a TID allocated for IPC. The client
2401 * is probably looking for DCE RPC end points which we
2402 * don't support OR it could be looking to make a DFS
2405 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2407 cm_ReleaseUser(userp);
2408 smb_FreeTran2Packet(outp);
2409 return CM_ERROR_NOSUCHPATH;
2414 code = cm_NameI(cm_data.rootSCachep, pathp,
2415 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2416 userp, tidPathp, &req, &scp);
2418 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2419 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2420 userp, tidPathp, &req, &dscp);
2421 cm_FreeSpace(spacep);
2424 cm_ReleaseUser(userp);
2425 smb_FreeTran2Packet(outp);
2430 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2431 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2432 (clientchar_t*) spacep->data);
2433 cm_ReleaseSCache(dscp);
2434 cm_ReleaseUser(userp);
2435 smb_FreeTran2Packet(outp);
2436 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2437 return CM_ERROR_PATH_NOT_COVERED;
2439 return CM_ERROR_BADSHARENAME;
2441 #endif /* DFS_SUPPORT */
2443 /* otherwise, scp points to the parent directory. Do a lookup,
2444 * and truncate the file if we find it, otherwise we create the
2451 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2453 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2454 cm_ReleaseSCache(dscp);
2455 cm_ReleaseUser(userp);
2456 smb_FreeTran2Packet(outp);
2461 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2462 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2463 cm_ReleaseSCache(scp);
2464 cm_ReleaseUser(userp);
2465 smb_FreeTran2Packet(outp);
2466 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2467 return CM_ERROR_PATH_NOT_COVERED;
2469 return CM_ERROR_BADSHARENAME;
2471 #endif /* DFS_SUPPORT */
2473 /* macintosh is expensive to program for it */
2474 cm_FreeSpace(spacep);
2477 /* if we get here, if code is 0, the file exists and is represented by
2478 * scp. Otherwise, we have to create it.
2481 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2484 cm_ReleaseSCache(dscp);
2485 cm_ReleaseSCache(scp);
2486 cm_ReleaseUser(userp);
2487 smb_FreeTran2Packet(outp);
2492 /* oops, file shouldn't be there */
2494 cm_ReleaseSCache(dscp);
2495 cm_ReleaseSCache(scp);
2496 cm_ReleaseUser(userp);
2497 smb_FreeTran2Packet(outp);
2498 return CM_ERROR_EXISTS;
2502 setAttr.mask = CM_ATTRMASK_LENGTH;
2503 setAttr.length.LowPart = 0;
2504 setAttr.length.HighPart = 0;
2505 code = cm_SetAttr(scp, &setAttr, userp, &req);
2506 openAction = 3; /* truncated existing file */
2509 openAction = 1; /* found existing file */
2511 else if (!(openFun & 0x10)) {
2512 /* don't create if not found */
2514 cm_ReleaseSCache(dscp);
2515 osi_assertx(scp == NULL, "null cm_scache_t");
2516 cm_ReleaseUser(userp);
2517 smb_FreeTran2Packet(outp);
2518 return CM_ERROR_NOSUCHFILE;
2521 osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2522 openAction = 2; /* created file */
2523 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2524 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2525 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2529 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2530 smb_NotifyChange(FILE_ACTION_ADDED,
2531 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2532 dscp, lastNamep, NULL, TRUE);
2533 } else if (!excl && code == CM_ERROR_EXISTS) {
2534 /* not an exclusive create, and someone else tried
2535 * creating it already, then we open it anyway. We
2536 * don't bother retrying after this, since if this next
2537 * fails, that means that the file was deleted after we
2538 * started this call.
2540 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2544 setAttr.mask = CM_ATTRMASK_LENGTH;
2545 setAttr.length.LowPart = 0;
2546 setAttr.length.HighPart = 0;
2547 code = cm_SetAttr(scp, &setAttr, userp,
2550 } /* lookup succeeded */
2554 /* we don't need this any longer */
2556 cm_ReleaseSCache(dscp);
2559 /* something went wrong creating or truncating the file */
2561 cm_ReleaseSCache(scp);
2562 cm_ReleaseUser(userp);
2563 smb_FreeTran2Packet(outp);
2567 /* make sure we're about to open a file */
2568 if (scp->fileType != CM_SCACHETYPE_FILE) {
2570 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2571 cm_scache_t * targetScp = 0;
2572 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2574 /* we have a more accurate file to use (the
2575 * target of the symbolic link). Otherwise,
2576 * we'll just use the symlink anyway.
2578 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2580 cm_ReleaseSCache(scp);
2584 if (scp->fileType != CM_SCACHETYPE_FILE) {
2585 cm_ReleaseSCache(scp);
2586 cm_ReleaseUser(userp);
2587 smb_FreeTran2Packet(outp);
2588 return CM_ERROR_ISDIR;
2592 /* now all we have to do is open the file itself */
2593 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2594 osi_assertx(fidp, "null smb_fid_t");
2597 lock_ObtainMutex(&fidp->mx);
2598 /* save a pointer to the vnode */
2599 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2601 lock_ObtainWrite(&scp->rw);
2602 scp->flags |= CM_SCACHEFLAG_SMB_FID;
2603 lock_ReleaseWrite(&scp->rw);
2606 fidp->userp = userp;
2608 /* compute open mode */
2610 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
2611 if (openMode == 1 || openMode == 2)
2612 fidp->flags |= SMB_FID_OPENWRITE;
2614 /* remember that the file was newly created */
2616 fidp->flags |= SMB_FID_CREATED;
2618 lock_ReleaseMutex(&fidp->mx);
2620 smb_ReleaseFID(fidp);
2622 cm_Open(scp, 0, userp);
2624 /* copy out remainder of the parms */
2626 outp->parmsp[parmSlot++] = fidp->fid;
2627 lock_ObtainRead(&scp->rw);
2629 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2630 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2631 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2632 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2633 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2634 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2635 outp->parmsp[parmSlot++] = openMode;
2636 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2637 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2639 /* and the final "always present" stuff */
2640 outp->parmsp[parmSlot++] = openAction;
2641 /* next write out the "unique" ID */
2642 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2643 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2644 outp->parmsp[parmSlot++] = 0;
2645 if (returnEALength) {
2646 outp->parmsp[parmSlot++] = 0;
2647 outp->parmsp[parmSlot++] = 0;
2649 lock_ReleaseRead(&scp->rw);
2650 outp->totalData = 0; /* total # of data bytes */
2651 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2653 smb_SendTran2Packet(vcp, outp, op);
2655 smb_FreeTran2Packet(outp);
2657 cm_ReleaseUser(userp);
2658 /* leave scp held since we put it in fidp->scp */
2662 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2665 unsigned short infolevel;
2667 infolevel = p->parmsp[0];
2669 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2671 return CM_ERROR_BAD_LEVEL;
2674 /* TRANS2_QUERY_FS_INFORMATION */
2675 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2677 smb_tran2Packet_t *outp;
2678 smb_tran2QFSInfo_t qi;
2682 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2684 switch (p->parmsp[0]) {
2685 case SMB_INFO_ALLOCATION:
2687 responseSize = sizeof(qi.u.allocInfo);
2689 qi.u.allocInfo.FSID = 0;
2690 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2691 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2692 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2693 qi.u.allocInfo.bytesPerSector = 1024;
2696 case SMB_INFO_VOLUME:
2698 qi.u.volumeInfo.vsn = 1234; /* Volume serial number */
2699 qi.u.volumeInfo.vnCount = 3; /* Number of characters in label (AFS\0)*/
2701 /* we're supposed to pad it out with zeroes to the end */
2702 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2703 smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
2705 responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
2708 case SMB_QUERY_FS_VOLUME_INFO:
2709 /* FS volume info */
2710 responseSize = sizeof(qi.u.FSvolumeInfo);
2713 FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
2714 memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
2717 qi.u.FSvolumeInfo.vsn = 1234;
2718 qi.u.FSvolumeInfo.vnCount = 6; /* This is always in Unicode */
2719 memset(&qi.u.FSvolumeInfo.label, 0, sizeof(qi.u.FSvolumeInfo.label));
2720 memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
2723 case SMB_QUERY_FS_SIZE_INFO:
2725 responseSize = sizeof(qi.u.FSsizeInfo);
2727 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2728 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2729 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2730 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2731 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2732 qi.u.FSsizeInfo.bytesPerSector = 1024;
2735 case SMB_QUERY_FS_DEVICE_INFO:
2736 /* FS device info */
2737 responseSize = sizeof(qi.u.FSdeviceInfo);
2739 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2740 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2743 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2744 /* FS attribute info */
2746 /* attributes, defined in WINNT.H:
2747 * FILE_CASE_SENSITIVE_SEARCH 0x1
2748 * FILE_CASE_PRESERVED_NAMES 0x2
2749 * FILE_UNICODE_ON_DISK 0x4
2750 * FILE_VOLUME_QUOTAS 0x10
2751 * <no name defined> 0x4000
2752 * If bit 0x4000 is not set, Windows 95 thinks
2753 * we can't handle long (non-8.3) names,
2754 * despite our protestations to the contrary.
2756 qi.u.FSattributeInfo.attributes = 0x4003;
2757 /* The maxCompLength is supposed to be in bytes */
2759 qi.u.FSattributeInfo.attributes |= 0x04;
2761 qi.u.FSattributeInfo.maxCompLength = 255;
2762 smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
2763 qi.u.FSattributeInfo.FSnameLength = sz;
2766 sizeof(qi.u.FSattributeInfo.attributes) +
2767 sizeof(qi.u.FSattributeInfo.maxCompLength) +
2768 sizeof(qi.u.FSattributeInfo.FSnameLength) +
2773 case SMB_INFO_UNIX: /* CIFS Unix Info */
2774 case SMB_INFO_MACOS: /* Mac FS Info */
2776 return CM_ERROR_BADOP;
2779 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2781 /* copy out return data, and set corresponding sizes */
2782 outp->totalParms = 0;
2783 outp->totalData = responseSize;
2784 memcpy(outp->datap, &qi, responseSize);
2786 /* send and free the packets */
2787 smb_SendTran2Packet(vcp, outp, op);
2788 smb_FreeTran2Packet(outp);
2793 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2795 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2796 return CM_ERROR_BADOP;
2799 struct smb_ShortNameRock {
2800 clientchar_t *maskp;
2802 clientchar_t *shortName;
2803 size_t shortNameLen;
2806 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2809 struct smb_ShortNameRock *rockp;
2810 normchar_t normName[MAX_PATH];
2811 clientchar_t *shortNameEnd;
2815 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t)) == 0) {
2816 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
2817 osi_LogSaveString(smb_logp, dep->name));
2821 /* compare both names and vnodes, though probably just comparing vnodes
2822 * would be safe enough.
2824 if (cm_NormStrCmpI(normName, rockp->maskp) != 0)
2826 if (ntohl(dep->fid.vnode) != rockp->vnode)
2829 /* This is the entry */
2830 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2831 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2833 return CM_ERROR_STOPNOW;
2836 long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
2837 clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
2839 struct smb_ShortNameRock rock;
2840 clientchar_t *lastNamep;
2843 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2847 spacep = cm_GetSpace();
2848 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2850 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2851 caseFold, userp, tidPathp,
2853 cm_FreeSpace(spacep);
2858 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2859 cm_ReleaseSCache(dscp);
2860 cm_ReleaseUser(userp);
2864 return CM_ERROR_PATH_NOT_COVERED;
2866 #endif /* DFS_SUPPORT */
2868 if (!lastNamep) lastNamep = pathp;
2871 thyper.HighPart = 0;
2872 rock.shortName = shortName;
2874 rock.maskp = lastNamep;
2875 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2877 cm_ReleaseSCache(dscp);
2880 return CM_ERROR_NOSUCHFILE;
2881 if (code == CM_ERROR_STOPNOW) {
2882 *shortNameLenp = rock.shortNameLen;
2888 /* TRANS2_QUERY_PATH_INFORMATION */
2889 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2891 smb_tran2Packet_t *outp;
2894 unsigned short infoLevel;
2895 smb_tran2QPathInfo_t qpi;
2897 unsigned short attributes;
2898 unsigned long extAttributes;
2899 clientchar_t shortName[13];
2903 cm_scache_t *scp, *dscp;
2904 int scp_rw_held = 0;
2907 clientchar_t *pathp;
2908 clientchar_t *tidPathp;
2909 clientchar_t *lastComp;
2914 infoLevel = p->parmsp[0];
2915 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2917 else if (infoLevel == SMB_INFO_STANDARD)
2918 responseSize = sizeof(qpi.u.QPstandardInfo);
2919 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2920 responseSize = sizeof(qpi.u.QPeaSizeInfo);
2921 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2922 responseSize = sizeof(qpi.u.QPfileBasicInfo);
2923 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2924 responseSize = sizeof(qpi.u.QPfileStandardInfo);
2925 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2926 responseSize = sizeof(qpi.u.QPfileEaInfo);
2927 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2928 responseSize = sizeof(qpi.u.QPfileNameInfo);
2929 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
2930 responseSize = sizeof(qpi.u.QPfileAllInfo);
2931 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2932 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2934 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2935 p->opcode, infoLevel);
2936 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
2940 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
2941 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %S", infoLevel,
2942 osi_LogSaveClientString(smb_logp, pathp));
2944 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2946 if (infoLevel > 0x100)
2947 outp->totalParms = 2;
2949 outp->totalParms = 0;
2950 outp->totalData = responseSize;
2952 /* now, if we're at infoLevel 6, we're only being asked to check
2953 * the syntax, so we just OK things now. In particular, we're *not*
2954 * being asked to verify anything about the state of any parent dirs.
2956 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2957 smb_SendTran2Packet(vcp, outp, opx);
2958 smb_FreeTran2Packet(outp);
2962 userp = smb_GetTran2User(vcp, p);
2964 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2965 smb_FreeTran2Packet(outp);
2966 return CM_ERROR_BADSMB;
2969 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2971 cm_ReleaseUser(userp);
2972 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2973 smb_FreeTran2Packet(outp);
2978 * XXX Strange hack XXX
2980 * As of Patch 7 (13 January 98), we are having the following problem:
2981 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2982 * requests to look up "desktop.ini" in all the subdirectories.
2983 * This can cause zillions of timeouts looking up non-existent cells
2984 * and volumes, especially in the top-level directory.
2986 * We have not found any way to avoid this or work around it except
2987 * to explicitly ignore the requests for mount points that haven't
2988 * yet been evaluated and for directories that haven't yet been
2991 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2992 spacep = cm_GetSpace();
2993 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
2994 #ifndef SPECIAL_FOLDERS
2995 /* Make sure that lastComp is not NULL */
2997 if (cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
2998 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3002 userp, tidPathp, &req, &dscp);
3005 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3006 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3008 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3009 code = CM_ERROR_PATH_NOT_COVERED;
3011 code = CM_ERROR_BADSHARENAME;
3013 #endif /* DFS_SUPPORT */
3014 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3015 code = CM_ERROR_NOSUCHFILE;
3016 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3017 cm_buf_t *bp = buf_Find(dscp, &hzero);
3023 code = CM_ERROR_NOSUCHFILE;
3025 cm_ReleaseSCache(dscp);
3027 cm_FreeSpace(spacep);
3028 cm_ReleaseUser(userp);
3029 smb_SendTran2Error(vcp, p, opx, code);
3030 smb_FreeTran2Packet(outp);
3036 #endif /* SPECIAL_FOLDERS */
3038 cm_FreeSpace(spacep);
3041 /* now do namei and stat, and copy out the info */
3042 code = cm_NameI(cm_data.rootSCachep, pathp,
3043 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3046 cm_ReleaseUser(userp);
3047 smb_SendTran2Error(vcp, p, opx, code);
3048 smb_FreeTran2Packet(outp);
3053 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3054 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3055 cm_ReleaseSCache(scp);
3056 cm_ReleaseUser(userp);
3057 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3058 code = CM_ERROR_PATH_NOT_COVERED;
3060 code = CM_ERROR_BADSHARENAME;
3061 smb_SendTran2Error(vcp, p, opx, code);
3062 smb_FreeTran2Packet(outp);
3065 #endif /* DFS_SUPPORT */
3067 lock_ObtainWrite(&scp->rw);
3069 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3070 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3074 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3076 lock_ConvertWToR(&scp->rw);
3081 /* now we have the status in the cache entry, and everything is locked.
3082 * Marshall the output data.
3084 /* for info level 108, figure out short name */
3085 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3086 code = cm_GetShortName(pathp, userp, &req,
3087 tidPathp, scp->fid.vnode, shortName,
3093 smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
3094 qpi.u.QPfileAltNameInfo.fileNameLength = len;
3098 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3099 smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3100 qpi.u.QPfileNameInfo.fileNameLength = len;
3104 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3105 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3106 qpi.u.QPstandardInfo.creationDateTime = dosTime;
3107 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3108 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3109 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3110 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3111 attributes = smb_Attributes(scp);
3112 qpi.u.QPstandardInfo.attributes = attributes;
3113 qpi.u.QPstandardInfo.eaSize = 0;
3115 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3116 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3117 qpi.u.QPfileBasicInfo.creationTime = ft;
3118 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3119 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3120 qpi.u.QPfileBasicInfo.changeTime = ft;
3121 extAttributes = smb_ExtAttributes(scp);
3122 qpi.u.QPfileBasicInfo.attributes = extAttributes;
3123 qpi.u.QPfileBasicInfo.reserved = 0;
3125 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3128 lock_ReleaseRead(&scp->rw);
3130 fidp = smb_FindFIDByScache(vcp, scp);
3132 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3133 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3134 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3135 qpi.u.QPfileStandardInfo.directory =
3136 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3137 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3138 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3139 qpi.u.QPfileStandardInfo.reserved = 0;
3142 lock_ObtainMutex(&fidp->mx);
3143 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3144 lock_ReleaseMutex(&fidp->mx);
3145 smb_ReleaseFID(fidp);
3147 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3149 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3150 qpi.u.QPfileEaInfo.eaSize = 0;
3152 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3153 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3154 qpi.u.QPfileAllInfo.creationTime = ft;
3155 qpi.u.QPfileAllInfo.lastAccessTime = ft;
3156 qpi.u.QPfileAllInfo.lastWriteTime = ft;
3157 qpi.u.QPfileAllInfo.changeTime = ft;
3158 extAttributes = smb_ExtAttributes(scp);
3159 qpi.u.QPfileAllInfo.attributes = extAttributes;
3160 qpi.u.QPfileAllInfo.allocationSize = scp->length;
3161 qpi.u.QPfileAllInfo.endOfFile = scp->length;
3162 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3163 qpi.u.QPfileAllInfo.deletePending = 0;
3164 qpi.u.QPfileAllInfo.directory =
3165 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3166 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3167 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3168 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
3169 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
3170 qpi.u.QPfileAllInfo.eaSize = 0;
3171 qpi.u.QPfileAllInfo.accessFlags = 0;
3172 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
3173 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
3174 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3175 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3176 qpi.u.QPfileAllInfo.mode = 0;
3177 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3179 smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3180 qpi.u.QPfileAllInfo.fileNameLength = len;
3183 /* send and free the packets */
3185 switch (scp_rw_held) {
3187 lock_ReleaseRead(&scp->rw);
3190 lock_ReleaseWrite(&scp->rw);
3194 cm_ReleaseSCache(scp);
3195 cm_ReleaseUser(userp);
3197 memcpy(outp->datap, &qpi, responseSize);
3198 smb_SendTran2Packet(vcp, outp, opx);
3200 smb_SendTran2Error(vcp, p, opx, code);
3202 smb_FreeTran2Packet(outp);
3207 /* TRANS2_SET_PATH_INFORMATION */
3208 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3211 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
3212 return CM_ERROR_BADOP;
3216 unsigned short infoLevel;
3217 clientchar_t * pathp;
3218 smb_tran2Packet_t *outp;
3219 smb_tran2QPathInfo_t *spi;
3221 cm_scache_t *scp, *dscp;
3224 clientchar_t *tidPathp;
3225 clientchar_t *lastComp;
3229 infoLevel = p->parmsp[0];
3230 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
3231 if (infoLevel != SMB_INFO_STANDARD &&
3232 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
3233 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
3234 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3235 p->opcode, infoLevel);
3236 smb_SendTran2Error(vcp, p, opx,
3237 infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3241 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3243 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
3244 osi_LogSaveClientString(smb_logp, pathp));
3246 userp = smb_GetTran2User(vcp, p);
3248 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3249 code = CM_ERROR_BADSMB;
3253 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3254 if (code == CM_ERROR_TIDIPC) {
3255 /* Attempt to use a TID allocated for IPC. The client
3256 * is probably looking for DCE RPC end points which we
3257 * don't support OR it could be looking to make a DFS
3260 osi_Log0(smb_logp, "Tran2Open received IPC TID");
3261 cm_ReleaseUser(userp);
3262 return CM_ERROR_NOSUCHPATH;
3266 * XXX Strange hack XXX
3268 * As of Patch 7 (13 January 98), we are having the following problem:
3269 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3270 * requests to look up "desktop.ini" in all the subdirectories.
3271 * This can cause zillions of timeouts looking up non-existent cells
3272 * and volumes, especially in the top-level directory.
3274 * We have not found any way to avoid this or work around it except
3275 * to explicitly ignore the requests for mount points that haven't
3276 * yet been evaluated and for directories that haven't yet been
3279 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3280 spacep = cm_GetSpace();
3281 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3282 #ifndef SPECIAL_FOLDERS
3283 /* Make sure that lastComp is not NULL */
3285 if (cm_ClientStrCmpI(lastComp, _C("\\desktop.ini")) == 0) {
3286 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3290 userp, tidPathp, &req, &dscp);
3293 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3294 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3296 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3297 code = CM_ERROR_PATH_NOT_COVERED;
3299 code = CM_ERROR_BADSHARENAME;
3301 #endif /* DFS_SUPPORT */
3302 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3303 code = CM_ERROR_NOSUCHFILE;
3304 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3305 cm_buf_t *bp = buf_Find(dscp, &hzero);
3311 code = CM_ERROR_NOSUCHFILE;
3313 cm_ReleaseSCache(dscp);
3315 cm_FreeSpace(spacep);
3316 cm_ReleaseUser(userp);
3317 smb_SendTran2Error(vcp, p, opx, code);
3323 #endif /* SPECIAL_FOLDERS */
3325 cm_FreeSpace(spacep);
3328 /* now do namei and stat, and copy out the info */
3329 code = cm_NameI(cm_data.rootSCachep, pathp,
3330 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3332 cm_ReleaseUser(userp);
3333 smb_SendTran2Error(vcp, p, opx, code);
3337 fidp = smb_FindFIDByScache(vcp, scp);
3339 cm_ReleaseSCache(scp);
3340 cm_ReleaseUser(userp);
3341 smb_SendTran2Error(vcp, p, opx, code);
3345 lock_ObtainMutex(&fidp->mx);
3346 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
3347 lock_ReleaseMutex(&fidp->mx);
3348 cm_ReleaseSCache(scp);
3349 smb_ReleaseFID(fidp);
3350 cm_ReleaseUser(userp);
3351 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3354 lock_ReleaseMutex(&fidp->mx);
3356 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3358 outp->totalParms = 2;
3359 outp->totalData = 0;
3361 spi = (smb_tran2QPathInfo_t *)p->datap;
3362 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3365 /* lock the vnode with a callback; we need the current status
3366 * to determine what the new status is, in some cases.
3368 lock_ObtainWrite(&scp->rw);
3369 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3370 CM_SCACHESYNC_GETSTATUS
3371 | CM_SCACHESYNC_NEEDCALLBACK);
3373 lock_ReleaseWrite(&scp->rw);
3376 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3378 lock_ReleaseWrite(&scp->rw);
3379 lock_ObtainMutex(&fidp->mx);
3380 lock_ObtainRead(&scp->rw);
3382 /* prepare for setattr call */
3383 attr.mask = CM_ATTRMASK_LENGTH;
3384 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3385 attr.length.HighPart = 0;
3387 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3388 smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3389 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3390 fidp->flags |= SMB_FID_MTIMESETDONE;
3393 if (spi->u.QPstandardInfo.attributes != 0) {
3394 if ((scp->unixModeBits & 0222)
3395 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3396 /* make a writable file read-only */
3397 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3398 attr.unixModeBits = scp->unixModeBits & ~0222;
3400 else if ((scp->unixModeBits & 0222) == 0
3401 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3402 /* make a read-only file writable */
3403 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3404 attr.unixModeBits = scp->unixModeBits | 0222;
3407 lock_ReleaseRead(&scp->rw);
3408 lock_ReleaseMutex(&fidp->mx);
3412 code = cm_SetAttr(scp, &attr, userp, &req);
3416 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3417 /* we don't support EAs */
3418 code = CM_ERROR_EAS_NOT_SUPPORTED;
3422 cm_ReleaseSCache(scp);
3423 cm_ReleaseUser(userp);
3424 smb_ReleaseFID(fidp);
3426 smb_SendTran2Packet(vcp, outp, opx);
3428 smb_SendTran2Error(vcp, p, opx, code);
3429 smb_FreeTran2Packet(outp);
3435 /* TRANS2_QUERY_FILE_INFORMATION */
3436 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3438 smb_tran2Packet_t *outp;
3440 unsigned long attributes;
3441 unsigned short infoLevel;
3448 smb_tran2QFileInfo_t qfi;
3456 fidp = smb_FindFID(vcp, fid, 0);
3459 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3463 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3464 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3465 smb_CloseFID(vcp, fidp, NULL, 0);
3466 smb_ReleaseFID(fidp);
3470 infoLevel = p->parmsp[1];
3471 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3472 responseSize = sizeof(qfi.u.QFbasicInfo);
3473 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3474 responseSize = sizeof(qfi.u.QFstandardInfo);
3475 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3476 responseSize = sizeof(qfi.u.QFeaInfo);
3477 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3478 responseSize = sizeof(qfi.u.QFfileNameInfo);
3480 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3481 p->opcode, infoLevel);
3482 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3483 smb_ReleaseFID(fidp);
3486 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3488 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3490 if (infoLevel > 0x100)
3491 outp->totalParms = 2;
3493 outp->totalParms = 0;
3494 outp->totalData = responseSize;
3496 userp = smb_GetTran2User(vcp, p);
3498 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3499 code = CM_ERROR_BADSMB;
3503 lock_ObtainMutex(&fidp->mx);
3504 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3506 osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3508 lock_ReleaseMutex(&fidp->mx);
3509 lock_ObtainWrite(&scp->rw);
3510 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3511 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3515 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3517 lock_ConvertWToR(&scp->rw);
3520 /* now we have the status in the cache entry, and everything is locked.
3521 * Marshall the output data.
3523 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3524 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3525 qfi.u.QFbasicInfo.creationTime = ft;
3526 qfi.u.QFbasicInfo.lastAccessTime = ft;
3527 qfi.u.QFbasicInfo.lastWriteTime = ft;
3528 qfi.u.QFbasicInfo.lastChangeTime = ft;
3529 attributes = smb_ExtAttributes(scp);
3530 qfi.u.QFbasicInfo.attributes = attributes;
3532 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3533 qfi.u.QFstandardInfo.allocationSize = scp->length;
3534 qfi.u.QFstandardInfo.endOfFile = scp->length;
3535 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3536 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3537 qfi.u.QFstandardInfo.directory =
3538 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3539 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3540 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3542 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3543 qfi.u.QFeaInfo.eaSize = 0;
3545 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3549 lock_ReleaseRead(&scp->rw);
3550 lock_ObtainMutex(&fidp->mx);
3551 lock_ObtainRead(&scp->rw);
3552 if (fidp->NTopen_wholepathp)
3553 name = fidp->NTopen_wholepathp;
3555 name = _C("\\"); /* probably can't happen */
3556 lock_ReleaseMutex(&fidp->mx);
3558 smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, SMB_STRF_IGNORENUL);
3559 outp->totalData = len + 4; /* this is actually what we want to return */
3560 qfi.u.QFfileNameInfo.fileNameLength = len;
3563 /* send and free the packets */
3566 lock_ReleaseRead(&scp->rw);
3568 lock_ReleaseWrite(&scp->rw);
3569 cm_ReleaseSCache(scp);
3570 cm_ReleaseUser(userp);
3571 smb_ReleaseFID(fidp);
3573 memcpy(outp->datap, &qfi, responseSize);
3574 smb_SendTran2Packet(vcp, outp, opx);
3576 smb_SendTran2Error(vcp, p, opx, code);
3578 smb_FreeTran2Packet(outp);
3584 /* TRANS2_SET_FILE_INFORMATION */
3585 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3590 unsigned short infoLevel;
3591 smb_tran2Packet_t *outp;
3592 cm_user_t *userp = NULL;
3593 cm_scache_t *scp = NULL;
3599 fidp = smb_FindFID(vcp, fid, 0);
3602 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3606 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3607 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3608 smb_CloseFID(vcp, fidp, NULL, 0);
3609 smb_ReleaseFID(fidp);
3613 infoLevel = p->parmsp[1];
3614 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3615 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3616 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3617 p->opcode, infoLevel);
3618 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3619 smb_ReleaseFID(fidp);
3623 lock_ObtainMutex(&fidp->mx);
3624 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
3625 !(fidp->flags & SMB_FID_OPENDELETE)) {
3626 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3627 fidp, fidp->scp, fidp->flags);
3628 lock_ReleaseMutex(&fidp->mx);
3629 smb_ReleaseFID(fidp);
3630 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3633 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3634 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3635 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3636 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3637 fidp, fidp->scp, fidp->flags);
3638 lock_ReleaseMutex(&fidp->mx);
3639 smb_ReleaseFID(fidp);
3640 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3645 osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3647 lock_ReleaseMutex(&fidp->mx);
3649 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3651 outp->totalParms = 2;
3652 outp->totalData = 0;
3654 userp = smb_GetTran2User(vcp, p);
3656 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3657 code = CM_ERROR_BADSMB;
3661 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3663 unsigned int attribute;
3665 smb_tran2QFileInfo_t *sfi;
3667 sfi = (smb_tran2QFileInfo_t *)p->datap;
3669 /* lock the vnode with a callback; we need the current status
3670 * to determine what the new status is, in some cases.
3672 lock_ObtainWrite(&scp->rw);
3673 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3674 CM_SCACHESYNC_GETSTATUS
3675 | CM_SCACHESYNC_NEEDCALLBACK);
3677 lock_ReleaseWrite(&scp->rw);
3681 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3683 lock_ReleaseWrite(&scp->rw);
3684 lock_ObtainMutex(&fidp->mx);
3685 lock_ObtainRead(&scp->rw);
3687 /* prepare for setattr call */
3690 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3691 /* when called as result of move a b, lastMod is (-1, -1).
3692 * If the check for -1 is not present, timestamp
3693 * of the resulting file will be 1969 (-1)
3695 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3696 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3697 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3698 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3699 fidp->flags |= SMB_FID_MTIMESETDONE;
3702 attribute = sfi->u.QFbasicInfo.attributes;
3703 if (attribute != 0) {
3704 if ((scp->unixModeBits & 0222)
3705 && (attribute & SMB_ATTR_READONLY) != 0) {
3706 /* make a writable file read-only */
3707 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3708 attr.unixModeBits = scp->unixModeBits & ~0222;
3710 else if ((scp->unixModeBits & 0222) == 0
3711 && (attribute & SMB_ATTR_READONLY) == 0) {
3712 /* make a read-only file writable */
3713 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3714 attr.unixModeBits = scp->unixModeBits | 0222;
3717 lock_ReleaseRead(&scp->rw);
3718 lock_ReleaseMutex(&fidp->mx);
3722 code = cm_SetAttr(scp, &attr, userp, &req);
3726 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3727 int delflag = *((char *)(p->datap));
3728 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
3729 delflag, fidp, scp);
3730 if (*((char *)(p->datap))) { /* File is Deleted */
3731 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3734 lock_ObtainMutex(&fidp->mx);
3735 fidp->flags |= SMB_FID_DELONCLOSE;
3736 lock_ReleaseMutex(&fidp->mx);
3738 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
3744 lock_ObtainMutex(&fidp->mx);
3745 fidp->flags &= ~SMB_FID_DELONCLOSE;
3746 lock_ReleaseMutex(&fidp->mx);
3749 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3750 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3751 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3754 attr.mask = CM_ATTRMASK_LENGTH;
3755 attr.length.LowPart = size.LowPart;
3756 attr.length.HighPart = size.HighPart;
3757 code = cm_SetAttr(scp, &attr, userp, &req);
3761 cm_ReleaseSCache(scp);
3762 cm_ReleaseUser(userp);
3763 smb_ReleaseFID(fidp);
3765 smb_SendTran2Packet(vcp, outp, opx);
3767 smb_SendTran2Error(vcp, p, opx, code);
3768 smb_FreeTran2Packet(outp);
3775 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3777 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3778 return CM_ERROR_BADOP;
3783 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3785 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3786 return CM_ERROR_BADOP;
3789 /* TRANS2_FIND_NOTIFY_FIRST */
3791 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3793 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3794 return CM_ERROR_BADOP;
3797 /* TRANS2_FIND_NOTIFY_NEXT */
3799 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3801 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3802 return CM_ERROR_BADOP;
3805 /* TRANS2_CREATE_DIRECTORY */
3807 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3809 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3810 return CM_ERROR_BADOP;
3813 /* TRANS2_SESSION_SETUP */
3815 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3817 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3818 return CM_ERROR_BADOP;
3821 struct smb_v2_referral {
3823 USHORT ReferralFlags;
3826 USHORT DfsPathOffset;
3827 USHORT DfsAlternativePathOffset;
3828 USHORT NetworkAddressOffset;
3831 /* TRANS2_GET_DFS_REFERRAL */
3833 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3835 /* This is a UNICODE only request (bit15 of Flags2) */
3836 /* The TID must be IPC$ */
3838 /* The documentation for the Flags response field is contradictory */
3840 /* Use Version 1 Referral Element Format */
3841 /* ServerType = 0; indicates the next server should be queried for the file */
3842 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3843 /* Node = UnicodeString of UNC path of the next share name */
3846 int maxReferralLevel = 0;
3847 clientchar_t requestFileName[1024] = _C("");
3848 clientchar_t referralPath[1024] = _C("");
3849 smb_tran2Packet_t *outp = 0;
3850 cm_user_t *userp = 0;
3851 cm_scache_t *scp = 0;
3852 cm_scache_t *dscp = 0;
3854 CPINFO CodePageInfo;
3855 int i, nbnLen, reqLen, refLen;
3860 maxReferralLevel = p->parmsp[0];
3862 GetCPInfo(CP_ACP, &CodePageInfo);
3863 cm_Utf16ToClientString(&p->parmsp[1], -1, requestFileName, lengthof(requestFileName));
3865 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%S]",
3866 maxReferralLevel, osi_LogSaveClientString(smb_logp, requestFileName));
3868 nbnLen = (int)cm_ClientStrLen(cm_NetbiosNameC);
3869 reqLen = (int)cm_ClientStrLen(requestFileName);
3871 if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
3872 !cm_ClientStrCmpNI(cm_NetbiosNameC, &requestFileName[1], nbnLen) &&
3873 requestFileName[nbnLen+1] == '\\')
3877 if (!cm_ClientStrCmpNI(_C("all"), &requestFileName[nbnLen+2], 3) ||
3878 !cm_ClientStrCmpNI(_C("*."), &requestFileName[nbnLen+2], 2)) {
3880 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
3883 userp = smb_GetTran2User(vcp, p);
3885 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3886 code = CM_ERROR_BADSMB;
3891 * We have a requested path. Check to see if it is something
3894 * But be careful because the name that we might be searching
3895 * for might be a known name with the final character stripped
3898 code = cm_NameI(cm_data.rootSCachep, &requestFileName[nbnLen+2],
3899 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
3900 userp, NULL, &req, &scp);
3904 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
3906 } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
3907 clientchar_t temp[1024];
3908 clientchar_t pathName[1024];
3909 clientchar_t *lastComponent;
3911 * we have a msdfs link somewhere in the path
3912 * we should figure out where in the path the link is.
3915 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%S]", requestFileName);
3917 cm_ClientStrCpy(temp, lengthof(temp), &requestFileName[nbnLen+2]);
3921 cm_ReleaseSCache(dscp);
3925 cm_ReleaseSCache(scp);
3928 smb_StripLastComponent(pathName, &lastComponent, temp);
3930 code = cm_NameI(cm_data.rootSCachep, pathName,
3931 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3932 userp, NULL, &req, &dscp);
3934 code = cm_NameI(dscp, ++lastComponent,
3936 userp, NULL, &req, &scp);
3937 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK)
3940 } while (code == CM_ERROR_PATH_NOT_COVERED);
3942 /* scp should now be the DfsLink we are looking for */
3944 /* figure out how much of the input path was used */
3945 reqLen = (int)(nbnLen+2 + cm_ClientStrLen(pathName) + 1 + cm_ClientStrLen(lastComponent));
3947 cm_FsStringToClientString(&scp->mountPointStringp[strlen("msdfs:")], -1,
3948 referralPath, lengthof(referralPath));
3949 refLen = (int)cm_ClientStrLen(referralPath);
3953 clientchar_t shareName[MAX_PATH + 1];
3954 clientchar_t *p, *q;
3955 /* we may have a sharename that is a volume reference */
3957 for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
3963 if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
3964 code = cm_NameI(cm_data.rootSCachep, _C(""),
3965 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
3966 userp, p, &req, &scp);
3971 cm_ClientStrCpy(referralPath, lengthof(referralPath),
3982 struct smb_v2_referral * v2ref;
3983 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (refLen + 8));
3985 sp = (USHORT *)outp->datap;
3987 sp[idx++] = reqLen; /* path consumed */
3988 sp[idx++] = 1; /* number of referrals */
3989 sp[idx++] = 0x03; /* flags */
3990 #ifdef DFS_VERSION_1
3991 sp[idx++] = 1; /* Version Number */
3992 sp[idx++] = refLen + 4; /* Referral Size */
3993 sp[idx++] = 1; /* Type = SMB Server */
3994 sp[idx++] = 0; /* Do not strip path consumed */
3995 for ( i=0;i<=refLen; i++ )
3996 sp[i+idx] = referralPath[i];
3997 #else /* DFS_VERSION_2 */
3998 sp[idx++] = 2; /* Version Number */
3999 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
4000 idx += (sizeof(struct smb_v2_referral) / 2);
4001 v2ref = (struct smb_v2_referral *) &sp[5];
4002 v2ref->ServerType = 1; /* SMB Server */
4003 v2ref->ReferralFlags = 0x03;
4004 v2ref->Proximity = 0; /* closest */
4005 v2ref->TimeToLive = 3600; /* seconds */
4006 v2ref->DfsPathOffset = idx * 2;
4007 v2ref->DfsAlternativePathOffset = idx * 2;
4008 v2ref->NetworkAddressOffset = 0;
4009 for ( i=0;i<=refLen; i++ )
4010 sp[i+idx] = referralPath[i];
4014 code = CM_ERROR_NOSUCHPATH;
4019 cm_ReleaseSCache(dscp);
4021 cm_ReleaseSCache(scp);
4023 cm_ReleaseUser(userp);
4025 smb_SendTran2Packet(vcp, outp, op);
4027 smb_SendTran2Error(vcp, p, op, code);
4029 smb_FreeTran2Packet(outp);
4032 #else /* DFS_SUPPORT */
4033 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
4034 return CM_ERROR_NOSUCHDEVICE;
4035 #endif /* DFS_SUPPORT */
4038 /* TRANS2_REPORT_DFS_INCONSISTENCY */
4040 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4042 /* This is a UNICODE only request (bit15 of Flags2) */
4044 /* There is nothing we can do about this operation. The client is going to
4045 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
4046 * Unfortunately, there is really nothing we can do about it other then log it
4047 * somewhere. Even then I don't think there is anything for us to do.
4048 * So let's return an error value.
4051 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
4052 return CM_ERROR_BADOP;
4056 smb_ApplyV3DirListPatches(cm_scache_t *dscp, smb_dirListPatch_t **dirPatchespp,
4057 clientchar_t * tidPathp, clientchar_t * relPathp,
4058 int infoLevel, cm_user_t *userp, cm_req_t *reqp)
4062 cm_scache_t *targetScp; /* target if scp is a symlink */
4065 unsigned short attr;
4066 unsigned long lattr;
4067 smb_dirListPatch_t *patchp;
4068 smb_dirListPatch_t *npatchp;
4070 afs_int32 mustFake = 0;
4071 clientchar_t path[AFSPATHMAX];
4073 code = cm_FindACLCache(dscp, userp, &rights);
4075 lock_ObtainWrite(&dscp->rw);
4076 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4077 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4079 cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4080 lock_ReleaseWrite(&dscp->rw);
4081 if (code == CM_ERROR_NOACCESS) {
4089 if (!mustFake) { /* Bulk Stat */
4091 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4093 memset(bsp, 0, sizeof(cm_bulkStat_t));
4095 for (patchp = *dirPatchespp, count=0;
4097 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4098 cm_scache_t *tscp = NULL;
4101 code = cm_GetSCache(&patchp->fid, &tscp, userp, reqp);
4103 if (lock_TryWrite(&tscp->rw)) {
4104 /* we have an entry that we can look at */
4105 #ifdef AFS_FREELANCE_CLIENT
4106 if (dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID && dscp->fid.volume == AFS_FAKE_ROOT_VOL_ID) {
4107 code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
4108 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4110 cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4112 lock_ReleaseWrite(&tscp->rw);
4113 cm_ReleaseSCache(tscp);
4116 #endif /* AFS_FREELANCE_CLIENT */
4117 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4118 /* we have a callback on it. Don't bother
4119 * fetching this stat entry, since we're happy
4120 * with the info we have.
4122 lock_ReleaseWrite(&tscp->rw);
4123 cm_ReleaseSCache(tscp);
4126 lock_ReleaseWrite(&tscp->rw);
4128 cm_ReleaseSCache(tscp);
4132 bsp->fids[i].Volume = patchp->fid.volume;
4133 bsp->fids[i].Vnode = patchp->fid.vnode;
4134 bsp->fids[i].Unique = patchp->fid.unique;
4136 if (bsp->counter == AFSCBMAX) {
4137 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4138 memset(bsp, 0, sizeof(cm_bulkStat_t));
4142 if (bsp->counter > 0)
4143 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4148 for( patchp = *dirPatchespp;
4150 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4151 cm_ClientStrPrintfN(path, lengthof(path),_C("%s\\%S"),
4152 relPathp ? relPathp : _C(""), patchp->dep->name);
4153 reqp->relPathp = path;
4154 reqp->tidPathp = tidPathp;
4156 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4157 reqp->relPathp = reqp->tidPathp = NULL;
4161 lock_ObtainWrite(&scp->rw);
4162 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4163 lock_ReleaseWrite(&scp->rw);
4165 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4166 errors in the client. */
4167 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4168 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4170 /* 1969-12-31 23:59:59 +00 */
4171 ft.dwHighDateTime = 0x19DB200;
4172 ft.dwLowDateTime = 0x5BB78980;
4174 /* copy to Creation Time */
4175 fa->creationTime = ft;
4176 fa->lastAccessTime = ft;
4177 fa->lastWriteTime = ft;
4178 fa->lastChangeTime = ft;
4180 switch (scp->fileType) {
4181 case CM_SCACHETYPE_DIRECTORY:
4182 case CM_SCACHETYPE_MOUNTPOINT:
4183 case CM_SCACHETYPE_INVALID:
4184 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4186 case CM_SCACHETYPE_SYMLINK:
4187 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4188 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4190 fa->extFileAttributes = SMB_ATTR_NORMAL;
4193 /* if we get here we either have a normal file
4194 * or we have a file for which we have never
4195 * received status info. In this case, we can
4196 * check the even/odd value of the entry's vnode.
4197 * odd means it is to be treated as a directory
4198 * and even means it is to be treated as a file.
4200 if (mustFake && (scp->fid.vnode & 0x1))
4201 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4203 fa->extFileAttributes = SMB_ATTR_NORMAL;
4205 /* merge in hidden attribute */
4206 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4207 fa->extFileAttributes |= SMB_ATTR_HIDDEN;
4210 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4212 /* 1969-12-31 23:59:58 +00*/
4213 dosTime = 0xEBBFBF7D;
4215 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4216 fa->lastAccessDateTime = fa->creationDateTime;
4217 fa->lastWriteDateTime = fa->creationDateTime;
4219 /* set the attribute */
4220 switch (scp->fileType) {
4221 case CM_SCACHETYPE_DIRECTORY:
4222 case CM_SCACHETYPE_MOUNTPOINT:
4223 case CM_SCACHETYPE_INVALID:
4224 fa->attributes = SMB_ATTR_DIRECTORY;
4226 case CM_SCACHETYPE_SYMLINK:
4227 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4228 fa->attributes = SMB_ATTR_DIRECTORY;
4230 fa->attributes = SMB_ATTR_NORMAL;
4233 /* if we get here we either have a normal file
4234 * or we have a file for which we have never
4235 * received status info. In this case, we can
4236 * check the even/odd value of the entry's vnode.
4237 * even means it is to be treated as a directory
4238 * and odd means it is to be treated as a file.
4240 if (mustFake && (scp->fid.vnode & 0x1))
4241 fa->attributes = SMB_ATTR_DIRECTORY;
4243 fa->attributes = SMB_ATTR_NORMAL;
4246 /* merge in hidden (dot file) attribute */
4247 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4248 fa->attributes |= SMB_ATTR_HIDDEN;
4252 cm_ReleaseSCache(scp);
4256 /* now watch for a symlink */
4258 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
4259 lock_ReleaseWrite(&scp->rw);
4260 cm_ClientStrPrintfN(path, lengthof(path), _C("%s\\%S"),
4261 relPathp ? relPathp : _C(""), patchp->dep->name);
4262 reqp->relPathp = path;
4263 reqp->tidPathp = tidPathp;
4264 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
4265 reqp->relPathp = reqp->tidPathp = NULL;
4267 /* we have a more accurate file to use (the
4268 * target of the symbolic link). Otherwise,
4269 * we'll just use the symlink anyway.
4271 osi_Log2(smb_logp, "symlink vp %x to vp %x",
4273 cm_ReleaseSCache(scp);
4276 lock_ObtainWrite(&scp->rw);
4279 lock_ConvertWToR(&scp->rw);
4281 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4282 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4285 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4287 fa->creationTime = ft;
4288 fa->lastAccessTime = ft;
4289 fa->lastWriteTime = ft;
4290 fa->lastChangeTime = ft;
4292 /* Use length for both file length and alloc length */
4293 fa->endOfFile = scp->length;
4294 fa->allocationSize = scp->length;
4296 /* Copy attributes */
4297 lattr = smb_ExtAttributes(scp);
4298 if ((code == CM_ERROR_NOSUCHPATH &&
4299 (scp->fileType == CM_SCACHETYPE_SYMLINK &&
4300 cm_TargetPerceivedAsDirectory(scp->mountPointStringp))) ||
4301 code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4302 if (lattr == SMB_ATTR_NORMAL)
4303 lattr = SMB_ATTR_DIRECTORY;
4305 lattr |= SMB_ATTR_DIRECTORY;
4307 /* merge in hidden (dot file) attribute */
4308 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4309 if (lattr == SMB_ATTR_NORMAL)
4310 lattr = SMB_ATTR_HIDDEN;
4312 lattr |= SMB_ATTR_HIDDEN;
4315 fa->extFileAttributes = lattr;
4317 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4320 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4322 fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
4323 fa->lastAccessDateTime = fa->creationDateTime;
4324 fa->lastWriteDateTime = fa->creationDateTime;
4326 /* copy out file length and alloc length,
4327 * using the same for both
4329 fa->dataSize = scp->length.LowPart;
4330 fa->allocationSize = scp->length.LowPart;
4332 /* finally copy out attributes as short */
4333 attr = smb_Attributes(scp);
4334 /* merge in hidden (dot file) attribute */
4335 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4336 if (lattr == SMB_ATTR_NORMAL)
4337 lattr = SMB_ATTR_HIDDEN;
4339 lattr |= SMB_ATTR_HIDDEN;
4341 fa->attributes = attr;
4344 lock_ReleaseRead(&scp->rw);
4345 cm_ReleaseSCache(scp);
4348 /* now free the patches */
4349 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4350 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4354 /* and mark the list as empty */
4355 *dirPatchespp = NULL;
4361 /* smb_ReceiveTran2SearchDir implements both
4362 * Tran2_Find_First and Tran2_Find_Next
4364 #define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
4365 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
4366 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
4367 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
4368 #define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
4370 /* this is an optimized handler for T2SearchDir that handles the case
4371 where there are no wildcards in the search path. I.e. an
4372 application is using FindFirst(Ex) to get information about a
4373 single file or directory. It will attempt to do a single lookup.
4374 If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4375 the usual mechanism.
4377 This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4379 TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
4381 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4385 long code = 0, code2 = 0;
4386 clientchar_t *pathp = 0;
4388 smb_dirListPatch_t *dirListPatchesp;
4389 smb_dirListPatch_t *curPatchp;
4390 size_t orbytes; /* # of bytes in this output record */
4391 size_t ohbytes; /* # of bytes, except file name */
4392 size_t onbytes; /* # of bytes in name, incl. term. null */
4393 cm_scache_t *scp = NULL;
4394 cm_scache_t *targetscp = NULL;
4395 cm_user_t *userp = NULL;
4396 char *op; /* output data ptr */
4397 char *origOp; /* original value of op */
4398 cm_space_t *spacep; /* for pathname buffer */
4399 unsigned long maxReturnData; /* max # of return data */
4400 long maxReturnParms; /* max # of return parms */
4401 long bytesInBuffer; /* # data bytes in the output buffer */
4402 clientchar_t *maskp; /* mask part of path */
4406 smb_tran2Packet_t *outp; /* response packet */
4407 clientchar_t *tidPathp = 0;
4409 clientchar_t shortName[13]; /* 8.3 name if needed */
4411 clientchar_t *shortNameEnd;
4412 cm_dirEntry_t * dep = NULL;
4415 void * attrp = NULL;
4416 smb_tran2Find_t * fp;
4421 osi_assertx(p->opcode == 1, "invalid opcode");
4423 /* find first; obtain basic parameters from request */
4425 /* note that since we are going to failover to regular
4426 * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4427 * modify any of the input parameters here. */
4428 attribute = p->parmsp[0];
4429 maxCount = p->parmsp[1];
4430 infoLevel = p->parmsp[3];
4431 searchFlags = p->parmsp[2];
4432 pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4434 maskp = cm_ClientStrRChr(pathp, '\\');
4438 maskp++; /* skip over backslash */
4439 /* track if this is likely to match a lot of entries */
4441 osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%S], mask[%S]",
4442 osi_LogSaveClientString(smb_logp, pathp),
4443 osi_LogSaveClientString(smb_logp, maskp));
4445 switch ( infoLevel ) {
4446 case SMB_INFO_STANDARD:
4448 ohbytes = sizeof(fp->u.FstandardInfo);
4451 case SMB_INFO_QUERY_EA_SIZE:
4452 ohbytes = sizeof(fp->u.FeaSizeInfo);
4453 s = "InfoQueryEaSize";
4456 case SMB_INFO_QUERY_EAS_FROM_LIST:
4457 ohbytes = sizeof(fp->u.FeasFromListInfo);
4458 s = "InfoQueryEasFromList";
4461 case SMB_FIND_FILE_DIRECTORY_INFO:
4462 s = "FindFileDirectoryInfo";
4463 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4466 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4467 s = "FindFileFullDirectoryInfo";
4468 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4471 case SMB_FIND_FILE_NAMES_INFO:
4472 s = "FindFileNamesInfo";
4473 ohbytes = sizeof(fp->u.FfileNamesInfo);
4476 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4477 s = "FindFileBothDirectoryInfo";
4478 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4482 s = "unknownInfoLevel";
4486 osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
4489 "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4490 attribute, infoLevel, maxCount, searchFlags);
4493 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4494 return CM_ERROR_INVAL;
4497 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4498 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4500 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4503 dirListPatchesp = NULL;
4505 maxReturnData = p->maxReturnData;
4506 maxReturnParms = 10; /* return params for findfirst, which
4507 is the only one we handle.*/
4509 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4512 osi_Log2(smb_logp, "T2SDSingle search dir count %d [%S]",
4513 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4515 /* bail out if request looks bad */
4517 smb_FreeTran2Packet(outp);
4518 return CM_ERROR_BADSMB;
4521 userp = smb_GetTran2User(vcp, p);
4523 osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
4524 smb_FreeTran2Packet(outp);
4525 return CM_ERROR_BADSMB;
4528 /* try to get the vnode for the path name next */
4529 spacep = cm_GetSpace();
4530 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4531 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4533 cm_ReleaseUser(userp);
4534 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4535 smb_FreeTran2Packet(outp);
4539 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4540 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4541 userp, tidPathp, &req, &scp);
4542 cm_FreeSpace(spacep);
4545 cm_ReleaseUser(userp);
4546 smb_SendTran2Error(vcp, p, opx, code);
4547 smb_FreeTran2Packet(outp);
4551 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4552 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4553 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
4554 cm_ReleaseSCache(scp);
4555 cm_ReleaseUser(userp);
4556 if ( WANTS_DFS_PATHNAMES(p) || pnc )
4557 code = CM_ERROR_PATH_NOT_COVERED;
4559 code = CM_ERROR_BADSHARENAME;
4560 smb_SendTran2Error(vcp, p, opx, code);
4561 smb_FreeTran2Packet(outp);
4564 #endif /* DFS_SUPPORT */
4565 osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
4567 /* now do a single case sensitive lookup for the file in question */
4568 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
4570 /* if a case sensitive match failed, we try a case insensitive one
4572 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
4573 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
4576 if (code == 0 && targetscp->fid.vnode == 0) {
4577 cm_ReleaseSCache(targetscp);
4578 code = CM_ERROR_NOSUCHFILE;
4582 /* if we can't find the directory entry, this block will
4583 return CM_ERROR_NOSUCHFILE, which we will pass on to
4584 smb_ReceiveTran2SearchDir(). */
4585 cm_ReleaseSCache(scp);
4586 cm_ReleaseUser(userp);
4587 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4588 smb_SendTran2Error(vcp, p, opx, code);
4591 smb_FreeTran2Packet(outp);
4595 /* now that we have the target in sight, we proceed with filling
4596 up the return data. */
4598 op = origOp = outp->datap;
4601 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4602 /* skip over resume key */
4606 fp = (smb_tran2Find_t *) op;
4608 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4609 && targetscp->fid.vnode != 0
4610 && !cm_Is8Dot3(maskp)) {
4613 dfid.vnode = htonl(targetscp->fid.vnode);
4614 dfid.unique = htonl(targetscp->fid.unique);
4616 cm_Gen8Dot3NameIntW(maskp, &dfid, shortName, &shortNameEnd);
4622 osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %S (%S)",
4623 htonl(targetscp->fid.vnode),
4624 htonl(targetscp->fid.unique),
4625 osi_LogSaveClientString(smb_logp, pathp),
4626 (NeedShortName)? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
4628 /* Eliminate entries that don't match requested attributes */
4629 if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
4630 smb_IsDotFile(maskp)) {
4632 code = CM_ERROR_NOSUCHFILE;
4633 osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
4638 if (!(attribute & SMB_ATTR_DIRECTORY) &&
4639 (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
4640 targetscp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4641 targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
4642 targetscp->fileType == CM_SCACHETYPE_INVALID)) {
4644 code = CM_ERROR_NOSUCHFILE;
4645 osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
4650 /* add header to name & term. null */
4652 smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
4653 orbytes = ohbytes + onbytes;
4655 /* now, we round up the record to a 4 byte alignment, and we make
4656 * sure that we have enough room here for even the aligned version
4657 * (so we don't have to worry about an * overflow when we pad
4658 * things out below). That's the reason for the alignment
4661 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4662 align = (4 - (orbytes & 3)) & 3;
4666 if (orbytes + align > maxReturnData) {
4668 /* even though this request is unlikely to succeed with a
4669 failover, we do it anyway. */
4670 code = CM_ERROR_NOSUCHFILE;
4671 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4676 /* this is one of the entries to use: it is not deleted and it
4677 * matches the star pattern we're looking for. Put out the name,
4678 * preceded by its length.
4680 /* First zero everything else */
4681 memset(origOp, 0, orbytes);
4684 smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
4686 switch (infoLevel) {
4687 case SMB_INFO_STANDARD:
4688 fp->u.FstandardInfo.fileNameLength = onbytes;
4689 attrp = &fp->u.FstandardInfo.fileAttrs;
4692 case SMB_INFO_QUERY_EA_SIZE:
4693 fp->u.FeaSizeInfo.fileNameLength = onbytes;
4694 attrp = &fp->u.FeaSizeInfo.fileAttrs;
4695 fp->u.FeaSizeInfo.eaSize = 0;
4698 case SMB_INFO_QUERY_EAS_FROM_LIST:
4699 fp->u.FeasFromListInfo.fileNameLength = onbytes;
4700 attrp = &fp->u.FeasFromListInfo.fileAttrs;
4701 fp->u.FeasFromListInfo.eaSize = 0;
4704 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4705 if (NeedShortName) {
4709 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
4710 fp->u.FfileBothDirectoryInfo.shortName,
4711 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
4713 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
4715 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
4716 fp->u.FfileBothDirectoryInfo.reserved = 0;
4718 strcpy(fp->u.FfileBothDirectoryInfo.shortName,
4720 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
4725 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4726 fp->u.FfileFullDirectoryInfo.eaSize = 0;
4729 case SMB_FIND_FILE_DIRECTORY_INFO:
4730 fp->u.FfileDirectoryInfo.nextEntryOffset = 0;
4731 fp->u.FfileDirectoryInfo.fileIndex = 0;
4732 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
4733 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
4736 case SMB_FIND_FILE_NAMES_INFO:
4737 fp->u.FfileNamesInfo.nextEntryOffset = 0;
4738 fp->u.FfileNamesInfo.fileIndex = 0;
4739 fp->u.FfileNamesInfo.fileNameLength = onbytes;
4743 /* we shouldn't hit this case */
4744 osi_assertx(FALSE, "Unknown query type");
4747 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4748 osi_assert(attrp != NULL);
4750 curPatchp = malloc(sizeof(*curPatchp));
4751 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4753 curPatchp->dptr = attrp;
4755 if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
4756 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4758 curPatchp->flags = 0;
4761 cm_SetFid(&curPatchp->fid, targetscp->fid.cell, targetscp->fid.volume, targetscp->fid.vnode, targetscp->fid.unique);
4765 int namelen = cm_ClientStringToFsString(maskp, -1, NULL, 0);
4766 dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+namelen);
4767 cm_ClientStringToFsString(maskp, -1, dep->name, namelen);
4769 dep->fid.vnode = targetscp->fid.vnode;
4770 dep->fid.unique = targetscp->fid.unique;
4771 curPatchp->dep = dep;
4774 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4775 /* put out resume key */
4776 *((u_long *)origOp) = 0;
4779 /* Adjust byte ptr and count */
4780 origOp += orbytes; /* skip entire record */
4781 bytesInBuffer += orbytes;
4783 /* and pad the record out */
4784 while (--align >= 0) {
4789 /* apply the patches */
4790 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->wdata, infoLevel, userp, &req);
4792 outp->parmsp[0] = 0;
4793 outp->parmsp[1] = 1; /* number of names returned */
4794 outp->parmsp[2] = 1; /* end of search */
4795 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4796 outp->parmsp[4] = 0;
4798 outp->totalParms = 10; /* in bytes */
4800 outp->totalData = bytesInBuffer;
4802 osi_Log0(smb_logp, "T2SDSingle done.");
4804 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4806 smb_SendTran2Error(vcp, p, opx, code);
4808 smb_SendTran2Packet(vcp, outp, opx);
4813 smb_FreeTran2Packet(outp);
4817 cm_ReleaseSCache(scp);
4818 cm_ReleaseSCache(targetscp);
4819 cm_ReleaseUser(userp);
4825 /* TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2 */
4826 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4831 long code = 0, code2 = 0;
4832 clientchar_t *pathp;
4833 cm_dirEntry_t *dep = 0;
4835 smb_dirListPatch_t *dirListPatchesp = 0;
4836 smb_dirListPatch_t *curPatchp = 0;
4839 size_t orbytes; /* # of bytes in this output record */
4840 size_t ohbytes; /* # of bytes, except file name */
4841 size_t onbytes; /* # of bytes in name, incl. term. null */
4842 osi_hyper_t dirLength;
4843 osi_hyper_t bufferOffset;
4844 osi_hyper_t curOffset;
4846 smb_dirSearch_t *dsp;
4850 cm_pageHeader_t *pageHeaderp;
4851 cm_user_t *userp = NULL;
4854 long nextEntryCookie;
4855 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4856 char *op; /* output data ptr */
4857 char *origOp; /* original value of op */
4858 cm_space_t *spacep; /* for pathname buffer */
4859 unsigned long maxReturnData; /* max # of return data */
4860 unsigned long maxReturnParms; /* max # of return parms */
4861 long bytesInBuffer; /* # data bytes in the output buffer */
4863 clientchar_t *maskp; /* mask part of path */
4867 smb_tran2Packet_t *outp; /* response packet */
4868 clientchar_t *tidPathp;
4870 clientchar_t shortName[13]; /* 8.3 name if needed */
4873 clientchar_t *shortNameEnd;
4879 smb_tran2Find_t * fp;
4884 if (p->opcode == 1) {
4885 /* find first; obtain basic parameters from request */
4886 attribute = p->parmsp[0];
4887 maxCount = p->parmsp[1];
4888 infoLevel = p->parmsp[3];
4889 searchFlags = p->parmsp[2];
4890 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4892 maskp = cm_ClientStrRChr(pathp, '\\');
4896 maskp++; /* skip over backslash */
4898 /* track if this is likely to match a lot of entries */
4899 starPattern = smb_V3IsStarMask(maskp);
4901 #ifndef NOFINDFIRSTOPTIMIZE
4903 /* if this is for a single directory or file, we let the
4904 optimized routine handle it. The only error it
4905 returns is CM_ERROR_NOSUCHFILE. The */
4906 code = smb_T2SearchDirSingle(vcp, p, opx);
4908 /* we only failover if we see a CM_ERROR_NOSUCHFILE */
4909 if (code != CM_ERROR_NOSUCHFILE) {
4911 /* unless we are using the BPlusTree */
4912 if (code == CM_ERROR_BPLUS_NOMATCH)
4913 code = CM_ERROR_NOSUCHFILE;
4914 #endif /* USE_BPLUS */
4918 #endif /* NOFINDFIRSTOPTIMIZE */
4921 dsp = smb_NewDirSearch(1);
4922 dsp->attribute = attribute;
4923 cm_ClientStrCpy(dsp->mask, lengthof(dsp->mask), maskp); /* and save mask */
4926 osi_assertx(p->opcode == 2, "invalid opcode");
4927 /* find next; obtain basic parameters from request or open dir file */
4928 dsp = smb_FindDirSearch(p->parmsp[0]);
4929 maxCount = p->parmsp[1];
4930 infoLevel = p->parmsp[2];
4931 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4932 searchFlags = p->parmsp[5];
4934 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4935 p->parmsp[0], nextCookie);
4936 return CM_ERROR_BADFD;
4938 attribute = dsp->attribute;
4941 starPattern = 1; /* assume, since required a Find Next */
4944 switch ( infoLevel ) {
4945 case SMB_INFO_STANDARD:
4947 ohbytes = sizeof(fp->u.FstandardInfo);
4950 case SMB_INFO_QUERY_EA_SIZE:
4951 ohbytes = sizeof(fp->u.FeaSizeInfo);
4952 s = "InfoQueryEaSize";
4955 case SMB_INFO_QUERY_EAS_FROM_LIST:
4956 ohbytes = sizeof(fp->u.FeasFromListInfo);
4957 s = "InfoQueryEasFromList";
4960 case SMB_FIND_FILE_DIRECTORY_INFO:
4961 s = "FindFileDirectoryInfo";
4962 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4965 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4966 s = "FindFileFullDirectoryInfo";
4967 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4970 case SMB_FIND_FILE_NAMES_INFO:
4971 s = "FindFileNamesInfo";
4972 ohbytes = sizeof(fp->u.FfileNamesInfo);
4975 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4976 s = "FindFileBothDirectoryInfo";
4977 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4981 s = "unknownInfoLevel";
4985 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
4988 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4989 attribute, infoLevel, maxCount, searchFlags);
4991 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
4992 p->opcode, dsp->cookie, nextCookie);
4995 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4996 smb_ReleaseDirSearch(dsp);
4997 return CM_ERROR_INVAL;
5000 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5001 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
5003 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5006 dirListPatchesp = NULL;
5008 maxReturnData = p->maxReturnData;
5009 if (p->opcode == 1) /* find first */
5010 maxReturnParms = 10; /* bytes */
5012 maxReturnParms = 8; /* bytes */
5014 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
5020 osi_Log2(smb_logp, "T2 receive search dir count %d [%S]",
5021 maxCount, osi_LogSaveClientString(smb_logp, pathp));
5023 /* bail out if request looks bad */
5024 if (p->opcode == 1 && !pathp) {
5025 smb_ReleaseDirSearch(dsp);
5026 smb_FreeTran2Packet(outp);
5027 return CM_ERROR_BADSMB;
5030 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
5031 dsp->cookie, nextCookie, attribute);
5033 userp = smb_GetTran2User(vcp, p);
5035 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
5036 smb_ReleaseDirSearch(dsp);
5037 smb_FreeTran2Packet(outp);
5038 return CM_ERROR_BADSMB;
5041 /* try to get the vnode for the path name next */
5042 lock_ObtainMutex(&dsp->mx);
5045 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5049 spacep = cm_GetSpace();
5050 smb_StripLastComponent(spacep->wdata, NULL, pathp);
5051 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
5053 cm_ReleaseUser(userp);
5054 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
5055 smb_FreeTran2Packet(outp);
5056 lock_ReleaseMutex(&dsp->mx);
5057 smb_DeleteDirSearch(dsp);
5058 smb_ReleaseDirSearch(dsp);
5062 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
5063 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
5065 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
5066 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5067 userp, tidPathp, &req, &scp);
5068 cm_FreeSpace(spacep);
5071 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
5072 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5073 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
5074 cm_ReleaseSCache(scp);
5075 cm_ReleaseUser(userp);
5076 if ( WANTS_DFS_PATHNAMES(p) || pnc )
5077 code = CM_ERROR_PATH_NOT_COVERED;
5079 code = CM_ERROR_BADSHARENAME;
5080 smb_SendTran2Error(vcp, p, opx, code);
5081 smb_FreeTran2Packet(outp);
5082 lock_ReleaseMutex(&dsp->mx);
5083 smb_DeleteDirSearch(dsp);
5084 smb_ReleaseDirSearch(dsp);
5087 #endif /* DFS_SUPPORT */
5089 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5090 /* we need one hold for the entry we just stored into,
5091 * and one for our own processing. When we're done
5092 * with this function, we'll drop the one for our own
5093 * processing. We held it once from the namei call,
5094 * and so we do another hold now.
5097 dsp->flags |= SMB_DIRSEARCH_BULKST;
5100 lock_ReleaseMutex(&dsp->mx);
5102 cm_ReleaseUser(userp);
5103 smb_FreeTran2Packet(outp);
5104 smb_DeleteDirSearch(dsp);
5105 smb_ReleaseDirSearch(dsp);
5109 /* get the directory size */
5110 lock_ObtainWrite(&scp->rw);
5111 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5112 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5114 lock_ReleaseWrite(&scp->rw);
5115 cm_ReleaseSCache(scp);
5116 cm_ReleaseUser(userp);
5117 smb_FreeTran2Packet(outp);
5118 smb_DeleteDirSearch(dsp);
5119 smb_ReleaseDirSearch(dsp);
5123 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5126 dirLength = scp->length;
5128 bufferOffset.LowPart = bufferOffset.HighPart = 0;
5129 curOffset.HighPart = 0;
5130 curOffset.LowPart = nextCookie;
5131 origOp = outp->datap;
5138 normchar_t normName[MAX_PATH]; /* Normalized name */
5139 clientchar_t cfileName[MAX_PATH]; /* Non-normalized name */
5142 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5143 /* skip over resume key */
5146 fp = (smb_tran2Find_t *) op;
5148 /* make sure that curOffset.LowPart doesn't point to the first
5149 * 32 bytes in the 2nd through last dir page, and that it doesn't
5150 * point at the first 13 32-byte chunks in the first dir page,
5151 * since those are dir and page headers, and don't contain useful
5154 temp = curOffset.LowPart & (2048-1);
5155 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5156 /* we're in the first page */
5157 if (temp < 13*32) temp = 13*32;
5160 /* we're in a later dir page */
5161 if (temp < 32) temp = 32;
5164 /* make sure the low order 5 bits are zero */
5167 /* now put temp bits back ito curOffset.LowPart */
5168 curOffset.LowPart &= ~(2048-1);
5169 curOffset.LowPart |= temp;
5171 /* check if we've passed the dir's EOF */
5172 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
5173 osi_Log0(smb_logp, "T2 search dir passed eof");
5178 /* check if we've returned all the names that will fit in the
5179 * response packet; we check return count as well as the number
5180 * of bytes requested. We check the # of bytes after we find
5181 * the dir entry, since we'll need to check its size.
5183 if (returnedNames >= maxCount) {
5184 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
5185 returnedNames, maxCount);
5189 /* when we have obtained as many entries as can be processed in
5190 * a single Bulk Status call to the file server, apply the dir listing
5193 if (returnedNames > 0 && returnedNames % AFSCBMAX == 0) {
5194 lock_ReleaseWrite(&scp->rw);
5195 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5196 dsp->relPath, infoLevel, userp, &req);
5197 lock_ObtainWrite(&scp->rw);
5199 /* Then check to see if we have time left to process more entries */
5200 if (GetTickCount() - req.startTime > (RDRtimeout - 15) * 1000) {
5201 osi_Log0(smb_logp, "T2 search dir RDRtimeout exceeded");
5205 /* see if we can use the bufferp we have now; compute in which
5206 * page the current offset would be, and check whether that's
5207 * the offset of the buffer we have. If not, get the buffer.
5209 thyper.HighPart = curOffset.HighPart;
5210 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5211 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5214 buf_Release(bufferp);
5217 lock_ReleaseWrite(&scp->rw);
5218 code = buf_Get(scp, &thyper, &bufferp);
5219 lock_ObtainWrite(&scp->rw);
5221 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
5225 bufferOffset = thyper;
5227 /* now get the data in the cache */
5229 code = cm_SyncOp(scp, bufferp, userp, &req,
5231 CM_SCACHESYNC_NEEDCALLBACK
5232 | CM_SCACHESYNC_READ);
5234 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5238 if (cm_HaveBuffer(scp, bufferp, 0)) {
5239 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5240 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5244 /* otherwise, load the buffer and try again */
5245 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5247 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5249 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5250 scp, bufferp, code);
5255 buf_Release(bufferp);
5259 } /* if (wrong buffer) ... */
5261 /* now we have the buffer containing the entry we're interested
5262 * in; copy it out if it represents a non-deleted entry.
5264 entryInDir = curOffset.LowPart & (2048-1);
5265 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5267 /* page header will help tell us which entries are free. Page
5268 * header can change more often than once per buffer, since
5269 * AFS 3 dir page size may be less than (but not more than)
5270 * a buffer package buffer.
5272 /* only look intra-buffer */
5273 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5274 temp &= ~(2048 - 1); /* turn off intra-page bits */
5275 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5277 /* now determine which entry we're looking at in the page.
5278 * If it is free (there's a free bitmap at the start of the
5279 * dir), we should skip these 32 bytes.
5281 slotInPage = (entryInDir & 0x7e0) >> 5;
5282 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5283 (1 << (slotInPage & 0x7)))) {
5284 /* this entry is free */
5285 numDirChunks = 1; /* only skip this guy */
5289 tp = bufferp->datap + entryInBuffer;
5290 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5292 /* while we're here, compute the next entry's location, too,
5293 * since we'll need it when writing out the cookie into the dir
5296 * XXXX Probably should do more sanity checking.
5298 numDirChunks = cm_NameEntries(dep->name, &onbytes);
5300 /* compute offset of cookie representing next entry */
5301 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5303 if (dep->fid.vnode == 0)
5304 goto nextEntry; /* This entry is not in use */
5306 if (cm_FsStringToClientString(dep->name, -1, cfileName, lengthof(cfileName)) == 0 ||
5307 cm_ClientStringToNormString(cfileName, -1, normName, lengthof(normName)) == 0) {
5309 osi_Log1(smb_logp, "Skipping entry [%s]. Can't convert or normalize FS String",
5310 osi_LogSaveString(smb_logp, dep->name));
5314 /* Need 8.3 name? */
5316 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
5317 !cm_Is8Dot3(cfileName)) {
5318 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5322 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %S (%S)",
5323 dep->fid.vnode, dep->fid.unique,
5324 osi_LogSaveClientString(smb_logp, cfileName),
5325 NeedShortName ? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
5327 /* When matching, we are using doing a case fold if we have a wildcard mask.
5328 * If we get a non-wildcard match, it's a lookup for a specific file.
5330 if (cm_MatchMask(normName, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5331 (NeedShortName && cm_MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))
5333 /* Eliminate entries that don't match requested attributes */
5334 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5335 smb_IsDotFile(cfileName)) {
5336 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5337 goto nextEntry; /* no hidden files */
5340 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5342 /* We have already done the cm_TryBulkStat above */
5343 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume,
5344 ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5345 fileType = cm_FindFileType(&fid);
5346 /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5347 * "has filetype %d", dep->name, fileType);
5349 if ( fileType == CM_SCACHETYPE_DIRECTORY ||
5350 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5351 fileType == CM_SCACHETYPE_DFSLINK ||
5352 fileType == CM_SCACHETYPE_INVALID)
5353 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5357 /* finally check if this name will fit */
5359 smb_UnparseString(opx, NULL, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5360 orbytes = ohbytes + onbytes;
5362 /* now, we round up the record to a 4 byte alignment,
5363 * and we make sure that we have enough room here for
5364 * even the aligned version (so we don't have to worry
5365 * about an overflow when we pad things out below).
5366 * That's the reason for the alignment arithmetic below.
5368 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5369 align = (4 - (orbytes & 3)) & 3;
5373 if (orbytes + bytesInBuffer + align > maxReturnData) {
5374 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5379 /* this is one of the entries to use: it is not deleted
5380 * and it matches the star pattern we're looking for.
5381 * Put out the name, preceded by its length.
5383 /* First zero everything else */
5384 memset(origOp, 0, orbytes);
5387 smb_UnparseString(opx, origOp + ohbytes, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5389 switch (infoLevel) {
5390 case SMB_INFO_STANDARD:
5391 fp->u.FstandardInfo.fileNameLength = onbytes;
5392 attrp = &fp->u.FstandardInfo.fileAttrs;
5395 case SMB_INFO_QUERY_EA_SIZE:
5396 fp->u.FeaSizeInfo.fileNameLength = onbytes;
5397 attrp = &fp->u.FeaSizeInfo.fileAttrs;
5398 fp->u.FeaSizeInfo.eaSize = 0;
5401 case SMB_INFO_QUERY_EAS_FROM_LIST:
5402 fp->u.FeasFromListInfo.fileNameLength = onbytes;
5403 attrp = &fp->u.FeasFromListInfo.fileAttrs;
5404 fp->u.FeasFromListInfo.eaSize = 0;
5407 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5408 if (NeedShortName) {
5412 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
5413 fp->u.FfileBothDirectoryInfo.shortName,
5414 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
5416 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
5418 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5419 fp->u.FfileBothDirectoryInfo.reserved = 0;
5421 cm_ClientStrCpy(fp->u.FfileBothDirectoryInfo.shortName,
5422 lengthof(fp->u.FfileBothDirectoryInfo.shortName),
5424 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
5429 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5430 fp->u.FfileFullDirectoryInfo.eaSize = 0;
5433 case SMB_FIND_FILE_DIRECTORY_INFO:
5434 fp->u.FfileDirectoryInfo.nextEntryOffset = orbytes + align;
5435 fp->u.FfileDirectoryInfo.fileIndex = nextEntryCookie;
5436 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5437 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5440 case SMB_FIND_FILE_NAMES_INFO:
5441 fp->u.FfileNamesInfo.nextEntryOffset = orbytes + align;
5442 fp->u.FfileNamesInfo.fileIndex = nextEntryCookie;
5443 fp->u.FfileNamesInfo.fileNameLength = onbytes;
5448 /* we shouldn't hit this case */
5449 osi_assertx(FALSE, "Unknown query type");
5452 /* now, adjust the # of entries copied */
5455 /* now we emit the attribute. This is tricky, since
5456 * we need to really stat the file to find out what
5457 * type of entry we've got. Right now, we're copying
5458 * out data from a buffer, while holding the scp
5459 * locked, so it isn't really convenient to stat
5460 * something now. We'll put in a place holder
5461 * now, and make a second pass before returning this
5462 * to get the real attributes. So, we just skip the
5463 * data for now, and adjust it later. We allocate a
5464 * patch record to make it easy to find this point
5465 * later. The replay will happen at a time when it is
5466 * safe to unlock the directory.
5468 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5469 osi_assert(attrp != NULL);
5470 curPatchp = malloc(sizeof(*curPatchp));
5471 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5472 curPatchp->dptr = attrp;
5474 if (smb_hideDotFiles && smb_IsDotFile(cfileName)) {
5475 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5477 curPatchp->flags = 0;
5480 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5483 curPatchp->dep = dep;
5486 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5487 /* put out resume key */
5488 *((u_long *)origOp) = nextEntryCookie;
5490 /* Adjust byte ptr and count */
5491 origOp += orbytes; /* skip entire record */
5492 bytesInBuffer += orbytes;
5494 /* and pad the record out */
5495 while (align-- > 0) {
5499 } /* if we're including this name */
5500 else if (!starPattern &&
5502 cm_MatchMask(normName, maskp, CM_FLAG_CASEFOLD)) {
5503 /* We were looking for exact matches, but here's an inexact one*/
5508 /* and adjust curOffset to be where the new cookie is */
5509 thyper.HighPart = 0;
5510 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5511 curOffset = LargeIntegerAdd(thyper, curOffset);
5512 } /* while copying data for dir listing */
5514 /* If we didn't get a star pattern, we did an exact match during the first pass.
5515 * If there were no exact matches found, we fail over to inexact matches by
5516 * marking the query as a star pattern (matches all case permutations), and
5517 * re-running the query.
5519 if (returnedNames == 0 && !starPattern && foundInexact) {
5520 osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
5525 /* release the mutex */
5526 lock_ReleaseWrite(&scp->rw);
5528 buf_Release(bufferp);
5533 * Finally, process whatever entries we have left.
5535 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5536 dsp->relPath, infoLevel, userp, &req);
5538 /* now put out the final parameters */
5539 if (returnedNames == 0)
5541 if (p->opcode == 1) {
5543 outp->parmsp[0] = (unsigned short) dsp->cookie;
5544 outp->parmsp[1] = returnedNames;
5545 outp->parmsp[2] = eos;
5546 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5547 outp->parmsp[4] = 0;
5548 /* don't need last name to continue
5549 * search, cookie is enough. Normally,
5550 * this is the offset of the file name
5551 * of the last entry returned.
5553 outp->totalParms = 10; /* in bytes */
5557 outp->parmsp[0] = returnedNames;
5558 outp->parmsp[1] = eos;
5559 outp->parmsp[2] = 0; /* EAS error */
5560 outp->parmsp[3] = 0; /* last name, as above */
5561 outp->totalParms = 8; /* in bytes */
5564 /* return # of bytes in the buffer */
5565 outp->totalData = bytesInBuffer;
5567 /* Return error code if unsuccessful on first request */
5568 if (code == 0 && p->opcode == 1 && returnedNames == 0)
5569 code = CM_ERROR_NOSUCHFILE;
5571 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
5572 p->opcode, dsp->cookie, returnedNames, code);
5574 /* if we're supposed to close the search after this request, or if
5575 * we're supposed to close the search if we're done, and we're done,
5576 * or if something went wrong, close the search.
5578 if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
5579 (returnedNames == 0) ||
5580 ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
5582 smb_DeleteDirSearch(dsp);
5585 smb_SendTran2Error(vcp, p, opx, code);
5587 smb_SendTran2Packet(vcp, outp, opx);
5589 smb_FreeTran2Packet(outp);
5590 smb_ReleaseDirSearch(dsp);
5591 cm_ReleaseSCache(scp);
5592 cm_ReleaseUser(userp);
5596 /* SMB_COM_FIND_CLOSE2 */
5597 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5600 smb_dirSearch_t *dsp;
5602 dirHandle = smb_GetSMBParm(inp, 0);
5604 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
5606 dsp = smb_FindDirSearch(dirHandle);
5609 return CM_ERROR_BADFD;
5611 /* otherwise, we have an FD to destroy */
5612 smb_DeleteDirSearch(dsp);
5613 smb_ReleaseDirSearch(dsp);
5615 /* and return results */
5616 smb_SetSMBDataLength(outp, 0);
5622 /* SMB_COM_FIND_NOTIFY_CLOSE */
5623 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5625 smb_SetSMBDataLength(outp, 0);
5629 /* SMB_COM_OPEN_ANDX */
5630 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5632 clientchar_t *pathp;
5637 cm_scache_t *dscp; /* dir we're dealing with */
5638 cm_scache_t *scp; /* file we're creating */
5640 int initialModeBits;
5643 clientchar_t *lastNamep;
5644 unsigned long dosTime;
5650 int parmSlot; /* which parm we're dealing with */
5651 clientchar_t *tidPathp;
5659 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
5660 openFun = smb_GetSMBParm(inp, 8); /* open function */
5661 excl = ((openFun & 3) == 0);
5662 trunc = ((openFun & 3) == 2); /* truncate it */
5663 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
5664 openAction = 0; /* tracks what we did */
5666 attributes = smb_GetSMBParm(inp, 5);
5667 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
5669 /* compute initial mode bits based on read-only flag in attributes */
5670 initialModeBits = 0666;
5671 if (attributes & SMB_ATTR_READONLY)
5672 initialModeBits &= ~0222;
5674 pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
5677 spacep = inp->spacep;
5678 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5681 (cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
5682 cm_ClientStrCmpIA(lastNamep, _C("\\srvsvc")) == 0 ||
5683 cm_ClientStrCmpIA(lastNamep, _C("\\wkssvc")) == 0 ||
5684 cm_ClientStrCmpIA(lastNamep, _C("ipc$")) == 0)) {
5685 /* special case magic file name for receiving IOCTL requests
5686 * (since IOCTL calls themselves aren't getting through).
5689 osi_Log0(smb_logp, "IOCTL Open");
5692 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5693 smb_SetupIoctlFid(fidp, spacep);
5695 /* set inp->fid so that later read calls in same msg can find fid */
5696 inp->fid = fidp->fid;
5698 /* copy out remainder of the parms */
5700 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5702 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
5703 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
5704 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5705 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
5706 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
5707 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5708 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5709 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5711 /* and the final "always present" stuff */
5712 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
5713 /* next write out the "unique" ID */
5714 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
5715 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
5716 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5717 smb_SetSMBDataLength(outp, 0);
5719 /* and clean up fid reference */
5720 smb_ReleaseFID(fidp);
5724 if (!cm_IsValidClientString(pathp)) {
5726 clientchar_t * hexp;
5728 hexp = cm_GetRawCharsAlloc(pathp, -1);
5729 osi_Log1(smb_logp, "NTOpenX rejecting invalid name. [%S]",
5730 osi_LogSaveClientString(smb_logp, hexp));
5734 osi_Log0(smb_logp, "NTOpenX rejecting invalid name");
5736 return CM_ERROR_BADNTFILENAME;
5739 #ifdef DEBUG_VERBOSE
5741 char *hexp, *asciip;
5742 asciip = (lastNamep ? lastNamep : pathp );
5743 hexp = osi_HexifyString(asciip);
5744 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
5748 userp = smb_GetUserFromVCP(vcp, inp);
5751 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5753 cm_ReleaseUser(userp);
5754 return CM_ERROR_NOSUCHPATH;
5756 code = cm_NameI(cm_data.rootSCachep, pathp,
5757 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5758 userp, tidPathp, &req, &scp);
5761 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5762 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5763 cm_ReleaseSCache(scp);
5764 cm_ReleaseUser(userp);
5765 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5766 return CM_ERROR_PATH_NOT_COVERED;
5768 return CM_ERROR_BADSHARENAME;
5770 #endif /* DFS_SUPPORT */
5773 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
5774 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5775 userp, tidPathp, &req, &dscp);
5777 cm_ReleaseUser(userp);
5782 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5783 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5785 cm_ReleaseSCache(dscp);
5786 cm_ReleaseUser(userp);
5787 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5788 return CM_ERROR_PATH_NOT_COVERED;
5790 return CM_ERROR_BADSHARENAME;
5792 #endif /* DFS_SUPPORT */
5793 /* otherwise, scp points to the parent directory. Do a lookup,
5794 * and truncate the file if we find it, otherwise we create the
5801 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
5803 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5804 cm_ReleaseSCache(dscp);
5805 cm_ReleaseUser(userp);
5810 /* if we get here, if code is 0, the file exists and is represented by
5811 * scp. Otherwise, we have to create it. The dir may be represented
5812 * by dscp, or we may have found the file directly. If code is non-zero,
5816 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
5818 if (dscp) cm_ReleaseSCache(dscp);
5819 cm_ReleaseSCache(scp);
5820 cm_ReleaseUser(userp);
5825 /* oops, file shouldn't be there */
5827 cm_ReleaseSCache(dscp);
5828 cm_ReleaseSCache(scp);
5829 cm_ReleaseUser(userp);
5830 return CM_ERROR_EXISTS;
5834 setAttr.mask = CM_ATTRMASK_LENGTH;
5835 setAttr.length.LowPart = 0;
5836 setAttr.length.HighPart = 0;
5837 code = cm_SetAttr(scp, &setAttr, userp, &req);
5838 openAction = 3; /* truncated existing file */
5840 else openAction = 1; /* found existing file */
5842 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
5843 /* don't create if not found */
5844 if (dscp) cm_ReleaseSCache(dscp);
5845 cm_ReleaseUser(userp);
5846 return CM_ERROR_NOSUCHFILE;
5849 osi_assertx(dscp != NULL, "null cm_scache_t");
5850 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %S",
5851 osi_LogSaveClientString(smb_logp, lastNamep));
5852 openAction = 2; /* created file */
5853 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5854 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5855 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5859 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5860 smb_NotifyChange(FILE_ACTION_ADDED,
5861 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5862 dscp, lastNamep, NULL, TRUE);
5863 } else if (!excl && code == CM_ERROR_EXISTS) {
5864 /* not an exclusive create, and someone else tried
5865 * creating it already, then we open it anyway. We
5866 * don't bother retrying after this, since if this next
5867 * fails, that means that the file was deleted after we
5868 * started this call.
5870 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5874 setAttr.mask = CM_ATTRMASK_LENGTH;
5875 setAttr.length.LowPart = 0;
5876 setAttr.length.HighPart = 0;
5877 code = cm_SetAttr(scp, &setAttr, userp, &req);
5879 } /* lookup succeeded */
5883 /* we don't need this any longer */
5885 cm_ReleaseSCache(dscp);
5888 /* something went wrong creating or truncating the file */
5890 cm_ReleaseSCache(scp);
5891 cm_ReleaseUser(userp);
5895 /* make sure we're about to open a file */
5896 if (scp->fileType != CM_SCACHETYPE_FILE) {
5897 cm_ReleaseSCache(scp);
5898 cm_ReleaseUser(userp);
5899 return CM_ERROR_ISDIR;
5902 /* now all we have to do is open the file itself */
5903 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5904 osi_assertx(fidp, "null smb_fid_t");
5907 lock_ObtainMutex(&fidp->mx);
5908 /* save a pointer to the vnode */
5910 lock_ObtainWrite(&scp->rw);
5911 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5912 lock_ReleaseWrite(&scp->rw);
5913 osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
5915 fidp->userp = userp;
5917 /* compute open mode */
5919 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5920 if (openMode == 1 || openMode == 2)
5921 fidp->flags |= SMB_FID_OPENWRITE;
5923 /* remember if the file was newly created */
5925 fidp->flags |= SMB_FID_CREATED;
5927 lock_ReleaseMutex(&fidp->mx);
5928 smb_ReleaseFID(fidp);
5930 cm_Open(scp, 0, userp);
5932 /* set inp->fid so that later read calls in same msg can find fid */
5933 inp->fid = fidp->fid;
5935 /* copy out remainder of the parms */
5937 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5938 lock_ObtainRead(&scp->rw);
5940 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5941 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5942 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5943 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5944 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5945 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5946 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5947 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5948 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5950 /* and the final "always present" stuff */
5951 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5952 /* next write out the "unique" ID */
5953 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5954 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5955 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5956 lock_ReleaseRead(&scp->rw);
5957 smb_SetSMBDataLength(outp, 0);
5959 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5961 cm_ReleaseUser(userp);
5962 /* leave scp held since we put it in fidp->scp */
5966 static void smb_GetLockParams(unsigned char LockType,
5968 unsigned int * ppid,
5969 LARGE_INTEGER * pOffset,
5970 LARGE_INTEGER * pLength)
5972 if (LockType & LOCKING_ANDX_LARGE_FILES) {
5974 *ppid = *((USHORT *) *buf);
5975 pOffset->HighPart = *((LONG *)(*buf + 4));
5976 pOffset->LowPart = *((DWORD *)(*buf + 8));
5977 pLength->HighPart = *((LONG *)(*buf + 12));
5978 pLength->LowPart = *((DWORD *)(*buf + 16));
5982 /* Not Large Files */
5983 *ppid = *((USHORT *) *buf);
5984 pOffset->HighPart = 0;
5985 pOffset->LowPart = *((DWORD *)(*buf + 2));
5986 pLength->HighPart = 0;
5987 pLength->LowPart = *((DWORD *)(*buf + 6));
5992 /* SMB_COM_LOCKING_ANDX */
5993 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6000 unsigned char LockType;
6001 unsigned short NumberOfUnlocks, NumberOfLocks;
6005 LARGE_INTEGER LOffset, LLength;
6006 smb_waitingLockRequest_t *wlRequest = NULL;
6007 cm_file_lock_t *lockp;
6015 fid = smb_GetSMBParm(inp, 2);
6016 fid = smb_ChainFID(fid, inp);
6018 fidp = smb_FindFID(vcp, fid, 0);
6020 return CM_ERROR_BADFD;
6022 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6023 smb_CloseFID(vcp, fidp, NULL, 0);
6024 smb_ReleaseFID(fidp);
6025 return CM_ERROR_NOSUCHFILE;
6028 lock_ObtainMutex(&fidp->mx);
6029 if (fidp->flags & SMB_FID_IOCTL) {
6030 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
6031 lock_ReleaseMutex(&fidp->mx);
6032 smb_ReleaseFID(fidp);
6033 return CM_ERROR_BADFD;
6036 osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
6038 lock_ReleaseMutex(&fidp->mx);
6040 /* set inp->fid so that later read calls in same msg can find fid */
6043 userp = smb_GetUserFromVCP(vcp, inp);
6046 lock_ObtainWrite(&scp->rw);
6047 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6048 CM_SCACHESYNC_NEEDCALLBACK
6049 | CM_SCACHESYNC_GETSTATUS
6050 | CM_SCACHESYNC_LOCK);
6052 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
6056 LockType = smb_GetSMBParm(inp, 3) & 0xff;
6057 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
6058 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
6059 NumberOfLocks = smb_GetSMBParm(inp, 7);
6061 if (!(fidp->flags & SMB_FID_OPENWRITE) &&
6062 !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
6063 /* somebody wants exclusive locks on a file that they only
6064 opened for reading. We downgrade this to a shared lock. */
6065 osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
6066 LockType |= LOCKING_ANDX_SHARED_LOCK;
6069 if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
6070 /* AFS does not support atomic changes of lock types from read or write and vice-versa */
6071 osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]");
6072 code = CM_ERROR_BADOP;
6077 op = smb_GetSMBData(inp, NULL);
6079 if (LockType & LOCKING_ANDX_CANCEL_LOCK) {
6080 /* Cancel outstanding lock requests */
6081 smb_waitingLock_t * wl;
6083 for (i=0; i<NumberOfLocks; i++) {
6084 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6086 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6088 lock_ObtainWrite(&smb_globalLock);
6089 for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
6091 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
6092 if (cm_KeyEquals(&wl->key, &key, 0) && LargeIntegerEqualTo(wl->LOffset, LOffset) &&
6093 LargeIntegerEqualTo(wl->LLength, LLength)) {
6094 wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
6095 goto found_lock_request;
6100 lock_ReleaseWrite(&smb_globalLock);
6103 smb_SetSMBDataLength(outp, 0);
6108 for (i=0; i<NumberOfUnlocks; i++) {
6109 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6111 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6113 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
6121 for (i=0; i<NumberOfLocks; i++) {
6122 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6124 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6126 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
6127 userp, &req, &lockp);
6129 if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
6130 (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
6132 code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
6133 userp, &req, &lockp);
6136 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
6137 smb_waitingLock_t * wLock;
6139 /* Put on waiting list */
6140 if(wlRequest == NULL) {
6144 LARGE_INTEGER tOffset, tLength;
6146 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
6148 osi_assertx(wlRequest != NULL, "null wlRequest");
6150 wlRequest->vcp = vcp;
6152 wlRequest->scp = scp;
6153 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
6155 wlRequest->inp = smb_CopyPacket(inp);
6156 wlRequest->outp = smb_CopyPacket(outp);
6157 wlRequest->lockType = LockType;
6158 wlRequest->msTimeout = Timeout;
6159 wlRequest->start_t = osi_Time();
6160 wlRequest->locks = NULL;
6162 /* The waiting lock request needs to have enough
6163 information to undo all the locks in the request.
6164 We do the following to store info about locks that
6165 have already been granted. Sure, we can get most
6166 of the info from the packet, but the packet doesn't
6167 hold the result of cm_Lock call. In practice we
6168 only receive packets with one or two locks, so we
6169 are only wasting a few bytes here and there and
6170 only for a limited period of time until the waiting
6171 lock times out or is freed. */
6173 for(opt = op_locks, j=i; j > 0; j--) {
6174 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
6176 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6178 wLock = malloc(sizeof(smb_waitingLock_t));
6180 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6183 wLock->LOffset = tOffset;
6184 wLock->LLength = tLength;
6185 wLock->lockp = NULL;
6186 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
6187 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6192 wLock = malloc(sizeof(smb_waitingLock_t));
6194 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6197 wLock->LOffset = LOffset;
6198 wLock->LLength = LLength;
6199 wLock->lockp = lockp;
6200 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
6201 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6204 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
6212 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
6219 /* Since something went wrong with the lock number i, we now
6220 have to go ahead and release any locks acquired before the
6221 failure. All locks before lock number i (of which there
6222 are i of them) have either been successful or are waiting.
6223 Either case requires calling cm_Unlock(). */
6225 /* And purge the waiting lock */
6226 if(wlRequest != NULL) {
6227 smb_waitingLock_t * wl;
6228 smb_waitingLock_t * wlNext;
6231 for(wl = wlRequest->locks; wl; wl = wlNext) {
6233 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
6235 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
6238 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
6240 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
6243 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
6248 smb_ReleaseVC(wlRequest->vcp);
6249 cm_ReleaseSCache(wlRequest->scp);
6250 smb_FreePacket(wlRequest->inp);
6251 smb_FreePacket(wlRequest->outp);
6260 if (wlRequest != NULL) {
6262 lock_ObtainWrite(&smb_globalLock);
6263 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
6265 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
6266 lock_ReleaseWrite(&smb_globalLock);
6268 /* don't send reply immediately */
6269 outp->flags |= SMB_PACKETFLAG_NOSEND;
6272 smb_SetSMBDataLength(outp, 0);
6276 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
6279 lock_ReleaseWrite(&scp->rw);
6280 cm_ReleaseSCache(scp);
6281 cm_ReleaseUser(userp);
6282 smb_ReleaseFID(fidp);
6287 /* SMB_COM_QUERY_INFORMATION2 */
6288 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6294 afs_uint32 searchTime;
6301 fid = smb_GetSMBParm(inp, 0);
6302 fid = smb_ChainFID(fid, inp);
6304 fidp = smb_FindFID(vcp, fid, 0);
6306 return CM_ERROR_BADFD;
6308 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6309 smb_CloseFID(vcp, fidp, NULL, 0);
6310 smb_ReleaseFID(fidp);
6311 return CM_ERROR_NOSUCHFILE;
6314 lock_ObtainMutex(&fidp->mx);
6315 if (fidp->flags & SMB_FID_IOCTL) {
6316 lock_ReleaseMutex(&fidp->mx);
6317 smb_ReleaseFID(fidp);
6318 return CM_ERROR_BADFD;
6321 osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6323 lock_ReleaseMutex(&fidp->mx);
6325 userp = smb_GetUserFromVCP(vcp, inp);
6328 /* otherwise, stat the file */
6329 lock_ObtainWrite(&scp->rw);
6330 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6331 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6335 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6337 lock_ConvertWToR(&scp->rw);
6340 /* decode times. We need a search time, but the response to this
6341 * call provides the date first, not the time, as returned in the
6342 * searchTime variable. So we take the high-order bits first.
6344 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
6345 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
6346 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
6347 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
6348 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
6349 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
6350 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
6352 /* now handle file size and allocation size */
6353 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
6354 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
6355 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
6356 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
6358 /* file attribute */
6359 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
6361 /* and finalize stuff */
6362 smb_SetSMBDataLength(outp, 0);
6367 lock_ReleaseRead(&scp->rw);
6369 lock_ReleaseWrite(&scp->rw);
6370 cm_ReleaseSCache(scp);
6371 cm_ReleaseUser(userp);
6372 smb_ReleaseFID(fidp);
6376 /* SMB_COM_SET_INFORMATION2 */
6377 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6383 afs_uint32 searchTime;
6391 fid = smb_GetSMBParm(inp, 0);
6392 fid = smb_ChainFID(fid, inp);
6394 fidp = smb_FindFID(vcp, fid, 0);
6396 return CM_ERROR_BADFD;
6398 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6399 smb_CloseFID(vcp, fidp, NULL, 0);
6400 smb_ReleaseFID(fidp);
6401 return CM_ERROR_NOSUCHFILE;
6404 lock_ObtainMutex(&fidp->mx);
6405 if (fidp->flags & SMB_FID_IOCTL) {
6406 lock_ReleaseMutex(&fidp->mx);
6407 smb_ReleaseFID(fidp);
6408 return CM_ERROR_BADFD;
6411 osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6413 lock_ReleaseMutex(&fidp->mx);
6415 userp = smb_GetUserFromVCP(vcp, inp);
6418 /* now prepare to call cm_setattr. This message only sets various times,
6419 * and AFS only implements mtime, and we'll set the mtime if that's
6420 * requested. The others we'll ignore.
6422 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
6424 if (searchTime != 0) {
6425 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
6427 if ( unixTime != -1 ) {
6428 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
6429 attrs.clientModTime = unixTime;
6430 code = cm_SetAttr(scp, &attrs, userp, &req);
6432 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
6434 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
6440 cm_ReleaseSCache(scp);
6441 cm_ReleaseUser(userp);
6442 smb_ReleaseFID(fidp);
6446 /* SMB_COM_WRITE_ANDX */
6447 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6450 long count, written = 0, total_written = 0;
6454 smb_t *smbp = (smb_t*) inp;
6458 int inDataBlockCount;
6460 fd = smb_GetSMBParm(inp, 2);
6461 count = smb_GetSMBParm(inp, 10);
6463 offset.HighPart = 0;
6464 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6466 if (*inp->wctp == 14) {
6467 /* we have a request with 64-bit file offsets */
6468 #ifdef AFS_LARGEFILES
6469 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6471 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6473 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
6474 /* we shouldn't have received this op if we didn't specify
6475 largefile support */
6476 return CM_ERROR_BADOP;
6481 op = inp->data + smb_GetSMBParm(inp, 11);
6482 inDataBlockCount = count;
6484 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
6485 fd, offset.HighPart, offset.LowPart, count);
6487 fd = smb_ChainFID(fd, inp);
6488 fidp = smb_FindFID(vcp, fd, 0);
6490 return CM_ERROR_BADFD;
6492 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6493 smb_CloseFID(vcp, fidp, NULL, 0);
6494 smb_ReleaseFID(fidp);
6495 return CM_ERROR_NOSUCHFILE;
6498 lock_ObtainMutex(&fidp->mx);
6499 if (fidp->flags & SMB_FID_IOCTL) {
6500 lock_ReleaseMutex(&fidp->mx);
6501 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
6502 smb_ReleaseFID(fidp);
6505 lock_ReleaseMutex(&fidp->mx);
6506 userp = smb_GetUserFromVCP(vcp, inp);
6508 /* special case: 0 bytes transferred means there is no data
6509 transferred. A slight departure from SMB_COM_WRITE where this
6510 means that we are supposed to truncate the file at this
6515 LARGE_INTEGER LOffset;
6516 LARGE_INTEGER LLength;
6520 key = cm_GenerateKey(vcp->vcID, pid, fd);
6522 LOffset.HighPart = offset.HighPart;
6523 LOffset.LowPart = offset.LowPart;
6524 LLength.HighPart = 0;
6525 LLength.LowPart = count;
6528 lock_ObtainWrite(&scp->rw);
6529 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
6530 lock_ReleaseWrite(&scp->rw);
6537 * Work around bug in NT client
6539 * When copying a file, the NT client should first copy the data,
6540 * then copy the last write time. But sometimes the NT client does
6541 * these in the wrong order, so the data copies would inadvertently
6542 * cause the last write time to be overwritten. We try to detect this,
6543 * and don't set client mod time if we think that would go against the
6546 lock_ObtainMutex(&fidp->mx);
6547 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6548 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6549 fidp->scp->clientModTime = time(NULL);
6551 lock_ReleaseMutex(&fidp->mx);
6554 while ( code == 0 && count > 0 ) {
6555 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6556 if (code == 0 && written == 0)
6557 code = CM_ERROR_PARTIALWRITE;
6559 offset = LargeIntegerAdd(offset,
6560 ConvertLongToLargeInteger(written));
6562 total_written += written;
6566 /* slots 0 and 1 are reserved for request chaining and will be
6567 filled in when we return. */
6568 smb_SetSMBParm(outp, 2, total_written);
6569 smb_SetSMBParm(outp, 3, 0); /* reserved */
6570 smb_SetSMBParm(outp, 4, 0); /* reserved */
6571 smb_SetSMBParm(outp, 5, 0); /* reserved */
6572 smb_SetSMBDataLength(outp, 0);
6575 cm_ReleaseUser(userp);
6576 smb_ReleaseFID(fidp);
6581 /* SMB_COM_READ_ANDX */
6582 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6586 long finalCount = 0;
6590 smb_t *smbp = (smb_t*) inp;
6596 fd = smb_GetSMBParm(inp, 2);
6597 count = smb_GetSMBParm(inp, 5);
6598 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6600 if (*inp->wctp == 12) {
6601 /* a request with 64-bit offsets */
6602 #ifdef AFS_LARGEFILES
6603 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
6605 if (LargeIntegerLessThanZero(offset)) {
6606 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
6607 offset.HighPart, offset.LowPart);
6608 return CM_ERROR_BADSMB;
6611 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
6612 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
6613 return CM_ERROR_BADSMB;
6615 offset.HighPart = 0;
6619 offset.HighPart = 0;
6622 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
6623 fd, offset.HighPart, offset.LowPart, count);
6625 fd = smb_ChainFID(fd, inp);
6626 fidp = smb_FindFID(vcp, fd, 0);
6628 return CM_ERROR_BADFD;
6631 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6632 smb_CloseFID(vcp, fidp, NULL, 0);
6633 smb_ReleaseFID(fidp);
6634 return CM_ERROR_NOSUCHFILE;
6638 key = cm_GenerateKey(vcp->vcID, pid, fd);
6640 LARGE_INTEGER LOffset, LLength;
6643 LOffset.HighPart = offset.HighPart;
6644 LOffset.LowPart = offset.LowPart;
6645 LLength.HighPart = 0;
6646 LLength.LowPart = count;
6649 lock_ObtainWrite(&scp->rw);
6650 code = cm_LockCheckRead(scp, LOffset, LLength, key);
6651 lock_ReleaseWrite(&scp->rw);
6655 smb_ReleaseFID(fidp);
6659 /* set inp->fid so that later read calls in same msg can find fid */
6662 lock_ObtainMutex(&fidp->mx);
6663 if (fidp->flags & SMB_FID_IOCTL) {
6664 lock_ReleaseMutex(&fidp->mx);
6665 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
6666 smb_ReleaseFID(fidp);
6669 lock_ReleaseMutex(&fidp->mx);
6671 userp = smb_GetUserFromVCP(vcp, inp);
6673 /* 0 and 1 are reserved for request chaining, were setup by our caller,
6674 * and will be further filled in after we return.
6676 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
6677 smb_SetSMBParm(outp, 3, 0); /* resvd */
6678 smb_SetSMBParm(outp, 4, 0); /* resvd */
6679 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
6680 /* fill in #6 when we have all the parameters' space reserved */
6681 smb_SetSMBParm(outp, 7, 0); /* resv'd */
6682 smb_SetSMBParm(outp, 8, 0); /* resv'd */
6683 smb_SetSMBParm(outp, 9, 0); /* resv'd */
6684 smb_SetSMBParm(outp, 10, 0); /* resv'd */
6685 smb_SetSMBParm(outp, 11, 0); /* reserved */
6687 /* get op ptr after putting in the parms, since otherwise we don't
6688 * know where the data really is.
6690 op = smb_GetSMBData(outp, NULL);
6692 /* now fill in offset from start of SMB header to first data byte (to op) */
6693 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
6695 /* set the packet data length the count of the # of bytes */
6696 smb_SetSMBDataLength(outp, count);
6698 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6700 /* fix some things up */
6701 smb_SetSMBParm(outp, 5, finalCount);
6702 smb_SetSMBDataLength(outp, finalCount);
6704 cm_ReleaseUser(userp);
6705 smb_ReleaseFID(fidp);
6710 * Values for createDisp, copied from NTDDK.H
6712 #define FILE_SUPERSEDE 0 // (???)
6713 #define FILE_OPEN 1 // (open)
6714 #define FILE_CREATE 2 // (exclusive)
6715 #define FILE_OPEN_IF 3 // (non-exclusive)
6716 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
6717 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
6720 #define REQUEST_OPLOCK 2
6721 #define REQUEST_BATCH_OPLOCK 4
6722 #define OPEN_DIRECTORY 8
6723 #define EXTENDED_RESPONSE_REQUIRED 0x10
6725 /* CreateOptions field. */
6726 #define FILE_DIRECTORY_FILE 0x0001
6727 #define FILE_WRITE_THROUGH 0x0002
6728 #define FILE_SEQUENTIAL_ONLY 0x0004
6729 #define FILE_NON_DIRECTORY_FILE 0x0040
6730 #define FILE_NO_EA_KNOWLEDGE 0x0200
6731 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
6732 #define FILE_RANDOM_ACCESS 0x0800
6733 #define FILE_DELETE_ON_CLOSE 0x1000
6734 #define FILE_OPEN_BY_FILE_ID 0x2000
6735 #define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000
6736 #define FILE_NO_COMPRESSION 0x00008000
6737 #define FILE_RESERVE_OPFILTER 0x00100000
6738 #define FILE_OPEN_REPARSE_POINT 0x00200000
6739 #define FILE_OPEN_NO_RECALL 0x00400000
6740 #define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000
6742 /* SMB_COM_NT_CREATE_ANDX */
6743 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6745 clientchar_t *pathp, *realPathp;
6749 cm_scache_t *dscp; /* parent dir */
6750 cm_scache_t *scp; /* file to create or open */
6751 cm_scache_t *targetScp; /* if scp is a symlink */
6753 clientchar_t *lastNamep;
6754 clientchar_t *treeStartp;
6755 unsigned short nameLength;
6757 unsigned int requestOpLock;
6758 unsigned int requestBatchOpLock;
6759 unsigned int mustBeDir;
6760 unsigned int extendedRespRequired;
6761 unsigned int treeCreate;
6763 unsigned int desiredAccess;
6764 unsigned int extAttributes;
6765 unsigned int createDisp;
6766 unsigned int createOptions;
6767 unsigned int shareAccess;
6768 int initialModeBits;
6769 unsigned short baseFid;
6770 smb_fid_t *baseFidp;
6772 cm_scache_t *baseDirp;
6773 unsigned short openAction;
6778 clientchar_t *tidPathp;
6783 int checkDoneRequired = 0;
6784 cm_lock_data_t *ldp = NULL;
6788 /* This code is very long and has a lot of if-then-else clauses
6789 * scp and dscp get reused frequently and we need to ensure that
6790 * we don't lose a reference. Start by ensuring that they are NULL.
6797 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
6798 flags = smb_GetSMBOffsetParm(inp, 3, 1)
6799 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
6800 requestOpLock = flags & REQUEST_OPLOCK;
6801 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6802 mustBeDir = flags & OPEN_DIRECTORY;
6803 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6806 * Why all of a sudden 32-bit FID?
6807 * We will reject all bits higher than 16.
6809 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
6810 return CM_ERROR_INVAL;
6811 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
6812 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
6813 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6814 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
6815 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
6816 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
6817 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
6818 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
6819 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
6820 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
6821 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
6823 /* mustBeDir is never set; createOptions directory bit seems to be
6826 if (createOptions & FILE_DIRECTORY_FILE)
6828 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6834 * compute initial mode bits based on read-only flag in
6835 * extended attributes
6837 initialModeBits = 0666;
6838 if (extAttributes & SMB_ATTR_READONLY)
6839 initialModeBits &= ~0222;
6841 pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
6842 NULL, SMB_STRF_ANSIPATH);
6844 /* Sometimes path is not null-terminated, so we make a copy. */
6845 realPathp = malloc(nameLength+sizeof(clientchar_t));
6846 memcpy(realPathp, pathp, nameLength+sizeof(clientchar_t));
6847 realPathp[nameLength/sizeof(clientchar_t)] = 0;
6849 spacep = inp->spacep;
6850 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
6852 osi_Log1(smb_logp,"NTCreateX for [%S]",osi_LogSaveClientString(smb_logp,realPathp));
6853 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
6854 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%S]", shareAccess, flags, osi_LogSaveClientString(smb_logp,(lastNamep?lastNamep:_C("null"))));
6857 (cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
6858 cm_ClientStrCmpIA(lastNamep, _C("\\srvsvc")) == 0 ||
6859 cm_ClientStrCmpIA(lastNamep, _C("\\wkssvc")) == 0 ||
6860 cm_ClientStrCmpIA(lastNamep, _C("ipc$")) == 0)) {
6861 /* special case magic file name for receiving IOCTL requests
6862 * (since IOCTL calls themselves aren't getting through).
6864 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6865 smb_SetupIoctlFid(fidp, spacep);
6866 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
6868 /* set inp->fid so that later read calls in same msg can find fid */
6869 inp->fid = fidp->fid;
6873 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6874 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6875 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
6877 memset(&ft, 0, sizeof(ft));
6878 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6879 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6880 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6881 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6882 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
6883 sz.HighPart = 0x7fff; sz.LowPart = 0;
6884 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
6885 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
6886 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6887 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6888 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
6889 smb_SetSMBDataLength(outp, 0);
6891 /* clean up fid reference */
6892 smb_ReleaseFID(fidp);
6897 if (!cm_IsValidClientString(realPathp)) {
6899 clientchar_t * hexp;
6901 hexp = cm_GetRawCharsAlloc(realPathp, -1);
6902 osi_Log1(smb_logp, "NTCreateX rejecting invalid name. [%S]",
6903 osi_LogSaveClientString(smb_logp, hexp));
6907 osi_Log0(smb_logp, "NTCreateX rejecting invalid name");
6910 return CM_ERROR_BADNTFILENAME;
6913 userp = smb_GetUserFromVCP(vcp, inp);
6915 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
6917 return CM_ERROR_INVAL;
6922 baseDirp = cm_data.rootSCachep;
6923 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6924 if (code == CM_ERROR_TIDIPC) {
6925 /* Attempt to use a TID allocated for IPC. The client
6926 * is probably looking for DCE RPC end points which we
6927 * don't support OR it could be looking to make a DFS
6930 osi_Log0(smb_logp, "NTCreateX received IPC TID");
6933 cm_ReleaseUser(userp);
6934 return CM_ERROR_NOSUCHFILE;
6935 #endif /* DFS_SUPPORT */
6938 baseFidp = smb_FindFID(vcp, baseFid, 0);
6940 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
6942 cm_ReleaseUser(userp);
6943 return CM_ERROR_INVAL;
6946 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6948 cm_ReleaseUser(userp);
6949 smb_CloseFID(vcp, baseFidp, NULL, 0);
6950 smb_ReleaseFID(baseFidp);
6951 return CM_ERROR_NOSUCHPATH;
6954 baseDirp = baseFidp->scp;
6958 osi_Log1(smb_logp, "NTCreateX tidPathp=[%S]", (tidPathp==NULL)?_C("null"): osi_LogSaveClientString(smb_logp,tidPathp));
6960 /* compute open mode */
6962 if (desiredAccess & DELETE)
6963 fidflags |= SMB_FID_OPENDELETE;
6964 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
6965 fidflags |= SMB_FID_OPENREAD_LISTDIR;
6966 if (desiredAccess & AFS_ACCESS_WRITE)
6967 fidflags |= SMB_FID_OPENWRITE;
6968 if (createOptions & FILE_DELETE_ON_CLOSE)
6969 fidflags |= SMB_FID_DELONCLOSE;
6970 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6971 fidflags |= SMB_FID_SEQUENTIAL;
6972 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6973 fidflags |= SMB_FID_RANDOM;
6974 if (createOptions & FILE_OPEN_REPARSE_POINT)
6975 osi_Log0(smb_logp, "NTCreateX Open Reparse Point");
6976 if (smb_IsExecutableFileName(lastNamep))
6977 fidflags |= SMB_FID_EXECUTABLE;
6979 /* and the share mode */
6980 if (shareAccess & FILE_SHARE_READ)
6981 fidflags |= SMB_FID_SHARE_READ;
6982 if (shareAccess & FILE_SHARE_WRITE)
6983 fidflags |= SMB_FID_SHARE_WRITE;
6985 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
6988 /* For an exclusive create, we want to do a case sensitive match for the last component. */
6989 if ( createDisp == FILE_CREATE ||
6990 createDisp == FILE_OVERWRITE ||
6991 createDisp == FILE_OVERWRITE_IF) {
6992 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6993 userp, tidPathp, &req, &dscp);
6996 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6997 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
6999 cm_ReleaseSCache(dscp);
7000 cm_ReleaseUser(userp);
7003 smb_ReleaseFID(baseFidp);
7004 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7005 return CM_ERROR_PATH_NOT_COVERED;
7007 return CM_ERROR_BADSHARENAME;
7009 #endif /* DFS_SUPPORT */
7010 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7012 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7013 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7014 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7015 if (code == 0 && realDirFlag == 1) {
7016 cm_ReleaseSCache(scp);
7017 cm_ReleaseSCache(dscp);
7018 cm_ReleaseUser(userp);
7021 smb_ReleaseFID(baseFidp);
7022 return CM_ERROR_EXISTS;
7026 /* we have both scp and dscp */
7028 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7029 userp, tidPathp, &req, &scp);
7031 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7032 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7033 cm_ReleaseSCache(scp);
7034 cm_ReleaseUser(userp);
7037 smb_ReleaseFID(baseFidp);
7038 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7039 return CM_ERROR_PATH_NOT_COVERED;
7041 return CM_ERROR_BADSHARENAME;
7043 #endif /* DFS_SUPPORT */
7044 /* we might have scp but not dscp */
7050 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7051 /* look up parent directory */
7052 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
7053 * the immediate parent. We have to work our way up realPathp until we hit something that we
7057 /* we might or might not have scp */
7063 code = cm_NameI(baseDirp, spacep->wdata,
7064 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7065 userp, tidPathp, &req, &dscp);
7068 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7069 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7072 cm_ReleaseSCache(scp);
7073 cm_ReleaseSCache(dscp);
7074 cm_ReleaseUser(userp);
7077 smb_ReleaseFID(baseFidp);
7078 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7079 return CM_ERROR_PATH_NOT_COVERED;
7081 return CM_ERROR_BADSHARENAME;
7083 #endif /* DFS_SUPPORT */
7086 (tp = cm_ClientStrRChr(spacep->wdata, '\\')) &&
7087 (createDisp == FILE_CREATE) &&
7088 (realDirFlag == 1)) {
7091 treeStartp = realPathp + (tp - spacep->wdata);
7093 if (*tp && !smb_IsLegalFilename(tp)) {
7094 cm_ReleaseUser(userp);
7096 smb_ReleaseFID(baseFidp);
7099 cm_ReleaseSCache(scp);
7100 return CM_ERROR_BADNTFILENAME;
7104 } while (dscp == NULL && code == 0);
7108 /* we might have scp and we might have dscp */
7111 smb_ReleaseFID(baseFidp);
7114 osi_Log0(smb_logp,"NTCreateX parent not found");
7116 cm_ReleaseSCache(scp);
7118 cm_ReleaseSCache(dscp);
7119 cm_ReleaseUser(userp);
7124 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
7125 /* A file exists where we want a directory. */
7127 cm_ReleaseSCache(scp);
7128 cm_ReleaseSCache(dscp);
7129 cm_ReleaseUser(userp);
7131 return CM_ERROR_EXISTS;
7135 lastNamep = realPathp;
7139 if (!smb_IsLegalFilename(lastNamep)) {
7141 cm_ReleaseSCache(scp);
7143 cm_ReleaseSCache(dscp);
7144 cm_ReleaseUser(userp);
7146 return CM_ERROR_BADNTFILENAME;
7149 if (!foundscp && !treeCreate) {
7150 if ( createDisp == FILE_CREATE ||
7151 createDisp == FILE_OVERWRITE ||
7152 createDisp == FILE_OVERWRITE_IF)
7154 code = cm_Lookup(dscp, lastNamep,
7155 CM_FLAG_FOLLOW, userp, &req, &scp);
7157 code = cm_Lookup(dscp, lastNamep,
7158 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7161 if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
7163 cm_ReleaseSCache(dscp);
7164 cm_ReleaseUser(userp);
7169 /* we have scp and dscp */
7171 /* we have scp but not dscp */
7173 smb_ReleaseFID(baseFidp);
7176 /* if we get here, if code is 0, the file exists and is represented by
7177 * scp. Otherwise, we have to create it. The dir may be represented
7178 * by dscp, or we may have found the file directly. If code is non-zero,
7181 if (code == 0 && !treeCreate) {
7182 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7184 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7186 cm_ReleaseSCache(dscp);
7188 cm_ReleaseSCache(scp);
7189 cm_ReleaseUser(userp);
7193 checkDoneRequired = 1;
7195 if (createDisp == FILE_CREATE) {
7196 /* oops, file shouldn't be there */
7197 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7199 cm_ReleaseSCache(dscp);
7201 cm_ReleaseSCache(scp);
7202 cm_ReleaseUser(userp);
7204 return CM_ERROR_EXISTS;
7207 if ( createDisp == FILE_OVERWRITE ||
7208 createDisp == FILE_OVERWRITE_IF) {
7210 setAttr.mask = CM_ATTRMASK_LENGTH;
7211 setAttr.length.LowPart = 0;
7212 setAttr.length.HighPart = 0;
7213 /* now watch for a symlink */
7215 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7217 osi_assertx(dscp != NULL, "null cm_scache_t");
7218 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7220 /* we have a more accurate file to use (the
7221 * target of the symbolic link). Otherwise,
7222 * we'll just use the symlink anyway.
7224 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7226 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7227 cm_ReleaseSCache(scp);
7229 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7231 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7233 cm_ReleaseSCache(dscp);
7235 cm_ReleaseSCache(scp);
7236 cm_ReleaseUser(userp);
7242 code = cm_SetAttr(scp, &setAttr, userp, &req);
7243 openAction = 3; /* truncated existing file */
7246 openAction = 1; /* found existing file */
7248 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7249 /* don't create if not found */
7251 cm_ReleaseSCache(dscp);
7253 cm_ReleaseSCache(scp);
7254 cm_ReleaseUser(userp);
7256 return CM_ERROR_NOSUCHFILE;
7257 } else if (realDirFlag == 0 || realDirFlag == -1) {
7258 osi_assertx(dscp != NULL, "null cm_scache_t");
7259 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %S",
7260 osi_LogSaveClientString(smb_logp, lastNamep));
7261 openAction = 2; /* created file */
7262 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7263 setAttr.clientModTime = time(NULL);
7264 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
7267 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7268 smb_NotifyChange(FILE_ACTION_ADDED,
7269 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7270 dscp, lastNamep, NULL, TRUE);
7271 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7272 /* Not an exclusive create, and someone else tried
7273 * creating it already, then we open it anyway. We
7274 * don't bother retrying after this, since if this next
7275 * fails, that means that the file was deleted after we
7276 * started this call.
7278 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7281 if (createDisp == FILE_OVERWRITE_IF) {
7282 setAttr.mask = CM_ATTRMASK_LENGTH;
7283 setAttr.length.LowPart = 0;
7284 setAttr.length.HighPart = 0;
7286 /* now watch for a symlink */
7288 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7290 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7292 /* we have a more accurate file to use (the
7293 * target of the symbolic link). Otherwise,
7294 * we'll just use the symlink anyway.
7296 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7298 cm_ReleaseSCache(scp);
7302 code = cm_SetAttr(scp, &setAttr, userp, &req);
7304 } /* lookup succeeded */
7307 clientchar_t *tp, *pp;
7308 clientchar_t *cp; /* This component */
7309 int clen = 0; /* length of component */
7310 cm_scache_t *tscp1, *tscp2;
7313 /* create directory */
7315 treeStartp = lastNamep;
7316 osi_assertx(dscp != NULL, "null cm_scache_t");
7317 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%S]",
7318 osi_LogSaveClientString(smb_logp, treeStartp));
7319 openAction = 2; /* created directory */
7321 /* if the request is to create the root directory
7322 * it will appear as a directory name of the nul-string
7323 * and a code of CM_ERROR_NOSUCHFILE
7325 if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
7326 code = CM_ERROR_EXISTS;
7328 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7329 setAttr.clientModTime = time(NULL);
7334 cm_HoldSCache(tscp1);
7338 tp = cm_ClientStrChr(pp, '\\');
7340 cm_ClientStrCpy(cp, lengthof(spacep->wdata) - (cp - spacep->wdata), pp);
7341 clen = (int)cm_ClientStrLen(cp);
7342 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
7344 clen = (int)(tp - pp);
7345 cm_ClientStrCpyN(cp, lengthof(spacep->wdata) - (cp - spacep->wdata),
7353 continue; /* the supplied path can't have consecutive slashes either , but */
7355 /* cp is the next component to be created. */
7356 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req, NULL);
7357 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
7358 smb_NotifyChange(FILE_ACTION_ADDED,
7359 FILE_NOTIFY_CHANGE_DIR_NAME,
7360 tscp1, cp, NULL, TRUE);
7362 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7363 /* Not an exclusive create, and someone else tried
7364 * creating it already, then we open it anyway. We
7365 * don't bother retrying after this, since if this next
7366 * fails, that means that the file was deleted after we
7367 * started this call.
7369 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
7370 userp, &req, &tscp2);
7375 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
7376 cm_ReleaseSCache(tscp1);
7377 tscp1 = tscp2; /* Newly created directory will be next parent */
7378 /* the hold is transfered to tscp1 from tscp2 */
7383 cm_ReleaseSCache(dscp);
7386 cm_ReleaseSCache(scp);
7389 * if we get here and code == 0, then scp is the last directory created, and dscp is the
7395 /* something went wrong creating or truncating the file */
7396 if (checkDoneRequired)
7397 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7399 cm_ReleaseSCache(scp);
7401 cm_ReleaseSCache(dscp);
7402 cm_ReleaseUser(userp);
7407 /* make sure we have file vs. dir right (only applies for single component case) */
7408 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7409 /* now watch for a symlink */
7411 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7412 cm_scache_t * targetScp = 0;
7413 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7415 /* we have a more accurate file to use (the
7416 * target of the symbolic link). Otherwise,
7417 * we'll just use the symlink anyway.
7419 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
7420 if (checkDoneRequired) {
7421 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7422 checkDoneRequired = 0;
7424 cm_ReleaseSCache(scp);
7429 if (scp->fileType != CM_SCACHETYPE_FILE) {
7430 if (checkDoneRequired)
7431 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7433 cm_ReleaseSCache(dscp);
7434 cm_ReleaseSCache(scp);
7435 cm_ReleaseUser(userp);
7437 return CM_ERROR_ISDIR;
7441 /* (only applies to single component case) */
7442 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7443 if (checkDoneRequired)
7444 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7445 cm_ReleaseSCache(scp);
7447 cm_ReleaseSCache(dscp);
7448 cm_ReleaseUser(userp);
7450 return CM_ERROR_NOTDIR;
7453 /* open the file itself */
7454 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7455 osi_assertx(fidp, "null smb_fid_t");
7457 /* save a reference to the user */
7459 fidp->userp = userp;
7461 /* If we are restricting sharing, we should do so with a suitable
7463 if (scp->fileType == CM_SCACHETYPE_FILE &&
7464 !(fidflags & SMB_FID_SHARE_WRITE)) {
7466 LARGE_INTEGER LOffset, LLength;
7469 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7470 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7471 LLength.HighPart = 0;
7472 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7474 /* If we are not opening the file for writing, then we don't
7475 try to get an exclusive lock. No one else should be able to
7476 get an exclusive lock on the file anyway, although someone
7477 else can get a shared lock. */
7478 if ((fidflags & SMB_FID_SHARE_READ) ||
7479 !(fidflags & SMB_FID_OPENWRITE)) {
7480 sLockType = LOCKING_ANDX_SHARED_LOCK;
7485 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7487 lock_ObtainWrite(&scp->rw);
7488 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7489 lock_ReleaseWrite(&scp->rw);
7492 if (checkDoneRequired)
7493 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7494 cm_ReleaseSCache(scp);
7496 cm_ReleaseSCache(dscp);
7497 cm_ReleaseUser(userp);
7498 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7499 smb_CloseFID(vcp, fidp, NULL, 0);
7500 smb_ReleaseFID(fidp);
7506 /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
7507 if (checkDoneRequired) {
7508 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7509 checkDoneRequired = 0;
7512 lock_ObtainMutex(&fidp->mx);
7513 /* save a pointer to the vnode */
7514 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
7515 lock_ObtainWrite(&scp->rw);
7516 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7517 lock_ReleaseWrite(&scp->rw);
7518 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
7520 fidp->flags = fidflags;
7522 /* remember if the file was newly created */
7524 fidp->flags |= SMB_FID_CREATED;
7526 /* save parent dir and pathname for delete or change notification */
7527 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7528 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
7529 fidp->flags |= SMB_FID_NTOPEN;
7530 fidp->NTopen_dscp = dscp;
7532 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
7534 fidp->NTopen_wholepathp = realPathp;
7535 lock_ReleaseMutex(&fidp->mx);
7537 /* we don't need this any longer */
7539 cm_ReleaseSCache(dscp);
7543 cm_Open(scp, 0, userp);
7545 /* set inp->fid so that later read calls in same msg can find fid */
7546 inp->fid = fidp->fid;
7550 lock_ObtainRead(&scp->rw);
7551 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7552 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7553 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7554 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7555 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7556 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7557 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7558 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7559 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7561 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7562 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7563 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
7564 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
7565 smb_SetSMBParmByte(outp, parmSlot,
7566 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7567 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7568 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7569 smb_SetSMBDataLength(outp, 0);
7571 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
7572 LargeIntegerGreaterThanZero(fidp->scp->length) &&
7573 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
7576 lock_ReleaseRead(&scp->rw);
7579 cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
7580 fidp->scp->length.LowPart, fidp->scp->length.HighPart,
7584 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %S", fidp->fid,
7585 osi_LogSaveClientString(smb_logp, realPathp));
7587 cm_ReleaseUser(userp);
7588 smb_ReleaseFID(fidp);
7590 /* Can't free realPathp if we get here since
7591 fidp->NTopen_wholepathp is pointing there */
7593 /* leave scp held since we put it in fidp->scp */
7598 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
7599 * Instead, ultimately, would like to use a subroutine for common code.
7602 /* NT_TRANSACT_CREATE (SMB_COM_NT_TRANSACT) */
7603 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7605 clientchar_t *pathp, *realPathp;
7609 cm_scache_t *dscp; /* parent dir */
7610 cm_scache_t *scp; /* file to create or open */
7611 cm_scache_t *targetScp; /* if scp is a symlink */
7613 clientchar_t *lastNamep;
7614 unsigned long nameLength;
7616 unsigned int requestOpLock;
7617 unsigned int requestBatchOpLock;
7618 unsigned int mustBeDir;
7619 unsigned int extendedRespRequired;
7621 unsigned int desiredAccess;
7622 unsigned int allocSize;
7623 unsigned int shareAccess;
7624 unsigned int extAttributes;
7625 unsigned int createDisp;
7628 unsigned int impLevel;
7629 unsigned int secFlags;
7630 unsigned int createOptions;
7631 int initialModeBits;
7632 unsigned short baseFid;
7633 smb_fid_t *baseFidp;
7635 cm_scache_t *baseDirp;
7636 unsigned short openAction;
7640 clientchar_t *tidPathp;
7642 int parmOffset, dataOffset;
7649 cm_lock_data_t *ldp = NULL;
7650 int checkDoneRequired = 0;
7657 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7658 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7659 parmp = inp->data + parmOffset;
7660 lparmp = (ULONG *) parmp;
7663 requestOpLock = flags & REQUEST_OPLOCK;
7664 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7665 mustBeDir = flags & OPEN_DIRECTORY;
7666 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7669 * Why all of a sudden 32-bit FID?
7670 * We will reject all bits higher than 16.
7672 if (lparmp[1] & 0xFFFF0000)
7673 return CM_ERROR_INVAL;
7674 baseFid = (unsigned short)lparmp[1];
7675 desiredAccess = lparmp[2];
7676 allocSize = lparmp[3];
7677 extAttributes = lparmp[5];
7678 shareAccess = lparmp[6];
7679 createDisp = lparmp[7];
7680 createOptions = lparmp[8];
7683 nameLength = lparmp[11]; /* spec says chars but appears to be bytes */
7684 impLevel = lparmp[12];
7685 secFlags = lparmp[13];
7687 /* mustBeDir is never set; createOptions directory bit seems to be
7690 if (createOptions & FILE_DIRECTORY_FILE)
7692 else if (createOptions & FILE_NON_DIRECTORY_FILE)
7698 * compute initial mode bits based on read-only flag in
7699 * extended attributes
7701 initialModeBits = 0666;
7702 if (extAttributes & SMB_ATTR_READONLY)
7703 initialModeBits &= ~0222;
7705 pathp = smb_ParseStringCb(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
7706 nameLength, NULL, SMB_STRF_ANSIPATH);
7707 /* Sometimes path is not nul-terminated, so we make a copy. */
7708 realPathp = malloc(nameLength+sizeof(clientchar_t));
7709 memcpy(realPathp, pathp, nameLength);
7710 realPathp[nameLength/sizeof(clientchar_t)] = 0;
7711 spacep = cm_GetSpace();
7712 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
7714 osi_Log1(smb_logp,"NTTranCreate %S",osi_LogSaveStringW(smb_logp,realPathp));
7715 osi_Log4(smb_logp,"... da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
7716 osi_Log4(smb_logp,"... co[%x],sdl[%x],eal[%x],as[%x],flags[%x]",createOptions,sdLen,eaLen,allocSize);
7717 osi_Log3(smb_logp,"... imp[%x],sec[%x],flags[%x]", impLevel, secFlags, flags);
7720 * Nothing here to handle SMB_IOCTL_FILENAME.
7721 * Will add it if necessary.
7724 if (!cm_IsValidClientString(realPathp)) {
7726 clientchar_t * hexp;
7728 hexp = cm_GetRawCharsAlloc(realPathp, -1);
7729 osi_Log1(smb_logp, "NTTranCreate rejecting invalid name. [%S]",
7730 osi_LogSaveClientString(smb_logp, hexp));
7734 osi_Log0(smb_logp, "NTTranCreate rejecting invalid name.");
7737 return CM_ERROR_BADNTFILENAME;
7740 userp = smb_GetUserFromVCP(vcp, inp);
7742 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
7744 return CM_ERROR_INVAL;
7749 baseDirp = cm_data.rootSCachep;
7750 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7751 if (code == CM_ERROR_TIDIPC) {
7752 /* Attempt to use a TID allocated for IPC. The client
7753 * is probably looking for DCE RPC end points which we
7754 * don't support OR it could be looking to make a DFS
7757 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
7760 cm_ReleaseUser(userp);
7761 return CM_ERROR_NOSUCHPATH;
7765 baseFidp = smb_FindFID(vcp, baseFid, 0);
7767 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
7769 cm_ReleaseUser(userp);
7770 return CM_ERROR_BADFD;
7773 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7775 cm_ReleaseUser(userp);
7776 smb_CloseFID(vcp, baseFidp, NULL, 0);
7777 smb_ReleaseFID(baseFidp);
7778 return CM_ERROR_NOSUCHPATH;
7781 baseDirp = baseFidp->scp;
7785 /* compute open mode */
7787 if (desiredAccess & DELETE)
7788 fidflags |= SMB_FID_OPENDELETE;
7789 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
7790 fidflags |= SMB_FID_OPENREAD_LISTDIR;
7791 if (desiredAccess & AFS_ACCESS_WRITE)
7792 fidflags |= SMB_FID_OPENWRITE;
7793 if (createOptions & FILE_DELETE_ON_CLOSE)
7794 fidflags |= SMB_FID_DELONCLOSE;
7795 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7796 fidflags |= SMB_FID_SEQUENTIAL;
7797 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7798 fidflags |= SMB_FID_RANDOM;
7799 if (createOptions & FILE_OPEN_REPARSE_POINT)
7800 osi_Log0(smb_logp, "NTTranCreate Open Reparse Point");
7801 if (smb_IsExecutableFileName(lastNamep))
7802 fidflags |= SMB_FID_EXECUTABLE;
7804 /* And the share mode */
7805 if (shareAccess & FILE_SHARE_READ)
7806 fidflags |= SMB_FID_SHARE_READ;
7807 if (shareAccess & FILE_SHARE_WRITE)
7808 fidflags |= SMB_FID_SHARE_WRITE;
7812 if ( createDisp == FILE_OPEN ||
7813 createDisp == FILE_OVERWRITE ||
7814 createDisp == FILE_OVERWRITE_IF) {
7815 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7816 userp, tidPathp, &req, &dscp);
7819 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7820 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7821 cm_ReleaseSCache(dscp);
7822 cm_ReleaseUser(userp);
7825 smb_ReleaseFID(baseFidp);
7826 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7827 return CM_ERROR_PATH_NOT_COVERED;
7829 return CM_ERROR_BADSHARENAME;
7831 #endif /* DFS_SUPPORT */
7832 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7834 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7835 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7836 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7837 if (code == 0 && realDirFlag == 1) {
7838 cm_ReleaseSCache(scp);
7839 cm_ReleaseSCache(dscp);
7840 cm_ReleaseUser(userp);
7843 smb_ReleaseFID(baseFidp);
7844 return CM_ERROR_EXISTS;
7850 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7851 userp, tidPathp, &req, &scp);
7853 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7854 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7855 cm_ReleaseSCache(scp);
7856 cm_ReleaseUser(userp);
7859 smb_ReleaseFID(baseFidp);
7860 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7861 return CM_ERROR_PATH_NOT_COVERED;
7863 return CM_ERROR_BADSHARENAME;
7865 #endif /* DFS_SUPPORT */
7871 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7872 /* look up parent directory */
7874 code = cm_NameI(baseDirp, spacep->wdata,
7875 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7876 userp, tidPathp, &req, &dscp);
7878 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7879 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7880 cm_ReleaseSCache(dscp);
7881 cm_ReleaseUser(userp);
7884 smb_ReleaseFID(baseFidp);
7885 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7886 return CM_ERROR_PATH_NOT_COVERED;
7888 return CM_ERROR_BADSHARENAME;
7890 #endif /* DFS_SUPPORT */
7894 cm_FreeSpace(spacep);
7897 smb_ReleaseFID(baseFidp);
7900 cm_ReleaseUser(userp);
7906 lastNamep = realPathp;
7910 if (!smb_IsLegalFilename(lastNamep))
7911 return CM_ERROR_BADNTFILENAME;
7914 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
7915 code = cm_Lookup(dscp, lastNamep,
7916 CM_FLAG_FOLLOW, userp, &req, &scp);
7918 code = cm_Lookup(dscp, lastNamep,
7919 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7922 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7923 cm_ReleaseSCache(dscp);
7924 cm_ReleaseUser(userp);
7931 smb_ReleaseFID(baseFidp);
7932 cm_FreeSpace(spacep);
7935 /* if we get here, if code is 0, the file exists and is represented by
7936 * scp. Otherwise, we have to create it. The dir may be represented
7937 * by dscp, or we may have found the file directly. If code is non-zero,
7941 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7943 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7945 cm_ReleaseSCache(dscp);
7946 cm_ReleaseSCache(scp);
7947 cm_ReleaseUser(userp);
7951 checkDoneRequired = 1;
7953 if (createDisp == FILE_CREATE) {
7954 /* oops, file shouldn't be there */
7955 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7957 cm_ReleaseSCache(dscp);
7958 cm_ReleaseSCache(scp);
7959 cm_ReleaseUser(userp);
7961 return CM_ERROR_EXISTS;
7964 if (createDisp == FILE_OVERWRITE ||
7965 createDisp == FILE_OVERWRITE_IF) {
7966 setAttr.mask = CM_ATTRMASK_LENGTH;
7967 setAttr.length.LowPart = 0;
7968 setAttr.length.HighPart = 0;
7970 /* now watch for a symlink */
7972 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7974 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7976 /* we have a more accurate file to use (the
7977 * target of the symbolic link). Otherwise,
7978 * we'll just use the symlink anyway.
7980 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7982 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7983 cm_ReleaseSCache(scp);
7985 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7987 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7989 cm_ReleaseSCache(dscp);
7991 cm_ReleaseSCache(scp);
7992 cm_ReleaseUser(userp);
7998 code = cm_SetAttr(scp, &setAttr, userp, &req);
7999 openAction = 3; /* truncated existing file */
8001 else openAction = 1; /* found existing file */
8003 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
8004 /* don't create if not found */
8006 cm_ReleaseSCache(dscp);
8007 cm_ReleaseUser(userp);
8009 return CM_ERROR_NOSUCHFILE;
8011 else if (realDirFlag == 0 || realDirFlag == -1) {
8012 osi_assertx(dscp != NULL, "null cm_scache_t");
8013 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %S",
8014 osi_LogSaveClientString(smb_logp, lastNamep));
8015 openAction = 2; /* created file */
8016 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8017 setAttr.clientModTime = time(NULL);
8018 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8022 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8023 smb_NotifyChange(FILE_ACTION_ADDED,
8024 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8025 dscp, lastNamep, NULL, TRUE);
8026 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
8027 /* Not an exclusive create, and someone else tried
8028 * creating it already, then we open it anyway. We
8029 * don't bother retrying after this, since if this next
8030 * fails, that means that the file was deleted after we
8031 * started this call.
8033 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8036 if (createDisp == FILE_OVERWRITE_IF) {
8037 setAttr.mask = CM_ATTRMASK_LENGTH;
8038 setAttr.length.LowPart = 0;
8039 setAttr.length.HighPart = 0;
8041 /* now watch for a symlink */
8043 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8045 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8047 /* we have a more accurate file to use (the
8048 * target of the symbolic link). Otherwise,
8049 * we'll just use the symlink anyway.
8051 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8053 cm_ReleaseSCache(scp);
8057 code = cm_SetAttr(scp, &setAttr, userp, &req);
8059 } /* lookup succeeded */
8062 /* create directory */
8063 osi_assertx(dscp != NULL, "null cm_scache_t");
8065 "smb_ReceiveNTTranCreate creating directory %S",
8066 osi_LogSaveClientString(smb_logp, lastNamep));
8067 openAction = 2; /* created directory */
8068 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8069 setAttr.clientModTime = time(NULL);
8070 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8071 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8072 smb_NotifyChange(FILE_ACTION_ADDED,
8073 FILE_NOTIFY_CHANGE_DIR_NAME,
8074 dscp, lastNamep, NULL, TRUE);
8076 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
8077 /* Not an exclusive create, and someone else tried
8078 * creating it already, then we open it anyway. We
8079 * don't bother retrying after this, since if this next
8080 * fails, that means that the file was deleted after we
8081 * started this call.
8083 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8089 /* something went wrong creating or truncating the file */
8090 if (checkDoneRequired)
8091 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8093 cm_ReleaseSCache(scp);
8094 cm_ReleaseUser(userp);
8099 /* make sure we have file vs. dir right */
8100 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
8101 /* now watch for a symlink */
8103 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8105 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8107 /* we have a more accurate file to use (the
8108 * target of the symbolic link). Otherwise,
8109 * we'll just use the symlink anyway.
8111 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8113 if (checkDoneRequired) {
8114 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8115 checkDoneRequired = 0;
8117 cm_ReleaseSCache(scp);
8122 if (scp->fileType != CM_SCACHETYPE_FILE) {
8123 if (checkDoneRequired)
8124 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8125 cm_ReleaseSCache(scp);
8126 cm_ReleaseUser(userp);
8128 return CM_ERROR_ISDIR;
8132 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8133 if (checkDoneRequired)
8134 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8135 cm_ReleaseSCache(scp);
8136 cm_ReleaseUser(userp);
8138 return CM_ERROR_NOTDIR;
8141 /* open the file itself */
8142 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8143 osi_assertx(fidp, "null smb_fid_t");
8145 /* save a reference to the user */
8147 fidp->userp = userp;
8149 /* If we are restricting sharing, we should do so with a suitable
8151 if (scp->fileType == CM_SCACHETYPE_FILE &&
8152 !(fidflags & SMB_FID_SHARE_WRITE)) {
8154 LARGE_INTEGER LOffset, LLength;
8157 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8158 LOffset.LowPart = SMB_FID_QLOCK_LOW;
8159 LLength.HighPart = 0;
8160 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8162 /* Similar to what we do in handling NTCreateX. We get a
8163 shared lock if we are only opening the file for reading. */
8164 if ((fidflags & SMB_FID_SHARE_READ) ||
8165 !(fidflags & SMB_FID_OPENWRITE)) {
8166 sLockType = LOCKING_ANDX_SHARED_LOCK;
8171 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8173 lock_ObtainWrite(&scp->rw);
8174 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8175 lock_ReleaseWrite(&scp->rw);
8178 if (checkDoneRequired)
8179 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8180 cm_ReleaseSCache(scp);
8181 cm_ReleaseUser(userp);
8182 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
8183 smb_CloseFID(vcp, fidp, NULL, 0);
8184 smb_ReleaseFID(fidp);
8186 return CM_ERROR_SHARING_VIOLATION;
8190 /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
8191 if (checkDoneRequired) {
8192 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8193 checkDoneRequired = 0;
8196 lock_ObtainMutex(&fidp->mx);
8197 /* save a pointer to the vnode */
8199 lock_ObtainWrite(&scp->rw);
8200 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8201 lock_ReleaseWrite(&scp->rw);
8202 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
8204 fidp->flags = fidflags;
8206 /* remember if the file was newly created */
8208 fidp->flags |= SMB_FID_CREATED;
8210 /* save parent dir and pathname for deletion or change notification */
8211 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8212 fidp->flags |= SMB_FID_NTOPEN;
8213 fidp->NTopen_dscp = dscp;
8214 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
8216 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
8218 fidp->NTopen_wholepathp = realPathp;
8219 lock_ReleaseMutex(&fidp->mx);
8221 /* we don't need this any longer */
8223 cm_ReleaseSCache(dscp);
8225 cm_Open(scp, 0, userp);
8227 /* set inp->fid so that later read calls in same msg can find fid */
8228 inp->fid = fidp->fid;
8230 /* check whether we are required to send an extended response */
8231 if (!extendedRespRequired) {
8233 parmOffset = 8*4 + 39;
8234 parmOffset += 1; /* pad to 4 */
8235 dataOffset = parmOffset + 70;
8239 /* Total Parameter Count */
8240 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8241 /* Total Data Count */
8242 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8243 /* Parameter Count */
8244 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8245 /* Parameter Offset */
8246 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8247 /* Parameter Displacement */
8248 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8250 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8252 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8253 /* Data Displacement */
8254 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8255 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8256 smb_SetSMBDataLength(outp, 70);
8258 lock_ObtainRead(&scp->rw);
8259 outData = smb_GetSMBData(outp, NULL);
8260 outData++; /* round to get to parmOffset */
8261 *outData = 0; outData++; /* oplock */
8262 *outData = 0; outData++; /* reserved */
8263 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8264 *((ULONG *)outData) = openAction; outData += 4;
8265 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8266 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8267 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8268 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8269 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8270 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8271 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8272 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8273 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8274 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8275 *((USHORT *)outData) = 0; outData += 2; /* dev state */
8276 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8277 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8278 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8279 outData += 2; /* is a dir? */
8282 parmOffset = 8*4 + 39;
8283 parmOffset += 1; /* pad to 4 */
8284 dataOffset = parmOffset + 104;
8288 /* Total Parameter Count */
8289 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8290 /* Total Data Count */
8291 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8292 /* Parameter Count */
8293 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8294 /* Parameter Offset */
8295 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8296 /* Parameter Displacement */
8297 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8299 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8301 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8302 /* Data Displacement */
8303 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8304 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8305 smb_SetSMBDataLength(outp, 105);
8307 lock_ObtainRead(&scp->rw);
8308 outData = smb_GetSMBData(outp, NULL);
8309 outData++; /* round to get to parmOffset */
8310 *outData = 0; outData++; /* oplock */
8311 *outData = 1; outData++; /* response type */
8312 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8313 *((ULONG *)outData) = openAction; outData += 4;
8314 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8315 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8316 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8317 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8318 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8319 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8320 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8321 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8322 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8323 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8324 *((USHORT *)outData) = 0; outData += 2; /* dev state */
8325 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8326 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8327 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8328 outData += 1; /* is a dir? */
8329 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
8330 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
8331 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
8334 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
8335 LargeIntegerGreaterThanZero(fidp->scp->length) &&
8336 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
8339 lock_ReleaseRead(&scp->rw);
8342 cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
8343 fidp->scp->length.LowPart, fidp->scp->length.HighPart,
8346 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
8348 cm_ReleaseUser(userp);
8349 smb_ReleaseFID(fidp);
8351 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
8352 /* leave scp held since we put it in fidp->scp */
8356 /* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
8357 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
8360 smb_packet_t *savedPacketp;
8362 USHORT fid, watchtree;
8366 filter = smb_GetSMBParm(inp, 19) |
8367 (smb_GetSMBParm(inp, 20) << 16);
8368 fid = smb_GetSMBParm(inp, 21);
8369 watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
8371 fidp = smb_FindFID(vcp, fid, 0);
8373 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
8374 return CM_ERROR_BADFD;
8377 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8378 smb_CloseFID(vcp, fidp, NULL, 0);
8379 smb_ReleaseFID(fidp);
8380 return CM_ERROR_NOSUCHFILE;
8383 /* Create a copy of the Directory Watch Packet to use when sending the
8384 * notification if in the future a matching change is detected.
8386 savedPacketp = smb_CopyPacket(inp);
8387 if (vcp != savedPacketp->vcp) {
8389 if (savedPacketp->vcp)
8390 smb_ReleaseVC(savedPacketp->vcp);
8391 savedPacketp->vcp = vcp;
8394 /* Add the watch to the list of events to send notifications for */
8395 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8396 savedPacketp->nextp = smb_Directory_Watches;
8397 smb_Directory_Watches = savedPacketp;
8398 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8401 osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%S\"",
8402 fidp, scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp));
8403 osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
8404 filter, fid, watchtree);
8405 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8406 osi_Log0(smb_logp, " Notify Change File Name");
8407 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8408 osi_Log0(smb_logp, " Notify Change Directory Name");
8409 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8410 osi_Log0(smb_logp, " Notify Change Attributes");
8411 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8412 osi_Log0(smb_logp, " Notify Change Size");
8413 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8414 osi_Log0(smb_logp, " Notify Change Last Write");
8415 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8416 osi_Log0(smb_logp, " Notify Change Last Access");
8417 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8418 osi_Log0(smb_logp, " Notify Change Creation");
8419 if (filter & FILE_NOTIFY_CHANGE_EA)
8420 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8421 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8422 osi_Log0(smb_logp, " Notify Change Security");
8423 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8424 osi_Log0(smb_logp, " Notify Change Stream Name");
8425 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8426 osi_Log0(smb_logp, " Notify Change Stream Size");
8427 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8428 osi_Log0(smb_logp, " Notify Change Stream Write");
8430 lock_ObtainWrite(&scp->rw);
8432 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
8434 scp->flags |= CM_SCACHEFLAG_WATCHED;
8435 lock_ReleaseWrite(&scp->rw);
8436 smb_ReleaseFID(fidp);
8438 outp->flags |= SMB_PACKETFLAG_NOSEND;
8442 unsigned char nullSecurityDesc[36] = {
8443 0x01, /* security descriptor revision */
8444 0x00, /* reserved, should be zero */
8445 0x00, 0x80, /* security descriptor control;
8446 * 0x8000 : self-relative format */
8447 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
8448 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
8449 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
8450 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
8451 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8452 /* "null SID" owner SID */
8453 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
8454 /* "null SID" group SID */
8457 /* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
8458 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8460 int parmOffset, parmCount, dataOffset, dataCount;
8468 ULONG securityInformation;
8470 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8471 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8472 parmp = inp->data + parmOffset;
8473 sparmp = (USHORT *) parmp;
8474 lparmp = (ULONG *) parmp;
8477 securityInformation = lparmp[1];
8479 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
8480 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
8488 parmOffset = 8*4 + 39;
8489 parmOffset += 1; /* pad to 4 */
8491 dataOffset = parmOffset + parmCount;
8495 /* Total Parameter Count */
8496 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8497 /* Total Data Count */
8498 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8499 /* Parameter Count */
8500 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8501 /* Parameter Offset */
8502 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8503 /* Parameter Displacement */
8504 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8506 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8508 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8509 /* Data Displacement */
8510 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8511 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8512 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
8514 outData = smb_GetSMBData(outp, NULL);
8515 outData++; /* round to get to parmOffset */
8516 *((ULONG *)outData) = 36; outData += 4; /* length */
8518 if (maxData >= 36) {
8519 memcpy(outData, nullSecurityDesc, 36);
8523 return CM_ERROR_BUFFERTOOSMALL;
8526 /* SMB_COM_NT_TRANSACT
8528 SMB_COM_NT_TRANSACT_SECONDARY should also be handled here.
8530 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8532 unsigned short function;
8534 function = smb_GetSMBParm(inp, 18);
8536 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
8538 /* We can handle long names */
8539 if (vcp->flags & SMB_VCFLAG_USENT)
8540 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
8543 case 1: /* NT_TRANSACT_CREATE */
8544 return smb_ReceiveNTTranCreate(vcp, inp, outp);
8545 case 2: /* NT_TRANSACT_IOCTL */
8546 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
8548 case 3: /* NT_TRANSACT_SET_SECURITY_DESC */
8549 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
8551 case 4: /* NT_TRANSACT_NOTIFY_CHANGE */
8552 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
8553 case 5: /* NT_TRANSACT_RENAME */
8554 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
8556 case 6: /* NT_TRANSACT_QUERY_SECURITY_DESC */
8557 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
8559 osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
8562 osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
8565 return CM_ERROR_INVAL;
8569 * smb_NotifyChange -- find relevant change notification messages and
8572 * If we don't know the file name (i.e. a callback break), filename is
8573 * NULL, and we return a zero-length list.
8575 * At present there is not a single call to smb_NotifyChange that
8576 * has the isDirectParent parameter set to FALSE.
8578 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
8579 cm_scache_t *dscp, clientchar_t *filename, clientchar_t *otherFilename,
8580 BOOL isDirectParent)
8582 smb_packet_t *watch, *lastWatch, *nextWatch;
8583 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen = 0;
8584 char *outData, *oldOutData;
8588 BOOL twoEntries = FALSE;
8589 ULONG otherNameLen, oldParmCount = 0;
8593 /* Get ready for rename within directory */
8594 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
8596 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
8599 osi_Log4(smb_logp,"in smb_NotifyChange for file [%S] dscp [%p] notification 0x%x parent %d",
8600 osi_LogSaveClientString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
8602 osi_Log0(smb_logp," FILE_ACTION_NONE");
8603 if (action == FILE_ACTION_ADDED)
8604 osi_Log0(smb_logp," FILE_ACTION_ADDED");
8605 if (action == FILE_ACTION_REMOVED)
8606 osi_Log0(smb_logp," FILE_ACTION_REMOVED");
8607 if (action == FILE_ACTION_MODIFIED)
8608 osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
8609 if (action == FILE_ACTION_RENAMED_OLD_NAME)
8610 osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
8611 if (action == FILE_ACTION_RENAMED_NEW_NAME)
8612 osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
8614 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8615 watch = smb_Directory_Watches;
8617 filter = smb_GetSMBParm(watch, 19)
8618 | (smb_GetSMBParm(watch, 20) << 16);
8619 fid = smb_GetSMBParm(watch, 21);
8620 wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
8622 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
8623 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
8626 * Strange hack - bug in NT Client and NT Server that we must emulate?
8628 if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
8629 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
8631 fidp = smb_FindFID(watch->vcp, fid, 0);
8633 osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
8635 watch = watch->nextp;
8639 if (fidp->scp != dscp ||
8640 fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
8641 (filter & notifyFilter) == 0 ||
8642 (!isDirectParent && !wtree))
8644 osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
8646 watch = watch->nextp;
8647 smb_ReleaseFID(fidp);
8652 "Sending Change Notification for fid %d filter 0x%x wtree %d file %S",
8653 fid, filter, wtree, osi_LogSaveClientString(smb_logp, filename));
8654 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8655 osi_Log0(smb_logp, " Notify Change File Name");
8656 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8657 osi_Log0(smb_logp, " Notify Change Directory Name");
8658 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8659 osi_Log0(smb_logp, " Notify Change Attributes");
8660 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8661 osi_Log0(smb_logp, " Notify Change Size");
8662 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8663 osi_Log0(smb_logp, " Notify Change Last Write");
8664 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8665 osi_Log0(smb_logp, " Notify Change Last Access");
8666 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8667 osi_Log0(smb_logp, " Notify Change Creation");
8668 if (filter & FILE_NOTIFY_CHANGE_EA)
8669 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8670 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8671 osi_Log0(smb_logp, " Notify Change Security");
8672 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8673 osi_Log0(smb_logp, " Notify Change Stream Name");
8674 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8675 osi_Log0(smb_logp, " Notify Change Stream Size");
8676 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8677 osi_Log0(smb_logp, " Notify Change Stream Write");
8679 /* A watch can only be notified once. Remove it from the list */
8680 nextWatch = watch->nextp;
8681 if (watch == smb_Directory_Watches)
8682 smb_Directory_Watches = nextWatch;
8684 lastWatch->nextp = nextWatch;
8686 /* Turn off WATCHED flag in dscp */
8687 lock_ObtainWrite(&dscp->rw);
8689 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8691 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
8692 lock_ReleaseWrite(&dscp->rw);
8694 /* Convert to response packet */
8695 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
8696 #ifdef SEND_CANONICAL_PATHNAMES
8697 ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
8699 ((smb_t *) watch)->wct = 0;
8702 if (filename == NULL) {
8705 nameLen = (ULONG)cm_ClientStrLen(filename);
8706 parmCount = 3*4 + nameLen*2;
8707 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8709 otherNameLen = (ULONG)cm_ClientStrLen(otherFilename);
8710 oldParmCount = parmCount;
8711 parmCount += 3*4 + otherNameLen*2;
8712 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8714 if (maxLen < parmCount)
8715 parmCount = 0; /* not enough room */
8717 parmOffset = 8*4 + 39;
8718 parmOffset += 1; /* pad to 4 */
8719 dataOffset = parmOffset + parmCount;
8723 /* Total Parameter Count */
8724 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8725 /* Total Data Count */
8726 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8727 /* Parameter Count */
8728 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8729 /* Parameter Offset */
8730 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
8731 /* Parameter Displacement */
8732 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8734 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8736 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
8737 /* Data Displacement */
8738 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8739 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
8740 smb_SetSMBDataLength(watch, parmCount + 1);
8742 if (parmCount != 0) {
8743 outData = smb_GetSMBData(watch, NULL);
8744 outData++; /* round to get to parmOffset */
8745 oldOutData = outData;
8746 *((DWORD *)outData) = oldParmCount; outData += 4;
8747 /* Next Entry Offset */
8748 *((DWORD *)outData) = action; outData += 4;
8750 *((DWORD *)outData) = nameLen*2; outData += 4;
8751 /* File Name Length */
8753 smb_UnparseString(watch, outData, filename, NULL, 0);
8757 outData = oldOutData + oldParmCount;
8758 *((DWORD *)outData) = 0; outData += 4;
8759 /* Next Entry Offset */
8760 *((DWORD *)outData) = otherAction; outData += 4;
8762 *((DWORD *)outData) = otherNameLen*2;
8763 outData += 4; /* File Name Length */
8764 smb_UnparseString(watch, outData, otherFilename, NULL, 0);
8769 * If filename is null, we don't know the cause of the
8770 * change notification. We return zero data (see above),
8771 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
8772 * (= 0x010C). We set the error code here by hand, without
8773 * modifying wct and bcc.
8775 if (filename == NULL) {
8776 ((smb_t *) watch)->rcls = 0x0C;
8777 ((smb_t *) watch)->reh = 0x01;
8778 ((smb_t *) watch)->errLow = 0;
8779 ((smb_t *) watch)->errHigh = 0;
8780 /* Set NT Status codes flag */
8781 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8784 smb_SendPacket(watch->vcp, watch);
8785 smb_FreePacket(watch);
8787 smb_ReleaseFID(fidp);
8790 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8793 /* SMB_COM_NT_CANCEL */
8794 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8796 unsigned char *replyWctp;
8797 smb_packet_t *watch, *lastWatch;
8798 USHORT fid, watchtree;
8802 osi_Log0(smb_logp, "SMB3 receive NT cancel");
8804 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8805 watch = smb_Directory_Watches;
8807 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
8808 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
8809 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
8810 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
8811 if (watch == smb_Directory_Watches)
8812 smb_Directory_Watches = watch->nextp;
8814 lastWatch->nextp = watch->nextp;
8815 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8817 /* Turn off WATCHED flag in scp */
8818 fid = smb_GetSMBParm(watch, 21);
8819 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
8821 if (vcp != watch->vcp)
8822 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
8825 fidp = smb_FindFID(vcp, fid, 0);
8827 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %S",
8829 (fidp ? osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp) :_C("")));
8832 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
8833 lock_ObtainWrite(&scp->rw);
8835 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8837 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
8838 lock_ReleaseWrite(&scp->rw);
8839 smb_ReleaseFID(fidp);
8841 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
8844 /* assume STATUS32; return 0xC0000120 (CANCELED) */
8845 replyWctp = watch->wctp;
8849 ((smb_t *)watch)->rcls = 0x20;
8850 ((smb_t *)watch)->reh = 0x1;
8851 ((smb_t *)watch)->errLow = 0;
8852 ((smb_t *)watch)->errHigh = 0xC0;
8853 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8854 smb_SendPacket(vcp, watch);
8855 smb_FreePacket(watch);
8859 watch = watch->nextp;
8861 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8867 * NT rename also does hard links.
8870 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
8871 #define RENAME_FLAG_HARD_LINK 0x103
8872 #define RENAME_FLAG_RENAME 0x104
8873 #define RENAME_FLAG_COPY 0x105
8875 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8877 clientchar_t *oldPathp, *newPathp;
8883 attrs = smb_GetSMBParm(inp, 0);
8884 rename_type = smb_GetSMBParm(inp, 1);
8886 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
8887 osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
8888 return CM_ERROR_NOACCESS;
8891 tp = smb_GetSMBData(inp, NULL);
8892 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
8893 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
8895 osi_Log3(smb_logp, "NTRename for [%S]->[%S] type [%s]",
8896 osi_LogSaveClientString(smb_logp, oldPathp),
8897 osi_LogSaveClientString(smb_logp, newPathp),
8898 ((rename_type==RENAME_FLAG_RENAME)?"rename":(rename_type==RENAME_FLAG_HARD_LINK)?"hardlink":"other"));
8900 if (rename_type == RENAME_FLAG_RENAME) {
8901 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
8902 } else if (rename_type == RENAME_FLAG_HARD_LINK) { /* RENAME_FLAG_HARD_LINK */
8903 code = smb_Link(vcp,inp,oldPathp,newPathp);
8905 code = CM_ERROR_BADOP;
8911 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock", LOCK_HIERARCHY_SMB_DIRWATCH);
8914 cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
8916 smb_username_t *unp;
8919 unp = smb_FindUserByName(usern, machine, flags);
8921 lock_ObtainMutex(&unp->mx);
8922 unp->userp = cm_NewUser();
8923 lock_ReleaseMutex(&unp->mx);
8924 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
8926 osi_Log2(smb_logp,"smb_FindCMUserByName Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
8930 smb_ReleaseUsername(unp);