2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
15 #pragma warning(disable: 4005)
17 #define SECURITY_WIN32
29 #include <WINNT\afsreg.h>
34 extern osi_hyper_t hzero;
36 smb_packet_t *smb_Directory_Watches = NULL;
37 osi_mutex_t smb_Dir_Watch_Lock;
39 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
41 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
43 /* protected by the smb_globalLock */
44 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
46 const clientchar_t **smb_ExecutableExtensions = NULL;
48 /* retrieve a held reference to a user structure corresponding to an incoming
50 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
55 uidp = smb_FindUID(vcp, inp->uid, 0);
59 up = smb_GetUserFromUID(uidp);
67 * Return boolean specifying if the path name is thought to be an
68 * executable file. For now .exe or .dll.
70 afs_uint32 smb_IsExecutableFileName(const clientchar_t *name)
74 if ( smb_ExecutableExtensions == NULL || name == NULL)
77 len = (int)cm_ClientStrLen(name);
79 for ( i=0; smb_ExecutableExtensions[i]; i++) {
80 j = len - (int)cm_ClientStrLen(smb_ExecutableExtensions[i]);
81 if (cm_ClientStrCmpI(smb_ExecutableExtensions[i], &name[j]) == 0)
89 * Return extended attributes.
90 * Right now, we aren't using any of the "new" bits, so this looks exactly
91 * like smb_Attributes() (see smb.c).
93 unsigned long smb_ExtAttributes(cm_scache_t *scp)
97 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
98 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
99 scp->fileType == CM_SCACHETYPE_INVALID)
101 attrs = SMB_ATTR_DIRECTORY;
102 #ifdef SPECIAL_FOLDERS
103 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
104 #endif /* SPECIAL_FOLDERS */
105 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
106 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
107 } else if (scp->fid.vnode & 0x1)
108 attrs = SMB_ATTR_DIRECTORY;
113 * We used to mark a file RO if it was in an RO volume, but that
114 * turns out to be impolitic in NT. See defect 10007.
117 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
118 attrs |= SMB_ATTR_READONLY; /* Read-only */
120 if ((scp->unixModeBits & 0222) == 0)
121 attrs |= SMB_ATTR_READONLY; /* Read-only */
125 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
130 int smb_V3IsStarMask(clientchar_t *maskp)
134 while (tc = *maskp++)
135 if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
140 void OutputDebugF(clientchar_t * format, ...) {
142 clientchar_t vbuffer[1024];
144 va_start( args, format );
145 cm_ClientStrPrintfV(vbuffer, lengthof(vbuffer), format, args);
146 osi_Log1(smb_logp, "%S", osi_LogSaveClientString(smb_logp, vbuffer));
147 cm_ClientStrCat(vbuffer, lengthof(vbuffer), _C("\n"));
148 OutputDebugStringW(vbuffer);
151 void OutputDebugHexDump(unsigned char * buffer, int len) {
154 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
156 OutputDebugF(_C("Hexdump length [%d]"),len);
158 for (i=0;i<len;i++) {
161 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
162 StringCchCatA(buf, lengthof(buf), "\r\n");
163 OutputDebugString(buf);
165 StringCchPrintfA(buf, lengthof(buf), "%5x", i);
166 memset(buf+5,' ',80);
171 j = j*3 + 7 + ((j>7)?1:0);
174 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
177 j = j + 56 + ((j>7)?1:0);
179 buf[j] = (k>32 && k<127)?k:'.';
182 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
183 StringCchCatA(buf, lengthof(buf), "\r\n");
184 OutputDebugString(buf);
188 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
190 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
191 SECURITY_STATUS status, istatus;
192 CredHandle creds = {0,0};
194 SecBufferDesc secOut;
202 OutputDebugF(_C("Negotiating Extended Security"));
204 status = AcquireCredentialsHandle( NULL,
205 SMB_EXT_SEC_PACKAGE_NAME,
214 if (status != SEC_E_OK) {
215 /* Really bad. We return an empty security blob */
216 OutputDebugF(_C("AcquireCredentialsHandle failed with %lX"), status);
221 secOut.pBuffers = &secTok;
222 secOut.ulVersion = SECBUFFER_VERSION;
224 secTok.BufferType = SECBUFFER_TOKEN;
226 secTok.pvBuffer = NULL;
228 ctx.dwLower = ctx.dwUpper = 0;
230 status = AcceptSecurityContext( &creds,
233 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
234 SECURITY_NETWORK_DREP,
241 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
242 OutputDebugF(_C("Completing token..."));
243 istatus = CompleteAuthToken(&ctx, &secOut);
244 if ( istatus != SEC_E_OK )
245 OutputDebugF(_C("Token completion failed: %x"), istatus);
248 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
249 if (secTok.pvBuffer) {
250 *secBlobLength = secTok.cbBuffer;
251 *secBlob = malloc( secTok.cbBuffer );
252 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
255 if ( status != SEC_E_OK )
256 OutputDebugF(_C("AcceptSecurityContext status != CONTINUE %lX"), status);
259 /* Discard partial security context */
260 DeleteSecurityContext(&ctx);
262 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
264 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
265 FreeCredentialsHandle(&creds);
271 struct smb_ext_context {
278 long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern,
279 char * secBlobIn, int secBlobInLength,
280 char ** secBlobOut, int * secBlobOutLength) {
281 SECURITY_STATUS status, istatus;
285 SecBufferDesc secBufIn;
287 SecBufferDesc secBufOut;
290 struct smb_ext_context * secCtx = NULL;
291 struct smb_ext_context * newSecCtx = NULL;
292 void * assembledBlob = NULL;
293 int assembledBlobLength = 0;
296 OutputDebugF(_C("In smb_AuthenticateUserExt"));
299 *secBlobOutLength = 0;
301 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
302 secCtx = vcp->secCtx;
303 lock_ObtainMutex(&vcp->mx);
304 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
306 lock_ReleaseMutex(&vcp->mx);
310 OutputDebugF(_C("Received incoming token:"));
311 OutputDebugHexDump(secBlobIn,secBlobInLength);
315 OutputDebugF(_C("Continuing with existing context."));
316 creds = secCtx->creds;
319 if (secCtx->partialToken) {
320 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
321 assembledBlob = malloc(assembledBlobLength);
322 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
323 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
326 status = AcquireCredentialsHandle( NULL,
327 SMB_EXT_SEC_PACKAGE_NAME,
336 if (status != SEC_E_OK) {
337 OutputDebugF(_C("Can't acquire Credentials handle [%lX]"), status);
338 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
346 secBufIn.cBuffers = 1;
347 secBufIn.pBuffers = &secTokIn;
348 secBufIn.ulVersion = SECBUFFER_VERSION;
350 secTokIn.BufferType = SECBUFFER_TOKEN;
352 secTokIn.cbBuffer = assembledBlobLength;
353 secTokIn.pvBuffer = assembledBlob;
355 secTokIn.cbBuffer = secBlobInLength;
356 secTokIn.pvBuffer = secBlobIn;
359 secBufOut.cBuffers = 1;
360 secBufOut.pBuffers = &secTokOut;
361 secBufOut.ulVersion = SECBUFFER_VERSION;
363 secTokOut.BufferType = SECBUFFER_TOKEN;
364 secTokOut.cbBuffer = 0;
365 secTokOut.pvBuffer = NULL;
367 status = AcceptSecurityContext( &creds,
368 ((secCtx)?&ctx:NULL),
370 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
371 SECURITY_NETWORK_DREP,
378 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
379 OutputDebugF(_C("Completing token..."));
380 istatus = CompleteAuthToken(&ctx, &secBufOut);
381 if ( istatus != SEC_E_OK )
382 OutputDebugF(_C("Token completion failed: %lX"), istatus);
385 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
386 OutputDebugF(_C("Continue needed"));
388 newSecCtx = malloc(sizeof(*newSecCtx));
390 newSecCtx->creds = creds;
391 newSecCtx->ctx = ctx;
392 newSecCtx->partialToken = NULL;
393 newSecCtx->partialTokenLen = 0;
395 lock_ObtainMutex( &vcp->mx );
396 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
397 vcp->secCtx = newSecCtx;
398 lock_ReleaseMutex( &vcp->mx );
400 code = CM_ERROR_GSSCONTINUE;
403 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
404 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
405 secTokOut.pvBuffer) {
406 OutputDebugF(_C("Need to send token back to client"));
408 *secBlobOutLength = secTokOut.cbBuffer;
409 *secBlobOut = malloc(secTokOut.cbBuffer);
410 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
412 OutputDebugF(_C("Outgoing token:"));
413 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
414 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
415 OutputDebugF(_C("Incomplete message"));
417 newSecCtx = malloc(sizeof(*newSecCtx));
419 newSecCtx->creds = creds;
420 newSecCtx->ctx = ctx;
421 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
422 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
423 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
425 lock_ObtainMutex( &vcp->mx );
426 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
427 vcp->secCtx = newSecCtx;
428 lock_ReleaseMutex( &vcp->mx );
430 code = CM_ERROR_GSSCONTINUE;
433 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
435 SecPkgContext_NamesW names;
437 OutputDebugF(_C("Authentication completed"));
438 OutputDebugF(_C("Returned flags : [%lX]"), flags);
440 if (!QueryContextAttributesW(&ctx, SECPKG_ATTR_NAMES, &names)) {
441 OutputDebugF(_C("Received name [%s]"), names.sUserName);
442 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, names.sUserName);
443 cm_ClientStrLwr(usern); /* in tandem with smb_GetNormalizedUsername */
444 FreeContextBuffer(names.sUserName);
446 /* Force the user to retry if the context is invalid */
447 OutputDebugF(_C("QueryContextAttributes Names failed [%x]"), GetLastError());
448 code = CM_ERROR_BADPASSWORD;
452 case SEC_E_INVALID_TOKEN:
453 OutputDebugF(_C("Returning bad password :: INVALID_TOKEN"));
455 case SEC_E_INVALID_HANDLE:
456 OutputDebugF(_C("Returning bad password :: INVALID_HANDLE"));
458 case SEC_E_LOGON_DENIED:
459 OutputDebugF(_C("Returning bad password :: LOGON_DENIED"));
461 case SEC_E_UNKNOWN_CREDENTIALS:
462 OutputDebugF(_C("Returning bad password :: UNKNOWN_CREDENTIALS"));
464 case SEC_E_NO_CREDENTIALS:
465 OutputDebugF(_C("Returning bad password :: NO_CREDENTIALS"));
467 case SEC_E_CONTEXT_EXPIRED:
468 OutputDebugF(_C("Returning bad password :: CONTEXT_EXPIRED"));
470 case SEC_E_INCOMPLETE_CREDENTIALS:
471 OutputDebugF(_C("Returning bad password :: INCOMPLETE_CREDENTIALS"));
473 case SEC_E_WRONG_PRINCIPAL:
474 OutputDebugF(_C("Returning bad password :: WRONG_PRINCIPAL"));
476 case SEC_E_TIME_SKEW:
477 OutputDebugF(_C("Returning bad password :: TIME_SKEW"));
480 OutputDebugF(_C("Returning bad password :: Status == %lX"), status);
482 code = CM_ERROR_BADPASSWORD;
486 if (secCtx->partialToken) free(secCtx->partialToken);
494 if (secTokOut.pvBuffer)
495 FreeContextBuffer(secTokOut.pvBuffer);
497 if (code != CM_ERROR_GSSCONTINUE) {
498 DeleteSecurityContext(&ctx);
499 FreeCredentialsHandle(&creds);
507 #define P_RESP_LEN 128
509 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
510 So put stuff in a struct. */
511 struct Lm20AuthBlob {
512 MSV1_0_LM20_LOGON lmlogon;
513 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
514 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
515 WCHAR accountNameW[P_LEN];
516 WCHAR primaryDomainW[P_LEN];
517 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
518 TOKEN_GROUPS tgroups;
519 TOKEN_SOURCE tsource;
522 long smb_AuthenticateUserLM(smb_vc_t *vcp, clientchar_t * accountName, clientchar_t * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
525 struct Lm20AuthBlob lmAuth;
526 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
527 QUOTA_LIMITS quotaLimits;
529 ULONG lmprofilepSize;
533 OutputDebugF(_C("In smb_AuthenticateUser for user [%s] domain [%s]"), accountName, primaryDomain);
534 OutputDebugF(_C("ciPwdLength is %d and csPwdLength is %d"), ciPwdLength, csPwdLength);
536 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
537 OutputDebugF(_C("ciPwdLength or csPwdLength is too long"));
538 return CM_ERROR_BADPASSWORD;
541 memset(&lmAuth,0,sizeof(lmAuth));
543 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
545 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
546 cm_ClientStringToUtf16(primaryDomain, -1, lmAuth.primaryDomainW, P_LEN);
547 lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
548 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
550 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
551 cm_ClientStringToUtf16(accountName, -1, lmAuth.accountNameW, P_LEN);
552 lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
553 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
555 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
556 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
557 size = MAX_COMPUTERNAME_LENGTH + 1;
558 GetComputerNameW(lmAuth.workstationW, &size);
559 lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
561 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
563 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
564 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
565 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
566 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
568 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
569 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
570 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
571 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
573 lmAuth.lmlogon.ParameterControl = 0;
575 lmAuth.tgroups.GroupCount = 0;
576 lmAuth.tgroups.Groups[0].Sid = NULL;
577 lmAuth.tgroups.Groups[0].Attributes = 0;
580 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
582 lmAuth.tsource.SourceIdentifier.HighPart = 0;
584 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
585 StringCchCopyA(lmAuth.tsource.SourceName, lengthof(lmAuth.tsource.SourceName),
586 "OpenAFS"); /* 8 char limit */
588 nts = LsaLogonUser( smb_lsaHandle,
603 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
604 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
607 OutputDebugF(_C("Return from LsaLogonUser is 0x%lX"), nts);
608 OutputDebugF(_C("Extended status is 0x%lX"), ntsEx);
610 if (nts == ERROR_SUCCESS) {
612 LsaFreeReturnBuffer(lmprofilep);
613 CloseHandle(lmToken);
617 if (nts == 0xC000015BL)
618 return CM_ERROR_BADLOGONTYPE;
619 else /* our catchall is a bad password though we could be more specific */
620 return CM_ERROR_BADPASSWORD;
624 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
625 long smb_GetNormalizedUsername(clientchar_t * usern, const clientchar_t * accountName, const clientchar_t * domainName)
627 clientchar_t * atsign;
628 const clientchar_t * domain;
630 /* check if we have sane input */
631 if ((cm_ClientStrLen(accountName) + cm_ClientStrLen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
634 /* we could get : [accountName][domainName]
640 atsign = cm_ClientStrChr(accountName, '@');
642 if (atsign) /* [user@domain][] -> [user@domain][domain] */
647 /* if for some reason the client doesn't know what domain to use,
648 it will either return an empty string or a '?' */
649 if (!domain[0] || domain[0] == '?')
650 /* Empty domains and empty usernames are usually sent from tokenless contexts.
651 This way such logins will get an empty username (easy to check). I don't know
652 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
653 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, accountName);
655 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
656 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, domain);
657 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, _C("\\"));
659 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
661 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
664 cm_ClientStrLwr(usern);
669 /* When using SMB auth, all SMB sessions have to pass through here
670 * first to authenticate the user.
672 * Caveat: If not using SMB auth, the protocol does not require
673 * sending a session setup packet, which means that we can't rely on a
674 * UID in subsequent packets. Though in practice we get one anyway.
676 /* SMB_COM_SESSION_SETUP_ANDX */
677 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
681 unsigned short newUid;
682 unsigned long caps = 0;
684 clientchar_t *s1 = _C(" ");
686 clientchar_t usern[SMB_MAX_USERNAME_LENGTH];
687 char *secBlobOut = NULL;
688 int secBlobOutLength = 0;
690 /* Check for bad conns */
691 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
692 return CM_ERROR_REMOTECONN;
694 if (vcp->flags & SMB_VCFLAG_USENT) {
695 if (smb_authType == SMB_AUTH_EXTENDED) {
696 /* extended authentication */
700 OutputDebugF(_C("NT Session Setup: Extended"));
702 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
703 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
706 secBlobInLength = smb_GetSMBParm(inp, 7);
707 secBlobIn = smb_GetSMBData(inp, NULL);
709 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
711 if (code == CM_ERROR_GSSCONTINUE) {
714 smb_SetSMBParm(outp, 2, 0);
715 smb_SetSMBParm(outp, 3, secBlobOutLength);
717 tp = smb_GetSMBData(outp, NULL);
718 if (secBlobOutLength) {
719 memcpy(tp, secBlobOut, secBlobOutLength);
721 tp += secBlobOutLength;
722 cb_data += secBlobOutLength;
724 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
725 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
726 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
728 smb_SetSMBDataLength(outp, cb_data);
731 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
733 unsigned ciPwdLength, csPwdLength;
735 clientchar_t *accountName;
736 clientchar_t *primaryDomain;
739 if (smb_authType == SMB_AUTH_NTLM)
740 OutputDebugF(_C("NT Session Setup: NTLM"));
742 OutputDebugF(_C("NT Session Setup: None"));
744 /* TODO: parse for extended auth as well */
745 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
746 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
748 tp = smb_GetSMBData(inp, &datalen);
750 OutputDebugF(_C("Session packet data size [%d]"),datalen);
757 accountName = smb_ParseString(inp, tp, &tp, 0);
758 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
760 OutputDebugF(_C("Account Name: %s"),accountName);
761 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
762 OutputDebugF(_C("Case Sensitive Password: %s"),
763 csPwd && csPwd[0] ? _C("yes") : _C("no"));
764 OutputDebugF(_C("Case Insensitive Password: %s"),
765 ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
767 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
768 /* shouldn't happen */
769 code = CM_ERROR_BADSMB;
770 goto after_read_packet;
773 /* capabilities are only valid for first session packet */
774 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
775 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
778 if (smb_authType == SMB_AUTH_NTLM) {
779 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
781 OutputDebugF(_C("LM authentication failed [%d]"), code);
783 OutputDebugF(_C("LM authentication succeeded"));
787 unsigned ciPwdLength;
789 clientchar_t *accountName;
790 clientchar_t *primaryDomain;
792 switch ( smb_authType ) {
793 case SMB_AUTH_EXTENDED:
794 OutputDebugF(_C("V3 Session Setup: Extended"));
797 OutputDebugF(_C("V3 Session Setup: NTLM"));
800 OutputDebugF(_C("V3 Session Setup: None"));
802 ciPwdLength = smb_GetSMBParm(inp, 7);
803 tp = smb_GetSMBData(inp, NULL);
807 accountName = smb_ParseString(inp, tp, &tp, 0);
808 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
810 OutputDebugF(_C("Account Name: %s"),accountName);
811 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
812 OutputDebugF(_C("Case Insensitive Password: %s"), ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
814 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
815 /* shouldn't happen */
816 code = CM_ERROR_BADSMB;
817 goto after_read_packet;
820 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
823 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
824 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
826 OutputDebugF(_C("LM authentication failed [%d]"), code);
828 OutputDebugF(_C("LM authentication succeeded"));
833 /* note down that we received a session setup X and set the capabilities flag */
834 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
835 lock_ObtainMutex(&vcp->mx);
836 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
837 /* for the moment we can only deal with NTSTATUS */
838 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
839 vcp->flags |= SMB_VCFLAG_STATUS32;
843 if ((caps & NTNEGOTIATE_CAPABILITY_UNICODE) && smb_UseUnicode) {
844 vcp->flags |= SMB_VCFLAG_USEUNICODE;
847 lock_ReleaseMutex(&vcp->mx);
850 /* code would be non-zero if there was an authentication failure.
851 Ideally we would like to invalidate the uid for this session or break
852 early to avoid accidently stealing someone else's tokens. */
858 OutputDebugF(_C("Received username=[%s]"), usern);
860 /* On Windows 2000, this function appears to be called more often than
861 it is expected to be called. This resulted in multiple smb_user_t
862 records existing all for the same user session which results in all
863 of the users tokens disappearing.
865 To avoid this problem, we look for an existing smb_user_t record
866 based on the users name, and use that one if we find it.
869 uidp = smb_FindUserByNameThisSession(vcp, usern);
870 if (uidp) { /* already there, so don't create a new one */
872 newUid = uidp->userID;
873 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
874 vcp->lana,vcp->lsn,newUid);
875 smb_ReleaseUID(uidp);
880 /* do a global search for the username/machine name pair */
881 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
882 lock_ObtainMutex(&unp->mx);
883 if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
884 /* clear the afslogon flag so that the tickets can now
885 * be freed when the refCount returns to zero.
887 unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
889 lock_ReleaseMutex(&unp->mx);
891 /* Create a new UID and cm_user_t structure */
894 userp = cm_NewUser();
895 cm_HoldUserVCRef(userp);
896 lock_ObtainMutex(&vcp->mx);
897 if (!vcp->uidCounter)
898 vcp->uidCounter++; /* handle unlikely wraparounds */
899 newUid = (cm_ClientStrLen(usern)==0)?0:vcp->uidCounter++;
900 lock_ReleaseMutex(&vcp->mx);
902 /* Create a new smb_user_t structure and connect them up */
903 lock_ObtainMutex(&unp->mx);
905 lock_ReleaseMutex(&unp->mx);
907 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
909 lock_ObtainMutex(&uidp->mx);
911 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
912 lock_ReleaseMutex(&uidp->mx);
913 smb_ReleaseUID(uidp);
917 /* Return UID to the client */
918 ((smb_t *)outp)->uid = newUid;
919 /* Also to the next chained message */
920 ((smb_t *)inp)->uid = newUid;
922 osi_Log3(smb_logp, "SMB3 session setup name %S creating ID %d%S",
923 osi_LogSaveClientString(smb_logp, usern), newUid,
924 osi_LogSaveClientString(smb_logp, s1));
926 smb_SetSMBParm(outp, 2, 0);
928 if (vcp->flags & SMB_VCFLAG_USENT) {
929 if (smb_authType == SMB_AUTH_EXTENDED) {
932 smb_SetSMBParm(outp, 3, secBlobOutLength);
934 tp = smb_GetSMBData(outp, NULL);
935 if (secBlobOutLength) {
936 memcpy(tp, secBlobOut, secBlobOutLength);
938 tp += secBlobOutLength;
939 cb_data += secBlobOutLength;
942 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
943 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
944 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
946 smb_SetSMBDataLength(outp, cb_data);
948 smb_SetSMBDataLength(outp, 0);
951 if (smb_authType == SMB_AUTH_EXTENDED) {
954 tp = smb_GetSMBData(outp, NULL);
956 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
957 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
958 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
960 smb_SetSMBDataLength(outp, cb_data);
962 smb_SetSMBDataLength(outp, 0);
969 /* SMB_COM_LOGOFF_ANDX */
970 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
974 /* find the tree and free it */
975 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
977 smb_username_t * unp;
979 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %S", uidp->userID,
980 osi_LogSaveClientString(smb_logp, (uidp->unp) ? uidp->unp->name: _C(" ")));
982 lock_ObtainMutex(&uidp->mx);
983 uidp->flags |= SMB_USERFLAG_DELETE;
985 * it doesn't get deleted right away
986 * because the vcp points to it
989 lock_ReleaseMutex(&uidp->mx);
992 /* we can't do this. we get logoff messages prior to a session
993 * disconnect even though it doesn't mean the user is logging out.
994 * we need to create a new pioctl and EventLogoff handler to set
995 * SMB_USERNAMEFLAG_LOGOFF.
997 if (unp && smb_LogoffTokenTransfer) {
998 lock_ObtainMutex(&unp->mx);
999 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
1000 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
1001 lock_ReleaseMutex(&unp->mx);
1005 smb_ReleaseUID(uidp);
1008 osi_Log0(smb_logp, "SMB3 user logoffX");
1010 smb_SetSMBDataLength(outp, 0);
1014 #define SMB_SUPPORT_SEARCH_BITS 0x0001
1015 #define SMB_SHARE_IS_IN_DFS 0x0002
1017 /* SMB_COM_TREE_CONNECT_ANDX */
1018 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1021 smb_user_t *uidp = NULL;
1022 unsigned short newTid;
1023 clientchar_t shareName[AFSPATHMAX];
1024 clientchar_t *sharePath;
1027 clientchar_t *slashp;
1028 clientchar_t *pathp;
1029 clientchar_t *passwordp;
1030 clientchar_t *servicep;
1031 cm_user_t *userp = NULL;
1034 osi_Log0(smb_logp, "SMB3 receive tree connect");
1036 /* parse input parameters */
1037 tp = smb_GetSMBData(inp, NULL);
1038 passwordp = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1039 pathp = smb_ParseString(inp, tp, &tp, SMB_STRF_ANSIPATH);
1040 servicep = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1042 slashp = cm_ClientStrRChr(pathp, '\\');
1044 return CM_ERROR_BADSMB;
1046 cm_ClientStrCpy(shareName, lengthof(shareName), slashp+1);
1048 osi_Log3(smb_logp, "Tree connect pathp[%S] shareName[%S] service[%S]",
1049 osi_LogSaveClientString(smb_logp, pathp),
1050 osi_LogSaveClientString(smb_logp, shareName),
1051 osi_LogSaveClientString(smb_logp, servicep));
1053 if (cm_ClientStrCmp(servicep, _C("IPC")) == 0 ||
1054 cm_ClientStrCmp(shareName, _C("IPC$")) == 0) {
1056 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1059 return CM_ERROR_NOIPC;
1063 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1065 userp = smb_GetUserFromUID(uidp);
1067 lock_ObtainMutex(&vcp->mx);
1068 newTid = vcp->tidCounter++;
1069 lock_ReleaseMutex(&vcp->mx);
1071 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1074 if (!cm_ClientStrCmp(shareName, _C("*.")))
1075 cm_ClientStrCpy(shareName, lengthof(shareName), _C("all"));
1076 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1079 smb_ReleaseUID(uidp);
1080 smb_ReleaseTID(tidp, FALSE);
1081 return CM_ERROR_BADSHARENAME;
1084 if (vcp->flags & SMB_VCFLAG_USENT)
1086 int policy = smb_FindShareCSCPolicy(shareName);
1089 DWORD dwAdvertiseDFS = 0, dwSize = sizeof(DWORD);
1091 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1092 0, KEY_QUERY_VALUE, &parmKey);
1093 if (code == ERROR_SUCCESS) {
1094 code = RegQueryValueEx(parmKey, "AdvertiseDFS", NULL, NULL,
1095 (BYTE *)&dwAdvertiseDFS, &dwSize);
1096 if (code != ERROR_SUCCESS)
1098 RegCloseKey (parmKey);
1100 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1101 (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
1105 smb_SetSMBParm(outp, 2, 0);
1109 smb_ReleaseUID(uidp);
1111 lock_ObtainMutex(&tidp->mx);
1112 tidp->userp = userp;
1113 tidp->pathname = sharePath;
1115 tidp->flags |= SMB_TIDFLAG_IPC;
1116 lock_ReleaseMutex(&tidp->mx);
1117 smb_ReleaseTID(tidp, FALSE);
1119 ((smb_t *)outp)->tid = newTid;
1120 ((smb_t *)inp)->tid = newTid;
1121 tp = smb_GetSMBData(outp, NULL);
1125 tp = smb_UnparseString(outp, tp, _C("A:"), &cb_data, SMB_STRF_FORCEASCII);
1126 tp = smb_UnparseString(outp, tp, _C("AFS"), &cb_data, 0);
1127 smb_SetSMBDataLength(outp, cb_data);
1131 tp = smb_UnparseString(outp, tp, _C("IPC"), &cb_data, SMB_STRF_FORCEASCII);
1132 smb_SetSMBDataLength(outp, cb_data);
1135 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1139 /* must be called with global tran lock held */
1140 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1142 smb_tran2Packet_t *tp;
1145 smbp = (smb_t *) inp->data;
1146 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1147 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1153 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1154 int totalParms, int totalData)
1156 smb_tran2Packet_t *tp;
1159 smbp = (smb_t *) inp->data;
1160 tp = malloc(sizeof(*tp));
1161 memset(tp, 0, sizeof(*tp));
1164 tp->curData = tp->curParms = 0;
1165 tp->totalData = totalData;
1166 tp->totalParms = totalParms;
1167 tp->tid = smbp->tid;
1168 tp->mid = smbp->mid;
1169 tp->uid = smbp->uid;
1170 tp->pid = smbp->pid;
1171 tp->res[0] = smbp->res[0];
1172 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1173 if (totalParms != 0)
1174 tp->parmsp = malloc(totalParms);
1176 tp->datap = malloc(totalData);
1177 if (smbp->com == 0x25 || smbp->com == 0x26)
1180 tp->opcode = smb_GetSMBParm(inp, 14);
1183 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1185 if (WANTS_UNICODE(inp) && (vcp->flags & SMB_VCFLAG_USEUNICODE))
1186 tp->flags |= SMB_TRAN2PFLAG_USEUNICODE;
1191 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1192 smb_tran2Packet_t *inp, smb_packet_t *outp,
1193 int totalParms, int totalData)
1195 smb_tran2Packet_t *tp;
1196 unsigned short parmOffset;
1197 unsigned short dataOffset;
1198 unsigned short dataAlign;
1200 tp = malloc(sizeof(*tp));
1201 memset(tp, 0, sizeof(*tp));
1204 tp->curData = tp->curParms = 0;
1205 tp->totalData = totalData;
1206 tp->totalParms = totalParms;
1207 tp->oldTotalParms = totalParms;
1212 tp->res[0] = inp->res[0];
1213 tp->opcode = inp->opcode;
1217 * We calculate where the parameters and data will start.
1218 * This calculation must parallel the calculation in
1219 * smb_SendTran2Packet.
1222 parmOffset = 10*2 + 35;
1223 parmOffset++; /* round to even */
1224 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1226 dataOffset = parmOffset + totalParms;
1227 dataAlign = dataOffset & 2; /* quad-align */
1228 dataOffset += dataAlign;
1229 tp->datap = outp->data + dataOffset;
1234 /* free a tran2 packet */
1235 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1238 smb_ReleaseVC(t2p->vcp);
1241 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1247 while (t2p->stringsp) {
1251 t2p->stringsp = ns->nextp;
1257 clientchar_t *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
1258 char ** chainpp, int flags)
1263 if (!(p->flags & SMB_TRAN2PFLAG_USEUNICODE))
1264 flags |= SMB_STRF_FORCEASCII;
1267 cb = p->totalParms - (inp - (char *)p->parmsp);
1268 if (inp < (char *) p->parmsp ||
1269 inp >= ((char *) p->parmsp) + p->totalParms) {
1270 #ifdef DEBUG_UNICODE
1276 return smb_ParseStringBuf((unsigned char *) p->parmsp, &p->stringsp,
1277 inp, &cb, chainpp, flags);
1280 /* called with a VC, an input packet to respond to, and an error code.
1281 * sends an error response.
1283 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1284 smb_packet_t *tp, long code)
1287 unsigned short errCode;
1288 unsigned char errClass;
1289 unsigned long NTStatus;
1291 if (vcp->flags & SMB_VCFLAG_STATUS32)
1292 smb_MapNTError(code, &NTStatus);
1294 smb_MapCoreError(code, vcp, &errCode, &errClass);
1296 smb_FormatResponsePacket(vcp, NULL, tp);
1297 smbp = (smb_t *) tp;
1299 /* We can handle long names */
1300 if (vcp->flags & SMB_VCFLAG_USENT)
1301 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1303 /* now copy important fields from the tran 2 packet */
1304 smbp->com = t2p->com;
1305 smbp->tid = t2p->tid;
1306 smbp->mid = t2p->mid;
1307 smbp->pid = t2p->pid;
1308 smbp->uid = t2p->uid;
1309 smbp->res[0] = t2p->res[0];
1310 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1311 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1312 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1313 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1314 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1315 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1318 smbp->rcls = errClass;
1319 smbp->errLow = (unsigned char) (errCode & 0xff);
1320 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1324 smb_SendPacket(vcp, tp);
1327 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1330 unsigned short parmOffset;
1331 unsigned short dataOffset;
1332 unsigned short totalLength;
1333 unsigned short dataAlign;
1336 smb_FormatResponsePacket(vcp, NULL, tp);
1337 smbp = (smb_t *) tp;
1339 /* We can handle long names */
1340 if (vcp->flags & SMB_VCFLAG_USENT)
1341 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1343 /* now copy important fields from the tran 2 packet */
1344 smbp->com = t2p->com;
1345 smbp->tid = t2p->tid;
1346 smbp->mid = t2p->mid;
1347 smbp->pid = t2p->pid;
1348 smbp->uid = t2p->uid;
1349 smbp->res[0] = t2p->res[0];
1351 totalLength = 1 + t2p->totalData + t2p->totalParms;
1353 /* now add the core parameters (tran2 info) to the packet */
1354 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1355 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1356 smb_SetSMBParm(tp, 2, 0); /* reserved */
1357 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1358 parmOffset = 10*2 + 35; /* parm offset in packet */
1359 parmOffset++; /* round to even */
1360 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1361 * hdr, bcc and wct */
1362 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1363 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1364 dataOffset = parmOffset + t2p->oldTotalParms;
1365 dataAlign = dataOffset & 2; /* quad-align */
1366 dataOffset += dataAlign;
1367 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1368 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1369 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1372 datap = smb_GetSMBData(tp, NULL);
1373 *datap++ = 0; /* we rounded to even */
1375 totalLength += dataAlign;
1376 smb_SetSMBDataLength(tp, totalLength);
1378 /* next, send the datagram */
1379 smb_SendPacket(vcp, tp);
1383 /* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
1384 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1386 smb_tran2Packet_t *asp;
1399 /* We sometimes see 0 word count. What to do? */
1400 if (*inp->wctp == 0) {
1401 osi_Log0(smb_logp, "Transaction2 word count = 0");
1402 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1404 smb_SetSMBDataLength(outp, 0);
1405 smb_SendPacket(vcp, outp);
1409 totalParms = smb_GetSMBParm(inp, 0);
1410 totalData = smb_GetSMBParm(inp, 1);
1412 firstPacket = (inp->inCom == 0x25);
1414 /* find the packet we're reassembling */
1415 lock_ObtainWrite(&smb_globalLock);
1416 asp = smb_FindTran2Packet(vcp, inp);
1418 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1420 lock_ReleaseWrite(&smb_globalLock);
1422 /* now merge in this latest packet; start by looking up offsets */
1424 parmDisp = dataDisp = 0;
1425 parmOffset = smb_GetSMBParm(inp, 10);
1426 dataOffset = smb_GetSMBParm(inp, 12);
1427 parmCount = smb_GetSMBParm(inp, 9);
1428 dataCount = smb_GetSMBParm(inp, 11);
1429 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1430 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1432 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1433 totalData, dataCount, asp->maxReturnData);
1436 parmDisp = smb_GetSMBParm(inp, 4);
1437 parmOffset = smb_GetSMBParm(inp, 3);
1438 dataDisp = smb_GetSMBParm(inp, 7);
1439 dataOffset = smb_GetSMBParm(inp, 6);
1440 parmCount = smb_GetSMBParm(inp, 2);
1441 dataCount = smb_GetSMBParm(inp, 5);
1443 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1444 parmCount, dataCount);
1447 /* now copy the parms and data */
1448 if ( asp->totalParms > 0 && parmCount != 0 )
1450 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1452 if ( asp->totalData > 0 && dataCount != 0 ) {
1453 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1456 /* account for new bytes */
1457 asp->curData += dataCount;
1458 asp->curParms += parmCount;
1460 /* finally, if we're done, remove the packet from the queue and dispatch it */
1461 if (asp->totalParms > 0 &&
1462 asp->curParms > 0 &&
1463 asp->totalData <= asp->curData &&
1464 asp->totalParms <= asp->curParms) {
1465 /* we've received it all */
1466 lock_ObtainWrite(&smb_globalLock);
1467 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1468 lock_ReleaseWrite(&smb_globalLock);
1470 /* now dispatch it */
1471 rapOp = asp->parmsp[0];
1473 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1474 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1475 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1476 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
1479 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1480 code = CM_ERROR_BADOP;
1483 /* if an error is returned, we're supposed to send an error packet,
1484 * otherwise the dispatched function already did the data sending.
1485 * We give dispatched proc the responsibility since it knows how much
1486 * space to allocate.
1489 smb_SendTran2Error(vcp, asp, outp, code);
1492 /* free the input tran 2 packet */
1493 smb_FreeTran2Packet(asp);
1495 else if (firstPacket) {
1496 /* the first packet in a multi-packet request, we need to send an
1497 * ack to get more data.
1499 smb_SetSMBDataLength(outp, 0);
1500 smb_SendPacket(vcp, outp);
1506 /* ANSI versions. */
1508 #pragma pack(push, 1)
1510 typedef struct smb_rap_share_info_0 {
1511 BYTE shi0_netname[13];
1512 } smb_rap_share_info_0_t;
1514 typedef struct smb_rap_share_info_1 {
1515 BYTE shi1_netname[13];
1518 DWORD shi1_remark; /* char *shi1_remark; data offset */
1519 } smb_rap_share_info_1_t;
1521 typedef struct smb_rap_share_info_2 {
1522 BYTE shi2_netname[13];
1525 DWORD shi2_remark; /* char *shi2_remark; data offset */
1526 WORD shi2_permissions;
1528 WORD shi2_current_uses;
1529 DWORD shi2_path; /* char *shi2_path; data offset */
1530 WORD shi2_passwd[9];
1532 } smb_rap_share_info_2_t;
1534 #define SMB_RAP_MAX_SHARES 512
1536 typedef struct smb_rap_share_list {
1539 smb_rap_share_info_0_t * shares;
1540 } smb_rap_share_list_t;
1544 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1545 smb_rap_share_list_t * sp;
1547 if (dep->name[0] == '.' && (!dep->name[1] || (dep->name[1] == '.' && !dep->name[2])))
1548 return 0; /* skip over '.' and '..' */
1550 sp = (smb_rap_share_list_t *) vrockp;
1552 strncpy(sp->shares[sp->cShare].shi0_netname, dep->name, 12);
1553 sp->shares[sp->cShare].shi0_netname[12] = 0;
1557 if (sp->cShare >= sp->maxShares)
1558 return CM_ERROR_STOPNOW;
1563 /* RAP NetShareEnumRequest */
1564 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1566 smb_tran2Packet_t *outp;
1567 unsigned short * tp;
1571 int outParmsTotal; /* total parameter bytes */
1572 int outDataTotal; /* total data bytes */
1575 DWORD allSubmount = 0;
1577 DWORD nRegShares = 0;
1578 DWORD nSharesRet = 0;
1580 HKEY hkSubmount = NULL;
1581 smb_rap_share_info_1_t * shares;
1584 clientchar_t thisShare[AFSPATHMAX];
1588 smb_rap_share_list_t rootShares;
1593 tp = p->parmsp + 1; /* skip over function number (always 0) */
1596 clientchar_t * cdescp;
1598 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1599 if (cm_ClientStrCmp(cdescp, _C("WrLeh")))
1600 return CM_ERROR_INVAL;
1601 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1602 if (cm_ClientStrCmp(cdescp, _C("B13BWz")))
1603 return CM_ERROR_INVAL;
1609 if (infoLevel != 1) {
1610 return CM_ERROR_INVAL;
1613 /* We are supposed to use the same ASCII data structure even if
1614 Unicode is negotiated, which ultimately means that the share
1615 names that we return must be at most 13 characters in length,
1616 including the NULL terminator.
1618 The RAP specification states that shares with names longer than
1619 12 characters should not be included in the enumeration.
1620 However, since we support prefix cell references and since many
1621 cell names are going to exceed 12 characters, we lie and send
1622 the first 12 characters.
1625 /* first figure out how many shares there are */
1626 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1627 KEY_QUERY_VALUE, &hkParam);
1628 if (rv == ERROR_SUCCESS) {
1629 len = sizeof(allSubmount);
1630 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1631 (BYTE *) &allSubmount, &len);
1632 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1635 RegCloseKey (hkParam);
1638 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1639 0, KEY_QUERY_VALUE, &hkSubmount);
1640 if (rv == ERROR_SUCCESS) {
1641 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1642 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1643 if (rv != ERROR_SUCCESS)
1649 /* fetch the root shares */
1650 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1651 rootShares.cShare = 0;
1652 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1656 userp = smb_GetTran2User(vcp,p);
1658 thyper.HighPart = 0;
1661 cm_HoldSCache(cm_data.rootSCachep);
1662 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1663 cm_ReleaseSCache(cm_data.rootSCachep);
1665 cm_ReleaseUser(userp);
1667 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1669 #define REMARK_LEN 1
1670 outParmsTotal = 8; /* 4 dwords */
1671 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1672 if(outDataTotal > bufsize) {
1673 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1674 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1677 nSharesRet = nShares;
1680 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1682 /* now for the submounts */
1683 shares = (smb_rap_share_info_1_t *) outp->datap;
1684 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1686 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1689 StringCchCopyA(shares[cshare].shi1_netname,
1690 lengthof(shares[cshare].shi1_netname), "all" );
1691 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1692 /* type and pad are zero already */
1698 for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
1699 len = sizeof(thisShare);
1700 rv = RegEnumValueW(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
1701 if (rv == ERROR_SUCCESS &&
1702 cm_ClientStrLen(thisShare) &&
1703 (!allSubmount || cm_ClientStrCmpI(thisShare,_C("all")))) {
1704 cm_ClientStringToUtf8(thisShare, -1, shares[cshare].shi1_netname,
1705 lengthof( shares[cshare].shi1_netname ));
1706 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1707 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1712 nShares--; /* uncount key */
1715 RegCloseKey(hkSubmount);
1718 nonrootShares = cshare;
1720 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1721 /* in case there are collisions with submounts, submounts have
1723 for (j=0; j < nonrootShares; j++)
1724 if (!cm_stricmp_utf8(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1727 if (j < nonrootShares) {
1728 nShares--; /* uncount */
1732 StringCchCopyA(shares[cshare].shi1_netname, lengthof(shares[cshare].shi1_netname),
1733 rootShares.shares[i].shi0_netname);
1734 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1739 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1740 outp->parmsp[1] = 0;
1741 outp->parmsp[2] = cshare;
1742 outp->parmsp[3] = nShares;
1744 outp->totalData = (int)(cstrp - outp->datap);
1745 outp->totalParms = outParmsTotal;
1747 smb_SendTran2Packet(vcp, outp, op);
1748 smb_FreeTran2Packet(outp);
1750 free(rootShares.shares);
1755 /* RAP NetShareGetInfo */
1756 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1758 smb_tran2Packet_t *outp;
1759 unsigned short * tp;
1760 clientchar_t * shareName;
1761 BOOL shareFound = FALSE;
1762 unsigned short infoLevel;
1763 unsigned short bufsize;
1772 cm_scache_t *scp = NULL;
1778 tp = p->parmsp + 1; /* skip over function number (always 1) */
1781 clientchar_t * cdescp;
1783 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1784 if (cm_ClientStrCmp(cdescp, _C("zWrLh")))
1786 return CM_ERROR_INVAL;
1788 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1789 if (cm_ClientStrCmp(cdescp, _C("B13")) &&
1790 cm_ClientStrCmp(cdescp, _C("B13BWz")) &&
1791 cm_ClientStrCmp(cdescp, _C("B13BWzWWWzB9B")))
1793 return CM_ERROR_INVAL;
1795 shareName = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1803 totalData = sizeof(smb_rap_share_info_0_t);
1804 else if(infoLevel == SMB_INFO_STANDARD)
1805 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1806 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1807 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1809 return CM_ERROR_INVAL;
1811 if(!cm_ClientStrCmpI(shareName, _C("all")) || !cm_ClientStrCmp(shareName,_C("*."))) {
1812 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1813 KEY_QUERY_VALUE, &hkParam);
1814 if (rv == ERROR_SUCCESS) {
1815 len = sizeof(allSubmount);
1816 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1817 (BYTE *) &allSubmount, &len);
1818 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1821 RegCloseKey (hkParam);
1828 userp = smb_GetTran2User(vcp, p);
1830 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
1831 return CM_ERROR_BADSMB;
1833 code = cm_NameI(cm_data.rootSCachep, shareName,
1834 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
1835 userp, NULL, &req, &scp);
1837 cm_ReleaseSCache(scp);
1840 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1841 KEY_QUERY_VALUE, &hkSubmount);
1842 if (rv == ERROR_SUCCESS) {
1843 rv = RegQueryValueExW(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1844 if (rv == ERROR_SUCCESS) {
1847 RegCloseKey(hkSubmount);
1853 return CM_ERROR_BADSHARENAME;
1855 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1856 memset(outp->datap, 0, totalData);
1858 outp->parmsp[0] = 0;
1859 outp->parmsp[1] = 0;
1860 outp->parmsp[2] = totalData;
1862 if (infoLevel == 0) {
1863 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1864 cm_ClientStringToUtf8(shareName, -1, info->shi0_netname,
1865 lengthof(info->shi0_netname));
1866 } else if(infoLevel == SMB_INFO_STANDARD) {
1867 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1868 cm_ClientStringToUtf8(shareName, -1, info->shi1_netname, lengthof(info->shi1_netname));
1869 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1870 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1871 /* type and pad are already zero */
1872 } else { /* infoLevel==2 */
1873 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1874 cm_ClientStringToUtf8(shareName, -1, info->shi2_netname, lengthof(info->shi2_netname));
1875 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1876 info->shi2_permissions = ACCESS_ALL;
1877 info->shi2_max_uses = (unsigned short) -1;
1878 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
1881 outp->totalData = totalData;
1882 outp->totalParms = totalParam;
1884 smb_SendTran2Packet(vcp, outp, op);
1885 smb_FreeTran2Packet(outp);
1890 #pragma pack(push, 1)
1892 typedef struct smb_rap_wksta_info_10 {
1893 DWORD wki10_computername; /*char *wki10_computername;*/
1894 DWORD wki10_username; /* char *wki10_username; */
1895 DWORD wki10_langroup; /* char *wki10_langroup;*/
1896 BYTE wki10_ver_major;
1897 BYTE wki10_ver_minor;
1898 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1899 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1900 } smb_rap_wksta_info_10_t;
1904 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1906 smb_tran2Packet_t *outp;
1910 unsigned short * tp;
1913 smb_rap_wksta_info_10_t * info;
1917 tp = p->parmsp + 1; /* Skip over function number */
1920 clientchar_t * cdescp;
1922 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
1923 SMB_STRF_FORCEASCII);
1924 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
1925 return CM_ERROR_INVAL;
1927 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
1928 SMB_STRF_FORCEASCII);
1929 if (cm_ClientStrCmp(cdescp, _C("zzzBBzz")))
1930 return CM_ERROR_INVAL;
1936 if (infoLevel != 10) {
1937 return CM_ERROR_INVAL;
1943 totalData = sizeof(*info) + /* info */
1944 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1945 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1946 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1947 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1948 1; /* wki10_oth_domains (null)*/
1950 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1952 memset(outp->parmsp,0,totalParams);
1953 memset(outp->datap,0,totalData);
1955 info = (smb_rap_wksta_info_10_t *) outp->datap;
1956 cstrp = (char *) (info + 1);
1958 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1959 StringCbCopyA(cstrp, totalData, smb_localNamep);
1960 cstrp += strlen(cstrp) + 1;
1962 info->wki10_username = (DWORD) (cstrp - outp->datap);
1963 uidp = smb_FindUID(vcp, p->uid, 0);
1965 lock_ObtainMutex(&uidp->mx);
1966 if(uidp->unp && uidp->unp->name)
1967 cm_ClientStringToUtf8(uidp->unp->name, -1,
1968 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
1969 lock_ReleaseMutex(&uidp->mx);
1970 smb_ReleaseUID(uidp);
1972 cstrp += strlen(cstrp) + 1;
1974 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1975 StringCbCopyA(cstrp, totalData - (cstrp - outp->datap)*sizeof(char), "WORKGROUP");
1976 cstrp += strlen(cstrp) + 1;
1978 /* TODO: Not sure what values these should take, but these work */
1979 info->wki10_ver_major = 5;
1980 info->wki10_ver_minor = 1;
1982 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1983 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
1984 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
1985 cstrp += strlen(cstrp) + 1;
1987 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1988 cstrp ++; /* no other domains */
1990 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1991 outp->parmsp[2] = outp->totalData;
1992 outp->totalParms = totalParams;
1994 smb_SendTran2Packet(vcp,outp,op);
1995 smb_FreeTran2Packet(outp);
2000 #pragma pack(push, 1)
2002 typedef struct smb_rap_server_info_0 {
2004 } smb_rap_server_info_0_t;
2006 typedef struct smb_rap_server_info_1 {
2008 BYTE sv1_version_major;
2009 BYTE sv1_version_minor;
2011 DWORD sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
2012 } smb_rap_server_info_1_t;
2016 char smb_ServerComment[] = "OpenAFS Client";
2017 int smb_ServerCommentLen = sizeof(smb_ServerComment);
2019 #define SMB_SV_TYPE_SERVER 0x00000002L
2020 #define SMB_SV_TYPE_NT 0x00001000L
2021 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
2023 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2025 smb_tran2Packet_t *outp;
2029 unsigned short * tp;
2032 smb_rap_server_info_0_t * info0;
2033 smb_rap_server_info_1_t * info1;
2036 tp = p->parmsp + 1; /* Skip over function number */
2039 clientchar_t * cdescp;
2041 cdescp = smb_ParseStringT2Parm(p, (unsigned char *) tp, (char **) &tp,
2042 SMB_STRF_FORCEASCII);
2043 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2044 return CM_ERROR_INVAL;
2045 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2046 SMB_STRF_FORCEASCII);
2047 if (cm_ClientStrCmp(cdescp, _C("B16")) ||
2048 cm_ClientStrCmp(cdescp, _C("B16BBDz")))
2049 return CM_ERROR_INVAL;
2055 if (infoLevel != 0 && infoLevel != 1) {
2056 return CM_ERROR_INVAL;
2062 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
2063 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
2065 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2067 memset(outp->parmsp,0,totalParams);
2068 memset(outp->datap,0,totalData);
2070 if (infoLevel == 0) {
2071 info0 = (smb_rap_server_info_0_t *) outp->datap;
2072 cstrp = (char *) (info0 + 1);
2073 StringCchCopyA(info0->sv0_name, lengthof(info0->sv0_name), "AFS");
2074 } else { /* infoLevel == SMB_INFO_STANDARD */
2075 info1 = (smb_rap_server_info_1_t *) outp->datap;
2076 cstrp = (char *) (info1 + 1);
2077 StringCchCopyA(info1->sv1_name, lengthof(info1->sv1_name), "AFS");
2080 SMB_SV_TYPE_SERVER |
2082 SMB_SV_TYPE_SERVER_NT;
2084 info1->sv1_version_major = 5;
2085 info1->sv1_version_minor = 1;
2086 info1->sv1_comment_or_master_browser = (DWORD) (cstrp - outp->datap);
2088 StringCbCopyA(cstrp, smb_ServerCommentLen, smb_ServerComment);
2090 cstrp += smb_ServerCommentLen / sizeof(char);
2093 totalData = (DWORD)(cstrp - outp->datap);
2094 outp->totalData = min(bufsize,totalData); /* actual data size */
2095 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
2096 outp->parmsp[2] = totalData;
2097 outp->totalParms = totalParams;
2099 smb_SendTran2Packet(vcp,outp,op);
2100 smb_FreeTran2Packet(outp);
2105 /* SMB_COM_TRANSACTION2 and SMB_COM_TRANSACTION2_SECONDARY */
2106 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2108 smb_tran2Packet_t *asp;
2120 /* We sometimes see 0 word count. What to do? */
2121 if (*inp->wctp == 0) {
2122 osi_Log0(smb_logp, "Transaction2 word count = 0");
2123 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
2125 smb_SetSMBDataLength(outp, 0);
2126 smb_SendPacket(vcp, outp);
2130 totalParms = smb_GetSMBParm(inp, 0);
2131 totalData = smb_GetSMBParm(inp, 1);
2133 firstPacket = (inp->inCom == 0x32);
2135 /* find the packet we're reassembling */
2136 lock_ObtainWrite(&smb_globalLock);
2137 asp = smb_FindTran2Packet(vcp, inp);
2139 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
2141 lock_ReleaseWrite(&smb_globalLock);
2143 /* now merge in this latest packet; start by looking up offsets */
2145 parmDisp = dataDisp = 0;
2146 parmOffset = smb_GetSMBParm(inp, 10);
2147 dataOffset = smb_GetSMBParm(inp, 12);
2148 parmCount = smb_GetSMBParm(inp, 9);
2149 dataCount = smb_GetSMBParm(inp, 11);
2150 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2151 asp->maxReturnData = smb_GetSMBParm(inp, 3);
2153 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2154 totalData, dataCount, asp->maxReturnData);
2157 parmDisp = smb_GetSMBParm(inp, 4);
2158 parmOffset = smb_GetSMBParm(inp, 3);
2159 dataDisp = smb_GetSMBParm(inp, 7);
2160 dataOffset = smb_GetSMBParm(inp, 6);
2161 parmCount = smb_GetSMBParm(inp, 2);
2162 dataCount = smb_GetSMBParm(inp, 5);
2164 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2165 parmCount, dataCount);
2168 /* now copy the parms and data */
2169 if ( asp->totalParms > 0 && parmCount != 0 )
2171 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2173 if ( asp->totalData > 0 && dataCount != 0 ) {
2174 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2177 /* account for new bytes */
2178 asp->curData += dataCount;
2179 asp->curParms += parmCount;
2181 /* finally, if we're done, remove the packet from the queue and dispatch it */
2182 if (asp->totalParms > 0 &&
2183 asp->curParms > 0 &&
2184 asp->totalData <= asp->curData &&
2185 asp->totalParms <= asp->curParms) {
2186 /* we've received it all */
2187 lock_ObtainWrite(&smb_globalLock);
2188 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2189 lock_ReleaseWrite(&smb_globalLock);
2191 /* now dispatch it */
2192 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2193 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2194 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2197 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2198 code = CM_ERROR_BADOP;
2201 /* if an error is returned, we're supposed to send an error packet,
2202 * otherwise the dispatched function already did the data sending.
2203 * We give dispatched proc the responsibility since it knows how much
2204 * space to allocate.
2207 smb_SendTran2Error(vcp, asp, outp, code);
2210 /* free the input tran 2 packet */
2211 smb_FreeTran2Packet(asp);
2213 else if (firstPacket) {
2214 /* the first packet in a multi-packet request, we need to send an
2215 * ack to get more data.
2217 smb_SetSMBDataLength(outp, 0);
2218 smb_SendPacket(vcp, outp);
2225 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2227 clientchar_t *pathp;
2228 smb_tran2Packet_t *outp;
2233 cm_scache_t *dscp; /* dir we're dealing with */
2234 cm_scache_t *scp; /* file we're creating */
2236 int initialModeBits;
2239 clientchar_t *lastNamep;
2246 int parmSlot; /* which parm we're dealing with */
2247 long returnEALength;
2248 clientchar_t *tidPathp;
2256 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2257 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2259 openFun = p->parmsp[6]; /* open function */
2260 excl = ((openFun & 3) == 0);
2261 trunc = ((openFun & 3) == 2); /* truncate it */
2262 openMode = (p->parmsp[1] & 0x7);
2263 openAction = 0; /* tracks what we did */
2265 attributes = p->parmsp[3];
2266 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2268 /* compute initial mode bits based on read-only flag in attributes */
2269 initialModeBits = 0666;
2270 if (attributes & SMB_ATTR_READONLY)
2271 initialModeBits &= ~0222;
2273 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
2276 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2278 spacep = cm_GetSpace();
2279 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2282 (cm_ClientStrCmpI(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
2283 cm_ClientStrCmpI(lastNamep, _C("\\srvsvc")) == 0 ||
2284 cm_ClientStrCmpI(lastNamep, _C("\\wkssvc")) == 0 ||
2285 cm_ClientStrCmpI(lastNamep, _C("\\ipc$")) == 0)) {
2286 /* special case magic file name for receiving IOCTL requests
2287 * (since IOCTL calls themselves aren't getting through).
2289 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2290 smb_SetupIoctlFid(fidp, spacep);
2292 /* copy out remainder of the parms */
2294 outp->parmsp[parmSlot++] = fidp->fid;
2296 outp->parmsp[parmSlot++] = 0; /* attrs */
2297 outp->parmsp[parmSlot++] = 0; /* mod time */
2298 outp->parmsp[parmSlot++] = 0;
2299 outp->parmsp[parmSlot++] = 0; /* len */
2300 outp->parmsp[parmSlot++] = 0x7fff;
2301 outp->parmsp[parmSlot++] = openMode;
2302 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2303 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2305 /* and the final "always present" stuff */
2306 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2307 /* next write out the "unique" ID */
2308 outp->parmsp[parmSlot++] = 0x1234;
2309 outp->parmsp[parmSlot++] = 0x5678;
2310 outp->parmsp[parmSlot++] = 0;
2311 if (returnEALength) {
2312 outp->parmsp[parmSlot++] = 0;
2313 outp->parmsp[parmSlot++] = 0;
2316 outp->totalData = 0;
2317 outp->totalParms = parmSlot * 2;
2319 smb_SendTran2Packet(vcp, outp, op);
2321 smb_FreeTran2Packet(outp);
2323 /* and clean up fid reference */
2324 smb_ReleaseFID(fidp);
2328 #ifdef DEBUG_VERBOSE
2330 char *hexp, *asciip;
2331 asciip = (lastNamep ? lastNamep : pathp);
2332 hexp = osi_HexifyString( asciip );
2333 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2338 userp = smb_GetTran2User(vcp, p);
2339 /* In the off chance that userp is NULL, we log and abandon */
2341 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2342 smb_FreeTran2Packet(outp);
2343 return CM_ERROR_BADSMB;
2346 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2347 if (code == CM_ERROR_TIDIPC) {
2348 /* Attempt to use a TID allocated for IPC. The client
2349 * is probably looking for DCE RPC end points which we
2350 * don't support OR it could be looking to make a DFS
2353 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2355 cm_ReleaseUser(userp);
2356 smb_FreeTran2Packet(outp);
2357 return CM_ERROR_NOSUCHPATH;
2362 code = cm_NameI(cm_data.rootSCachep, pathp,
2363 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2364 userp, tidPathp, &req, &scp);
2366 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2367 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2368 userp, tidPathp, &req, &dscp);
2369 cm_FreeSpace(spacep);
2372 cm_ReleaseUser(userp);
2373 smb_FreeTran2Packet(outp);
2378 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2379 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2380 (clientchar_t*) spacep->data);
2381 cm_ReleaseSCache(dscp);
2382 cm_ReleaseUser(userp);
2383 smb_FreeTran2Packet(outp);
2384 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2385 return CM_ERROR_PATH_NOT_COVERED;
2387 return CM_ERROR_BADSHARENAME;
2389 #endif /* DFS_SUPPORT */
2391 /* otherwise, scp points to the parent directory. Do a lookup,
2392 * and truncate the file if we find it, otherwise we create the
2399 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2401 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2402 cm_ReleaseSCache(dscp);
2403 cm_ReleaseUser(userp);
2404 smb_FreeTran2Packet(outp);
2409 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2410 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2411 cm_ReleaseSCache(scp);
2412 cm_ReleaseUser(userp);
2413 smb_FreeTran2Packet(outp);
2414 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2415 return CM_ERROR_PATH_NOT_COVERED;
2417 return CM_ERROR_BADSHARENAME;
2419 #endif /* DFS_SUPPORT */
2421 /* macintosh is expensive to program for it */
2422 cm_FreeSpace(spacep);
2425 /* if we get here, if code is 0, the file exists and is represented by
2426 * scp. Otherwise, we have to create it.
2429 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2432 cm_ReleaseSCache(dscp);
2433 cm_ReleaseSCache(scp);
2434 cm_ReleaseUser(userp);
2435 smb_FreeTran2Packet(outp);
2440 /* oops, file shouldn't be there */
2442 cm_ReleaseSCache(dscp);
2443 cm_ReleaseSCache(scp);
2444 cm_ReleaseUser(userp);
2445 smb_FreeTran2Packet(outp);
2446 return CM_ERROR_EXISTS;
2450 setAttr.mask = CM_ATTRMASK_LENGTH;
2451 setAttr.length.LowPart = 0;
2452 setAttr.length.HighPart = 0;
2453 code = cm_SetAttr(scp, &setAttr, userp, &req);
2454 openAction = 3; /* truncated existing file */
2457 openAction = 1; /* found existing file */
2459 else if (!(openFun & 0x10)) {
2460 /* don't create if not found */
2462 cm_ReleaseSCache(dscp);
2463 osi_assertx(scp == NULL, "null cm_scache_t");
2464 cm_ReleaseUser(userp);
2465 smb_FreeTran2Packet(outp);
2466 return CM_ERROR_NOSUCHFILE;
2469 osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2470 openAction = 2; /* created file */
2471 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2472 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2473 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2477 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2478 smb_NotifyChange(FILE_ACTION_ADDED,
2479 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2480 dscp, lastNamep, NULL, TRUE);
2481 } else if (!excl && code == CM_ERROR_EXISTS) {
2482 /* not an exclusive create, and someone else tried
2483 * creating it already, then we open it anyway. We
2484 * don't bother retrying after this, since if this next
2485 * fails, that means that the file was deleted after we
2486 * started this call.
2488 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2492 setAttr.mask = CM_ATTRMASK_LENGTH;
2493 setAttr.length.LowPart = 0;
2494 setAttr.length.HighPart = 0;
2495 code = cm_SetAttr(scp, &setAttr, userp,
2498 } /* lookup succeeded */
2502 /* we don't need this any longer */
2504 cm_ReleaseSCache(dscp);
2507 /* something went wrong creating or truncating the file */
2509 cm_ReleaseSCache(scp);
2510 cm_ReleaseUser(userp);
2511 smb_FreeTran2Packet(outp);
2515 /* make sure we're about to open a file */
2516 if (scp->fileType != CM_SCACHETYPE_FILE) {
2518 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2519 cm_scache_t * targetScp = 0;
2520 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2522 /* we have a more accurate file to use (the
2523 * target of the symbolic link). Otherwise,
2524 * we'll just use the symlink anyway.
2526 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2528 cm_ReleaseSCache(scp);
2532 if (scp->fileType != CM_SCACHETYPE_FILE) {
2533 cm_ReleaseSCache(scp);
2534 cm_ReleaseUser(userp);
2535 smb_FreeTran2Packet(outp);
2536 return CM_ERROR_ISDIR;
2540 /* now all we have to do is open the file itself */
2541 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2542 osi_assertx(fidp, "null smb_fid_t");
2545 lock_ObtainMutex(&fidp->mx);
2546 /* save a pointer to the vnode */
2547 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2549 lock_ObtainWrite(&scp->rw);
2550 scp->flags |= CM_SCACHEFLAG_SMB_FID;
2551 lock_ReleaseWrite(&scp->rw);
2554 fidp->userp = userp;
2556 /* compute open mode */
2558 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
2559 if (openMode == 1 || openMode == 2)
2560 fidp->flags |= SMB_FID_OPENWRITE;
2562 /* remember that the file was newly created */
2564 fidp->flags |= SMB_FID_CREATED;
2566 lock_ReleaseMutex(&fidp->mx);
2568 smb_ReleaseFID(fidp);
2570 cm_Open(scp, 0, userp);
2572 /* copy out remainder of the parms */
2574 outp->parmsp[parmSlot++] = fidp->fid;
2575 lock_ObtainRead(&scp->rw);
2577 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2578 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2579 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2580 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2581 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2582 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2583 outp->parmsp[parmSlot++] = openMode;
2584 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2585 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2587 /* and the final "always present" stuff */
2588 outp->parmsp[parmSlot++] = openAction;
2589 /* next write out the "unique" ID */
2590 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2591 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2592 outp->parmsp[parmSlot++] = 0;
2593 if (returnEALength) {
2594 outp->parmsp[parmSlot++] = 0;
2595 outp->parmsp[parmSlot++] = 0;
2597 lock_ReleaseRead(&scp->rw);
2598 outp->totalData = 0; /* total # of data bytes */
2599 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2601 smb_SendTran2Packet(vcp, outp, op);
2603 smb_FreeTran2Packet(outp);
2605 cm_ReleaseUser(userp);
2606 /* leave scp held since we put it in fidp->scp */
2610 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2613 unsigned short infolevel;
2615 infolevel = p->parmsp[0];
2617 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2619 return CM_ERROR_BAD_LEVEL;
2622 /* TRANS2_QUERY_FS_INFORMATION */
2623 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2625 smb_tran2Packet_t *outp;
2626 smb_tran2QFSInfo_t qi;
2630 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2632 switch (p->parmsp[0]) {
2633 case SMB_INFO_ALLOCATION:
2635 responseSize = sizeof(qi.u.allocInfo);
2637 qi.u.allocInfo.FSID = 0;
2638 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2639 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2640 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2641 qi.u.allocInfo.bytesPerSector = 1024;
2644 case SMB_INFO_VOLUME:
2646 qi.u.volumeInfo.vsn = 1234; /* Volume serial number */
2647 qi.u.volumeInfo.vnCount = 4; /* Number of characters in label (AFS\0)*/
2649 /* we're supposed to pad it out with zeroes to the end */
2650 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2651 smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
2653 responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
2656 case SMB_QUERY_FS_VOLUME_INFO:
2657 /* FS volume info */
2658 responseSize = sizeof(qi.u.FSvolumeInfo);
2661 FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
2662 memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
2665 qi.u.FSvolumeInfo.vsn = 1234;
2666 qi.u.FSvolumeInfo.vnCount = 8; /* This is always in Unicode */
2667 memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
2670 case SMB_QUERY_FS_SIZE_INFO:
2672 responseSize = sizeof(qi.u.FSsizeInfo);
2674 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2675 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2676 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2677 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2678 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2679 qi.u.FSsizeInfo.bytesPerSector = 1024;
2682 case SMB_QUERY_FS_DEVICE_INFO:
2683 /* FS device info */
2684 responseSize = sizeof(qi.u.FSdeviceInfo);
2686 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2687 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2690 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2691 /* FS attribute info */
2693 /* attributes, defined in WINNT.H:
2694 * FILE_CASE_SENSITIVE_SEARCH 0x1
2695 * FILE_CASE_PRESERVED_NAMES 0x2
2696 * FILE_VOLUME_QUOTAS 0x10
2697 * <no name defined> 0x4000
2698 * If bit 0x4000 is not set, Windows 95 thinks
2699 * we can't handle long (non-8.3) names,
2700 * despite our protestations to the contrary.
2702 qi.u.FSattributeInfo.attributes = 0x4003;
2703 /* The maxCompLength is supposed to be in bytes */
2705 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2706 qi.u.FSattributeInfo.maxCompLength = MAX_PATH * sizeof(wchar_t);
2709 qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
2713 smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, 0);
2714 qi.u.FSattributeInfo.FSnameLength = sz;
2717 sizeof(qi.u.FSattributeInfo.attributes) +
2718 sizeof(qi.u.FSattributeInfo.maxCompLength) +
2719 sizeof(qi.u.FSattributeInfo.FSnameLength) +
2724 case SMB_INFO_UNIX: /* CIFS Unix Info */
2725 case SMB_INFO_MACOS: /* Mac FS Info */
2727 return CM_ERROR_BADOP;
2730 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2732 /* copy out return data, and set corresponding sizes */
2733 outp->totalParms = 0;
2734 outp->totalData = responseSize;
2735 memcpy(outp->datap, &qi, responseSize);
2737 /* send and free the packets */
2738 smb_SendTran2Packet(vcp, outp, op);
2739 smb_FreeTran2Packet(outp);
2744 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2746 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2747 return CM_ERROR_BADOP;
2750 struct smb_ShortNameRock {
2751 clientchar_t *maskp;
2753 clientchar_t *shortName;
2754 size_t shortNameLen;
2757 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2760 struct smb_ShortNameRock *rockp;
2761 normchar_t normName[MAX_PATH];
2762 clientchar_t *shortNameEnd;
2766 cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t));
2768 /* compare both names and vnodes, though probably just comparing vnodes
2769 * would be safe enough.
2771 if (cm_NormStrCmpI(normName, rockp->maskp) != 0)
2773 if (ntohl(dep->fid.vnode) != rockp->vnode)
2776 /* This is the entry */
2777 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2778 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2780 return CM_ERROR_STOPNOW;
2783 long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
2784 clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
2786 struct smb_ShortNameRock rock;
2787 clientchar_t *lastNamep;
2790 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2794 spacep = cm_GetSpace();
2795 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2797 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2798 caseFold, userp, tidPathp,
2800 cm_FreeSpace(spacep);
2805 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2806 cm_ReleaseSCache(dscp);
2807 cm_ReleaseUser(userp);
2811 return CM_ERROR_PATH_NOT_COVERED;
2813 #endif /* DFS_SUPPORT */
2815 if (!lastNamep) lastNamep = pathp;
2818 thyper.HighPart = 0;
2819 rock.shortName = shortName;
2821 rock.maskp = lastNamep;
2822 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2824 cm_ReleaseSCache(dscp);
2827 return CM_ERROR_NOSUCHFILE;
2828 if (code == CM_ERROR_STOPNOW) {
2829 *shortNameLenp = rock.shortNameLen;
2835 /* TRANS2_QUERY_PATH_INFORMATION */
2836 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2838 smb_tran2Packet_t *outp;
2841 unsigned short infoLevel;
2842 smb_tran2QPathInfo_t qpi;
2844 unsigned short attributes;
2845 unsigned long extAttributes;
2846 clientchar_t shortName[13];
2850 cm_scache_t *scp, *dscp;
2851 int scp_mx_held = 0;
2854 clientchar_t *pathp;
2855 clientchar_t *tidPathp;
2856 clientchar_t *lastComp;
2861 infoLevel = p->parmsp[0];
2862 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2864 else if (infoLevel == SMB_INFO_STANDARD)
2865 responseSize = sizeof(qpi.u.QPstandardInfo);
2866 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2867 responseSize = sizeof(qpi.u.QPeaSizeInfo);
2868 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2869 responseSize = sizeof(qpi.u.QPfileBasicInfo);
2870 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2871 responseSize = sizeof(qpi.u.QPfileStandardInfo);
2872 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2873 responseSize = sizeof(qpi.u.QPfileEaInfo);
2874 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2875 responseSize = sizeof(qpi.u.QPfileNameInfo);
2876 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
2877 responseSize = sizeof(qpi.u.QPfileAllInfo);
2878 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2879 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2881 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2882 p->opcode, infoLevel);
2883 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
2887 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
2888 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %S", infoLevel,
2889 osi_LogSaveClientString(smb_logp, pathp));
2891 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2893 if (infoLevel > 0x100)
2894 outp->totalParms = 2;
2896 outp->totalParms = 0;
2897 outp->totalData = responseSize;
2899 /* now, if we're at infoLevel 6, we're only being asked to check
2900 * the syntax, so we just OK things now. In particular, we're *not*
2901 * being asked to verify anything about the state of any parent dirs.
2903 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2904 smb_SendTran2Packet(vcp, outp, opx);
2905 smb_FreeTran2Packet(outp);
2909 userp = smb_GetTran2User(vcp, p);
2911 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2912 smb_FreeTran2Packet(outp);
2913 return CM_ERROR_BADSMB;
2916 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2918 cm_ReleaseUser(userp);
2919 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2920 smb_FreeTran2Packet(outp);
2925 * XXX Strange hack XXX
2927 * As of Patch 7 (13 January 98), we are having the following problem:
2928 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2929 * requests to look up "desktop.ini" in all the subdirectories.
2930 * This can cause zillions of timeouts looking up non-existent cells
2931 * and volumes, especially in the top-level directory.
2933 * We have not found any way to avoid this or work around it except
2934 * to explicitly ignore the requests for mount points that haven't
2935 * yet been evaluated and for directories that haven't yet been
2938 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2939 spacep = cm_GetSpace();
2940 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
2941 #ifndef SPECIAL_FOLDERS
2942 /* Make sure that lastComp is not NULL */
2944 if (cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
2945 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2949 userp, tidPathp, &req, &dscp);
2952 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2953 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2955 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2956 code = CM_ERROR_PATH_NOT_COVERED;
2958 code = CM_ERROR_BADSHARENAME;
2960 #endif /* DFS_SUPPORT */
2961 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2962 code = CM_ERROR_NOSUCHFILE;
2963 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2964 cm_buf_t *bp = buf_Find(dscp, &hzero);
2970 code = CM_ERROR_NOSUCHFILE;
2972 cm_ReleaseSCache(dscp);
2974 cm_FreeSpace(spacep);
2975 cm_ReleaseUser(userp);
2976 smb_SendTran2Error(vcp, p, opx, code);
2977 smb_FreeTran2Packet(outp);
2983 #endif /* SPECIAL_FOLDERS */
2985 cm_FreeSpace(spacep);
2988 /* now do namei and stat, and copy out the info */
2989 code = cm_NameI(cm_data.rootSCachep, pathp,
2990 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2993 cm_ReleaseUser(userp);
2994 smb_SendTran2Error(vcp, p, opx, code);
2995 smb_FreeTran2Packet(outp);
3000 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3001 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3002 cm_ReleaseSCache(scp);
3003 cm_ReleaseUser(userp);
3004 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3005 code = CM_ERROR_PATH_NOT_COVERED;
3007 code = CM_ERROR_BADSHARENAME;
3008 smb_SendTran2Error(vcp, p, opx, code);
3009 smb_FreeTran2Packet(outp);
3012 #endif /* DFS_SUPPORT */
3014 lock_ObtainWrite(&scp->rw);
3016 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3017 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3018 if (code) goto done;
3020 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3022 lock_ConvertWToR(&scp->rw);
3026 /* now we have the status in the cache entry, and everything is locked.
3027 * Marshall the output data.
3029 /* for info level 108, figure out short name */
3030 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3031 code = cm_GetShortName(pathp, userp, &req,
3032 tidPathp, scp->fid.vnode, shortName,
3038 smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, 0);
3039 qpi.u.QPfileAltNameInfo.fileNameLength = len;
3043 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3044 smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, 0);
3045 qpi.u.QPfileNameInfo.fileNameLength = len;
3049 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3050 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3051 qpi.u.QPstandardInfo.creationDateTime = dosTime;
3052 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3053 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3054 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3055 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3056 attributes = smb_Attributes(scp);
3057 qpi.u.QPstandardInfo.attributes = attributes;
3058 qpi.u.QPstandardInfo.eaSize = 0;
3060 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3061 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3062 qpi.u.QPfileBasicInfo.creationTime = ft;
3063 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3064 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3065 qpi.u.QPfileBasicInfo.changeTime = ft;
3066 extAttributes = smb_ExtAttributes(scp);
3067 qpi.u.QPfileBasicInfo.attributes = extAttributes;
3068 qpi.u.QPfileBasicInfo.reserved = 0;
3070 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3071 smb_fid_t *fidp = smb_FindFIDByScache(vcp, scp);
3073 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3074 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3075 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3076 qpi.u.QPfileStandardInfo.directory =
3077 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3078 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3079 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3080 qpi.u.QPfileStandardInfo.reserved = 0;
3083 lock_ReleaseRead(&scp->rw);
3085 lock_ObtainMutex(&fidp->mx);
3086 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3087 lock_ReleaseMutex(&fidp->mx);
3088 smb_ReleaseFID(fidp);
3090 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3092 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3093 qpi.u.QPfileEaInfo.eaSize = 0;
3095 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3096 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3097 qpi.u.QPfileAllInfo.creationTime = ft;
3098 qpi.u.QPfileAllInfo.lastAccessTime = ft;
3099 qpi.u.QPfileAllInfo.lastWriteTime = ft;
3100 qpi.u.QPfileAllInfo.changeTime = ft;
3101 extAttributes = smb_ExtAttributes(scp);
3102 qpi.u.QPfileAllInfo.attributes = extAttributes;
3103 qpi.u.QPfileAllInfo.allocationSize = scp->length;
3104 qpi.u.QPfileAllInfo.endOfFile = scp->length;
3105 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3106 qpi.u.QPfileAllInfo.deletePending = 0;
3107 qpi.u.QPfileAllInfo.directory =
3108 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3109 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3110 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3111 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
3112 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
3113 qpi.u.QPfileAllInfo.eaSize = 0;
3114 qpi.u.QPfileAllInfo.accessFlags = 0;
3115 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
3116 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
3117 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3118 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3119 qpi.u.QPfileAllInfo.mode = 0;
3120 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3122 smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, 0);
3123 qpi.u.QPfileAllInfo.fileNameLength = len;
3126 /* send and free the packets */
3129 lock_ReleaseRead(&scp->rw);
3130 cm_ReleaseSCache(scp);
3131 cm_ReleaseUser(userp);
3133 memcpy(outp->datap, &qpi, responseSize);
3134 smb_SendTran2Packet(vcp, outp, opx);
3136 smb_SendTran2Error(vcp, p, opx, code);
3138 smb_FreeTran2Packet(outp);
3143 /* TRANS2_SET_PATH_INFORMATION */
3144 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3147 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
3148 return CM_ERROR_BADOP;
3152 unsigned short infoLevel;
3153 clientchar_t * pathp;
3154 smb_tran2Packet_t *outp;
3155 smb_tran2QPathInfo_t *spi;
3157 cm_scache_t *scp, *dscp;
3160 clientchar_t *tidPathp;
3161 clientchar_t *lastComp;
3165 infoLevel = p->parmsp[0];
3166 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
3167 if (infoLevel != SMB_INFO_STANDARD &&
3168 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
3169 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
3170 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3171 p->opcode, infoLevel);
3172 smb_SendTran2Error(vcp, p, opx,
3173 infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3177 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3179 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
3180 osi_LogSaveClientString(smb_logp, pathp));
3182 userp = smb_GetTran2User(vcp, p);
3184 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3185 code = CM_ERROR_BADSMB;
3189 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3190 if (code == CM_ERROR_TIDIPC) {
3191 /* Attempt to use a TID allocated for IPC. The client
3192 * is probably looking for DCE RPC end points which we
3193 * don't support OR it could be looking to make a DFS
3196 osi_Log0(smb_logp, "Tran2Open received IPC TID");
3197 cm_ReleaseUser(userp);
3198 return CM_ERROR_NOSUCHPATH;
3202 * XXX Strange hack XXX
3204 * As of Patch 7 (13 January 98), we are having the following problem:
3205 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3206 * requests to look up "desktop.ini" in all the subdirectories.
3207 * This can cause zillions of timeouts looking up non-existent cells
3208 * and volumes, especially in the top-level directory.
3210 * We have not found any way to avoid this or work around it except
3211 * to explicitly ignore the requests for mount points that haven't
3212 * yet been evaluated and for directories that haven't yet been
3215 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3216 spacep = cm_GetSpace();
3217 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3218 #ifndef SPECIAL_FOLDERS
3219 /* Make sure that lastComp is not NULL */
3221 if (cm_ClientStrCmpI(lastComp, _C("\\desktop.ini")) == 0) {
3222 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3226 userp, tidPathp, &req, &dscp);
3229 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3230 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3232 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3233 code = CM_ERROR_PATH_NOT_COVERED;
3235 code = CM_ERROR_BADSHARENAME;
3237 #endif /* DFS_SUPPORT */
3238 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3239 code = CM_ERROR_NOSUCHFILE;
3240 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3241 cm_buf_t *bp = buf_Find(dscp, &hzero);
3247 code = CM_ERROR_NOSUCHFILE;
3249 cm_ReleaseSCache(dscp);
3251 cm_FreeSpace(spacep);
3252 cm_ReleaseUser(userp);
3253 smb_SendTran2Error(vcp, p, opx, code);
3259 #endif /* SPECIAL_FOLDERS */
3261 cm_FreeSpace(spacep);
3264 /* now do namei and stat, and copy out the info */
3265 code = cm_NameI(cm_data.rootSCachep, pathp,
3266 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3268 cm_ReleaseUser(userp);
3269 smb_SendTran2Error(vcp, p, opx, code);
3273 fidp = smb_FindFIDByScache(vcp, scp);
3275 cm_ReleaseSCache(scp);
3276 cm_ReleaseUser(userp);
3277 smb_SendTran2Error(vcp, p, opx, code);
3281 lock_ObtainMutex(&fidp->mx);
3282 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
3283 lock_ReleaseMutex(&fidp->mx);
3284 cm_ReleaseSCache(scp);
3285 smb_ReleaseFID(fidp);
3286 cm_ReleaseUser(userp);
3287 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3290 lock_ReleaseMutex(&fidp->mx);
3292 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3294 outp->totalParms = 2;
3295 outp->totalData = 0;
3297 spi = (smb_tran2QPathInfo_t *)p->datap;
3298 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3301 /* lock the vnode with a callback; we need the current status
3302 * to determine what the new status is, in some cases.
3304 lock_ObtainWrite(&scp->rw);
3305 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3306 CM_SCACHESYNC_GETSTATUS
3307 | CM_SCACHESYNC_NEEDCALLBACK);
3309 lock_ReleaseWrite(&scp->rw);
3312 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3314 lock_ReleaseWrite(&scp->rw);
3315 lock_ObtainMutex(&fidp->mx);
3316 lock_ObtainRead(&scp->rw);
3318 /* prepare for setattr call */
3319 attr.mask = CM_ATTRMASK_LENGTH;
3320 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3321 attr.length.HighPart = 0;
3323 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3324 smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3325 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3326 fidp->flags |= SMB_FID_MTIMESETDONE;
3329 if (spi->u.QPstandardInfo.attributes != 0) {
3330 if ((scp->unixModeBits & 0222)
3331 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3332 /* make a writable file read-only */
3333 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3334 attr.unixModeBits = scp->unixModeBits & ~0222;
3336 else if ((scp->unixModeBits & 0222) == 0
3337 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3338 /* make a read-only file writable */
3339 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3340 attr.unixModeBits = scp->unixModeBits | 0222;
3343 lock_ReleaseRead(&scp->rw);
3344 lock_ReleaseMutex(&fidp->mx);
3348 code = cm_SetAttr(scp, &attr, userp, &req);
3352 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3353 /* we don't support EAs */
3354 code = CM_ERROR_EAS_NOT_SUPPORTED;
3358 cm_ReleaseSCache(scp);
3359 cm_ReleaseUser(userp);
3360 smb_ReleaseFID(fidp);
3362 smb_SendTran2Packet(vcp, outp, opx);
3364 smb_SendTran2Error(vcp, p, opx, code);
3365 smb_FreeTran2Packet(outp);
3371 /* TRANS2_QUERY_FILE_INFORMATION */
3372 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3374 smb_tran2Packet_t *outp;
3376 unsigned long attributes;
3377 unsigned short infoLevel;
3384 smb_tran2QFileInfo_t qfi;
3392 fidp = smb_FindFID(vcp, fid, 0);
3395 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3399 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3400 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3401 smb_CloseFID(vcp, fidp, NULL, 0);
3402 smb_ReleaseFID(fidp);
3406 infoLevel = p->parmsp[1];
3407 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3408 responseSize = sizeof(qfi.u.QFbasicInfo);
3409 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3410 responseSize = sizeof(qfi.u.QFstandardInfo);
3411 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3412 responseSize = sizeof(qfi.u.QFeaInfo);
3413 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3414 responseSize = sizeof(qfi.u.QFfileNameInfo);
3416 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3417 p->opcode, infoLevel);
3418 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3419 smb_ReleaseFID(fidp);
3422 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3424 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3426 if (infoLevel > 0x100)
3427 outp->totalParms = 2;
3429 outp->totalParms = 0;
3430 outp->totalData = responseSize;
3432 userp = smb_GetTran2User(vcp, p);
3434 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3435 code = CM_ERROR_BADSMB;
3439 lock_ObtainMutex(&fidp->mx);
3440 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3442 osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3444 lock_ReleaseMutex(&fidp->mx);
3445 lock_ObtainWrite(&scp->rw);
3446 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3447 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3451 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3453 lock_ConvertWToR(&scp->rw);
3456 /* now we have the status in the cache entry, and everything is locked.
3457 * Marshall the output data.
3459 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3460 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3461 qfi.u.QFbasicInfo.creationTime = ft;
3462 qfi.u.QFbasicInfo.lastAccessTime = ft;
3463 qfi.u.QFbasicInfo.lastWriteTime = ft;
3464 qfi.u.QFbasicInfo.lastChangeTime = ft;
3465 attributes = smb_ExtAttributes(scp);
3466 qfi.u.QFbasicInfo.attributes = attributes;
3468 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3469 qfi.u.QFstandardInfo.allocationSize = scp->length;
3470 qfi.u.QFstandardInfo.endOfFile = scp->length;
3471 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3472 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3473 qfi.u.QFstandardInfo.directory =
3474 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3475 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3476 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3478 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3479 qfi.u.QFeaInfo.eaSize = 0;
3481 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3485 lock_ReleaseRead(&scp->rw);
3486 lock_ObtainMutex(&fidp->mx);
3487 lock_ObtainRead(&scp->rw);
3488 if (fidp->NTopen_wholepathp)
3489 name = fidp->NTopen_wholepathp;
3491 name = _C("\\"); /* probably can't happen */
3492 lock_ReleaseMutex(&fidp->mx);
3494 smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, 0);
3495 outp->totalData = len + 4; /* this is actually what we want to return */
3496 qfi.u.QFfileNameInfo.fileNameLength = len;
3499 /* send and free the packets */
3502 lock_ReleaseRead(&scp->rw);
3504 lock_ReleaseWrite(&scp->rw);
3505 cm_ReleaseSCache(scp);
3506 cm_ReleaseUser(userp);
3507 smb_ReleaseFID(fidp);
3509 memcpy(outp->datap, &qfi, responseSize);
3510 smb_SendTran2Packet(vcp, outp, opx);
3512 smb_SendTran2Error(vcp, p, opx, code);
3514 smb_FreeTran2Packet(outp);
3520 /* TRANS2_SET_FILE_INFORMATION */
3521 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3526 unsigned short infoLevel;
3527 smb_tran2Packet_t *outp;
3528 cm_user_t *userp = NULL;
3529 cm_scache_t *scp = NULL;
3535 fidp = smb_FindFID(vcp, fid, 0);
3538 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3542 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3543 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3544 smb_CloseFID(vcp, fidp, NULL, 0);
3545 smb_ReleaseFID(fidp);
3549 infoLevel = p->parmsp[1];
3550 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3551 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3552 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3553 p->opcode, infoLevel);
3554 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3555 smb_ReleaseFID(fidp);
3559 lock_ObtainMutex(&fidp->mx);
3560 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
3561 !(fidp->flags & SMB_FID_OPENDELETE)) {
3562 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3563 fidp, fidp->scp, fidp->flags);
3564 lock_ReleaseMutex(&fidp->mx);
3565 smb_ReleaseFID(fidp);
3566 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3569 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3570 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3571 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3572 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3573 fidp, fidp->scp, fidp->flags);
3574 lock_ReleaseMutex(&fidp->mx);
3575 smb_ReleaseFID(fidp);
3576 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3581 osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3583 lock_ReleaseMutex(&fidp->mx);
3585 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3587 outp->totalParms = 2;
3588 outp->totalData = 0;
3590 userp = smb_GetTran2User(vcp, p);
3592 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3593 code = CM_ERROR_BADSMB;
3597 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3599 unsigned int attribute;
3601 smb_tran2QFileInfo_t *sfi;
3603 sfi = (smb_tran2QFileInfo_t *)p->datap;
3605 /* lock the vnode with a callback; we need the current status
3606 * to determine what the new status is, in some cases.
3608 lock_ObtainWrite(&scp->rw);
3609 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3610 CM_SCACHESYNC_GETSTATUS
3611 | CM_SCACHESYNC_NEEDCALLBACK);
3613 lock_ReleaseWrite(&scp->rw);
3617 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3619 lock_ReleaseWrite(&scp->rw);
3620 lock_ObtainMutex(&fidp->mx);
3621 lock_ObtainRead(&scp->rw);
3623 /* prepare for setattr call */
3626 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3627 /* when called as result of move a b, lastMod is (-1, -1).
3628 * If the check for -1 is not present, timestamp
3629 * of the resulting file will be 1969 (-1)
3631 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3632 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3633 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3634 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3635 fidp->flags |= SMB_FID_MTIMESETDONE;
3638 attribute = sfi->u.QFbasicInfo.attributes;
3639 if (attribute != 0) {
3640 if ((scp->unixModeBits & 0222)
3641 && (attribute & SMB_ATTR_READONLY) != 0) {
3642 /* make a writable file read-only */
3643 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3644 attr.unixModeBits = scp->unixModeBits & ~0222;
3646 else if ((scp->unixModeBits & 0222) == 0
3647 && (attribute & SMB_ATTR_READONLY) == 0) {
3648 /* make a read-only file writable */
3649 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3650 attr.unixModeBits = scp->unixModeBits | 0222;
3653 lock_ReleaseRead(&scp->rw);
3654 lock_ReleaseMutex(&fidp->mx);
3658 code = cm_SetAttr(scp, &attr, userp, &req);
3662 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3663 int delflag = *((char *)(p->datap));
3664 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
3665 delflag, fidp, scp);
3666 if (*((char *)(p->datap))) { /* File is Deleted */
3667 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3670 lock_ObtainMutex(&fidp->mx);
3671 fidp->flags |= SMB_FID_DELONCLOSE;
3672 lock_ReleaseMutex(&fidp->mx);
3674 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
3680 lock_ObtainMutex(&fidp->mx);
3681 fidp->flags &= ~SMB_FID_DELONCLOSE;
3682 lock_ReleaseMutex(&fidp->mx);
3685 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3686 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3687 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3690 attr.mask = CM_ATTRMASK_LENGTH;
3691 attr.length.LowPart = size.LowPart;
3692 attr.length.HighPart = size.HighPart;
3693 code = cm_SetAttr(scp, &attr, userp, &req);
3697 cm_ReleaseSCache(scp);
3698 cm_ReleaseUser(userp);
3699 smb_ReleaseFID(fidp);
3701 smb_SendTran2Packet(vcp, outp, opx);
3703 smb_SendTran2Error(vcp, p, opx, code);
3704 smb_FreeTran2Packet(outp);
3711 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3713 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3714 return CM_ERROR_BADOP;
3719 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3721 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3722 return CM_ERROR_BADOP;
3725 /* TRANS2_FIND_NOTIFY_FIRST */
3727 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3729 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3730 return CM_ERROR_BADOP;
3733 /* TRANS2_FIND_NOTIFY_NEXT */
3735 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3737 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3738 return CM_ERROR_BADOP;
3741 /* TRANS2_CREATE_DIRECTORY */
3743 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3745 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3746 return CM_ERROR_BADOP;
3749 /* TRANS2_SESSION_SETUP */
3751 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3753 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3754 return CM_ERROR_BADOP;
3757 struct smb_v2_referral {
3759 USHORT ReferralFlags;
3762 USHORT DfsPathOffset;
3763 USHORT DfsAlternativePathOffset;
3764 USHORT NetworkAddressOffset;
3767 /* TRANS2_GET_DFS_REFERRAL */
3769 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3771 /* This is a UNICODE only request (bit15 of Flags2) */
3772 /* The TID must be IPC$ */
3774 /* The documentation for the Flags response field is contradictory */
3776 /* Use Version 1 Referral Element Format */
3777 /* ServerType = 0; indicates the next server should be queried for the file */
3778 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3779 /* Node = UnicodeString of UNC path of the next share name */
3782 int maxReferralLevel = 0;
3783 clientchar_t requestFileName[1024] = _C("");
3784 clientchar_t referralPath[1024] = _C("");
3785 smb_tran2Packet_t *outp = 0;
3786 cm_user_t *userp = 0;
3787 cm_scache_t *scp = 0;
3788 cm_scache_t *dscp = 0;
3790 CPINFO CodePageInfo;
3791 int i, nbnLen, reqLen, refLen;
3796 maxReferralLevel = p->parmsp[0];
3798 GetCPInfo(CP_ACP, &CodePageInfo);
3799 cm_Utf16ToClientString(&p->parmsp[1], -1, requestFileName, lengthof(requestFileName));
3801 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%S]",
3802 maxReferralLevel, osi_LogSaveClientString(smb_logp, requestFileName));
3804 nbnLen = (int)cm_ClientStrLen(cm_NetbiosNameC);
3805 reqLen = (int)cm_ClientStrLen(requestFileName);
3807 if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
3808 !cm_ClientStrCmpNI(cm_NetbiosNameC, &requestFileName[1], nbnLen) &&
3809 requestFileName[nbnLen+1] == '\\')
3813 if (!cm_ClientStrCmpNI(_C("all"), &requestFileName[nbnLen+2], 3) ||
3814 !cm_ClientStrCmpNI(_C("*."), &requestFileName[nbnLen+2], 2)) {
3816 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
3819 userp = smb_GetTran2User(vcp, p);
3821 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3822 code = CM_ERROR_BADSMB;
3827 * We have a requested path. Check to see if it is something
3830 * But be careful because the name that we might be searching
3831 * for might be a known name with the final character stripped
3834 code = cm_NameI(cm_data.rootSCachep, &requestFileName[nbnLen+2],
3835 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
3836 userp, NULL, &req, &scp);
3840 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
3842 } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
3843 clientchar_t temp[1024];
3844 clientchar_t pathName[1024];
3845 clientchar_t *lastComponent;
3847 * we have a msdfs link somewhere in the path
3848 * we should figure out where in the path the link is.
3851 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%S]", requestFileName);
3853 cm_ClientStrCpy(temp, lengthof(temp), &requestFileName[nbnLen+2]);
3857 cm_ReleaseSCache(dscp);
3861 cm_ReleaseSCache(scp);
3864 smb_StripLastComponent(pathName, &lastComponent, temp);
3866 code = cm_NameI(cm_data.rootSCachep, pathName,
3867 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3868 userp, NULL, &req, &dscp);
3870 code = cm_NameI(dscp, ++lastComponent,
3872 userp, NULL, &req, &scp);
3873 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK)
3876 } while (code == CM_ERROR_PATH_NOT_COVERED);
3878 /* scp should now be the DfsLink we are looking for */
3880 /* figure out how much of the input path was used */
3881 reqLen = (int)(nbnLen+2 + cm_ClientStrLen(pathName) + 1 + cm_ClientStrLen(lastComponent));
3883 cm_FsStringToClientString(&scp->mountPointStringp[strlen("msdfs:")], -1,
3884 referralPath, lengthof(referralPath));
3885 refLen = (int)cm_ClientStrLen(referralPath);
3889 clientchar_t shareName[MAX_PATH + 1];
3890 clientchar_t *p, *q;
3891 /* we may have a sharename that is a volume reference */
3893 for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
3899 if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
3900 code = cm_NameI(cm_data.rootSCachep, _C(""),
3901 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
3902 userp, p, &req, &scp);
3907 cm_ClientStrCpy(referralPath, lengthof(referralPath),
3918 struct smb_v2_referral * v2ref;
3919 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (refLen + 8));
3921 sp = (USHORT *)outp->datap;
3923 sp[idx++] = reqLen; /* path consumed */
3924 sp[idx++] = 1; /* number of referrals */
3925 sp[idx++] = 0x03; /* flags */
3926 #ifdef DFS_VERSION_1
3927 sp[idx++] = 1; /* Version Number */
3928 sp[idx++] = refLen + 4; /* Referral Size */
3929 sp[idx++] = 1; /* Type = SMB Server */
3930 sp[idx++] = 0; /* Do not strip path consumed */
3931 for ( i=0;i<=refLen; i++ )
3932 sp[i+idx] = referralPath[i];
3933 #else /* DFS_VERSION_2 */
3934 sp[idx++] = 2; /* Version Number */
3935 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3936 idx += (sizeof(struct smb_v2_referral) / 2);
3937 v2ref = (struct smb_v2_referral *) &sp[5];
3938 v2ref->ServerType = 1; /* SMB Server */
3939 v2ref->ReferralFlags = 0x03;
3940 v2ref->Proximity = 0; /* closest */
3941 v2ref->TimeToLive = 3600; /* seconds */
3942 v2ref->DfsPathOffset = idx * 2;
3943 v2ref->DfsAlternativePathOffset = idx * 2;
3944 v2ref->NetworkAddressOffset = 0;
3945 for ( i=0;i<=refLen; i++ )
3946 sp[i+idx] = referralPath[i];
3950 code = CM_ERROR_NOSUCHPATH;
3955 cm_ReleaseSCache(dscp);
3957 cm_ReleaseSCache(scp);
3959 cm_ReleaseUser(userp);
3961 smb_SendTran2Packet(vcp, outp, op);
3963 smb_SendTran2Error(vcp, p, op, code);
3965 smb_FreeTran2Packet(outp);
3968 #else /* DFS_SUPPORT */
3969 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3970 return CM_ERROR_NOSUCHDEVICE;
3971 #endif /* DFS_SUPPORT */
3974 /* TRANS2_REPORT_DFS_INCONSISTENCY */
3976 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3978 /* This is a UNICODE only request (bit15 of Flags2) */
3980 /* There is nothing we can do about this operation. The client is going to
3981 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3982 * Unfortunately, there is really nothing we can do about it other then log it
3983 * somewhere. Even then I don't think there is anything for us to do.
3984 * So let's return an error value.
3987 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3988 return CM_ERROR_BADOP;
3992 smb_ApplyV3DirListPatches(cm_scache_t *dscp, smb_dirListPatch_t **dirPatchespp,
3993 clientchar_t * tidPathp, clientchar_t * relPathp,
3994 int infoLevel, cm_user_t *userp, cm_req_t *reqp)
3998 cm_scache_t *targetScp; /* target if scp is a symlink */
4001 unsigned short attr;
4002 unsigned long lattr;
4003 smb_dirListPatch_t *patchp;
4004 smb_dirListPatch_t *npatchp;
4006 afs_int32 mustFake = 0;
4007 clientchar_t path[AFSPATHMAX];
4009 code = cm_FindACLCache(dscp, userp, &rights);
4010 if (code == 0 && !(rights & PRSFS_READ))
4012 else if (code == -1) {
4013 lock_ObtainWrite(&dscp->rw);
4014 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4015 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4016 lock_ReleaseWrite(&dscp->rw);
4017 if (code == CM_ERROR_NOACCESS) {
4025 if (!mustFake) { /* Bulk Stat */
4027 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4029 memset(bsp, 0, sizeof(cm_bulkStat_t));
4031 for (patchp = *dirPatchespp, count=0;
4033 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4034 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4038 if (lock_TryWrite(&tscp->rw)) {
4039 /* we have an entry that we can look at */
4040 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4041 /* we have a callback on it. Don't bother
4042 * fetching this stat entry, since we're happy
4043 * with the info we have.
4045 lock_ReleaseWrite(&tscp->rw);
4046 cm_ReleaseSCache(tscp);
4049 lock_ReleaseWrite(&tscp->rw);
4051 cm_ReleaseSCache(tscp);
4055 bsp->fids[i].Volume = patchp->fid.volume;
4056 bsp->fids[i].Vnode = patchp->fid.vnode;
4057 bsp->fids[i].Unique = patchp->fid.unique;
4059 if (bsp->counter == AFSCBMAX) {
4060 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4061 memset(bsp, 0, sizeof(cm_bulkStat_t));
4065 if (bsp->counter > 0)
4066 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4071 for( patchp = *dirPatchespp;
4073 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4074 cm_ClientStrPrintfN(path, lengthof(path),_C("%s\\%S"),
4075 relPathp ? relPathp : _C(""), patchp->dep->name);
4076 reqp->relPathp = path;
4077 reqp->tidPathp = tidPathp;
4079 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4080 reqp->relPathp = reqp->tidPathp = NULL;
4084 lock_ObtainWrite(&scp->rw);
4085 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4086 lock_ReleaseWrite(&scp->rw);
4088 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4089 errors in the client. */
4090 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4091 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4093 /* 1969-12-31 23:59:59 +00 */
4094 ft.dwHighDateTime = 0x19DB200;
4095 ft.dwLowDateTime = 0x5BB78980;
4097 /* copy to Creation Time */
4098 fa->creationTime = ft;
4099 fa->lastAccessTime = ft;
4100 fa->lastWriteTime = ft;
4101 fa->lastChangeTime = ft;
4103 switch (scp->fileType) {
4104 case CM_SCACHETYPE_DIRECTORY:
4105 case CM_SCACHETYPE_MOUNTPOINT:
4106 case CM_SCACHETYPE_SYMLINK:
4107 case CM_SCACHETYPE_INVALID:
4108 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4111 /* if we get here we either have a normal file
4112 * or we have a file for which we have never
4113 * received status info. In this case, we can
4114 * check the even/odd value of the entry's vnode.
4115 * even means it is to be treated as a directory
4116 * and odd means it is to be treated as a file.
4118 if (mustFake && (scp->fid.vnode & 0x1))
4119 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4121 fa->extFileAttributes = SMB_ATTR_NORMAL;
4123 /* merge in hidden attribute */
4124 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4125 fa->extFileAttributes |= SMB_ATTR_HIDDEN;
4128 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4130 /* 1969-12-31 23:59:58 +00*/
4131 dosTime = 0xEBBFBF7D;
4133 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4134 fa->lastAccessDateTime = fa->creationDateTime;
4135 fa->lastWriteDateTime = fa->creationDateTime;
4137 /* set the attribute */
4138 switch (scp->fileType) {
4139 case CM_SCACHETYPE_DIRECTORY:
4140 case CM_SCACHETYPE_MOUNTPOINT:
4141 case CM_SCACHETYPE_SYMLINK:
4142 case CM_SCACHETYPE_INVALID:
4143 fa->attributes = SMB_ATTR_DIRECTORY;
4146 /* if we get here we either have a normal file
4147 * or we have a file for which we have never
4148 * received status info. In this case, we can
4149 * check the even/odd value of the entry's vnode.
4150 * even means it is to be treated as a directory
4151 * and odd means it is to be treated as a file.
4153 if (mustFake && (scp->fid.vnode & 0x1))
4154 fa->attributes = SMB_ATTR_DIRECTORY;
4156 fa->attributes = SMB_ATTR_NORMAL;
4159 /* merge in hidden (dot file) attribute */
4160 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4161 fa->attributes |= SMB_ATTR_HIDDEN;
4165 cm_ReleaseSCache(scp);
4169 /* now watch for a symlink */
4171 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
4172 lock_ReleaseWrite(&scp->rw);
4173 cm_ClientStrPrintfN(path, lengthof(path), _C("%s\\%S"),
4174 relPathp ? relPathp : _C(""), patchp->dep->name);
4175 reqp->relPathp = path;
4176 reqp->tidPathp = tidPathp;
4177 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
4178 reqp->relPathp = reqp->tidPathp = NULL;
4180 /* we have a more accurate file to use (the
4181 * target of the symbolic link). Otherwise,
4182 * we'll just use the symlink anyway.
4184 osi_Log2(smb_logp, "symlink vp %x to vp %x",
4186 cm_ReleaseSCache(scp);
4189 lock_ObtainWrite(&scp->rw);
4192 lock_ConvertWToR(&scp->rw);
4194 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4195 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4198 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4200 fa->creationTime = ft;
4201 fa->lastAccessTime = ft;
4202 fa->lastWriteTime = ft;
4203 fa->lastChangeTime = ft;
4205 /* Use length for both file length and alloc length */
4206 fa->endOfFile = scp->length;
4207 fa->allocationSize = scp->length;
4209 /* Copy attributes */
4210 lattr = smb_ExtAttributes(scp);
4211 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK ||
4212 code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4213 if (lattr == SMB_ATTR_NORMAL)
4214 lattr = SMB_ATTR_DIRECTORY;
4216 lattr |= SMB_ATTR_DIRECTORY;
4218 /* merge in hidden (dot file) attribute */
4219 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4220 if (lattr == SMB_ATTR_NORMAL)
4221 lattr = SMB_ATTR_HIDDEN;
4223 lattr |= SMB_ATTR_HIDDEN;
4226 fa->extFileAttributes = lattr;
4228 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4231 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4233 fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
4234 fa->lastAccessDateTime = fa->creationDateTime;
4235 fa->lastWriteDateTime = fa->creationDateTime;
4237 /* copy out file length and alloc length,
4238 * using the same for both
4240 fa->dataSize = scp->length.LowPart;
4241 fa->allocationSize = scp->length.LowPart;
4243 /* finally copy out attributes as short */
4244 attr = smb_Attributes(scp);
4245 /* merge in hidden (dot file) attribute */
4246 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4247 if (lattr == SMB_ATTR_NORMAL)
4248 lattr = SMB_ATTR_HIDDEN;
4250 lattr |= SMB_ATTR_HIDDEN;
4252 fa->attributes = attr;
4255 lock_ReleaseRead(&scp->rw);
4256 cm_ReleaseSCache(scp);
4259 /* now free the patches */
4260 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4261 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4265 /* and mark the list as empty */
4266 *dirPatchespp = NULL;
4272 /* smb_ReceiveTran2SearchDir implements both
4273 * Tran2_Find_First and Tran2_Find_Next
4275 #define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
4276 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
4277 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
4278 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
4279 #define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
4281 /* this is an optimized handler for T2SearchDir that handles the case
4282 where there are no wildcards in the search path. I.e. an
4283 application is using FindFirst(Ex) to get information about a
4284 single file or directory. It will attempt to do a single lookup.
4285 If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4286 the usual mechanism.
4288 This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4290 TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
4292 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4296 long code = 0, code2 = 0;
4297 clientchar_t *pathp = 0;
4299 smb_dirListPatch_t *dirListPatchesp;
4300 smb_dirListPatch_t *curPatchp;
4301 size_t orbytes; /* # of bytes in this output record */
4302 size_t ohbytes; /* # of bytes, except file name */
4303 size_t onbytes; /* # of bytes in name, incl. term. null */
4304 cm_scache_t *scp = NULL;
4305 cm_scache_t *targetscp = NULL;
4306 cm_user_t *userp = NULL;
4307 char *op; /* output data ptr */
4308 char *origOp; /* original value of op */
4309 cm_space_t *spacep; /* for pathname buffer */
4310 unsigned long maxReturnData; /* max # of return data */
4311 long maxReturnParms; /* max # of return parms */
4312 long bytesInBuffer; /* # data bytes in the output buffer */
4313 clientchar_t *maskp; /* mask part of path */
4317 smb_tran2Packet_t *outp; /* response packet */
4318 clientchar_t *tidPathp = 0;
4320 clientchar_t shortName[13]; /* 8.3 name if needed */
4322 clientchar_t *shortNameEnd;
4323 cm_dirEntry_t * dep = NULL;
4326 void * attrp = NULL;
4327 smb_tran2Find_t * fp;
4332 osi_assertx(p->opcode == 1, "invalid opcode");
4334 /* find first; obtain basic parameters from request */
4336 /* note that since we are going to failover to regular
4337 * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4338 * modify any of the input parameters here. */
4339 attribute = p->parmsp[0];
4340 maxCount = p->parmsp[1];
4341 infoLevel = p->parmsp[3];
4342 searchFlags = p->parmsp[2];
4343 pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4345 maskp = cm_ClientStrRChr(pathp, '\\');
4349 maskp++; /* skip over backslash */
4350 /* track if this is likely to match a lot of entries */
4352 osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%S], mask[%S]",
4353 osi_LogSaveClientString(smb_logp, pathp),
4354 osi_LogSaveClientString(smb_logp, maskp));
4356 switch ( infoLevel ) {
4357 case SMB_INFO_STANDARD:
4359 ohbytes = sizeof(fp->u.FstandardInfo);
4362 case SMB_INFO_QUERY_EA_SIZE:
4363 ohbytes = sizeof(fp->u.FeaSizeInfo);
4364 s = "InfoQueryEaSize";
4367 case SMB_INFO_QUERY_EAS_FROM_LIST:
4368 ohbytes = sizeof(fp->u.FeasFromListInfo);
4369 s = "InfoQueryEasFromList";
4372 case SMB_FIND_FILE_DIRECTORY_INFO:
4373 s = "FindFileDirectoryInfo";
4374 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4377 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4378 s = "FindFileFullDirectoryInfo";
4379 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4382 case SMB_FIND_FILE_NAMES_INFO:
4383 s = "FindFileNamesInfo";
4384 ohbytes = sizeof(fp->u.FfileNamesInfo);
4387 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4388 s = "FindFileBothDirectoryInfo";
4389 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4393 s = "unknownInfoLevel";
4397 osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
4400 "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4401 attribute, infoLevel, maxCount, searchFlags);
4404 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4405 return CM_ERROR_INVAL;
4408 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4409 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4411 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4414 dirListPatchesp = NULL;
4416 maxReturnData = p->maxReturnData;
4417 maxReturnParms = 10; /* return params for findfirst, which
4418 is the only one we handle.*/
4420 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4423 osi_Log2(smb_logp, "T2SDSingle search dir count %d [%S]",
4424 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4426 /* bail out if request looks bad */
4428 smb_FreeTran2Packet(outp);
4429 return CM_ERROR_BADSMB;
4432 userp = smb_GetTran2User(vcp, p);
4434 osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
4435 smb_FreeTran2Packet(outp);
4436 return CM_ERROR_BADSMB;
4439 /* try to get the vnode for the path name next */
4440 spacep = cm_GetSpace();
4441 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4442 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4444 cm_ReleaseUser(userp);
4445 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4446 smb_FreeTran2Packet(outp);
4450 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4451 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4452 userp, tidPathp, &req, &scp);
4453 cm_FreeSpace(spacep);
4456 cm_ReleaseUser(userp);
4457 smb_SendTran2Error(vcp, p, opx, code);
4458 smb_FreeTran2Packet(outp);
4462 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4463 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4464 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
4465 cm_ReleaseSCache(scp);
4466 cm_ReleaseUser(userp);
4467 if ( WANTS_DFS_PATHNAMES(p) || pnc )
4468 code = CM_ERROR_PATH_NOT_COVERED;
4470 code = CM_ERROR_BADSHARENAME;
4471 smb_SendTran2Error(vcp, p, opx, code);
4472 smb_FreeTran2Packet(outp);
4475 #endif /* DFS_SUPPORT */
4476 osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
4478 /* now do a single case sensitive lookup for the file in question */
4479 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
4481 /* if a case sensitive match failed, we try a case insensitive one
4483 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
4484 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
4487 if (code == 0 && targetscp->fid.vnode == 0) {
4488 cm_ReleaseSCache(targetscp);
4489 code = CM_ERROR_NOSUCHFILE;
4493 /* if we can't find the directory entry, this block will
4494 return CM_ERROR_NOSUCHFILE, which we will pass on to
4495 smb_ReceiveTran2SearchDir(). */
4496 cm_ReleaseSCache(scp);
4497 cm_ReleaseUser(userp);
4498 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4499 smb_SendTran2Error(vcp, p, opx, code);
4502 smb_FreeTran2Packet(outp);
4506 /* now that we have the target in sight, we proceed with filling
4507 up the return data. */
4509 op = origOp = outp->datap;
4512 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4513 /* skip over resume key */
4517 fp = (smb_tran2Find_t *) op;
4519 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4520 && targetscp->fid.vnode != 0
4521 && !cm_Is8Dot3(maskp)) {
4524 dfid.vnode = htonl(targetscp->fid.vnode);
4525 dfid.unique = htonl(targetscp->fid.unique);
4527 cm_Gen8Dot3NameIntW(maskp, &dfid, shortName, &shortNameEnd);
4533 osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %S (%S)",
4534 htonl(targetscp->fid.vnode),
4535 htonl(targetscp->fid.unique),
4536 osi_LogSaveClientString(smb_logp, pathp),
4537 (NeedShortName)? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
4539 /* Eliminate entries that don't match requested attributes */
4540 if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
4541 smb_IsDotFile(maskp)) {
4543 code = CM_ERROR_NOSUCHFILE;
4544 osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
4549 if (!(attribute & SMB_ATTR_DIRECTORY) &&
4550 (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
4551 targetscp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4552 targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
4553 targetscp->fileType == CM_SCACHETYPE_INVALID)) {
4555 code = CM_ERROR_NOSUCHFILE;
4556 osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
4561 /* add header to name & term. null */
4563 smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH);
4564 orbytes = ohbytes + onbytes;
4566 /* now, we round up the record to a 4 byte alignment, and we make
4567 * sure that we have enough room here for even the aligned version
4568 * (so we don't have to worry about an * overflow when we pad
4569 * things out below). That's the reason for the alignment
4572 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4573 align = (4 - (orbytes & 3)) & 3;
4577 if (orbytes + align > maxReturnData) {
4579 /* even though this request is unlikely to succeed with a
4580 failover, we do it anyway. */
4581 code = CM_ERROR_NOSUCHFILE;
4582 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4587 /* this is one of the entries to use: it is not deleted and it
4588 * matches the star pattern we're looking for. Put out the name,
4589 * preceded by its length.
4591 /* First zero everything else */
4592 memset(origOp, 0, orbytes);
4595 smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH);
4597 switch (infoLevel) {
4598 case SMB_INFO_STANDARD:
4599 fp->u.FstandardInfo.fileNameLength = onbytes;
4600 attrp = &fp->u.FstandardInfo.fileAttrs;
4603 case SMB_INFO_QUERY_EA_SIZE:
4604 fp->u.FeaSizeInfo.fileNameLength = onbytes;
4605 attrp = &fp->u.FeaSizeInfo.fileAttrs;
4606 fp->u.FeaSizeInfo.eaSize = 0;
4609 case SMB_INFO_QUERY_EAS_FROM_LIST:
4610 fp->u.FeasFromListInfo.fileNameLength = onbytes;
4611 attrp = &fp->u.FeasFromListInfo.fileAttrs;
4612 fp->u.FeasFromListInfo.eaSize = 0;
4615 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4616 if (NeedShortName) {
4620 nchars = cm_ClientStringToUtf16(shortName, -1,
4621 fp->u.FfileBothDirectoryInfo.shortName,
4622 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
4624 fp->u.FfileBothDirectoryInfo.shortNameLength = (nchars - 1)*sizeof(wchar_t);
4626 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
4627 fp->u.FfileBothDirectoryInfo.reserved = 0;
4629 strcpy(fp->u.FfileBothDirectoryInfo.shortName,
4631 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
4636 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4637 fp->u.FfileFullDirectoryInfo.eaSize = 0;
4640 case SMB_FIND_FILE_DIRECTORY_INFO:
4641 fp->u.FfileDirectoryInfo.nextEntryOffset = 0;
4642 fp->u.FfileDirectoryInfo.fileIndex = 0;
4643 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
4644 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
4647 case SMB_FIND_FILE_NAMES_INFO:
4648 fp->u.FfileNamesInfo.nextEntryOffset = 0;
4649 fp->u.FfileNamesInfo.fileIndex = 0;
4650 fp->u.FfileNamesInfo.fileNameLength = onbytes;
4654 /* we shouldn't hit this case */
4655 osi_assertx(FALSE, "Unknown query type");
4658 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4659 osi_assert(attrp != NULL);
4661 curPatchp = malloc(sizeof(*curPatchp));
4662 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4664 curPatchp->dptr = attrp;
4666 if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
4667 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4669 curPatchp->flags = 0;
4672 cm_SetFid(&curPatchp->fid, targetscp->fid.cell, targetscp->fid.volume, targetscp->fid.vnode, targetscp->fid.unique);
4676 int namelen = cm_ClientStringToFsString(maskp, -1, NULL, 0);
4677 dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+namelen);
4678 cm_ClientStringToFsString(maskp, -1, dep->name, namelen);
4680 dep->fid.vnode = targetscp->fid.vnode;
4681 dep->fid.unique = targetscp->fid.unique;
4682 curPatchp->dep = dep;
4685 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4686 /* put out resume key */
4687 *((u_long *)origOp) = 0;
4690 /* Adjust byte ptr and count */
4691 origOp += orbytes; /* skip entire record */
4692 bytesInBuffer += orbytes;
4694 /* and pad the record out */
4695 while (--align >= 0) {
4700 /* apply the patches */
4701 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->wdata, infoLevel, userp, &req);
4703 outp->parmsp[0] = 0;
4704 outp->parmsp[1] = 1; /* number of names returned */
4705 outp->parmsp[2] = 1; /* end of search */
4706 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4707 outp->parmsp[4] = 0;
4709 outp->totalParms = 10; /* in bytes */
4711 outp->totalData = bytesInBuffer;
4713 osi_Log0(smb_logp, "T2SDSingle done.");
4715 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4717 smb_SendTran2Error(vcp, p, opx, code);
4719 smb_SendTran2Packet(vcp, outp, opx);
4724 smb_FreeTran2Packet(outp);
4728 cm_ReleaseSCache(scp);
4729 cm_ReleaseSCache(targetscp);
4730 cm_ReleaseUser(userp);
4736 /* TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2 */
4737 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4742 long code = 0, code2 = 0;
4743 clientchar_t *pathp;
4744 cm_dirEntry_t *dep = 0;
4746 smb_dirListPatch_t *dirListPatchesp = 0;
4747 smb_dirListPatch_t *curPatchp = 0;
4750 size_t orbytes; /* # of bytes in this output record */
4751 size_t ohbytes; /* # of bytes, except file name */
4752 size_t onbytes; /* # of bytes in name, incl. term. null */
4753 osi_hyper_t dirLength;
4754 osi_hyper_t bufferOffset;
4755 osi_hyper_t curOffset;
4757 smb_dirSearch_t *dsp;
4761 cm_pageHeader_t *pageHeaderp;
4762 cm_user_t *userp = NULL;
4765 long nextEntryCookie;
4766 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4767 char *op; /* output data ptr */
4768 char *origOp; /* original value of op */
4769 cm_space_t *spacep; /* for pathname buffer */
4770 unsigned long maxReturnData; /* max # of return data */
4771 unsigned long maxReturnParms; /* max # of return parms */
4772 long bytesInBuffer; /* # data bytes in the output buffer */
4774 clientchar_t *maskp; /* mask part of path */
4778 smb_tran2Packet_t *outp; /* response packet */
4779 clientchar_t *tidPathp;
4781 clientchar_t shortName[13]; /* 8.3 name if needed */
4784 clientchar_t *shortNameEnd;
4790 smb_tran2Find_t * fp;
4795 if (p->opcode == 1) {
4796 /* find first; obtain basic parameters from request */
4797 attribute = p->parmsp[0];
4798 maxCount = p->parmsp[1];
4799 infoLevel = p->parmsp[3];
4800 searchFlags = p->parmsp[2];
4801 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4803 maskp = cm_ClientStrRChr(pathp, '\\');
4807 maskp++; /* skip over backslash */
4809 /* track if this is likely to match a lot of entries */
4810 starPattern = smb_V3IsStarMask(maskp);
4812 #ifndef NOFINDFIRSTOPTIMIZE
4814 /* if this is for a single directory or file, we let the
4815 optimized routine handle it. The only error it
4816 returns is CM_ERROR_NOSUCHFILE. The */
4817 code = smb_T2SearchDirSingle(vcp, p, opx);
4819 /* we only failover if we see a CM_ERROR_NOSUCHFILE */
4820 if (code != CM_ERROR_NOSUCHFILE) {
4822 /* unless we are using the BPlusTree */
4823 if (code == CM_ERROR_BPLUS_NOMATCH)
4824 code = CM_ERROR_NOSUCHFILE;
4825 #endif /* USE_BPLUS */
4829 #endif /* NOFINDFIRSTOPTIMIZE */
4832 dsp = smb_NewDirSearch(1);
4833 dsp->attribute = attribute;
4834 cm_ClientStrCpy(dsp->mask, lengthof(dsp->mask), maskp); /* and save mask */
4837 osi_assertx(p->opcode == 2, "invalid opcode");
4838 /* find next; obtain basic parameters from request or open dir file */
4839 dsp = smb_FindDirSearch(p->parmsp[0]);
4840 maxCount = p->parmsp[1];
4841 infoLevel = p->parmsp[2];
4842 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4843 searchFlags = p->parmsp[5];
4845 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4846 p->parmsp[0], nextCookie);
4847 return CM_ERROR_BADFD;
4849 attribute = dsp->attribute;
4852 starPattern = 1; /* assume, since required a Find Next */
4855 switch ( infoLevel ) {
4856 case SMB_INFO_STANDARD:
4858 ohbytes = sizeof(fp->u.FstandardInfo);
4861 case SMB_INFO_QUERY_EA_SIZE:
4862 ohbytes = sizeof(fp->u.FeaSizeInfo);
4863 s = "InfoQueryEaSize";
4866 case SMB_INFO_QUERY_EAS_FROM_LIST:
4867 ohbytes = sizeof(fp->u.FeasFromListInfo);
4868 s = "InfoQueryEasFromList";
4871 case SMB_FIND_FILE_DIRECTORY_INFO:
4872 s = "FindFileDirectoryInfo";
4873 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4876 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4877 s = "FindFileFullDirectoryInfo";
4878 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4881 case SMB_FIND_FILE_NAMES_INFO:
4882 s = "FindFileNamesInfo";
4883 ohbytes = sizeof(fp->u.FfileNamesInfo);
4886 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4887 s = "FindFileBothDirectoryInfo";
4888 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4892 s = "unknownInfoLevel";
4896 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
4899 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4900 attribute, infoLevel, maxCount, searchFlags);
4902 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
4903 p->opcode, dsp->cookie, nextCookie);
4906 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4907 smb_ReleaseDirSearch(dsp);
4908 return CM_ERROR_INVAL;
4911 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4912 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4914 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4917 dirListPatchesp = NULL;
4919 maxReturnData = p->maxReturnData;
4920 if (p->opcode == 1) /* find first */
4921 maxReturnParms = 10; /* bytes */
4923 maxReturnParms = 8; /* bytes */
4925 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4931 osi_Log2(smb_logp, "T2 receive search dir count %d [%S]",
4932 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4934 /* bail out if request looks bad */
4935 if (p->opcode == 1 && !pathp) {
4936 smb_ReleaseDirSearch(dsp);
4937 smb_FreeTran2Packet(outp);
4938 return CM_ERROR_BADSMB;
4941 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
4942 dsp->cookie, nextCookie, attribute);
4944 userp = smb_GetTran2User(vcp, p);
4946 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
4947 smb_ReleaseDirSearch(dsp);
4948 smb_FreeTran2Packet(outp);
4949 return CM_ERROR_BADSMB;
4952 /* try to get the vnode for the path name next */
4953 lock_ObtainMutex(&dsp->mx);
4956 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4960 spacep = cm_GetSpace();
4961 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4962 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4964 cm_ReleaseUser(userp);
4965 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4966 smb_FreeTran2Packet(outp);
4967 lock_ReleaseMutex(&dsp->mx);
4968 smb_DeleteDirSearch(dsp);
4969 smb_ReleaseDirSearch(dsp);
4973 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4974 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4976 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4977 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4978 userp, tidPathp, &req, &scp);
4979 cm_FreeSpace(spacep);
4982 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4983 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4984 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
4985 cm_ReleaseSCache(scp);
4986 cm_ReleaseUser(userp);
4987 if ( WANTS_DFS_PATHNAMES(p) || pnc )
4988 code = CM_ERROR_PATH_NOT_COVERED;
4990 code = CM_ERROR_BADSHARENAME;
4991 smb_SendTran2Error(vcp, p, opx, code);
4992 smb_FreeTran2Packet(outp);
4993 lock_ReleaseMutex(&dsp->mx);
4994 smb_DeleteDirSearch(dsp);
4995 smb_ReleaseDirSearch(dsp);
4998 #endif /* DFS_SUPPORT */
5000 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5001 /* we need one hold for the entry we just stored into,
5002 * and one for our own processing. When we're done
5003 * with this function, we'll drop the one for our own
5004 * processing. We held it once from the namei call,
5005 * and so we do another hold now.
5008 dsp->flags |= SMB_DIRSEARCH_BULKST;
5011 lock_ReleaseMutex(&dsp->mx);
5013 cm_ReleaseUser(userp);
5014 smb_FreeTran2Packet(outp);
5015 smb_DeleteDirSearch(dsp);
5016 smb_ReleaseDirSearch(dsp);
5020 /* get the directory size */
5021 lock_ObtainWrite(&scp->rw);
5022 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5023 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5025 lock_ReleaseWrite(&scp->rw);
5026 cm_ReleaseSCache(scp);
5027 cm_ReleaseUser(userp);
5028 smb_FreeTran2Packet(outp);
5029 smb_DeleteDirSearch(dsp);
5030 smb_ReleaseDirSearch(dsp);
5034 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5037 dirLength = scp->length;
5039 bufferOffset.LowPart = bufferOffset.HighPart = 0;
5040 curOffset.HighPart = 0;
5041 curOffset.LowPart = nextCookie;
5042 origOp = outp->datap;
5049 normchar_t normName[MAX_PATH]; /* Normalized name */
5050 clientchar_t cfileName[MAX_PATH]; /* Non-normalized name */
5053 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5054 /* skip over resume key */
5057 fp = (smb_tran2Find_t *) op;
5059 /* make sure that curOffset.LowPart doesn't point to the first
5060 * 32 bytes in the 2nd through last dir page, and that it doesn't
5061 * point at the first 13 32-byte chunks in the first dir page,
5062 * since those are dir and page headers, and don't contain useful
5065 temp = curOffset.LowPart & (2048-1);
5066 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5067 /* we're in the first page */
5068 if (temp < 13*32) temp = 13*32;
5071 /* we're in a later dir page */
5072 if (temp < 32) temp = 32;
5075 /* make sure the low order 5 bits are zero */
5078 /* now put temp bits back ito curOffset.LowPart */
5079 curOffset.LowPart &= ~(2048-1);
5080 curOffset.LowPart |= temp;
5082 /* check if we've passed the dir's EOF */
5083 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
5084 osi_Log0(smb_logp, "T2 search dir passed eof");
5089 /* check if we've returned all the names that will fit in the
5090 * response packet; we check return count as well as the number
5091 * of bytes requested. We check the # of bytes after we find
5092 * the dir entry, since we'll need to check its size.
5094 if (returnedNames >= maxCount) {
5095 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
5096 returnedNames, maxCount);
5100 /* when we have obtained as many entries as can be processed in
5101 * a single Bulk Status call to the file server, apply the dir listing
5104 if (returnedNames > 0 && returnedNames % AFSCBMAX == 0) {
5105 lock_ReleaseWrite(&scp->rw);
5106 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5107 dsp->relPath, infoLevel, userp, &req);
5108 lock_ObtainWrite(&scp->rw);
5110 /* Then check to see if we have time left to process more entries */
5111 if (GetTickCount() - req.startTime > (RDRtimeout - 15) * 1000) {
5112 osi_Log0(smb_logp, "T2 search dir RDRtimeout exceeded");
5116 /* see if we can use the bufferp we have now; compute in which
5117 * page the current offset would be, and check whether that's
5118 * the offset of the buffer we have. If not, get the buffer.
5120 thyper.HighPart = curOffset.HighPart;
5121 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5122 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5125 buf_Release(bufferp);
5128 lock_ReleaseWrite(&scp->rw);
5129 code = buf_Get(scp, &thyper, &bufferp);
5130 lock_ObtainWrite(&scp->rw);
5132 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
5136 bufferOffset = thyper;
5138 /* now get the data in the cache */
5140 code = cm_SyncOp(scp, bufferp, userp, &req,
5142 CM_SCACHESYNC_NEEDCALLBACK
5143 | CM_SCACHESYNC_READ);
5145 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5149 if (cm_HaveBuffer(scp, bufferp, 0)) {
5150 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5151 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5155 /* otherwise, load the buffer and try again */
5156 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5158 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5160 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5161 scp, bufferp, code);
5166 buf_Release(bufferp);
5170 } /* if (wrong buffer) ... */
5172 /* now we have the buffer containing the entry we're interested
5173 * in; copy it out if it represents a non-deleted entry.
5175 entryInDir = curOffset.LowPart & (2048-1);
5176 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5178 /* page header will help tell us which entries are free. Page
5179 * header can change more often than once per buffer, since
5180 * AFS 3 dir page size may be less than (but not more than)
5181 * a buffer package buffer.
5183 /* only look intra-buffer */
5184 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5185 temp &= ~(2048 - 1); /* turn off intra-page bits */
5186 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5188 /* now determine which entry we're looking at in the page.
5189 * If it is free (there's a free bitmap at the start of the
5190 * dir), we should skip these 32 bytes.
5192 slotInPage = (entryInDir & 0x7e0) >> 5;
5193 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5194 (1 << (slotInPage & 0x7)))) {
5195 /* this entry is free */
5196 numDirChunks = 1; /* only skip this guy */
5200 tp = bufferp->datap + entryInBuffer;
5201 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5203 /* while we're here, compute the next entry's location, too,
5204 * since we'll need it when writing out the cookie into the dir
5207 * XXXX Probably should do more sanity checking.
5209 numDirChunks = cm_NameEntries(dep->name, &onbytes);
5211 /* compute offset of cookie representing next entry */
5212 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5214 if (dep->fid.vnode == 0)
5215 goto nextEntry; /* This entry is not in use */
5217 cm_FsStringToClientString(dep->name, -1, cfileName, lengthof(cfileName));
5218 cm_ClientStringToNormString(cfileName, -1, normName, lengthof(normName));
5220 /* Need 8.3 name? */
5222 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
5223 !cm_Is8Dot3(cfileName)) {
5224 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5228 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %S (%S)",
5229 dep->fid.vnode, dep->fid.unique,
5230 osi_LogSaveClientString(smb_logp, cfileName),
5231 NeedShortName ? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
5233 /* When matching, we are using doing a case fold if we have a wildcard mask.
5234 * If we get a non-wildcard match, it's a lookup for a specific file.
5236 if (cm_MatchMask(normName, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5237 (NeedShortName && cm_MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))
5239 /* Eliminate entries that don't match requested attributes */
5240 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5241 smb_IsDotFile(cfileName)) {
5242 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5243 goto nextEntry; /* no hidden files */
5246 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5248 /* We have already done the cm_TryBulkStat above */
5249 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume,
5250 ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5251 fileType = cm_FindFileType(&fid);
5252 /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5253 * "has filetype %d", dep->name, fileType);
5255 if ( fileType == CM_SCACHETYPE_DIRECTORY ||
5256 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5257 fileType == CM_SCACHETYPE_DFSLINK ||
5258 fileType == CM_SCACHETYPE_INVALID)
5259 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5263 /* finally check if this name will fit */
5265 smb_UnparseString(opx, NULL, cfileName, &onbytes, SMB_STRF_ANSIPATH);
5266 orbytes = ohbytes + onbytes;
5268 /* now, we round up the record to a 4 byte alignment,
5269 * and we make sure that we have enough room here for
5270 * even the aligned version (so we don't have to worry
5271 * about an overflow when we pad things out below).
5272 * That's the reason for the alignment arithmetic below.
5274 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5275 align = (4 - (orbytes & 3)) & 3;
5279 if (orbytes + bytesInBuffer + align > maxReturnData) {
5280 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5285 /* this is one of the entries to use: it is not deleted
5286 * and it matches the star pattern we're looking for.
5287 * Put out the name, preceded by its length.
5289 /* First zero everything else */
5290 memset(origOp, 0, orbytes);
5293 smb_UnparseString(opx, origOp + ohbytes, cfileName, &onbytes, SMB_STRF_ANSIPATH);
5295 switch (infoLevel) {
5296 case SMB_INFO_STANDARD:
5297 fp->u.FstandardInfo.fileNameLength = onbytes;
5298 attrp = &fp->u.FstandardInfo.fileAttrs;
5301 case SMB_INFO_QUERY_EA_SIZE:
5302 fp->u.FeaSizeInfo.fileNameLength = onbytes;
5303 attrp = &fp->u.FeaSizeInfo.fileAttrs;
5304 fp->u.FeaSizeInfo.eaSize = 0;
5307 case SMB_INFO_QUERY_EAS_FROM_LIST:
5308 fp->u.FeasFromListInfo.fileNameLength = onbytes;
5309 attrp = &fp->u.FeasFromListInfo.fileAttrs;
5310 fp->u.FeasFromListInfo.eaSize = 0;
5313 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5314 if (NeedShortName) {
5318 nchars = cm_ClientStringToUtf16(shortName, -1,
5319 fp->u.FfileBothDirectoryInfo.shortName,
5320 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
5322 fp->u.FfileBothDirectoryInfo.shortNameLength = (nchars - 1)*sizeof(wchar_t);
5324 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5325 fp->u.FfileBothDirectoryInfo.reserved = 0;
5327 cm_ClientStrCpy(fp->u.FfileBothDirectoryInfo.shortName,
5328 lengthof(fp->u.FfileBothDirectoryInfo.shortName),
5330 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
5335 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5336 fp->u.FfileFullDirectoryInfo.eaSize = 0;
5339 case SMB_FIND_FILE_DIRECTORY_INFO:
5340 fp->u.FfileDirectoryInfo.nextEntryOffset = orbytes + align;
5341 fp->u.FfileDirectoryInfo.fileIndex = nextEntryCookie;
5342 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5343 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5346 case SMB_FIND_FILE_NAMES_INFO:
5347 fp->u.FfileNamesInfo.nextEntryOffset = orbytes + align;
5348 fp->u.FfileNamesInfo.fileIndex = nextEntryCookie;
5349 fp->u.FfileNamesInfo.fileNameLength = onbytes;
5354 /* we shouldn't hit this case */
5355 osi_assertx(FALSE, "Unknown query type");
5358 /* now, adjust the # of entries copied */
5361 /* now we emit the attribute. This is tricky, since
5362 * we need to really stat the file to find out what
5363 * type of entry we've got. Right now, we're copying
5364 * out data from a buffer, while holding the scp
5365 * locked, so it isn't really convenient to stat
5366 * something now. We'll put in a place holder
5367 * now, and make a second pass before returning this
5368 * to get the real attributes. So, we just skip the
5369 * data for now, and adjust it later. We allocate a
5370 * patch record to make it easy to find this point
5371 * later. The replay will happen at a time when it is
5372 * safe to unlock the directory.
5374 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5375 osi_assert(attrp != NULL);
5376 curPatchp = malloc(sizeof(*curPatchp));
5377 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5378 curPatchp->dptr = attrp;
5380 if (smb_hideDotFiles && smb_IsDotFile(cfileName)) {
5381 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5383 curPatchp->flags = 0;
5386 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5389 curPatchp->dep = dep;
5392 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5393 /* put out resume key */
5394 *((u_long *)origOp) = nextEntryCookie;
5396 /* Adjust byte ptr and count */
5397 origOp += orbytes; /* skip entire record */
5398 bytesInBuffer += orbytes;
5400 /* and pad the record out */
5401 while (align-- > 0) {
5405 } /* if we're including this name */
5406 else if (!starPattern &&
5408 cm_MatchMask(normName, maskp, CM_FLAG_CASEFOLD)) {
5409 /* We were looking for exact matches, but here's an inexact one*/
5414 /* and adjust curOffset to be where the new cookie is */
5415 thyper.HighPart = 0;
5416 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5417 curOffset = LargeIntegerAdd(thyper, curOffset);
5418 } /* while copying data for dir listing */
5420 /* If we didn't get a star pattern, we did an exact match during the first pass.
5421 * If there were no exact matches found, we fail over to inexact matches by
5422 * marking the query as a star pattern (matches all case permutations), and
5423 * re-running the query.
5425 if (returnedNames == 0 && !starPattern && foundInexact) {
5426 osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
5431 /* release the mutex */
5432 lock_ReleaseWrite(&scp->rw);
5434 buf_Release(bufferp);
5439 * Finally, process whatever entries we have left.
5441 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5442 dsp->relPath, infoLevel, userp, &req);
5444 /* now put out the final parameters */
5445 if (returnedNames == 0)
5447 if (p->opcode == 1) {
5449 outp->parmsp[0] = (unsigned short) dsp->cookie;
5450 outp->parmsp[1] = returnedNames;
5451 outp->parmsp[2] = eos;
5452 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5453 outp->parmsp[4] = 0;
5454 /* don't need last name to continue
5455 * search, cookie is enough. Normally,
5456 * this is the offset of the file name
5457 * of the last entry returned.
5459 outp->totalParms = 10; /* in bytes */
5463 outp->parmsp[0] = returnedNames;
5464 outp->parmsp[1] = eos;
5465 outp->parmsp[2] = 0; /* EAS error */
5466 outp->parmsp[3] = 0; /* last name, as above */
5467 outp->totalParms = 8; /* in bytes */
5470 /* return # of bytes in the buffer */
5471 outp->totalData = bytesInBuffer;
5473 /* Return error code if unsuccessful on first request */
5474 if (code == 0 && p->opcode == 1 && returnedNames == 0)
5475 code = CM_ERROR_NOSUCHFILE;
5477 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
5478 p->opcode, dsp->cookie, returnedNames, code);
5480 /* if we're supposed to close the search after this request, or if
5481 * we're supposed to close the search if we're done, and we're done,
5482 * or if something went wrong, close the search.
5484 if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
5485 (returnedNames == 0) ||
5486 ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
5488 smb_DeleteDirSearch(dsp);
5491 smb_SendTran2Error(vcp, p, opx, code);
5493 smb_SendTran2Packet(vcp, outp, opx);
5495 smb_FreeTran2Packet(outp);
5496 smb_ReleaseDirSearch(dsp);
5497 cm_ReleaseSCache(scp);
5498 cm_ReleaseUser(userp);
5502 /* SMB_COM_FIND_CLOSE2 */
5503 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5506 smb_dirSearch_t *dsp;
5508 dirHandle = smb_GetSMBParm(inp, 0);
5510 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
5512 dsp = smb_FindDirSearch(dirHandle);
5515 return CM_ERROR_BADFD;
5517 /* otherwise, we have an FD to destroy */
5518 smb_DeleteDirSearch(dsp);
5519 smb_ReleaseDirSearch(dsp);
5521 /* and return results */
5522 smb_SetSMBDataLength(outp, 0);
5528 /* SMB_COM_FIND_NOTIFY_CLOSE */
5529 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5531 smb_SetSMBDataLength(outp, 0);
5535 /* SMB_COM_OPEN_ANDX */
5536 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5538 clientchar_t *pathp;
5543 cm_scache_t *dscp; /* dir we're dealing with */
5544 cm_scache_t *scp; /* file we're creating */
5546 int initialModeBits;
5549 clientchar_t *lastNamep;
5550 unsigned long dosTime;
5556 int parmSlot; /* which parm we're dealing with */
5557 clientchar_t *tidPathp;
5565 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
5566 openFun = smb_GetSMBParm(inp, 8); /* open function */
5567 excl = ((openFun & 3) == 0);
5568 trunc = ((openFun & 3) == 2); /* truncate it */
5569 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
5570 openAction = 0; /* tracks what we did */
5572 attributes = smb_GetSMBParm(inp, 5);
5573 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
5575 /* compute initial mode bits based on read-only flag in attributes */
5576 initialModeBits = 0666;
5577 if (attributes & SMB_ATTR_READONLY)
5578 initialModeBits &= ~0222;
5580 pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
5583 spacep = inp->spacep;
5584 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5587 (cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
5588 cm_ClientStrCmpIA(lastNamep, _C("\\srvsvc")) == 0 ||
5589 cm_ClientStrCmpIA(lastNamep, _C("\\wkssvc")) == 0 ||
5590 cm_ClientStrCmpIA(lastNamep, _C("ipc$")) == 0)) {
5591 /* special case magic file name for receiving IOCTL requests
5592 * (since IOCTL calls themselves aren't getting through).
5595 osi_Log0(smb_logp, "IOCTL Open");
5598 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5599 smb_SetupIoctlFid(fidp, spacep);
5601 /* set inp->fid so that later read calls in same msg can find fid */
5602 inp->fid = fidp->fid;
5604 /* copy out remainder of the parms */
5606 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5608 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
5609 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
5610 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5611 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
5612 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
5613 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5614 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5615 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5617 /* and the final "always present" stuff */
5618 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
5619 /* next write out the "unique" ID */
5620 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
5621 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
5622 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5623 smb_SetSMBDataLength(outp, 0);
5625 /* and clean up fid reference */
5626 smb_ReleaseFID(fidp);
5630 #ifdef DEBUG_VERBOSE
5632 char *hexp, *asciip;
5633 asciip = (lastNamep ? lastNamep : pathp );
5634 hexp = osi_HexifyString(asciip);
5635 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
5639 userp = smb_GetUserFromVCP(vcp, inp);
5642 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5644 cm_ReleaseUser(userp);
5645 return CM_ERROR_NOSUCHPATH;
5647 code = cm_NameI(cm_data.rootSCachep, pathp,
5648 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5649 userp, tidPathp, &req, &scp);
5652 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5653 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5654 cm_ReleaseSCache(scp);
5655 cm_ReleaseUser(userp);
5656 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5657 return CM_ERROR_PATH_NOT_COVERED;
5659 return CM_ERROR_BADSHARENAME;
5661 #endif /* DFS_SUPPORT */
5664 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
5665 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5666 userp, tidPathp, &req, &dscp);
5668 cm_ReleaseUser(userp);
5673 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5674 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5676 cm_ReleaseSCache(dscp);
5677 cm_ReleaseUser(userp);
5678 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5679 return CM_ERROR_PATH_NOT_COVERED;
5681 return CM_ERROR_BADSHARENAME;
5683 #endif /* DFS_SUPPORT */
5684 /* otherwise, scp points to the parent directory. Do a lookup,
5685 * and truncate the file if we find it, otherwise we create the
5692 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
5694 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5695 cm_ReleaseSCache(dscp);
5696 cm_ReleaseUser(userp);
5701 /* if we get here, if code is 0, the file exists and is represented by
5702 * scp. Otherwise, we have to create it. The dir may be represented
5703 * by dscp, or we may have found the file directly. If code is non-zero,
5707 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
5709 if (dscp) cm_ReleaseSCache(dscp);
5710 cm_ReleaseSCache(scp);
5711 cm_ReleaseUser(userp);
5716 /* oops, file shouldn't be there */
5718 cm_ReleaseSCache(dscp);
5719 cm_ReleaseSCache(scp);
5720 cm_ReleaseUser(userp);
5721 return CM_ERROR_EXISTS;
5725 setAttr.mask = CM_ATTRMASK_LENGTH;
5726 setAttr.length.LowPart = 0;
5727 setAttr.length.HighPart = 0;
5728 code = cm_SetAttr(scp, &setAttr, userp, &req);
5729 openAction = 3; /* truncated existing file */
5731 else openAction = 1; /* found existing file */
5733 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
5734 /* don't create if not found */
5735 if (dscp) cm_ReleaseSCache(dscp);
5736 cm_ReleaseUser(userp);
5737 return CM_ERROR_NOSUCHFILE;
5740 osi_assertx(dscp != NULL, "null cm_scache_t");
5741 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %S",
5742 osi_LogSaveClientString(smb_logp, lastNamep));
5743 openAction = 2; /* created file */
5744 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5745 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5746 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5750 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5751 smb_NotifyChange(FILE_ACTION_ADDED,
5752 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5753 dscp, lastNamep, NULL, TRUE);
5754 } else if (!excl && code == CM_ERROR_EXISTS) {
5755 /* not an exclusive create, and someone else tried
5756 * creating it already, then we open it anyway. We
5757 * don't bother retrying after this, since if this next
5758 * fails, that means that the file was deleted after we
5759 * started this call.
5761 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5765 setAttr.mask = CM_ATTRMASK_LENGTH;
5766 setAttr.length.LowPart = 0;
5767 setAttr.length.HighPart = 0;
5768 code = cm_SetAttr(scp, &setAttr, userp, &req);
5770 } /* lookup succeeded */
5774 /* we don't need this any longer */
5776 cm_ReleaseSCache(dscp);
5779 /* something went wrong creating or truncating the file */
5781 cm_ReleaseSCache(scp);
5782 cm_ReleaseUser(userp);
5786 /* make sure we're about to open a file */
5787 if (scp->fileType != CM_SCACHETYPE_FILE) {
5788 cm_ReleaseSCache(scp);
5789 cm_ReleaseUser(userp);
5790 return CM_ERROR_ISDIR;
5793 /* now all we have to do is open the file itself */
5794 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5795 osi_assertx(fidp, "null smb_fid_t");
5798 lock_ObtainMutex(&fidp->mx);
5799 /* save a pointer to the vnode */
5801 lock_ObtainWrite(&scp->rw);
5802 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5803 lock_ReleaseWrite(&scp->rw);
5804 osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
5806 fidp->userp = userp;
5808 /* compute open mode */
5810 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5811 if (openMode == 1 || openMode == 2)
5812 fidp->flags |= SMB_FID_OPENWRITE;
5814 /* remember if the file was newly created */
5816 fidp->flags |= SMB_FID_CREATED;
5818 lock_ReleaseMutex(&fidp->mx);
5819 smb_ReleaseFID(fidp);
5821 cm_Open(scp, 0, userp);
5823 /* set inp->fid so that later read calls in same msg can find fid */
5824 inp->fid = fidp->fid;
5826 /* copy out remainder of the parms */
5828 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5829 lock_ObtainRead(&scp->rw);
5831 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5832 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5833 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5834 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5835 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5836 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5837 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5838 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5839 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5841 /* and the final "always present" stuff */
5842 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5843 /* next write out the "unique" ID */
5844 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5845 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5846 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5847 lock_ReleaseRead(&scp->rw);
5848 smb_SetSMBDataLength(outp, 0);
5850 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5852 cm_ReleaseUser(userp);
5853 /* leave scp held since we put it in fidp->scp */
5857 static void smb_GetLockParams(unsigned char LockType,
5859 unsigned int * ppid,
5860 LARGE_INTEGER * pOffset,
5861 LARGE_INTEGER * pLength)
5863 if (LockType & LOCKING_ANDX_LARGE_FILES) {
5865 *ppid = *((USHORT *) *buf);
5866 pOffset->HighPart = *((LONG *)(*buf + 4));
5867 pOffset->LowPart = *((DWORD *)(*buf + 8));
5868 pLength->HighPart = *((LONG *)(*buf + 12));
5869 pLength->LowPart = *((DWORD *)(*buf + 16));
5873 /* Not Large Files */
5874 *ppid = *((USHORT *) *buf);
5875 pOffset->HighPart = 0;
5876 pOffset->LowPart = *((DWORD *)(*buf + 2));
5877 pLength->HighPart = 0;
5878 pLength->LowPart = *((DWORD *)(*buf + 6));
5883 /* SMB_COM_LOCKING_ANDX */
5884 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5891 unsigned char LockType;
5892 unsigned short NumberOfUnlocks, NumberOfLocks;
5896 LARGE_INTEGER LOffset, LLength;
5897 smb_waitingLockRequest_t *wlRequest = NULL;
5898 cm_file_lock_t *lockp;
5906 fid = smb_GetSMBParm(inp, 2);
5907 fid = smb_ChainFID(fid, inp);
5909 fidp = smb_FindFID(vcp, fid, 0);
5911 return CM_ERROR_BADFD;
5913 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
5914 smb_CloseFID(vcp, fidp, NULL, 0);
5915 smb_ReleaseFID(fidp);
5916 return CM_ERROR_NOSUCHFILE;
5919 lock_ObtainMutex(&fidp->mx);
5920 if (fidp->flags & SMB_FID_IOCTL) {
5921 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
5922 lock_ReleaseMutex(&fidp->mx);
5923 smb_ReleaseFID(fidp);
5924 return CM_ERROR_BADFD;
5927 osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
5929 lock_ReleaseMutex(&fidp->mx);
5931 /* set inp->fid so that later read calls in same msg can find fid */
5934 userp = smb_GetUserFromVCP(vcp, inp);
5937 lock_ObtainWrite(&scp->rw);
5938 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5939 CM_SCACHESYNC_NEEDCALLBACK
5940 | CM_SCACHESYNC_GETSTATUS
5941 | CM_SCACHESYNC_LOCK);
5943 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
5947 LockType = smb_GetSMBParm(inp, 3) & 0xff;
5948 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
5949 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
5950 NumberOfLocks = smb_GetSMBParm(inp, 7);
5952 if (!(fidp->flags & SMB_FID_OPENWRITE) &&
5953 !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
5954 /* somebody wants exclusive locks on a file that they only
5955 opened for reading. We downgrade this to a shared lock. */
5956 osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
5957 LockType |= LOCKING_ANDX_SHARED_LOCK;
5960 if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
5961 /* AFS does not support atomic changes of lock types from read or write and vice-versa */
5962 osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]");
5963 code = CM_ERROR_BADOP;
5968 op = smb_GetSMBData(inp, NULL);
5970 if (LockType & LOCKING_ANDX_CANCEL_LOCK) {
5971 /* Cancel outstanding lock requests */
5972 smb_waitingLock_t * wl;
5974 for (i=0; i<NumberOfLocks; i++) {
5975 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5977 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5979 lock_ObtainWrite(&smb_globalLock);
5980 for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
5982 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
5983 if (wl->key == key && LargeIntegerEqualTo(wl->LOffset, LOffset) &&
5984 LargeIntegerEqualTo(wl->LLength, LLength)) {
5985 wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
5986 goto found_lock_request;
5991 lock_ReleaseWrite(&smb_globalLock);
5994 smb_SetSMBDataLength(outp, 0);
5999 for (i=0; i<NumberOfUnlocks; i++) {
6000 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6002 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6004 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
6012 for (i=0; i<NumberOfLocks; i++) {
6013 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6015 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6017 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
6018 userp, &req, &lockp);
6020 if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
6021 (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
6023 code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
6024 userp, &req, &lockp);
6027 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
6028 smb_waitingLock_t * wLock;
6030 /* Put on waiting list */
6031 if(wlRequest == NULL) {
6035 LARGE_INTEGER tOffset, tLength;
6037 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
6039 osi_assertx(wlRequest != NULL, "null wlRequest");
6041 wlRequest->vcp = vcp;
6043 wlRequest->scp = scp;
6044 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
6046 wlRequest->inp = smb_CopyPacket(inp);
6047 wlRequest->outp = smb_CopyPacket(outp);
6048 wlRequest->lockType = LockType;
6049 wlRequest->msTimeout = Timeout;
6050 wlRequest->start_t = osi_Time();
6051 wlRequest->locks = NULL;
6053 /* The waiting lock request needs to have enough
6054 information to undo all the locks in the request.
6055 We do the following to store info about locks that
6056 have already been granted. Sure, we can get most
6057 of the info from the packet, but the packet doesn't
6058 hold the result of cm_Lock call. In practice we
6059 only receive packets with one or two locks, so we
6060 are only wasting a few bytes here and there and
6061 only for a limited period of time until the waiting
6062 lock times out or is freed. */
6064 for(opt = op_locks, j=i; j > 0; j--) {
6065 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
6067 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6069 wLock = malloc(sizeof(smb_waitingLock_t));
6071 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6074 wLock->LOffset = tOffset;
6075 wLock->LLength = tLength;
6076 wLock->lockp = NULL;
6077 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
6078 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6083 wLock = malloc(sizeof(smb_waitingLock_t));
6085 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6088 wLock->LOffset = LOffset;
6089 wLock->LLength = LLength;
6090 wLock->lockp = lockp;
6091 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
6092 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6095 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
6103 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
6110 /* Since something went wrong with the lock number i, we now
6111 have to go ahead and release any locks acquired before the
6112 failure. All locks before lock number i (of which there
6113 are i of them) have either been successful or are waiting.
6114 Either case requires calling cm_Unlock(). */
6116 /* And purge the waiting lock */
6117 if(wlRequest != NULL) {
6118 smb_waitingLock_t * wl;
6119 smb_waitingLock_t * wlNext;
6122 for(wl = wlRequest->locks; wl; wl = wlNext) {
6124 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
6126 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
6129 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
6131 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
6134 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
6139 smb_ReleaseVC(wlRequest->vcp);
6140 cm_ReleaseSCache(wlRequest->scp);
6141 smb_FreePacket(wlRequest->inp);
6142 smb_FreePacket(wlRequest->outp);
6151 if (wlRequest != NULL) {
6153 lock_ObtainWrite(&smb_globalLock);
6154 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
6156 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
6157 lock_ReleaseWrite(&smb_globalLock);
6159 /* don't send reply immediately */
6160 outp->flags |= SMB_PACKETFLAG_NOSEND;
6163 smb_SetSMBDataLength(outp, 0);
6167 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
6170 lock_ReleaseWrite(&scp->rw);
6171 cm_ReleaseSCache(scp);
6172 cm_ReleaseUser(userp);
6173 smb_ReleaseFID(fidp);
6178 /* SMB_COM_QUERY_INFORMATION2 */
6179 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6185 afs_uint32 searchTime;
6192 fid = smb_GetSMBParm(inp, 0);
6193 fid = smb_ChainFID(fid, inp);
6195 fidp = smb_FindFID(vcp, fid, 0);
6197 return CM_ERROR_BADFD;
6199 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6200 smb_CloseFID(vcp, fidp, NULL, 0);
6201 smb_ReleaseFID(fidp);
6202 return CM_ERROR_NOSUCHFILE;
6205 lock_ObtainMutex(&fidp->mx);
6206 if (fidp->flags & SMB_FID_IOCTL) {
6207 lock_ReleaseMutex(&fidp->mx);
6208 smb_ReleaseFID(fidp);
6209 return CM_ERROR_BADFD;
6212 osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6214 lock_ReleaseMutex(&fidp->mx);
6216 userp = smb_GetUserFromVCP(vcp, inp);
6219 /* otherwise, stat the file */
6220 lock_ObtainWrite(&scp->rw);
6221 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6222 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6226 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6228 lock_ConvertWToR(&scp->rw);
6230 /* decode times. We need a search time, but the response to this
6231 * call provides the date first, not the time, as returned in the
6232 * searchTime variable. So we take the high-order bits first.
6234 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
6235 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
6236 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
6237 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
6238 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
6239 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
6240 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
6242 /* now handle file size and allocation size */
6243 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
6244 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
6245 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
6246 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
6248 /* file attribute */
6249 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
6251 /* and finalize stuff */
6252 smb_SetSMBDataLength(outp, 0);
6257 lock_ReleaseRead(&scp->rw);
6259 lock_ReleaseWrite(&scp->rw);
6260 cm_ReleaseSCache(scp);
6261 cm_ReleaseUser(userp);
6262 smb_ReleaseFID(fidp);
6266 /* SMB_COM_SET_INFORMATION2 */
6267 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6273 afs_uint32 searchTime;
6281 fid = smb_GetSMBParm(inp, 0);
6282 fid = smb_ChainFID(fid, inp);
6284 fidp = smb_FindFID(vcp, fid, 0);
6286 return CM_ERROR_BADFD;
6288 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6289 smb_CloseFID(vcp, fidp, NULL, 0);
6290 smb_ReleaseFID(fidp);
6291 return CM_ERROR_NOSUCHFILE;
6294 lock_ObtainMutex(&fidp->mx);
6295 if (fidp->flags & SMB_FID_IOCTL) {
6296 lock_ReleaseMutex(&fidp->mx);
6297 smb_ReleaseFID(fidp);
6298 return CM_ERROR_BADFD;
6301 osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6303 lock_ReleaseMutex(&fidp->mx);
6305 userp = smb_GetUserFromVCP(vcp, inp);
6308 /* now prepare to call cm_setattr. This message only sets various times,
6309 * and AFS only implements mtime, and we'll set the mtime if that's
6310 * requested. The others we'll ignore.
6312 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
6314 if (searchTime != 0) {
6315 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
6317 if ( unixTime != -1 ) {
6318 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
6319 attrs.clientModTime = unixTime;
6320 code = cm_SetAttr(scp, &attrs, userp, &req);
6322 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
6324 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
6330 cm_ReleaseSCache(scp);
6331 cm_ReleaseUser(userp);
6332 smb_ReleaseFID(fidp);
6336 /* SMB_COM_WRITE_ANDX */
6337 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6340 long count, written = 0, total_written = 0;
6344 smb_t *smbp = (smb_t*) inp;
6348 int inDataBlockCount;
6350 fd = smb_GetSMBParm(inp, 2);
6351 count = smb_GetSMBParm(inp, 10);
6353 offset.HighPart = 0;
6354 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6356 if (*inp->wctp == 14) {
6357 /* we have a request with 64-bit file offsets */
6358 #ifdef AFS_LARGEFILES
6359 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6361 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6363 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
6364 /* we shouldn't have received this op if we didn't specify
6365 largefile support */
6366 return CM_ERROR_BADOP;
6371 op = inp->data + smb_GetSMBParm(inp, 11);
6372 inDataBlockCount = count;
6374 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
6375 fd, offset.HighPart, offset.LowPart, count);
6377 fd = smb_ChainFID(fd, inp);
6378 fidp = smb_FindFID(vcp, fd, 0);
6380 return CM_ERROR_BADFD;
6382 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6383 smb_CloseFID(vcp, fidp, NULL, 0);
6384 smb_ReleaseFID(fidp);
6385 return CM_ERROR_NOSUCHFILE;
6388 lock_ObtainMutex(&fidp->mx);
6389 if (fidp->flags & SMB_FID_IOCTL) {
6390 lock_ReleaseMutex(&fidp->mx);
6391 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
6392 smb_ReleaseFID(fidp);
6395 lock_ReleaseMutex(&fidp->mx);
6396 userp = smb_GetUserFromVCP(vcp, inp);
6398 /* special case: 0 bytes transferred means there is no data
6399 transferred. A slight departure from SMB_COM_WRITE where this
6400 means that we are supposed to truncate the file at this
6405 LARGE_INTEGER LOffset;
6406 LARGE_INTEGER LLength;
6410 key = cm_GenerateKey(vcp->vcID, pid, fd);
6412 LOffset.HighPart = offset.HighPart;
6413 LOffset.LowPart = offset.LowPart;
6414 LLength.HighPart = 0;
6415 LLength.LowPart = count;
6418 lock_ObtainWrite(&scp->rw);
6419 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
6420 lock_ReleaseWrite(&scp->rw);
6427 * Work around bug in NT client
6429 * When copying a file, the NT client should first copy the data,
6430 * then copy the last write time. But sometimes the NT client does
6431 * these in the wrong order, so the data copies would inadvertently
6432 * cause the last write time to be overwritten. We try to detect this,
6433 * and don't set client mod time if we think that would go against the
6436 lock_ObtainMutex(&fidp->mx);
6437 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6438 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6439 fidp->scp->clientModTime = time(NULL);
6441 lock_ReleaseMutex(&fidp->mx);
6444 while ( code == 0 && count > 0 ) {
6445 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6446 if (code == 0 && written == 0)
6447 code = CM_ERROR_PARTIALWRITE;
6449 offset = LargeIntegerAdd(offset,
6450 ConvertLongToLargeInteger(written));
6452 total_written += written;
6456 /* slots 0 and 1 are reserved for request chaining and will be
6457 filled in when we return. */
6458 smb_SetSMBParm(outp, 2, total_written);
6459 smb_SetSMBParm(outp, 3, 0); /* reserved */
6460 smb_SetSMBParm(outp, 4, 0); /* reserved */
6461 smb_SetSMBParm(outp, 5, 0); /* reserved */
6462 smb_SetSMBDataLength(outp, 0);
6465 cm_ReleaseUser(userp);
6466 smb_ReleaseFID(fidp);
6471 /* SMB_COM_READ_ANDX */
6472 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6476 long finalCount = 0;
6480 smb_t *smbp = (smb_t*) inp;
6486 fd = smb_GetSMBParm(inp, 2);
6487 count = smb_GetSMBParm(inp, 5);
6488 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6490 if (*inp->wctp == 12) {
6491 /* a request with 64-bit offsets */
6492 #ifdef AFS_LARGEFILES
6493 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
6495 if (LargeIntegerLessThanZero(offset)) {
6496 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
6497 offset.HighPart, offset.LowPart);
6498 return CM_ERROR_BADSMB;
6501 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
6502 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
6503 return CM_ERROR_BADSMB;
6505 offset.HighPart = 0;
6509 offset.HighPart = 0;
6512 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
6513 fd, offset.HighPart, offset.LowPart, count);
6515 fd = smb_ChainFID(fd, inp);
6516 fidp = smb_FindFID(vcp, fd, 0);
6518 return CM_ERROR_BADFD;
6521 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6522 smb_CloseFID(vcp, fidp, NULL, 0);
6523 smb_ReleaseFID(fidp);
6524 return CM_ERROR_NOSUCHFILE;
6528 key = cm_GenerateKey(vcp->vcID, pid, fd);
6530 LARGE_INTEGER LOffset, LLength;
6533 LOffset.HighPart = offset.HighPart;
6534 LOffset.LowPart = offset.LowPart;
6535 LLength.HighPart = 0;
6536 LLength.LowPart = count;
6539 lock_ObtainWrite(&scp->rw);
6540 code = cm_LockCheckRead(scp, LOffset, LLength, key);
6541 lock_ReleaseWrite(&scp->rw);
6545 smb_ReleaseFID(fidp);
6549 /* set inp->fid so that later read calls in same msg can find fid */
6552 lock_ObtainMutex(&fidp->mx);
6553 if (fidp->flags & SMB_FID_IOCTL) {
6554 lock_ReleaseMutex(&fidp->mx);
6555 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
6556 smb_ReleaseFID(fidp);
6559 lock_ReleaseMutex(&fidp->mx);
6561 userp = smb_GetUserFromVCP(vcp, inp);
6563 /* 0 and 1 are reserved for request chaining, were setup by our caller,
6564 * and will be further filled in after we return.
6566 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
6567 smb_SetSMBParm(outp, 3, 0); /* resvd */
6568 smb_SetSMBParm(outp, 4, 0); /* resvd */
6569 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
6570 /* fill in #6 when we have all the parameters' space reserved */
6571 smb_SetSMBParm(outp, 7, 0); /* resv'd */
6572 smb_SetSMBParm(outp, 8, 0); /* resv'd */
6573 smb_SetSMBParm(outp, 9, 0); /* resv'd */
6574 smb_SetSMBParm(outp, 10, 0); /* resv'd */
6575 smb_SetSMBParm(outp, 11, 0); /* reserved */
6577 /* get op ptr after putting in the parms, since otherwise we don't
6578 * know where the data really is.
6580 op = smb_GetSMBData(outp, NULL);
6582 /* now fill in offset from start of SMB header to first data byte (to op) */
6583 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
6585 /* set the packet data length the count of the # of bytes */
6586 smb_SetSMBDataLength(outp, count);
6588 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6590 /* fix some things up */
6591 smb_SetSMBParm(outp, 5, finalCount);
6592 smb_SetSMBDataLength(outp, finalCount);
6594 cm_ReleaseUser(userp);
6595 smb_ReleaseFID(fidp);
6600 * Values for createDisp, copied from NTDDK.H
6602 #define FILE_SUPERSEDE 0 // (???)
6603 #define FILE_OPEN 1 // (open)
6604 #define FILE_CREATE 2 // (exclusive)
6605 #define FILE_OPEN_IF 3 // (non-exclusive)
6606 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
6607 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
6610 #define REQUEST_OPLOCK 2
6611 #define REQUEST_BATCH_OPLOCK 4
6612 #define OPEN_DIRECTORY 8
6613 #define EXTENDED_RESPONSE_REQUIRED 0x10
6615 /* CreateOptions field. */
6616 #define FILE_DIRECTORY_FILE 0x0001
6617 #define FILE_WRITE_THROUGH 0x0002
6618 #define FILE_SEQUENTIAL_ONLY 0x0004
6619 #define FILE_NON_DIRECTORY_FILE 0x0040
6620 #define FILE_NO_EA_KNOWLEDGE 0x0200
6621 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
6622 #define FILE_RANDOM_ACCESS 0x0800
6623 #define FILE_DELETE_ON_CLOSE 0x1000
6624 #define FILE_OPEN_BY_FILE_ID 0x2000
6626 /* SMB_COM_NT_CREATE_ANDX */
6627 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6629 clientchar_t *pathp, *realPathp;
6633 cm_scache_t *dscp; /* parent dir */
6634 cm_scache_t *scp; /* file to create or open */
6635 cm_scache_t *targetScp; /* if scp is a symlink */
6637 clientchar_t *lastNamep;
6638 clientchar_t *treeStartp;
6639 unsigned short nameLength;
6641 unsigned int requestOpLock;
6642 unsigned int requestBatchOpLock;
6643 unsigned int mustBeDir;
6644 unsigned int extendedRespRequired;
6645 unsigned int treeCreate;
6647 unsigned int desiredAccess;
6648 unsigned int extAttributes;
6649 unsigned int createDisp;
6650 unsigned int createOptions;
6651 unsigned int shareAccess;
6652 int initialModeBits;
6653 unsigned short baseFid;
6654 smb_fid_t *baseFidp;
6656 cm_scache_t *baseDirp;
6657 unsigned short openAction;
6662 clientchar_t *tidPathp;
6666 cm_lock_data_t *ldp = NULL;
6670 /* This code is very long and has a lot of if-then-else clauses
6671 * scp and dscp get reused frequently and we need to ensure that
6672 * we don't lose a reference. Start by ensuring that they are NULL.
6679 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
6680 flags = smb_GetSMBOffsetParm(inp, 3, 1)
6681 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
6682 requestOpLock = flags & REQUEST_OPLOCK;
6683 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6684 mustBeDir = flags & OPEN_DIRECTORY;
6685 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6688 * Why all of a sudden 32-bit FID?
6689 * We will reject all bits higher than 16.
6691 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
6692 return CM_ERROR_INVAL;
6693 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
6694 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
6695 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6696 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
6697 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
6698 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
6699 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
6700 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
6701 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
6702 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
6703 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
6705 /* mustBeDir is never set; createOptions directory bit seems to be
6708 if (createOptions & FILE_DIRECTORY_FILE)
6710 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6716 * compute initial mode bits based on read-only flag in
6717 * extended attributes
6719 initialModeBits = 0666;
6720 if (extAttributes & SMB_ATTR_READONLY)
6721 initialModeBits &= ~0222;
6723 pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
6724 NULL, SMB_STRF_ANSIPATH);
6726 /* Sometimes path is not null-terminated, so we make a copy. */
6727 realPathp = malloc(nameLength+sizeof(clientchar_t));
6728 memcpy(realPathp, pathp, nameLength+sizeof(clientchar_t));
6729 realPathp[nameLength/sizeof(clientchar_t)] = 0;
6731 spacep = inp->spacep;
6732 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
6734 osi_Log1(smb_logp,"NTCreateX for [%S]",osi_LogSaveClientString(smb_logp,realPathp));
6735 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
6736 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%S]", shareAccess, flags, osi_LogSaveClientString(smb_logp,(lastNamep?lastNamep:_C("null"))));
6739 (cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
6740 cm_ClientStrCmpIA(lastNamep, _C("\\srvsvc")) == 0 ||
6741 cm_ClientStrCmpIA(lastNamep, _C("\\wkssvc")) == 0 ||
6742 cm_ClientStrCmpIA(lastNamep, _C("ipc$")) == 0)) {
6743 /* special case magic file name for receiving IOCTL requests
6744 * (since IOCTL calls themselves aren't getting through).
6746 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6747 smb_SetupIoctlFid(fidp, spacep);
6748 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
6750 /* set inp->fid so that later read calls in same msg can find fid */
6751 inp->fid = fidp->fid;
6755 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6756 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6757 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
6759 memset(&ft, 0, sizeof(ft));
6760 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6761 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6762 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6763 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6764 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
6765 sz.HighPart = 0x7fff; sz.LowPart = 0;
6766 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
6767 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
6768 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6769 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6770 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
6771 smb_SetSMBDataLength(outp, 0);
6773 /* clean up fid reference */
6774 smb_ReleaseFID(fidp);
6779 #ifdef DEBUG_VERBOSE
6781 char *hexp, *asciip;
6782 asciip = (lastNamep? lastNamep : realPathp);
6783 hexp = osi_HexifyString( asciip );
6784 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
6789 userp = smb_GetUserFromVCP(vcp, inp);
6791 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
6793 return CM_ERROR_INVAL;
6798 baseDirp = cm_data.rootSCachep;
6799 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6800 if (code == CM_ERROR_TIDIPC) {
6801 /* Attempt to use a TID allocated for IPC. The client
6802 * is probably looking for DCE RPC end points which we
6803 * don't support OR it could be looking to make a DFS
6806 osi_Log0(smb_logp, "NTCreateX received IPC TID");
6809 cm_ReleaseUser(userp);
6810 return CM_ERROR_NOSUCHFILE;
6811 #endif /* DFS_SUPPORT */
6814 baseFidp = smb_FindFID(vcp, baseFid, 0);
6816 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
6818 cm_ReleaseUser(userp);
6819 return CM_ERROR_INVAL;
6822 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6824 cm_ReleaseUser(userp);
6825 smb_CloseFID(vcp, baseFidp, NULL, 0);
6826 smb_ReleaseFID(baseFidp);
6827 return CM_ERROR_NOSUCHPATH;
6830 baseDirp = baseFidp->scp;
6834 osi_Log1(smb_logp, "NTCreateX tidPathp=[%S]", (tidPathp==NULL)?_C("null"): osi_LogSaveClientString(smb_logp,tidPathp));
6836 /* compute open mode */
6838 if (desiredAccess & DELETE)
6839 fidflags |= SMB_FID_OPENDELETE;
6840 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
6841 fidflags |= SMB_FID_OPENREAD_LISTDIR;
6842 if (desiredAccess & AFS_ACCESS_WRITE)
6843 fidflags |= SMB_FID_OPENWRITE;
6844 if (createOptions & FILE_DELETE_ON_CLOSE)
6845 fidflags |= SMB_FID_DELONCLOSE;
6846 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6847 fidflags |= SMB_FID_SEQUENTIAL;
6848 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6849 fidflags |= SMB_FID_RANDOM;
6850 if (smb_IsExecutableFileName(lastNamep))
6851 fidflags |= SMB_FID_EXECUTABLE;
6853 /* and the share mode */
6854 if (shareAccess & FILE_SHARE_READ)
6855 fidflags |= SMB_FID_SHARE_READ;
6856 if (shareAccess & FILE_SHARE_WRITE)
6857 fidflags |= SMB_FID_SHARE_WRITE;
6859 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
6862 /* For an exclusive create, we want to do a case sensitive match for the last component. */
6863 if ( createDisp == FILE_CREATE ||
6864 createDisp == FILE_OVERWRITE ||
6865 createDisp == FILE_OVERWRITE_IF) {
6866 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6867 userp, tidPathp, &req, &dscp);
6870 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6871 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
6873 cm_ReleaseSCache(dscp);
6874 cm_ReleaseUser(userp);
6877 smb_ReleaseFID(baseFidp);
6878 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6879 return CM_ERROR_PATH_NOT_COVERED;
6881 return CM_ERROR_BADSHARENAME;
6883 #endif /* DFS_SUPPORT */
6884 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6886 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
6887 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6888 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6889 if (code == 0 && realDirFlag == 1) {
6890 cm_ReleaseSCache(scp);
6891 cm_ReleaseSCache(dscp);
6892 cm_ReleaseUser(userp);
6895 smb_ReleaseFID(baseFidp);
6896 return CM_ERROR_EXISTS;
6900 /* we have both scp and dscp */
6902 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6903 userp, tidPathp, &req, &scp);
6905 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6906 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
6907 cm_ReleaseSCache(scp);
6908 cm_ReleaseUser(userp);
6911 smb_ReleaseFID(baseFidp);
6912 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6913 return CM_ERROR_PATH_NOT_COVERED;
6915 return CM_ERROR_BADSHARENAME;
6917 #endif /* DFS_SUPPORT */
6918 /* we might have scp but not dscp */
6924 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6925 /* look up parent directory */
6926 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
6927 * the immediate parent. We have to work our way up realPathp until we hit something that we
6931 /* we might or might not have scp */
6937 code = cm_NameI(baseDirp, spacep->wdata,
6938 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6939 userp, tidPathp, &req, &dscp);
6942 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6943 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
6946 cm_ReleaseSCache(scp);
6947 cm_ReleaseSCache(dscp);
6948 cm_ReleaseUser(userp);
6951 smb_ReleaseFID(baseFidp);
6952 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6953 return CM_ERROR_PATH_NOT_COVERED;
6955 return CM_ERROR_BADSHARENAME;
6957 #endif /* DFS_SUPPORT */
6960 (tp = cm_ClientStrRChr(spacep->wdata, '\\')) &&
6961 (createDisp == FILE_CREATE) &&
6962 (realDirFlag == 1)) {
6965 treeStartp = realPathp + (tp - spacep->wdata);
6967 if (*tp && !smb_IsLegalFilename(tp)) {
6968 cm_ReleaseUser(userp);
6970 smb_ReleaseFID(baseFidp);
6973 cm_ReleaseSCache(scp);
6974 return CM_ERROR_BADNTFILENAME;
6978 } while (dscp == NULL && code == 0);
6982 /* we might have scp and we might have dscp */
6985 smb_ReleaseFID(baseFidp);
6988 osi_Log0(smb_logp,"NTCreateX parent not found");
6990 cm_ReleaseSCache(scp);
6992 cm_ReleaseSCache(dscp);
6993 cm_ReleaseUser(userp);
6998 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
6999 /* A file exists where we want a directory. */
7001 cm_ReleaseSCache(scp);
7002 cm_ReleaseSCache(dscp);
7003 cm_ReleaseUser(userp);
7005 return CM_ERROR_EXISTS;
7009 lastNamep = realPathp;
7013 if (!smb_IsLegalFilename(lastNamep)) {
7015 cm_ReleaseSCache(scp);
7017 cm_ReleaseSCache(dscp);
7018 cm_ReleaseUser(userp);
7020 return CM_ERROR_BADNTFILENAME;
7023 if (!foundscp && !treeCreate) {
7024 if ( createDisp == FILE_CREATE ||
7025 createDisp == FILE_OVERWRITE ||
7026 createDisp == FILE_OVERWRITE_IF)
7028 code = cm_Lookup(dscp, lastNamep,
7029 CM_FLAG_FOLLOW, userp, &req, &scp);
7031 code = cm_Lookup(dscp, lastNamep,
7032 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7035 if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
7037 cm_ReleaseSCache(dscp);
7038 cm_ReleaseUser(userp);
7043 /* we have scp and dscp */
7045 /* we have scp but not dscp */
7047 smb_ReleaseFID(baseFidp);
7050 /* if we get here, if code is 0, the file exists and is represented by
7051 * scp. Otherwise, we have to create it. The dir may be represented
7052 * by dscp, or we may have found the file directly. If code is non-zero,
7055 if (code == 0 && !treeCreate) {
7056 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7059 cm_ReleaseSCache(dscp);
7061 cm_ReleaseSCache(scp);
7062 cm_ReleaseUser(userp);
7067 if (createDisp == FILE_CREATE) {
7068 /* oops, file shouldn't be there */
7069 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7071 cm_ReleaseSCache(dscp);
7073 cm_ReleaseSCache(scp);
7074 cm_ReleaseUser(userp);
7076 return CM_ERROR_EXISTS;
7079 if ( createDisp == FILE_OVERWRITE ||
7080 createDisp == FILE_OVERWRITE_IF) {
7082 setAttr.mask = CM_ATTRMASK_LENGTH;
7083 setAttr.length.LowPart = 0;
7084 setAttr.length.HighPart = 0;
7085 /* now watch for a symlink */
7087 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7089 osi_assertx(dscp != NULL, "null cm_scache_t");
7090 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7092 /* we have a more accurate file to use (the
7093 * target of the symbolic link). Otherwise,
7094 * we'll just use the symlink anyway.
7096 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7098 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7099 cm_ReleaseSCache(scp);
7101 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7104 cm_ReleaseSCache(dscp);
7106 cm_ReleaseSCache(scp);
7107 cm_ReleaseUser(userp);
7113 code = cm_SetAttr(scp, &setAttr, userp, &req);
7114 openAction = 3; /* truncated existing file */
7117 openAction = 1; /* found existing file */
7119 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7120 /* don't create if not found */
7122 cm_ReleaseSCache(dscp);
7124 cm_ReleaseSCache(scp);
7125 cm_ReleaseUser(userp);
7127 return CM_ERROR_NOSUCHFILE;
7128 } else if (realDirFlag == 0 || realDirFlag == -1) {
7129 osi_assertx(dscp != NULL, "null cm_scache_t");
7130 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %S",
7131 osi_LogSaveClientString(smb_logp, lastNamep));
7132 openAction = 2; /* created file */
7133 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7134 setAttr.clientModTime = time(NULL);
7135 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
7138 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7139 smb_NotifyChange(FILE_ACTION_ADDED,
7140 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7141 dscp, lastNamep, NULL, TRUE);
7142 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7143 /* Not an exclusive create, and someone else tried
7144 * creating it already, then we open it anyway. We
7145 * don't bother retrying after this, since if this next
7146 * fails, that means that the file was deleted after we
7147 * started this call.
7149 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7152 if (createDisp == FILE_OVERWRITE_IF) {
7153 setAttr.mask = CM_ATTRMASK_LENGTH;
7154 setAttr.length.LowPart = 0;
7155 setAttr.length.HighPart = 0;
7157 /* now watch for a symlink */
7159 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7161 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7163 /* we have a more accurate file to use (the
7164 * target of the symbolic link). Otherwise,
7165 * we'll just use the symlink anyway.
7167 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7169 cm_ReleaseSCache(scp);
7173 code = cm_SetAttr(scp, &setAttr, userp, &req);
7175 } /* lookup succeeded */
7178 clientchar_t *tp, *pp;
7179 clientchar_t *cp; /* This component */
7180 int clen = 0; /* length of component */
7181 cm_scache_t *tscp1, *tscp2;
7184 /* create directory */
7186 treeStartp = lastNamep;
7187 osi_assertx(dscp != NULL, "null cm_scache_t");
7188 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%S]",
7189 osi_LogSaveClientString(smb_logp, treeStartp));
7190 openAction = 2; /* created directory */
7192 /* if the request is to create the root directory
7193 * it will appear as a directory name of the nul-string
7194 * and a code of CM_ERROR_NOSUCHFILE
7196 if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
7197 code = CM_ERROR_EXISTS;
7199 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7200 setAttr.clientModTime = time(NULL);
7205 cm_HoldSCache(tscp1);
7209 tp = cm_ClientStrChr(pp, '\\');
7211 cm_ClientStrCpy(cp, lengthof(spacep->wdata) - (cp - spacep->wdata), pp);
7212 clen = (int)cm_ClientStrLen(cp);
7213 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
7215 clen = (int)(tp - pp);
7216 cm_ClientStrCpyN(cp, lengthof(spacep->wdata) - (cp - spacep->wdata),
7224 continue; /* the supplied path can't have consecutive slashes either , but */
7226 /* cp is the next component to be created. */
7227 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req, NULL);
7228 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
7229 smb_NotifyChange(FILE_ACTION_ADDED,
7230 FILE_NOTIFY_CHANGE_DIR_NAME,
7231 tscp1, cp, NULL, TRUE);
7233 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7234 /* Not an exclusive create, and someone else tried
7235 * creating it already, then we open it anyway. We
7236 * don't bother retrying after this, since if this next
7237 * fails, that means that the file was deleted after we
7238 * started this call.
7240 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
7241 userp, &req, &tscp2);
7246 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
7247 cm_ReleaseSCache(tscp1);
7248 tscp1 = tscp2; /* Newly created directory will be next parent */
7249 /* the hold is transfered to tscp1 from tscp2 */
7254 cm_ReleaseSCache(dscp);
7257 cm_ReleaseSCache(scp);
7260 * if we get here and code == 0, then scp is the last directory created, and dscp is the
7266 /* something went wrong creating or truncating the file */
7268 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7270 cm_ReleaseSCache(scp);
7272 cm_ReleaseSCache(dscp);
7273 cm_ReleaseUser(userp);
7278 /* make sure we have file vs. dir right (only applies for single component case) */
7279 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7280 /* now watch for a symlink */
7282 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7283 cm_scache_t * targetScp = 0;
7284 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7286 /* we have a more accurate file to use (the
7287 * target of the symbolic link). Otherwise,
7288 * we'll just use the symlink anyway.
7290 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
7292 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7293 cm_ReleaseSCache(scp);
7298 if (scp->fileType != CM_SCACHETYPE_FILE) {
7300 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7302 cm_ReleaseSCache(dscp);
7303 cm_ReleaseSCache(scp);
7304 cm_ReleaseUser(userp);
7306 return CM_ERROR_ISDIR;
7310 /* (only applies to single component case) */
7311 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7313 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7314 cm_ReleaseSCache(scp);
7316 cm_ReleaseSCache(dscp);
7317 cm_ReleaseUser(userp);
7319 return CM_ERROR_NOTDIR;
7322 /* open the file itself */
7323 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7324 osi_assertx(fidp, "null smb_fid_t");
7326 /* save a reference to the user */
7328 fidp->userp = userp;
7330 /* If we are restricting sharing, we should do so with a suitable
7332 if (scp->fileType == CM_SCACHETYPE_FILE &&
7333 !(fidflags & SMB_FID_SHARE_WRITE)) {
7335 LARGE_INTEGER LOffset, LLength;
7338 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7339 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7340 LLength.HighPart = 0;
7341 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7343 /* If we are not opening the file for writing, then we don't
7344 try to get an exclusive lock. No one else should be able to
7345 get an exclusive lock on the file anyway, although someone
7346 else can get a shared lock. */
7347 if ((fidflags & SMB_FID_SHARE_READ) ||
7348 !(fidflags & SMB_FID_OPENWRITE)) {
7349 sLockType = LOCKING_ANDX_SHARED_LOCK;
7354 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7356 lock_ObtainWrite(&scp->rw);
7357 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7358 lock_ReleaseWrite(&scp->rw);
7362 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7363 cm_ReleaseSCache(scp);
7365 cm_ReleaseSCache(dscp);
7366 cm_ReleaseUser(userp);
7367 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7368 smb_CloseFID(vcp, fidp, NULL, 0);
7369 smb_ReleaseFID(fidp);
7375 /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
7377 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7379 lock_ObtainMutex(&fidp->mx);
7380 /* save a pointer to the vnode */
7381 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
7382 lock_ObtainWrite(&scp->rw);
7383 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7384 lock_ReleaseWrite(&scp->rw);
7385 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
7387 fidp->flags = fidflags;
7389 /* remember if the file was newly created */
7391 fidp->flags |= SMB_FID_CREATED;
7393 /* save parent dir and pathname for delete or change notification */
7394 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7395 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
7396 fidp->flags |= SMB_FID_NTOPEN;
7397 fidp->NTopen_dscp = dscp;
7399 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
7401 fidp->NTopen_wholepathp = realPathp;
7402 lock_ReleaseMutex(&fidp->mx);
7404 /* we don't need this any longer */
7406 cm_ReleaseSCache(dscp);
7410 cm_Open(scp, 0, userp);
7412 /* set inp->fid so that later read calls in same msg can find fid */
7413 inp->fid = fidp->fid;
7417 lock_ObtainRead(&scp->rw);
7418 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7419 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7420 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7421 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7422 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7423 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7424 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7425 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7426 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7428 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7429 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7430 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
7431 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
7432 smb_SetSMBParmByte(outp, parmSlot,
7433 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7434 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7435 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7436 smb_SetSMBDataLength(outp, 0);
7438 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
7439 LargeIntegerGreaterThanZero(fidp->scp->length) &&
7440 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
7441 cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
7442 fidp->scp->length.LowPart, fidp->scp->length.HighPart,
7445 lock_ReleaseRead(&scp->rw);
7447 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %S", fidp->fid,
7448 osi_LogSaveClientString(smb_logp, realPathp));
7450 cm_ReleaseUser(userp);
7451 smb_ReleaseFID(fidp);
7453 /* Can't free realPathp if we get here since
7454 fidp->NTopen_wholepathp is pointing there */
7456 /* leave scp held since we put it in fidp->scp */
7461 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
7462 * Instead, ultimately, would like to use a subroutine for common code.
7465 /* NT_TRANSACT_CREATE (SMB_COM_NT_TRANSACT) */
7466 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7468 clientchar_t *pathp, *realPathp;
7472 cm_scache_t *dscp; /* parent dir */
7473 cm_scache_t *scp; /* file to create or open */
7474 cm_scache_t *targetScp; /* if scp is a symlink */
7476 clientchar_t *lastNamep;
7477 unsigned long nameLength;
7479 unsigned int requestOpLock;
7480 unsigned int requestBatchOpLock;
7481 unsigned int mustBeDir;
7482 unsigned int extendedRespRequired;
7484 unsigned int desiredAccess;
7485 #ifdef DEBUG_VERBOSE
7486 unsigned int allocSize;
7488 unsigned int shareAccess;
7489 unsigned int extAttributes;
7490 unsigned int createDisp;
7491 #ifdef DEBUG_VERBOSE
7494 unsigned int createOptions;
7495 int initialModeBits;
7496 unsigned short baseFid;
7497 smb_fid_t *baseFidp;
7499 cm_scache_t *baseDirp;
7500 unsigned short openAction;
7504 clientchar_t *tidPathp;
7506 int parmOffset, dataOffset;
7512 cm_lock_data_t *ldp = NULL;
7519 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7520 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7521 parmp = inp->data + parmOffset;
7522 lparmp = (ULONG *) parmp;
7525 requestOpLock = flags & REQUEST_OPLOCK;
7526 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7527 mustBeDir = flags & OPEN_DIRECTORY;
7528 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7531 * Why all of a sudden 32-bit FID?
7532 * We will reject all bits higher than 16.
7534 if (lparmp[1] & 0xFFFF0000)
7535 return CM_ERROR_INVAL;
7536 baseFid = (unsigned short)lparmp[1];
7537 desiredAccess = lparmp[2];
7538 #ifdef DEBUG_VERBOSE
7539 allocSize = lparmp[3];
7540 #endif /* DEBUG_VERSOSE */
7541 extAttributes = lparmp[5];
7542 shareAccess = lparmp[6];
7543 createDisp = lparmp[7];
7544 createOptions = lparmp[8];
7545 #ifdef DEBUG_VERBOSE
7548 nameLength = lparmp[11];
7550 #ifdef DEBUG_VERBOSE
7551 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
7552 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
7553 osi_Log1(smb_logp,"... flags[%x]",flags);
7556 /* mustBeDir is never set; createOptions directory bit seems to be
7559 if (createOptions & FILE_DIRECTORY_FILE)
7561 else if (createOptions & FILE_NON_DIRECTORY_FILE)
7567 * compute initial mode bits based on read-only flag in
7568 * extended attributes
7570 initialModeBits = 0666;
7571 if (extAttributes & SMB_ATTR_READONLY)
7572 initialModeBits &= ~0222;
7574 pathp = smb_ParseStringCch(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
7575 nameLength, NULL, SMB_STRF_ANSIPATH);
7576 /* Sometimes path is not null-terminated, so we make a copy. */
7577 realPathp = malloc((nameLength+1) * sizeof(clientchar_t));
7578 memcpy(realPathp, pathp, nameLength * sizeof(clientchar_t));
7579 realPathp[nameLength] = 0;
7580 spacep = cm_GetSpace();
7581 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
7584 * Nothing here to handle SMB_IOCTL_FILENAME.
7585 * Will add it if necessary.
7588 #ifdef DEBUG_VERBOSE
7590 char *hexp, *asciip;
7591 asciip = (lastNamep? lastNamep : realPathp);
7592 hexp = osi_HexifyString( asciip );
7593 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
7598 userp = smb_GetUserFromVCP(vcp, inp);
7600 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
7602 return CM_ERROR_INVAL;
7607 baseDirp = cm_data.rootSCachep;
7608 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7609 if (code == CM_ERROR_TIDIPC) {
7610 /* Attempt to use a TID allocated for IPC. The client
7611 * is probably looking for DCE RPC end points which we
7612 * don't support OR it could be looking to make a DFS
7615 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
7618 cm_ReleaseUser(userp);
7619 return CM_ERROR_NOSUCHPATH;
7623 baseFidp = smb_FindFID(vcp, baseFid, 0);
7625 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
7627 cm_ReleaseUser(userp);
7628 return CM_ERROR_BADFD;
7631 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7633 cm_ReleaseUser(userp);
7634 smb_CloseFID(vcp, baseFidp, NULL, 0);
7635 smb_ReleaseFID(baseFidp);
7636 return CM_ERROR_NOSUCHPATH;
7639 baseDirp = baseFidp->scp;
7643 /* compute open mode */
7645 if (desiredAccess & DELETE)
7646 fidflags |= SMB_FID_OPENDELETE;
7647 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
7648 fidflags |= SMB_FID_OPENREAD_LISTDIR;
7649 if (desiredAccess & AFS_ACCESS_WRITE)
7650 fidflags |= SMB_FID_OPENWRITE;
7651 if (createOptions & FILE_DELETE_ON_CLOSE)
7652 fidflags |= SMB_FID_DELONCLOSE;
7653 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7654 fidflags |= SMB_FID_SEQUENTIAL;
7655 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7656 fidflags |= SMB_FID_RANDOM;
7657 if (smb_IsExecutableFileName(lastNamep))
7658 fidflags |= SMB_FID_EXECUTABLE;
7660 /* And the share mode */
7661 if (shareAccess & FILE_SHARE_READ)
7662 fidflags |= SMB_FID_SHARE_READ;
7663 if (shareAccess & FILE_SHARE_WRITE)
7664 fidflags |= SMB_FID_SHARE_WRITE;
7668 if ( createDisp == FILE_OPEN ||
7669 createDisp == FILE_OVERWRITE ||
7670 createDisp == FILE_OVERWRITE_IF) {
7671 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7672 userp, tidPathp, &req, &dscp);
7675 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7676 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7677 cm_ReleaseSCache(dscp);
7678 cm_ReleaseUser(userp);
7681 smb_ReleaseFID(baseFidp);
7682 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7683 return CM_ERROR_PATH_NOT_COVERED;
7685 return CM_ERROR_BADSHARENAME;
7687 #endif /* DFS_SUPPORT */
7688 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7690 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7691 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7692 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7693 if (code == 0 && realDirFlag == 1) {
7694 cm_ReleaseSCache(scp);
7695 cm_ReleaseSCache(dscp);
7696 cm_ReleaseUser(userp);
7699 smb_ReleaseFID(baseFidp);
7700 return CM_ERROR_EXISTS;
7706 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7707 userp, tidPathp, &req, &scp);
7709 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7710 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7711 cm_ReleaseSCache(scp);
7712 cm_ReleaseUser(userp);
7715 smb_ReleaseFID(baseFidp);
7716 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7717 return CM_ERROR_PATH_NOT_COVERED;
7719 return CM_ERROR_BADSHARENAME;
7721 #endif /* DFS_SUPPORT */
7727 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7728 /* look up parent directory */
7730 code = cm_NameI(baseDirp, spacep->wdata,
7731 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7732 userp, tidPathp, &req, &dscp);
7734 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7735 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7736 cm_ReleaseSCache(dscp);
7737 cm_ReleaseUser(userp);
7740 smb_ReleaseFID(baseFidp);
7741 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7742 return CM_ERROR_PATH_NOT_COVERED;
7744 return CM_ERROR_BADSHARENAME;
7746 #endif /* DFS_SUPPORT */
7750 cm_FreeSpace(spacep);
7753 smb_ReleaseFID(baseFidp);
7756 cm_ReleaseUser(userp);
7762 lastNamep = realPathp;
7766 if (!smb_IsLegalFilename(lastNamep))
7767 return CM_ERROR_BADNTFILENAME;
7770 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
7771 code = cm_Lookup(dscp, lastNamep,
7772 CM_FLAG_FOLLOW, userp, &req, &scp);
7774 code = cm_Lookup(dscp, lastNamep,
7775 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7778 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7779 cm_ReleaseSCache(dscp);
7780 cm_ReleaseUser(userp);
7787 smb_ReleaseFID(baseFidp);
7788 cm_FreeSpace(spacep);
7791 /* if we get here, if code is 0, the file exists and is represented by
7792 * scp. Otherwise, we have to create it. The dir may be represented
7793 * by dscp, or we may have found the file directly. If code is non-zero,
7797 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7800 cm_ReleaseSCache(dscp);
7801 cm_ReleaseSCache(scp);
7802 cm_ReleaseUser(userp);
7807 if (createDisp == FILE_CREATE) {
7808 /* oops, file shouldn't be there */
7809 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7811 cm_ReleaseSCache(dscp);
7812 cm_ReleaseSCache(scp);
7813 cm_ReleaseUser(userp);
7815 return CM_ERROR_EXISTS;
7818 if (createDisp == FILE_OVERWRITE ||
7819 createDisp == FILE_OVERWRITE_IF) {
7820 setAttr.mask = CM_ATTRMASK_LENGTH;
7821 setAttr.length.LowPart = 0;
7822 setAttr.length.HighPart = 0;
7824 /* now watch for a symlink */
7826 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7828 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7830 /* we have a more accurate file to use (the
7831 * target of the symbolic link). Otherwise,
7832 * we'll just use the symlink anyway.
7834 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7836 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7837 cm_ReleaseSCache(scp);
7839 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7842 cm_ReleaseSCache(dscp);
7844 cm_ReleaseSCache(scp);
7845 cm_ReleaseUser(userp);
7851 code = cm_SetAttr(scp, &setAttr, userp, &req);
7852 openAction = 3; /* truncated existing file */
7854 else openAction = 1; /* found existing file */
7856 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7857 /* don't create if not found */
7859 cm_ReleaseSCache(dscp);
7860 cm_ReleaseUser(userp);
7862 return CM_ERROR_NOSUCHFILE;
7864 else if (realDirFlag == 0 || realDirFlag == -1) {
7865 osi_assertx(dscp != NULL, "null cm_scache_t");
7866 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %S",
7867 osi_LogSaveClientString(smb_logp, lastNamep));
7868 openAction = 2; /* created file */
7869 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7870 setAttr.clientModTime = time(NULL);
7871 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7875 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7876 smb_NotifyChange(FILE_ACTION_ADDED,
7877 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7878 dscp, lastNamep, NULL, TRUE);
7879 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7880 /* Not an exclusive create, and someone else tried
7881 * creating it already, then we open it anyway. We
7882 * don't bother retrying after this, since if this next
7883 * fails, that means that the file was deleted after we
7884 * started this call.
7886 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7889 if (createDisp == FILE_OVERWRITE_IF) {
7890 setAttr.mask = CM_ATTRMASK_LENGTH;
7891 setAttr.length.LowPart = 0;
7892 setAttr.length.HighPart = 0;
7894 /* now watch for a symlink */
7896 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7898 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7900 /* we have a more accurate file to use (the
7901 * target of the symbolic link). Otherwise,
7902 * we'll just use the symlink anyway.
7904 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7906 cm_ReleaseSCache(scp);
7910 code = cm_SetAttr(scp, &setAttr, userp, &req);
7912 } /* lookup succeeded */
7915 /* create directory */
7916 osi_assertx(dscp != NULL, "null cm_scache_t");
7918 "smb_ReceiveNTTranCreate creating directory %S",
7919 osi_LogSaveClientString(smb_logp, lastNamep));
7920 openAction = 2; /* created directory */
7921 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7922 setAttr.clientModTime = time(NULL);
7923 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
7924 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7925 smb_NotifyChange(FILE_ACTION_ADDED,
7926 FILE_NOTIFY_CHANGE_DIR_NAME,
7927 dscp, lastNamep, NULL, TRUE);
7929 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7930 /* Not an exclusive create, and someone else tried
7931 * creating it already, then we open it anyway. We
7932 * don't bother retrying after this, since if this next
7933 * fails, that means that the file was deleted after we
7934 * started this call.
7936 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7942 /* something went wrong creating or truncating the file */
7944 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7946 cm_ReleaseSCache(scp);
7947 cm_ReleaseUser(userp);
7952 /* make sure we have file vs. dir right */
7953 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7954 /* now watch for a symlink */
7956 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7958 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7960 /* we have a more accurate file to use (the
7961 * target of the symbolic link). Otherwise,
7962 * we'll just use the symlink anyway.
7964 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7967 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7968 cm_ReleaseSCache(scp);
7973 if (scp->fileType != CM_SCACHETYPE_FILE) {
7975 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7976 cm_ReleaseSCache(scp);
7977 cm_ReleaseUser(userp);
7979 return CM_ERROR_ISDIR;
7983 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7985 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7986 cm_ReleaseSCache(scp);
7987 cm_ReleaseUser(userp);
7989 return CM_ERROR_NOTDIR;
7992 /* open the file itself */
7993 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7994 osi_assertx(fidp, "null smb_fid_t");
7996 /* save a reference to the user */
7998 fidp->userp = userp;
8000 /* If we are restricting sharing, we should do so with a suitable
8002 if (scp->fileType == CM_SCACHETYPE_FILE &&
8003 !(fidflags & SMB_FID_SHARE_WRITE)) {
8005 LARGE_INTEGER LOffset, LLength;
8008 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8009 LOffset.LowPart = SMB_FID_QLOCK_LOW;
8010 LLength.HighPart = 0;
8011 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8013 /* Similar to what we do in handling NTCreateX. We get a
8014 shared lock if we are only opening the file for reading. */
8015 if ((fidflags & SMB_FID_SHARE_READ) ||
8016 !(fidflags & SMB_FID_OPENWRITE)) {
8017 sLockType = LOCKING_ANDX_SHARED_LOCK;
8022 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8024 lock_ObtainWrite(&scp->rw);
8025 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8026 lock_ReleaseWrite(&scp->rw);
8030 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8031 cm_ReleaseSCache(scp);
8032 cm_ReleaseUser(userp);
8033 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
8034 smb_CloseFID(vcp, fidp, NULL, 0);
8035 smb_ReleaseFID(fidp);
8037 return CM_ERROR_SHARING_VIOLATION;
8041 /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
8043 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8045 lock_ObtainMutex(&fidp->mx);
8046 /* save a pointer to the vnode */
8048 lock_ObtainWrite(&scp->rw);
8049 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8050 lock_ReleaseWrite(&scp->rw);
8051 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
8053 fidp->flags = fidflags;
8055 /* remember if the file was newly created */
8057 fidp->flags |= SMB_FID_CREATED;
8059 /* save parent dir and pathname for deletion or change notification */
8060 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8061 fidp->flags |= SMB_FID_NTOPEN;
8062 fidp->NTopen_dscp = dscp;
8063 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
8065 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
8067 fidp->NTopen_wholepathp = realPathp;
8068 lock_ReleaseMutex(&fidp->mx);
8070 /* we don't need this any longer */
8072 cm_ReleaseSCache(dscp);
8074 cm_Open(scp, 0, userp);
8076 /* set inp->fid so that later read calls in same msg can find fid */
8077 inp->fid = fidp->fid;
8079 /* check whether we are required to send an extended response */
8080 if (!extendedRespRequired) {
8082 parmOffset = 8*4 + 39;
8083 parmOffset += 1; /* pad to 4 */
8084 dataOffset = parmOffset + 70;
8088 /* Total Parameter Count */
8089 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8090 /* Total Data Count */
8091 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8092 /* Parameter Count */
8093 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8094 /* Parameter Offset */
8095 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8096 /* Parameter Displacement */
8097 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8099 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8101 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8102 /* Data Displacement */
8103 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8104 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8105 smb_SetSMBDataLength(outp, 70);
8107 lock_ObtainRead(&scp->rw);
8108 outData = smb_GetSMBData(outp, NULL);
8109 outData++; /* round to get to parmOffset */
8110 *outData = 0; outData++; /* oplock */
8111 *outData = 0; outData++; /* reserved */
8112 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8113 *((ULONG *)outData) = openAction; outData += 4;
8114 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8115 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8116 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8117 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8118 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8119 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8120 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8121 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8122 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8123 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8124 *((USHORT *)outData) = 0; outData += 2; /* dev state */
8125 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8126 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8127 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8128 outData += 2; /* is a dir? */
8131 parmOffset = 8*4 + 39;
8132 parmOffset += 1; /* pad to 4 */
8133 dataOffset = parmOffset + 104;
8137 /* Total Parameter Count */
8138 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8139 /* Total Data Count */
8140 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8141 /* Parameter Count */
8142 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8143 /* Parameter Offset */
8144 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8145 /* Parameter Displacement */
8146 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8148 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8150 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8151 /* Data Displacement */
8152 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8153 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8154 smb_SetSMBDataLength(outp, 105);
8156 lock_ObtainRead(&scp->rw);
8157 outData = smb_GetSMBData(outp, NULL);
8158 outData++; /* round to get to parmOffset */
8159 *outData = 0; outData++; /* oplock */
8160 *outData = 1; outData++; /* response type */
8161 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8162 *((ULONG *)outData) = openAction; outData += 4;
8163 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8164 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8165 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8166 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8167 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8168 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8169 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8170 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8171 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8172 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8173 *((USHORT *)outData) = 0; outData += 2; /* dev state */
8174 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8175 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8176 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8177 outData += 1; /* is a dir? */
8178 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
8179 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
8180 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
8183 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
8184 LargeIntegerGreaterThanZero(fidp->scp->length) &&
8185 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
8186 cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
8187 fidp->scp->length.LowPart, fidp->scp->length.HighPart,
8190 lock_ReleaseRead(&scp->rw);
8192 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
8194 cm_ReleaseUser(userp);
8195 smb_ReleaseFID(fidp);
8197 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
8198 /* leave scp held since we put it in fidp->scp */
8202 /* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
8203 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
8206 smb_packet_t *savedPacketp;
8208 USHORT fid, watchtree;
8212 filter = smb_GetSMBParm(inp, 19) |
8213 (smb_GetSMBParm(inp, 20) << 16);
8214 fid = smb_GetSMBParm(inp, 21);
8215 watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
8217 fidp = smb_FindFID(vcp, fid, 0);
8219 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
8220 return CM_ERROR_BADFD;
8223 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8224 smb_CloseFID(vcp, fidp, NULL, 0);
8225 smb_ReleaseFID(fidp);
8226 return CM_ERROR_NOSUCHFILE;
8229 /* Create a copy of the Directory Watch Packet to use when sending the
8230 * notification if in the future a matching change is detected.
8232 savedPacketp = smb_CopyPacket(inp);
8233 if (vcp != savedPacketp->vcp) {
8235 if (savedPacketp->vcp)
8236 smb_ReleaseVC(savedPacketp->vcp);
8237 savedPacketp->vcp = vcp;
8240 /* Add the watch to the list of events to send notifications for */
8241 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8242 savedPacketp->nextp = smb_Directory_Watches;
8243 smb_Directory_Watches = savedPacketp;
8244 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8247 osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%S\"",
8248 fidp, scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp));
8249 osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
8250 filter, fid, watchtree);
8251 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8252 osi_Log0(smb_logp, " Notify Change File Name");
8253 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8254 osi_Log0(smb_logp, " Notify Change Directory Name");
8255 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8256 osi_Log0(smb_logp, " Notify Change Attributes");
8257 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8258 osi_Log0(smb_logp, " Notify Change Size");
8259 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8260 osi_Log0(smb_logp, " Notify Change Last Write");
8261 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8262 osi_Log0(smb_logp, " Notify Change Last Access");
8263 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8264 osi_Log0(smb_logp, " Notify Change Creation");
8265 if (filter & FILE_NOTIFY_CHANGE_EA)
8266 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8267 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8268 osi_Log0(smb_logp, " Notify Change Security");
8269 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8270 osi_Log0(smb_logp, " Notify Change Stream Name");
8271 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8272 osi_Log0(smb_logp, " Notify Change Stream Size");
8273 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8274 osi_Log0(smb_logp, " Notify Change Stream Write");
8276 lock_ObtainWrite(&scp->rw);
8278 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
8280 scp->flags |= CM_SCACHEFLAG_WATCHED;
8281 lock_ReleaseWrite(&scp->rw);
8282 smb_ReleaseFID(fidp);
8284 outp->flags |= SMB_PACKETFLAG_NOSEND;
8288 unsigned char nullSecurityDesc[36] = {
8289 0x01, /* security descriptor revision */
8290 0x00, /* reserved, should be zero */
8291 0x00, 0x80, /* security descriptor control;
8292 * 0x8000 : self-relative format */
8293 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
8294 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
8295 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
8296 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
8297 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8298 /* "null SID" owner SID */
8299 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
8300 /* "null SID" group SID */
8303 /* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
8304 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8306 int parmOffset, parmCount, dataOffset, dataCount;
8314 ULONG securityInformation;
8316 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8317 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8318 parmp = inp->data + parmOffset;
8319 sparmp = (USHORT *) parmp;
8320 lparmp = (ULONG *) parmp;
8323 securityInformation = lparmp[1];
8325 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
8326 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
8334 parmOffset = 8*4 + 39;
8335 parmOffset += 1; /* pad to 4 */
8337 dataOffset = parmOffset + parmCount;
8341 /* Total Parameter Count */
8342 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8343 /* Total Data Count */
8344 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8345 /* Parameter Count */
8346 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8347 /* Parameter Offset */
8348 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8349 /* Parameter Displacement */
8350 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8352 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8354 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8355 /* Data Displacement */
8356 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8357 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8358 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
8360 outData = smb_GetSMBData(outp, NULL);
8361 outData++; /* round to get to parmOffset */
8362 *((ULONG *)outData) = 36; outData += 4; /* length */
8364 if (maxData >= 36) {
8365 memcpy(outData, nullSecurityDesc, 36);
8369 return CM_ERROR_BUFFERTOOSMALL;
8372 /* SMB_COM_NT_TRANSACT
8374 SMB_COM_NT_TRANSACT_SECONDARY should also be handled here.
8376 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8378 unsigned short function;
8380 function = smb_GetSMBParm(inp, 18);
8382 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
8384 /* We can handle long names */
8385 if (vcp->flags & SMB_VCFLAG_USENT)
8386 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
8389 case 1: /* NT_TRANSACT_CREATE */
8390 return smb_ReceiveNTTranCreate(vcp, inp, outp);
8391 case 2: /* NT_TRANSACT_IOCTL */
8392 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
8394 case 3: /* NT_TRANSACT_SET_SECURITY_DESC */
8395 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
8397 case 4: /* NT_TRANSACT_NOTIFY_CHANGE */
8398 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
8399 case 5: /* NT_TRANSACT_RENAME */
8400 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
8402 case 6: /* NT_TRANSACT_QUERY_SECURITY_DESC */
8403 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
8405 osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
8408 osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
8411 return CM_ERROR_INVAL;
8415 * smb_NotifyChange -- find relevant change notification messages and
8418 * If we don't know the file name (i.e. a callback break), filename is
8419 * NULL, and we return a zero-length list.
8421 * At present there is not a single call to smb_NotifyChange that
8422 * has the isDirectParent parameter set to FALSE.
8424 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
8425 cm_scache_t *dscp, clientchar_t *filename, clientchar_t *otherFilename,
8426 BOOL isDirectParent)
8428 smb_packet_t *watch, *lastWatch, *nextWatch;
8429 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen = 0;
8430 char *outData, *oldOutData;
8434 BOOL twoEntries = FALSE;
8435 ULONG otherNameLen, oldParmCount = 0;
8439 /* Get ready for rename within directory */
8440 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
8442 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
8445 osi_Log4(smb_logp,"in smb_NotifyChange for file [%S] dscp [%p] notification 0x%x parent %d",
8446 osi_LogSaveClientString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
8448 osi_Log0(smb_logp," FILE_ACTION_NONE");
8449 if (action == FILE_ACTION_ADDED)
8450 osi_Log0(smb_logp," FILE_ACTION_ADDED");
8451 if (action == FILE_ACTION_REMOVED)
8452 osi_Log0(smb_logp," FILE_ACTION_REMOVED");
8453 if (action == FILE_ACTION_MODIFIED)
8454 osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
8455 if (action == FILE_ACTION_RENAMED_OLD_NAME)
8456 osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
8457 if (action == FILE_ACTION_RENAMED_NEW_NAME)
8458 osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
8460 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8461 watch = smb_Directory_Watches;
8463 filter = smb_GetSMBParm(watch, 19)
8464 | (smb_GetSMBParm(watch, 20) << 16);
8465 fid = smb_GetSMBParm(watch, 21);
8466 wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
8468 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
8469 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
8472 * Strange hack - bug in NT Client and NT Server that we must emulate?
8474 if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
8475 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
8477 fidp = smb_FindFID(watch->vcp, fid, 0);
8479 osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
8481 watch = watch->nextp;
8485 if (fidp->scp != dscp ||
8486 fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
8487 (filter & notifyFilter) == 0 ||
8488 (!isDirectParent && !wtree))
8490 osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
8491 smb_ReleaseFID(fidp);
8493 watch = watch->nextp;
8496 smb_ReleaseFID(fidp);
8499 "Sending Change Notification for fid %d filter 0x%x wtree %d file %S",
8500 fid, filter, wtree, osi_LogSaveClientString(smb_logp, filename));
8501 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8502 osi_Log0(smb_logp, " Notify Change File Name");
8503 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8504 osi_Log0(smb_logp, " Notify Change Directory Name");
8505 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8506 osi_Log0(smb_logp, " Notify Change Attributes");
8507 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8508 osi_Log0(smb_logp, " Notify Change Size");
8509 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8510 osi_Log0(smb_logp, " Notify Change Last Write");
8511 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8512 osi_Log0(smb_logp, " Notify Change Last Access");
8513 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8514 osi_Log0(smb_logp, " Notify Change Creation");
8515 if (filter & FILE_NOTIFY_CHANGE_EA)
8516 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8517 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8518 osi_Log0(smb_logp, " Notify Change Security");
8519 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8520 osi_Log0(smb_logp, " Notify Change Stream Name");
8521 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8522 osi_Log0(smb_logp, " Notify Change Stream Size");
8523 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8524 osi_Log0(smb_logp, " Notify Change Stream Write");
8526 /* A watch can only be notified once. Remove it from the list */
8527 nextWatch = watch->nextp;
8528 if (watch == smb_Directory_Watches)
8529 smb_Directory_Watches = nextWatch;
8531 lastWatch->nextp = nextWatch;
8533 /* Turn off WATCHED flag in dscp */
8534 lock_ObtainWrite(&dscp->rw);
8536 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8538 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
8539 lock_ReleaseWrite(&dscp->rw);
8541 /* Convert to response packet */
8542 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
8543 #ifdef SEND_CANONICAL_PATHNAMES
8544 ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
8546 ((smb_t *) watch)->wct = 0;
8549 if (filename == NULL) {
8552 nameLen = (ULONG)cm_ClientStrLen(filename);
8553 parmCount = 3*4 + nameLen*2;
8554 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8556 otherNameLen = (ULONG)cm_ClientStrLen(otherFilename);
8557 oldParmCount = parmCount;
8558 parmCount += 3*4 + otherNameLen*2;
8559 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8561 if (maxLen < parmCount)
8562 parmCount = 0; /* not enough room */
8564 parmOffset = 8*4 + 39;
8565 parmOffset += 1; /* pad to 4 */
8566 dataOffset = parmOffset + parmCount;
8570 /* Total Parameter Count */
8571 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8572 /* Total Data Count */
8573 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8574 /* Parameter Count */
8575 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8576 /* Parameter Offset */
8577 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
8578 /* Parameter Displacement */
8579 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8581 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8583 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
8584 /* Data Displacement */
8585 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8586 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
8587 smb_SetSMBDataLength(watch, parmCount + 1);
8589 if (parmCount != 0) {
8590 outData = smb_GetSMBData(watch, NULL);
8591 outData++; /* round to get to parmOffset */
8592 oldOutData = outData;
8593 *((DWORD *)outData) = oldParmCount; outData += 4;
8594 /* Next Entry Offset */
8595 *((DWORD *)outData) = action; outData += 4;
8597 *((DWORD *)outData) = nameLen*2; outData += 4;
8598 /* File Name Length */
8600 smb_UnparseString(watch, outData, filename, NULL, 0);
8604 outData = oldOutData + oldParmCount;
8605 *((DWORD *)outData) = 0; outData += 4;
8606 /* Next Entry Offset */
8607 *((DWORD *)outData) = otherAction; outData += 4;
8609 *((DWORD *)outData) = otherNameLen*2;
8610 outData += 4; /* File Name Length */
8611 smb_UnparseString(watch, outData, otherFilename, NULL, 0);
8616 * If filename is null, we don't know the cause of the
8617 * change notification. We return zero data (see above),
8618 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
8619 * (= 0x010C). We set the error code here by hand, without
8620 * modifying wct and bcc.
8622 if (filename == NULL) {
8623 ((smb_t *) watch)->rcls = 0x0C;
8624 ((smb_t *) watch)->reh = 0x01;
8625 ((smb_t *) watch)->errLow = 0;
8626 ((smb_t *) watch)->errHigh = 0;
8627 /* Set NT Status codes flag */
8628 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8631 smb_SendPacket(watch->vcp, watch);
8632 smb_FreePacket(watch);
8635 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8638 /* SMB_COM_NT_CANCEL */
8639 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8641 unsigned char *replyWctp;
8642 smb_packet_t *watch, *lastWatch;
8643 USHORT fid, watchtree;
8647 osi_Log0(smb_logp, "SMB3 receive NT cancel");
8649 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8650 watch = smb_Directory_Watches;
8652 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
8653 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
8654 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
8655 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
8656 if (watch == smb_Directory_Watches)
8657 smb_Directory_Watches = watch->nextp;
8659 lastWatch->nextp = watch->nextp;
8660 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8662 /* Turn off WATCHED flag in scp */
8663 fid = smb_GetSMBParm(watch, 21);
8664 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
8666 if (vcp != watch->vcp)
8667 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
8670 fidp = smb_FindFID(vcp, fid, 0);
8672 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %S",
8674 (fidp ? osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp) :_C("")));
8677 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
8678 lock_ObtainWrite(&scp->rw);
8680 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8682 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
8683 lock_ReleaseWrite(&scp->rw);
8684 smb_ReleaseFID(fidp);
8686 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
8689 /* assume STATUS32; return 0xC0000120 (CANCELED) */
8690 replyWctp = watch->wctp;
8694 ((smb_t *)watch)->rcls = 0x20;
8695 ((smb_t *)watch)->reh = 0x1;
8696 ((smb_t *)watch)->errLow = 0;
8697 ((smb_t *)watch)->errHigh = 0xC0;
8698 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8699 smb_SendPacket(vcp, watch);
8700 smb_FreePacket(watch);
8704 watch = watch->nextp;
8706 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8712 * NT rename also does hard links.
8715 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
8716 #define RENAME_FLAG_HARD_LINK 0x103
8717 #define RENAME_FLAG_RENAME 0x104
8718 #define RENAME_FLAG_COPY 0x105
8720 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8722 clientchar_t *oldPathp, *newPathp;
8728 attrs = smb_GetSMBParm(inp, 0);
8729 rename_type = smb_GetSMBParm(inp, 1);
8731 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
8732 osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
8733 return CM_ERROR_NOACCESS;
8736 tp = smb_GetSMBData(inp, NULL);
8737 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
8738 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
8740 osi_Log3(smb_logp, "NTRename for [%S]->[%S] type [%s]",
8741 osi_LogSaveClientString(smb_logp, oldPathp),
8742 osi_LogSaveClientString(smb_logp, newPathp),
8743 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
8745 if (rename_type == RENAME_FLAG_RENAME) {
8746 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
8747 } else { /* RENAME_FLAG_HARD_LINK */
8748 code = smb_Link(vcp,inp,oldPathp,newPathp);
8755 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
8758 cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
8760 smb_username_t *unp;
8763 unp = smb_FindUserByName(usern, machine, flags);
8765 lock_ObtainMutex(&unp->mx);
8766 unp->userp = cm_NewUser();
8767 lock_ReleaseMutex(&unp->mx);
8768 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
8770 osi_Log2(smb_logp,"smb_FindCMUserByName Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
8774 smb_ReleaseUsername(unp);