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,
3999 cm_scache_t *targetScp; /* target if scp is a symlink */
4002 unsigned short attr;
4003 unsigned long lattr;
4004 smb_dirListPatch_t *patchp;
4005 smb_dirListPatch_t *npatchp;
4007 afs_int32 mustFake = 0;
4008 clientchar_t path[AFSPATHMAX];
4010 code = cm_FindACLCache(dscp, userp, &rights);
4011 if (code == 0 && !(rights & PRSFS_READ))
4013 else if (code == -1) {
4014 lock_ObtainWrite(&dscp->rw);
4015 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4016 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4017 lock_ReleaseWrite(&dscp->rw);
4018 if (code == CM_ERROR_NOACCESS) {
4026 for(patchp = *dirPatchespp; patchp; patchp =
4027 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4028 cm_ClientStrPrintfN(path, lengthof(path),_C("%s\\%S"),
4029 relPathp ? relPathp : _C(""), patchp->dep->name);
4030 reqp->relPathp = path;
4031 reqp->tidPathp = tidPathp;
4033 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4034 reqp->relPathp = reqp->tidPathp = NULL;
4038 lock_ObtainWrite(&scp->rw);
4040 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
4041 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4042 if (mustFake || code) {
4043 lock_ReleaseWrite(&scp->rw);
4045 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4046 errors in the client. */
4047 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4048 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4050 /* 1969-12-31 23:59:59 +00 */
4051 ft.dwHighDateTime = 0x19DB200;
4052 ft.dwLowDateTime = 0x5BB78980;
4054 /* copy to Creation Time */
4055 fa->creationTime = ft;
4056 fa->lastAccessTime = ft;
4057 fa->lastWriteTime = ft;
4058 fa->lastChangeTime = ft;
4060 switch (scp->fileType) {
4061 case CM_SCACHETYPE_DIRECTORY:
4062 case CM_SCACHETYPE_MOUNTPOINT:
4063 case CM_SCACHETYPE_SYMLINK:
4064 case CM_SCACHETYPE_INVALID:
4065 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4068 /* if we get here we either have a normal file
4069 * or we have a file for which we have never
4070 * received status info. In this case, we can
4071 * check the even/odd value of the entry's vnode.
4072 * even means it is to be treated as a directory
4073 * and odd means it is to be treated as a file.
4075 if (mustFake && (scp->fid.vnode & 0x1))
4076 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4078 fa->extFileAttributes = SMB_ATTR_NORMAL;
4080 /* merge in hidden attribute */
4081 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4082 fa->extFileAttributes |= SMB_ATTR_HIDDEN;
4085 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4087 /* 1969-12-31 23:59:58 +00*/
4088 dosTime = 0xEBBFBF7D;
4090 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4091 fa->lastAccessDateTime = fa->creationDateTime;
4092 fa->lastWriteDateTime = fa->creationDateTime;
4094 /* set the attribute */
4095 switch (scp->fileType) {
4096 case CM_SCACHETYPE_DIRECTORY:
4097 case CM_SCACHETYPE_MOUNTPOINT:
4098 case CM_SCACHETYPE_SYMLINK:
4099 case CM_SCACHETYPE_INVALID:
4100 fa->attributes = SMB_ATTR_DIRECTORY;
4103 /* if we get here we either have a normal file
4104 * or we have a file for which we have never
4105 * received status info. In this case, we can
4106 * check the even/odd value of the entry's vnode.
4107 * even means it is to be treated as a directory
4108 * and odd means it is to be treated as a file.
4110 if (mustFake && (scp->fid.vnode & 0x1))
4111 fa->attributes = SMB_ATTR_DIRECTORY;
4113 fa->attributes = SMB_ATTR_NORMAL;
4115 /* merge in hidden (dot file) attribute */
4116 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4117 fa->attributes |= SMB_ATTR_HIDDEN;
4121 cm_ReleaseSCache(scp);
4125 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4127 /* now watch for a symlink */
4129 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
4130 lock_ReleaseWrite(&scp->rw);
4131 cm_ClientStrPrintfN(path, lengthof(path), _C("%s\\%S"),
4132 relPathp ? relPathp : _C(""), patchp->dep->name);
4133 reqp->relPathp = path;
4134 reqp->tidPathp = tidPathp;
4135 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
4136 reqp->relPathp = reqp->tidPathp = NULL;
4138 /* we have a more accurate file to use (the
4139 * target of the symbolic link). Otherwise,
4140 * we'll just use the symlink anyway.
4142 osi_Log2(smb_logp, "symlink vp %x to vp %x",
4144 cm_ReleaseSCache(scp);
4147 lock_ObtainWrite(&scp->rw);
4150 lock_ConvertWToR(&scp->rw);
4152 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4153 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4156 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4158 fa->creationTime = ft;
4159 fa->lastAccessTime = ft;
4160 fa->lastWriteTime = ft;
4161 fa->lastChangeTime = ft;
4163 /* Use length for both file length and alloc length */
4164 fa->endOfFile = scp->length;
4165 fa->allocationSize = scp->length;
4167 /* Copy attributes */
4168 lattr = smb_ExtAttributes(scp);
4169 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK ||
4170 code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4171 if (lattr == SMB_ATTR_NORMAL)
4172 lattr = SMB_ATTR_DIRECTORY;
4174 lattr |= SMB_ATTR_DIRECTORY;
4176 /* merge in hidden (dot file) attribute */
4177 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4178 if (lattr == SMB_ATTR_NORMAL)
4179 lattr = SMB_ATTR_HIDDEN;
4181 lattr |= SMB_ATTR_HIDDEN;
4184 fa->extFileAttributes = lattr;
4186 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4189 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4191 fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
4192 fa->lastAccessDateTime = fa->creationDateTime;
4193 fa->lastWriteDateTime = fa->creationDateTime;
4195 /* copy out file length and alloc length,
4196 * using the same for both
4198 fa->dataSize = scp->length.LowPart;
4199 fa->allocationSize = scp->length.LowPart;
4201 /* finally copy out attributes as short */
4202 attr = smb_Attributes(scp);
4203 /* merge in hidden (dot file) attribute */
4204 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4205 if (lattr == SMB_ATTR_NORMAL)
4206 lattr = SMB_ATTR_HIDDEN;
4208 lattr |= SMB_ATTR_HIDDEN;
4210 fa->attributes = attr;
4213 lock_ReleaseRead(&scp->rw);
4214 cm_ReleaseSCache(scp);
4217 /* now free the patches */
4218 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4219 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4223 /* and mark the list as empty */
4224 *dirPatchespp = NULL;
4229 /* smb_ReceiveTran2SearchDir implements both
4230 * Tran2_Find_First and Tran2_Find_Next
4232 #define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
4233 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
4234 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
4235 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
4236 #define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
4238 /* this is an optimized handler for T2SearchDir that handles the case
4239 where there are no wildcards in the search path. I.e. an
4240 application is using FindFirst(Ex) to get information about a
4241 single file or directory. It will attempt to do a single lookup.
4242 If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4243 the usual mechanism.
4245 This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4247 TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
4249 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4253 long code = 0, code2 = 0;
4254 clientchar_t *pathp = 0;
4256 smb_dirListPatch_t *dirListPatchesp;
4257 smb_dirListPatch_t *curPatchp;
4258 size_t orbytes; /* # of bytes in this output record */
4259 size_t ohbytes; /* # of bytes, except file name */
4260 size_t onbytes; /* # of bytes in name, incl. term. null */
4261 cm_scache_t *scp = NULL;
4262 cm_scache_t *targetscp = NULL;
4263 cm_user_t *userp = NULL;
4264 char *op; /* output data ptr */
4265 char *origOp; /* original value of op */
4266 cm_space_t *spacep; /* for pathname buffer */
4267 unsigned long maxReturnData; /* max # of return data */
4268 long maxReturnParms; /* max # of return parms */
4269 long bytesInBuffer; /* # data bytes in the output buffer */
4270 clientchar_t *maskp; /* mask part of path */
4274 smb_tran2Packet_t *outp; /* response packet */
4275 clientchar_t *tidPathp = 0;
4277 clientchar_t shortName[13]; /* 8.3 name if needed */
4279 clientchar_t *shortNameEnd;
4280 cm_dirEntry_t * dep = NULL;
4283 void * attrp = NULL;
4284 smb_tran2Find_t * fp;
4289 osi_assertx(p->opcode == 1, "invalid opcode");
4291 /* find first; obtain basic parameters from request */
4293 /* note that since we are going to failover to regular
4294 * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4295 * modify any of the input parameters here. */
4296 attribute = p->parmsp[0];
4297 maxCount = p->parmsp[1];
4298 infoLevel = p->parmsp[3];
4299 searchFlags = p->parmsp[2];
4300 pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4302 maskp = cm_ClientStrRChr(pathp, '\\');
4306 maskp++; /* skip over backslash */
4307 /* track if this is likely to match a lot of entries */
4309 osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%S], mask[%S]",
4310 osi_LogSaveClientString(smb_logp, pathp),
4311 osi_LogSaveClientString(smb_logp, maskp));
4313 switch ( infoLevel ) {
4314 case SMB_INFO_STANDARD:
4316 ohbytes = sizeof(fp->u.FstandardInfo);
4319 case SMB_INFO_QUERY_EA_SIZE:
4320 ohbytes = sizeof(fp->u.FeaSizeInfo);
4321 s = "InfoQueryEaSize";
4324 case SMB_INFO_QUERY_EAS_FROM_LIST:
4325 ohbytes = sizeof(fp->u.FeasFromListInfo);
4326 s = "InfoQueryEasFromList";
4329 case SMB_FIND_FILE_DIRECTORY_INFO:
4330 s = "FindFileDirectoryInfo";
4331 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4334 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4335 s = "FindFileFullDirectoryInfo";
4336 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4339 case SMB_FIND_FILE_NAMES_INFO:
4340 s = "FindFileNamesInfo";
4341 ohbytes = sizeof(fp->u.FfileNamesInfo);
4344 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4345 s = "FindFileBothDirectoryInfo";
4346 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4350 s = "unknownInfoLevel";
4354 osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
4357 "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4358 attribute, infoLevel, maxCount, searchFlags);
4361 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4362 return CM_ERROR_INVAL;
4365 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4366 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4368 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4371 dirListPatchesp = NULL;
4373 maxReturnData = p->maxReturnData;
4374 maxReturnParms = 10; /* return params for findfirst, which
4375 is the only one we handle.*/
4377 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4378 if (maxReturnData > 6000)
4379 maxReturnData = 6000;
4380 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4382 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4385 osi_Log2(smb_logp, "T2SDSingle search dir count %d [%S]",
4386 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4388 /* bail out if request looks bad */
4390 smb_FreeTran2Packet(outp);
4391 return CM_ERROR_BADSMB;
4394 userp = smb_GetTran2User(vcp, p);
4396 osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
4397 smb_FreeTran2Packet(outp);
4398 return CM_ERROR_BADSMB;
4401 /* try to get the vnode for the path name next */
4402 spacep = cm_GetSpace();
4403 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4404 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4406 cm_ReleaseUser(userp);
4407 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4408 smb_FreeTran2Packet(outp);
4412 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4413 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4414 userp, tidPathp, &req, &scp);
4415 cm_FreeSpace(spacep);
4418 cm_ReleaseUser(userp);
4419 smb_SendTran2Error(vcp, p, opx, code);
4420 smb_FreeTran2Packet(outp);
4424 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4425 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4426 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
4427 cm_ReleaseSCache(scp);
4428 cm_ReleaseUser(userp);
4429 if ( WANTS_DFS_PATHNAMES(p) || pnc )
4430 code = CM_ERROR_PATH_NOT_COVERED;
4432 code = CM_ERROR_BADSHARENAME;
4433 smb_SendTran2Error(vcp, p, opx, code);
4434 smb_FreeTran2Packet(outp);
4437 #endif /* DFS_SUPPORT */
4438 osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
4440 /* now do a single case sensitive lookup for the file in question */
4441 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
4443 /* if a case sensitive match failed, we try a case insensitive one
4445 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
4446 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
4449 if (code == 0 && targetscp->fid.vnode == 0) {
4450 cm_ReleaseSCache(targetscp);
4451 code = CM_ERROR_NOSUCHFILE;
4455 /* if we can't find the directory entry, this block will
4456 return CM_ERROR_NOSUCHFILE, which we will pass on to
4457 smb_ReceiveTran2SearchDir(). */
4458 cm_ReleaseSCache(scp);
4459 cm_ReleaseUser(userp);
4460 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4461 smb_SendTran2Error(vcp, p, opx, code);
4464 smb_FreeTran2Packet(outp);
4468 /* now that we have the target in sight, we proceed with filling
4469 up the return data. */
4471 op = origOp = outp->datap;
4474 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4475 /* skip over resume key */
4479 fp = (smb_tran2Find_t *) op;
4481 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4482 && targetscp->fid.vnode != 0
4483 && !cm_Is8Dot3(maskp)) {
4486 dfid.vnode = htonl(targetscp->fid.vnode);
4487 dfid.unique = htonl(targetscp->fid.unique);
4489 cm_Gen8Dot3NameIntW(maskp, &dfid, shortName, &shortNameEnd);
4495 osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %S (%S)",
4496 htonl(targetscp->fid.vnode),
4497 htonl(targetscp->fid.unique),
4498 osi_LogSaveClientString(smb_logp, pathp),
4499 (NeedShortName)? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
4501 /* Eliminate entries that don't match requested attributes */
4502 if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
4503 smb_IsDotFile(maskp)) {
4505 code = CM_ERROR_NOSUCHFILE;
4506 osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
4511 if (!(attribute & SMB_ATTR_DIRECTORY) &&
4512 (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
4513 targetscp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4514 targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
4515 targetscp->fileType == CM_SCACHETYPE_INVALID)) {
4517 code = CM_ERROR_NOSUCHFILE;
4518 osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
4523 /* add header to name & term. null */
4525 smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH);
4526 orbytes = ohbytes + onbytes;
4528 /* now, we round up the record to a 4 byte alignment, and we make
4529 * sure that we have enough room here for even the aligned version
4530 * (so we don't have to worry about an * overflow when we pad
4531 * things out below). That's the reason for the alignment
4534 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4535 align = (4 - (orbytes & 3)) & 3;
4539 if (orbytes + align > maxReturnData) {
4541 /* even though this request is unlikely to succeed with a
4542 failover, we do it anyway. */
4543 code = CM_ERROR_NOSUCHFILE;
4544 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4549 /* this is one of the entries to use: it is not deleted and it
4550 * matches the star pattern we're looking for. Put out the name,
4551 * preceded by its length.
4553 /* First zero everything else */
4554 memset(origOp, 0, orbytes);
4557 smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH);
4559 switch (infoLevel) {
4560 case SMB_INFO_STANDARD:
4561 fp->u.FstandardInfo.fileNameLength = onbytes;
4562 attrp = &fp->u.FstandardInfo.fileAttrs;
4565 case SMB_INFO_QUERY_EA_SIZE:
4566 fp->u.FeaSizeInfo.fileNameLength = onbytes;
4567 attrp = &fp->u.FeaSizeInfo.fileAttrs;
4568 fp->u.FeaSizeInfo.eaSize = 0;
4571 case SMB_INFO_QUERY_EAS_FROM_LIST:
4572 fp->u.FeasFromListInfo.fileNameLength = onbytes;
4573 attrp = &fp->u.FeasFromListInfo.fileAttrs;
4574 fp->u.FeasFromListInfo.eaSize = 0;
4577 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4578 if (NeedShortName) {
4582 nchars = cm_ClientStringToUtf16(shortName, -1,
4583 fp->u.FfileBothDirectoryInfo.shortName,
4584 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
4586 fp->u.FfileBothDirectoryInfo.shortNameLength = (nchars - 1)*sizeof(wchar_t);
4588 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
4589 fp->u.FfileBothDirectoryInfo.reserved = 0;
4591 strcpy(fp->u.FfileBothDirectoryInfo.shortName,
4593 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
4598 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4599 fp->u.FfileFullDirectoryInfo.eaSize = 0;
4602 case SMB_FIND_FILE_DIRECTORY_INFO:
4603 fp->u.FfileDirectoryInfo.nextEntryOffset = 0;
4604 fp->u.FfileDirectoryInfo.fileIndex = 0;
4605 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
4606 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
4609 case SMB_FIND_FILE_NAMES_INFO:
4610 fp->u.FfileNamesInfo.nextEntryOffset = 0;
4611 fp->u.FfileNamesInfo.fileIndex = 0;
4612 fp->u.FfileNamesInfo.fileNameLength = onbytes;
4616 /* we shouldn't hit this case */
4617 osi_assertx(FALSE, "Unknown query type");
4620 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4621 osi_assert(attrp != NULL);
4623 curPatchp = malloc(sizeof(*curPatchp));
4624 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4626 curPatchp->dptr = attrp;
4628 if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
4629 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4631 curPatchp->flags = 0;
4634 cm_SetFid(&curPatchp->fid, targetscp->fid.cell, targetscp->fid.volume, targetscp->fid.vnode, targetscp->fid.unique);
4638 int namelen = cm_ClientStringToFsString(maskp, -1, NULL, 0);
4639 dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+namelen);
4640 cm_ClientStringToFsString(maskp, -1, dep->name, namelen);
4642 dep->fid.vnode = targetscp->fid.vnode;
4643 dep->fid.unique = targetscp->fid.unique;
4644 curPatchp->dep = dep;
4647 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4648 /* put out resume key */
4649 *((u_long *)origOp) = 0;
4652 /* Adjust byte ptr and count */
4653 origOp += orbytes; /* skip entire record */
4654 bytesInBuffer += orbytes;
4656 /* and pad the record out */
4657 while (--align >= 0) {
4662 /* apply the patches */
4663 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->wdata, infoLevel, userp, &req);
4665 outp->parmsp[0] = 0;
4666 outp->parmsp[1] = 1; /* number of names returned */
4667 outp->parmsp[2] = 1; /* end of search */
4668 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4669 outp->parmsp[4] = 0;
4671 outp->totalParms = 10; /* in bytes */
4673 outp->totalData = bytesInBuffer;
4675 osi_Log0(smb_logp, "T2SDSingle done.");
4677 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4679 smb_SendTran2Error(vcp, p, opx, code);
4681 smb_SendTran2Packet(vcp, outp, opx);
4686 smb_FreeTran2Packet(outp);
4690 cm_ReleaseSCache(scp);
4691 cm_ReleaseSCache(targetscp);
4692 cm_ReleaseUser(userp);
4698 /* TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2 */
4699 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4704 long code = 0, code2 = 0;
4705 clientchar_t *pathp;
4706 cm_dirEntry_t *dep = 0;
4708 smb_dirListPatch_t *dirListPatchesp = 0;
4709 smb_dirListPatch_t *curPatchp = 0;
4712 size_t orbytes; /* # of bytes in this output record */
4713 size_t ohbytes; /* # of bytes, except file name */
4714 size_t onbytes; /* # of bytes in name, incl. term. null */
4715 osi_hyper_t dirLength;
4716 osi_hyper_t bufferOffset;
4717 osi_hyper_t curOffset;
4719 smb_dirSearch_t *dsp;
4723 cm_pageHeader_t *pageHeaderp;
4724 cm_user_t *userp = NULL;
4727 long nextEntryCookie;
4728 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4729 char *op; /* output data ptr */
4730 char *origOp; /* original value of op */
4731 cm_space_t *spacep; /* for pathname buffer */
4732 unsigned long maxReturnData; /* max # of return data */
4733 unsigned long maxReturnParms; /* max # of return parms */
4734 long bytesInBuffer; /* # data bytes in the output buffer */
4736 clientchar_t *maskp; /* mask part of path */
4740 smb_tran2Packet_t *outp; /* response packet */
4741 clientchar_t *tidPathp;
4743 clientchar_t shortName[13]; /* 8.3 name if needed */
4746 clientchar_t *shortNameEnd;
4752 smb_tran2Find_t * fp;
4757 if (p->opcode == 1) {
4758 /* find first; obtain basic parameters from request */
4759 attribute = p->parmsp[0];
4760 maxCount = p->parmsp[1];
4761 infoLevel = p->parmsp[3];
4762 searchFlags = p->parmsp[2];
4763 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4765 maskp = cm_ClientStrRChr(pathp, '\\');
4769 maskp++; /* skip over backslash */
4771 /* track if this is likely to match a lot of entries */
4772 starPattern = smb_V3IsStarMask(maskp);
4774 #ifndef NOFINDFIRSTOPTIMIZE
4776 /* if this is for a single directory or file, we let the
4777 optimized routine handle it. The only error it
4778 returns is CM_ERROR_NOSUCHFILE. The */
4779 code = smb_T2SearchDirSingle(vcp, p, opx);
4781 /* we only failover if we see a CM_ERROR_NOSUCHFILE */
4782 if (code != CM_ERROR_NOSUCHFILE) {
4784 /* unless we are using the BPlusTree */
4785 if (code == CM_ERROR_BPLUS_NOMATCH)
4786 code = CM_ERROR_NOSUCHFILE;
4787 #endif /* USE_BPLUS */
4791 #endif /* NOFINDFIRSTOPTIMIZE */
4794 dsp = smb_NewDirSearch(1);
4795 dsp->attribute = attribute;
4796 cm_ClientStrCpy(dsp->mask, lengthof(dsp->mask), maskp); /* and save mask */
4799 osi_assertx(p->opcode == 2, "invalid opcode");
4800 /* find next; obtain basic parameters from request or open dir file */
4801 dsp = smb_FindDirSearch(p->parmsp[0]);
4802 maxCount = p->parmsp[1];
4803 infoLevel = p->parmsp[2];
4804 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4805 searchFlags = p->parmsp[5];
4807 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4808 p->parmsp[0], nextCookie);
4809 return CM_ERROR_BADFD;
4811 attribute = dsp->attribute;
4814 starPattern = 1; /* assume, since required a Find Next */
4817 switch ( infoLevel ) {
4818 case SMB_INFO_STANDARD:
4820 ohbytes = sizeof(fp->u.FstandardInfo);
4823 case SMB_INFO_QUERY_EA_SIZE:
4824 ohbytes = sizeof(fp->u.FeaSizeInfo);
4825 s = "InfoQueryEaSize";
4828 case SMB_INFO_QUERY_EAS_FROM_LIST:
4829 ohbytes = sizeof(fp->u.FeasFromListInfo);
4830 s = "InfoQueryEasFromList";
4833 case SMB_FIND_FILE_DIRECTORY_INFO:
4834 s = "FindFileDirectoryInfo";
4835 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4838 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4839 s = "FindFileFullDirectoryInfo";
4840 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4843 case SMB_FIND_FILE_NAMES_INFO:
4844 s = "FindFileNamesInfo";
4845 ohbytes = sizeof(fp->u.FfileNamesInfo);
4848 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4849 s = "FindFileBothDirectoryInfo";
4850 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4854 s = "unknownInfoLevel";
4858 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
4861 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4862 attribute, infoLevel, maxCount, searchFlags);
4864 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
4865 p->opcode, dsp->cookie, nextCookie);
4868 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4869 smb_ReleaseDirSearch(dsp);
4870 return CM_ERROR_INVAL;
4873 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4874 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4876 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4879 dirListPatchesp = NULL;
4881 maxReturnData = p->maxReturnData;
4882 if (p->opcode == 1) /* find first */
4883 maxReturnParms = 10; /* bytes */
4885 maxReturnParms = 8; /* bytes */
4887 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4888 if (maxReturnData > 6000)
4889 maxReturnData = 6000;
4890 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4892 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4895 osi_Log2(smb_logp, "T2 receive search dir count %d [%S]",
4896 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4898 /* bail out if request looks bad */
4899 if (p->opcode == 1 && !pathp) {
4900 smb_ReleaseDirSearch(dsp);
4901 smb_FreeTran2Packet(outp);
4902 return CM_ERROR_BADSMB;
4905 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
4906 dsp->cookie, nextCookie, attribute);
4908 userp = smb_GetTran2User(vcp, p);
4910 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
4911 smb_ReleaseDirSearch(dsp);
4912 smb_FreeTran2Packet(outp);
4913 return CM_ERROR_BADSMB;
4916 /* try to get the vnode for the path name next */
4917 lock_ObtainMutex(&dsp->mx);
4920 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4924 spacep = cm_GetSpace();
4925 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4926 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4928 cm_ReleaseUser(userp);
4929 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4930 smb_FreeTran2Packet(outp);
4931 lock_ReleaseMutex(&dsp->mx);
4932 smb_DeleteDirSearch(dsp);
4933 smb_ReleaseDirSearch(dsp);
4937 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4938 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4940 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4941 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4942 userp, tidPathp, &req, &scp);
4943 cm_FreeSpace(spacep);
4946 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4947 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4948 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
4949 cm_ReleaseSCache(scp);
4950 cm_ReleaseUser(userp);
4951 if ( WANTS_DFS_PATHNAMES(p) || pnc )
4952 code = CM_ERROR_PATH_NOT_COVERED;
4954 code = CM_ERROR_BADSHARENAME;
4955 smb_SendTran2Error(vcp, p, opx, code);
4956 smb_FreeTran2Packet(outp);
4957 lock_ReleaseMutex(&dsp->mx);
4958 smb_DeleteDirSearch(dsp);
4959 smb_ReleaseDirSearch(dsp);
4962 #endif /* DFS_SUPPORT */
4964 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4965 /* we need one hold for the entry we just stored into,
4966 * and one for our own processing. When we're done
4967 * with this function, we'll drop the one for our own
4968 * processing. We held it once from the namei call,
4969 * and so we do another hold now.
4972 lock_ObtainWrite(&scp->rw);
4973 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
4974 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4975 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4976 dsp->flags |= SMB_DIRSEARCH_BULKST;
4978 lock_ReleaseWrite(&scp->rw);
4981 lock_ReleaseMutex(&dsp->mx);
4983 cm_ReleaseUser(userp);
4984 smb_FreeTran2Packet(outp);
4985 smb_DeleteDirSearch(dsp);
4986 smb_ReleaseDirSearch(dsp);
4990 /* get the directory size */
4991 lock_ObtainWrite(&scp->rw);
4992 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4993 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4995 lock_ReleaseWrite(&scp->rw);
4996 cm_ReleaseSCache(scp);
4997 cm_ReleaseUser(userp);
4998 smb_FreeTran2Packet(outp);
4999 smb_DeleteDirSearch(dsp);
5000 smb_ReleaseDirSearch(dsp);
5004 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5007 dirLength = scp->length;
5009 bufferOffset.LowPart = bufferOffset.HighPart = 0;
5010 curOffset.HighPart = 0;
5011 curOffset.LowPart = nextCookie;
5012 origOp = outp->datap;
5019 normchar_t normName[MAX_PATH]; /* Normalized name */
5020 clientchar_t cfileName[MAX_PATH]; /* Non-normalized name */
5023 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5024 /* skip over resume key */
5027 fp = (smb_tran2Find_t *) op;
5029 /* make sure that curOffset.LowPart doesn't point to the first
5030 * 32 bytes in the 2nd through last dir page, and that it doesn't
5031 * point at the first 13 32-byte chunks in the first dir page,
5032 * since those are dir and page headers, and don't contain useful
5035 temp = curOffset.LowPart & (2048-1);
5036 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5037 /* we're in the first page */
5038 if (temp < 13*32) temp = 13*32;
5041 /* we're in a later dir page */
5042 if (temp < 32) temp = 32;
5045 /* make sure the low order 5 bits are zero */
5048 /* now put temp bits back ito curOffset.LowPart */
5049 curOffset.LowPart &= ~(2048-1);
5050 curOffset.LowPart |= temp;
5052 /* check if we've passed the dir's EOF */
5053 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
5054 osi_Log0(smb_logp, "T2 search dir passed eof");
5059 /* check if we've returned all the names that will fit in the
5060 * response packet; we check return count as well as the number
5061 * of bytes requested. We check the # of bytes after we find
5062 * the dir entry, since we'll need to check its size.
5064 if (returnedNames >= maxCount) {
5065 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
5066 returnedNames, maxCount);
5070 /* see if we can use the bufferp we have now; compute in which
5071 * page the current offset would be, and check whether that's
5072 * the offset of the buffer we have. If not, get the buffer.
5074 thyper.HighPart = curOffset.HighPart;
5075 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5076 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5079 buf_Release(bufferp);
5082 lock_ReleaseWrite(&scp->rw);
5083 code = buf_Get(scp, &thyper, &bufferp);
5084 lock_ObtainMutex(&dsp->mx);
5086 /* now, if we're doing a star match, do bulk fetching
5087 * of all of the status info for files in the dir.
5090 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, infoLevel, userp, &req);
5092 lock_ObtainWrite(&scp->rw);
5093 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
5094 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
5095 /* Don't bulk stat if risking timeout */
5096 DWORD now = GetTickCount();
5097 if (now - req.startTime > RDRtimeout * 1000) {
5098 scp->bulkStatProgress = thyper;
5099 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
5100 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
5102 code = cm_TryBulkStat(scp, &thyper, userp, &req);
5105 lock_ObtainWrite(&scp->rw);
5107 lock_ReleaseMutex(&dsp->mx);
5109 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
5113 bufferOffset = thyper;
5115 /* now get the data in the cache */
5117 code = cm_SyncOp(scp, bufferp, userp, &req,
5119 CM_SCACHESYNC_NEEDCALLBACK
5120 | CM_SCACHESYNC_READ);
5122 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5126 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5128 if (cm_HaveBuffer(scp, bufferp, 0)) {
5129 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5133 /* otherwise, load the buffer and try again */
5134 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5137 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5138 scp, bufferp, code);
5143 buf_Release(bufferp);
5147 } /* if (wrong buffer) ... */
5149 /* now we have the buffer containing the entry we're interested
5150 * in; copy it out if it represents a non-deleted entry.
5152 entryInDir = curOffset.LowPart & (2048-1);
5153 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5155 /* page header will help tell us which entries are free. Page
5156 * header can change more often than once per buffer, since
5157 * AFS 3 dir page size may be less than (but not more than)
5158 * a buffer package buffer.
5160 /* only look intra-buffer */
5161 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5162 temp &= ~(2048 - 1); /* turn off intra-page bits */
5163 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5165 /* now determine which entry we're looking at in the page.
5166 * If it is free (there's a free bitmap at the start of the
5167 * dir), we should skip these 32 bytes.
5169 slotInPage = (entryInDir & 0x7e0) >> 5;
5170 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5171 (1 << (slotInPage & 0x7)))) {
5172 /* this entry is free */
5173 numDirChunks = 1; /* only skip this guy */
5177 tp = bufferp->datap + entryInBuffer;
5178 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5180 /* while we're here, compute the next entry's location, too,
5181 * since we'll need it when writing out the cookie into the dir
5184 * XXXX Probably should do more sanity checking.
5186 numDirChunks = cm_NameEntries(dep->name, &onbytes);
5188 /* compute offset of cookie representing next entry */
5189 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5191 if (dep->fid.vnode == 0)
5192 goto nextEntry; /* This entry is not in use */
5194 cm_FsStringToClientString(dep->name, -1, cfileName, lengthof(cfileName));
5195 cm_ClientStringToNormString(cfileName, -1, normName, lengthof(normName));
5197 /* Need 8.3 name? */
5199 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
5200 !cm_Is8Dot3(cfileName)) {
5201 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5205 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %S (%S)",
5206 dep->fid.vnode, dep->fid.unique,
5207 osi_LogSaveClientString(smb_logp, cfileName),
5208 NeedShortName ? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
5210 /* When matching, we are using doing a case fold if we have a wildcard mask.
5211 * If we get a non-wildcard match, it's a lookup for a specific file.
5213 if (cm_MatchMask(normName, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5214 (NeedShortName && cm_MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))
5216 /* Eliminate entries that don't match requested attributes */
5217 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5218 smb_IsDotFile(cfileName)) {
5219 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5220 goto nextEntry; /* no hidden files */
5223 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5225 /* We have already done the cm_TryBulkStat above */
5226 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume,
5227 ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5228 fileType = cm_FindFileType(&fid);
5229 /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5230 * "has filetype %d", dep->name, fileType);
5232 if ( fileType == CM_SCACHETYPE_DIRECTORY ||
5233 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5234 fileType == CM_SCACHETYPE_DFSLINK ||
5235 fileType == CM_SCACHETYPE_INVALID)
5236 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5240 /* finally check if this name will fit */
5242 smb_UnparseString(opx, NULL, cfileName, &onbytes, SMB_STRF_ANSIPATH);
5243 orbytes = ohbytes + onbytes;
5245 /* now, we round up the record to a 4 byte alignment,
5246 * and we make sure that we have enough room here for
5247 * even the aligned version (so we don't have to worry
5248 * about an overflow when we pad things out below).
5249 * That's the reason for the alignment arithmetic below.
5251 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5252 align = (4 - (orbytes & 3)) & 3;
5256 if (orbytes + bytesInBuffer + align > maxReturnData) {
5257 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5262 /* this is one of the entries to use: it is not deleted
5263 * and it matches the star pattern we're looking for.
5264 * Put out the name, preceded by its length.
5266 /* First zero everything else */
5267 memset(origOp, 0, orbytes);
5270 smb_UnparseString(opx, origOp + ohbytes, cfileName, &onbytes, SMB_STRF_ANSIPATH);
5272 switch (infoLevel) {
5273 case SMB_INFO_STANDARD:
5274 fp->u.FstandardInfo.fileNameLength = onbytes;
5275 attrp = &fp->u.FstandardInfo.fileAttrs;
5278 case SMB_INFO_QUERY_EA_SIZE:
5279 fp->u.FeaSizeInfo.fileNameLength = onbytes;
5280 attrp = &fp->u.FeaSizeInfo.fileAttrs;
5281 fp->u.FeaSizeInfo.eaSize = 0;
5284 case SMB_INFO_QUERY_EAS_FROM_LIST:
5285 fp->u.FeasFromListInfo.fileNameLength = onbytes;
5286 attrp = &fp->u.FeasFromListInfo.fileAttrs;
5287 fp->u.FeasFromListInfo.eaSize = 0;
5290 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5291 if (NeedShortName) {
5295 nchars = cm_ClientStringToUtf16(shortName, -1,
5296 fp->u.FfileBothDirectoryInfo.shortName,
5297 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
5299 fp->u.FfileBothDirectoryInfo.shortNameLength = (nchars - 1)*sizeof(wchar_t);
5301 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5302 fp->u.FfileBothDirectoryInfo.reserved = 0;
5304 cm_ClientStrCpy(fp->u.FfileBothDirectoryInfo.shortName,
5305 lengthof(fp->u.FfileBothDirectoryInfo.shortName),
5307 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
5312 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5313 fp->u.FfileFullDirectoryInfo.eaSize = 0;
5316 case SMB_FIND_FILE_DIRECTORY_INFO:
5317 fp->u.FfileDirectoryInfo.nextEntryOffset = orbytes + align;
5318 fp->u.FfileDirectoryInfo.fileIndex = nextEntryCookie;
5319 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5320 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5323 case SMB_FIND_FILE_NAMES_INFO:
5324 fp->u.FfileNamesInfo.nextEntryOffset = orbytes + align;
5325 fp->u.FfileNamesInfo.fileIndex = nextEntryCookie;
5326 fp->u.FfileNamesInfo.fileNameLength = onbytes;
5331 /* we shouldn't hit this case */
5332 osi_assertx(FALSE, "Unknown query type");
5335 /* now, adjust the # of entries copied */
5338 /* now we emit the attribute. This is tricky, since
5339 * we need to really stat the file to find out what
5340 * type of entry we've got. Right now, we're copying
5341 * out data from a buffer, while holding the scp
5342 * locked, so it isn't really convenient to stat
5343 * something now. We'll put in a place holder
5344 * now, and make a second pass before returning this
5345 * to get the real attributes. So, we just skip the
5346 * data for now, and adjust it later. We allocate a
5347 * patch record to make it easy to find this point
5348 * later. The replay will happen at a time when it is
5349 * safe to unlock the directory.
5351 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5352 osi_assert(attrp != NULL);
5353 curPatchp = malloc(sizeof(*curPatchp));
5354 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5355 curPatchp->dptr = attrp;
5357 if (smb_hideDotFiles && smb_IsDotFile(cfileName)) {
5358 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5360 curPatchp->flags = 0;
5363 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5366 curPatchp->dep = dep;
5369 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5370 /* put out resume key */
5371 *((u_long *)origOp) = nextEntryCookie;
5373 /* Adjust byte ptr and count */
5374 origOp += orbytes; /* skip entire record */
5375 bytesInBuffer += orbytes;
5377 /* and pad the record out */
5378 while (align-- > 0) {
5382 } /* if we're including this name */
5383 else if (!starPattern &&
5385 cm_MatchMask(normName, maskp, CM_FLAG_CASEFOLD)) {
5386 /* We were looking for exact matches, but here's an inexact one*/
5391 /* and adjust curOffset to be where the new cookie is */
5392 thyper.HighPart = 0;
5393 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5394 curOffset = LargeIntegerAdd(thyper, curOffset);
5395 } /* while copying data for dir listing */
5397 /* If we didn't get a star pattern, we did an exact match during the first pass.
5398 * If there were no exact matches found, we fail over to inexact matches by
5399 * marking the query as a star pattern (matches all case permutations), and
5400 * re-running the query.
5402 if (returnedNames == 0 && !starPattern && foundInexact) {
5403 osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
5408 /* release the mutex */
5409 lock_ReleaseWrite(&scp->rw);
5411 buf_Release(bufferp);
5415 /* apply and free last set of patches; if not doing a star match, this
5416 * will be empty, but better safe (and freeing everything) than sorry.
5418 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5419 dsp->relPath, infoLevel, userp, &req);
5421 /* now put out the final parameters */
5422 if (returnedNames == 0)
5424 if (p->opcode == 1) {
5426 outp->parmsp[0] = (unsigned short) dsp->cookie;
5427 outp->parmsp[1] = returnedNames;
5428 outp->parmsp[2] = eos;
5429 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5430 outp->parmsp[4] = 0;
5431 /* don't need last name to continue
5432 * search, cookie is enough. Normally,
5433 * this is the offset of the file name
5434 * of the last entry returned.
5436 outp->totalParms = 10; /* in bytes */
5440 outp->parmsp[0] = returnedNames;
5441 outp->parmsp[1] = eos;
5442 outp->parmsp[2] = 0; /* EAS error */
5443 outp->parmsp[3] = 0; /* last name, as above */
5444 outp->totalParms = 8; /* in bytes */
5447 /* return # of bytes in the buffer */
5448 outp->totalData = bytesInBuffer;
5450 /* Return error code if unsuccessful on first request */
5451 if (code == 0 && p->opcode == 1 && returnedNames == 0)
5452 code = CM_ERROR_NOSUCHFILE;
5454 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
5455 p->opcode, dsp->cookie, returnedNames, code);
5457 /* if we're supposed to close the search after this request, or if
5458 * we're supposed to close the search if we're done, and we're done,
5459 * or if something went wrong, close the search.
5461 if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
5462 (returnedNames == 0) ||
5463 ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
5465 smb_DeleteDirSearch(dsp);
5468 smb_SendTran2Error(vcp, p, opx, code);
5470 smb_SendTran2Packet(vcp, outp, opx);
5472 smb_FreeTran2Packet(outp);
5473 smb_ReleaseDirSearch(dsp);
5474 cm_ReleaseSCache(scp);
5475 cm_ReleaseUser(userp);
5479 /* SMB_COM_FIND_CLOSE2 */
5480 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5483 smb_dirSearch_t *dsp;
5485 dirHandle = smb_GetSMBParm(inp, 0);
5487 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
5489 dsp = smb_FindDirSearch(dirHandle);
5492 return CM_ERROR_BADFD;
5494 /* otherwise, we have an FD to destroy */
5495 smb_DeleteDirSearch(dsp);
5496 smb_ReleaseDirSearch(dsp);
5498 /* and return results */
5499 smb_SetSMBDataLength(outp, 0);
5505 /* SMB_COM_FIND_NOTIFY_CLOSE */
5506 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5508 smb_SetSMBDataLength(outp, 0);
5512 /* SMB_COM_OPEN_ANDX */
5513 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5515 clientchar_t *pathp;
5520 cm_scache_t *dscp; /* dir we're dealing with */
5521 cm_scache_t *scp; /* file we're creating */
5523 int initialModeBits;
5526 clientchar_t *lastNamep;
5527 unsigned long dosTime;
5533 int parmSlot; /* which parm we're dealing with */
5534 clientchar_t *tidPathp;
5542 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
5543 openFun = smb_GetSMBParm(inp, 8); /* open function */
5544 excl = ((openFun & 3) == 0);
5545 trunc = ((openFun & 3) == 2); /* truncate it */
5546 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
5547 openAction = 0; /* tracks what we did */
5549 attributes = smb_GetSMBParm(inp, 5);
5550 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
5552 /* compute initial mode bits based on read-only flag in attributes */
5553 initialModeBits = 0666;
5554 if (attributes & SMB_ATTR_READONLY)
5555 initialModeBits &= ~0222;
5557 pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
5560 spacep = inp->spacep;
5561 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5564 (cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
5565 cm_ClientStrCmpIA(lastNamep, _C("\\srvsvc")) == 0 ||
5566 cm_ClientStrCmpIA(lastNamep, _C("\\wkssvc")) == 0 ||
5567 cm_ClientStrCmpIA(lastNamep, _C("ipc$")) == 0)) {
5568 /* special case magic file name for receiving IOCTL requests
5569 * (since IOCTL calls themselves aren't getting through).
5572 osi_Log0(smb_logp, "IOCTL Open");
5575 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5576 smb_SetupIoctlFid(fidp, spacep);
5578 /* set inp->fid so that later read calls in same msg can find fid */
5579 inp->fid = fidp->fid;
5581 /* copy out remainder of the parms */
5583 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5585 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
5586 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
5587 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5588 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
5589 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
5590 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5591 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5592 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5594 /* and the final "always present" stuff */
5595 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
5596 /* next write out the "unique" ID */
5597 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
5598 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
5599 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5600 smb_SetSMBDataLength(outp, 0);
5602 /* and clean up fid reference */
5603 smb_ReleaseFID(fidp);
5607 #ifdef DEBUG_VERBOSE
5609 char *hexp, *asciip;
5610 asciip = (lastNamep ? lastNamep : pathp );
5611 hexp = osi_HexifyString(asciip);
5612 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
5616 userp = smb_GetUserFromVCP(vcp, inp);
5619 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5621 cm_ReleaseUser(userp);
5622 return CM_ERROR_NOSUCHPATH;
5624 code = cm_NameI(cm_data.rootSCachep, pathp,
5625 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5626 userp, tidPathp, &req, &scp);
5629 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5630 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5631 cm_ReleaseSCache(scp);
5632 cm_ReleaseUser(userp);
5633 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5634 return CM_ERROR_PATH_NOT_COVERED;
5636 return CM_ERROR_BADSHARENAME;
5638 #endif /* DFS_SUPPORT */
5641 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
5642 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5643 userp, tidPathp, &req, &dscp);
5645 cm_ReleaseUser(userp);
5650 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5651 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5653 cm_ReleaseSCache(dscp);
5654 cm_ReleaseUser(userp);
5655 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5656 return CM_ERROR_PATH_NOT_COVERED;
5658 return CM_ERROR_BADSHARENAME;
5660 #endif /* DFS_SUPPORT */
5661 /* otherwise, scp points to the parent directory. Do a lookup,
5662 * and truncate the file if we find it, otherwise we create the
5669 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
5671 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5672 cm_ReleaseSCache(dscp);
5673 cm_ReleaseUser(userp);
5678 /* if we get here, if code is 0, the file exists and is represented by
5679 * scp. Otherwise, we have to create it. The dir may be represented
5680 * by dscp, or we may have found the file directly. If code is non-zero,
5684 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
5686 if (dscp) cm_ReleaseSCache(dscp);
5687 cm_ReleaseSCache(scp);
5688 cm_ReleaseUser(userp);
5693 /* oops, file shouldn't be there */
5695 cm_ReleaseSCache(dscp);
5696 cm_ReleaseSCache(scp);
5697 cm_ReleaseUser(userp);
5698 return CM_ERROR_EXISTS;
5702 setAttr.mask = CM_ATTRMASK_LENGTH;
5703 setAttr.length.LowPart = 0;
5704 setAttr.length.HighPart = 0;
5705 code = cm_SetAttr(scp, &setAttr, userp, &req);
5706 openAction = 3; /* truncated existing file */
5708 else openAction = 1; /* found existing file */
5710 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
5711 /* don't create if not found */
5712 if (dscp) cm_ReleaseSCache(dscp);
5713 cm_ReleaseUser(userp);
5714 return CM_ERROR_NOSUCHFILE;
5717 osi_assertx(dscp != NULL, "null cm_scache_t");
5718 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %S",
5719 osi_LogSaveClientString(smb_logp, lastNamep));
5720 openAction = 2; /* created file */
5721 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5722 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5723 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5727 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5728 smb_NotifyChange(FILE_ACTION_ADDED,
5729 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5730 dscp, lastNamep, NULL, TRUE);
5731 } else if (!excl && code == CM_ERROR_EXISTS) {
5732 /* not an exclusive create, and someone else tried
5733 * creating it already, then we open it anyway. We
5734 * don't bother retrying after this, since if this next
5735 * fails, that means that the file was deleted after we
5736 * started this call.
5738 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5742 setAttr.mask = CM_ATTRMASK_LENGTH;
5743 setAttr.length.LowPart = 0;
5744 setAttr.length.HighPart = 0;
5745 code = cm_SetAttr(scp, &setAttr, userp, &req);
5747 } /* lookup succeeded */
5751 /* we don't need this any longer */
5753 cm_ReleaseSCache(dscp);
5756 /* something went wrong creating or truncating the file */
5758 cm_ReleaseSCache(scp);
5759 cm_ReleaseUser(userp);
5763 /* make sure we're about to open a file */
5764 if (scp->fileType != CM_SCACHETYPE_FILE) {
5765 cm_ReleaseSCache(scp);
5766 cm_ReleaseUser(userp);
5767 return CM_ERROR_ISDIR;
5770 /* now all we have to do is open the file itself */
5771 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5772 osi_assertx(fidp, "null smb_fid_t");
5775 lock_ObtainMutex(&fidp->mx);
5776 /* save a pointer to the vnode */
5778 lock_ObtainWrite(&scp->rw);
5779 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5780 lock_ReleaseWrite(&scp->rw);
5781 osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
5783 fidp->userp = userp;
5785 /* compute open mode */
5787 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5788 if (openMode == 1 || openMode == 2)
5789 fidp->flags |= SMB_FID_OPENWRITE;
5791 /* remember if the file was newly created */
5793 fidp->flags |= SMB_FID_CREATED;
5795 lock_ReleaseMutex(&fidp->mx);
5796 smb_ReleaseFID(fidp);
5798 cm_Open(scp, 0, userp);
5800 /* set inp->fid so that later read calls in same msg can find fid */
5801 inp->fid = fidp->fid;
5803 /* copy out remainder of the parms */
5805 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5806 lock_ObtainRead(&scp->rw);
5808 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5809 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5810 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5811 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5812 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5813 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5814 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5815 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5816 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5818 /* and the final "always present" stuff */
5819 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5820 /* next write out the "unique" ID */
5821 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5822 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5823 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5824 lock_ReleaseRead(&scp->rw);
5825 smb_SetSMBDataLength(outp, 0);
5827 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5829 cm_ReleaseUser(userp);
5830 /* leave scp held since we put it in fidp->scp */
5834 static void smb_GetLockParams(unsigned char LockType,
5836 unsigned int * ppid,
5837 LARGE_INTEGER * pOffset,
5838 LARGE_INTEGER * pLength)
5840 if (LockType & LOCKING_ANDX_LARGE_FILES) {
5842 *ppid = *((USHORT *) *buf);
5843 pOffset->HighPart = *((LONG *)(*buf + 4));
5844 pOffset->LowPart = *((DWORD *)(*buf + 8));
5845 pLength->HighPart = *((LONG *)(*buf + 12));
5846 pLength->LowPart = *((DWORD *)(*buf + 16));
5850 /* Not Large Files */
5851 *ppid = *((USHORT *) *buf);
5852 pOffset->HighPart = 0;
5853 pOffset->LowPart = *((DWORD *)(*buf + 2));
5854 pLength->HighPart = 0;
5855 pLength->LowPart = *((DWORD *)(*buf + 6));
5860 /* SMB_COM_LOCKING_ANDX */
5861 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5868 unsigned char LockType;
5869 unsigned short NumberOfUnlocks, NumberOfLocks;
5873 LARGE_INTEGER LOffset, LLength;
5874 smb_waitingLockRequest_t *wlRequest = NULL;
5875 cm_file_lock_t *lockp;
5883 fid = smb_GetSMBParm(inp, 2);
5884 fid = smb_ChainFID(fid, inp);
5886 fidp = smb_FindFID(vcp, fid, 0);
5888 return CM_ERROR_BADFD;
5890 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
5891 smb_CloseFID(vcp, fidp, NULL, 0);
5892 smb_ReleaseFID(fidp);
5893 return CM_ERROR_NOSUCHFILE;
5896 lock_ObtainMutex(&fidp->mx);
5897 if (fidp->flags & SMB_FID_IOCTL) {
5898 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
5899 lock_ReleaseMutex(&fidp->mx);
5900 smb_ReleaseFID(fidp);
5901 return CM_ERROR_BADFD;
5904 osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
5906 lock_ReleaseMutex(&fidp->mx);
5908 /* set inp->fid so that later read calls in same msg can find fid */
5911 userp = smb_GetUserFromVCP(vcp, inp);
5914 lock_ObtainWrite(&scp->rw);
5915 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5916 CM_SCACHESYNC_NEEDCALLBACK
5917 | CM_SCACHESYNC_GETSTATUS
5918 | CM_SCACHESYNC_LOCK);
5920 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
5924 LockType = smb_GetSMBParm(inp, 3) & 0xff;
5925 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
5926 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
5927 NumberOfLocks = smb_GetSMBParm(inp, 7);
5929 if (!(fidp->flags & SMB_FID_OPENWRITE) &&
5930 !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
5931 /* somebody wants exclusive locks on a file that they only
5932 opened for reading. We downgrade this to a shared lock. */
5933 osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
5934 LockType |= LOCKING_ANDX_SHARED_LOCK;
5937 if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
5938 /* AFS does not support atomic changes of lock types from read or write and vice-versa */
5939 osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]");
5940 code = CM_ERROR_BADOP;
5945 op = smb_GetSMBData(inp, NULL);
5947 if (LockType & LOCKING_ANDX_CANCEL_LOCK) {
5948 /* Cancel outstanding lock requests */
5949 smb_waitingLock_t * wl;
5951 for (i=0; i<NumberOfLocks; i++) {
5952 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5954 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5956 lock_ObtainWrite(&smb_globalLock);
5957 for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
5959 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
5960 if (wl->key == key && LargeIntegerEqualTo(wl->LOffset, LOffset) &&
5961 LargeIntegerEqualTo(wl->LLength, LLength)) {
5962 wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
5963 goto found_lock_request;
5968 lock_ReleaseWrite(&smb_globalLock);
5971 smb_SetSMBDataLength(outp, 0);
5976 for (i=0; i<NumberOfUnlocks; i++) {
5977 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5979 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5981 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
5989 for (i=0; i<NumberOfLocks; i++) {
5990 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5992 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5994 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
5995 userp, &req, &lockp);
5997 if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
5998 (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
6000 code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
6001 userp, &req, &lockp);
6004 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
6005 smb_waitingLock_t * wLock;
6007 /* Put on waiting list */
6008 if(wlRequest == NULL) {
6012 LARGE_INTEGER tOffset, tLength;
6014 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
6016 osi_assertx(wlRequest != NULL, "null wlRequest");
6018 wlRequest->vcp = vcp;
6020 wlRequest->scp = scp;
6021 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
6023 wlRequest->inp = smb_CopyPacket(inp);
6024 wlRequest->outp = smb_CopyPacket(outp);
6025 wlRequest->lockType = LockType;
6026 wlRequest->msTimeout = Timeout;
6027 wlRequest->start_t = osi_Time();
6028 wlRequest->locks = NULL;
6030 /* The waiting lock request needs to have enough
6031 information to undo all the locks in the request.
6032 We do the following to store info about locks that
6033 have already been granted. Sure, we can get most
6034 of the info from the packet, but the packet doesn't
6035 hold the result of cm_Lock call. In practice we
6036 only receive packets with one or two locks, so we
6037 are only wasting a few bytes here and there and
6038 only for a limited period of time until the waiting
6039 lock times out or is freed. */
6041 for(opt = op_locks, j=i; j > 0; j--) {
6042 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
6044 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6046 wLock = malloc(sizeof(smb_waitingLock_t));
6048 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6051 wLock->LOffset = tOffset;
6052 wLock->LLength = tLength;
6053 wLock->lockp = NULL;
6054 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
6055 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6060 wLock = malloc(sizeof(smb_waitingLock_t));
6062 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6065 wLock->LOffset = LOffset;
6066 wLock->LLength = LLength;
6067 wLock->lockp = lockp;
6068 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
6069 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6072 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
6080 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
6087 /* Since something went wrong with the lock number i, we now
6088 have to go ahead and release any locks acquired before the
6089 failure. All locks before lock number i (of which there
6090 are i of them) have either been successful or are waiting.
6091 Either case requires calling cm_Unlock(). */
6093 /* And purge the waiting lock */
6094 if(wlRequest != NULL) {
6095 smb_waitingLock_t * wl;
6096 smb_waitingLock_t * wlNext;
6099 for(wl = wlRequest->locks; wl; wl = wlNext) {
6101 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
6103 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
6106 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
6108 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
6111 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
6116 smb_ReleaseVC(wlRequest->vcp);
6117 cm_ReleaseSCache(wlRequest->scp);
6118 smb_FreePacket(wlRequest->inp);
6119 smb_FreePacket(wlRequest->outp);
6128 if (wlRequest != NULL) {
6130 lock_ObtainWrite(&smb_globalLock);
6131 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
6133 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
6134 lock_ReleaseWrite(&smb_globalLock);
6136 /* don't send reply immediately */
6137 outp->flags |= SMB_PACKETFLAG_NOSEND;
6140 smb_SetSMBDataLength(outp, 0);
6144 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
6147 lock_ReleaseWrite(&scp->rw);
6148 cm_ReleaseSCache(scp);
6149 cm_ReleaseUser(userp);
6150 smb_ReleaseFID(fidp);
6155 /* SMB_COM_QUERY_INFORMATION2 */
6156 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6162 afs_uint32 searchTime;
6169 fid = smb_GetSMBParm(inp, 0);
6170 fid = smb_ChainFID(fid, inp);
6172 fidp = smb_FindFID(vcp, fid, 0);
6174 return CM_ERROR_BADFD;
6176 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6177 smb_CloseFID(vcp, fidp, NULL, 0);
6178 smb_ReleaseFID(fidp);
6179 return CM_ERROR_NOSUCHFILE;
6182 lock_ObtainMutex(&fidp->mx);
6183 if (fidp->flags & SMB_FID_IOCTL) {
6184 lock_ReleaseMutex(&fidp->mx);
6185 smb_ReleaseFID(fidp);
6186 return CM_ERROR_BADFD;
6189 osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6191 lock_ReleaseMutex(&fidp->mx);
6193 userp = smb_GetUserFromVCP(vcp, inp);
6196 /* otherwise, stat the file */
6197 lock_ObtainWrite(&scp->rw);
6198 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6199 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6203 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6205 lock_ConvertWToR(&scp->rw);
6207 /* decode times. We need a search time, but the response to this
6208 * call provides the date first, not the time, as returned in the
6209 * searchTime variable. So we take the high-order bits first.
6211 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
6212 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
6213 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
6214 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
6215 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
6216 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
6217 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
6219 /* now handle file size and allocation size */
6220 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
6221 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
6222 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
6223 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
6225 /* file attribute */
6226 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
6228 /* and finalize stuff */
6229 smb_SetSMBDataLength(outp, 0);
6234 lock_ReleaseRead(&scp->rw);
6236 lock_ReleaseWrite(&scp->rw);
6237 cm_ReleaseSCache(scp);
6238 cm_ReleaseUser(userp);
6239 smb_ReleaseFID(fidp);
6243 /* SMB_COM_SET_INFORMATION2 */
6244 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6250 afs_uint32 searchTime;
6258 fid = smb_GetSMBParm(inp, 0);
6259 fid = smb_ChainFID(fid, inp);
6261 fidp = smb_FindFID(vcp, fid, 0);
6263 return CM_ERROR_BADFD;
6265 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6266 smb_CloseFID(vcp, fidp, NULL, 0);
6267 smb_ReleaseFID(fidp);
6268 return CM_ERROR_NOSUCHFILE;
6271 lock_ObtainMutex(&fidp->mx);
6272 if (fidp->flags & SMB_FID_IOCTL) {
6273 lock_ReleaseMutex(&fidp->mx);
6274 smb_ReleaseFID(fidp);
6275 return CM_ERROR_BADFD;
6278 osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6280 lock_ReleaseMutex(&fidp->mx);
6282 userp = smb_GetUserFromVCP(vcp, inp);
6285 /* now prepare to call cm_setattr. This message only sets various times,
6286 * and AFS only implements mtime, and we'll set the mtime if that's
6287 * requested. The others we'll ignore.
6289 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
6291 if (searchTime != 0) {
6292 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
6294 if ( unixTime != -1 ) {
6295 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
6296 attrs.clientModTime = unixTime;
6297 code = cm_SetAttr(scp, &attrs, userp, &req);
6299 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
6301 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
6307 cm_ReleaseSCache(scp);
6308 cm_ReleaseUser(userp);
6309 smb_ReleaseFID(fidp);
6313 /* SMB_COM_WRITE_ANDX */
6314 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6317 long count, written = 0, total_written = 0;
6321 smb_t *smbp = (smb_t*) inp;
6325 int inDataBlockCount;
6327 fd = smb_GetSMBParm(inp, 2);
6328 count = smb_GetSMBParm(inp, 10);
6330 offset.HighPart = 0;
6331 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6333 if (*inp->wctp == 14) {
6334 /* we have a request with 64-bit file offsets */
6335 #ifdef AFS_LARGEFILES
6336 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6338 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6340 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
6341 /* we shouldn't have received this op if we didn't specify
6342 largefile support */
6343 return CM_ERROR_BADOP;
6348 op = inp->data + smb_GetSMBParm(inp, 11);
6349 inDataBlockCount = count;
6351 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
6352 fd, offset.HighPart, offset.LowPart, count);
6354 fd = smb_ChainFID(fd, inp);
6355 fidp = smb_FindFID(vcp, fd, 0);
6357 return CM_ERROR_BADFD;
6359 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6360 smb_CloseFID(vcp, fidp, NULL, 0);
6361 smb_ReleaseFID(fidp);
6362 return CM_ERROR_NOSUCHFILE;
6365 lock_ObtainMutex(&fidp->mx);
6366 if (fidp->flags & SMB_FID_IOCTL) {
6367 lock_ReleaseMutex(&fidp->mx);
6368 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
6369 smb_ReleaseFID(fidp);
6372 lock_ReleaseMutex(&fidp->mx);
6373 userp = smb_GetUserFromVCP(vcp, inp);
6375 /* special case: 0 bytes transferred means there is no data
6376 transferred. A slight departure from SMB_COM_WRITE where this
6377 means that we are supposed to truncate the file at this
6382 LARGE_INTEGER LOffset;
6383 LARGE_INTEGER LLength;
6387 key = cm_GenerateKey(vcp->vcID, pid, fd);
6389 LOffset.HighPart = offset.HighPart;
6390 LOffset.LowPart = offset.LowPart;
6391 LLength.HighPart = 0;
6392 LLength.LowPart = count;
6395 lock_ObtainWrite(&scp->rw);
6396 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
6397 lock_ReleaseWrite(&scp->rw);
6404 * Work around bug in NT client
6406 * When copying a file, the NT client should first copy the data,
6407 * then copy the last write time. But sometimes the NT client does
6408 * these in the wrong order, so the data copies would inadvertently
6409 * cause the last write time to be overwritten. We try to detect this,
6410 * and don't set client mod time if we think that would go against the
6413 lock_ObtainMutex(&fidp->mx);
6414 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6415 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6416 fidp->scp->clientModTime = time(NULL);
6418 lock_ReleaseMutex(&fidp->mx);
6421 while ( code == 0 && count > 0 ) {
6422 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6423 if (code == 0 && written == 0)
6424 code = CM_ERROR_PARTIALWRITE;
6426 offset = LargeIntegerAdd(offset,
6427 ConvertLongToLargeInteger(written));
6429 total_written += written;
6433 /* slots 0 and 1 are reserved for request chaining and will be
6434 filled in when we return. */
6435 smb_SetSMBParm(outp, 2, total_written);
6436 smb_SetSMBParm(outp, 3, 0); /* reserved */
6437 smb_SetSMBParm(outp, 4, 0); /* reserved */
6438 smb_SetSMBParm(outp, 5, 0); /* reserved */
6439 smb_SetSMBDataLength(outp, 0);
6442 cm_ReleaseUser(userp);
6443 smb_ReleaseFID(fidp);
6448 /* SMB_COM_READ_ANDX */
6449 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6453 long finalCount = 0;
6457 smb_t *smbp = (smb_t*) inp;
6463 fd = smb_GetSMBParm(inp, 2);
6464 count = smb_GetSMBParm(inp, 5);
6465 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6467 if (*inp->wctp == 12) {
6468 /* a request with 64-bit offsets */
6469 #ifdef AFS_LARGEFILES
6470 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
6472 if (LargeIntegerLessThanZero(offset)) {
6473 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
6474 offset.HighPart, offset.LowPart);
6475 return CM_ERROR_BADSMB;
6478 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
6479 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
6480 return CM_ERROR_BADSMB;
6482 offset.HighPart = 0;
6486 offset.HighPart = 0;
6489 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
6490 fd, offset.HighPart, offset.LowPart, count);
6492 fd = smb_ChainFID(fd, inp);
6493 fidp = smb_FindFID(vcp, fd, 0);
6495 return CM_ERROR_BADFD;
6498 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6499 smb_CloseFID(vcp, fidp, NULL, 0);
6500 smb_ReleaseFID(fidp);
6501 return CM_ERROR_NOSUCHFILE;
6505 key = cm_GenerateKey(vcp->vcID, pid, fd);
6507 LARGE_INTEGER LOffset, LLength;
6510 LOffset.HighPart = offset.HighPart;
6511 LOffset.LowPart = offset.LowPart;
6512 LLength.HighPart = 0;
6513 LLength.LowPart = count;
6516 lock_ObtainWrite(&scp->rw);
6517 code = cm_LockCheckRead(scp, LOffset, LLength, key);
6518 lock_ReleaseWrite(&scp->rw);
6522 smb_ReleaseFID(fidp);
6526 /* set inp->fid so that later read calls in same msg can find fid */
6529 lock_ObtainMutex(&fidp->mx);
6530 if (fidp->flags & SMB_FID_IOCTL) {
6531 lock_ReleaseMutex(&fidp->mx);
6532 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
6533 smb_ReleaseFID(fidp);
6536 lock_ReleaseMutex(&fidp->mx);
6538 userp = smb_GetUserFromVCP(vcp, inp);
6540 /* 0 and 1 are reserved for request chaining, were setup by our caller,
6541 * and will be further filled in after we return.
6543 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
6544 smb_SetSMBParm(outp, 3, 0); /* resvd */
6545 smb_SetSMBParm(outp, 4, 0); /* resvd */
6546 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
6547 /* fill in #6 when we have all the parameters' space reserved */
6548 smb_SetSMBParm(outp, 7, 0); /* resv'd */
6549 smb_SetSMBParm(outp, 8, 0); /* resv'd */
6550 smb_SetSMBParm(outp, 9, 0); /* resv'd */
6551 smb_SetSMBParm(outp, 10, 0); /* resv'd */
6552 smb_SetSMBParm(outp, 11, 0); /* reserved */
6554 /* get op ptr after putting in the parms, since otherwise we don't
6555 * know where the data really is.
6557 op = smb_GetSMBData(outp, NULL);
6559 /* now fill in offset from start of SMB header to first data byte (to op) */
6560 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
6562 /* set the packet data length the count of the # of bytes */
6563 smb_SetSMBDataLength(outp, count);
6565 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6567 /* fix some things up */
6568 smb_SetSMBParm(outp, 5, finalCount);
6569 smb_SetSMBDataLength(outp, finalCount);
6571 cm_ReleaseUser(userp);
6572 smb_ReleaseFID(fidp);
6577 * Values for createDisp, copied from NTDDK.H
6579 #define FILE_SUPERSEDE 0 // (???)
6580 #define FILE_OPEN 1 // (open)
6581 #define FILE_CREATE 2 // (exclusive)
6582 #define FILE_OPEN_IF 3 // (non-exclusive)
6583 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
6584 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
6587 #define REQUEST_OPLOCK 2
6588 #define REQUEST_BATCH_OPLOCK 4
6589 #define OPEN_DIRECTORY 8
6590 #define EXTENDED_RESPONSE_REQUIRED 0x10
6592 /* CreateOptions field. */
6593 #define FILE_DIRECTORY_FILE 0x0001
6594 #define FILE_WRITE_THROUGH 0x0002
6595 #define FILE_SEQUENTIAL_ONLY 0x0004
6596 #define FILE_NON_DIRECTORY_FILE 0x0040
6597 #define FILE_NO_EA_KNOWLEDGE 0x0200
6598 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
6599 #define FILE_RANDOM_ACCESS 0x0800
6600 #define FILE_DELETE_ON_CLOSE 0x1000
6601 #define FILE_OPEN_BY_FILE_ID 0x2000
6603 /* SMB_COM_NT_CREATE_ANDX */
6604 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6606 clientchar_t *pathp, *realPathp;
6610 cm_scache_t *dscp; /* parent dir */
6611 cm_scache_t *scp; /* file to create or open */
6612 cm_scache_t *targetScp; /* if scp is a symlink */
6614 clientchar_t *lastNamep;
6615 clientchar_t *treeStartp;
6616 unsigned short nameLength;
6618 unsigned int requestOpLock;
6619 unsigned int requestBatchOpLock;
6620 unsigned int mustBeDir;
6621 unsigned int extendedRespRequired;
6622 unsigned int treeCreate;
6624 unsigned int desiredAccess;
6625 unsigned int extAttributes;
6626 unsigned int createDisp;
6627 unsigned int createOptions;
6628 unsigned int shareAccess;
6629 int initialModeBits;
6630 unsigned short baseFid;
6631 smb_fid_t *baseFidp;
6633 cm_scache_t *baseDirp;
6634 unsigned short openAction;
6639 clientchar_t *tidPathp;
6643 cm_lock_data_t *ldp = NULL;
6647 /* This code is very long and has a lot of if-then-else clauses
6648 * scp and dscp get reused frequently and we need to ensure that
6649 * we don't lose a reference. Start by ensuring that they are NULL.
6656 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
6657 flags = smb_GetSMBOffsetParm(inp, 3, 1)
6658 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
6659 requestOpLock = flags & REQUEST_OPLOCK;
6660 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6661 mustBeDir = flags & OPEN_DIRECTORY;
6662 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6665 * Why all of a sudden 32-bit FID?
6666 * We will reject all bits higher than 16.
6668 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
6669 return CM_ERROR_INVAL;
6670 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
6671 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
6672 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6673 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
6674 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
6675 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
6676 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
6677 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
6678 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
6679 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
6680 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
6682 /* mustBeDir is never set; createOptions directory bit seems to be
6685 if (createOptions & FILE_DIRECTORY_FILE)
6687 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6693 * compute initial mode bits based on read-only flag in
6694 * extended attributes
6696 initialModeBits = 0666;
6697 if (extAttributes & SMB_ATTR_READONLY)
6698 initialModeBits &= ~0222;
6700 pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
6701 NULL, SMB_STRF_ANSIPATH);
6703 /* Sometimes path is not null-terminated, so we make a copy. */
6704 realPathp = malloc(nameLength+sizeof(clientchar_t));
6705 memcpy(realPathp, pathp, nameLength+sizeof(clientchar_t));
6706 realPathp[nameLength/sizeof(clientchar_t)] = 0;
6708 spacep = inp->spacep;
6709 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
6711 osi_Log1(smb_logp,"NTCreateX for [%S]",osi_LogSaveClientString(smb_logp,realPathp));
6712 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
6713 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%S]", shareAccess, flags, osi_LogSaveClientString(smb_logp,(lastNamep?lastNamep:_C("null"))));
6716 (cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
6717 cm_ClientStrCmpIA(lastNamep, _C("\\srvsvc")) == 0 ||
6718 cm_ClientStrCmpIA(lastNamep, _C("\\wkssvc")) == 0 ||
6719 cm_ClientStrCmpIA(lastNamep, _C("ipc$")) == 0)) {
6720 /* special case magic file name for receiving IOCTL requests
6721 * (since IOCTL calls themselves aren't getting through).
6723 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6724 smb_SetupIoctlFid(fidp, spacep);
6725 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
6727 /* set inp->fid so that later read calls in same msg can find fid */
6728 inp->fid = fidp->fid;
6732 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6733 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6734 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
6736 memset(&ft, 0, sizeof(ft));
6737 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6738 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6739 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6740 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6741 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
6742 sz.HighPart = 0x7fff; sz.LowPart = 0;
6743 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
6744 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
6745 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6746 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6747 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
6748 smb_SetSMBDataLength(outp, 0);
6750 /* clean up fid reference */
6751 smb_ReleaseFID(fidp);
6756 #ifdef DEBUG_VERBOSE
6758 char *hexp, *asciip;
6759 asciip = (lastNamep? lastNamep : realPathp);
6760 hexp = osi_HexifyString( asciip );
6761 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
6766 userp = smb_GetUserFromVCP(vcp, inp);
6768 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
6770 return CM_ERROR_INVAL;
6775 baseDirp = cm_data.rootSCachep;
6776 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6777 if (code == CM_ERROR_TIDIPC) {
6778 /* Attempt to use a TID allocated for IPC. The client
6779 * is probably looking for DCE RPC end points which we
6780 * don't support OR it could be looking to make a DFS
6783 osi_Log0(smb_logp, "NTCreateX received IPC TID");
6786 cm_ReleaseUser(userp);
6787 return CM_ERROR_NOSUCHFILE;
6788 #endif /* DFS_SUPPORT */
6791 baseFidp = smb_FindFID(vcp, baseFid, 0);
6793 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
6795 cm_ReleaseUser(userp);
6796 return CM_ERROR_INVAL;
6799 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6801 cm_ReleaseUser(userp);
6802 smb_CloseFID(vcp, baseFidp, NULL, 0);
6803 smb_ReleaseFID(baseFidp);
6804 return CM_ERROR_NOSUCHPATH;
6807 baseDirp = baseFidp->scp;
6811 osi_Log1(smb_logp, "NTCreateX tidPathp=[%S]", (tidPathp==NULL)?_C("null"): osi_LogSaveClientString(smb_logp,tidPathp));
6813 /* compute open mode */
6815 if (desiredAccess & DELETE)
6816 fidflags |= SMB_FID_OPENDELETE;
6817 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
6818 fidflags |= SMB_FID_OPENREAD_LISTDIR;
6819 if (desiredAccess & AFS_ACCESS_WRITE)
6820 fidflags |= SMB_FID_OPENWRITE;
6821 if (createOptions & FILE_DELETE_ON_CLOSE)
6822 fidflags |= SMB_FID_DELONCLOSE;
6823 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6824 fidflags |= SMB_FID_SEQUENTIAL;
6825 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6826 fidflags |= SMB_FID_RANDOM;
6827 if (smb_IsExecutableFileName(lastNamep))
6828 fidflags |= SMB_FID_EXECUTABLE;
6830 /* and the share mode */
6831 if (shareAccess & FILE_SHARE_READ)
6832 fidflags |= SMB_FID_SHARE_READ;
6833 if (shareAccess & FILE_SHARE_WRITE)
6834 fidflags |= SMB_FID_SHARE_WRITE;
6836 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
6839 /* For an exclusive create, we want to do a case sensitive match for the last component. */
6840 if ( createDisp == FILE_CREATE ||
6841 createDisp == FILE_OVERWRITE ||
6842 createDisp == FILE_OVERWRITE_IF) {
6843 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6844 userp, tidPathp, &req, &dscp);
6847 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6848 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
6850 cm_ReleaseSCache(dscp);
6851 cm_ReleaseUser(userp);
6854 smb_ReleaseFID(baseFidp);
6855 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6856 return CM_ERROR_PATH_NOT_COVERED;
6858 return CM_ERROR_BADSHARENAME;
6860 #endif /* DFS_SUPPORT */
6861 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6863 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
6864 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6865 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6866 if (code == 0 && realDirFlag == 1) {
6867 cm_ReleaseSCache(scp);
6868 cm_ReleaseSCache(dscp);
6869 cm_ReleaseUser(userp);
6872 smb_ReleaseFID(baseFidp);
6873 return CM_ERROR_EXISTS;
6877 /* we have both scp and dscp */
6879 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6880 userp, tidPathp, &req, &scp);
6882 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6883 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
6884 cm_ReleaseSCache(scp);
6885 cm_ReleaseUser(userp);
6888 smb_ReleaseFID(baseFidp);
6889 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6890 return CM_ERROR_PATH_NOT_COVERED;
6892 return CM_ERROR_BADSHARENAME;
6894 #endif /* DFS_SUPPORT */
6895 /* we might have scp but not dscp */
6901 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6902 /* look up parent directory */
6903 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
6904 * the immediate parent. We have to work our way up realPathp until we hit something that we
6908 /* we might or might not have scp */
6914 code = cm_NameI(baseDirp, spacep->wdata,
6915 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6916 userp, tidPathp, &req, &dscp);
6919 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6920 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
6923 cm_ReleaseSCache(scp);
6924 cm_ReleaseSCache(dscp);
6925 cm_ReleaseUser(userp);
6928 smb_ReleaseFID(baseFidp);
6929 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6930 return CM_ERROR_PATH_NOT_COVERED;
6932 return CM_ERROR_BADSHARENAME;
6934 #endif /* DFS_SUPPORT */
6937 (tp = cm_ClientStrRChr(spacep->wdata, '\\')) &&
6938 (createDisp == FILE_CREATE) &&
6939 (realDirFlag == 1)) {
6942 treeStartp = realPathp + (tp - spacep->wdata);
6944 if (*tp && !smb_IsLegalFilename(tp)) {
6945 cm_ReleaseUser(userp);
6947 smb_ReleaseFID(baseFidp);
6950 cm_ReleaseSCache(scp);
6951 return CM_ERROR_BADNTFILENAME;
6955 } while (dscp == NULL && code == 0);
6959 /* we might have scp and we might have dscp */
6962 smb_ReleaseFID(baseFidp);
6965 osi_Log0(smb_logp,"NTCreateX parent not found");
6967 cm_ReleaseSCache(scp);
6969 cm_ReleaseSCache(dscp);
6970 cm_ReleaseUser(userp);
6975 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
6976 /* A file exists where we want a directory. */
6978 cm_ReleaseSCache(scp);
6979 cm_ReleaseSCache(dscp);
6980 cm_ReleaseUser(userp);
6982 return CM_ERROR_EXISTS;
6986 lastNamep = realPathp;
6990 if (!smb_IsLegalFilename(lastNamep)) {
6992 cm_ReleaseSCache(scp);
6994 cm_ReleaseSCache(dscp);
6995 cm_ReleaseUser(userp);
6997 return CM_ERROR_BADNTFILENAME;
7000 if (!foundscp && !treeCreate) {
7001 if ( createDisp == FILE_CREATE ||
7002 createDisp == FILE_OVERWRITE ||
7003 createDisp == FILE_OVERWRITE_IF)
7005 code = cm_Lookup(dscp, lastNamep,
7006 CM_FLAG_FOLLOW, userp, &req, &scp);
7008 code = cm_Lookup(dscp, lastNamep,
7009 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7012 if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
7014 cm_ReleaseSCache(dscp);
7015 cm_ReleaseUser(userp);
7020 /* we have scp and dscp */
7022 /* we have scp but not dscp */
7024 smb_ReleaseFID(baseFidp);
7027 /* if we get here, if code is 0, the file exists and is represented by
7028 * scp. Otherwise, we have to create it. The dir may be represented
7029 * by dscp, or we may have found the file directly. If code is non-zero,
7032 if (code == 0 && !treeCreate) {
7033 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7036 cm_ReleaseSCache(dscp);
7038 cm_ReleaseSCache(scp);
7039 cm_ReleaseUser(userp);
7044 if (createDisp == FILE_CREATE) {
7045 /* oops, file shouldn't be there */
7046 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7048 cm_ReleaseSCache(dscp);
7050 cm_ReleaseSCache(scp);
7051 cm_ReleaseUser(userp);
7053 return CM_ERROR_EXISTS;
7056 if ( createDisp == FILE_OVERWRITE ||
7057 createDisp == FILE_OVERWRITE_IF) {
7059 setAttr.mask = CM_ATTRMASK_LENGTH;
7060 setAttr.length.LowPart = 0;
7061 setAttr.length.HighPart = 0;
7062 /* now watch for a symlink */
7064 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7066 osi_assertx(dscp != NULL, "null cm_scache_t");
7067 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7069 /* we have a more accurate file to use (the
7070 * target of the symbolic link). Otherwise,
7071 * we'll just use the symlink anyway.
7073 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7075 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7076 cm_ReleaseSCache(scp);
7078 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7081 cm_ReleaseSCache(dscp);
7083 cm_ReleaseSCache(scp);
7084 cm_ReleaseUser(userp);
7090 code = cm_SetAttr(scp, &setAttr, userp, &req);
7091 openAction = 3; /* truncated existing file */
7094 openAction = 1; /* found existing file */
7096 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7097 /* don't create if not found */
7099 cm_ReleaseSCache(dscp);
7101 cm_ReleaseSCache(scp);
7102 cm_ReleaseUser(userp);
7104 return CM_ERROR_NOSUCHFILE;
7105 } else if (realDirFlag == 0 || realDirFlag == -1) {
7106 osi_assertx(dscp != NULL, "null cm_scache_t");
7107 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %S",
7108 osi_LogSaveClientString(smb_logp, lastNamep));
7109 openAction = 2; /* created file */
7110 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7111 setAttr.clientModTime = time(NULL);
7112 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
7115 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7116 smb_NotifyChange(FILE_ACTION_ADDED,
7117 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7118 dscp, lastNamep, NULL, TRUE);
7119 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7120 /* Not an exclusive create, and someone else tried
7121 * creating it already, then we open it anyway. We
7122 * don't bother retrying after this, since if this next
7123 * fails, that means that the file was deleted after we
7124 * started this call.
7126 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7129 if (createDisp == FILE_OVERWRITE_IF) {
7130 setAttr.mask = CM_ATTRMASK_LENGTH;
7131 setAttr.length.LowPart = 0;
7132 setAttr.length.HighPart = 0;
7134 /* now watch for a symlink */
7136 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7138 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7140 /* we have a more accurate file to use (the
7141 * target of the symbolic link). Otherwise,
7142 * we'll just use the symlink anyway.
7144 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7146 cm_ReleaseSCache(scp);
7150 code = cm_SetAttr(scp, &setAttr, userp, &req);
7152 } /* lookup succeeded */
7155 clientchar_t *tp, *pp;
7156 clientchar_t *cp; /* This component */
7157 int clen = 0; /* length of component */
7158 cm_scache_t *tscp1, *tscp2;
7161 /* create directory */
7163 treeStartp = lastNamep;
7164 osi_assertx(dscp != NULL, "null cm_scache_t");
7165 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%S]",
7166 osi_LogSaveClientString(smb_logp, treeStartp));
7167 openAction = 2; /* created directory */
7169 /* if the request is to create the root directory
7170 * it will appear as a directory name of the nul-string
7171 * and a code of CM_ERROR_NOSUCHFILE
7173 if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
7174 code = CM_ERROR_EXISTS;
7176 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7177 setAttr.clientModTime = time(NULL);
7182 cm_HoldSCache(tscp1);
7186 tp = cm_ClientStrChr(pp, '\\');
7188 cm_ClientStrCpy(cp, lengthof(spacep->wdata) - (cp - spacep->wdata), pp);
7189 clen = (int)cm_ClientStrLen(cp);
7190 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
7192 clen = (int)(tp - pp);
7193 cm_ClientStrCpyN(cp, lengthof(spacep->wdata) - (cp - spacep->wdata),
7201 continue; /* the supplied path can't have consecutive slashes either , but */
7203 /* cp is the next component to be created. */
7204 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
7205 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
7206 smb_NotifyChange(FILE_ACTION_ADDED,
7207 FILE_NOTIFY_CHANGE_DIR_NAME,
7208 tscp1, cp, NULL, TRUE);
7210 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7211 /* Not an exclusive create, and someone else tried
7212 * creating it already, then we open it anyway. We
7213 * don't bother retrying after this, since if this next
7214 * fails, that means that the file was deleted after we
7215 * started this call.
7217 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
7218 userp, &req, &tscp2);
7223 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
7224 cm_ReleaseSCache(tscp1);
7225 tscp1 = tscp2; /* Newly created directory will be next parent */
7226 /* the hold is transfered to tscp1 from tscp2 */
7231 cm_ReleaseSCache(dscp);
7234 cm_ReleaseSCache(scp);
7237 * if we get here and code == 0, then scp is the last directory created, and dscp is the
7243 /* something went wrong creating or truncating the file */
7245 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7247 cm_ReleaseSCache(scp);
7249 cm_ReleaseSCache(dscp);
7250 cm_ReleaseUser(userp);
7255 /* make sure we have file vs. dir right (only applies for single component case) */
7256 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7257 /* now watch for a symlink */
7259 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7260 cm_scache_t * targetScp = 0;
7261 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7263 /* we have a more accurate file to use (the
7264 * target of the symbolic link). Otherwise,
7265 * we'll just use the symlink anyway.
7267 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
7269 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7270 cm_ReleaseSCache(scp);
7275 if (scp->fileType != CM_SCACHETYPE_FILE) {
7277 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7279 cm_ReleaseSCache(dscp);
7280 cm_ReleaseSCache(scp);
7281 cm_ReleaseUser(userp);
7283 return CM_ERROR_ISDIR;
7287 /* (only applies to single component case) */
7288 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7290 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7291 cm_ReleaseSCache(scp);
7293 cm_ReleaseSCache(dscp);
7294 cm_ReleaseUser(userp);
7296 return CM_ERROR_NOTDIR;
7299 /* open the file itself */
7300 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7301 osi_assertx(fidp, "null smb_fid_t");
7303 /* save a reference to the user */
7305 fidp->userp = userp;
7307 /* If we are restricting sharing, we should do so with a suitable
7309 if (scp->fileType == CM_SCACHETYPE_FILE &&
7310 !(fidflags & SMB_FID_SHARE_WRITE)) {
7312 LARGE_INTEGER LOffset, LLength;
7315 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7316 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7317 LLength.HighPart = 0;
7318 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7320 /* If we are not opening the file for writing, then we don't
7321 try to get an exclusive lock. No one else should be able to
7322 get an exclusive lock on the file anyway, although someone
7323 else can get a shared lock. */
7324 if ((fidflags & SMB_FID_SHARE_READ) ||
7325 !(fidflags & SMB_FID_OPENWRITE)) {
7326 sLockType = LOCKING_ANDX_SHARED_LOCK;
7331 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7333 lock_ObtainWrite(&scp->rw);
7334 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7335 lock_ReleaseWrite(&scp->rw);
7339 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7340 cm_ReleaseSCache(scp);
7342 cm_ReleaseSCache(dscp);
7343 cm_ReleaseUser(userp);
7344 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7345 smb_CloseFID(vcp, fidp, NULL, 0);
7346 smb_ReleaseFID(fidp);
7352 /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
7354 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7356 lock_ObtainMutex(&fidp->mx);
7357 /* save a pointer to the vnode */
7358 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
7359 lock_ObtainWrite(&scp->rw);
7360 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7361 lock_ReleaseWrite(&scp->rw);
7362 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
7364 fidp->flags = fidflags;
7366 /* remember if the file was newly created */
7368 fidp->flags |= SMB_FID_CREATED;
7370 /* save parent dir and pathname for delete or change notification */
7371 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7372 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
7373 fidp->flags |= SMB_FID_NTOPEN;
7374 fidp->NTopen_dscp = dscp;
7376 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
7378 fidp->NTopen_wholepathp = realPathp;
7379 lock_ReleaseMutex(&fidp->mx);
7381 /* we don't need this any longer */
7383 cm_ReleaseSCache(dscp);
7387 cm_Open(scp, 0, userp);
7389 /* set inp->fid so that later read calls in same msg can find fid */
7390 inp->fid = fidp->fid;
7394 lock_ObtainRead(&scp->rw);
7395 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7396 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7397 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7398 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7399 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7400 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7401 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7402 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7403 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7405 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7406 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7407 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
7408 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
7409 smb_SetSMBParmByte(outp, parmSlot,
7410 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7411 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7412 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7413 smb_SetSMBDataLength(outp, 0);
7415 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
7416 LargeIntegerGreaterThanZero(fidp->scp->length) &&
7417 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
7418 cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
7419 fidp->scp->length.LowPart, fidp->scp->length.HighPart,
7422 lock_ReleaseRead(&scp->rw);
7424 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %S", fidp->fid,
7425 osi_LogSaveClientString(smb_logp, realPathp));
7427 cm_ReleaseUser(userp);
7428 smb_ReleaseFID(fidp);
7430 /* Can't free realPathp if we get here since
7431 fidp->NTopen_wholepathp is pointing there */
7433 /* leave scp held since we put it in fidp->scp */
7438 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
7439 * Instead, ultimately, would like to use a subroutine for common code.
7442 /* NT_TRANSACT_CREATE (SMB_COM_NT_TRANSACT) */
7443 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7445 clientchar_t *pathp, *realPathp;
7449 cm_scache_t *dscp; /* parent dir */
7450 cm_scache_t *scp; /* file to create or open */
7451 cm_scache_t *targetScp; /* if scp is a symlink */
7453 clientchar_t *lastNamep;
7454 unsigned long nameLength;
7456 unsigned int requestOpLock;
7457 unsigned int requestBatchOpLock;
7458 unsigned int mustBeDir;
7459 unsigned int extendedRespRequired;
7461 unsigned int desiredAccess;
7462 #ifdef DEBUG_VERBOSE
7463 unsigned int allocSize;
7465 unsigned int shareAccess;
7466 unsigned int extAttributes;
7467 unsigned int createDisp;
7468 #ifdef DEBUG_VERBOSE
7471 unsigned int createOptions;
7472 int initialModeBits;
7473 unsigned short baseFid;
7474 smb_fid_t *baseFidp;
7476 cm_scache_t *baseDirp;
7477 unsigned short openAction;
7481 clientchar_t *tidPathp;
7483 int parmOffset, dataOffset;
7489 cm_lock_data_t *ldp = NULL;
7496 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7497 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7498 parmp = inp->data + parmOffset;
7499 lparmp = (ULONG *) parmp;
7502 requestOpLock = flags & REQUEST_OPLOCK;
7503 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7504 mustBeDir = flags & OPEN_DIRECTORY;
7505 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7508 * Why all of a sudden 32-bit FID?
7509 * We will reject all bits higher than 16.
7511 if (lparmp[1] & 0xFFFF0000)
7512 return CM_ERROR_INVAL;
7513 baseFid = (unsigned short)lparmp[1];
7514 desiredAccess = lparmp[2];
7515 #ifdef DEBUG_VERBOSE
7516 allocSize = lparmp[3];
7517 #endif /* DEBUG_VERSOSE */
7518 extAttributes = lparmp[5];
7519 shareAccess = lparmp[6];
7520 createDisp = lparmp[7];
7521 createOptions = lparmp[8];
7522 #ifdef DEBUG_VERBOSE
7525 nameLength = lparmp[11];
7527 #ifdef DEBUG_VERBOSE
7528 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
7529 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
7530 osi_Log1(smb_logp,"... flags[%x]",flags);
7533 /* mustBeDir is never set; createOptions directory bit seems to be
7536 if (createOptions & FILE_DIRECTORY_FILE)
7538 else if (createOptions & FILE_NON_DIRECTORY_FILE)
7544 * compute initial mode bits based on read-only flag in
7545 * extended attributes
7547 initialModeBits = 0666;
7548 if (extAttributes & SMB_ATTR_READONLY)
7549 initialModeBits &= ~0222;
7551 pathp = smb_ParseStringCch(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
7552 nameLength, NULL, SMB_STRF_ANSIPATH);
7553 /* Sometimes path is not null-terminated, so we make a copy. */
7554 realPathp = malloc((nameLength+1) * sizeof(clientchar_t));
7555 memcpy(realPathp, pathp, nameLength * sizeof(clientchar_t));
7556 realPathp[nameLength] = 0;
7557 spacep = cm_GetSpace();
7558 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
7561 * Nothing here to handle SMB_IOCTL_FILENAME.
7562 * Will add it if necessary.
7565 #ifdef DEBUG_VERBOSE
7567 char *hexp, *asciip;
7568 asciip = (lastNamep? lastNamep : realPathp);
7569 hexp = osi_HexifyString( asciip );
7570 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
7575 userp = smb_GetUserFromVCP(vcp, inp);
7577 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
7579 return CM_ERROR_INVAL;
7584 baseDirp = cm_data.rootSCachep;
7585 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7586 if (code == CM_ERROR_TIDIPC) {
7587 /* Attempt to use a TID allocated for IPC. The client
7588 * is probably looking for DCE RPC end points which we
7589 * don't support OR it could be looking to make a DFS
7592 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
7595 cm_ReleaseUser(userp);
7596 return CM_ERROR_NOSUCHPATH;
7600 baseFidp = smb_FindFID(vcp, baseFid, 0);
7602 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
7604 cm_ReleaseUser(userp);
7605 return CM_ERROR_BADFD;
7608 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7610 cm_ReleaseUser(userp);
7611 smb_CloseFID(vcp, baseFidp, NULL, 0);
7612 smb_ReleaseFID(baseFidp);
7613 return CM_ERROR_NOSUCHPATH;
7616 baseDirp = baseFidp->scp;
7620 /* compute open mode */
7622 if (desiredAccess & DELETE)
7623 fidflags |= SMB_FID_OPENDELETE;
7624 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
7625 fidflags |= SMB_FID_OPENREAD_LISTDIR;
7626 if (desiredAccess & AFS_ACCESS_WRITE)
7627 fidflags |= SMB_FID_OPENWRITE;
7628 if (createOptions & FILE_DELETE_ON_CLOSE)
7629 fidflags |= SMB_FID_DELONCLOSE;
7630 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7631 fidflags |= SMB_FID_SEQUENTIAL;
7632 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7633 fidflags |= SMB_FID_RANDOM;
7634 if (smb_IsExecutableFileName(lastNamep))
7635 fidflags |= SMB_FID_EXECUTABLE;
7637 /* And the share mode */
7638 if (shareAccess & FILE_SHARE_READ)
7639 fidflags |= SMB_FID_SHARE_READ;
7640 if (shareAccess & FILE_SHARE_WRITE)
7641 fidflags |= SMB_FID_SHARE_WRITE;
7645 if ( createDisp == FILE_OPEN ||
7646 createDisp == FILE_OVERWRITE ||
7647 createDisp == FILE_OVERWRITE_IF) {
7648 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7649 userp, tidPathp, &req, &dscp);
7652 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7653 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7654 cm_ReleaseSCache(dscp);
7655 cm_ReleaseUser(userp);
7658 smb_ReleaseFID(baseFidp);
7659 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7660 return CM_ERROR_PATH_NOT_COVERED;
7662 return CM_ERROR_BADSHARENAME;
7664 #endif /* DFS_SUPPORT */
7665 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7667 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7668 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7669 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7670 if (code == 0 && realDirFlag == 1) {
7671 cm_ReleaseSCache(scp);
7672 cm_ReleaseSCache(dscp);
7673 cm_ReleaseUser(userp);
7676 smb_ReleaseFID(baseFidp);
7677 return CM_ERROR_EXISTS;
7683 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7684 userp, tidPathp, &req, &scp);
7686 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7687 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7688 cm_ReleaseSCache(scp);
7689 cm_ReleaseUser(userp);
7692 smb_ReleaseFID(baseFidp);
7693 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7694 return CM_ERROR_PATH_NOT_COVERED;
7696 return CM_ERROR_BADSHARENAME;
7698 #endif /* DFS_SUPPORT */
7704 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7705 /* look up parent directory */
7707 code = cm_NameI(baseDirp, spacep->wdata,
7708 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7709 userp, tidPathp, &req, &dscp);
7711 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7712 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7713 cm_ReleaseSCache(dscp);
7714 cm_ReleaseUser(userp);
7717 smb_ReleaseFID(baseFidp);
7718 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7719 return CM_ERROR_PATH_NOT_COVERED;
7721 return CM_ERROR_BADSHARENAME;
7723 #endif /* DFS_SUPPORT */
7727 cm_FreeSpace(spacep);
7730 smb_ReleaseFID(baseFidp);
7733 cm_ReleaseUser(userp);
7739 lastNamep = realPathp;
7743 if (!smb_IsLegalFilename(lastNamep))
7744 return CM_ERROR_BADNTFILENAME;
7747 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
7748 code = cm_Lookup(dscp, lastNamep,
7749 CM_FLAG_FOLLOW, userp, &req, &scp);
7751 code = cm_Lookup(dscp, lastNamep,
7752 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7755 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7756 cm_ReleaseSCache(dscp);
7757 cm_ReleaseUser(userp);
7764 smb_ReleaseFID(baseFidp);
7765 cm_FreeSpace(spacep);
7768 /* if we get here, if code is 0, the file exists and is represented by
7769 * scp. Otherwise, we have to create it. The dir may be represented
7770 * by dscp, or we may have found the file directly. If code is non-zero,
7774 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7777 cm_ReleaseSCache(dscp);
7778 cm_ReleaseSCache(scp);
7779 cm_ReleaseUser(userp);
7784 if (createDisp == FILE_CREATE) {
7785 /* oops, file shouldn't be there */
7786 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7788 cm_ReleaseSCache(dscp);
7789 cm_ReleaseSCache(scp);
7790 cm_ReleaseUser(userp);
7792 return CM_ERROR_EXISTS;
7795 if (createDisp == FILE_OVERWRITE ||
7796 createDisp == FILE_OVERWRITE_IF) {
7797 setAttr.mask = CM_ATTRMASK_LENGTH;
7798 setAttr.length.LowPart = 0;
7799 setAttr.length.HighPart = 0;
7801 /* now watch for a symlink */
7803 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7805 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7807 /* we have a more accurate file to use (the
7808 * target of the symbolic link). Otherwise,
7809 * we'll just use the symlink anyway.
7811 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7813 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7814 cm_ReleaseSCache(scp);
7816 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7819 cm_ReleaseSCache(dscp);
7821 cm_ReleaseSCache(scp);
7822 cm_ReleaseUser(userp);
7828 code = cm_SetAttr(scp, &setAttr, userp, &req);
7829 openAction = 3; /* truncated existing file */
7831 else openAction = 1; /* found existing file */
7833 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7834 /* don't create if not found */
7836 cm_ReleaseSCache(dscp);
7837 cm_ReleaseUser(userp);
7839 return CM_ERROR_NOSUCHFILE;
7841 else if (realDirFlag == 0 || realDirFlag == -1) {
7842 osi_assertx(dscp != NULL, "null cm_scache_t");
7843 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %S",
7844 osi_LogSaveClientString(smb_logp, lastNamep));
7845 openAction = 2; /* created file */
7846 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7847 setAttr.clientModTime = time(NULL);
7848 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7852 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7853 smb_NotifyChange(FILE_ACTION_ADDED,
7854 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7855 dscp, lastNamep, NULL, TRUE);
7856 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7857 /* Not an exclusive create, and someone else tried
7858 * creating it already, then we open it anyway. We
7859 * don't bother retrying after this, since if this next
7860 * fails, that means that the file was deleted after we
7861 * started this call.
7863 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7866 if (createDisp == FILE_OVERWRITE_IF) {
7867 setAttr.mask = CM_ATTRMASK_LENGTH;
7868 setAttr.length.LowPart = 0;
7869 setAttr.length.HighPart = 0;
7871 /* now watch for a symlink */
7873 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7875 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7877 /* we have a more accurate file to use (the
7878 * target of the symbolic link). Otherwise,
7879 * we'll just use the symlink anyway.
7881 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7883 cm_ReleaseSCache(scp);
7887 code = cm_SetAttr(scp, &setAttr, userp, &req);
7889 } /* lookup succeeded */
7892 /* create directory */
7893 osi_assertx(dscp != NULL, "null cm_scache_t");
7895 "smb_ReceiveNTTranCreate creating directory %S",
7896 osi_LogSaveClientString(smb_logp, lastNamep));
7897 openAction = 2; /* created directory */
7898 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7899 setAttr.clientModTime = time(NULL);
7900 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
7901 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7902 smb_NotifyChange(FILE_ACTION_ADDED,
7903 FILE_NOTIFY_CHANGE_DIR_NAME,
7904 dscp, lastNamep, NULL, TRUE);
7906 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7907 /* Not an exclusive create, and someone else tried
7908 * creating it already, then we open it anyway. We
7909 * don't bother retrying after this, since if this next
7910 * fails, that means that the file was deleted after we
7911 * started this call.
7913 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7919 /* something went wrong creating or truncating the file */
7921 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7923 cm_ReleaseSCache(scp);
7924 cm_ReleaseUser(userp);
7929 /* make sure we have file vs. dir right */
7930 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7931 /* now watch for a symlink */
7933 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7935 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7937 /* we have a more accurate file to use (the
7938 * target of the symbolic link). Otherwise,
7939 * we'll just use the symlink anyway.
7941 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7944 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7945 cm_ReleaseSCache(scp);
7950 if (scp->fileType != CM_SCACHETYPE_FILE) {
7952 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7953 cm_ReleaseSCache(scp);
7954 cm_ReleaseUser(userp);
7956 return CM_ERROR_ISDIR;
7960 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7962 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7963 cm_ReleaseSCache(scp);
7964 cm_ReleaseUser(userp);
7966 return CM_ERROR_NOTDIR;
7969 /* open the file itself */
7970 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7971 osi_assertx(fidp, "null smb_fid_t");
7973 /* save a reference to the user */
7975 fidp->userp = userp;
7977 /* If we are restricting sharing, we should do so with a suitable
7979 if (scp->fileType == CM_SCACHETYPE_FILE &&
7980 !(fidflags & SMB_FID_SHARE_WRITE)) {
7982 LARGE_INTEGER LOffset, LLength;
7985 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7986 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7987 LLength.HighPart = 0;
7988 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7990 /* Similar to what we do in handling NTCreateX. We get a
7991 shared lock if we are only opening the file for reading. */
7992 if ((fidflags & SMB_FID_SHARE_READ) ||
7993 !(fidflags & SMB_FID_OPENWRITE)) {
7994 sLockType = LOCKING_ANDX_SHARED_LOCK;
7999 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8001 lock_ObtainWrite(&scp->rw);
8002 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8003 lock_ReleaseWrite(&scp->rw);
8007 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8008 cm_ReleaseSCache(scp);
8009 cm_ReleaseUser(userp);
8010 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
8011 smb_CloseFID(vcp, fidp, NULL, 0);
8012 smb_ReleaseFID(fidp);
8014 return CM_ERROR_SHARING_VIOLATION;
8018 /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
8020 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8022 lock_ObtainMutex(&fidp->mx);
8023 /* save a pointer to the vnode */
8025 lock_ObtainWrite(&scp->rw);
8026 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8027 lock_ReleaseWrite(&scp->rw);
8028 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
8030 fidp->flags = fidflags;
8032 /* remember if the file was newly created */
8034 fidp->flags |= SMB_FID_CREATED;
8036 /* save parent dir and pathname for deletion or change notification */
8037 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8038 fidp->flags |= SMB_FID_NTOPEN;
8039 fidp->NTopen_dscp = dscp;
8040 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
8042 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
8044 fidp->NTopen_wholepathp = realPathp;
8045 lock_ReleaseMutex(&fidp->mx);
8047 /* we don't need this any longer */
8049 cm_ReleaseSCache(dscp);
8051 cm_Open(scp, 0, userp);
8053 /* set inp->fid so that later read calls in same msg can find fid */
8054 inp->fid = fidp->fid;
8056 /* check whether we are required to send an extended response */
8057 if (!extendedRespRequired) {
8059 parmOffset = 8*4 + 39;
8060 parmOffset += 1; /* pad to 4 */
8061 dataOffset = parmOffset + 70;
8065 /* Total Parameter Count */
8066 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8067 /* Total Data Count */
8068 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8069 /* Parameter Count */
8070 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8071 /* Parameter Offset */
8072 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8073 /* Parameter Displacement */
8074 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8076 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8078 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8079 /* Data Displacement */
8080 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8081 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8082 smb_SetSMBDataLength(outp, 70);
8084 lock_ObtainRead(&scp->rw);
8085 outData = smb_GetSMBData(outp, NULL);
8086 outData++; /* round to get to parmOffset */
8087 *outData = 0; outData++; /* oplock */
8088 *outData = 0; outData++; /* reserved */
8089 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8090 *((ULONG *)outData) = openAction; outData += 4;
8091 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8092 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8093 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8094 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8095 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8096 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8097 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8098 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8099 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8100 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8101 *((USHORT *)outData) = 0; outData += 2; /* dev state */
8102 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8103 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8104 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8105 outData += 2; /* is a dir? */
8108 parmOffset = 8*4 + 39;
8109 parmOffset += 1; /* pad to 4 */
8110 dataOffset = parmOffset + 104;
8114 /* Total Parameter Count */
8115 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8116 /* Total Data Count */
8117 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8118 /* Parameter Count */
8119 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8120 /* Parameter Offset */
8121 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8122 /* Parameter Displacement */
8123 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8125 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8127 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8128 /* Data Displacement */
8129 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8130 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8131 smb_SetSMBDataLength(outp, 105);
8133 lock_ObtainRead(&scp->rw);
8134 outData = smb_GetSMBData(outp, NULL);
8135 outData++; /* round to get to parmOffset */
8136 *outData = 0; outData++; /* oplock */
8137 *outData = 1; outData++; /* response type */
8138 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8139 *((ULONG *)outData) = openAction; outData += 4;
8140 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8141 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8142 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8143 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8144 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8145 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8146 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8147 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8148 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8149 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8150 *((USHORT *)outData) = 0; outData += 2; /* dev state */
8151 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8152 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8153 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8154 outData += 1; /* is a dir? */
8155 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
8156 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
8157 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
8160 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
8161 LargeIntegerGreaterThanZero(fidp->scp->length) &&
8162 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
8163 cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
8164 fidp->scp->length.LowPart, fidp->scp->length.HighPart,
8167 lock_ReleaseRead(&scp->rw);
8169 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
8171 cm_ReleaseUser(userp);
8172 smb_ReleaseFID(fidp);
8174 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
8175 /* leave scp held since we put it in fidp->scp */
8179 /* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
8180 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
8183 smb_packet_t *savedPacketp;
8185 USHORT fid, watchtree;
8189 filter = smb_GetSMBParm(inp, 19) |
8190 (smb_GetSMBParm(inp, 20) << 16);
8191 fid = smb_GetSMBParm(inp, 21);
8192 watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
8194 fidp = smb_FindFID(vcp, fid, 0);
8196 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
8197 return CM_ERROR_BADFD;
8200 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8201 smb_CloseFID(vcp, fidp, NULL, 0);
8202 smb_ReleaseFID(fidp);
8203 return CM_ERROR_NOSUCHFILE;
8206 /* Create a copy of the Directory Watch Packet to use when sending the
8207 * notification if in the future a matching change is detected.
8209 savedPacketp = smb_CopyPacket(inp);
8211 if (savedPacketp->vcp)
8212 smb_ReleaseVC(savedPacketp->vcp);
8213 savedPacketp->vcp = vcp;
8215 /* Add the watch to the list of events to send notifications for */
8216 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8217 savedPacketp->nextp = smb_Directory_Watches;
8218 smb_Directory_Watches = savedPacketp;
8219 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8222 osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%S\"",
8223 fidp, scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp));
8224 osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
8225 filter, fid, watchtree);
8226 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8227 osi_Log0(smb_logp, " Notify Change File Name");
8228 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8229 osi_Log0(smb_logp, " Notify Change Directory Name");
8230 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8231 osi_Log0(smb_logp, " Notify Change Attributes");
8232 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8233 osi_Log0(smb_logp, " Notify Change Size");
8234 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8235 osi_Log0(smb_logp, " Notify Change Last Write");
8236 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8237 osi_Log0(smb_logp, " Notify Change Last Access");
8238 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8239 osi_Log0(smb_logp, " Notify Change Creation");
8240 if (filter & FILE_NOTIFY_CHANGE_EA)
8241 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8242 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8243 osi_Log0(smb_logp, " Notify Change Security");
8244 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8245 osi_Log0(smb_logp, " Notify Change Stream Name");
8246 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8247 osi_Log0(smb_logp, " Notify Change Stream Size");
8248 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8249 osi_Log0(smb_logp, " Notify Change Stream Write");
8251 lock_ObtainWrite(&scp->rw);
8253 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
8255 scp->flags |= CM_SCACHEFLAG_WATCHED;
8256 lock_ReleaseWrite(&scp->rw);
8257 smb_ReleaseFID(fidp);
8259 outp->flags |= SMB_PACKETFLAG_NOSEND;
8263 unsigned char nullSecurityDesc[36] = {
8264 0x01, /* security descriptor revision */
8265 0x00, /* reserved, should be zero */
8266 0x00, 0x80, /* security descriptor control;
8267 * 0x8000 : self-relative format */
8268 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
8269 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
8270 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
8271 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
8272 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8273 /* "null SID" owner SID */
8274 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
8275 /* "null SID" group SID */
8278 /* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
8279 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8281 int parmOffset, parmCount, dataOffset, dataCount;
8289 ULONG securityInformation;
8291 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8292 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8293 parmp = inp->data + parmOffset;
8294 sparmp = (USHORT *) parmp;
8295 lparmp = (ULONG *) parmp;
8298 securityInformation = lparmp[1];
8300 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
8301 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
8309 parmOffset = 8*4 + 39;
8310 parmOffset += 1; /* pad to 4 */
8312 dataOffset = parmOffset + parmCount;
8316 /* Total Parameter Count */
8317 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8318 /* Total Data Count */
8319 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8320 /* Parameter Count */
8321 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8322 /* Parameter Offset */
8323 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8324 /* Parameter Displacement */
8325 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8327 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8329 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8330 /* Data Displacement */
8331 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8332 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8333 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
8335 outData = smb_GetSMBData(outp, NULL);
8336 outData++; /* round to get to parmOffset */
8337 *((ULONG *)outData) = 36; outData += 4; /* length */
8339 if (maxData >= 36) {
8340 memcpy(outData, nullSecurityDesc, 36);
8344 return CM_ERROR_BUFFERTOOSMALL;
8347 /* SMB_COM_NT_TRANSACT
8349 SMB_COM_NT_TRANSACT_SECONDARY should also be handled here.
8351 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8353 unsigned short function;
8355 function = smb_GetSMBParm(inp, 18);
8357 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
8359 /* We can handle long names */
8360 if (vcp->flags & SMB_VCFLAG_USENT)
8361 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
8364 case 1: /* NT_TRANSACT_CREATE */
8365 return smb_ReceiveNTTranCreate(vcp, inp, outp);
8366 case 2: /* NT_TRANSACT_IOCTL */
8367 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
8369 case 3: /* NT_TRANSACT_SET_SECURITY_DESC */
8370 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
8372 case 4: /* NT_TRANSACT_NOTIFY_CHANGE */
8373 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
8374 case 5: /* NT_TRANSACT_RENAME */
8375 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
8377 case 6: /* NT_TRANSACT_QUERY_SECURITY_DESC */
8378 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
8380 osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
8383 osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
8386 return CM_ERROR_INVAL;
8390 * smb_NotifyChange -- find relevant change notification messages and
8393 * If we don't know the file name (i.e. a callback break), filename is
8394 * NULL, and we return a zero-length list.
8396 * At present there is not a single call to smb_NotifyChange that
8397 * has the isDirectParent parameter set to FALSE.
8399 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
8400 cm_scache_t *dscp, clientchar_t *filename, clientchar_t *otherFilename,
8401 BOOL isDirectParent)
8403 smb_packet_t *watch, *lastWatch, *nextWatch;
8404 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen = 0;
8405 char *outData, *oldOutData;
8409 BOOL twoEntries = FALSE;
8410 ULONG otherNameLen, oldParmCount = 0;
8414 /* Get ready for rename within directory */
8415 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
8417 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
8420 osi_Log4(smb_logp,"in smb_NotifyChange for file [%S] dscp [%p] notification 0x%x parent %d",
8421 osi_LogSaveClientString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
8423 osi_Log0(smb_logp," FILE_ACTION_NONE");
8424 if (action == FILE_ACTION_ADDED)
8425 osi_Log0(smb_logp," FILE_ACTION_ADDED");
8426 if (action == FILE_ACTION_REMOVED)
8427 osi_Log0(smb_logp," FILE_ACTION_REMOVED");
8428 if (action == FILE_ACTION_MODIFIED)
8429 osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
8430 if (action == FILE_ACTION_RENAMED_OLD_NAME)
8431 osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
8432 if (action == FILE_ACTION_RENAMED_NEW_NAME)
8433 osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
8435 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8436 watch = smb_Directory_Watches;
8438 filter = smb_GetSMBParm(watch, 19)
8439 | (smb_GetSMBParm(watch, 20) << 16);
8440 fid = smb_GetSMBParm(watch, 21);
8441 wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
8443 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
8444 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
8447 * Strange hack - bug in NT Client and NT Server that we must emulate?
8449 if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
8450 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
8452 fidp = smb_FindFID(watch->vcp, fid, 0);
8454 osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
8456 watch = watch->nextp;
8460 if (fidp->scp != dscp ||
8461 fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
8462 (filter & notifyFilter) == 0 ||
8463 (!isDirectParent && !wtree))
8465 osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
8466 smb_ReleaseFID(fidp);
8468 watch = watch->nextp;
8471 smb_ReleaseFID(fidp);
8474 "Sending Change Notification for fid %d filter 0x%x wtree %d file %S",
8475 fid, filter, wtree, osi_LogSaveClientString(smb_logp, filename));
8476 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8477 osi_Log0(smb_logp, " Notify Change File Name");
8478 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8479 osi_Log0(smb_logp, " Notify Change Directory Name");
8480 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8481 osi_Log0(smb_logp, " Notify Change Attributes");
8482 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8483 osi_Log0(smb_logp, " Notify Change Size");
8484 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8485 osi_Log0(smb_logp, " Notify Change Last Write");
8486 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8487 osi_Log0(smb_logp, " Notify Change Last Access");
8488 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8489 osi_Log0(smb_logp, " Notify Change Creation");
8490 if (filter & FILE_NOTIFY_CHANGE_EA)
8491 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8492 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8493 osi_Log0(smb_logp, " Notify Change Security");
8494 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8495 osi_Log0(smb_logp, " Notify Change Stream Name");
8496 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8497 osi_Log0(smb_logp, " Notify Change Stream Size");
8498 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8499 osi_Log0(smb_logp, " Notify Change Stream Write");
8501 /* A watch can only be notified once. Remove it from the list */
8502 nextWatch = watch->nextp;
8503 if (watch == smb_Directory_Watches)
8504 smb_Directory_Watches = nextWatch;
8506 lastWatch->nextp = nextWatch;
8508 /* Turn off WATCHED flag in dscp */
8509 lock_ObtainWrite(&dscp->rw);
8511 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8513 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
8514 lock_ReleaseWrite(&dscp->rw);
8516 /* Convert to response packet */
8517 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
8518 #ifdef SEND_CANONICAL_PATHNAMES
8519 ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
8521 ((smb_t *) watch)->wct = 0;
8524 if (filename == NULL) {
8527 nameLen = (ULONG)cm_ClientStrLen(filename);
8528 parmCount = 3*4 + nameLen*2;
8529 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8531 otherNameLen = (ULONG)cm_ClientStrLen(otherFilename);
8532 oldParmCount = parmCount;
8533 parmCount += 3*4 + otherNameLen*2;
8534 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8536 if (maxLen < parmCount)
8537 parmCount = 0; /* not enough room */
8539 parmOffset = 8*4 + 39;
8540 parmOffset += 1; /* pad to 4 */
8541 dataOffset = parmOffset + parmCount;
8545 /* Total Parameter Count */
8546 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8547 /* Total Data Count */
8548 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8549 /* Parameter Count */
8550 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8551 /* Parameter Offset */
8552 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
8553 /* Parameter Displacement */
8554 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8556 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8558 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
8559 /* Data Displacement */
8560 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8561 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
8562 smb_SetSMBDataLength(watch, parmCount + 1);
8564 if (parmCount != 0) {
8565 outData = smb_GetSMBData(watch, NULL);
8566 outData++; /* round to get to parmOffset */
8567 oldOutData = outData;
8568 *((DWORD *)outData) = oldParmCount; outData += 4;
8569 /* Next Entry Offset */
8570 *((DWORD *)outData) = action; outData += 4;
8572 *((DWORD *)outData) = nameLen*2; outData += 4;
8573 /* File Name Length */
8575 smb_UnparseString(watch, outData, filename, NULL, 0);
8579 outData = oldOutData + oldParmCount;
8580 *((DWORD *)outData) = 0; outData += 4;
8581 /* Next Entry Offset */
8582 *((DWORD *)outData) = otherAction; outData += 4;
8584 *((DWORD *)outData) = otherNameLen*2;
8585 outData += 4; /* File Name Length */
8586 smb_UnparseString(watch, outData, otherFilename, NULL, 0);
8591 * If filename is null, we don't know the cause of the
8592 * change notification. We return zero data (see above),
8593 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
8594 * (= 0x010C). We set the error code here by hand, without
8595 * modifying wct and bcc.
8597 if (filename == NULL) {
8598 ((smb_t *) watch)->rcls = 0x0C;
8599 ((smb_t *) watch)->reh = 0x01;
8600 ((smb_t *) watch)->errLow = 0;
8601 ((smb_t *) watch)->errHigh = 0;
8602 /* Set NT Status codes flag */
8603 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8606 smb_SendPacket(watch->vcp, watch);
8607 smb_FreePacket(watch);
8610 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8613 /* SMB_COM_NT_CANCEL */
8614 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8616 unsigned char *replyWctp;
8617 smb_packet_t *watch, *lastWatch;
8618 USHORT fid, watchtree;
8622 osi_Log0(smb_logp, "SMB3 receive NT cancel");
8624 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8625 watch = smb_Directory_Watches;
8627 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
8628 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
8629 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
8630 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
8631 if (watch == smb_Directory_Watches)
8632 smb_Directory_Watches = watch->nextp;
8634 lastWatch->nextp = watch->nextp;
8635 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8637 /* Turn off WATCHED flag in scp */
8638 fid = smb_GetSMBParm(watch, 21);
8639 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
8641 if (vcp != watch->vcp)
8642 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
8645 fidp = smb_FindFID(vcp, fid, 0);
8647 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %S",
8649 (fidp ? osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp) :_C("")));
8652 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
8653 lock_ObtainWrite(&scp->rw);
8655 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8657 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
8658 lock_ReleaseWrite(&scp->rw);
8659 smb_ReleaseFID(fidp);
8661 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
8664 /* assume STATUS32; return 0xC0000120 (CANCELED) */
8665 replyWctp = watch->wctp;
8669 ((smb_t *)watch)->rcls = 0x20;
8670 ((smb_t *)watch)->reh = 0x1;
8671 ((smb_t *)watch)->errLow = 0;
8672 ((smb_t *)watch)->errHigh = 0xC0;
8673 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8674 smb_SendPacket(vcp, watch);
8675 smb_FreePacket(watch);
8679 watch = watch->nextp;
8681 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8687 * NT rename also does hard links.
8690 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
8691 #define RENAME_FLAG_HARD_LINK 0x103
8692 #define RENAME_FLAG_RENAME 0x104
8693 #define RENAME_FLAG_COPY 0x105
8695 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8697 clientchar_t *oldPathp, *newPathp;
8703 attrs = smb_GetSMBParm(inp, 0);
8704 rename_type = smb_GetSMBParm(inp, 1);
8706 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
8707 osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
8708 return CM_ERROR_NOACCESS;
8711 tp = smb_GetSMBData(inp, NULL);
8712 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
8713 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
8715 osi_Log3(smb_logp, "NTRename for [%S]->[%S] type [%s]",
8716 osi_LogSaveClientString(smb_logp, oldPathp),
8717 osi_LogSaveClientString(smb_logp, newPathp),
8718 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
8720 if (rename_type == RENAME_FLAG_RENAME) {
8721 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
8722 } else { /* RENAME_FLAG_HARD_LINK */
8723 code = smb_Link(vcp,inp,oldPathp,newPathp);
8730 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
8733 cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
8735 smb_username_t *unp;
8738 unp = smb_FindUserByName(usern, machine, flags);
8740 lock_ObtainMutex(&unp->mx);
8741 unp->userp = cm_NewUser();
8742 lock_ReleaseMutex(&unp->mx);
8743 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
8745 osi_Log2(smb_logp,"smb_FindCMUserByName Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
8749 smb_ReleaseUsername(unp);