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 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2762 qi.u.FSattributeInfo.maxCompLength = MAX_PATH * sizeof(wchar_t);
2765 qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
2769 smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
2770 qi.u.FSattributeInfo.FSnameLength = sz;
2773 sizeof(qi.u.FSattributeInfo.attributes) +
2774 sizeof(qi.u.FSattributeInfo.maxCompLength) +
2775 sizeof(qi.u.FSattributeInfo.FSnameLength) +
2780 case SMB_INFO_UNIX: /* CIFS Unix Info */
2781 case SMB_INFO_MACOS: /* Mac FS Info */
2783 return CM_ERROR_BADOP;
2786 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2788 /* copy out return data, and set corresponding sizes */
2789 outp->totalParms = 0;
2790 outp->totalData = responseSize;
2791 memcpy(outp->datap, &qi, responseSize);
2793 /* send and free the packets */
2794 smb_SendTran2Packet(vcp, outp, op);
2795 smb_FreeTran2Packet(outp);
2800 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2802 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2803 return CM_ERROR_BADOP;
2806 struct smb_ShortNameRock {
2807 clientchar_t *maskp;
2809 clientchar_t *shortName;
2810 size_t shortNameLen;
2813 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2816 struct smb_ShortNameRock *rockp;
2817 normchar_t normName[MAX_PATH];
2818 clientchar_t *shortNameEnd;
2822 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t)) == 0) {
2823 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
2824 osi_LogSaveString(smb_logp, dep->name));
2828 /* compare both names and vnodes, though probably just comparing vnodes
2829 * would be safe enough.
2831 if (cm_NormStrCmpI(normName, rockp->maskp) != 0)
2833 if (ntohl(dep->fid.vnode) != rockp->vnode)
2836 /* This is the entry */
2837 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2838 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2840 return CM_ERROR_STOPNOW;
2843 long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
2844 clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
2846 struct smb_ShortNameRock rock;
2847 clientchar_t *lastNamep;
2850 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2854 spacep = cm_GetSpace();
2855 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2857 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2858 caseFold, userp, tidPathp,
2860 cm_FreeSpace(spacep);
2865 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2866 cm_ReleaseSCache(dscp);
2867 cm_ReleaseUser(userp);
2871 return CM_ERROR_PATH_NOT_COVERED;
2873 #endif /* DFS_SUPPORT */
2875 if (!lastNamep) lastNamep = pathp;
2878 thyper.HighPart = 0;
2879 rock.shortName = shortName;
2881 rock.maskp = lastNamep;
2882 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2884 cm_ReleaseSCache(dscp);
2887 return CM_ERROR_NOSUCHFILE;
2888 if (code == CM_ERROR_STOPNOW) {
2889 *shortNameLenp = rock.shortNameLen;
2895 /* TRANS2_QUERY_PATH_INFORMATION */
2896 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2898 smb_tran2Packet_t *outp;
2901 unsigned short infoLevel;
2902 smb_tran2QPathInfo_t qpi;
2904 unsigned short attributes;
2905 unsigned long extAttributes;
2906 clientchar_t shortName[13];
2910 cm_scache_t *scp, *dscp;
2911 int scp_rw_held = 0;
2914 clientchar_t *pathp;
2915 clientchar_t *tidPathp;
2916 clientchar_t *lastComp;
2921 infoLevel = p->parmsp[0];
2922 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2924 else if (infoLevel == SMB_INFO_STANDARD)
2925 responseSize = sizeof(qpi.u.QPstandardInfo);
2926 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2927 responseSize = sizeof(qpi.u.QPeaSizeInfo);
2928 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2929 responseSize = sizeof(qpi.u.QPfileBasicInfo);
2930 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2931 responseSize = sizeof(qpi.u.QPfileStandardInfo);
2932 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2933 responseSize = sizeof(qpi.u.QPfileEaInfo);
2934 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2935 responseSize = sizeof(qpi.u.QPfileNameInfo);
2936 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
2937 responseSize = sizeof(qpi.u.QPfileAllInfo);
2938 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2939 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2941 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2942 p->opcode, infoLevel);
2943 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
2947 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
2948 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %S", infoLevel,
2949 osi_LogSaveClientString(smb_logp, pathp));
2951 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2953 if (infoLevel > 0x100)
2954 outp->totalParms = 2;
2956 outp->totalParms = 0;
2957 outp->totalData = responseSize;
2959 /* now, if we're at infoLevel 6, we're only being asked to check
2960 * the syntax, so we just OK things now. In particular, we're *not*
2961 * being asked to verify anything about the state of any parent dirs.
2963 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2964 smb_SendTran2Packet(vcp, outp, opx);
2965 smb_FreeTran2Packet(outp);
2969 userp = smb_GetTran2User(vcp, p);
2971 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2972 smb_FreeTran2Packet(outp);
2973 return CM_ERROR_BADSMB;
2976 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2978 cm_ReleaseUser(userp);
2979 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2980 smb_FreeTran2Packet(outp);
2985 * XXX Strange hack XXX
2987 * As of Patch 7 (13 January 98), we are having the following problem:
2988 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2989 * requests to look up "desktop.ini" in all the subdirectories.
2990 * This can cause zillions of timeouts looking up non-existent cells
2991 * and volumes, especially in the top-level directory.
2993 * We have not found any way to avoid this or work around it except
2994 * to explicitly ignore the requests for mount points that haven't
2995 * yet been evaluated and for directories that haven't yet been
2998 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2999 spacep = cm_GetSpace();
3000 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3001 #ifndef SPECIAL_FOLDERS
3002 /* Make sure that lastComp is not NULL */
3004 if (cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
3005 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3009 userp, tidPathp, &req, &dscp);
3012 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3013 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3015 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3016 code = CM_ERROR_PATH_NOT_COVERED;
3018 code = CM_ERROR_BADSHARENAME;
3020 #endif /* DFS_SUPPORT */
3021 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3022 code = CM_ERROR_NOSUCHFILE;
3023 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3024 cm_buf_t *bp = buf_Find(dscp, &hzero);
3030 code = CM_ERROR_NOSUCHFILE;
3032 cm_ReleaseSCache(dscp);
3034 cm_FreeSpace(spacep);
3035 cm_ReleaseUser(userp);
3036 smb_SendTran2Error(vcp, p, opx, code);
3037 smb_FreeTran2Packet(outp);
3043 #endif /* SPECIAL_FOLDERS */
3045 cm_FreeSpace(spacep);
3048 /* now do namei and stat, and copy out the info */
3049 code = cm_NameI(cm_data.rootSCachep, pathp,
3050 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3053 cm_ReleaseUser(userp);
3054 smb_SendTran2Error(vcp, p, opx, code);
3055 smb_FreeTran2Packet(outp);
3060 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3061 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3062 cm_ReleaseSCache(scp);
3063 cm_ReleaseUser(userp);
3064 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3065 code = CM_ERROR_PATH_NOT_COVERED;
3067 code = CM_ERROR_BADSHARENAME;
3068 smb_SendTran2Error(vcp, p, opx, code);
3069 smb_FreeTran2Packet(outp);
3072 #endif /* DFS_SUPPORT */
3074 lock_ObtainWrite(&scp->rw);
3076 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3077 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3081 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3083 lock_ConvertWToR(&scp->rw);
3088 /* now we have the status in the cache entry, and everything is locked.
3089 * Marshall the output data.
3091 /* for info level 108, figure out short name */
3092 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3093 code = cm_GetShortName(pathp, userp, &req,
3094 tidPathp, scp->fid.vnode, shortName,
3100 smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
3101 qpi.u.QPfileAltNameInfo.fileNameLength = len;
3105 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3106 smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3107 qpi.u.QPfileNameInfo.fileNameLength = len;
3111 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3112 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3113 qpi.u.QPstandardInfo.creationDateTime = dosTime;
3114 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3115 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3116 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3117 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3118 attributes = smb_Attributes(scp);
3119 qpi.u.QPstandardInfo.attributes = attributes;
3120 qpi.u.QPstandardInfo.eaSize = 0;
3122 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3123 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3124 qpi.u.QPfileBasicInfo.creationTime = ft;
3125 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3126 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3127 qpi.u.QPfileBasicInfo.changeTime = ft;
3128 extAttributes = smb_ExtAttributes(scp);
3129 qpi.u.QPfileBasicInfo.attributes = extAttributes;
3130 qpi.u.QPfileBasicInfo.reserved = 0;
3132 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3135 lock_ReleaseRead(&scp->rw);
3137 fidp = smb_FindFIDByScache(vcp, scp);
3139 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3140 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3141 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3142 qpi.u.QPfileStandardInfo.directory =
3143 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3144 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3145 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3146 qpi.u.QPfileStandardInfo.reserved = 0;
3149 lock_ObtainMutex(&fidp->mx);
3150 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3151 lock_ReleaseMutex(&fidp->mx);
3152 smb_ReleaseFID(fidp);
3154 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3156 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3157 qpi.u.QPfileEaInfo.eaSize = 0;
3159 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3160 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3161 qpi.u.QPfileAllInfo.creationTime = ft;
3162 qpi.u.QPfileAllInfo.lastAccessTime = ft;
3163 qpi.u.QPfileAllInfo.lastWriteTime = ft;
3164 qpi.u.QPfileAllInfo.changeTime = ft;
3165 extAttributes = smb_ExtAttributes(scp);
3166 qpi.u.QPfileAllInfo.attributes = extAttributes;
3167 qpi.u.QPfileAllInfo.allocationSize = scp->length;
3168 qpi.u.QPfileAllInfo.endOfFile = scp->length;
3169 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3170 qpi.u.QPfileAllInfo.deletePending = 0;
3171 qpi.u.QPfileAllInfo.directory =
3172 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3173 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3174 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3175 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
3176 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
3177 qpi.u.QPfileAllInfo.eaSize = 0;
3178 qpi.u.QPfileAllInfo.accessFlags = 0;
3179 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
3180 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
3181 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3182 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3183 qpi.u.QPfileAllInfo.mode = 0;
3184 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3186 smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3187 qpi.u.QPfileAllInfo.fileNameLength = len;
3190 /* send and free the packets */
3192 switch (scp_rw_held) {
3194 lock_ReleaseRead(&scp->rw);
3197 lock_ReleaseWrite(&scp->rw);
3201 cm_ReleaseSCache(scp);
3202 cm_ReleaseUser(userp);
3204 memcpy(outp->datap, &qpi, responseSize);
3205 smb_SendTran2Packet(vcp, outp, opx);
3207 smb_SendTran2Error(vcp, p, opx, code);
3209 smb_FreeTran2Packet(outp);
3214 /* TRANS2_SET_PATH_INFORMATION */
3215 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3218 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
3219 return CM_ERROR_BADOP;
3223 unsigned short infoLevel;
3224 clientchar_t * pathp;
3225 smb_tran2Packet_t *outp;
3226 smb_tran2QPathInfo_t *spi;
3228 cm_scache_t *scp, *dscp;
3231 clientchar_t *tidPathp;
3232 clientchar_t *lastComp;
3236 infoLevel = p->parmsp[0];
3237 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
3238 if (infoLevel != SMB_INFO_STANDARD &&
3239 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
3240 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
3241 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3242 p->opcode, infoLevel);
3243 smb_SendTran2Error(vcp, p, opx,
3244 infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3248 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3250 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
3251 osi_LogSaveClientString(smb_logp, pathp));
3253 userp = smb_GetTran2User(vcp, p);
3255 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3256 code = CM_ERROR_BADSMB;
3260 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3261 if (code == CM_ERROR_TIDIPC) {
3262 /* Attempt to use a TID allocated for IPC. The client
3263 * is probably looking for DCE RPC end points which we
3264 * don't support OR it could be looking to make a DFS
3267 osi_Log0(smb_logp, "Tran2Open received IPC TID");
3268 cm_ReleaseUser(userp);
3269 return CM_ERROR_NOSUCHPATH;
3273 * XXX Strange hack XXX
3275 * As of Patch 7 (13 January 98), we are having the following problem:
3276 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3277 * requests to look up "desktop.ini" in all the subdirectories.
3278 * This can cause zillions of timeouts looking up non-existent cells
3279 * and volumes, especially in the top-level directory.
3281 * We have not found any way to avoid this or work around it except
3282 * to explicitly ignore the requests for mount points that haven't
3283 * yet been evaluated and for directories that haven't yet been
3286 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3287 spacep = cm_GetSpace();
3288 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3289 #ifndef SPECIAL_FOLDERS
3290 /* Make sure that lastComp is not NULL */
3292 if (cm_ClientStrCmpI(lastComp, _C("\\desktop.ini")) == 0) {
3293 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3297 userp, tidPathp, &req, &dscp);
3300 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3301 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3303 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3304 code = CM_ERROR_PATH_NOT_COVERED;
3306 code = CM_ERROR_BADSHARENAME;
3308 #endif /* DFS_SUPPORT */
3309 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3310 code = CM_ERROR_NOSUCHFILE;
3311 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3312 cm_buf_t *bp = buf_Find(dscp, &hzero);
3318 code = CM_ERROR_NOSUCHFILE;
3320 cm_ReleaseSCache(dscp);
3322 cm_FreeSpace(spacep);
3323 cm_ReleaseUser(userp);
3324 smb_SendTran2Error(vcp, p, opx, code);
3330 #endif /* SPECIAL_FOLDERS */
3332 cm_FreeSpace(spacep);
3335 /* now do namei and stat, and copy out the info */
3336 code = cm_NameI(cm_data.rootSCachep, pathp,
3337 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3339 cm_ReleaseUser(userp);
3340 smb_SendTran2Error(vcp, p, opx, code);
3344 fidp = smb_FindFIDByScache(vcp, scp);
3346 cm_ReleaseSCache(scp);
3347 cm_ReleaseUser(userp);
3348 smb_SendTran2Error(vcp, p, opx, code);
3352 lock_ObtainMutex(&fidp->mx);
3353 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
3354 lock_ReleaseMutex(&fidp->mx);
3355 cm_ReleaseSCache(scp);
3356 smb_ReleaseFID(fidp);
3357 cm_ReleaseUser(userp);
3358 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3361 lock_ReleaseMutex(&fidp->mx);
3363 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3365 outp->totalParms = 2;
3366 outp->totalData = 0;
3368 spi = (smb_tran2QPathInfo_t *)p->datap;
3369 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3372 /* lock the vnode with a callback; we need the current status
3373 * to determine what the new status is, in some cases.
3375 lock_ObtainWrite(&scp->rw);
3376 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3377 CM_SCACHESYNC_GETSTATUS
3378 | CM_SCACHESYNC_NEEDCALLBACK);
3380 lock_ReleaseWrite(&scp->rw);
3383 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3385 lock_ReleaseWrite(&scp->rw);
3386 lock_ObtainMutex(&fidp->mx);
3387 lock_ObtainRead(&scp->rw);
3389 /* prepare for setattr call */
3390 attr.mask = CM_ATTRMASK_LENGTH;
3391 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3392 attr.length.HighPart = 0;
3394 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3395 smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3396 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3397 fidp->flags |= SMB_FID_MTIMESETDONE;
3400 if (spi->u.QPstandardInfo.attributes != 0) {
3401 if ((scp->unixModeBits & 0222)
3402 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3403 /* make a writable file read-only */
3404 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3405 attr.unixModeBits = scp->unixModeBits & ~0222;
3407 else if ((scp->unixModeBits & 0222) == 0
3408 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3409 /* make a read-only file writable */
3410 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3411 attr.unixModeBits = scp->unixModeBits | 0222;
3414 lock_ReleaseRead(&scp->rw);
3415 lock_ReleaseMutex(&fidp->mx);
3419 code = cm_SetAttr(scp, &attr, userp, &req);
3423 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3424 /* we don't support EAs */
3425 code = CM_ERROR_EAS_NOT_SUPPORTED;
3429 cm_ReleaseSCache(scp);
3430 cm_ReleaseUser(userp);
3431 smb_ReleaseFID(fidp);
3433 smb_SendTran2Packet(vcp, outp, opx);
3435 smb_SendTran2Error(vcp, p, opx, code);
3436 smb_FreeTran2Packet(outp);
3442 /* TRANS2_QUERY_FILE_INFORMATION */
3443 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3445 smb_tran2Packet_t *outp;
3447 unsigned long attributes;
3448 unsigned short infoLevel;
3455 smb_tran2QFileInfo_t qfi;
3463 fidp = smb_FindFID(vcp, fid, 0);
3466 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3470 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3471 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3472 smb_CloseFID(vcp, fidp, NULL, 0);
3473 smb_ReleaseFID(fidp);
3477 infoLevel = p->parmsp[1];
3478 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3479 responseSize = sizeof(qfi.u.QFbasicInfo);
3480 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3481 responseSize = sizeof(qfi.u.QFstandardInfo);
3482 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3483 responseSize = sizeof(qfi.u.QFeaInfo);
3484 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3485 responseSize = sizeof(qfi.u.QFfileNameInfo);
3487 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3488 p->opcode, infoLevel);
3489 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3490 smb_ReleaseFID(fidp);
3493 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3495 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3497 if (infoLevel > 0x100)
3498 outp->totalParms = 2;
3500 outp->totalParms = 0;
3501 outp->totalData = responseSize;
3503 userp = smb_GetTran2User(vcp, p);
3505 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3506 code = CM_ERROR_BADSMB;
3510 lock_ObtainMutex(&fidp->mx);
3511 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3513 osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3515 lock_ReleaseMutex(&fidp->mx);
3516 lock_ObtainWrite(&scp->rw);
3517 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3518 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3522 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3524 lock_ConvertWToR(&scp->rw);
3527 /* now we have the status in the cache entry, and everything is locked.
3528 * Marshall the output data.
3530 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3531 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3532 qfi.u.QFbasicInfo.creationTime = ft;
3533 qfi.u.QFbasicInfo.lastAccessTime = ft;
3534 qfi.u.QFbasicInfo.lastWriteTime = ft;
3535 qfi.u.QFbasicInfo.lastChangeTime = ft;
3536 attributes = smb_ExtAttributes(scp);
3537 qfi.u.QFbasicInfo.attributes = attributes;
3539 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3540 qfi.u.QFstandardInfo.allocationSize = scp->length;
3541 qfi.u.QFstandardInfo.endOfFile = scp->length;
3542 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3543 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3544 qfi.u.QFstandardInfo.directory =
3545 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3546 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3547 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3549 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3550 qfi.u.QFeaInfo.eaSize = 0;
3552 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3556 lock_ReleaseRead(&scp->rw);
3557 lock_ObtainMutex(&fidp->mx);
3558 lock_ObtainRead(&scp->rw);
3559 if (fidp->NTopen_wholepathp)
3560 name = fidp->NTopen_wholepathp;
3562 name = _C("\\"); /* probably can't happen */
3563 lock_ReleaseMutex(&fidp->mx);
3565 smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, SMB_STRF_IGNORENUL);
3566 outp->totalData = len + 4; /* this is actually what we want to return */
3567 qfi.u.QFfileNameInfo.fileNameLength = len;
3570 /* send and free the packets */
3573 lock_ReleaseRead(&scp->rw);
3575 lock_ReleaseWrite(&scp->rw);
3576 cm_ReleaseSCache(scp);
3577 cm_ReleaseUser(userp);
3578 smb_ReleaseFID(fidp);
3580 memcpy(outp->datap, &qfi, responseSize);
3581 smb_SendTran2Packet(vcp, outp, opx);
3583 smb_SendTran2Error(vcp, p, opx, code);
3585 smb_FreeTran2Packet(outp);
3591 /* TRANS2_SET_FILE_INFORMATION */
3592 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3597 unsigned short infoLevel;
3598 smb_tran2Packet_t *outp;
3599 cm_user_t *userp = NULL;
3600 cm_scache_t *scp = NULL;
3606 fidp = smb_FindFID(vcp, fid, 0);
3609 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3613 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3614 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3615 smb_CloseFID(vcp, fidp, NULL, 0);
3616 smb_ReleaseFID(fidp);
3620 infoLevel = p->parmsp[1];
3621 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3622 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3623 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3624 p->opcode, infoLevel);
3625 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3626 smb_ReleaseFID(fidp);
3630 lock_ObtainMutex(&fidp->mx);
3631 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
3632 !(fidp->flags & SMB_FID_OPENDELETE)) {
3633 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3634 fidp, fidp->scp, fidp->flags);
3635 lock_ReleaseMutex(&fidp->mx);
3636 smb_ReleaseFID(fidp);
3637 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3640 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3641 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3642 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3643 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3644 fidp, fidp->scp, fidp->flags);
3645 lock_ReleaseMutex(&fidp->mx);
3646 smb_ReleaseFID(fidp);
3647 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3652 osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3654 lock_ReleaseMutex(&fidp->mx);
3656 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3658 outp->totalParms = 2;
3659 outp->totalData = 0;
3661 userp = smb_GetTran2User(vcp, p);
3663 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3664 code = CM_ERROR_BADSMB;
3668 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3670 unsigned int attribute;
3672 smb_tran2QFileInfo_t *sfi;
3674 sfi = (smb_tran2QFileInfo_t *)p->datap;
3676 /* lock the vnode with a callback; we need the current status
3677 * to determine what the new status is, in some cases.
3679 lock_ObtainWrite(&scp->rw);
3680 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3681 CM_SCACHESYNC_GETSTATUS
3682 | CM_SCACHESYNC_NEEDCALLBACK);
3684 lock_ReleaseWrite(&scp->rw);
3688 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3690 lock_ReleaseWrite(&scp->rw);
3691 lock_ObtainMutex(&fidp->mx);
3692 lock_ObtainRead(&scp->rw);
3694 /* prepare for setattr call */
3697 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3698 /* when called as result of move a b, lastMod is (-1, -1).
3699 * If the check for -1 is not present, timestamp
3700 * of the resulting file will be 1969 (-1)
3702 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3703 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3704 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3705 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3706 fidp->flags |= SMB_FID_MTIMESETDONE;
3709 attribute = sfi->u.QFbasicInfo.attributes;
3710 if (attribute != 0) {
3711 if ((scp->unixModeBits & 0222)
3712 && (attribute & SMB_ATTR_READONLY) != 0) {
3713 /* make a writable file read-only */
3714 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3715 attr.unixModeBits = scp->unixModeBits & ~0222;
3717 else if ((scp->unixModeBits & 0222) == 0
3718 && (attribute & SMB_ATTR_READONLY) == 0) {
3719 /* make a read-only file writable */
3720 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3721 attr.unixModeBits = scp->unixModeBits | 0222;
3724 lock_ReleaseRead(&scp->rw);
3725 lock_ReleaseMutex(&fidp->mx);
3729 code = cm_SetAttr(scp, &attr, userp, &req);
3733 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3734 int delflag = *((char *)(p->datap));
3735 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
3736 delflag, fidp, scp);
3737 if (*((char *)(p->datap))) { /* File is Deleted */
3738 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3741 lock_ObtainMutex(&fidp->mx);
3742 fidp->flags |= SMB_FID_DELONCLOSE;
3743 lock_ReleaseMutex(&fidp->mx);
3745 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
3751 lock_ObtainMutex(&fidp->mx);
3752 fidp->flags &= ~SMB_FID_DELONCLOSE;
3753 lock_ReleaseMutex(&fidp->mx);
3756 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3757 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3758 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3761 attr.mask = CM_ATTRMASK_LENGTH;
3762 attr.length.LowPart = size.LowPart;
3763 attr.length.HighPart = size.HighPart;
3764 code = cm_SetAttr(scp, &attr, userp, &req);
3768 cm_ReleaseSCache(scp);
3769 cm_ReleaseUser(userp);
3770 smb_ReleaseFID(fidp);
3772 smb_SendTran2Packet(vcp, outp, opx);
3774 smb_SendTran2Error(vcp, p, opx, code);
3775 smb_FreeTran2Packet(outp);
3782 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3784 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3785 return CM_ERROR_BADOP;
3790 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3792 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3793 return CM_ERROR_BADOP;
3796 /* TRANS2_FIND_NOTIFY_FIRST */
3798 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3800 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3801 return CM_ERROR_BADOP;
3804 /* TRANS2_FIND_NOTIFY_NEXT */
3806 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3808 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3809 return CM_ERROR_BADOP;
3812 /* TRANS2_CREATE_DIRECTORY */
3814 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3816 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3817 return CM_ERROR_BADOP;
3820 /* TRANS2_SESSION_SETUP */
3822 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3824 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3825 return CM_ERROR_BADOP;
3828 struct smb_v2_referral {
3830 USHORT ReferralFlags;
3833 USHORT DfsPathOffset;
3834 USHORT DfsAlternativePathOffset;
3835 USHORT NetworkAddressOffset;
3838 /* TRANS2_GET_DFS_REFERRAL */
3840 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3842 /* This is a UNICODE only request (bit15 of Flags2) */
3843 /* The TID must be IPC$ */
3845 /* The documentation for the Flags response field is contradictory */
3847 /* Use Version 1 Referral Element Format */
3848 /* ServerType = 0; indicates the next server should be queried for the file */
3849 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3850 /* Node = UnicodeString of UNC path of the next share name */
3853 int maxReferralLevel = 0;
3854 clientchar_t requestFileName[1024] = _C("");
3855 clientchar_t referralPath[1024] = _C("");
3856 smb_tran2Packet_t *outp = 0;
3857 cm_user_t *userp = 0;
3858 cm_scache_t *scp = 0;
3859 cm_scache_t *dscp = 0;
3861 CPINFO CodePageInfo;
3862 int i, nbnLen, reqLen, refLen;
3867 maxReferralLevel = p->parmsp[0];
3869 GetCPInfo(CP_ACP, &CodePageInfo);
3870 cm_Utf16ToClientString(&p->parmsp[1], -1, requestFileName, lengthof(requestFileName));
3872 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%S]",
3873 maxReferralLevel, osi_LogSaveClientString(smb_logp, requestFileName));
3875 nbnLen = (int)cm_ClientStrLen(cm_NetbiosNameC);
3876 reqLen = (int)cm_ClientStrLen(requestFileName);
3878 if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
3879 !cm_ClientStrCmpNI(cm_NetbiosNameC, &requestFileName[1], nbnLen) &&
3880 requestFileName[nbnLen+1] == '\\')
3884 if (!cm_ClientStrCmpNI(_C("all"), &requestFileName[nbnLen+2], 3) ||
3885 !cm_ClientStrCmpNI(_C("*."), &requestFileName[nbnLen+2], 2)) {
3887 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
3890 userp = smb_GetTran2User(vcp, p);
3892 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3893 code = CM_ERROR_BADSMB;
3898 * We have a requested path. Check to see if it is something
3901 * But be careful because the name that we might be searching
3902 * for might be a known name with the final character stripped
3905 code = cm_NameI(cm_data.rootSCachep, &requestFileName[nbnLen+2],
3906 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
3907 userp, NULL, &req, &scp);
3911 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
3913 } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
3914 clientchar_t temp[1024];
3915 clientchar_t pathName[1024];
3916 clientchar_t *lastComponent;
3918 * we have a msdfs link somewhere in the path
3919 * we should figure out where in the path the link is.
3922 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%S]", requestFileName);
3924 cm_ClientStrCpy(temp, lengthof(temp), &requestFileName[nbnLen+2]);
3928 cm_ReleaseSCache(dscp);
3932 cm_ReleaseSCache(scp);
3935 smb_StripLastComponent(pathName, &lastComponent, temp);
3937 code = cm_NameI(cm_data.rootSCachep, pathName,
3938 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3939 userp, NULL, &req, &dscp);
3941 code = cm_NameI(dscp, ++lastComponent,
3943 userp, NULL, &req, &scp);
3944 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK)
3947 } while (code == CM_ERROR_PATH_NOT_COVERED);
3949 /* scp should now be the DfsLink we are looking for */
3951 /* figure out how much of the input path was used */
3952 reqLen = (int)(nbnLen+2 + cm_ClientStrLen(pathName) + 1 + cm_ClientStrLen(lastComponent));
3954 cm_FsStringToClientString(&scp->mountPointStringp[strlen("msdfs:")], -1,
3955 referralPath, lengthof(referralPath));
3956 refLen = (int)cm_ClientStrLen(referralPath);
3960 clientchar_t shareName[MAX_PATH + 1];
3961 clientchar_t *p, *q;
3962 /* we may have a sharename that is a volume reference */
3964 for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
3970 if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
3971 code = cm_NameI(cm_data.rootSCachep, _C(""),
3972 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
3973 userp, p, &req, &scp);
3978 cm_ClientStrCpy(referralPath, lengthof(referralPath),
3989 struct smb_v2_referral * v2ref;
3990 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (refLen + 8));
3992 sp = (USHORT *)outp->datap;
3994 sp[idx++] = reqLen; /* path consumed */
3995 sp[idx++] = 1; /* number of referrals */
3996 sp[idx++] = 0x03; /* flags */
3997 #ifdef DFS_VERSION_1
3998 sp[idx++] = 1; /* Version Number */
3999 sp[idx++] = refLen + 4; /* Referral Size */
4000 sp[idx++] = 1; /* Type = SMB Server */
4001 sp[idx++] = 0; /* Do not strip path consumed */
4002 for ( i=0;i<=refLen; i++ )
4003 sp[i+idx] = referralPath[i];
4004 #else /* DFS_VERSION_2 */
4005 sp[idx++] = 2; /* Version Number */
4006 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
4007 idx += (sizeof(struct smb_v2_referral) / 2);
4008 v2ref = (struct smb_v2_referral *) &sp[5];
4009 v2ref->ServerType = 1; /* SMB Server */
4010 v2ref->ReferralFlags = 0x03;
4011 v2ref->Proximity = 0; /* closest */
4012 v2ref->TimeToLive = 3600; /* seconds */
4013 v2ref->DfsPathOffset = idx * 2;
4014 v2ref->DfsAlternativePathOffset = idx * 2;
4015 v2ref->NetworkAddressOffset = 0;
4016 for ( i=0;i<=refLen; i++ )
4017 sp[i+idx] = referralPath[i];
4021 code = CM_ERROR_NOSUCHPATH;
4026 cm_ReleaseSCache(dscp);
4028 cm_ReleaseSCache(scp);
4030 cm_ReleaseUser(userp);
4032 smb_SendTran2Packet(vcp, outp, op);
4034 smb_SendTran2Error(vcp, p, op, code);
4036 smb_FreeTran2Packet(outp);
4039 #else /* DFS_SUPPORT */
4040 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
4041 return CM_ERROR_NOSUCHDEVICE;
4042 #endif /* DFS_SUPPORT */
4045 /* TRANS2_REPORT_DFS_INCONSISTENCY */
4047 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4049 /* This is a UNICODE only request (bit15 of Flags2) */
4051 /* There is nothing we can do about this operation. The client is going to
4052 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
4053 * Unfortunately, there is really nothing we can do about it other then log it
4054 * somewhere. Even then I don't think there is anything for us to do.
4055 * So let's return an error value.
4058 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
4059 return CM_ERROR_BADOP;
4063 smb_ApplyV3DirListPatches(cm_scache_t *dscp, smb_dirListPatch_t **dirPatchespp,
4064 clientchar_t * tidPathp, clientchar_t * relPathp,
4065 int infoLevel, cm_user_t *userp, cm_req_t *reqp)
4069 cm_scache_t *targetScp; /* target if scp is a symlink */
4072 unsigned short attr;
4073 unsigned long lattr;
4074 smb_dirListPatch_t *patchp;
4075 smb_dirListPatch_t *npatchp;
4077 afs_int32 mustFake = 0;
4078 clientchar_t path[AFSPATHMAX];
4080 code = cm_FindACLCache(dscp, userp, &rights);
4082 lock_ObtainWrite(&dscp->rw);
4083 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4084 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4086 cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4087 lock_ReleaseWrite(&dscp->rw);
4088 if (code == CM_ERROR_NOACCESS) {
4096 if (!mustFake) { /* Bulk Stat */
4098 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4100 memset(bsp, 0, sizeof(cm_bulkStat_t));
4102 for (patchp = *dirPatchespp, count=0;
4104 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4105 cm_scache_t *tscp = NULL;
4108 code = cm_GetSCache(&patchp->fid, &tscp, userp, reqp);
4110 if (lock_TryWrite(&tscp->rw)) {
4111 /* we have an entry that we can look at */
4112 #ifdef AFS_FREELANCE_CLIENT
4113 if (dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID && dscp->fid.volume == AFS_FAKE_ROOT_VOL_ID) {
4114 code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
4115 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4117 cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4119 lock_ReleaseWrite(&tscp->rw);
4120 cm_ReleaseSCache(tscp);
4123 #endif /* AFS_FREELANCE_CLIENT */
4124 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4125 /* we have a callback on it. Don't bother
4126 * fetching this stat entry, since we're happy
4127 * with the info we have.
4129 lock_ReleaseWrite(&tscp->rw);
4130 cm_ReleaseSCache(tscp);
4133 lock_ReleaseWrite(&tscp->rw);
4135 cm_ReleaseSCache(tscp);
4139 bsp->fids[i].Volume = patchp->fid.volume;
4140 bsp->fids[i].Vnode = patchp->fid.vnode;
4141 bsp->fids[i].Unique = patchp->fid.unique;
4143 if (bsp->counter == AFSCBMAX) {
4144 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4145 memset(bsp, 0, sizeof(cm_bulkStat_t));
4149 if (bsp->counter > 0)
4150 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4155 for( patchp = *dirPatchespp;
4157 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4158 cm_ClientStrPrintfN(path, lengthof(path),_C("%s\\%S"),
4159 relPathp ? relPathp : _C(""), patchp->dep->name);
4160 reqp->relPathp = path;
4161 reqp->tidPathp = tidPathp;
4163 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4164 reqp->relPathp = reqp->tidPathp = NULL;
4168 lock_ObtainWrite(&scp->rw);
4169 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4170 lock_ReleaseWrite(&scp->rw);
4172 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4173 errors in the client. */
4174 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4175 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4177 /* 1969-12-31 23:59:59 +00 */
4178 ft.dwHighDateTime = 0x19DB200;
4179 ft.dwLowDateTime = 0x5BB78980;
4181 /* copy to Creation Time */
4182 fa->creationTime = ft;
4183 fa->lastAccessTime = ft;
4184 fa->lastWriteTime = ft;
4185 fa->lastChangeTime = ft;
4187 switch (scp->fileType) {
4188 case CM_SCACHETYPE_DIRECTORY:
4189 case CM_SCACHETYPE_MOUNTPOINT:
4190 case CM_SCACHETYPE_INVALID:
4191 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4193 case CM_SCACHETYPE_SYMLINK:
4194 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4195 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4197 fa->extFileAttributes = SMB_ATTR_NORMAL;
4200 /* if we get here we either have a normal file
4201 * or we have a file for which we have never
4202 * received status info. In this case, we can
4203 * check the even/odd value of the entry's vnode.
4204 * odd means it is to be treated as a directory
4205 * and even means it is to be treated as a file.
4207 if (mustFake && (scp->fid.vnode & 0x1))
4208 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4210 fa->extFileAttributes = SMB_ATTR_NORMAL;
4212 /* merge in hidden attribute */
4213 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4214 fa->extFileAttributes |= SMB_ATTR_HIDDEN;
4217 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4219 /* 1969-12-31 23:59:58 +00*/
4220 dosTime = 0xEBBFBF7D;
4222 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4223 fa->lastAccessDateTime = fa->creationDateTime;
4224 fa->lastWriteDateTime = fa->creationDateTime;
4226 /* set the attribute */
4227 switch (scp->fileType) {
4228 case CM_SCACHETYPE_DIRECTORY:
4229 case CM_SCACHETYPE_MOUNTPOINT:
4230 case CM_SCACHETYPE_INVALID:
4231 fa->attributes = SMB_ATTR_DIRECTORY;
4233 case CM_SCACHETYPE_SYMLINK:
4234 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4235 fa->attributes = SMB_ATTR_DIRECTORY;
4237 fa->attributes = SMB_ATTR_NORMAL;
4240 /* if we get here we either have a normal file
4241 * or we have a file for which we have never
4242 * received status info. In this case, we can
4243 * check the even/odd value of the entry's vnode.
4244 * even means it is to be treated as a directory
4245 * and odd means it is to be treated as a file.
4247 if (mustFake && (scp->fid.vnode & 0x1))
4248 fa->attributes = SMB_ATTR_DIRECTORY;
4250 fa->attributes = SMB_ATTR_NORMAL;
4253 /* merge in hidden (dot file) attribute */
4254 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4255 fa->attributes |= SMB_ATTR_HIDDEN;
4259 cm_ReleaseSCache(scp);
4263 /* now watch for a symlink */
4265 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
4266 lock_ReleaseWrite(&scp->rw);
4267 cm_ClientStrPrintfN(path, lengthof(path), _C("%s\\%S"),
4268 relPathp ? relPathp : _C(""), patchp->dep->name);
4269 reqp->relPathp = path;
4270 reqp->tidPathp = tidPathp;
4271 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
4272 reqp->relPathp = reqp->tidPathp = NULL;
4274 /* we have a more accurate file to use (the
4275 * target of the symbolic link). Otherwise,
4276 * we'll just use the symlink anyway.
4278 osi_Log2(smb_logp, "symlink vp %x to vp %x",
4280 cm_ReleaseSCache(scp);
4283 lock_ObtainWrite(&scp->rw);
4286 lock_ConvertWToR(&scp->rw);
4288 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4289 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4292 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4294 fa->creationTime = ft;
4295 fa->lastAccessTime = ft;
4296 fa->lastWriteTime = ft;
4297 fa->lastChangeTime = ft;
4299 /* Use length for both file length and alloc length */
4300 fa->endOfFile = scp->length;
4301 fa->allocationSize = scp->length;
4303 /* Copy attributes */
4304 lattr = smb_ExtAttributes(scp);
4305 if ((code == CM_ERROR_NOSUCHPATH &&
4306 (scp->fileType == CM_SCACHETYPE_SYMLINK &&
4307 cm_TargetPerceivedAsDirectory(scp->mountPointStringp))) ||
4308 code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4309 if (lattr == SMB_ATTR_NORMAL)
4310 lattr = SMB_ATTR_DIRECTORY;
4312 lattr |= SMB_ATTR_DIRECTORY;
4314 /* merge in hidden (dot file) attribute */
4315 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4316 if (lattr == SMB_ATTR_NORMAL)
4317 lattr = SMB_ATTR_HIDDEN;
4319 lattr |= SMB_ATTR_HIDDEN;
4322 fa->extFileAttributes = lattr;
4324 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4327 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4329 fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
4330 fa->lastAccessDateTime = fa->creationDateTime;
4331 fa->lastWriteDateTime = fa->creationDateTime;
4333 /* copy out file length and alloc length,
4334 * using the same for both
4336 fa->dataSize = scp->length.LowPart;
4337 fa->allocationSize = scp->length.LowPart;
4339 /* finally copy out attributes as short */
4340 attr = smb_Attributes(scp);
4341 /* merge in hidden (dot file) attribute */
4342 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4343 if (lattr == SMB_ATTR_NORMAL)
4344 lattr = SMB_ATTR_HIDDEN;
4346 lattr |= SMB_ATTR_HIDDEN;
4348 fa->attributes = attr;
4351 lock_ReleaseRead(&scp->rw);
4352 cm_ReleaseSCache(scp);
4355 /* now free the patches */
4356 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4357 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4361 /* and mark the list as empty */
4362 *dirPatchespp = NULL;
4368 /* smb_ReceiveTran2SearchDir implements both
4369 * Tran2_Find_First and Tran2_Find_Next
4371 #define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
4372 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
4373 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
4374 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
4375 #define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
4377 /* this is an optimized handler for T2SearchDir that handles the case
4378 where there are no wildcards in the search path. I.e. an
4379 application is using FindFirst(Ex) to get information about a
4380 single file or directory. It will attempt to do a single lookup.
4381 If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4382 the usual mechanism.
4384 This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4386 TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
4388 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4392 long code = 0, code2 = 0;
4393 clientchar_t *pathp = 0;
4395 smb_dirListPatch_t *dirListPatchesp;
4396 smb_dirListPatch_t *curPatchp;
4397 size_t orbytes; /* # of bytes in this output record */
4398 size_t ohbytes; /* # of bytes, except file name */
4399 size_t onbytes; /* # of bytes in name, incl. term. null */
4400 cm_scache_t *scp = NULL;
4401 cm_scache_t *targetscp = NULL;
4402 cm_user_t *userp = NULL;
4403 char *op; /* output data ptr */
4404 char *origOp; /* original value of op */
4405 cm_space_t *spacep; /* for pathname buffer */
4406 unsigned long maxReturnData; /* max # of return data */
4407 long maxReturnParms; /* max # of return parms */
4408 long bytesInBuffer; /* # data bytes in the output buffer */
4409 clientchar_t *maskp; /* mask part of path */
4413 smb_tran2Packet_t *outp; /* response packet */
4414 clientchar_t *tidPathp = 0;
4416 clientchar_t shortName[13]; /* 8.3 name if needed */
4418 clientchar_t *shortNameEnd;
4419 cm_dirEntry_t * dep = NULL;
4422 void * attrp = NULL;
4423 smb_tran2Find_t * fp;
4428 osi_assertx(p->opcode == 1, "invalid opcode");
4430 /* find first; obtain basic parameters from request */
4432 /* note that since we are going to failover to regular
4433 * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4434 * modify any of the input parameters here. */
4435 attribute = p->parmsp[0];
4436 maxCount = p->parmsp[1];
4437 infoLevel = p->parmsp[3];
4438 searchFlags = p->parmsp[2];
4439 pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4441 maskp = cm_ClientStrRChr(pathp, '\\');
4445 maskp++; /* skip over backslash */
4446 /* track if this is likely to match a lot of entries */
4448 osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%S], mask[%S]",
4449 osi_LogSaveClientString(smb_logp, pathp),
4450 osi_LogSaveClientString(smb_logp, maskp));
4452 switch ( infoLevel ) {
4453 case SMB_INFO_STANDARD:
4455 ohbytes = sizeof(fp->u.FstandardInfo);
4458 case SMB_INFO_QUERY_EA_SIZE:
4459 ohbytes = sizeof(fp->u.FeaSizeInfo);
4460 s = "InfoQueryEaSize";
4463 case SMB_INFO_QUERY_EAS_FROM_LIST:
4464 ohbytes = sizeof(fp->u.FeasFromListInfo);
4465 s = "InfoQueryEasFromList";
4468 case SMB_FIND_FILE_DIRECTORY_INFO:
4469 s = "FindFileDirectoryInfo";
4470 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4473 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4474 s = "FindFileFullDirectoryInfo";
4475 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4478 case SMB_FIND_FILE_NAMES_INFO:
4479 s = "FindFileNamesInfo";
4480 ohbytes = sizeof(fp->u.FfileNamesInfo);
4483 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4484 s = "FindFileBothDirectoryInfo";
4485 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4489 s = "unknownInfoLevel";
4493 osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
4496 "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4497 attribute, infoLevel, maxCount, searchFlags);
4500 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4501 return CM_ERROR_INVAL;
4504 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4505 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4507 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4510 dirListPatchesp = NULL;
4512 maxReturnData = p->maxReturnData;
4513 maxReturnParms = 10; /* return params for findfirst, which
4514 is the only one we handle.*/
4516 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4519 osi_Log2(smb_logp, "T2SDSingle search dir count %d [%S]",
4520 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4522 /* bail out if request looks bad */
4524 smb_FreeTran2Packet(outp);
4525 return CM_ERROR_BADSMB;
4528 userp = smb_GetTran2User(vcp, p);
4530 osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
4531 smb_FreeTran2Packet(outp);
4532 return CM_ERROR_BADSMB;
4535 /* try to get the vnode for the path name next */
4536 spacep = cm_GetSpace();
4537 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4538 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4540 cm_ReleaseUser(userp);
4541 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4542 smb_FreeTran2Packet(outp);
4546 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4547 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4548 userp, tidPathp, &req, &scp);
4549 cm_FreeSpace(spacep);
4552 cm_ReleaseUser(userp);
4553 smb_SendTran2Error(vcp, p, opx, code);
4554 smb_FreeTran2Packet(outp);
4558 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4559 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4560 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
4561 cm_ReleaseSCache(scp);
4562 cm_ReleaseUser(userp);
4563 if ( WANTS_DFS_PATHNAMES(p) || pnc )
4564 code = CM_ERROR_PATH_NOT_COVERED;
4566 code = CM_ERROR_BADSHARENAME;
4567 smb_SendTran2Error(vcp, p, opx, code);
4568 smb_FreeTran2Packet(outp);
4571 #endif /* DFS_SUPPORT */
4572 osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
4574 /* now do a single case sensitive lookup for the file in question */
4575 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
4577 /* if a case sensitive match failed, we try a case insensitive one
4579 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
4580 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
4583 if (code == 0 && targetscp->fid.vnode == 0) {
4584 cm_ReleaseSCache(targetscp);
4585 code = CM_ERROR_NOSUCHFILE;
4589 /* if we can't find the directory entry, this block will
4590 return CM_ERROR_NOSUCHFILE, which we will pass on to
4591 smb_ReceiveTran2SearchDir(). */
4592 cm_ReleaseSCache(scp);
4593 cm_ReleaseUser(userp);
4594 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4595 smb_SendTran2Error(vcp, p, opx, code);
4598 smb_FreeTran2Packet(outp);
4602 /* now that we have the target in sight, we proceed with filling
4603 up the return data. */
4605 op = origOp = outp->datap;
4608 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4609 /* skip over resume key */
4613 fp = (smb_tran2Find_t *) op;
4615 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4616 && targetscp->fid.vnode != 0
4617 && !cm_Is8Dot3(maskp)) {
4620 dfid.vnode = htonl(targetscp->fid.vnode);
4621 dfid.unique = htonl(targetscp->fid.unique);
4623 cm_Gen8Dot3NameIntW(maskp, &dfid, shortName, &shortNameEnd);
4629 osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %S (%S)",
4630 htonl(targetscp->fid.vnode),
4631 htonl(targetscp->fid.unique),
4632 osi_LogSaveClientString(smb_logp, pathp),
4633 (NeedShortName)? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
4635 /* Eliminate entries that don't match requested attributes */
4636 if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
4637 smb_IsDotFile(maskp)) {
4639 code = CM_ERROR_NOSUCHFILE;
4640 osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
4645 if (!(attribute & SMB_ATTR_DIRECTORY) &&
4646 (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
4647 targetscp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4648 targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
4649 targetscp->fileType == CM_SCACHETYPE_INVALID)) {
4651 code = CM_ERROR_NOSUCHFILE;
4652 osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
4657 /* add header to name & term. null */
4659 smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
4660 orbytes = ohbytes + onbytes;
4662 /* now, we round up the record to a 4 byte alignment, and we make
4663 * sure that we have enough room here for even the aligned version
4664 * (so we don't have to worry about an * overflow when we pad
4665 * things out below). That's the reason for the alignment
4668 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4669 align = (4 - (orbytes & 3)) & 3;
4673 if (orbytes + align > maxReturnData) {
4675 /* even though this request is unlikely to succeed with a
4676 failover, we do it anyway. */
4677 code = CM_ERROR_NOSUCHFILE;
4678 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4683 /* this is one of the entries to use: it is not deleted and it
4684 * matches the star pattern we're looking for. Put out the name,
4685 * preceded by its length.
4687 /* First zero everything else */
4688 memset(origOp, 0, orbytes);
4691 smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
4693 switch (infoLevel) {
4694 case SMB_INFO_STANDARD:
4695 fp->u.FstandardInfo.fileNameLength = onbytes;
4696 attrp = &fp->u.FstandardInfo.fileAttrs;
4699 case SMB_INFO_QUERY_EA_SIZE:
4700 fp->u.FeaSizeInfo.fileNameLength = onbytes;
4701 attrp = &fp->u.FeaSizeInfo.fileAttrs;
4702 fp->u.FeaSizeInfo.eaSize = 0;
4705 case SMB_INFO_QUERY_EAS_FROM_LIST:
4706 fp->u.FeasFromListInfo.fileNameLength = onbytes;
4707 attrp = &fp->u.FeasFromListInfo.fileAttrs;
4708 fp->u.FeasFromListInfo.eaSize = 0;
4711 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4712 if (NeedShortName) {
4716 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
4717 fp->u.FfileBothDirectoryInfo.shortName,
4718 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
4720 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
4722 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
4723 fp->u.FfileBothDirectoryInfo.reserved = 0;
4725 strcpy(fp->u.FfileBothDirectoryInfo.shortName,
4727 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
4732 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4733 fp->u.FfileFullDirectoryInfo.eaSize = 0;
4736 case SMB_FIND_FILE_DIRECTORY_INFO:
4737 fp->u.FfileDirectoryInfo.nextEntryOffset = 0;
4738 fp->u.FfileDirectoryInfo.fileIndex = 0;
4739 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
4740 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
4743 case SMB_FIND_FILE_NAMES_INFO:
4744 fp->u.FfileNamesInfo.nextEntryOffset = 0;
4745 fp->u.FfileNamesInfo.fileIndex = 0;
4746 fp->u.FfileNamesInfo.fileNameLength = onbytes;
4750 /* we shouldn't hit this case */
4751 osi_assertx(FALSE, "Unknown query type");
4754 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4755 osi_assert(attrp != NULL);
4757 curPatchp = malloc(sizeof(*curPatchp));
4758 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4760 curPatchp->dptr = attrp;
4762 if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
4763 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4765 curPatchp->flags = 0;
4768 cm_SetFid(&curPatchp->fid, targetscp->fid.cell, targetscp->fid.volume, targetscp->fid.vnode, targetscp->fid.unique);
4772 int namelen = cm_ClientStringToFsString(maskp, -1, NULL, 0);
4773 dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+namelen);
4774 cm_ClientStringToFsString(maskp, -1, dep->name, namelen);
4776 dep->fid.vnode = targetscp->fid.vnode;
4777 dep->fid.unique = targetscp->fid.unique;
4778 curPatchp->dep = dep;
4781 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4782 /* put out resume key */
4783 *((u_long *)origOp) = 0;
4786 /* Adjust byte ptr and count */
4787 origOp += orbytes; /* skip entire record */
4788 bytesInBuffer += orbytes;
4790 /* and pad the record out */
4791 while (--align >= 0) {
4796 /* apply the patches */
4797 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->wdata, infoLevel, userp, &req);
4799 outp->parmsp[0] = 0;
4800 outp->parmsp[1] = 1; /* number of names returned */
4801 outp->parmsp[2] = 1; /* end of search */
4802 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4803 outp->parmsp[4] = 0;
4805 outp->totalParms = 10; /* in bytes */
4807 outp->totalData = bytesInBuffer;
4809 osi_Log0(smb_logp, "T2SDSingle done.");
4811 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4813 smb_SendTran2Error(vcp, p, opx, code);
4815 smb_SendTran2Packet(vcp, outp, opx);
4820 smb_FreeTran2Packet(outp);
4824 cm_ReleaseSCache(scp);
4825 cm_ReleaseSCache(targetscp);
4826 cm_ReleaseUser(userp);
4832 /* TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2 */
4833 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4838 long code = 0, code2 = 0;
4839 clientchar_t *pathp;
4840 cm_dirEntry_t *dep = 0;
4842 smb_dirListPatch_t *dirListPatchesp = 0;
4843 smb_dirListPatch_t *curPatchp = 0;
4846 size_t orbytes; /* # of bytes in this output record */
4847 size_t ohbytes; /* # of bytes, except file name */
4848 size_t onbytes; /* # of bytes in name, incl. term. null */
4849 osi_hyper_t dirLength;
4850 osi_hyper_t bufferOffset;
4851 osi_hyper_t curOffset;
4853 smb_dirSearch_t *dsp;
4857 cm_pageHeader_t *pageHeaderp;
4858 cm_user_t *userp = NULL;
4861 long nextEntryCookie;
4862 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4863 char *op; /* output data ptr */
4864 char *origOp; /* original value of op */
4865 cm_space_t *spacep; /* for pathname buffer */
4866 unsigned long maxReturnData; /* max # of return data */
4867 unsigned long maxReturnParms; /* max # of return parms */
4868 long bytesInBuffer; /* # data bytes in the output buffer */
4870 clientchar_t *maskp; /* mask part of path */
4874 smb_tran2Packet_t *outp; /* response packet */
4875 clientchar_t *tidPathp;
4877 clientchar_t shortName[13]; /* 8.3 name if needed */
4880 clientchar_t *shortNameEnd;
4886 smb_tran2Find_t * fp;
4891 if (p->opcode == 1) {
4892 /* find first; obtain basic parameters from request */
4893 attribute = p->parmsp[0];
4894 maxCount = p->parmsp[1];
4895 infoLevel = p->parmsp[3];
4896 searchFlags = p->parmsp[2];
4897 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4899 maskp = cm_ClientStrRChr(pathp, '\\');
4903 maskp++; /* skip over backslash */
4905 /* track if this is likely to match a lot of entries */
4906 starPattern = smb_V3IsStarMask(maskp);
4908 #ifndef NOFINDFIRSTOPTIMIZE
4910 /* if this is for a single directory or file, we let the
4911 optimized routine handle it. The only error it
4912 returns is CM_ERROR_NOSUCHFILE. The */
4913 code = smb_T2SearchDirSingle(vcp, p, opx);
4915 /* we only failover if we see a CM_ERROR_NOSUCHFILE */
4916 if (code != CM_ERROR_NOSUCHFILE) {
4918 /* unless we are using the BPlusTree */
4919 if (code == CM_ERROR_BPLUS_NOMATCH)
4920 code = CM_ERROR_NOSUCHFILE;
4921 #endif /* USE_BPLUS */
4925 #endif /* NOFINDFIRSTOPTIMIZE */
4928 dsp = smb_NewDirSearch(1);
4929 dsp->attribute = attribute;
4930 cm_ClientStrCpy(dsp->mask, lengthof(dsp->mask), maskp); /* and save mask */
4933 osi_assertx(p->opcode == 2, "invalid opcode");
4934 /* find next; obtain basic parameters from request or open dir file */
4935 dsp = smb_FindDirSearch(p->parmsp[0]);
4936 maxCount = p->parmsp[1];
4937 infoLevel = p->parmsp[2];
4938 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4939 searchFlags = p->parmsp[5];
4941 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4942 p->parmsp[0], nextCookie);
4943 return CM_ERROR_BADFD;
4945 attribute = dsp->attribute;
4948 starPattern = 1; /* assume, since required a Find Next */
4951 switch ( infoLevel ) {
4952 case SMB_INFO_STANDARD:
4954 ohbytes = sizeof(fp->u.FstandardInfo);
4957 case SMB_INFO_QUERY_EA_SIZE:
4958 ohbytes = sizeof(fp->u.FeaSizeInfo);
4959 s = "InfoQueryEaSize";
4962 case SMB_INFO_QUERY_EAS_FROM_LIST:
4963 ohbytes = sizeof(fp->u.FeasFromListInfo);
4964 s = "InfoQueryEasFromList";
4967 case SMB_FIND_FILE_DIRECTORY_INFO:
4968 s = "FindFileDirectoryInfo";
4969 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4972 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4973 s = "FindFileFullDirectoryInfo";
4974 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4977 case SMB_FIND_FILE_NAMES_INFO:
4978 s = "FindFileNamesInfo";
4979 ohbytes = sizeof(fp->u.FfileNamesInfo);
4982 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4983 s = "FindFileBothDirectoryInfo";
4984 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4988 s = "unknownInfoLevel";
4992 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
4995 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4996 attribute, infoLevel, maxCount, searchFlags);
4998 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
4999 p->opcode, dsp->cookie, nextCookie);
5002 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
5003 smb_ReleaseDirSearch(dsp);
5004 return CM_ERROR_INVAL;
5007 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5008 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
5010 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5013 dirListPatchesp = NULL;
5015 maxReturnData = p->maxReturnData;
5016 if (p->opcode == 1) /* find first */
5017 maxReturnParms = 10; /* bytes */
5019 maxReturnParms = 8; /* bytes */
5021 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
5027 osi_Log2(smb_logp, "T2 receive search dir count %d [%S]",
5028 maxCount, osi_LogSaveClientString(smb_logp, pathp));
5030 /* bail out if request looks bad */
5031 if (p->opcode == 1 && !pathp) {
5032 smb_ReleaseDirSearch(dsp);
5033 smb_FreeTran2Packet(outp);
5034 return CM_ERROR_BADSMB;
5037 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
5038 dsp->cookie, nextCookie, attribute);
5040 userp = smb_GetTran2User(vcp, p);
5042 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
5043 smb_ReleaseDirSearch(dsp);
5044 smb_FreeTran2Packet(outp);
5045 return CM_ERROR_BADSMB;
5048 /* try to get the vnode for the path name next */
5049 lock_ObtainMutex(&dsp->mx);
5052 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5056 spacep = cm_GetSpace();
5057 smb_StripLastComponent(spacep->wdata, NULL, pathp);
5058 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
5060 cm_ReleaseUser(userp);
5061 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
5062 smb_FreeTran2Packet(outp);
5063 lock_ReleaseMutex(&dsp->mx);
5064 smb_DeleteDirSearch(dsp);
5065 smb_ReleaseDirSearch(dsp);
5069 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
5070 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
5072 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
5073 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5074 userp, tidPathp, &req, &scp);
5075 cm_FreeSpace(spacep);
5078 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
5079 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5080 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
5081 cm_ReleaseSCache(scp);
5082 cm_ReleaseUser(userp);
5083 if ( WANTS_DFS_PATHNAMES(p) || pnc )
5084 code = CM_ERROR_PATH_NOT_COVERED;
5086 code = CM_ERROR_BADSHARENAME;
5087 smb_SendTran2Error(vcp, p, opx, code);
5088 smb_FreeTran2Packet(outp);
5089 lock_ReleaseMutex(&dsp->mx);
5090 smb_DeleteDirSearch(dsp);
5091 smb_ReleaseDirSearch(dsp);
5094 #endif /* DFS_SUPPORT */
5096 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5097 /* we need one hold for the entry we just stored into,
5098 * and one for our own processing. When we're done
5099 * with this function, we'll drop the one for our own
5100 * processing. We held it once from the namei call,
5101 * and so we do another hold now.
5104 dsp->flags |= SMB_DIRSEARCH_BULKST;
5107 lock_ReleaseMutex(&dsp->mx);
5109 cm_ReleaseUser(userp);
5110 smb_FreeTran2Packet(outp);
5111 smb_DeleteDirSearch(dsp);
5112 smb_ReleaseDirSearch(dsp);
5116 /* get the directory size */
5117 lock_ObtainWrite(&scp->rw);
5118 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5119 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5121 lock_ReleaseWrite(&scp->rw);
5122 cm_ReleaseSCache(scp);
5123 cm_ReleaseUser(userp);
5124 smb_FreeTran2Packet(outp);
5125 smb_DeleteDirSearch(dsp);
5126 smb_ReleaseDirSearch(dsp);
5130 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5133 dirLength = scp->length;
5135 bufferOffset.LowPart = bufferOffset.HighPart = 0;
5136 curOffset.HighPart = 0;
5137 curOffset.LowPart = nextCookie;
5138 origOp = outp->datap;
5145 normchar_t normName[MAX_PATH]; /* Normalized name */
5146 clientchar_t cfileName[MAX_PATH]; /* Non-normalized name */
5149 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5150 /* skip over resume key */
5153 fp = (smb_tran2Find_t *) op;
5155 /* make sure that curOffset.LowPart doesn't point to the first
5156 * 32 bytes in the 2nd through last dir page, and that it doesn't
5157 * point at the first 13 32-byte chunks in the first dir page,
5158 * since those are dir and page headers, and don't contain useful
5161 temp = curOffset.LowPart & (2048-1);
5162 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5163 /* we're in the first page */
5164 if (temp < 13*32) temp = 13*32;
5167 /* we're in a later dir page */
5168 if (temp < 32) temp = 32;
5171 /* make sure the low order 5 bits are zero */
5174 /* now put temp bits back ito curOffset.LowPart */
5175 curOffset.LowPart &= ~(2048-1);
5176 curOffset.LowPart |= temp;
5178 /* check if we've passed the dir's EOF */
5179 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
5180 osi_Log0(smb_logp, "T2 search dir passed eof");
5185 /* check if we've returned all the names that will fit in the
5186 * response packet; we check return count as well as the number
5187 * of bytes requested. We check the # of bytes after we find
5188 * the dir entry, since we'll need to check its size.
5190 if (returnedNames >= maxCount) {
5191 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
5192 returnedNames, maxCount);
5196 /* when we have obtained as many entries as can be processed in
5197 * a single Bulk Status call to the file server, apply the dir listing
5200 if (returnedNames > 0 && returnedNames % AFSCBMAX == 0) {
5201 lock_ReleaseWrite(&scp->rw);
5202 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5203 dsp->relPath, infoLevel, userp, &req);
5204 lock_ObtainWrite(&scp->rw);
5206 /* Then check to see if we have time left to process more entries */
5207 if (GetTickCount() - req.startTime > (RDRtimeout - 15) * 1000) {
5208 osi_Log0(smb_logp, "T2 search dir RDRtimeout exceeded");
5212 /* see if we can use the bufferp we have now; compute in which
5213 * page the current offset would be, and check whether that's
5214 * the offset of the buffer we have. If not, get the buffer.
5216 thyper.HighPart = curOffset.HighPart;
5217 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5218 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5221 buf_Release(bufferp);
5224 lock_ReleaseWrite(&scp->rw);
5225 code = buf_Get(scp, &thyper, &bufferp);
5226 lock_ObtainWrite(&scp->rw);
5228 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
5232 bufferOffset = thyper;
5234 /* now get the data in the cache */
5236 code = cm_SyncOp(scp, bufferp, userp, &req,
5238 CM_SCACHESYNC_NEEDCALLBACK
5239 | CM_SCACHESYNC_READ);
5241 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5245 if (cm_HaveBuffer(scp, bufferp, 0)) {
5246 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5247 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5251 /* otherwise, load the buffer and try again */
5252 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5254 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5256 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5257 scp, bufferp, code);
5262 buf_Release(bufferp);
5266 } /* if (wrong buffer) ... */
5268 /* now we have the buffer containing the entry we're interested
5269 * in; copy it out if it represents a non-deleted entry.
5271 entryInDir = curOffset.LowPart & (2048-1);
5272 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5274 /* page header will help tell us which entries are free. Page
5275 * header can change more often than once per buffer, since
5276 * AFS 3 dir page size may be less than (but not more than)
5277 * a buffer package buffer.
5279 /* only look intra-buffer */
5280 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5281 temp &= ~(2048 - 1); /* turn off intra-page bits */
5282 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5284 /* now determine which entry we're looking at in the page.
5285 * If it is free (there's a free bitmap at the start of the
5286 * dir), we should skip these 32 bytes.
5288 slotInPage = (entryInDir & 0x7e0) >> 5;
5289 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5290 (1 << (slotInPage & 0x7)))) {
5291 /* this entry is free */
5292 numDirChunks = 1; /* only skip this guy */
5296 tp = bufferp->datap + entryInBuffer;
5297 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5299 /* while we're here, compute the next entry's location, too,
5300 * since we'll need it when writing out the cookie into the dir
5303 * XXXX Probably should do more sanity checking.
5305 numDirChunks = cm_NameEntries(dep->name, &onbytes);
5307 /* compute offset of cookie representing next entry */
5308 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5310 if (dep->fid.vnode == 0)
5311 goto nextEntry; /* This entry is not in use */
5313 if (cm_FsStringToClientString(dep->name, -1, cfileName, lengthof(cfileName)) == 0 ||
5314 cm_ClientStringToNormString(cfileName, -1, normName, lengthof(normName)) == 0) {
5316 osi_Log1(smb_logp, "Skipping entry [%s]. Can't convert or normalize FS String",
5317 osi_LogSaveString(smb_logp, dep->name));
5321 /* Need 8.3 name? */
5323 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
5324 !cm_Is8Dot3(cfileName)) {
5325 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5329 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %S (%S)",
5330 dep->fid.vnode, dep->fid.unique,
5331 osi_LogSaveClientString(smb_logp, cfileName),
5332 NeedShortName ? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
5334 /* When matching, we are using doing a case fold if we have a wildcard mask.
5335 * If we get a non-wildcard match, it's a lookup for a specific file.
5337 if (cm_MatchMask(normName, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5338 (NeedShortName && cm_MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))
5340 /* Eliminate entries that don't match requested attributes */
5341 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5342 smb_IsDotFile(cfileName)) {
5343 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5344 goto nextEntry; /* no hidden files */
5347 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5349 /* We have already done the cm_TryBulkStat above */
5350 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume,
5351 ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5352 fileType = cm_FindFileType(&fid);
5353 /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5354 * "has filetype %d", dep->name, fileType);
5356 if ( fileType == CM_SCACHETYPE_DIRECTORY ||
5357 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5358 fileType == CM_SCACHETYPE_DFSLINK ||
5359 fileType == CM_SCACHETYPE_INVALID)
5360 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5364 /* finally check if this name will fit */
5366 smb_UnparseString(opx, NULL, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5367 orbytes = ohbytes + onbytes;
5369 /* now, we round up the record to a 4 byte alignment,
5370 * and we make sure that we have enough room here for
5371 * even the aligned version (so we don't have to worry
5372 * about an overflow when we pad things out below).
5373 * That's the reason for the alignment arithmetic below.
5375 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5376 align = (4 - (orbytes & 3)) & 3;
5380 if (orbytes + bytesInBuffer + align > maxReturnData) {
5381 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5386 /* this is one of the entries to use: it is not deleted
5387 * and it matches the star pattern we're looking for.
5388 * Put out the name, preceded by its length.
5390 /* First zero everything else */
5391 memset(origOp, 0, orbytes);
5394 smb_UnparseString(opx, origOp + ohbytes, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5396 switch (infoLevel) {
5397 case SMB_INFO_STANDARD:
5398 fp->u.FstandardInfo.fileNameLength = onbytes;
5399 attrp = &fp->u.FstandardInfo.fileAttrs;
5402 case SMB_INFO_QUERY_EA_SIZE:
5403 fp->u.FeaSizeInfo.fileNameLength = onbytes;
5404 attrp = &fp->u.FeaSizeInfo.fileAttrs;
5405 fp->u.FeaSizeInfo.eaSize = 0;
5408 case SMB_INFO_QUERY_EAS_FROM_LIST:
5409 fp->u.FeasFromListInfo.fileNameLength = onbytes;
5410 attrp = &fp->u.FeasFromListInfo.fileAttrs;
5411 fp->u.FeasFromListInfo.eaSize = 0;
5414 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5415 if (NeedShortName) {
5419 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
5420 fp->u.FfileBothDirectoryInfo.shortName,
5421 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
5423 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
5425 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5426 fp->u.FfileBothDirectoryInfo.reserved = 0;
5428 cm_ClientStrCpy(fp->u.FfileBothDirectoryInfo.shortName,
5429 lengthof(fp->u.FfileBothDirectoryInfo.shortName),
5431 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
5436 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5437 fp->u.FfileFullDirectoryInfo.eaSize = 0;
5440 case SMB_FIND_FILE_DIRECTORY_INFO:
5441 fp->u.FfileDirectoryInfo.nextEntryOffset = orbytes + align;
5442 fp->u.FfileDirectoryInfo.fileIndex = nextEntryCookie;
5443 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5444 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5447 case SMB_FIND_FILE_NAMES_INFO:
5448 fp->u.FfileNamesInfo.nextEntryOffset = orbytes + align;
5449 fp->u.FfileNamesInfo.fileIndex = nextEntryCookie;
5450 fp->u.FfileNamesInfo.fileNameLength = onbytes;
5455 /* we shouldn't hit this case */
5456 osi_assertx(FALSE, "Unknown query type");
5459 /* now, adjust the # of entries copied */
5462 /* now we emit the attribute. This is tricky, since
5463 * we need to really stat the file to find out what
5464 * type of entry we've got. Right now, we're copying
5465 * out data from a buffer, while holding the scp
5466 * locked, so it isn't really convenient to stat
5467 * something now. We'll put in a place holder
5468 * now, and make a second pass before returning this
5469 * to get the real attributes. So, we just skip the
5470 * data for now, and adjust it later. We allocate a
5471 * patch record to make it easy to find this point
5472 * later. The replay will happen at a time when it is
5473 * safe to unlock the directory.
5475 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5476 osi_assert(attrp != NULL);
5477 curPatchp = malloc(sizeof(*curPatchp));
5478 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5479 curPatchp->dptr = attrp;
5481 if (smb_hideDotFiles && smb_IsDotFile(cfileName)) {
5482 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5484 curPatchp->flags = 0;
5487 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5490 curPatchp->dep = dep;
5493 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5494 /* put out resume key */
5495 *((u_long *)origOp) = nextEntryCookie;
5497 /* Adjust byte ptr and count */
5498 origOp += orbytes; /* skip entire record */
5499 bytesInBuffer += orbytes;
5501 /* and pad the record out */
5502 while (align-- > 0) {
5506 } /* if we're including this name */
5507 else if (!starPattern &&
5509 cm_MatchMask(normName, maskp, CM_FLAG_CASEFOLD)) {
5510 /* We were looking for exact matches, but here's an inexact one*/
5515 /* and adjust curOffset to be where the new cookie is */
5516 thyper.HighPart = 0;
5517 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5518 curOffset = LargeIntegerAdd(thyper, curOffset);
5519 } /* while copying data for dir listing */
5521 /* If we didn't get a star pattern, we did an exact match during the first pass.
5522 * If there were no exact matches found, we fail over to inexact matches by
5523 * marking the query as a star pattern (matches all case permutations), and
5524 * re-running the query.
5526 if (returnedNames == 0 && !starPattern && foundInexact) {
5527 osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
5532 /* release the mutex */
5533 lock_ReleaseWrite(&scp->rw);
5535 buf_Release(bufferp);
5540 * Finally, process whatever entries we have left.
5542 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5543 dsp->relPath, infoLevel, userp, &req);
5545 /* now put out the final parameters */
5546 if (returnedNames == 0)
5548 if (p->opcode == 1) {
5550 outp->parmsp[0] = (unsigned short) dsp->cookie;
5551 outp->parmsp[1] = returnedNames;
5552 outp->parmsp[2] = eos;
5553 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5554 outp->parmsp[4] = 0;
5555 /* don't need last name to continue
5556 * search, cookie is enough. Normally,
5557 * this is the offset of the file name
5558 * of the last entry returned.
5560 outp->totalParms = 10; /* in bytes */
5564 outp->parmsp[0] = returnedNames;
5565 outp->parmsp[1] = eos;
5566 outp->parmsp[2] = 0; /* EAS error */
5567 outp->parmsp[3] = 0; /* last name, as above */
5568 outp->totalParms = 8; /* in bytes */
5571 /* return # of bytes in the buffer */
5572 outp->totalData = bytesInBuffer;
5574 /* Return error code if unsuccessful on first request */
5575 if (code == 0 && p->opcode == 1 && returnedNames == 0)
5576 code = CM_ERROR_NOSUCHFILE;
5578 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
5579 p->opcode, dsp->cookie, returnedNames, code);
5581 /* if we're supposed to close the search after this request, or if
5582 * we're supposed to close the search if we're done, and we're done,
5583 * or if something went wrong, close the search.
5585 if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
5586 (returnedNames == 0) ||
5587 ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
5589 smb_DeleteDirSearch(dsp);
5592 smb_SendTran2Error(vcp, p, opx, code);
5594 smb_SendTran2Packet(vcp, outp, opx);
5596 smb_FreeTran2Packet(outp);
5597 smb_ReleaseDirSearch(dsp);
5598 cm_ReleaseSCache(scp);
5599 cm_ReleaseUser(userp);
5603 /* SMB_COM_FIND_CLOSE2 */
5604 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5607 smb_dirSearch_t *dsp;
5609 dirHandle = smb_GetSMBParm(inp, 0);
5611 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
5613 dsp = smb_FindDirSearch(dirHandle);
5616 return CM_ERROR_BADFD;
5618 /* otherwise, we have an FD to destroy */
5619 smb_DeleteDirSearch(dsp);
5620 smb_ReleaseDirSearch(dsp);
5622 /* and return results */
5623 smb_SetSMBDataLength(outp, 0);
5629 /* SMB_COM_FIND_NOTIFY_CLOSE */
5630 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5632 smb_SetSMBDataLength(outp, 0);
5636 /* SMB_COM_OPEN_ANDX */
5637 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5639 clientchar_t *pathp;
5644 cm_scache_t *dscp; /* dir we're dealing with */
5645 cm_scache_t *scp; /* file we're creating */
5647 int initialModeBits;
5650 clientchar_t *lastNamep;
5651 unsigned long dosTime;
5657 int parmSlot; /* which parm we're dealing with */
5658 clientchar_t *tidPathp;
5666 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
5667 openFun = smb_GetSMBParm(inp, 8); /* open function */
5668 excl = ((openFun & 3) == 0);
5669 trunc = ((openFun & 3) == 2); /* truncate it */
5670 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
5671 openAction = 0; /* tracks what we did */
5673 attributes = smb_GetSMBParm(inp, 5);
5674 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
5676 /* compute initial mode bits based on read-only flag in attributes */
5677 initialModeBits = 0666;
5678 if (attributes & SMB_ATTR_READONLY)
5679 initialModeBits &= ~0222;
5681 pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
5684 spacep = inp->spacep;
5685 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5688 (cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
5689 cm_ClientStrCmpIA(lastNamep, _C("\\srvsvc")) == 0 ||
5690 cm_ClientStrCmpIA(lastNamep, _C("\\wkssvc")) == 0 ||
5691 cm_ClientStrCmpIA(lastNamep, _C("ipc$")) == 0)) {
5692 /* special case magic file name for receiving IOCTL requests
5693 * (since IOCTL calls themselves aren't getting through).
5696 osi_Log0(smb_logp, "IOCTL Open");
5699 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5700 smb_SetupIoctlFid(fidp, spacep);
5702 /* set inp->fid so that later read calls in same msg can find fid */
5703 inp->fid = fidp->fid;
5705 /* copy out remainder of the parms */
5707 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5709 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
5710 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
5711 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5712 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
5713 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
5714 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5715 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5716 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5718 /* and the final "always present" stuff */
5719 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
5720 /* next write out the "unique" ID */
5721 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
5722 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
5723 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5724 smb_SetSMBDataLength(outp, 0);
5726 /* and clean up fid reference */
5727 smb_ReleaseFID(fidp);
5731 if (!cm_IsValidClientString(pathp)) {
5733 clientchar_t * hexp;
5735 hexp = cm_GetRawCharsAlloc(pathp, -1);
5736 osi_Log1(smb_logp, "NTOpenX rejecting invalid name. [%S]",
5737 osi_LogSaveClientString(smb_logp, hexp));
5741 osi_Log0(smb_logp, "NTOpenX rejecting invalid name");
5743 return CM_ERROR_BADNTFILENAME;
5746 #ifdef DEBUG_VERBOSE
5748 char *hexp, *asciip;
5749 asciip = (lastNamep ? lastNamep : pathp );
5750 hexp = osi_HexifyString(asciip);
5751 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
5755 userp = smb_GetUserFromVCP(vcp, inp);
5758 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5760 cm_ReleaseUser(userp);
5761 return CM_ERROR_NOSUCHPATH;
5763 code = cm_NameI(cm_data.rootSCachep, pathp,
5764 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5765 userp, tidPathp, &req, &scp);
5768 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5769 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5770 cm_ReleaseSCache(scp);
5771 cm_ReleaseUser(userp);
5772 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5773 return CM_ERROR_PATH_NOT_COVERED;
5775 return CM_ERROR_BADSHARENAME;
5777 #endif /* DFS_SUPPORT */
5780 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
5781 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5782 userp, tidPathp, &req, &dscp);
5784 cm_ReleaseUser(userp);
5789 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5790 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5792 cm_ReleaseSCache(dscp);
5793 cm_ReleaseUser(userp);
5794 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5795 return CM_ERROR_PATH_NOT_COVERED;
5797 return CM_ERROR_BADSHARENAME;
5799 #endif /* DFS_SUPPORT */
5800 /* otherwise, scp points to the parent directory. Do a lookup,
5801 * and truncate the file if we find it, otherwise we create the
5808 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
5810 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5811 cm_ReleaseSCache(dscp);
5812 cm_ReleaseUser(userp);
5817 /* if we get here, if code is 0, the file exists and is represented by
5818 * scp. Otherwise, we have to create it. The dir may be represented
5819 * by dscp, or we may have found the file directly. If code is non-zero,
5823 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
5825 if (dscp) cm_ReleaseSCache(dscp);
5826 cm_ReleaseSCache(scp);
5827 cm_ReleaseUser(userp);
5832 /* oops, file shouldn't be there */
5834 cm_ReleaseSCache(dscp);
5835 cm_ReleaseSCache(scp);
5836 cm_ReleaseUser(userp);
5837 return CM_ERROR_EXISTS;
5841 setAttr.mask = CM_ATTRMASK_LENGTH;
5842 setAttr.length.LowPart = 0;
5843 setAttr.length.HighPart = 0;
5844 code = cm_SetAttr(scp, &setAttr, userp, &req);
5845 openAction = 3; /* truncated existing file */
5847 else openAction = 1; /* found existing file */
5849 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
5850 /* don't create if not found */
5851 if (dscp) cm_ReleaseSCache(dscp);
5852 cm_ReleaseUser(userp);
5853 return CM_ERROR_NOSUCHFILE;
5856 osi_assertx(dscp != NULL, "null cm_scache_t");
5857 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %S",
5858 osi_LogSaveClientString(smb_logp, lastNamep));
5859 openAction = 2; /* created file */
5860 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5861 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5862 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5866 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5867 smb_NotifyChange(FILE_ACTION_ADDED,
5868 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5869 dscp, lastNamep, NULL, TRUE);
5870 } else if (!excl && code == CM_ERROR_EXISTS) {
5871 /* not an exclusive create, and someone else tried
5872 * creating it already, then we open it anyway. We
5873 * don't bother retrying after this, since if this next
5874 * fails, that means that the file was deleted after we
5875 * started this call.
5877 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5881 setAttr.mask = CM_ATTRMASK_LENGTH;
5882 setAttr.length.LowPart = 0;
5883 setAttr.length.HighPart = 0;
5884 code = cm_SetAttr(scp, &setAttr, userp, &req);
5886 } /* lookup succeeded */
5890 /* we don't need this any longer */
5892 cm_ReleaseSCache(dscp);
5895 /* something went wrong creating or truncating the file */
5897 cm_ReleaseSCache(scp);
5898 cm_ReleaseUser(userp);
5902 /* make sure we're about to open a file */
5903 if (scp->fileType != CM_SCACHETYPE_FILE) {
5904 cm_ReleaseSCache(scp);
5905 cm_ReleaseUser(userp);
5906 return CM_ERROR_ISDIR;
5909 /* now all we have to do is open the file itself */
5910 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5911 osi_assertx(fidp, "null smb_fid_t");
5914 lock_ObtainMutex(&fidp->mx);
5915 /* save a pointer to the vnode */
5917 lock_ObtainWrite(&scp->rw);
5918 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5919 lock_ReleaseWrite(&scp->rw);
5920 osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
5922 fidp->userp = userp;
5924 /* compute open mode */
5926 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5927 if (openMode == 1 || openMode == 2)
5928 fidp->flags |= SMB_FID_OPENWRITE;
5930 /* remember if the file was newly created */
5932 fidp->flags |= SMB_FID_CREATED;
5934 lock_ReleaseMutex(&fidp->mx);
5935 smb_ReleaseFID(fidp);
5937 cm_Open(scp, 0, userp);
5939 /* set inp->fid so that later read calls in same msg can find fid */
5940 inp->fid = fidp->fid;
5942 /* copy out remainder of the parms */
5944 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5945 lock_ObtainRead(&scp->rw);
5947 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5948 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5949 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5950 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5951 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5952 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5953 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5954 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5955 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5957 /* and the final "always present" stuff */
5958 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5959 /* next write out the "unique" ID */
5960 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5961 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5962 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5963 lock_ReleaseRead(&scp->rw);
5964 smb_SetSMBDataLength(outp, 0);
5966 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5968 cm_ReleaseUser(userp);
5969 /* leave scp held since we put it in fidp->scp */
5973 static void smb_GetLockParams(unsigned char LockType,
5975 unsigned int * ppid,
5976 LARGE_INTEGER * pOffset,
5977 LARGE_INTEGER * pLength)
5979 if (LockType & LOCKING_ANDX_LARGE_FILES) {
5981 *ppid = *((USHORT *) *buf);
5982 pOffset->HighPart = *((LONG *)(*buf + 4));
5983 pOffset->LowPart = *((DWORD *)(*buf + 8));
5984 pLength->HighPart = *((LONG *)(*buf + 12));
5985 pLength->LowPart = *((DWORD *)(*buf + 16));
5989 /* Not Large Files */
5990 *ppid = *((USHORT *) *buf);
5991 pOffset->HighPart = 0;
5992 pOffset->LowPart = *((DWORD *)(*buf + 2));
5993 pLength->HighPart = 0;
5994 pLength->LowPart = *((DWORD *)(*buf + 6));
5999 /* SMB_COM_LOCKING_ANDX */
6000 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6007 unsigned char LockType;
6008 unsigned short NumberOfUnlocks, NumberOfLocks;
6012 LARGE_INTEGER LOffset, LLength;
6013 smb_waitingLockRequest_t *wlRequest = NULL;
6014 cm_file_lock_t *lockp;
6022 fid = smb_GetSMBParm(inp, 2);
6023 fid = smb_ChainFID(fid, inp);
6025 fidp = smb_FindFID(vcp, fid, 0);
6027 return CM_ERROR_BADFD;
6029 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6030 smb_CloseFID(vcp, fidp, NULL, 0);
6031 smb_ReleaseFID(fidp);
6032 return CM_ERROR_NOSUCHFILE;
6035 lock_ObtainMutex(&fidp->mx);
6036 if (fidp->flags & SMB_FID_IOCTL) {
6037 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
6038 lock_ReleaseMutex(&fidp->mx);
6039 smb_ReleaseFID(fidp);
6040 return CM_ERROR_BADFD;
6043 osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
6045 lock_ReleaseMutex(&fidp->mx);
6047 /* set inp->fid so that later read calls in same msg can find fid */
6050 userp = smb_GetUserFromVCP(vcp, inp);
6053 lock_ObtainWrite(&scp->rw);
6054 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6055 CM_SCACHESYNC_NEEDCALLBACK
6056 | CM_SCACHESYNC_GETSTATUS
6057 | CM_SCACHESYNC_LOCK);
6059 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
6063 LockType = smb_GetSMBParm(inp, 3) & 0xff;
6064 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
6065 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
6066 NumberOfLocks = smb_GetSMBParm(inp, 7);
6068 if (!(fidp->flags & SMB_FID_OPENWRITE) &&
6069 !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
6070 /* somebody wants exclusive locks on a file that they only
6071 opened for reading. We downgrade this to a shared lock. */
6072 osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
6073 LockType |= LOCKING_ANDX_SHARED_LOCK;
6076 if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
6077 /* AFS does not support atomic changes of lock types from read or write and vice-versa */
6078 osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]");
6079 code = CM_ERROR_BADOP;
6084 op = smb_GetSMBData(inp, NULL);
6086 if (LockType & LOCKING_ANDX_CANCEL_LOCK) {
6087 /* Cancel outstanding lock requests */
6088 smb_waitingLock_t * wl;
6090 for (i=0; i<NumberOfLocks; i++) {
6091 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6093 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6095 lock_ObtainWrite(&smb_globalLock);
6096 for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
6098 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
6099 if (cm_KeyEquals(&wl->key, &key, 0) && LargeIntegerEqualTo(wl->LOffset, LOffset) &&
6100 LargeIntegerEqualTo(wl->LLength, LLength)) {
6101 wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
6102 goto found_lock_request;
6107 lock_ReleaseWrite(&smb_globalLock);
6110 smb_SetSMBDataLength(outp, 0);
6115 for (i=0; i<NumberOfUnlocks; i++) {
6116 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6118 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6120 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
6128 for (i=0; i<NumberOfLocks; i++) {
6129 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6131 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6133 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
6134 userp, &req, &lockp);
6136 if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
6137 (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
6139 code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
6140 userp, &req, &lockp);
6143 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
6144 smb_waitingLock_t * wLock;
6146 /* Put on waiting list */
6147 if(wlRequest == NULL) {
6151 LARGE_INTEGER tOffset, tLength;
6153 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
6155 osi_assertx(wlRequest != NULL, "null wlRequest");
6157 wlRequest->vcp = vcp;
6159 wlRequest->scp = scp;
6160 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
6162 wlRequest->inp = smb_CopyPacket(inp);
6163 wlRequest->outp = smb_CopyPacket(outp);
6164 wlRequest->lockType = LockType;
6165 wlRequest->msTimeout = Timeout;
6166 wlRequest->start_t = osi_Time();
6167 wlRequest->locks = NULL;
6169 /* The waiting lock request needs to have enough
6170 information to undo all the locks in the request.
6171 We do the following to store info about locks that
6172 have already been granted. Sure, we can get most
6173 of the info from the packet, but the packet doesn't
6174 hold the result of cm_Lock call. In practice we
6175 only receive packets with one or two locks, so we
6176 are only wasting a few bytes here and there and
6177 only for a limited period of time until the waiting
6178 lock times out or is freed. */
6180 for(opt = op_locks, j=i; j > 0; j--) {
6181 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
6183 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6185 wLock = malloc(sizeof(smb_waitingLock_t));
6187 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6190 wLock->LOffset = tOffset;
6191 wLock->LLength = tLength;
6192 wLock->lockp = NULL;
6193 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
6194 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6199 wLock = malloc(sizeof(smb_waitingLock_t));
6201 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6204 wLock->LOffset = LOffset;
6205 wLock->LLength = LLength;
6206 wLock->lockp = lockp;
6207 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
6208 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6211 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
6219 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
6226 /* Since something went wrong with the lock number i, we now
6227 have to go ahead and release any locks acquired before the
6228 failure. All locks before lock number i (of which there
6229 are i of them) have either been successful or are waiting.
6230 Either case requires calling cm_Unlock(). */
6232 /* And purge the waiting lock */
6233 if(wlRequest != NULL) {
6234 smb_waitingLock_t * wl;
6235 smb_waitingLock_t * wlNext;
6238 for(wl = wlRequest->locks; wl; wl = wlNext) {
6240 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
6242 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
6245 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
6247 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
6250 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
6255 smb_ReleaseVC(wlRequest->vcp);
6256 cm_ReleaseSCache(wlRequest->scp);
6257 smb_FreePacket(wlRequest->inp);
6258 smb_FreePacket(wlRequest->outp);
6267 if (wlRequest != NULL) {
6269 lock_ObtainWrite(&smb_globalLock);
6270 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
6272 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
6273 lock_ReleaseWrite(&smb_globalLock);
6275 /* don't send reply immediately */
6276 outp->flags |= SMB_PACKETFLAG_NOSEND;
6279 smb_SetSMBDataLength(outp, 0);
6283 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
6286 lock_ReleaseWrite(&scp->rw);
6287 cm_ReleaseSCache(scp);
6288 cm_ReleaseUser(userp);
6289 smb_ReleaseFID(fidp);
6294 /* SMB_COM_QUERY_INFORMATION2 */
6295 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6301 afs_uint32 searchTime;
6308 fid = smb_GetSMBParm(inp, 0);
6309 fid = smb_ChainFID(fid, inp);
6311 fidp = smb_FindFID(vcp, fid, 0);
6313 return CM_ERROR_BADFD;
6315 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6316 smb_CloseFID(vcp, fidp, NULL, 0);
6317 smb_ReleaseFID(fidp);
6318 return CM_ERROR_NOSUCHFILE;
6321 lock_ObtainMutex(&fidp->mx);
6322 if (fidp->flags & SMB_FID_IOCTL) {
6323 lock_ReleaseMutex(&fidp->mx);
6324 smb_ReleaseFID(fidp);
6325 return CM_ERROR_BADFD;
6328 osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6330 lock_ReleaseMutex(&fidp->mx);
6332 userp = smb_GetUserFromVCP(vcp, inp);
6335 /* otherwise, stat the file */
6336 lock_ObtainWrite(&scp->rw);
6337 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6338 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6342 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6344 lock_ConvertWToR(&scp->rw);
6347 /* decode times. We need a search time, but the response to this
6348 * call provides the date first, not the time, as returned in the
6349 * searchTime variable. So we take the high-order bits first.
6351 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
6352 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
6353 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
6354 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
6355 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
6356 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
6357 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
6359 /* now handle file size and allocation size */
6360 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
6361 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
6362 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
6363 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
6365 /* file attribute */
6366 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
6368 /* and finalize stuff */
6369 smb_SetSMBDataLength(outp, 0);
6374 lock_ReleaseRead(&scp->rw);
6376 lock_ReleaseWrite(&scp->rw);
6377 cm_ReleaseSCache(scp);
6378 cm_ReleaseUser(userp);
6379 smb_ReleaseFID(fidp);
6383 /* SMB_COM_SET_INFORMATION2 */
6384 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6390 afs_uint32 searchTime;
6398 fid = smb_GetSMBParm(inp, 0);
6399 fid = smb_ChainFID(fid, inp);
6401 fidp = smb_FindFID(vcp, fid, 0);
6403 return CM_ERROR_BADFD;
6405 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6406 smb_CloseFID(vcp, fidp, NULL, 0);
6407 smb_ReleaseFID(fidp);
6408 return CM_ERROR_NOSUCHFILE;
6411 lock_ObtainMutex(&fidp->mx);
6412 if (fidp->flags & SMB_FID_IOCTL) {
6413 lock_ReleaseMutex(&fidp->mx);
6414 smb_ReleaseFID(fidp);
6415 return CM_ERROR_BADFD;
6418 osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6420 lock_ReleaseMutex(&fidp->mx);
6422 userp = smb_GetUserFromVCP(vcp, inp);
6425 /* now prepare to call cm_setattr. This message only sets various times,
6426 * and AFS only implements mtime, and we'll set the mtime if that's
6427 * requested. The others we'll ignore.
6429 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
6431 if (searchTime != 0) {
6432 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
6434 if ( unixTime != -1 ) {
6435 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
6436 attrs.clientModTime = unixTime;
6437 code = cm_SetAttr(scp, &attrs, userp, &req);
6439 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
6441 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
6447 cm_ReleaseSCache(scp);
6448 cm_ReleaseUser(userp);
6449 smb_ReleaseFID(fidp);
6453 /* SMB_COM_WRITE_ANDX */
6454 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6457 long count, written = 0, total_written = 0;
6461 smb_t *smbp = (smb_t*) inp;
6465 int inDataBlockCount;
6467 fd = smb_GetSMBParm(inp, 2);
6468 count = smb_GetSMBParm(inp, 10);
6470 offset.HighPart = 0;
6471 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6473 if (*inp->wctp == 14) {
6474 /* we have a request with 64-bit file offsets */
6475 #ifdef AFS_LARGEFILES
6476 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6478 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6480 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
6481 /* we shouldn't have received this op if we didn't specify
6482 largefile support */
6483 return CM_ERROR_BADOP;
6488 op = inp->data + smb_GetSMBParm(inp, 11);
6489 inDataBlockCount = count;
6491 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
6492 fd, offset.HighPart, offset.LowPart, count);
6494 fd = smb_ChainFID(fd, inp);
6495 fidp = smb_FindFID(vcp, fd, 0);
6497 return CM_ERROR_BADFD;
6499 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6500 smb_CloseFID(vcp, fidp, NULL, 0);
6501 smb_ReleaseFID(fidp);
6502 return CM_ERROR_NOSUCHFILE;
6505 lock_ObtainMutex(&fidp->mx);
6506 if (fidp->flags & SMB_FID_IOCTL) {
6507 lock_ReleaseMutex(&fidp->mx);
6508 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
6509 smb_ReleaseFID(fidp);
6512 lock_ReleaseMutex(&fidp->mx);
6513 userp = smb_GetUserFromVCP(vcp, inp);
6515 /* special case: 0 bytes transferred means there is no data
6516 transferred. A slight departure from SMB_COM_WRITE where this
6517 means that we are supposed to truncate the file at this
6522 LARGE_INTEGER LOffset;
6523 LARGE_INTEGER LLength;
6527 key = cm_GenerateKey(vcp->vcID, pid, fd);
6529 LOffset.HighPart = offset.HighPart;
6530 LOffset.LowPart = offset.LowPart;
6531 LLength.HighPart = 0;
6532 LLength.LowPart = count;
6535 lock_ObtainWrite(&scp->rw);
6536 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
6537 lock_ReleaseWrite(&scp->rw);
6544 * Work around bug in NT client
6546 * When copying a file, the NT client should first copy the data,
6547 * then copy the last write time. But sometimes the NT client does
6548 * these in the wrong order, so the data copies would inadvertently
6549 * cause the last write time to be overwritten. We try to detect this,
6550 * and don't set client mod time if we think that would go against the
6553 lock_ObtainMutex(&fidp->mx);
6554 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6555 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6556 fidp->scp->clientModTime = time(NULL);
6558 lock_ReleaseMutex(&fidp->mx);
6561 while ( code == 0 && count > 0 ) {
6562 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6563 if (code == 0 && written == 0)
6564 code = CM_ERROR_PARTIALWRITE;
6566 offset = LargeIntegerAdd(offset,
6567 ConvertLongToLargeInteger(written));
6569 total_written += written;
6573 /* slots 0 and 1 are reserved for request chaining and will be
6574 filled in when we return. */
6575 smb_SetSMBParm(outp, 2, total_written);
6576 smb_SetSMBParm(outp, 3, 0); /* reserved */
6577 smb_SetSMBParm(outp, 4, 0); /* reserved */
6578 smb_SetSMBParm(outp, 5, 0); /* reserved */
6579 smb_SetSMBDataLength(outp, 0);
6582 cm_ReleaseUser(userp);
6583 smb_ReleaseFID(fidp);
6588 /* SMB_COM_READ_ANDX */
6589 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6593 long finalCount = 0;
6597 smb_t *smbp = (smb_t*) inp;
6603 fd = smb_GetSMBParm(inp, 2);
6604 count = smb_GetSMBParm(inp, 5);
6605 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6607 if (*inp->wctp == 12) {
6608 /* a request with 64-bit offsets */
6609 #ifdef AFS_LARGEFILES
6610 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
6612 if (LargeIntegerLessThanZero(offset)) {
6613 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
6614 offset.HighPart, offset.LowPart);
6615 return CM_ERROR_BADSMB;
6618 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
6619 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
6620 return CM_ERROR_BADSMB;
6622 offset.HighPart = 0;
6626 offset.HighPart = 0;
6629 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
6630 fd, offset.HighPart, offset.LowPart, count);
6632 fd = smb_ChainFID(fd, inp);
6633 fidp = smb_FindFID(vcp, fd, 0);
6635 return CM_ERROR_BADFD;
6638 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6639 smb_CloseFID(vcp, fidp, NULL, 0);
6640 smb_ReleaseFID(fidp);
6641 return CM_ERROR_NOSUCHFILE;
6645 key = cm_GenerateKey(vcp->vcID, pid, fd);
6647 LARGE_INTEGER LOffset, LLength;
6650 LOffset.HighPart = offset.HighPart;
6651 LOffset.LowPart = offset.LowPart;
6652 LLength.HighPart = 0;
6653 LLength.LowPart = count;
6656 lock_ObtainWrite(&scp->rw);
6657 code = cm_LockCheckRead(scp, LOffset, LLength, key);
6658 lock_ReleaseWrite(&scp->rw);
6662 smb_ReleaseFID(fidp);
6666 /* set inp->fid so that later read calls in same msg can find fid */
6669 lock_ObtainMutex(&fidp->mx);
6670 if (fidp->flags & SMB_FID_IOCTL) {
6671 lock_ReleaseMutex(&fidp->mx);
6672 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
6673 smb_ReleaseFID(fidp);
6676 lock_ReleaseMutex(&fidp->mx);
6678 userp = smb_GetUserFromVCP(vcp, inp);
6680 /* 0 and 1 are reserved for request chaining, were setup by our caller,
6681 * and will be further filled in after we return.
6683 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
6684 smb_SetSMBParm(outp, 3, 0); /* resvd */
6685 smb_SetSMBParm(outp, 4, 0); /* resvd */
6686 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
6687 /* fill in #6 when we have all the parameters' space reserved */
6688 smb_SetSMBParm(outp, 7, 0); /* resv'd */
6689 smb_SetSMBParm(outp, 8, 0); /* resv'd */
6690 smb_SetSMBParm(outp, 9, 0); /* resv'd */
6691 smb_SetSMBParm(outp, 10, 0); /* resv'd */
6692 smb_SetSMBParm(outp, 11, 0); /* reserved */
6694 /* get op ptr after putting in the parms, since otherwise we don't
6695 * know where the data really is.
6697 op = smb_GetSMBData(outp, NULL);
6699 /* now fill in offset from start of SMB header to first data byte (to op) */
6700 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
6702 /* set the packet data length the count of the # of bytes */
6703 smb_SetSMBDataLength(outp, count);
6705 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6707 /* fix some things up */
6708 smb_SetSMBParm(outp, 5, finalCount);
6709 smb_SetSMBDataLength(outp, finalCount);
6711 cm_ReleaseUser(userp);
6712 smb_ReleaseFID(fidp);
6717 * Values for createDisp, copied from NTDDK.H
6719 #define FILE_SUPERSEDE 0 // (???)
6720 #define FILE_OPEN 1 // (open)
6721 #define FILE_CREATE 2 // (exclusive)
6722 #define FILE_OPEN_IF 3 // (non-exclusive)
6723 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
6724 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
6727 #define REQUEST_OPLOCK 2
6728 #define REQUEST_BATCH_OPLOCK 4
6729 #define OPEN_DIRECTORY 8
6730 #define EXTENDED_RESPONSE_REQUIRED 0x10
6732 /* CreateOptions field. */
6733 #define FILE_DIRECTORY_FILE 0x0001
6734 #define FILE_WRITE_THROUGH 0x0002
6735 #define FILE_SEQUENTIAL_ONLY 0x0004
6736 #define FILE_NON_DIRECTORY_FILE 0x0040
6737 #define FILE_NO_EA_KNOWLEDGE 0x0200
6738 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
6739 #define FILE_RANDOM_ACCESS 0x0800
6740 #define FILE_DELETE_ON_CLOSE 0x1000
6741 #define FILE_OPEN_BY_FILE_ID 0x2000
6742 #define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000
6743 #define FILE_NO_COMPRESSION 0x00008000
6744 #define FILE_RESERVE_OPFILTER 0x00100000
6745 #define FILE_OPEN_REPARSE_POINT 0x00200000
6746 #define FILE_OPEN_NO_RECALL 0x00400000
6747 #define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000
6749 /* SMB_COM_NT_CREATE_ANDX */
6750 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6752 clientchar_t *pathp, *realPathp;
6756 cm_scache_t *dscp; /* parent dir */
6757 cm_scache_t *scp; /* file to create or open */
6758 cm_scache_t *targetScp; /* if scp is a symlink */
6760 clientchar_t *lastNamep;
6761 clientchar_t *treeStartp;
6762 unsigned short nameLength;
6764 unsigned int requestOpLock;
6765 unsigned int requestBatchOpLock;
6766 unsigned int mustBeDir;
6767 unsigned int extendedRespRequired;
6768 unsigned int treeCreate;
6770 unsigned int desiredAccess;
6771 unsigned int extAttributes;
6772 unsigned int createDisp;
6773 unsigned int createOptions;
6774 unsigned int shareAccess;
6775 int initialModeBits;
6776 unsigned short baseFid;
6777 smb_fid_t *baseFidp;
6779 cm_scache_t *baseDirp;
6780 unsigned short openAction;
6785 clientchar_t *tidPathp;
6790 int checkDoneRequired = 0;
6791 cm_lock_data_t *ldp = NULL;
6795 /* This code is very long and has a lot of if-then-else clauses
6796 * scp and dscp get reused frequently and we need to ensure that
6797 * we don't lose a reference. Start by ensuring that they are NULL.
6804 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
6805 flags = smb_GetSMBOffsetParm(inp, 3, 1)
6806 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
6807 requestOpLock = flags & REQUEST_OPLOCK;
6808 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6809 mustBeDir = flags & OPEN_DIRECTORY;
6810 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6813 * Why all of a sudden 32-bit FID?
6814 * We will reject all bits higher than 16.
6816 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
6817 return CM_ERROR_INVAL;
6818 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
6819 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
6820 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6821 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
6822 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
6823 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
6824 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
6825 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
6826 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
6827 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
6828 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
6830 /* mustBeDir is never set; createOptions directory bit seems to be
6833 if (createOptions & FILE_DIRECTORY_FILE)
6835 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6841 * compute initial mode bits based on read-only flag in
6842 * extended attributes
6844 initialModeBits = 0666;
6845 if (extAttributes & SMB_ATTR_READONLY)
6846 initialModeBits &= ~0222;
6848 pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
6849 NULL, SMB_STRF_ANSIPATH);
6851 /* Sometimes path is not null-terminated, so we make a copy. */
6852 realPathp = malloc(nameLength+sizeof(clientchar_t));
6853 memcpy(realPathp, pathp, nameLength+sizeof(clientchar_t));
6854 realPathp[nameLength/sizeof(clientchar_t)] = 0;
6856 spacep = inp->spacep;
6857 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
6859 osi_Log1(smb_logp,"NTCreateX for [%S]",osi_LogSaveClientString(smb_logp,realPathp));
6860 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
6861 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%S]", shareAccess, flags, osi_LogSaveClientString(smb_logp,(lastNamep?lastNamep:_C("null"))));
6864 (cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
6865 cm_ClientStrCmpIA(lastNamep, _C("\\srvsvc")) == 0 ||
6866 cm_ClientStrCmpIA(lastNamep, _C("\\wkssvc")) == 0 ||
6867 cm_ClientStrCmpIA(lastNamep, _C("ipc$")) == 0)) {
6868 /* special case magic file name for receiving IOCTL requests
6869 * (since IOCTL calls themselves aren't getting through).
6871 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6872 smb_SetupIoctlFid(fidp, spacep);
6873 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
6875 /* set inp->fid so that later read calls in same msg can find fid */
6876 inp->fid = fidp->fid;
6880 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6881 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6882 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
6884 memset(&ft, 0, sizeof(ft));
6885 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6886 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6887 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6888 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6889 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
6890 sz.HighPart = 0x7fff; sz.LowPart = 0;
6891 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
6892 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
6893 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6894 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6895 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
6896 smb_SetSMBDataLength(outp, 0);
6898 /* clean up fid reference */
6899 smb_ReleaseFID(fidp);
6904 if (!cm_IsValidClientString(realPathp)) {
6906 clientchar_t * hexp;
6908 hexp = cm_GetRawCharsAlloc(realPathp, -1);
6909 osi_Log1(smb_logp, "NTCreateX rejecting invalid name. [%S]",
6910 osi_LogSaveClientString(smb_logp, hexp));
6914 osi_Log0(smb_logp, "NTCreateX rejecting invalid name");
6917 return CM_ERROR_BADNTFILENAME;
6920 userp = smb_GetUserFromVCP(vcp, inp);
6922 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
6924 return CM_ERROR_INVAL;
6929 baseDirp = cm_data.rootSCachep;
6930 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6931 if (code == CM_ERROR_TIDIPC) {
6932 /* Attempt to use a TID allocated for IPC. The client
6933 * is probably looking for DCE RPC end points which we
6934 * don't support OR it could be looking to make a DFS
6937 osi_Log0(smb_logp, "NTCreateX received IPC TID");
6940 cm_ReleaseUser(userp);
6941 return CM_ERROR_NOSUCHFILE;
6942 #endif /* DFS_SUPPORT */
6945 baseFidp = smb_FindFID(vcp, baseFid, 0);
6947 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
6949 cm_ReleaseUser(userp);
6950 return CM_ERROR_INVAL;
6953 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6955 cm_ReleaseUser(userp);
6956 smb_CloseFID(vcp, baseFidp, NULL, 0);
6957 smb_ReleaseFID(baseFidp);
6958 return CM_ERROR_NOSUCHPATH;
6961 baseDirp = baseFidp->scp;
6965 osi_Log1(smb_logp, "NTCreateX tidPathp=[%S]", (tidPathp==NULL)?_C("null"): osi_LogSaveClientString(smb_logp,tidPathp));
6967 /* compute open mode */
6969 if (desiredAccess & DELETE)
6970 fidflags |= SMB_FID_OPENDELETE;
6971 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
6972 fidflags |= SMB_FID_OPENREAD_LISTDIR;
6973 if (desiredAccess & AFS_ACCESS_WRITE)
6974 fidflags |= SMB_FID_OPENWRITE;
6975 if (createOptions & FILE_DELETE_ON_CLOSE)
6976 fidflags |= SMB_FID_DELONCLOSE;
6977 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6978 fidflags |= SMB_FID_SEQUENTIAL;
6979 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6980 fidflags |= SMB_FID_RANDOM;
6981 if (createOptions & FILE_OPEN_REPARSE_POINT)
6982 osi_Log0(smb_logp, "NTCreateX Open Reparse Point");
6983 if (smb_IsExecutableFileName(lastNamep))
6984 fidflags |= SMB_FID_EXECUTABLE;
6986 /* and the share mode */
6987 if (shareAccess & FILE_SHARE_READ)
6988 fidflags |= SMB_FID_SHARE_READ;
6989 if (shareAccess & FILE_SHARE_WRITE)
6990 fidflags |= SMB_FID_SHARE_WRITE;
6992 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
6995 /* For an exclusive create, we want to do a case sensitive match for the last component. */
6996 if ( createDisp == FILE_CREATE ||
6997 createDisp == FILE_OVERWRITE ||
6998 createDisp == FILE_OVERWRITE_IF) {
6999 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7000 userp, tidPathp, &req, &dscp);
7003 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7004 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7006 cm_ReleaseSCache(dscp);
7007 cm_ReleaseUser(userp);
7010 smb_ReleaseFID(baseFidp);
7011 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7012 return CM_ERROR_PATH_NOT_COVERED;
7014 return CM_ERROR_BADSHARENAME;
7016 #endif /* DFS_SUPPORT */
7017 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7019 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7020 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7021 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7022 if (code == 0 && realDirFlag == 1) {
7023 cm_ReleaseSCache(scp);
7024 cm_ReleaseSCache(dscp);
7025 cm_ReleaseUser(userp);
7028 smb_ReleaseFID(baseFidp);
7029 return CM_ERROR_EXISTS;
7033 /* we have both scp and dscp */
7035 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7036 userp, tidPathp, &req, &scp);
7038 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7039 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7040 cm_ReleaseSCache(scp);
7041 cm_ReleaseUser(userp);
7044 smb_ReleaseFID(baseFidp);
7045 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7046 return CM_ERROR_PATH_NOT_COVERED;
7048 return CM_ERROR_BADSHARENAME;
7050 #endif /* DFS_SUPPORT */
7051 /* we might have scp but not dscp */
7057 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7058 /* look up parent directory */
7059 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
7060 * the immediate parent. We have to work our way up realPathp until we hit something that we
7064 /* we might or might not have scp */
7070 code = cm_NameI(baseDirp, spacep->wdata,
7071 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7072 userp, tidPathp, &req, &dscp);
7075 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7076 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7079 cm_ReleaseSCache(scp);
7080 cm_ReleaseSCache(dscp);
7081 cm_ReleaseUser(userp);
7084 smb_ReleaseFID(baseFidp);
7085 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7086 return CM_ERROR_PATH_NOT_COVERED;
7088 return CM_ERROR_BADSHARENAME;
7090 #endif /* DFS_SUPPORT */
7093 (tp = cm_ClientStrRChr(spacep->wdata, '\\')) &&
7094 (createDisp == FILE_CREATE) &&
7095 (realDirFlag == 1)) {
7098 treeStartp = realPathp + (tp - spacep->wdata);
7100 if (*tp && !smb_IsLegalFilename(tp)) {
7101 cm_ReleaseUser(userp);
7103 smb_ReleaseFID(baseFidp);
7106 cm_ReleaseSCache(scp);
7107 return CM_ERROR_BADNTFILENAME;
7111 } while (dscp == NULL && code == 0);
7115 /* we might have scp and we might have dscp */
7118 smb_ReleaseFID(baseFidp);
7121 osi_Log0(smb_logp,"NTCreateX parent not found");
7123 cm_ReleaseSCache(scp);
7125 cm_ReleaseSCache(dscp);
7126 cm_ReleaseUser(userp);
7131 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
7132 /* A file exists where we want a directory. */
7134 cm_ReleaseSCache(scp);
7135 cm_ReleaseSCache(dscp);
7136 cm_ReleaseUser(userp);
7138 return CM_ERROR_EXISTS;
7142 lastNamep = realPathp;
7146 if (!smb_IsLegalFilename(lastNamep)) {
7148 cm_ReleaseSCache(scp);
7150 cm_ReleaseSCache(dscp);
7151 cm_ReleaseUser(userp);
7153 return CM_ERROR_BADNTFILENAME;
7156 if (!foundscp && !treeCreate) {
7157 if ( createDisp == FILE_CREATE ||
7158 createDisp == FILE_OVERWRITE ||
7159 createDisp == FILE_OVERWRITE_IF)
7161 code = cm_Lookup(dscp, lastNamep,
7162 CM_FLAG_FOLLOW, userp, &req, &scp);
7164 code = cm_Lookup(dscp, lastNamep,
7165 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7168 if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
7170 cm_ReleaseSCache(dscp);
7171 cm_ReleaseUser(userp);
7176 /* we have scp and dscp */
7178 /* we have scp but not dscp */
7180 smb_ReleaseFID(baseFidp);
7183 /* if we get here, if code is 0, the file exists and is represented by
7184 * scp. Otherwise, we have to create it. The dir may be represented
7185 * by dscp, or we may have found the file directly. If code is non-zero,
7188 if (code == 0 && !treeCreate) {
7189 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7191 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7193 cm_ReleaseSCache(dscp);
7195 cm_ReleaseSCache(scp);
7196 cm_ReleaseUser(userp);
7200 checkDoneRequired = 1;
7202 if (createDisp == FILE_CREATE) {
7203 /* oops, file shouldn't be there */
7204 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7206 cm_ReleaseSCache(dscp);
7208 cm_ReleaseSCache(scp);
7209 cm_ReleaseUser(userp);
7211 return CM_ERROR_EXISTS;
7214 if ( createDisp == FILE_OVERWRITE ||
7215 createDisp == FILE_OVERWRITE_IF) {
7217 setAttr.mask = CM_ATTRMASK_LENGTH;
7218 setAttr.length.LowPart = 0;
7219 setAttr.length.HighPart = 0;
7220 /* now watch for a symlink */
7222 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7224 osi_assertx(dscp != NULL, "null cm_scache_t");
7225 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7227 /* we have a more accurate file to use (the
7228 * target of the symbolic link). Otherwise,
7229 * we'll just use the symlink anyway.
7231 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7233 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7234 cm_ReleaseSCache(scp);
7236 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7238 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7240 cm_ReleaseSCache(dscp);
7242 cm_ReleaseSCache(scp);
7243 cm_ReleaseUser(userp);
7249 code = cm_SetAttr(scp, &setAttr, userp, &req);
7250 openAction = 3; /* truncated existing file */
7253 openAction = 1; /* found existing file */
7255 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7256 /* don't create if not found */
7258 cm_ReleaseSCache(dscp);
7260 cm_ReleaseSCache(scp);
7261 cm_ReleaseUser(userp);
7263 return CM_ERROR_NOSUCHFILE;
7264 } else if (realDirFlag == 0 || realDirFlag == -1) {
7265 osi_assertx(dscp != NULL, "null cm_scache_t");
7266 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %S",
7267 osi_LogSaveClientString(smb_logp, lastNamep));
7268 openAction = 2; /* created file */
7269 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7270 setAttr.clientModTime = time(NULL);
7271 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
7274 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7275 smb_NotifyChange(FILE_ACTION_ADDED,
7276 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7277 dscp, lastNamep, NULL, TRUE);
7278 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7279 /* Not an exclusive create, and someone else tried
7280 * creating it already, then we open it anyway. We
7281 * don't bother retrying after this, since if this next
7282 * fails, that means that the file was deleted after we
7283 * started this call.
7285 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7288 if (createDisp == FILE_OVERWRITE_IF) {
7289 setAttr.mask = CM_ATTRMASK_LENGTH;
7290 setAttr.length.LowPart = 0;
7291 setAttr.length.HighPart = 0;
7293 /* now watch for a symlink */
7295 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7297 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7299 /* we have a more accurate file to use (the
7300 * target of the symbolic link). Otherwise,
7301 * we'll just use the symlink anyway.
7303 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7305 cm_ReleaseSCache(scp);
7309 code = cm_SetAttr(scp, &setAttr, userp, &req);
7311 } /* lookup succeeded */
7314 clientchar_t *tp, *pp;
7315 clientchar_t *cp; /* This component */
7316 int clen = 0; /* length of component */
7317 cm_scache_t *tscp1, *tscp2;
7320 /* create directory */
7322 treeStartp = lastNamep;
7323 osi_assertx(dscp != NULL, "null cm_scache_t");
7324 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%S]",
7325 osi_LogSaveClientString(smb_logp, treeStartp));
7326 openAction = 2; /* created directory */
7328 /* if the request is to create the root directory
7329 * it will appear as a directory name of the nul-string
7330 * and a code of CM_ERROR_NOSUCHFILE
7332 if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
7333 code = CM_ERROR_EXISTS;
7335 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7336 setAttr.clientModTime = time(NULL);
7341 cm_HoldSCache(tscp1);
7345 tp = cm_ClientStrChr(pp, '\\');
7347 cm_ClientStrCpy(cp, lengthof(spacep->wdata) - (cp - spacep->wdata), pp);
7348 clen = (int)cm_ClientStrLen(cp);
7349 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
7351 clen = (int)(tp - pp);
7352 cm_ClientStrCpyN(cp, lengthof(spacep->wdata) - (cp - spacep->wdata),
7360 continue; /* the supplied path can't have consecutive slashes either , but */
7362 /* cp is the next component to be created. */
7363 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req, NULL);
7364 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
7365 smb_NotifyChange(FILE_ACTION_ADDED,
7366 FILE_NOTIFY_CHANGE_DIR_NAME,
7367 tscp1, cp, NULL, TRUE);
7369 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7370 /* Not an exclusive create, and someone else tried
7371 * creating it already, then we open it anyway. We
7372 * don't bother retrying after this, since if this next
7373 * fails, that means that the file was deleted after we
7374 * started this call.
7376 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
7377 userp, &req, &tscp2);
7382 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
7383 cm_ReleaseSCache(tscp1);
7384 tscp1 = tscp2; /* Newly created directory will be next parent */
7385 /* the hold is transfered to tscp1 from tscp2 */
7390 cm_ReleaseSCache(dscp);
7393 cm_ReleaseSCache(scp);
7396 * if we get here and code == 0, then scp is the last directory created, and dscp is the
7402 /* something went wrong creating or truncating the file */
7403 if (checkDoneRequired)
7404 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7406 cm_ReleaseSCache(scp);
7408 cm_ReleaseSCache(dscp);
7409 cm_ReleaseUser(userp);
7414 /* make sure we have file vs. dir right (only applies for single component case) */
7415 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7416 /* now watch for a symlink */
7418 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7419 cm_scache_t * targetScp = 0;
7420 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7422 /* we have a more accurate file to use (the
7423 * target of the symbolic link). Otherwise,
7424 * we'll just use the symlink anyway.
7426 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
7427 if (checkDoneRequired) {
7428 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7429 checkDoneRequired = 0;
7431 cm_ReleaseSCache(scp);
7436 if (scp->fileType != CM_SCACHETYPE_FILE) {
7437 if (checkDoneRequired)
7438 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7440 cm_ReleaseSCache(dscp);
7441 cm_ReleaseSCache(scp);
7442 cm_ReleaseUser(userp);
7444 return CM_ERROR_ISDIR;
7448 /* (only applies to single component case) */
7449 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7450 if (checkDoneRequired)
7451 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7452 cm_ReleaseSCache(scp);
7454 cm_ReleaseSCache(dscp);
7455 cm_ReleaseUser(userp);
7457 return CM_ERROR_NOTDIR;
7460 /* open the file itself */
7461 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7462 osi_assertx(fidp, "null smb_fid_t");
7464 /* save a reference to the user */
7466 fidp->userp = userp;
7468 /* If we are restricting sharing, we should do so with a suitable
7470 if (scp->fileType == CM_SCACHETYPE_FILE &&
7471 !(fidflags & SMB_FID_SHARE_WRITE)) {
7473 LARGE_INTEGER LOffset, LLength;
7476 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7477 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7478 LLength.HighPart = 0;
7479 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7481 /* If we are not opening the file for writing, then we don't
7482 try to get an exclusive lock. No one else should be able to
7483 get an exclusive lock on the file anyway, although someone
7484 else can get a shared lock. */
7485 if ((fidflags & SMB_FID_SHARE_READ) ||
7486 !(fidflags & SMB_FID_OPENWRITE)) {
7487 sLockType = LOCKING_ANDX_SHARED_LOCK;
7492 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7494 lock_ObtainWrite(&scp->rw);
7495 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7496 lock_ReleaseWrite(&scp->rw);
7499 if (checkDoneRequired)
7500 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7501 cm_ReleaseSCache(scp);
7503 cm_ReleaseSCache(dscp);
7504 cm_ReleaseUser(userp);
7505 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7506 smb_CloseFID(vcp, fidp, NULL, 0);
7507 smb_ReleaseFID(fidp);
7513 /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
7514 if (checkDoneRequired) {
7515 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7516 checkDoneRequired = 0;
7519 lock_ObtainMutex(&fidp->mx);
7520 /* save a pointer to the vnode */
7521 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
7522 lock_ObtainWrite(&scp->rw);
7523 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7524 lock_ReleaseWrite(&scp->rw);
7525 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
7527 fidp->flags = fidflags;
7529 /* remember if the file was newly created */
7531 fidp->flags |= SMB_FID_CREATED;
7533 /* save parent dir and pathname for delete or change notification */
7534 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7535 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
7536 fidp->flags |= SMB_FID_NTOPEN;
7537 fidp->NTopen_dscp = dscp;
7539 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
7541 fidp->NTopen_wholepathp = realPathp;
7542 lock_ReleaseMutex(&fidp->mx);
7544 /* we don't need this any longer */
7546 cm_ReleaseSCache(dscp);
7550 cm_Open(scp, 0, userp);
7552 /* set inp->fid so that later read calls in same msg can find fid */
7553 inp->fid = fidp->fid;
7557 lock_ObtainRead(&scp->rw);
7558 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7559 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7560 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7561 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7562 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7563 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7564 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7565 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7566 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7568 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7569 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7570 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
7571 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
7572 smb_SetSMBParmByte(outp, parmSlot,
7573 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7574 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7575 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7576 smb_SetSMBDataLength(outp, 0);
7578 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
7579 LargeIntegerGreaterThanZero(fidp->scp->length) &&
7580 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
7583 lock_ReleaseRead(&scp->rw);
7586 cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
7587 fidp->scp->length.LowPart, fidp->scp->length.HighPart,
7591 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %S", fidp->fid,
7592 osi_LogSaveClientString(smb_logp, realPathp));
7594 cm_ReleaseUser(userp);
7595 smb_ReleaseFID(fidp);
7597 /* Can't free realPathp if we get here since
7598 fidp->NTopen_wholepathp is pointing there */
7600 /* leave scp held since we put it in fidp->scp */
7605 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
7606 * Instead, ultimately, would like to use a subroutine for common code.
7609 /* NT_TRANSACT_CREATE (SMB_COM_NT_TRANSACT) */
7610 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7612 clientchar_t *pathp, *realPathp;
7616 cm_scache_t *dscp; /* parent dir */
7617 cm_scache_t *scp; /* file to create or open */
7618 cm_scache_t *targetScp; /* if scp is a symlink */
7620 clientchar_t *lastNamep;
7621 unsigned long nameLength;
7623 unsigned int requestOpLock;
7624 unsigned int requestBatchOpLock;
7625 unsigned int mustBeDir;
7626 unsigned int extendedRespRequired;
7628 unsigned int desiredAccess;
7629 unsigned int allocSize;
7630 unsigned int shareAccess;
7631 unsigned int extAttributes;
7632 unsigned int createDisp;
7635 unsigned int impLevel;
7636 unsigned int secFlags;
7637 unsigned int createOptions;
7638 int initialModeBits;
7639 unsigned short baseFid;
7640 smb_fid_t *baseFidp;
7642 cm_scache_t *baseDirp;
7643 unsigned short openAction;
7647 clientchar_t *tidPathp;
7649 int parmOffset, dataOffset;
7656 cm_lock_data_t *ldp = NULL;
7657 int checkDoneRequired = 0;
7664 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7665 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7666 parmp = inp->data + parmOffset;
7667 lparmp = (ULONG *) parmp;
7670 requestOpLock = flags & REQUEST_OPLOCK;
7671 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7672 mustBeDir = flags & OPEN_DIRECTORY;
7673 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7676 * Why all of a sudden 32-bit FID?
7677 * We will reject all bits higher than 16.
7679 if (lparmp[1] & 0xFFFF0000)
7680 return CM_ERROR_INVAL;
7681 baseFid = (unsigned short)lparmp[1];
7682 desiredAccess = lparmp[2];
7683 allocSize = lparmp[3];
7684 extAttributes = lparmp[5];
7685 shareAccess = lparmp[6];
7686 createDisp = lparmp[7];
7687 createOptions = lparmp[8];
7690 nameLength = lparmp[11]; /* spec says chars but appears to be bytes */
7691 impLevel = lparmp[12];
7692 secFlags = lparmp[13];
7694 /* mustBeDir is never set; createOptions directory bit seems to be
7697 if (createOptions & FILE_DIRECTORY_FILE)
7699 else if (createOptions & FILE_NON_DIRECTORY_FILE)
7705 * compute initial mode bits based on read-only flag in
7706 * extended attributes
7708 initialModeBits = 0666;
7709 if (extAttributes & SMB_ATTR_READONLY)
7710 initialModeBits &= ~0222;
7712 pathp = smb_ParseStringCb(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
7713 nameLength, NULL, SMB_STRF_ANSIPATH);
7714 /* Sometimes path is not nul-terminated, so we make a copy. */
7715 realPathp = malloc(nameLength+sizeof(clientchar_t));
7716 memcpy(realPathp, pathp, nameLength);
7717 realPathp[nameLength/sizeof(clientchar_t)] = 0;
7718 spacep = cm_GetSpace();
7719 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
7721 osi_Log1(smb_logp,"NTTranCreate %S",osi_LogSaveStringW(smb_logp,realPathp));
7722 osi_Log4(smb_logp,"... da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
7723 osi_Log4(smb_logp,"... co[%x],sdl[%x],eal[%x],as[%x],flags[%x]",createOptions,sdLen,eaLen,allocSize);
7724 osi_Log3(smb_logp,"... imp[%x],sec[%x],flags[%x]", impLevel, secFlags, flags);
7727 * Nothing here to handle SMB_IOCTL_FILENAME.
7728 * Will add it if necessary.
7731 if (!cm_IsValidClientString(realPathp)) {
7733 clientchar_t * hexp;
7735 hexp = cm_GetRawCharsAlloc(realPathp, -1);
7736 osi_Log1(smb_logp, "NTTranCreate rejecting invalid name. [%S]",
7737 osi_LogSaveClientString(smb_logp, hexp));
7741 osi_Log0(smb_logp, "NTTranCreate rejecting invalid name.");
7744 return CM_ERROR_BADNTFILENAME;
7747 userp = smb_GetUserFromVCP(vcp, inp);
7749 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
7751 return CM_ERROR_INVAL;
7756 baseDirp = cm_data.rootSCachep;
7757 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7758 if (code == CM_ERROR_TIDIPC) {
7759 /* Attempt to use a TID allocated for IPC. The client
7760 * is probably looking for DCE RPC end points which we
7761 * don't support OR it could be looking to make a DFS
7764 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
7767 cm_ReleaseUser(userp);
7768 return CM_ERROR_NOSUCHPATH;
7772 baseFidp = smb_FindFID(vcp, baseFid, 0);
7774 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
7776 cm_ReleaseUser(userp);
7777 return CM_ERROR_BADFD;
7780 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7782 cm_ReleaseUser(userp);
7783 smb_CloseFID(vcp, baseFidp, NULL, 0);
7784 smb_ReleaseFID(baseFidp);
7785 return CM_ERROR_NOSUCHPATH;
7788 baseDirp = baseFidp->scp;
7792 /* compute open mode */
7794 if (desiredAccess & DELETE)
7795 fidflags |= SMB_FID_OPENDELETE;
7796 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
7797 fidflags |= SMB_FID_OPENREAD_LISTDIR;
7798 if (desiredAccess & AFS_ACCESS_WRITE)
7799 fidflags |= SMB_FID_OPENWRITE;
7800 if (createOptions & FILE_DELETE_ON_CLOSE)
7801 fidflags |= SMB_FID_DELONCLOSE;
7802 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7803 fidflags |= SMB_FID_SEQUENTIAL;
7804 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7805 fidflags |= SMB_FID_RANDOM;
7806 if (createOptions & FILE_OPEN_REPARSE_POINT)
7807 osi_Log0(smb_logp, "NTTranCreate Open Reparse Point");
7808 if (smb_IsExecutableFileName(lastNamep))
7809 fidflags |= SMB_FID_EXECUTABLE;
7811 /* And the share mode */
7812 if (shareAccess & FILE_SHARE_READ)
7813 fidflags |= SMB_FID_SHARE_READ;
7814 if (shareAccess & FILE_SHARE_WRITE)
7815 fidflags |= SMB_FID_SHARE_WRITE;
7819 if ( createDisp == FILE_OPEN ||
7820 createDisp == FILE_OVERWRITE ||
7821 createDisp == FILE_OVERWRITE_IF) {
7822 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7823 userp, tidPathp, &req, &dscp);
7826 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7827 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7828 cm_ReleaseSCache(dscp);
7829 cm_ReleaseUser(userp);
7832 smb_ReleaseFID(baseFidp);
7833 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7834 return CM_ERROR_PATH_NOT_COVERED;
7836 return CM_ERROR_BADSHARENAME;
7838 #endif /* DFS_SUPPORT */
7839 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7841 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7842 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7843 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7844 if (code == 0 && realDirFlag == 1) {
7845 cm_ReleaseSCache(scp);
7846 cm_ReleaseSCache(dscp);
7847 cm_ReleaseUser(userp);
7850 smb_ReleaseFID(baseFidp);
7851 return CM_ERROR_EXISTS;
7857 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7858 userp, tidPathp, &req, &scp);
7860 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7861 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7862 cm_ReleaseSCache(scp);
7863 cm_ReleaseUser(userp);
7866 smb_ReleaseFID(baseFidp);
7867 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7868 return CM_ERROR_PATH_NOT_COVERED;
7870 return CM_ERROR_BADSHARENAME;
7872 #endif /* DFS_SUPPORT */
7878 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7879 /* look up parent directory */
7881 code = cm_NameI(baseDirp, spacep->wdata,
7882 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7883 userp, tidPathp, &req, &dscp);
7885 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7886 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7887 cm_ReleaseSCache(dscp);
7888 cm_ReleaseUser(userp);
7891 smb_ReleaseFID(baseFidp);
7892 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7893 return CM_ERROR_PATH_NOT_COVERED;
7895 return CM_ERROR_BADSHARENAME;
7897 #endif /* DFS_SUPPORT */
7901 cm_FreeSpace(spacep);
7904 smb_ReleaseFID(baseFidp);
7907 cm_ReleaseUser(userp);
7913 lastNamep = realPathp;
7917 if (!smb_IsLegalFilename(lastNamep))
7918 return CM_ERROR_BADNTFILENAME;
7921 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
7922 code = cm_Lookup(dscp, lastNamep,
7923 CM_FLAG_FOLLOW, userp, &req, &scp);
7925 code = cm_Lookup(dscp, lastNamep,
7926 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7929 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7930 cm_ReleaseSCache(dscp);
7931 cm_ReleaseUser(userp);
7938 smb_ReleaseFID(baseFidp);
7939 cm_FreeSpace(spacep);
7942 /* if we get here, if code is 0, the file exists and is represented by
7943 * scp. Otherwise, we have to create it. The dir may be represented
7944 * by dscp, or we may have found the file directly. If code is non-zero,
7948 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7950 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7952 cm_ReleaseSCache(dscp);
7953 cm_ReleaseSCache(scp);
7954 cm_ReleaseUser(userp);
7958 checkDoneRequired = 1;
7960 if (createDisp == FILE_CREATE) {
7961 /* oops, file shouldn't be there */
7962 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7964 cm_ReleaseSCache(dscp);
7965 cm_ReleaseSCache(scp);
7966 cm_ReleaseUser(userp);
7968 return CM_ERROR_EXISTS;
7971 if (createDisp == FILE_OVERWRITE ||
7972 createDisp == FILE_OVERWRITE_IF) {
7973 setAttr.mask = CM_ATTRMASK_LENGTH;
7974 setAttr.length.LowPart = 0;
7975 setAttr.length.HighPart = 0;
7977 /* now watch for a symlink */
7979 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7981 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7983 /* we have a more accurate file to use (the
7984 * target of the symbolic link). Otherwise,
7985 * we'll just use the symlink anyway.
7987 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7989 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7990 cm_ReleaseSCache(scp);
7992 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7994 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7996 cm_ReleaseSCache(dscp);
7998 cm_ReleaseSCache(scp);
7999 cm_ReleaseUser(userp);
8005 code = cm_SetAttr(scp, &setAttr, userp, &req);
8006 openAction = 3; /* truncated existing file */
8008 else openAction = 1; /* found existing file */
8010 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
8011 /* don't create if not found */
8013 cm_ReleaseSCache(dscp);
8014 cm_ReleaseUser(userp);
8016 return CM_ERROR_NOSUCHFILE;
8018 else if (realDirFlag == 0 || realDirFlag == -1) {
8019 osi_assertx(dscp != NULL, "null cm_scache_t");
8020 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %S",
8021 osi_LogSaveClientString(smb_logp, lastNamep));
8022 openAction = 2; /* created file */
8023 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8024 setAttr.clientModTime = time(NULL);
8025 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8029 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8030 smb_NotifyChange(FILE_ACTION_ADDED,
8031 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8032 dscp, lastNamep, NULL, TRUE);
8033 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
8034 /* Not an exclusive create, and someone else tried
8035 * creating it already, then we open it anyway. We
8036 * don't bother retrying after this, since if this next
8037 * fails, that means that the file was deleted after we
8038 * started this call.
8040 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8043 if (createDisp == FILE_OVERWRITE_IF) {
8044 setAttr.mask = CM_ATTRMASK_LENGTH;
8045 setAttr.length.LowPart = 0;
8046 setAttr.length.HighPart = 0;
8048 /* now watch for a symlink */
8050 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8052 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8054 /* we have a more accurate file to use (the
8055 * target of the symbolic link). Otherwise,
8056 * we'll just use the symlink anyway.
8058 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8060 cm_ReleaseSCache(scp);
8064 code = cm_SetAttr(scp, &setAttr, userp, &req);
8066 } /* lookup succeeded */
8069 /* create directory */
8070 osi_assertx(dscp != NULL, "null cm_scache_t");
8072 "smb_ReceiveNTTranCreate creating directory %S",
8073 osi_LogSaveClientString(smb_logp, lastNamep));
8074 openAction = 2; /* created directory */
8075 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8076 setAttr.clientModTime = time(NULL);
8077 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8078 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8079 smb_NotifyChange(FILE_ACTION_ADDED,
8080 FILE_NOTIFY_CHANGE_DIR_NAME,
8081 dscp, lastNamep, NULL, TRUE);
8083 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
8084 /* Not an exclusive create, and someone else tried
8085 * creating it already, then we open it anyway. We
8086 * don't bother retrying after this, since if this next
8087 * fails, that means that the file was deleted after we
8088 * started this call.
8090 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8096 /* something went wrong creating or truncating the file */
8097 if (checkDoneRequired)
8098 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8100 cm_ReleaseSCache(scp);
8101 cm_ReleaseUser(userp);
8106 /* make sure we have file vs. dir right */
8107 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
8108 /* now watch for a symlink */
8110 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8112 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8114 /* we have a more accurate file to use (the
8115 * target of the symbolic link). Otherwise,
8116 * we'll just use the symlink anyway.
8118 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8120 if (checkDoneRequired) {
8121 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8122 checkDoneRequired = 0;
8124 cm_ReleaseSCache(scp);
8129 if (scp->fileType != CM_SCACHETYPE_FILE) {
8130 if (checkDoneRequired)
8131 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8132 cm_ReleaseSCache(scp);
8133 cm_ReleaseUser(userp);
8135 return CM_ERROR_ISDIR;
8139 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8140 if (checkDoneRequired)
8141 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8142 cm_ReleaseSCache(scp);
8143 cm_ReleaseUser(userp);
8145 return CM_ERROR_NOTDIR;
8148 /* open the file itself */
8149 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8150 osi_assertx(fidp, "null smb_fid_t");
8152 /* save a reference to the user */
8154 fidp->userp = userp;
8156 /* If we are restricting sharing, we should do so with a suitable
8158 if (scp->fileType == CM_SCACHETYPE_FILE &&
8159 !(fidflags & SMB_FID_SHARE_WRITE)) {
8161 LARGE_INTEGER LOffset, LLength;
8164 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8165 LOffset.LowPart = SMB_FID_QLOCK_LOW;
8166 LLength.HighPart = 0;
8167 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8169 /* Similar to what we do in handling NTCreateX. We get a
8170 shared lock if we are only opening the file for reading. */
8171 if ((fidflags & SMB_FID_SHARE_READ) ||
8172 !(fidflags & SMB_FID_OPENWRITE)) {
8173 sLockType = LOCKING_ANDX_SHARED_LOCK;
8178 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8180 lock_ObtainWrite(&scp->rw);
8181 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8182 lock_ReleaseWrite(&scp->rw);
8185 if (checkDoneRequired)
8186 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8187 cm_ReleaseSCache(scp);
8188 cm_ReleaseUser(userp);
8189 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
8190 smb_CloseFID(vcp, fidp, NULL, 0);
8191 smb_ReleaseFID(fidp);
8193 return CM_ERROR_SHARING_VIOLATION;
8197 /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
8198 if (checkDoneRequired) {
8199 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8200 checkDoneRequired = 0;
8203 lock_ObtainMutex(&fidp->mx);
8204 /* save a pointer to the vnode */
8206 lock_ObtainWrite(&scp->rw);
8207 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8208 lock_ReleaseWrite(&scp->rw);
8209 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
8211 fidp->flags = fidflags;
8213 /* remember if the file was newly created */
8215 fidp->flags |= SMB_FID_CREATED;
8217 /* save parent dir and pathname for deletion or change notification */
8218 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8219 fidp->flags |= SMB_FID_NTOPEN;
8220 fidp->NTopen_dscp = dscp;
8221 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
8223 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
8225 fidp->NTopen_wholepathp = realPathp;
8226 lock_ReleaseMutex(&fidp->mx);
8228 /* we don't need this any longer */
8230 cm_ReleaseSCache(dscp);
8232 cm_Open(scp, 0, userp);
8234 /* set inp->fid so that later read calls in same msg can find fid */
8235 inp->fid = fidp->fid;
8237 /* check whether we are required to send an extended response */
8238 if (!extendedRespRequired) {
8240 parmOffset = 8*4 + 39;
8241 parmOffset += 1; /* pad to 4 */
8242 dataOffset = parmOffset + 70;
8246 /* Total Parameter Count */
8247 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8248 /* Total Data Count */
8249 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8250 /* Parameter Count */
8251 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8252 /* Parameter Offset */
8253 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8254 /* Parameter Displacement */
8255 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8257 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8259 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8260 /* Data Displacement */
8261 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8262 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8263 smb_SetSMBDataLength(outp, 70);
8265 lock_ObtainRead(&scp->rw);
8266 outData = smb_GetSMBData(outp, NULL);
8267 outData++; /* round to get to parmOffset */
8268 *outData = 0; outData++; /* oplock */
8269 *outData = 0; outData++; /* reserved */
8270 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8271 *((ULONG *)outData) = openAction; outData += 4;
8272 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8273 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8274 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8275 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8276 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8277 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8278 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8279 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8280 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8281 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8282 *((USHORT *)outData) = 0; outData += 2; /* dev state */
8283 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8284 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8285 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8286 outData += 2; /* is a dir? */
8289 parmOffset = 8*4 + 39;
8290 parmOffset += 1; /* pad to 4 */
8291 dataOffset = parmOffset + 104;
8295 /* Total Parameter Count */
8296 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8297 /* Total Data Count */
8298 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8299 /* Parameter Count */
8300 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8301 /* Parameter Offset */
8302 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8303 /* Parameter Displacement */
8304 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8306 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8308 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8309 /* Data Displacement */
8310 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8311 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8312 smb_SetSMBDataLength(outp, 105);
8314 lock_ObtainRead(&scp->rw);
8315 outData = smb_GetSMBData(outp, NULL);
8316 outData++; /* round to get to parmOffset */
8317 *outData = 0; outData++; /* oplock */
8318 *outData = 1; outData++; /* response type */
8319 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8320 *((ULONG *)outData) = openAction; outData += 4;
8321 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8322 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8323 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8324 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8325 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8326 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8327 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8328 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8329 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8330 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8331 *((USHORT *)outData) = 0; outData += 2; /* dev state */
8332 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8333 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8334 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8335 outData += 1; /* is a dir? */
8336 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
8337 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
8338 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
8341 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
8342 LargeIntegerGreaterThanZero(fidp->scp->length) &&
8343 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
8346 lock_ReleaseRead(&scp->rw);
8349 cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
8350 fidp->scp->length.LowPart, fidp->scp->length.HighPart,
8353 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
8355 cm_ReleaseUser(userp);
8356 smb_ReleaseFID(fidp);
8358 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
8359 /* leave scp held since we put it in fidp->scp */
8363 /* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
8364 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
8367 smb_packet_t *savedPacketp;
8369 USHORT fid, watchtree;
8373 filter = smb_GetSMBParm(inp, 19) |
8374 (smb_GetSMBParm(inp, 20) << 16);
8375 fid = smb_GetSMBParm(inp, 21);
8376 watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
8378 fidp = smb_FindFID(vcp, fid, 0);
8380 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
8381 return CM_ERROR_BADFD;
8384 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8385 smb_CloseFID(vcp, fidp, NULL, 0);
8386 smb_ReleaseFID(fidp);
8387 return CM_ERROR_NOSUCHFILE;
8390 /* Create a copy of the Directory Watch Packet to use when sending the
8391 * notification if in the future a matching change is detected.
8393 savedPacketp = smb_CopyPacket(inp);
8394 if (vcp != savedPacketp->vcp) {
8396 if (savedPacketp->vcp)
8397 smb_ReleaseVC(savedPacketp->vcp);
8398 savedPacketp->vcp = vcp;
8401 /* Add the watch to the list of events to send notifications for */
8402 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8403 savedPacketp->nextp = smb_Directory_Watches;
8404 smb_Directory_Watches = savedPacketp;
8405 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8408 osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%S\"",
8409 fidp, scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp));
8410 osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
8411 filter, fid, watchtree);
8412 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8413 osi_Log0(smb_logp, " Notify Change File Name");
8414 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8415 osi_Log0(smb_logp, " Notify Change Directory Name");
8416 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8417 osi_Log0(smb_logp, " Notify Change Attributes");
8418 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8419 osi_Log0(smb_logp, " Notify Change Size");
8420 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8421 osi_Log0(smb_logp, " Notify Change Last Write");
8422 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8423 osi_Log0(smb_logp, " Notify Change Last Access");
8424 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8425 osi_Log0(smb_logp, " Notify Change Creation");
8426 if (filter & FILE_NOTIFY_CHANGE_EA)
8427 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8428 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8429 osi_Log0(smb_logp, " Notify Change Security");
8430 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8431 osi_Log0(smb_logp, " Notify Change Stream Name");
8432 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8433 osi_Log0(smb_logp, " Notify Change Stream Size");
8434 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8435 osi_Log0(smb_logp, " Notify Change Stream Write");
8437 lock_ObtainWrite(&scp->rw);
8439 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
8441 scp->flags |= CM_SCACHEFLAG_WATCHED;
8442 lock_ReleaseWrite(&scp->rw);
8443 smb_ReleaseFID(fidp);
8445 outp->flags |= SMB_PACKETFLAG_NOSEND;
8449 unsigned char nullSecurityDesc[36] = {
8450 0x01, /* security descriptor revision */
8451 0x00, /* reserved, should be zero */
8452 0x00, 0x80, /* security descriptor control;
8453 * 0x8000 : self-relative format */
8454 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
8455 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
8456 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
8457 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
8458 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8459 /* "null SID" owner SID */
8460 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
8461 /* "null SID" group SID */
8464 /* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
8465 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8467 int parmOffset, parmCount, dataOffset, dataCount;
8475 ULONG securityInformation;
8477 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8478 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8479 parmp = inp->data + parmOffset;
8480 sparmp = (USHORT *) parmp;
8481 lparmp = (ULONG *) parmp;
8484 securityInformation = lparmp[1];
8486 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
8487 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
8495 parmOffset = 8*4 + 39;
8496 parmOffset += 1; /* pad to 4 */
8498 dataOffset = parmOffset + parmCount;
8502 /* Total Parameter Count */
8503 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8504 /* Total Data Count */
8505 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8506 /* Parameter Count */
8507 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8508 /* Parameter Offset */
8509 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8510 /* Parameter Displacement */
8511 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8513 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8515 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8516 /* Data Displacement */
8517 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8518 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8519 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
8521 outData = smb_GetSMBData(outp, NULL);
8522 outData++; /* round to get to parmOffset */
8523 *((ULONG *)outData) = 36; outData += 4; /* length */
8525 if (maxData >= 36) {
8526 memcpy(outData, nullSecurityDesc, 36);
8530 return CM_ERROR_BUFFERTOOSMALL;
8533 /* SMB_COM_NT_TRANSACT
8535 SMB_COM_NT_TRANSACT_SECONDARY should also be handled here.
8537 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8539 unsigned short function;
8541 function = smb_GetSMBParm(inp, 18);
8543 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
8545 /* We can handle long names */
8546 if (vcp->flags & SMB_VCFLAG_USENT)
8547 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
8550 case 1: /* NT_TRANSACT_CREATE */
8551 return smb_ReceiveNTTranCreate(vcp, inp, outp);
8552 case 2: /* NT_TRANSACT_IOCTL */
8553 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
8555 case 3: /* NT_TRANSACT_SET_SECURITY_DESC */
8556 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
8558 case 4: /* NT_TRANSACT_NOTIFY_CHANGE */
8559 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
8560 case 5: /* NT_TRANSACT_RENAME */
8561 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
8563 case 6: /* NT_TRANSACT_QUERY_SECURITY_DESC */
8564 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
8566 osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
8569 osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
8572 return CM_ERROR_INVAL;
8576 * smb_NotifyChange -- find relevant change notification messages and
8579 * If we don't know the file name (i.e. a callback break), filename is
8580 * NULL, and we return a zero-length list.
8582 * At present there is not a single call to smb_NotifyChange that
8583 * has the isDirectParent parameter set to FALSE.
8585 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
8586 cm_scache_t *dscp, clientchar_t *filename, clientchar_t *otherFilename,
8587 BOOL isDirectParent)
8589 smb_packet_t *watch, *lastWatch, *nextWatch;
8590 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen = 0;
8591 char *outData, *oldOutData;
8595 BOOL twoEntries = FALSE;
8596 ULONG otherNameLen, oldParmCount = 0;
8600 /* Get ready for rename within directory */
8601 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
8603 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
8606 osi_Log4(smb_logp,"in smb_NotifyChange for file [%S] dscp [%p] notification 0x%x parent %d",
8607 osi_LogSaveClientString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
8609 osi_Log0(smb_logp," FILE_ACTION_NONE");
8610 if (action == FILE_ACTION_ADDED)
8611 osi_Log0(smb_logp," FILE_ACTION_ADDED");
8612 if (action == FILE_ACTION_REMOVED)
8613 osi_Log0(smb_logp," FILE_ACTION_REMOVED");
8614 if (action == FILE_ACTION_MODIFIED)
8615 osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
8616 if (action == FILE_ACTION_RENAMED_OLD_NAME)
8617 osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
8618 if (action == FILE_ACTION_RENAMED_NEW_NAME)
8619 osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
8621 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8622 watch = smb_Directory_Watches;
8624 filter = smb_GetSMBParm(watch, 19)
8625 | (smb_GetSMBParm(watch, 20) << 16);
8626 fid = smb_GetSMBParm(watch, 21);
8627 wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
8629 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
8630 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
8633 * Strange hack - bug in NT Client and NT Server that we must emulate?
8635 if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
8636 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
8638 fidp = smb_FindFID(watch->vcp, fid, 0);
8640 osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
8642 watch = watch->nextp;
8646 if (fidp->scp != dscp ||
8647 fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
8648 (filter & notifyFilter) == 0 ||
8649 (!isDirectParent && !wtree))
8651 osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
8653 watch = watch->nextp;
8654 smb_ReleaseFID(fidp);
8659 "Sending Change Notification for fid %d filter 0x%x wtree %d file %S",
8660 fid, filter, wtree, osi_LogSaveClientString(smb_logp, filename));
8661 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8662 osi_Log0(smb_logp, " Notify Change File Name");
8663 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8664 osi_Log0(smb_logp, " Notify Change Directory Name");
8665 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8666 osi_Log0(smb_logp, " Notify Change Attributes");
8667 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8668 osi_Log0(smb_logp, " Notify Change Size");
8669 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8670 osi_Log0(smb_logp, " Notify Change Last Write");
8671 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8672 osi_Log0(smb_logp, " Notify Change Last Access");
8673 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8674 osi_Log0(smb_logp, " Notify Change Creation");
8675 if (filter & FILE_NOTIFY_CHANGE_EA)
8676 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8677 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8678 osi_Log0(smb_logp, " Notify Change Security");
8679 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8680 osi_Log0(smb_logp, " Notify Change Stream Name");
8681 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8682 osi_Log0(smb_logp, " Notify Change Stream Size");
8683 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8684 osi_Log0(smb_logp, " Notify Change Stream Write");
8686 /* A watch can only be notified once. Remove it from the list */
8687 nextWatch = watch->nextp;
8688 if (watch == smb_Directory_Watches)
8689 smb_Directory_Watches = nextWatch;
8691 lastWatch->nextp = nextWatch;
8693 /* Turn off WATCHED flag in dscp */
8694 lock_ObtainWrite(&dscp->rw);
8696 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8698 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
8699 lock_ReleaseWrite(&dscp->rw);
8701 /* Convert to response packet */
8702 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
8703 #ifdef SEND_CANONICAL_PATHNAMES
8704 ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
8706 ((smb_t *) watch)->wct = 0;
8709 if (filename == NULL) {
8712 nameLen = (ULONG)cm_ClientStrLen(filename);
8713 parmCount = 3*4 + nameLen*2;
8714 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8716 otherNameLen = (ULONG)cm_ClientStrLen(otherFilename);
8717 oldParmCount = parmCount;
8718 parmCount += 3*4 + otherNameLen*2;
8719 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8721 if (maxLen < parmCount)
8722 parmCount = 0; /* not enough room */
8724 parmOffset = 8*4 + 39;
8725 parmOffset += 1; /* pad to 4 */
8726 dataOffset = parmOffset + parmCount;
8730 /* Total Parameter Count */
8731 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8732 /* Total Data Count */
8733 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8734 /* Parameter Count */
8735 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8736 /* Parameter Offset */
8737 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
8738 /* Parameter Displacement */
8739 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8741 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8743 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
8744 /* Data Displacement */
8745 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8746 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
8747 smb_SetSMBDataLength(watch, parmCount + 1);
8749 if (parmCount != 0) {
8750 outData = smb_GetSMBData(watch, NULL);
8751 outData++; /* round to get to parmOffset */
8752 oldOutData = outData;
8753 *((DWORD *)outData) = oldParmCount; outData += 4;
8754 /* Next Entry Offset */
8755 *((DWORD *)outData) = action; outData += 4;
8757 *((DWORD *)outData) = nameLen*2; outData += 4;
8758 /* File Name Length */
8760 smb_UnparseString(watch, outData, filename, NULL, 0);
8764 outData = oldOutData + oldParmCount;
8765 *((DWORD *)outData) = 0; outData += 4;
8766 /* Next Entry Offset */
8767 *((DWORD *)outData) = otherAction; outData += 4;
8769 *((DWORD *)outData) = otherNameLen*2;
8770 outData += 4; /* File Name Length */
8771 smb_UnparseString(watch, outData, otherFilename, NULL, 0);
8776 * If filename is null, we don't know the cause of the
8777 * change notification. We return zero data (see above),
8778 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
8779 * (= 0x010C). We set the error code here by hand, without
8780 * modifying wct and bcc.
8782 if (filename == NULL) {
8783 ((smb_t *) watch)->rcls = 0x0C;
8784 ((smb_t *) watch)->reh = 0x01;
8785 ((smb_t *) watch)->errLow = 0;
8786 ((smb_t *) watch)->errHigh = 0;
8787 /* Set NT Status codes flag */
8788 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8791 smb_SendPacket(watch->vcp, watch);
8792 smb_FreePacket(watch);
8794 smb_ReleaseFID(fidp);
8797 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8800 /* SMB_COM_NT_CANCEL */
8801 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8803 unsigned char *replyWctp;
8804 smb_packet_t *watch, *lastWatch;
8805 USHORT fid, watchtree;
8809 osi_Log0(smb_logp, "SMB3 receive NT cancel");
8811 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8812 watch = smb_Directory_Watches;
8814 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
8815 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
8816 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
8817 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
8818 if (watch == smb_Directory_Watches)
8819 smb_Directory_Watches = watch->nextp;
8821 lastWatch->nextp = watch->nextp;
8822 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8824 /* Turn off WATCHED flag in scp */
8825 fid = smb_GetSMBParm(watch, 21);
8826 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
8828 if (vcp != watch->vcp)
8829 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
8832 fidp = smb_FindFID(vcp, fid, 0);
8834 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %S",
8836 (fidp ? osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp) :_C("")));
8839 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
8840 lock_ObtainWrite(&scp->rw);
8842 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8844 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
8845 lock_ReleaseWrite(&scp->rw);
8846 smb_ReleaseFID(fidp);
8848 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
8851 /* assume STATUS32; return 0xC0000120 (CANCELED) */
8852 replyWctp = watch->wctp;
8856 ((smb_t *)watch)->rcls = 0x20;
8857 ((smb_t *)watch)->reh = 0x1;
8858 ((smb_t *)watch)->errLow = 0;
8859 ((smb_t *)watch)->errHigh = 0xC0;
8860 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8861 smb_SendPacket(vcp, watch);
8862 smb_FreePacket(watch);
8866 watch = watch->nextp;
8868 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8874 * NT rename also does hard links.
8877 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
8878 #define RENAME_FLAG_HARD_LINK 0x103
8879 #define RENAME_FLAG_RENAME 0x104
8880 #define RENAME_FLAG_COPY 0x105
8882 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8884 clientchar_t *oldPathp, *newPathp;
8890 attrs = smb_GetSMBParm(inp, 0);
8891 rename_type = smb_GetSMBParm(inp, 1);
8893 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
8894 osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
8895 return CM_ERROR_NOACCESS;
8898 tp = smb_GetSMBData(inp, NULL);
8899 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
8900 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
8902 osi_Log3(smb_logp, "NTRename for [%S]->[%S] type [%s]",
8903 osi_LogSaveClientString(smb_logp, oldPathp),
8904 osi_LogSaveClientString(smb_logp, newPathp),
8905 ((rename_type==RENAME_FLAG_RENAME)?"rename":(rename_type==RENAME_FLAG_HARD_LINK)?"hardlink":"other"));
8907 if (rename_type == RENAME_FLAG_RENAME) {
8908 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
8909 } else if (rename_type == RENAME_FLAG_HARD_LINK) { /* RENAME_FLAG_HARD_LINK */
8910 code = smb_Link(vcp,inp,oldPathp,newPathp);
8912 code = CM_ERROR_BADOP;
8918 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock", LOCK_HIERARCHY_SMB_DIRWATCH);
8921 cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
8923 smb_username_t *unp;
8926 unp = smb_FindUserByName(usern, machine, flags);
8928 lock_ObtainMutex(&unp->mx);
8929 unp->userp = cm_NewUser();
8930 lock_ReleaseMutex(&unp->mx);
8931 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
8933 osi_Log2(smb_logp,"smb_FindCMUserByName Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
8937 smb_ReleaseUsername(unp);