2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
15 #pragma warning(disable: 4005)
17 #define SECURITY_WIN32
29 #include <WINNT\afsreg.h>
34 extern osi_hyper_t hzero;
36 smb_packet_t *smb_Directory_Watches = NULL;
37 osi_mutex_t smb_Dir_Watch_Lock;
39 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
41 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
43 /* protected by the smb_globalLock */
44 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
46 const clientchar_t **smb_ExecutableExtensions = NULL;
48 /* retrieve a held reference to a user structure corresponding to an incoming
50 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
55 uidp = smb_FindUID(vcp, inp->uid, 0);
59 up = smb_GetUserFromUID(uidp);
67 * Return boolean specifying if the path name is thought to be an
68 * executable file. For now .exe or .dll.
70 afs_uint32 smb_IsExecutableFileName(const clientchar_t *name)
74 if ( smb_ExecutableExtensions == NULL || name == NULL)
77 len = (int)cm_ClientStrLen(name);
79 for ( i=0; smb_ExecutableExtensions[i]; i++) {
80 j = len - (int)cm_ClientStrLen(smb_ExecutableExtensions[i]);
81 if (cm_ClientStrCmpI(smb_ExecutableExtensions[i], &name[j]) == 0)
89 * Return extended attributes.
90 * Right now, we aren't using any of the "new" bits, so this looks exactly
91 * like smb_Attributes() (see smb.c).
93 unsigned long smb_ExtAttributes(cm_scache_t *scp)
97 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
98 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
99 scp->fileType == CM_SCACHETYPE_INVALID)
101 attrs = SMB_ATTR_DIRECTORY;
102 #ifdef SPECIAL_FOLDERS
103 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
104 #endif /* SPECIAL_FOLDERS */
105 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
106 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
107 } else if (scp->fid.vnode & 0x1)
108 attrs = SMB_ATTR_DIRECTORY;
113 * We used to mark a file RO if it was in an RO volume, but that
114 * turns out to be impolitic in NT. See defect 10007.
117 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
118 attrs |= SMB_ATTR_READONLY; /* Read-only */
120 if ((scp->unixModeBits & 0222) == 0)
121 attrs |= SMB_ATTR_READONLY; /* Read-only */
125 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
130 int smb_V3IsStarMask(clientchar_t *maskp)
134 while (tc = *maskp++)
135 if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
140 void OutputDebugF(clientchar_t * format, ...) {
142 clientchar_t vbuffer[1024];
144 va_start( args, format );
145 cm_ClientStrPrintfV(vbuffer, lengthof(vbuffer), format, args);
146 osi_Log1(smb_logp, "%S", osi_LogSaveClientString(smb_logp, vbuffer));
147 cm_ClientStrCat(vbuffer, lengthof(vbuffer), _C("\n"));
148 OutputDebugStringW(vbuffer);
151 void OutputDebugHexDump(unsigned char * buffer, int len) {
154 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
156 OutputDebugF(_C("Hexdump length [%d]"),len);
158 for (i=0;i<len;i++) {
161 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
162 StringCchCatA(buf, lengthof(buf), "\r\n");
163 OutputDebugString(buf);
165 StringCchPrintfA(buf, lengthof(buf), "%5x", i);
166 memset(buf+5,' ',80);
171 j = j*3 + 7 + ((j>7)?1:0);
174 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
177 j = j + 56 + ((j>7)?1:0);
179 buf[j] = (k>32 && k<127)?k:'.';
182 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
183 StringCchCatA(buf, lengthof(buf), "\r\n");
184 OutputDebugString(buf);
188 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
190 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
191 SECURITY_STATUS status, istatus;
192 CredHandle creds = {0,0};
194 SecBufferDesc secOut;
202 OutputDebugF(_C("Negotiating Extended Security"));
204 status = AcquireCredentialsHandle( NULL,
205 SMB_EXT_SEC_PACKAGE_NAME,
214 if (status != SEC_E_OK) {
215 /* Really bad. We return an empty security blob */
216 OutputDebugF(_C("AcquireCredentialsHandle failed with %lX"), status);
221 secOut.pBuffers = &secTok;
222 secOut.ulVersion = SECBUFFER_VERSION;
224 secTok.BufferType = SECBUFFER_TOKEN;
226 secTok.pvBuffer = NULL;
228 ctx.dwLower = ctx.dwUpper = 0;
230 status = AcceptSecurityContext( &creds,
233 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
234 SECURITY_NETWORK_DREP,
241 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
242 OutputDebugF(_C("Completing token..."));
243 istatus = CompleteAuthToken(&ctx, &secOut);
244 if ( istatus != SEC_E_OK )
245 OutputDebugF(_C("Token completion failed: %x"), istatus);
248 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
249 if (secTok.pvBuffer) {
250 *secBlobLength = secTok.cbBuffer;
251 *secBlob = malloc( secTok.cbBuffer );
252 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
255 if ( status != SEC_E_OK )
256 OutputDebugF(_C("AcceptSecurityContext status != CONTINUE %lX"), status);
259 /* Discard partial security context */
260 DeleteSecurityContext(&ctx);
262 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
264 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
265 FreeCredentialsHandle(&creds);
271 struct smb_ext_context {
278 long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern,
279 char * secBlobIn, int secBlobInLength,
280 char ** secBlobOut, int * secBlobOutLength) {
281 SECURITY_STATUS status, istatus;
285 SecBufferDesc secBufIn;
287 SecBufferDesc secBufOut;
290 struct smb_ext_context * secCtx = NULL;
291 struct smb_ext_context * newSecCtx = NULL;
292 void * assembledBlob = NULL;
293 int assembledBlobLength = 0;
296 OutputDebugF(_C("In smb_AuthenticateUserExt"));
299 *secBlobOutLength = 0;
301 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
302 secCtx = vcp->secCtx;
303 lock_ObtainMutex(&vcp->mx);
304 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
306 lock_ReleaseMutex(&vcp->mx);
310 OutputDebugF(_C("Received incoming token:"));
311 OutputDebugHexDump(secBlobIn,secBlobInLength);
315 OutputDebugF(_C("Continuing with existing context."));
316 creds = secCtx->creds;
319 if (secCtx->partialToken) {
320 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
321 assembledBlob = malloc(assembledBlobLength);
322 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
323 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
326 status = AcquireCredentialsHandle( NULL,
327 SMB_EXT_SEC_PACKAGE_NAME,
336 if (status != SEC_E_OK) {
337 OutputDebugF(_C("Can't acquire Credentials handle [%lX]"), status);
338 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
346 secBufIn.cBuffers = 1;
347 secBufIn.pBuffers = &secTokIn;
348 secBufIn.ulVersion = SECBUFFER_VERSION;
350 secTokIn.BufferType = SECBUFFER_TOKEN;
352 secTokIn.cbBuffer = assembledBlobLength;
353 secTokIn.pvBuffer = assembledBlob;
355 secTokIn.cbBuffer = secBlobInLength;
356 secTokIn.pvBuffer = secBlobIn;
359 secBufOut.cBuffers = 1;
360 secBufOut.pBuffers = &secTokOut;
361 secBufOut.ulVersion = SECBUFFER_VERSION;
363 secTokOut.BufferType = SECBUFFER_TOKEN;
364 secTokOut.cbBuffer = 0;
365 secTokOut.pvBuffer = NULL;
367 status = AcceptSecurityContext( &creds,
368 ((secCtx)?&ctx:NULL),
370 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
371 SECURITY_NETWORK_DREP,
378 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
379 OutputDebugF(_C("Completing token..."));
380 istatus = CompleteAuthToken(&ctx, &secBufOut);
381 if ( istatus != SEC_E_OK )
382 OutputDebugF(_C("Token completion failed: %lX"), istatus);
385 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
386 OutputDebugF(_C("Continue needed"));
388 newSecCtx = malloc(sizeof(*newSecCtx));
390 newSecCtx->creds = creds;
391 newSecCtx->ctx = ctx;
392 newSecCtx->partialToken = NULL;
393 newSecCtx->partialTokenLen = 0;
395 lock_ObtainMutex( &vcp->mx );
396 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
397 vcp->secCtx = newSecCtx;
398 lock_ReleaseMutex( &vcp->mx );
400 code = CM_ERROR_GSSCONTINUE;
403 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
404 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
405 secTokOut.pvBuffer) {
406 OutputDebugF(_C("Need to send token back to client"));
408 *secBlobOutLength = secTokOut.cbBuffer;
409 *secBlobOut = malloc(secTokOut.cbBuffer);
410 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
412 OutputDebugF(_C("Outgoing token:"));
413 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
414 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
415 OutputDebugF(_C("Incomplete message"));
417 newSecCtx = malloc(sizeof(*newSecCtx));
419 newSecCtx->creds = creds;
420 newSecCtx->ctx = ctx;
421 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
422 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
423 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
425 lock_ObtainMutex( &vcp->mx );
426 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
427 vcp->secCtx = newSecCtx;
428 lock_ReleaseMutex( &vcp->mx );
430 code = CM_ERROR_GSSCONTINUE;
433 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
435 SecPkgContext_NamesW names;
437 OutputDebugF(_C("Authentication completed"));
438 OutputDebugF(_C("Returned flags : [%lX]"), flags);
440 if (!QueryContextAttributesW(&ctx, SECPKG_ATTR_NAMES, &names)) {
441 OutputDebugF(_C("Received name [%s]"), names.sUserName);
442 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, names.sUserName);
443 cm_ClientStrLwr(usern); /* in tandem with smb_GetNormalizedUsername */
444 FreeContextBuffer(names.sUserName);
446 /* Force the user to retry if the context is invalid */
447 OutputDebugF(_C("QueryContextAttributes Names failed [%x]"), GetLastError());
448 code = CM_ERROR_BADPASSWORD;
452 case SEC_E_INVALID_TOKEN:
453 OutputDebugF(_C("Returning bad password :: INVALID_TOKEN"));
455 case SEC_E_INVALID_HANDLE:
456 OutputDebugF(_C("Returning bad password :: INVALID_HANDLE"));
458 case SEC_E_LOGON_DENIED:
459 OutputDebugF(_C("Returning bad password :: LOGON_DENIED"));
461 case SEC_E_UNKNOWN_CREDENTIALS:
462 OutputDebugF(_C("Returning bad password :: UNKNOWN_CREDENTIALS"));
464 case SEC_E_NO_CREDENTIALS:
465 OutputDebugF(_C("Returning bad password :: NO_CREDENTIALS"));
467 case SEC_E_CONTEXT_EXPIRED:
468 OutputDebugF(_C("Returning bad password :: CONTEXT_EXPIRED"));
470 case SEC_E_INCOMPLETE_CREDENTIALS:
471 OutputDebugF(_C("Returning bad password :: INCOMPLETE_CREDENTIALS"));
473 case SEC_E_WRONG_PRINCIPAL:
474 OutputDebugF(_C("Returning bad password :: WRONG_PRINCIPAL"));
476 case SEC_E_TIME_SKEW:
477 OutputDebugF(_C("Returning bad password :: TIME_SKEW"));
480 OutputDebugF(_C("Returning bad password :: Status == %lX"), status);
482 code = CM_ERROR_BADPASSWORD;
486 if (secCtx->partialToken) free(secCtx->partialToken);
494 if (secTokOut.pvBuffer)
495 FreeContextBuffer(secTokOut.pvBuffer);
497 if (code != CM_ERROR_GSSCONTINUE) {
498 DeleteSecurityContext(&ctx);
499 FreeCredentialsHandle(&creds);
507 #define P_RESP_LEN 128
509 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
510 So put stuff in a struct. */
511 struct Lm20AuthBlob {
512 MSV1_0_LM20_LOGON lmlogon;
513 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
514 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
515 WCHAR accountNameW[P_LEN];
516 WCHAR primaryDomainW[P_LEN];
517 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
518 TOKEN_GROUPS tgroups;
519 TOKEN_SOURCE tsource;
522 long smb_AuthenticateUserLM(smb_vc_t *vcp, clientchar_t * accountName, clientchar_t * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
525 struct Lm20AuthBlob lmAuth;
526 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
527 QUOTA_LIMITS quotaLimits;
529 ULONG lmprofilepSize;
533 OutputDebugF(_C("In smb_AuthenticateUser for user [%s] domain [%s]"), accountName, primaryDomain);
534 OutputDebugF(_C("ciPwdLength is %d and csPwdLength is %d"), ciPwdLength, csPwdLength);
536 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
537 OutputDebugF(_C("ciPwdLength or csPwdLength is too long"));
538 return CM_ERROR_BADPASSWORD;
541 memset(&lmAuth,0,sizeof(lmAuth));
543 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
545 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
546 cm_ClientStringToUtf16(primaryDomain, -1, lmAuth.primaryDomainW, P_LEN);
547 lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
548 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
550 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
551 cm_ClientStringToUtf16(accountName, -1, lmAuth.accountNameW, P_LEN);
552 lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
553 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
555 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
556 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
557 size = MAX_COMPUTERNAME_LENGTH + 1;
558 GetComputerNameW(lmAuth.workstationW, &size);
559 lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
561 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
563 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
564 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
565 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
566 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
568 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
569 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
570 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
571 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
573 lmAuth.lmlogon.ParameterControl = 0;
575 lmAuth.tgroups.GroupCount = 0;
576 lmAuth.tgroups.Groups[0].Sid = NULL;
577 lmAuth.tgroups.Groups[0].Attributes = 0;
580 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
582 lmAuth.tsource.SourceIdentifier.HighPart = 0;
584 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
585 StringCchCopyA(lmAuth.tsource.SourceName, lengthof(lmAuth.tsource.SourceName),
586 "OpenAFS"); /* 8 char limit */
588 nts = LsaLogonUser( smb_lsaHandle,
603 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
604 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
607 OutputDebugF(_C("Return from LsaLogonUser is 0x%lX"), nts);
608 OutputDebugF(_C("Extended status is 0x%lX"), ntsEx);
610 if (nts == ERROR_SUCCESS) {
612 LsaFreeReturnBuffer(lmprofilep);
613 CloseHandle(lmToken);
617 if (nts == 0xC000015BL)
618 return CM_ERROR_BADLOGONTYPE;
619 else /* our catchall is a bad password though we could be more specific */
620 return CM_ERROR_BADPASSWORD;
624 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
625 long smb_GetNormalizedUsername(clientchar_t * usern, const clientchar_t * accountName, const clientchar_t * domainName)
627 clientchar_t * atsign;
628 const clientchar_t * domain;
630 /* check if we have sane input */
631 if ((cm_ClientStrLen(accountName) + cm_ClientStrLen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
634 /* we could get : [accountName][domainName]
640 atsign = cm_ClientStrChr(accountName, '@');
642 if (atsign) /* [user@domain][] -> [user@domain][domain] */
647 /* if for some reason the client doesn't know what domain to use,
648 it will either return an empty string or a '?' */
649 if (!domain[0] || domain[0] == '?')
650 /* Empty domains and empty usernames are usually sent from tokenless contexts.
651 This way such logins will get an empty username (easy to check). I don't know
652 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
653 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, accountName);
655 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
656 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, domain);
657 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, _C("\\"));
659 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
661 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
664 cm_ClientStrLwr(usern);
669 /* When using SMB auth, all SMB sessions have to pass through here
670 * first to authenticate the user.
672 * Caveat: If not using SMB auth, the protocol does not require
673 * sending a session setup packet, which means that we can't rely on a
674 * UID in subsequent packets. Though in practice we get one anyway.
676 /* SMB_COM_SESSION_SETUP_ANDX */
677 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
681 unsigned short newUid;
682 unsigned long caps = 0;
684 clientchar_t *s1 = _C(" ");
686 clientchar_t usern[SMB_MAX_USERNAME_LENGTH];
687 char *secBlobOut = NULL;
688 int secBlobOutLength = 0;
690 /* Check for bad conns */
691 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
692 return CM_ERROR_REMOTECONN;
694 if (vcp->flags & SMB_VCFLAG_USENT) {
695 if (smb_authType == SMB_AUTH_EXTENDED) {
696 /* extended authentication */
700 OutputDebugF(_C("NT Session Setup: Extended"));
702 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
703 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
706 secBlobInLength = smb_GetSMBParm(inp, 7);
707 secBlobIn = smb_GetSMBData(inp, NULL);
709 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
711 if (code == CM_ERROR_GSSCONTINUE) {
714 smb_SetSMBParm(outp, 2, 0);
715 smb_SetSMBParm(outp, 3, secBlobOutLength);
717 tp = smb_GetSMBData(outp, NULL);
718 if (secBlobOutLength) {
719 memcpy(tp, secBlobOut, secBlobOutLength);
721 tp += secBlobOutLength;
722 cb_data += secBlobOutLength;
724 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
725 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
726 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
728 smb_SetSMBDataLength(outp, cb_data);
731 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
733 unsigned ciPwdLength, csPwdLength;
735 clientchar_t *accountName;
736 clientchar_t *primaryDomain;
739 if (smb_authType == SMB_AUTH_NTLM)
740 OutputDebugF(_C("NT Session Setup: NTLM"));
742 OutputDebugF(_C("NT Session Setup: None"));
744 /* TODO: parse for extended auth as well */
745 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
746 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
748 tp = smb_GetSMBData(inp, &datalen);
750 OutputDebugF(_C("Session packet data size [%d]"),datalen);
757 accountName = smb_ParseString(inp, tp, &tp, 0);
758 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
760 OutputDebugF(_C("Account Name: %s"),accountName);
761 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
762 OutputDebugF(_C("Case Sensitive Password: %s"),
763 csPwd && csPwd[0] ? _C("yes") : _C("no"));
764 OutputDebugF(_C("Case Insensitive Password: %s"),
765 ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
767 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
768 /* shouldn't happen */
769 code = CM_ERROR_BADSMB;
770 goto after_read_packet;
773 /* capabilities are only valid for first session packet */
774 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
775 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
778 if (smb_authType == SMB_AUTH_NTLM) {
779 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
781 OutputDebugF(_C("LM authentication failed [%d]"), code);
783 OutputDebugF(_C("LM authentication succeeded"));
787 unsigned ciPwdLength;
789 clientchar_t *accountName;
790 clientchar_t *primaryDomain;
792 switch ( smb_authType ) {
793 case SMB_AUTH_EXTENDED:
794 OutputDebugF(_C("V3 Session Setup: Extended"));
797 OutputDebugF(_C("V3 Session Setup: NTLM"));
800 OutputDebugF(_C("V3 Session Setup: None"));
802 ciPwdLength = smb_GetSMBParm(inp, 7);
803 tp = smb_GetSMBData(inp, NULL);
807 accountName = smb_ParseString(inp, tp, &tp, 0);
808 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
810 OutputDebugF(_C("Account Name: %s"),accountName);
811 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
812 OutputDebugF(_C("Case Insensitive Password: %s"), ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
814 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
815 /* shouldn't happen */
816 code = CM_ERROR_BADSMB;
817 goto after_read_packet;
820 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
823 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
824 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
826 OutputDebugF(_C("LM authentication failed [%d]"), code);
828 OutputDebugF(_C("LM authentication succeeded"));
833 /* note down that we received a session setup X and set the capabilities flag */
834 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
835 lock_ObtainMutex(&vcp->mx);
836 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
837 /* for the moment we can only deal with NTSTATUS */
838 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
839 vcp->flags |= SMB_VCFLAG_STATUS32;
843 if ((caps & NTNEGOTIATE_CAPABILITY_UNICODE) && smb_UseUnicode) {
844 vcp->flags |= SMB_VCFLAG_USEUNICODE;
847 lock_ReleaseMutex(&vcp->mx);
850 /* code would be non-zero if there was an authentication failure.
851 Ideally we would like to invalidate the uid for this session or break
852 early to avoid accidently stealing someone else's tokens. */
858 OutputDebugF(_C("Received username=[%s]"), usern);
860 /* On Windows 2000, this function appears to be called more often than
861 it is expected to be called. This resulted in multiple smb_user_t
862 records existing all for the same user session which results in all
863 of the users tokens disappearing.
865 To avoid this problem, we look for an existing smb_user_t record
866 based on the users name, and use that one if we find it.
869 uidp = smb_FindUserByNameThisSession(vcp, usern);
870 if (uidp) { /* already there, so don't create a new one */
872 newUid = uidp->userID;
873 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
874 vcp->lana,vcp->lsn,newUid);
875 smb_ReleaseUID(uidp);
880 /* do a global search for the username/machine name pair */
881 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
882 lock_ObtainMutex(&unp->mx);
883 if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
884 /* clear the afslogon flag so that the tickets can now
885 * be freed when the refCount returns to zero.
887 unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
889 lock_ReleaseMutex(&unp->mx);
891 /* Create a new UID and cm_user_t structure */
894 userp = cm_NewUser();
895 cm_HoldUserVCRef(userp);
896 lock_ObtainMutex(&vcp->mx);
897 if (!vcp->uidCounter)
898 vcp->uidCounter++; /* handle unlikely wraparounds */
899 newUid = (cm_ClientStrLen(usern)==0)?0:vcp->uidCounter++;
900 lock_ReleaseMutex(&vcp->mx);
902 /* Create a new smb_user_t structure and connect them up */
903 lock_ObtainMutex(&unp->mx);
905 lock_ReleaseMutex(&unp->mx);
907 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
909 lock_ObtainMutex(&uidp->mx);
911 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
912 lock_ReleaseMutex(&uidp->mx);
913 smb_ReleaseUID(uidp);
917 /* Return UID to the client */
918 ((smb_t *)outp)->uid = newUid;
919 /* Also to the next chained message */
920 ((smb_t *)inp)->uid = newUid;
922 osi_Log3(smb_logp, "SMB3 session setup name %S creating ID %d%S",
923 osi_LogSaveClientString(smb_logp, usern), newUid,
924 osi_LogSaveClientString(smb_logp, s1));
926 smb_SetSMBParm(outp, 2, 0);
928 if (vcp->flags & SMB_VCFLAG_USENT) {
929 if (smb_authType == SMB_AUTH_EXTENDED) {
932 smb_SetSMBParm(outp, 3, secBlobOutLength);
934 tp = smb_GetSMBData(outp, NULL);
935 if (secBlobOutLength) {
936 memcpy(tp, secBlobOut, secBlobOutLength);
938 tp += secBlobOutLength;
939 cb_data += secBlobOutLength;
942 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
943 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
944 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
946 smb_SetSMBDataLength(outp, cb_data);
948 smb_SetSMBDataLength(outp, 0);
951 if (smb_authType == SMB_AUTH_EXTENDED) {
954 tp = smb_GetSMBData(outp, NULL);
956 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
957 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
958 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
960 smb_SetSMBDataLength(outp, cb_data);
962 smb_SetSMBDataLength(outp, 0);
969 /* SMB_COM_LOGOFF_ANDX */
970 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
974 /* find the tree and free it */
975 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
977 smb_username_t * unp;
979 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %S", uidp->userID,
980 osi_LogSaveClientString(smb_logp, (uidp->unp) ? uidp->unp->name: _C(" ")));
982 lock_ObtainMutex(&uidp->mx);
983 uidp->flags |= SMB_USERFLAG_DELETE;
985 * it doesn't get deleted right away
986 * because the vcp points to it
989 lock_ReleaseMutex(&uidp->mx);
992 /* we can't do this. we get logoff messages prior to a session
993 * disconnect even though it doesn't mean the user is logging out.
994 * we need to create a new pioctl and EventLogoff handler to set
995 * SMB_USERNAMEFLAG_LOGOFF.
997 if (unp && smb_LogoffTokenTransfer) {
998 lock_ObtainMutex(&unp->mx);
999 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
1000 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
1001 lock_ReleaseMutex(&unp->mx);
1005 smb_ReleaseUID(uidp);
1008 osi_Log0(smb_logp, "SMB3 user logoffX");
1010 smb_SetSMBDataLength(outp, 0);
1014 #define SMB_SUPPORT_SEARCH_BITS 0x0001
1015 #define SMB_SHARE_IS_IN_DFS 0x0002
1017 /* SMB_COM_TREE_CONNECT_ANDX */
1018 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1021 smb_user_t *uidp = NULL;
1022 unsigned short newTid;
1023 clientchar_t shareName[AFSPATHMAX];
1024 clientchar_t *sharePath;
1027 clientchar_t *slashp;
1028 clientchar_t *pathp;
1029 clientchar_t *passwordp;
1030 clientchar_t *servicep;
1031 cm_user_t *userp = NULL;
1034 osi_Log0(smb_logp, "SMB3 receive tree connect");
1036 /* parse input parameters */
1037 tp = smb_GetSMBData(inp, NULL);
1038 passwordp = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1039 pathp = smb_ParseString(inp, tp, &tp, SMB_STRF_ANSIPATH);
1040 servicep = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1042 slashp = cm_ClientStrRChr(pathp, '\\');
1044 return CM_ERROR_BADSMB;
1046 cm_ClientStrCpy(shareName, lengthof(shareName), slashp+1);
1048 osi_Log3(smb_logp, "Tree connect pathp[%S] shareName[%S] service[%S]",
1049 osi_LogSaveClientString(smb_logp, pathp),
1050 osi_LogSaveClientString(smb_logp, shareName),
1051 osi_LogSaveClientString(smb_logp, servicep));
1053 if (cm_ClientStrCmp(servicep, _C("IPC")) == 0 ||
1054 cm_ClientStrCmp(shareName, _C("IPC$")) == 0) {
1056 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1059 return CM_ERROR_NOIPC;
1063 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1065 userp = smb_GetUserFromUID(uidp);
1067 lock_ObtainMutex(&vcp->mx);
1068 newTid = vcp->tidCounter++;
1069 lock_ReleaseMutex(&vcp->mx);
1071 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1074 if (!cm_ClientStrCmp(shareName, _C("*.")))
1075 cm_ClientStrCpy(shareName, lengthof(shareName), _C("all"));
1076 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1079 smb_ReleaseUID(uidp);
1080 smb_ReleaseTID(tidp, FALSE);
1081 return CM_ERROR_BADSHARENAME;
1084 if (vcp->flags & SMB_VCFLAG_USENT)
1086 int policy = smb_FindShareCSCPolicy(shareName);
1089 DWORD dwAdvertiseDFS = 0, dwSize = sizeof(DWORD);
1091 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1092 0, KEY_QUERY_VALUE, &parmKey);
1093 if (code == ERROR_SUCCESS) {
1094 code = RegQueryValueEx(parmKey, "AdvertiseDFS", NULL, NULL,
1095 (BYTE *)&dwAdvertiseDFS, &dwSize);
1096 if (code != ERROR_SUCCESS)
1098 RegCloseKey (parmKey);
1100 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1101 (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
1105 smb_SetSMBParm(outp, 2, 0);
1109 smb_ReleaseUID(uidp);
1111 lock_ObtainMutex(&tidp->mx);
1112 tidp->userp = userp;
1113 tidp->pathname = sharePath;
1115 tidp->flags |= SMB_TIDFLAG_IPC;
1116 lock_ReleaseMutex(&tidp->mx);
1117 smb_ReleaseTID(tidp, FALSE);
1119 ((smb_t *)outp)->tid = newTid;
1120 ((smb_t *)inp)->tid = newTid;
1121 tp = smb_GetSMBData(outp, NULL);
1125 tp = smb_UnparseString(outp, tp, _C("A:"), &cb_data, SMB_STRF_FORCEASCII);
1126 tp = smb_UnparseString(outp, tp, _C("AFS"), &cb_data, 0);
1127 smb_SetSMBDataLength(outp, cb_data);
1131 tp = smb_UnparseString(outp, tp, _C("IPC"), &cb_data, SMB_STRF_FORCEASCII);
1132 smb_SetSMBDataLength(outp, cb_data);
1135 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1139 /* must be called with global tran lock held */
1140 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1142 smb_tran2Packet_t *tp;
1145 smbp = (smb_t *) inp->data;
1146 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1147 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1153 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1154 int totalParms, int totalData)
1156 smb_tran2Packet_t *tp;
1159 smbp = (smb_t *) inp->data;
1160 tp = malloc(sizeof(*tp));
1161 memset(tp, 0, sizeof(*tp));
1164 tp->curData = tp->curParms = 0;
1165 tp->totalData = totalData;
1166 tp->totalParms = totalParms;
1167 tp->tid = smbp->tid;
1168 tp->mid = smbp->mid;
1169 tp->uid = smbp->uid;
1170 tp->pid = smbp->pid;
1171 tp->res[0] = smbp->res[0];
1172 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1173 if (totalParms != 0)
1174 tp->parmsp = malloc(totalParms);
1176 tp->datap = malloc(totalData);
1177 if (smbp->com == 0x25 || smbp->com == 0x26)
1180 tp->opcode = smb_GetSMBParm(inp, 14);
1183 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1185 if (WANTS_UNICODE(inp) && (vcp->flags & SMB_VCFLAG_USEUNICODE))
1186 tp->flags |= SMB_TRAN2PFLAG_USEUNICODE;
1191 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1192 smb_tran2Packet_t *inp, smb_packet_t *outp,
1193 int totalParms, int totalData)
1195 smb_tran2Packet_t *tp;
1196 unsigned short parmOffset;
1197 unsigned short dataOffset;
1198 unsigned short dataAlign;
1200 tp = malloc(sizeof(*tp));
1201 memset(tp, 0, sizeof(*tp));
1204 tp->curData = tp->curParms = 0;
1205 tp->totalData = totalData;
1206 tp->totalParms = totalParms;
1207 tp->oldTotalParms = totalParms;
1212 tp->res[0] = inp->res[0];
1213 tp->opcode = inp->opcode;
1217 * We calculate where the parameters and data will start.
1218 * This calculation must parallel the calculation in
1219 * smb_SendTran2Packet.
1222 parmOffset = 10*2 + 35;
1223 parmOffset++; /* round to even */
1224 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1226 dataOffset = parmOffset + totalParms;
1227 dataAlign = dataOffset & 2; /* quad-align */
1228 dataOffset += dataAlign;
1229 tp->datap = outp->data + dataOffset;
1234 /* free a tran2 packet */
1235 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1238 smb_ReleaseVC(t2p->vcp);
1241 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1247 while (t2p->stringsp) {
1251 t2p->stringsp = ns->nextp;
1257 clientchar_t *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
1258 char ** chainpp, int flags)
1263 if (!(p->flags & SMB_TRAN2PFLAG_USEUNICODE))
1264 flags |= SMB_STRF_FORCEASCII;
1267 cb = p->totalParms - (inp - (char *)p->parmsp);
1268 if (inp < (char *) p->parmsp ||
1269 inp >= ((char *) p->parmsp) + p->totalParms) {
1270 #ifdef DEBUG_UNICODE
1276 return smb_ParseStringBuf((unsigned char *) p->parmsp, &p->stringsp,
1277 inp, &cb, chainpp, flags);
1280 /* called with a VC, an input packet to respond to, and an error code.
1281 * sends an error response.
1283 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1284 smb_packet_t *tp, long code)
1287 unsigned short errCode;
1288 unsigned char errClass;
1289 unsigned long NTStatus;
1291 if (vcp->flags & SMB_VCFLAG_STATUS32)
1292 smb_MapNTError(code, &NTStatus);
1294 smb_MapCoreError(code, vcp, &errCode, &errClass);
1296 smb_FormatResponsePacket(vcp, NULL, tp);
1297 smbp = (smb_t *) tp;
1299 /* We can handle long names */
1300 if (vcp->flags & SMB_VCFLAG_USENT)
1301 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1303 /* now copy important fields from the tran 2 packet */
1304 smbp->com = t2p->com;
1305 smbp->tid = t2p->tid;
1306 smbp->mid = t2p->mid;
1307 smbp->pid = t2p->pid;
1308 smbp->uid = t2p->uid;
1309 smbp->res[0] = t2p->res[0];
1310 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1311 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1312 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1313 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1314 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1315 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1318 smbp->rcls = errClass;
1319 smbp->errLow = (unsigned char) (errCode & 0xff);
1320 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1324 smb_SendPacket(vcp, tp);
1327 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1330 unsigned short parmOffset;
1331 unsigned short dataOffset;
1332 unsigned short totalLength;
1333 unsigned short dataAlign;
1336 smb_FormatResponsePacket(vcp, NULL, tp);
1337 smbp = (smb_t *) tp;
1339 /* We can handle long names */
1340 if (vcp->flags & SMB_VCFLAG_USENT)
1341 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1343 /* now copy important fields from the tran 2 packet */
1344 smbp->com = t2p->com;
1345 smbp->tid = t2p->tid;
1346 smbp->mid = t2p->mid;
1347 smbp->pid = t2p->pid;
1348 smbp->uid = t2p->uid;
1349 smbp->res[0] = t2p->res[0];
1351 totalLength = 1 + t2p->totalData + t2p->totalParms;
1353 /* now add the core parameters (tran2 info) to the packet */
1354 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1355 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1356 smb_SetSMBParm(tp, 2, 0); /* reserved */
1357 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1358 parmOffset = 10*2 + 35; /* parm offset in packet */
1359 parmOffset++; /* round to even */
1360 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1361 * hdr, bcc and wct */
1362 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1363 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1364 dataOffset = parmOffset + t2p->oldTotalParms;
1365 dataAlign = dataOffset & 2; /* quad-align */
1366 dataOffset += dataAlign;
1367 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1368 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1369 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1372 datap = smb_GetSMBData(tp, NULL);
1373 *datap++ = 0; /* we rounded to even */
1375 totalLength += dataAlign;
1376 smb_SetSMBDataLength(tp, totalLength);
1378 /* next, send the datagram */
1379 smb_SendPacket(vcp, tp);
1383 /* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
1384 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1386 smb_tran2Packet_t *asp;
1399 /* We sometimes see 0 word count. What to do? */
1400 if (*inp->wctp == 0) {
1401 osi_Log0(smb_logp, "Transaction2 word count = 0");
1402 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1404 smb_SetSMBDataLength(outp, 0);
1405 smb_SendPacket(vcp, outp);
1409 totalParms = smb_GetSMBParm(inp, 0);
1410 totalData = smb_GetSMBParm(inp, 1);
1412 firstPacket = (inp->inCom == 0x25);
1414 /* find the packet we're reassembling */
1415 lock_ObtainWrite(&smb_globalLock);
1416 asp = smb_FindTran2Packet(vcp, inp);
1418 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1420 lock_ReleaseWrite(&smb_globalLock);
1422 /* now merge in this latest packet; start by looking up offsets */
1424 parmDisp = dataDisp = 0;
1425 parmOffset = smb_GetSMBParm(inp, 10);
1426 dataOffset = smb_GetSMBParm(inp, 12);
1427 parmCount = smb_GetSMBParm(inp, 9);
1428 dataCount = smb_GetSMBParm(inp, 11);
1429 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1430 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1432 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1433 totalData, dataCount, asp->maxReturnData);
1436 parmDisp = smb_GetSMBParm(inp, 4);
1437 parmOffset = smb_GetSMBParm(inp, 3);
1438 dataDisp = smb_GetSMBParm(inp, 7);
1439 dataOffset = smb_GetSMBParm(inp, 6);
1440 parmCount = smb_GetSMBParm(inp, 2);
1441 dataCount = smb_GetSMBParm(inp, 5);
1443 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1444 parmCount, dataCount);
1447 /* now copy the parms and data */
1448 if ( asp->totalParms > 0 && parmCount != 0 )
1450 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1452 if ( asp->totalData > 0 && dataCount != 0 ) {
1453 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1456 /* account for new bytes */
1457 asp->curData += dataCount;
1458 asp->curParms += parmCount;
1460 /* finally, if we're done, remove the packet from the queue and dispatch it */
1461 if (asp->totalParms > 0 &&
1462 asp->curParms > 0 &&
1463 asp->totalData <= asp->curData &&
1464 asp->totalParms <= asp->curParms) {
1465 /* we've received it all */
1466 lock_ObtainWrite(&smb_globalLock);
1467 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1468 lock_ReleaseWrite(&smb_globalLock);
1470 /* now dispatch it */
1471 rapOp = asp->parmsp[0];
1473 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1474 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1475 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1476 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
1479 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1480 code = CM_ERROR_BADOP;
1483 /* if an error is returned, we're supposed to send an error packet,
1484 * otherwise the dispatched function already did the data sending.
1485 * We give dispatched proc the responsibility since it knows how much
1486 * space to allocate.
1489 smb_SendTran2Error(vcp, asp, outp, code);
1492 /* free the input tran 2 packet */
1493 smb_FreeTran2Packet(asp);
1495 else if (firstPacket) {
1496 /* the first packet in a multi-packet request, we need to send an
1497 * ack to get more data.
1499 smb_SetSMBDataLength(outp, 0);
1500 smb_SendPacket(vcp, outp);
1506 /* ANSI versions. */
1508 #pragma pack(push, 1)
1510 typedef struct smb_rap_share_info_0 {
1511 BYTE shi0_netname[13];
1512 } smb_rap_share_info_0_t;
1514 typedef struct smb_rap_share_info_1 {
1515 BYTE shi1_netname[13];
1518 DWORD shi1_remark; /* char *shi1_remark; data offset */
1519 } smb_rap_share_info_1_t;
1521 typedef struct smb_rap_share_info_2 {
1522 BYTE shi2_netname[13];
1525 DWORD shi2_remark; /* char *shi2_remark; data offset */
1526 WORD shi2_permissions;
1528 WORD shi2_current_uses;
1529 DWORD shi2_path; /* char *shi2_path; data offset */
1530 WORD shi2_passwd[9];
1532 } smb_rap_share_info_2_t;
1534 #define SMB_RAP_MAX_SHARES 512
1536 typedef struct smb_rap_share_list {
1539 smb_rap_share_info_0_t * shares;
1540 } smb_rap_share_list_t;
1544 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1545 smb_rap_share_list_t * sp;
1547 if (dep->name[0] == '.' && (!dep->name[1] || (dep->name[1] == '.' && !dep->name[2])))
1548 return 0; /* skip over '.' and '..' */
1550 sp = (smb_rap_share_list_t *) vrockp;
1552 strncpy(sp->shares[sp->cShare].shi0_netname, dep->name, 12);
1553 sp->shares[sp->cShare].shi0_netname[12] = 0;
1557 if (sp->cShare >= sp->maxShares)
1558 return CM_ERROR_STOPNOW;
1563 /* RAP NetShareEnumRequest */
1564 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1566 smb_tran2Packet_t *outp;
1567 unsigned short * tp;
1571 int outParmsTotal; /* total parameter bytes */
1572 int outDataTotal; /* total data bytes */
1575 DWORD allSubmount = 0;
1577 DWORD nRegShares = 0;
1578 DWORD nSharesRet = 0;
1580 HKEY hkSubmount = NULL;
1581 smb_rap_share_info_1_t * shares;
1584 clientchar_t thisShare[AFSPATHMAX];
1588 smb_rap_share_list_t rootShares;
1593 tp = p->parmsp + 1; /* skip over function number (always 0) */
1596 clientchar_t * cdescp;
1598 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1599 if (cm_ClientStrCmp(cdescp, _C("WrLeh")))
1600 return CM_ERROR_INVAL;
1601 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1602 if (cm_ClientStrCmp(cdescp, _C("B13BWz")))
1603 return CM_ERROR_INVAL;
1609 if (infoLevel != 1) {
1610 return CM_ERROR_INVAL;
1613 /* We are supposed to use the same ASCII data structure even if
1614 Unicode is negotiated, which ultimately means that the share
1615 names that we return must be at most 13 characters in length,
1616 including the NULL terminator.
1618 The RAP specification states that shares with names longer than
1619 12 characters should not be included in the enumeration.
1620 However, since we support prefix cell references and since many
1621 cell names are going to exceed 12 characters, we lie and send
1622 the first 12 characters.
1625 /* first figure out how many shares there are */
1626 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1627 KEY_QUERY_VALUE, &hkParam);
1628 if (rv == ERROR_SUCCESS) {
1629 len = sizeof(allSubmount);
1630 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1631 (BYTE *) &allSubmount, &len);
1632 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1635 RegCloseKey (hkParam);
1638 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1639 0, KEY_QUERY_VALUE, &hkSubmount);
1640 if (rv == ERROR_SUCCESS) {
1641 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1642 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1643 if (rv != ERROR_SUCCESS)
1649 /* fetch the root shares */
1650 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1651 rootShares.cShare = 0;
1652 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1656 userp = smb_GetTran2User(vcp,p);
1658 thyper.HighPart = 0;
1661 cm_HoldSCache(cm_data.rootSCachep);
1662 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1663 cm_ReleaseSCache(cm_data.rootSCachep);
1665 cm_ReleaseUser(userp);
1667 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1669 #define REMARK_LEN 1
1670 outParmsTotal = 8; /* 4 dwords */
1671 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1672 if(outDataTotal > bufsize) {
1673 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1674 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1677 nSharesRet = nShares;
1680 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1682 /* now for the submounts */
1683 shares = (smb_rap_share_info_1_t *) outp->datap;
1684 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1686 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1689 StringCchCopyA(shares[cshare].shi1_netname,
1690 lengthof(shares[cshare].shi1_netname), "all" );
1691 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1692 /* type and pad are zero already */
1698 for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
1699 len = sizeof(thisShare);
1700 rv = RegEnumValueW(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
1701 if (rv == ERROR_SUCCESS &&
1702 cm_ClientStrLen(thisShare) &&
1703 (!allSubmount || cm_ClientStrCmpI(thisShare,_C("all")))) {
1704 cm_ClientStringToUtf8(thisShare, -1, shares[cshare].shi1_netname,
1705 lengthof( shares[cshare].shi1_netname ));
1706 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1707 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1712 nShares--; /* uncount key */
1715 RegCloseKey(hkSubmount);
1718 nonrootShares = cshare;
1720 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1721 /* in case there are collisions with submounts, submounts have
1723 for (j=0; j < nonrootShares; j++)
1724 if (!cm_stricmp_utf8(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1727 if (j < nonrootShares) {
1728 nShares--; /* uncount */
1732 StringCchCopyA(shares[cshare].shi1_netname, lengthof(shares[cshare].shi1_netname),
1733 rootShares.shares[i].shi0_netname);
1734 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1739 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1740 outp->parmsp[1] = 0;
1741 outp->parmsp[2] = cshare;
1742 outp->parmsp[3] = nShares;
1744 outp->totalData = (int)(cstrp - outp->datap);
1745 outp->totalParms = outParmsTotal;
1747 smb_SendTran2Packet(vcp, outp, op);
1748 smb_FreeTran2Packet(outp);
1750 free(rootShares.shares);
1755 /* RAP NetShareGetInfo */
1756 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1758 smb_tran2Packet_t *outp;
1759 unsigned short * tp;
1760 clientchar_t * shareName;
1761 BOOL shareFound = FALSE;
1762 unsigned short infoLevel;
1763 unsigned short bufsize;
1772 cm_scache_t *scp = NULL;
1778 tp = p->parmsp + 1; /* skip over function number (always 1) */
1781 clientchar_t * cdescp;
1783 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1784 if (cm_ClientStrCmp(cdescp, _C("zWrLh")))
1786 return CM_ERROR_INVAL;
1788 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1789 if (cm_ClientStrCmp(cdescp, _C("B13")) &&
1790 cm_ClientStrCmp(cdescp, _C("B13BWz")) &&
1791 cm_ClientStrCmp(cdescp, _C("B13BWzWWWzB9B")))
1793 return CM_ERROR_INVAL;
1795 shareName = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1803 totalData = sizeof(smb_rap_share_info_0_t);
1804 else if(infoLevel == SMB_INFO_STANDARD)
1805 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1806 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1807 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1809 return CM_ERROR_INVAL;
1811 if(!cm_ClientStrCmpI(shareName, _C("all")) || !cm_ClientStrCmp(shareName,_C("*."))) {
1812 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1813 KEY_QUERY_VALUE, &hkParam);
1814 if (rv == ERROR_SUCCESS) {
1815 len = sizeof(allSubmount);
1816 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1817 (BYTE *) &allSubmount, &len);
1818 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1821 RegCloseKey (hkParam);
1828 userp = smb_GetTran2User(vcp, p);
1830 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
1831 return CM_ERROR_BADSMB;
1833 code = cm_NameI(cm_data.rootSCachep, shareName,
1834 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
1835 userp, NULL, &req, &scp);
1837 cm_ReleaseSCache(scp);
1840 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1841 KEY_QUERY_VALUE, &hkSubmount);
1842 if (rv == ERROR_SUCCESS) {
1843 rv = RegQueryValueExW(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1844 if (rv == ERROR_SUCCESS) {
1847 RegCloseKey(hkSubmount);
1853 return CM_ERROR_BADSHARENAME;
1855 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1856 memset(outp->datap, 0, totalData);
1858 outp->parmsp[0] = 0;
1859 outp->parmsp[1] = 0;
1860 outp->parmsp[2] = totalData;
1862 if (infoLevel == 0) {
1863 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1864 cm_ClientStringToUtf8(shareName, -1, info->shi0_netname,
1865 lengthof(info->shi0_netname));
1866 } else if(infoLevel == SMB_INFO_STANDARD) {
1867 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1868 cm_ClientStringToUtf8(shareName, -1, info->shi1_netname, lengthof(info->shi1_netname));
1869 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1870 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1871 /* type and pad are already zero */
1872 } else { /* infoLevel==2 */
1873 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1874 cm_ClientStringToUtf8(shareName, -1, info->shi2_netname, lengthof(info->shi2_netname));
1875 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1876 info->shi2_permissions = ACCESS_ALL;
1877 info->shi2_max_uses = (unsigned short) -1;
1878 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
1881 outp->totalData = totalData;
1882 outp->totalParms = totalParam;
1884 smb_SendTran2Packet(vcp, outp, op);
1885 smb_FreeTran2Packet(outp);
1890 #pragma pack(push, 1)
1892 typedef struct smb_rap_wksta_info_10 {
1893 DWORD wki10_computername; /*char *wki10_computername;*/
1894 DWORD wki10_username; /* char *wki10_username; */
1895 DWORD wki10_langroup; /* char *wki10_langroup;*/
1896 BYTE wki10_ver_major;
1897 BYTE wki10_ver_minor;
1898 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1899 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1900 } smb_rap_wksta_info_10_t;
1904 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1906 smb_tran2Packet_t *outp;
1910 unsigned short * tp;
1913 smb_rap_wksta_info_10_t * info;
1917 tp = p->parmsp + 1; /* Skip over function number */
1920 clientchar_t * cdescp;
1922 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
1923 SMB_STRF_FORCEASCII);
1924 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
1925 return CM_ERROR_INVAL;
1927 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
1928 SMB_STRF_FORCEASCII);
1929 if (cm_ClientStrCmp(cdescp, _C("zzzBBzz")))
1930 return CM_ERROR_INVAL;
1936 if (infoLevel != 10) {
1937 return CM_ERROR_INVAL;
1943 totalData = sizeof(*info) + /* info */
1944 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1945 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1946 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1947 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1948 1; /* wki10_oth_domains (null)*/
1950 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1952 memset(outp->parmsp,0,totalParams);
1953 memset(outp->datap,0,totalData);
1955 info = (smb_rap_wksta_info_10_t *) outp->datap;
1956 cstrp = (char *) (info + 1);
1958 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1959 StringCbCopyA(cstrp, totalData, smb_localNamep);
1960 cstrp += strlen(cstrp) + 1;
1962 info->wki10_username = (DWORD) (cstrp - outp->datap);
1963 uidp = smb_FindUID(vcp, p->uid, 0);
1965 lock_ObtainMutex(&uidp->mx);
1966 if(uidp->unp && uidp->unp->name)
1967 cm_ClientStringToUtf8(uidp->unp->name, -1,
1968 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
1969 lock_ReleaseMutex(&uidp->mx);
1970 smb_ReleaseUID(uidp);
1972 cstrp += strlen(cstrp) + 1;
1974 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1975 StringCbCopyA(cstrp, totalData - (cstrp - outp->datap)*sizeof(char), "WORKGROUP");
1976 cstrp += strlen(cstrp) + 1;
1978 /* TODO: Not sure what values these should take, but these work */
1979 info->wki10_ver_major = 5;
1980 info->wki10_ver_minor = 1;
1982 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1983 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
1984 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
1985 cstrp += strlen(cstrp) + 1;
1987 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1988 cstrp ++; /* no other domains */
1990 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1991 outp->parmsp[2] = outp->totalData;
1992 outp->totalParms = totalParams;
1994 smb_SendTran2Packet(vcp,outp,op);
1995 smb_FreeTran2Packet(outp);
2000 #pragma pack(push, 1)
2002 typedef struct smb_rap_server_info_0 {
2004 } smb_rap_server_info_0_t;
2006 typedef struct smb_rap_server_info_1 {
2008 BYTE sv1_version_major;
2009 BYTE sv1_version_minor;
2011 DWORD sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
2012 } smb_rap_server_info_1_t;
2016 char smb_ServerComment[] = "OpenAFS Client";
2017 int smb_ServerCommentLen = sizeof(smb_ServerComment);
2019 #define SMB_SV_TYPE_SERVER 0x00000002L
2020 #define SMB_SV_TYPE_NT 0x00001000L
2021 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
2023 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2025 smb_tran2Packet_t *outp;
2029 unsigned short * tp;
2032 smb_rap_server_info_0_t * info0;
2033 smb_rap_server_info_1_t * info1;
2036 tp = p->parmsp + 1; /* Skip over function number */
2039 clientchar_t * cdescp;
2041 cdescp = smb_ParseStringT2Parm(p, (unsigned char *) tp, (char **) &tp,
2042 SMB_STRF_FORCEASCII);
2043 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2044 return CM_ERROR_INVAL;
2045 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2046 SMB_STRF_FORCEASCII);
2047 if (cm_ClientStrCmp(cdescp, _C("B16")) ||
2048 cm_ClientStrCmp(cdescp, _C("B16BBDz")))
2049 return CM_ERROR_INVAL;
2055 if (infoLevel != 0 && infoLevel != 1) {
2056 return CM_ERROR_INVAL;
2062 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
2063 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
2065 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2067 memset(outp->parmsp,0,totalParams);
2068 memset(outp->datap,0,totalData);
2070 if (infoLevel == 0) {
2071 info0 = (smb_rap_server_info_0_t *) outp->datap;
2072 cstrp = (char *) (info0 + 1);
2073 StringCchCopyA(info0->sv0_name, lengthof(info0->sv0_name), "AFS");
2074 } else { /* infoLevel == SMB_INFO_STANDARD */
2075 info1 = (smb_rap_server_info_1_t *) outp->datap;
2076 cstrp = (char *) (info1 + 1);
2077 StringCchCopyA(info1->sv1_name, lengthof(info1->sv1_name), "AFS");
2080 SMB_SV_TYPE_SERVER |
2082 SMB_SV_TYPE_SERVER_NT;
2084 info1->sv1_version_major = 5;
2085 info1->sv1_version_minor = 1;
2086 info1->sv1_comment_or_master_browser = (DWORD) (cstrp - outp->datap);
2088 StringCbCopyA(cstrp, smb_ServerCommentLen, smb_ServerComment);
2090 cstrp += smb_ServerCommentLen / sizeof(char);
2093 totalData = (DWORD)(cstrp - outp->datap);
2094 outp->totalData = min(bufsize,totalData); /* actual data size */
2095 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
2096 outp->parmsp[2] = totalData;
2097 outp->totalParms = totalParams;
2099 smb_SendTran2Packet(vcp,outp,op);
2100 smb_FreeTran2Packet(outp);
2105 /* SMB_COM_TRANSACTION2 and SMB_COM_TRANSACTION2_SECONDARY */
2106 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2108 smb_tran2Packet_t *asp;
2120 /* We sometimes see 0 word count. What to do? */
2121 if (*inp->wctp == 0) {
2122 osi_Log0(smb_logp, "Transaction2 word count = 0");
2123 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
2125 smb_SetSMBDataLength(outp, 0);
2126 smb_SendPacket(vcp, outp);
2130 totalParms = smb_GetSMBParm(inp, 0);
2131 totalData = smb_GetSMBParm(inp, 1);
2133 firstPacket = (inp->inCom == 0x32);
2135 /* find the packet we're reassembling */
2136 lock_ObtainWrite(&smb_globalLock);
2137 asp = smb_FindTran2Packet(vcp, inp);
2139 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
2141 lock_ReleaseWrite(&smb_globalLock);
2143 /* now merge in this latest packet; start by looking up offsets */
2145 parmDisp = dataDisp = 0;
2146 parmOffset = smb_GetSMBParm(inp, 10);
2147 dataOffset = smb_GetSMBParm(inp, 12);
2148 parmCount = smb_GetSMBParm(inp, 9);
2149 dataCount = smb_GetSMBParm(inp, 11);
2150 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2151 asp->maxReturnData = smb_GetSMBParm(inp, 3);
2153 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2154 totalData, dataCount, asp->maxReturnData);
2157 parmDisp = smb_GetSMBParm(inp, 4);
2158 parmOffset = smb_GetSMBParm(inp, 3);
2159 dataDisp = smb_GetSMBParm(inp, 7);
2160 dataOffset = smb_GetSMBParm(inp, 6);
2161 parmCount = smb_GetSMBParm(inp, 2);
2162 dataCount = smb_GetSMBParm(inp, 5);
2164 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2165 parmCount, dataCount);
2168 /* now copy the parms and data */
2169 if ( asp->totalParms > 0 && parmCount != 0 )
2171 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2173 if ( asp->totalData > 0 && dataCount != 0 ) {
2174 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2177 /* account for new bytes */
2178 asp->curData += dataCount;
2179 asp->curParms += parmCount;
2181 /* finally, if we're done, remove the packet from the queue and dispatch it */
2182 if (asp->totalParms > 0 &&
2183 asp->curParms > 0 &&
2184 asp->totalData <= asp->curData &&
2185 asp->totalParms <= asp->curParms) {
2186 /* we've received it all */
2187 lock_ObtainWrite(&smb_globalLock);
2188 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2189 lock_ReleaseWrite(&smb_globalLock);
2191 /* now dispatch it */
2192 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2193 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2194 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2197 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2198 code = CM_ERROR_BADOP;
2201 /* if an error is returned, we're supposed to send an error packet,
2202 * otherwise the dispatched function already did the data sending.
2203 * We give dispatched proc the responsibility since it knows how much
2204 * space to allocate.
2207 smb_SendTran2Error(vcp, asp, outp, code);
2210 /* free the input tran 2 packet */
2211 smb_FreeTran2Packet(asp);
2213 else if (firstPacket) {
2214 /* the first packet in a multi-packet request, we need to send an
2215 * ack to get more data.
2217 smb_SetSMBDataLength(outp, 0);
2218 smb_SendPacket(vcp, outp);
2225 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2227 clientchar_t *pathp;
2228 smb_tran2Packet_t *outp;
2233 cm_scache_t *dscp; /* dir we're dealing with */
2234 cm_scache_t *scp; /* file we're creating */
2236 int initialModeBits;
2239 clientchar_t *lastNamep;
2246 int parmSlot; /* which parm we're dealing with */
2247 long returnEALength;
2248 clientchar_t *tidPathp;
2256 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2257 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2259 openFun = p->parmsp[6]; /* open function */
2260 excl = ((openFun & 3) == 0);
2261 trunc = ((openFun & 3) == 2); /* truncate it */
2262 openMode = (p->parmsp[1] & 0x7);
2263 openAction = 0; /* tracks what we did */
2265 attributes = p->parmsp[3];
2266 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2268 /* compute initial mode bits based on read-only flag in attributes */
2269 initialModeBits = 0666;
2270 if (attributes & SMB_ATTR_READONLY)
2271 initialModeBits &= ~0222;
2273 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
2276 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2278 spacep = cm_GetSpace();
2279 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2282 (cm_ClientStrCmpI(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
2283 cm_ClientStrCmpI(lastNamep, _C("\\srvsvc")) == 0 ||
2284 cm_ClientStrCmpI(lastNamep, _C("\\wkssvc")) == 0 ||
2285 cm_ClientStrCmpI(lastNamep, _C("\\ipc$")) == 0)) {
2286 /* special case magic file name for receiving IOCTL requests
2287 * (since IOCTL calls themselves aren't getting through).
2289 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2290 smb_SetupIoctlFid(fidp, spacep);
2292 /* copy out remainder of the parms */
2294 outp->parmsp[parmSlot++] = fidp->fid;
2296 outp->parmsp[parmSlot++] = 0; /* attrs */
2297 outp->parmsp[parmSlot++] = 0; /* mod time */
2298 outp->parmsp[parmSlot++] = 0;
2299 outp->parmsp[parmSlot++] = 0; /* len */
2300 outp->parmsp[parmSlot++] = 0x7fff;
2301 outp->parmsp[parmSlot++] = openMode;
2302 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2303 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2305 /* and the final "always present" stuff */
2306 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2307 /* next write out the "unique" ID */
2308 outp->parmsp[parmSlot++] = 0x1234;
2309 outp->parmsp[parmSlot++] = 0x5678;
2310 outp->parmsp[parmSlot++] = 0;
2311 if (returnEALength) {
2312 outp->parmsp[parmSlot++] = 0;
2313 outp->parmsp[parmSlot++] = 0;
2316 outp->totalData = 0;
2317 outp->totalParms = parmSlot * 2;
2319 smb_SendTran2Packet(vcp, outp, op);
2321 smb_FreeTran2Packet(outp);
2323 /* and clean up fid reference */
2324 smb_ReleaseFID(fidp);
2328 #ifdef DEBUG_VERBOSE
2330 char *hexp, *asciip;
2331 asciip = (lastNamep ? lastNamep : pathp);
2332 hexp = osi_HexifyString( asciip );
2333 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2338 userp = smb_GetTran2User(vcp, p);
2339 /* In the off chance that userp is NULL, we log and abandon */
2341 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2342 smb_FreeTran2Packet(outp);
2343 return CM_ERROR_BADSMB;
2346 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2347 if (code == CM_ERROR_TIDIPC) {
2348 /* Attempt to use a TID allocated for IPC. The client
2349 * is probably looking for DCE RPC end points which we
2350 * don't support OR it could be looking to make a DFS
2353 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2355 cm_ReleaseUser(userp);
2356 smb_FreeTran2Packet(outp);
2357 return CM_ERROR_NOSUCHPATH;
2362 code = cm_NameI(cm_data.rootSCachep, pathp,
2363 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2364 userp, tidPathp, &req, &scp);
2366 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2367 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2368 userp, tidPathp, &req, &dscp);
2369 cm_FreeSpace(spacep);
2372 cm_ReleaseUser(userp);
2373 smb_FreeTran2Packet(outp);
2378 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2379 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2380 (clientchar_t*) spacep->data);
2381 cm_ReleaseSCache(dscp);
2382 cm_ReleaseUser(userp);
2383 smb_FreeTran2Packet(outp);
2384 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2385 return CM_ERROR_PATH_NOT_COVERED;
2387 return CM_ERROR_BADSHARENAME;
2389 #endif /* DFS_SUPPORT */
2391 /* otherwise, scp points to the parent directory. Do a lookup,
2392 * and truncate the file if we find it, otherwise we create the
2399 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2401 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2402 cm_ReleaseSCache(dscp);
2403 cm_ReleaseUser(userp);
2404 smb_FreeTran2Packet(outp);
2409 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2410 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2411 cm_ReleaseSCache(scp);
2412 cm_ReleaseUser(userp);
2413 smb_FreeTran2Packet(outp);
2414 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2415 return CM_ERROR_PATH_NOT_COVERED;
2417 return CM_ERROR_BADSHARENAME;
2419 #endif /* DFS_SUPPORT */
2421 /* macintosh is expensive to program for it */
2422 cm_FreeSpace(spacep);
2425 /* if we get here, if code is 0, the file exists and is represented by
2426 * scp. Otherwise, we have to create it.
2429 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2432 cm_ReleaseSCache(dscp);
2433 cm_ReleaseSCache(scp);
2434 cm_ReleaseUser(userp);
2435 smb_FreeTran2Packet(outp);
2440 /* oops, file shouldn't be there */
2442 cm_ReleaseSCache(dscp);
2443 cm_ReleaseSCache(scp);
2444 cm_ReleaseUser(userp);
2445 smb_FreeTran2Packet(outp);
2446 return CM_ERROR_EXISTS;
2450 setAttr.mask = CM_ATTRMASK_LENGTH;
2451 setAttr.length.LowPart = 0;
2452 setAttr.length.HighPart = 0;
2453 code = cm_SetAttr(scp, &setAttr, userp, &req);
2454 openAction = 3; /* truncated existing file */
2457 openAction = 1; /* found existing file */
2459 else if (!(openFun & 0x10)) {
2460 /* don't create if not found */
2462 cm_ReleaseSCache(dscp);
2463 osi_assertx(scp == NULL, "null cm_scache_t");
2464 cm_ReleaseUser(userp);
2465 smb_FreeTran2Packet(outp);
2466 return CM_ERROR_NOSUCHFILE;
2469 osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2470 openAction = 2; /* created file */
2471 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2472 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2473 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2477 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2478 smb_NotifyChange(FILE_ACTION_ADDED,
2479 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2480 dscp, lastNamep, NULL, TRUE);
2481 } else if (!excl && code == CM_ERROR_EXISTS) {
2482 /* not an exclusive create, and someone else tried
2483 * creating it already, then we open it anyway. We
2484 * don't bother retrying after this, since if this next
2485 * fails, that means that the file was deleted after we
2486 * started this call.
2488 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2492 setAttr.mask = CM_ATTRMASK_LENGTH;
2493 setAttr.length.LowPart = 0;
2494 setAttr.length.HighPart = 0;
2495 code = cm_SetAttr(scp, &setAttr, userp,
2498 } /* lookup succeeded */
2502 /* we don't need this any longer */
2504 cm_ReleaseSCache(dscp);
2507 /* something went wrong creating or truncating the file */
2509 cm_ReleaseSCache(scp);
2510 cm_ReleaseUser(userp);
2511 smb_FreeTran2Packet(outp);
2515 /* make sure we're about to open a file */
2516 if (scp->fileType != CM_SCACHETYPE_FILE) {
2518 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2519 cm_scache_t * targetScp = 0;
2520 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2522 /* we have a more accurate file to use (the
2523 * target of the symbolic link). Otherwise,
2524 * we'll just use the symlink anyway.
2526 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2528 cm_ReleaseSCache(scp);
2532 if (scp->fileType != CM_SCACHETYPE_FILE) {
2533 cm_ReleaseSCache(scp);
2534 cm_ReleaseUser(userp);
2535 smb_FreeTran2Packet(outp);
2536 return CM_ERROR_ISDIR;
2540 /* now all we have to do is open the file itself */
2541 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2542 osi_assertx(fidp, "null smb_fid_t");
2545 lock_ObtainMutex(&fidp->mx);
2546 /* save a pointer to the vnode */
2547 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2549 lock_ObtainWrite(&scp->rw);
2550 scp->flags |= CM_SCACHEFLAG_SMB_FID;
2551 lock_ReleaseWrite(&scp->rw);
2554 fidp->userp = userp;
2556 /* compute open mode */
2558 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
2559 if (openMode == 1 || openMode == 2)
2560 fidp->flags |= SMB_FID_OPENWRITE;
2562 /* remember that the file was newly created */
2564 fidp->flags |= SMB_FID_CREATED;
2566 lock_ReleaseMutex(&fidp->mx);
2568 smb_ReleaseFID(fidp);
2570 cm_Open(scp, 0, userp);
2572 /* copy out remainder of the parms */
2574 outp->parmsp[parmSlot++] = fidp->fid;
2575 lock_ObtainRead(&scp->rw);
2577 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2578 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2579 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2580 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2581 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2582 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2583 outp->parmsp[parmSlot++] = openMode;
2584 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2585 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2587 /* and the final "always present" stuff */
2588 outp->parmsp[parmSlot++] = openAction;
2589 /* next write out the "unique" ID */
2590 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2591 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2592 outp->parmsp[parmSlot++] = 0;
2593 if (returnEALength) {
2594 outp->parmsp[parmSlot++] = 0;
2595 outp->parmsp[parmSlot++] = 0;
2597 lock_ReleaseRead(&scp->rw);
2598 outp->totalData = 0; /* total # of data bytes */
2599 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2601 smb_SendTran2Packet(vcp, outp, op);
2603 smb_FreeTran2Packet(outp);
2605 cm_ReleaseUser(userp);
2606 /* leave scp held since we put it in fidp->scp */
2610 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2613 unsigned short infolevel;
2615 infolevel = p->parmsp[0];
2617 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2619 return CM_ERROR_BAD_LEVEL;
2622 /* TRANS2_QUERY_FS_INFORMATION */
2623 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2625 smb_tran2Packet_t *outp;
2626 smb_tran2QFSInfo_t qi;
2630 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2632 switch (p->parmsp[0]) {
2633 case SMB_INFO_ALLOCATION:
2635 responseSize = sizeof(qi.u.allocInfo);
2637 qi.u.allocInfo.FSID = 0;
2638 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2639 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2640 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2641 qi.u.allocInfo.bytesPerSector = 1024;
2644 case SMB_INFO_VOLUME:
2646 qi.u.volumeInfo.vsn = 1234; /* Volume serial number */
2647 qi.u.volumeInfo.vnCount = 4; /* Number of characters in label (AFS\0)*/
2649 /* we're supposed to pad it out with zeroes to the end */
2650 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2651 smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
2653 responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
2656 case SMB_QUERY_FS_VOLUME_INFO:
2657 /* FS volume info */
2658 responseSize = sizeof(qi.u.FSvolumeInfo);
2661 FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
2662 memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
2665 qi.u.FSvolumeInfo.vsn = 1234;
2666 qi.u.FSvolumeInfo.vnCount = 8; /* This is always in Unicode */
2667 memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
2670 case SMB_QUERY_FS_SIZE_INFO:
2672 responseSize = sizeof(qi.u.FSsizeInfo);
2674 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2675 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2676 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2677 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2678 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2679 qi.u.FSsizeInfo.bytesPerSector = 1024;
2682 case SMB_QUERY_FS_DEVICE_INFO:
2683 /* FS device info */
2684 responseSize = sizeof(qi.u.FSdeviceInfo);
2686 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2687 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2690 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2691 /* FS attribute info */
2693 /* attributes, defined in WINNT.H:
2694 * FILE_CASE_SENSITIVE_SEARCH 0x1
2695 * FILE_CASE_PRESERVED_NAMES 0x2
2696 * FILE_VOLUME_QUOTAS 0x10
2697 * <no name defined> 0x4000
2698 * If bit 0x4000 is not set, Windows 95 thinks
2699 * we can't handle long (non-8.3) names,
2700 * despite our protestations to the contrary.
2702 qi.u.FSattributeInfo.attributes = 0x4003;
2703 /* The maxCompLength is supposed to be in bytes */
2705 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2706 qi.u.FSattributeInfo.maxCompLength = MAX_PATH * sizeof(wchar_t);
2709 qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
2713 smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
2714 qi.u.FSattributeInfo.FSnameLength = sz;
2717 sizeof(qi.u.FSattributeInfo.attributes) +
2718 sizeof(qi.u.FSattributeInfo.maxCompLength) +
2719 sizeof(qi.u.FSattributeInfo.FSnameLength) +
2724 case SMB_INFO_UNIX: /* CIFS Unix Info */
2725 case SMB_INFO_MACOS: /* Mac FS Info */
2727 return CM_ERROR_BADOP;
2730 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2732 /* copy out return data, and set corresponding sizes */
2733 outp->totalParms = 0;
2734 outp->totalData = responseSize;
2735 memcpy(outp->datap, &qi, responseSize);
2737 /* send and free the packets */
2738 smb_SendTran2Packet(vcp, outp, op);
2739 smb_FreeTran2Packet(outp);
2744 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2746 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2747 return CM_ERROR_BADOP;
2750 struct smb_ShortNameRock {
2751 clientchar_t *maskp;
2753 clientchar_t *shortName;
2754 size_t shortNameLen;
2757 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2760 struct smb_ShortNameRock *rockp;
2761 normchar_t normName[MAX_PATH];
2762 clientchar_t *shortNameEnd;
2766 cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t));
2768 /* compare both names and vnodes, though probably just comparing vnodes
2769 * would be safe enough.
2771 if (cm_NormStrCmpI(normName, rockp->maskp) != 0)
2773 if (ntohl(dep->fid.vnode) != rockp->vnode)
2776 /* This is the entry */
2777 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2778 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2780 return CM_ERROR_STOPNOW;
2783 long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
2784 clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
2786 struct smb_ShortNameRock rock;
2787 clientchar_t *lastNamep;
2790 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2794 spacep = cm_GetSpace();
2795 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2797 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2798 caseFold, userp, tidPathp,
2800 cm_FreeSpace(spacep);
2805 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2806 cm_ReleaseSCache(dscp);
2807 cm_ReleaseUser(userp);
2811 return CM_ERROR_PATH_NOT_COVERED;
2813 #endif /* DFS_SUPPORT */
2815 if (!lastNamep) lastNamep = pathp;
2818 thyper.HighPart = 0;
2819 rock.shortName = shortName;
2821 rock.maskp = lastNamep;
2822 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2824 cm_ReleaseSCache(dscp);
2827 return CM_ERROR_NOSUCHFILE;
2828 if (code == CM_ERROR_STOPNOW) {
2829 *shortNameLenp = rock.shortNameLen;
2835 /* TRANS2_QUERY_PATH_INFORMATION */
2836 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2838 smb_tran2Packet_t *outp;
2841 unsigned short infoLevel;
2842 smb_tran2QPathInfo_t qpi;
2844 unsigned short attributes;
2845 unsigned long extAttributes;
2846 clientchar_t shortName[13];
2850 cm_scache_t *scp, *dscp;
2851 int scp_rw_held = 0;
2854 clientchar_t *pathp;
2855 clientchar_t *tidPathp;
2856 clientchar_t *lastComp;
2861 infoLevel = p->parmsp[0];
2862 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2864 else if (infoLevel == SMB_INFO_STANDARD)
2865 responseSize = sizeof(qpi.u.QPstandardInfo);
2866 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2867 responseSize = sizeof(qpi.u.QPeaSizeInfo);
2868 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2869 responseSize = sizeof(qpi.u.QPfileBasicInfo);
2870 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2871 responseSize = sizeof(qpi.u.QPfileStandardInfo);
2872 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2873 responseSize = sizeof(qpi.u.QPfileEaInfo);
2874 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2875 responseSize = sizeof(qpi.u.QPfileNameInfo);
2876 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
2877 responseSize = sizeof(qpi.u.QPfileAllInfo);
2878 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2879 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2881 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2882 p->opcode, infoLevel);
2883 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
2887 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
2888 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %S", infoLevel,
2889 osi_LogSaveClientString(smb_logp, pathp));
2891 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2893 if (infoLevel > 0x100)
2894 outp->totalParms = 2;
2896 outp->totalParms = 0;
2897 outp->totalData = responseSize;
2899 /* now, if we're at infoLevel 6, we're only being asked to check
2900 * the syntax, so we just OK things now. In particular, we're *not*
2901 * being asked to verify anything about the state of any parent dirs.
2903 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2904 smb_SendTran2Packet(vcp, outp, opx);
2905 smb_FreeTran2Packet(outp);
2909 userp = smb_GetTran2User(vcp, p);
2911 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2912 smb_FreeTran2Packet(outp);
2913 return CM_ERROR_BADSMB;
2916 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2918 cm_ReleaseUser(userp);
2919 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2920 smb_FreeTran2Packet(outp);
2925 * XXX Strange hack XXX
2927 * As of Patch 7 (13 January 98), we are having the following problem:
2928 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2929 * requests to look up "desktop.ini" in all the subdirectories.
2930 * This can cause zillions of timeouts looking up non-existent cells
2931 * and volumes, especially in the top-level directory.
2933 * We have not found any way to avoid this or work around it except
2934 * to explicitly ignore the requests for mount points that haven't
2935 * yet been evaluated and for directories that haven't yet been
2938 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2939 spacep = cm_GetSpace();
2940 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
2941 #ifndef SPECIAL_FOLDERS
2942 /* Make sure that lastComp is not NULL */
2944 if (cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
2945 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2949 userp, tidPathp, &req, &dscp);
2952 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2953 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2955 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2956 code = CM_ERROR_PATH_NOT_COVERED;
2958 code = CM_ERROR_BADSHARENAME;
2960 #endif /* DFS_SUPPORT */
2961 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2962 code = CM_ERROR_NOSUCHFILE;
2963 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2964 cm_buf_t *bp = buf_Find(dscp, &hzero);
2970 code = CM_ERROR_NOSUCHFILE;
2972 cm_ReleaseSCache(dscp);
2974 cm_FreeSpace(spacep);
2975 cm_ReleaseUser(userp);
2976 smb_SendTran2Error(vcp, p, opx, code);
2977 smb_FreeTran2Packet(outp);
2983 #endif /* SPECIAL_FOLDERS */
2985 cm_FreeSpace(spacep);
2988 /* now do namei and stat, and copy out the info */
2989 code = cm_NameI(cm_data.rootSCachep, pathp,
2990 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2993 cm_ReleaseUser(userp);
2994 smb_SendTran2Error(vcp, p, opx, code);
2995 smb_FreeTran2Packet(outp);
3000 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3001 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3002 cm_ReleaseSCache(scp);
3003 cm_ReleaseUser(userp);
3004 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3005 code = CM_ERROR_PATH_NOT_COVERED;
3007 code = CM_ERROR_BADSHARENAME;
3008 smb_SendTran2Error(vcp, p, opx, code);
3009 smb_FreeTran2Packet(outp);
3012 #endif /* DFS_SUPPORT */
3014 lock_ObtainWrite(&scp->rw);
3016 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3017 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3021 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3023 lock_ConvertWToR(&scp->rw);
3028 /* now we have the status in the cache entry, and everything is locked.
3029 * Marshall the output data.
3031 /* for info level 108, figure out short name */
3032 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3033 code = cm_GetShortName(pathp, userp, &req,
3034 tidPathp, scp->fid.vnode, shortName,
3040 smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
3041 qpi.u.QPfileAltNameInfo.fileNameLength = len;
3045 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3046 smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3047 qpi.u.QPfileNameInfo.fileNameLength = len;
3051 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3052 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3053 qpi.u.QPstandardInfo.creationDateTime = dosTime;
3054 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3055 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3056 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3057 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3058 attributes = smb_Attributes(scp);
3059 qpi.u.QPstandardInfo.attributes = attributes;
3060 qpi.u.QPstandardInfo.eaSize = 0;
3062 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3063 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3064 qpi.u.QPfileBasicInfo.creationTime = ft;
3065 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3066 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3067 qpi.u.QPfileBasicInfo.changeTime = ft;
3068 extAttributes = smb_ExtAttributes(scp);
3069 qpi.u.QPfileBasicInfo.attributes = extAttributes;
3070 qpi.u.QPfileBasicInfo.reserved = 0;
3072 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3075 lock_ReleaseRead(&scp->rw);
3077 fidp = smb_FindFIDByScache(vcp, scp);
3079 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3080 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3081 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3082 qpi.u.QPfileStandardInfo.directory =
3083 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3084 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3085 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3086 qpi.u.QPfileStandardInfo.reserved = 0;
3089 lock_ObtainMutex(&fidp->mx);
3090 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3091 lock_ReleaseMutex(&fidp->mx);
3092 smb_ReleaseFID(fidp);
3094 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3096 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3097 qpi.u.QPfileEaInfo.eaSize = 0;
3099 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3100 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3101 qpi.u.QPfileAllInfo.creationTime = ft;
3102 qpi.u.QPfileAllInfo.lastAccessTime = ft;
3103 qpi.u.QPfileAllInfo.lastWriteTime = ft;
3104 qpi.u.QPfileAllInfo.changeTime = ft;
3105 extAttributes = smb_ExtAttributes(scp);
3106 qpi.u.QPfileAllInfo.attributes = extAttributes;
3107 qpi.u.QPfileAllInfo.allocationSize = scp->length;
3108 qpi.u.QPfileAllInfo.endOfFile = scp->length;
3109 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3110 qpi.u.QPfileAllInfo.deletePending = 0;
3111 qpi.u.QPfileAllInfo.directory =
3112 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3113 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3114 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3115 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
3116 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
3117 qpi.u.QPfileAllInfo.eaSize = 0;
3118 qpi.u.QPfileAllInfo.accessFlags = 0;
3119 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
3120 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
3121 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3122 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3123 qpi.u.QPfileAllInfo.mode = 0;
3124 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3126 smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3127 qpi.u.QPfileAllInfo.fileNameLength = len;
3130 /* send and free the packets */
3132 switch (scp_rw_held) {
3134 lock_ReleaseRead(&scp->rw);
3137 lock_ReleaseWrite(&scp->rw);
3141 cm_ReleaseSCache(scp);
3142 cm_ReleaseUser(userp);
3144 memcpy(outp->datap, &qpi, responseSize);
3145 smb_SendTran2Packet(vcp, outp, opx);
3147 smb_SendTran2Error(vcp, p, opx, code);
3149 smb_FreeTran2Packet(outp);
3154 /* TRANS2_SET_PATH_INFORMATION */
3155 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3158 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
3159 return CM_ERROR_BADOP;
3163 unsigned short infoLevel;
3164 clientchar_t * pathp;
3165 smb_tran2Packet_t *outp;
3166 smb_tran2QPathInfo_t *spi;
3168 cm_scache_t *scp, *dscp;
3171 clientchar_t *tidPathp;
3172 clientchar_t *lastComp;
3176 infoLevel = p->parmsp[0];
3177 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
3178 if (infoLevel != SMB_INFO_STANDARD &&
3179 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
3180 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
3181 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3182 p->opcode, infoLevel);
3183 smb_SendTran2Error(vcp, p, opx,
3184 infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3188 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3190 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
3191 osi_LogSaveClientString(smb_logp, pathp));
3193 userp = smb_GetTran2User(vcp, p);
3195 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3196 code = CM_ERROR_BADSMB;
3200 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3201 if (code == CM_ERROR_TIDIPC) {
3202 /* Attempt to use a TID allocated for IPC. The client
3203 * is probably looking for DCE RPC end points which we
3204 * don't support OR it could be looking to make a DFS
3207 osi_Log0(smb_logp, "Tran2Open received IPC TID");
3208 cm_ReleaseUser(userp);
3209 return CM_ERROR_NOSUCHPATH;
3213 * XXX Strange hack XXX
3215 * As of Patch 7 (13 January 98), we are having the following problem:
3216 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3217 * requests to look up "desktop.ini" in all the subdirectories.
3218 * This can cause zillions of timeouts looking up non-existent cells
3219 * and volumes, especially in the top-level directory.
3221 * We have not found any way to avoid this or work around it except
3222 * to explicitly ignore the requests for mount points that haven't
3223 * yet been evaluated and for directories that haven't yet been
3226 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3227 spacep = cm_GetSpace();
3228 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3229 #ifndef SPECIAL_FOLDERS
3230 /* Make sure that lastComp is not NULL */
3232 if (cm_ClientStrCmpI(lastComp, _C("\\desktop.ini")) == 0) {
3233 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3237 userp, tidPathp, &req, &dscp);
3240 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3241 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3243 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3244 code = CM_ERROR_PATH_NOT_COVERED;
3246 code = CM_ERROR_BADSHARENAME;
3248 #endif /* DFS_SUPPORT */
3249 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3250 code = CM_ERROR_NOSUCHFILE;
3251 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3252 cm_buf_t *bp = buf_Find(dscp, &hzero);
3258 code = CM_ERROR_NOSUCHFILE;
3260 cm_ReleaseSCache(dscp);
3262 cm_FreeSpace(spacep);
3263 cm_ReleaseUser(userp);
3264 smb_SendTran2Error(vcp, p, opx, code);
3270 #endif /* SPECIAL_FOLDERS */
3272 cm_FreeSpace(spacep);
3275 /* now do namei and stat, and copy out the info */
3276 code = cm_NameI(cm_data.rootSCachep, pathp,
3277 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3279 cm_ReleaseUser(userp);
3280 smb_SendTran2Error(vcp, p, opx, code);
3284 fidp = smb_FindFIDByScache(vcp, scp);
3286 cm_ReleaseSCache(scp);
3287 cm_ReleaseUser(userp);
3288 smb_SendTran2Error(vcp, p, opx, code);
3292 lock_ObtainMutex(&fidp->mx);
3293 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
3294 lock_ReleaseMutex(&fidp->mx);
3295 cm_ReleaseSCache(scp);
3296 smb_ReleaseFID(fidp);
3297 cm_ReleaseUser(userp);
3298 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3301 lock_ReleaseMutex(&fidp->mx);
3303 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3305 outp->totalParms = 2;
3306 outp->totalData = 0;
3308 spi = (smb_tran2QPathInfo_t *)p->datap;
3309 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3312 /* lock the vnode with a callback; we need the current status
3313 * to determine what the new status is, in some cases.
3315 lock_ObtainWrite(&scp->rw);
3316 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3317 CM_SCACHESYNC_GETSTATUS
3318 | CM_SCACHESYNC_NEEDCALLBACK);
3320 lock_ReleaseWrite(&scp->rw);
3323 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3325 lock_ReleaseWrite(&scp->rw);
3326 lock_ObtainMutex(&fidp->mx);
3327 lock_ObtainRead(&scp->rw);
3329 /* prepare for setattr call */
3330 attr.mask = CM_ATTRMASK_LENGTH;
3331 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3332 attr.length.HighPart = 0;
3334 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3335 smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3336 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3337 fidp->flags |= SMB_FID_MTIMESETDONE;
3340 if (spi->u.QPstandardInfo.attributes != 0) {
3341 if ((scp->unixModeBits & 0222)
3342 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3343 /* make a writable file read-only */
3344 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3345 attr.unixModeBits = scp->unixModeBits & ~0222;
3347 else if ((scp->unixModeBits & 0222) == 0
3348 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3349 /* make a read-only file writable */
3350 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3351 attr.unixModeBits = scp->unixModeBits | 0222;
3354 lock_ReleaseRead(&scp->rw);
3355 lock_ReleaseMutex(&fidp->mx);
3359 code = cm_SetAttr(scp, &attr, userp, &req);
3363 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3364 /* we don't support EAs */
3365 code = CM_ERROR_EAS_NOT_SUPPORTED;
3369 cm_ReleaseSCache(scp);
3370 cm_ReleaseUser(userp);
3371 smb_ReleaseFID(fidp);
3373 smb_SendTran2Packet(vcp, outp, opx);
3375 smb_SendTran2Error(vcp, p, opx, code);
3376 smb_FreeTran2Packet(outp);
3382 /* TRANS2_QUERY_FILE_INFORMATION */
3383 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3385 smb_tran2Packet_t *outp;
3387 unsigned long attributes;
3388 unsigned short infoLevel;
3395 smb_tran2QFileInfo_t qfi;
3403 fidp = smb_FindFID(vcp, fid, 0);
3406 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3410 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3411 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3412 smb_CloseFID(vcp, fidp, NULL, 0);
3413 smb_ReleaseFID(fidp);
3417 infoLevel = p->parmsp[1];
3418 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3419 responseSize = sizeof(qfi.u.QFbasicInfo);
3420 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3421 responseSize = sizeof(qfi.u.QFstandardInfo);
3422 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3423 responseSize = sizeof(qfi.u.QFeaInfo);
3424 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3425 responseSize = sizeof(qfi.u.QFfileNameInfo);
3427 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3428 p->opcode, infoLevel);
3429 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3430 smb_ReleaseFID(fidp);
3433 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3435 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3437 if (infoLevel > 0x100)
3438 outp->totalParms = 2;
3440 outp->totalParms = 0;
3441 outp->totalData = responseSize;
3443 userp = smb_GetTran2User(vcp, p);
3445 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3446 code = CM_ERROR_BADSMB;
3450 lock_ObtainMutex(&fidp->mx);
3451 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3453 osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3455 lock_ReleaseMutex(&fidp->mx);
3456 lock_ObtainWrite(&scp->rw);
3457 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3458 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3462 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3464 lock_ConvertWToR(&scp->rw);
3467 /* now we have the status in the cache entry, and everything is locked.
3468 * Marshall the output data.
3470 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3471 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3472 qfi.u.QFbasicInfo.creationTime = ft;
3473 qfi.u.QFbasicInfo.lastAccessTime = ft;
3474 qfi.u.QFbasicInfo.lastWriteTime = ft;
3475 qfi.u.QFbasicInfo.lastChangeTime = ft;
3476 attributes = smb_ExtAttributes(scp);
3477 qfi.u.QFbasicInfo.attributes = attributes;
3479 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3480 qfi.u.QFstandardInfo.allocationSize = scp->length;
3481 qfi.u.QFstandardInfo.endOfFile = scp->length;
3482 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3483 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3484 qfi.u.QFstandardInfo.directory =
3485 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3486 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3487 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3489 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3490 qfi.u.QFeaInfo.eaSize = 0;
3492 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3496 lock_ReleaseRead(&scp->rw);
3497 lock_ObtainMutex(&fidp->mx);
3498 lock_ObtainRead(&scp->rw);
3499 if (fidp->NTopen_wholepathp)
3500 name = fidp->NTopen_wholepathp;
3502 name = _C("\\"); /* probably can't happen */
3503 lock_ReleaseMutex(&fidp->mx);
3505 smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, SMB_STRF_IGNORENUL);
3506 outp->totalData = len + 4; /* this is actually what we want to return */
3507 qfi.u.QFfileNameInfo.fileNameLength = len;
3510 /* send and free the packets */
3513 lock_ReleaseRead(&scp->rw);
3515 lock_ReleaseWrite(&scp->rw);
3516 cm_ReleaseSCache(scp);
3517 cm_ReleaseUser(userp);
3518 smb_ReleaseFID(fidp);
3520 memcpy(outp->datap, &qfi, responseSize);
3521 smb_SendTran2Packet(vcp, outp, opx);
3523 smb_SendTran2Error(vcp, p, opx, code);
3525 smb_FreeTran2Packet(outp);
3531 /* TRANS2_SET_FILE_INFORMATION */
3532 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3537 unsigned short infoLevel;
3538 smb_tran2Packet_t *outp;
3539 cm_user_t *userp = NULL;
3540 cm_scache_t *scp = NULL;
3546 fidp = smb_FindFID(vcp, fid, 0);
3549 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3553 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3554 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3555 smb_CloseFID(vcp, fidp, NULL, 0);
3556 smb_ReleaseFID(fidp);
3560 infoLevel = p->parmsp[1];
3561 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3562 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3563 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3564 p->opcode, infoLevel);
3565 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3566 smb_ReleaseFID(fidp);
3570 lock_ObtainMutex(&fidp->mx);
3571 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
3572 !(fidp->flags & SMB_FID_OPENDELETE)) {
3573 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3574 fidp, fidp->scp, fidp->flags);
3575 lock_ReleaseMutex(&fidp->mx);
3576 smb_ReleaseFID(fidp);
3577 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3580 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3581 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3582 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3583 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3584 fidp, fidp->scp, fidp->flags);
3585 lock_ReleaseMutex(&fidp->mx);
3586 smb_ReleaseFID(fidp);
3587 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3592 osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3594 lock_ReleaseMutex(&fidp->mx);
3596 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3598 outp->totalParms = 2;
3599 outp->totalData = 0;
3601 userp = smb_GetTran2User(vcp, p);
3603 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3604 code = CM_ERROR_BADSMB;
3608 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3610 unsigned int attribute;
3612 smb_tran2QFileInfo_t *sfi;
3614 sfi = (smb_tran2QFileInfo_t *)p->datap;
3616 /* lock the vnode with a callback; we need the current status
3617 * to determine what the new status is, in some cases.
3619 lock_ObtainWrite(&scp->rw);
3620 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3621 CM_SCACHESYNC_GETSTATUS
3622 | CM_SCACHESYNC_NEEDCALLBACK);
3624 lock_ReleaseWrite(&scp->rw);
3628 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3630 lock_ReleaseWrite(&scp->rw);
3631 lock_ObtainMutex(&fidp->mx);
3632 lock_ObtainRead(&scp->rw);
3634 /* prepare for setattr call */
3637 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3638 /* when called as result of move a b, lastMod is (-1, -1).
3639 * If the check for -1 is not present, timestamp
3640 * of the resulting file will be 1969 (-1)
3642 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3643 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3644 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3645 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3646 fidp->flags |= SMB_FID_MTIMESETDONE;
3649 attribute = sfi->u.QFbasicInfo.attributes;
3650 if (attribute != 0) {
3651 if ((scp->unixModeBits & 0222)
3652 && (attribute & SMB_ATTR_READONLY) != 0) {
3653 /* make a writable file read-only */
3654 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3655 attr.unixModeBits = scp->unixModeBits & ~0222;
3657 else if ((scp->unixModeBits & 0222) == 0
3658 && (attribute & SMB_ATTR_READONLY) == 0) {
3659 /* make a read-only file writable */
3660 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3661 attr.unixModeBits = scp->unixModeBits | 0222;
3664 lock_ReleaseRead(&scp->rw);
3665 lock_ReleaseMutex(&fidp->mx);
3669 code = cm_SetAttr(scp, &attr, userp, &req);
3673 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3674 int delflag = *((char *)(p->datap));
3675 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
3676 delflag, fidp, scp);
3677 if (*((char *)(p->datap))) { /* File is Deleted */
3678 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3681 lock_ObtainMutex(&fidp->mx);
3682 fidp->flags |= SMB_FID_DELONCLOSE;
3683 lock_ReleaseMutex(&fidp->mx);
3685 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
3691 lock_ObtainMutex(&fidp->mx);
3692 fidp->flags &= ~SMB_FID_DELONCLOSE;
3693 lock_ReleaseMutex(&fidp->mx);
3696 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3697 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3698 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3701 attr.mask = CM_ATTRMASK_LENGTH;
3702 attr.length.LowPart = size.LowPart;
3703 attr.length.HighPart = size.HighPart;
3704 code = cm_SetAttr(scp, &attr, userp, &req);
3708 cm_ReleaseSCache(scp);
3709 cm_ReleaseUser(userp);
3710 smb_ReleaseFID(fidp);
3712 smb_SendTran2Packet(vcp, outp, opx);
3714 smb_SendTran2Error(vcp, p, opx, code);
3715 smb_FreeTran2Packet(outp);
3722 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3724 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3725 return CM_ERROR_BADOP;
3730 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3732 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3733 return CM_ERROR_BADOP;
3736 /* TRANS2_FIND_NOTIFY_FIRST */
3738 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3740 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3741 return CM_ERROR_BADOP;
3744 /* TRANS2_FIND_NOTIFY_NEXT */
3746 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3748 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3749 return CM_ERROR_BADOP;
3752 /* TRANS2_CREATE_DIRECTORY */
3754 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3756 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3757 return CM_ERROR_BADOP;
3760 /* TRANS2_SESSION_SETUP */
3762 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3764 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3765 return CM_ERROR_BADOP;
3768 struct smb_v2_referral {
3770 USHORT ReferralFlags;
3773 USHORT DfsPathOffset;
3774 USHORT DfsAlternativePathOffset;
3775 USHORT NetworkAddressOffset;
3778 /* TRANS2_GET_DFS_REFERRAL */
3780 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3782 /* This is a UNICODE only request (bit15 of Flags2) */
3783 /* The TID must be IPC$ */
3785 /* The documentation for the Flags response field is contradictory */
3787 /* Use Version 1 Referral Element Format */
3788 /* ServerType = 0; indicates the next server should be queried for the file */
3789 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3790 /* Node = UnicodeString of UNC path of the next share name */
3793 int maxReferralLevel = 0;
3794 clientchar_t requestFileName[1024] = _C("");
3795 clientchar_t referralPath[1024] = _C("");
3796 smb_tran2Packet_t *outp = 0;
3797 cm_user_t *userp = 0;
3798 cm_scache_t *scp = 0;
3799 cm_scache_t *dscp = 0;
3801 CPINFO CodePageInfo;
3802 int i, nbnLen, reqLen, refLen;
3807 maxReferralLevel = p->parmsp[0];
3809 GetCPInfo(CP_ACP, &CodePageInfo);
3810 cm_Utf16ToClientString(&p->parmsp[1], -1, requestFileName, lengthof(requestFileName));
3812 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%S]",
3813 maxReferralLevel, osi_LogSaveClientString(smb_logp, requestFileName));
3815 nbnLen = (int)cm_ClientStrLen(cm_NetbiosNameC);
3816 reqLen = (int)cm_ClientStrLen(requestFileName);
3818 if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
3819 !cm_ClientStrCmpNI(cm_NetbiosNameC, &requestFileName[1], nbnLen) &&
3820 requestFileName[nbnLen+1] == '\\')
3824 if (!cm_ClientStrCmpNI(_C("all"), &requestFileName[nbnLen+2], 3) ||
3825 !cm_ClientStrCmpNI(_C("*."), &requestFileName[nbnLen+2], 2)) {
3827 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
3830 userp = smb_GetTran2User(vcp, p);
3832 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3833 code = CM_ERROR_BADSMB;
3838 * We have a requested path. Check to see if it is something
3841 * But be careful because the name that we might be searching
3842 * for might be a known name with the final character stripped
3845 code = cm_NameI(cm_data.rootSCachep, &requestFileName[nbnLen+2],
3846 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
3847 userp, NULL, &req, &scp);
3851 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
3853 } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
3854 clientchar_t temp[1024];
3855 clientchar_t pathName[1024];
3856 clientchar_t *lastComponent;
3858 * we have a msdfs link somewhere in the path
3859 * we should figure out where in the path the link is.
3862 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%S]", requestFileName);
3864 cm_ClientStrCpy(temp, lengthof(temp), &requestFileName[nbnLen+2]);
3868 cm_ReleaseSCache(dscp);
3872 cm_ReleaseSCache(scp);
3875 smb_StripLastComponent(pathName, &lastComponent, temp);
3877 code = cm_NameI(cm_data.rootSCachep, pathName,
3878 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3879 userp, NULL, &req, &dscp);
3881 code = cm_NameI(dscp, ++lastComponent,
3883 userp, NULL, &req, &scp);
3884 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK)
3887 } while (code == CM_ERROR_PATH_NOT_COVERED);
3889 /* scp should now be the DfsLink we are looking for */
3891 /* figure out how much of the input path was used */
3892 reqLen = (int)(nbnLen+2 + cm_ClientStrLen(pathName) + 1 + cm_ClientStrLen(lastComponent));
3894 cm_FsStringToClientString(&scp->mountPointStringp[strlen("msdfs:")], -1,
3895 referralPath, lengthof(referralPath));
3896 refLen = (int)cm_ClientStrLen(referralPath);
3900 clientchar_t shareName[MAX_PATH + 1];
3901 clientchar_t *p, *q;
3902 /* we may have a sharename that is a volume reference */
3904 for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
3910 if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
3911 code = cm_NameI(cm_data.rootSCachep, _C(""),
3912 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
3913 userp, p, &req, &scp);
3918 cm_ClientStrCpy(referralPath, lengthof(referralPath),
3929 struct smb_v2_referral * v2ref;
3930 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (refLen + 8));
3932 sp = (USHORT *)outp->datap;
3934 sp[idx++] = reqLen; /* path consumed */
3935 sp[idx++] = 1; /* number of referrals */
3936 sp[idx++] = 0x03; /* flags */
3937 #ifdef DFS_VERSION_1
3938 sp[idx++] = 1; /* Version Number */
3939 sp[idx++] = refLen + 4; /* Referral Size */
3940 sp[idx++] = 1; /* Type = SMB Server */
3941 sp[idx++] = 0; /* Do not strip path consumed */
3942 for ( i=0;i<=refLen; i++ )
3943 sp[i+idx] = referralPath[i];
3944 #else /* DFS_VERSION_2 */
3945 sp[idx++] = 2; /* Version Number */
3946 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3947 idx += (sizeof(struct smb_v2_referral) / 2);
3948 v2ref = (struct smb_v2_referral *) &sp[5];
3949 v2ref->ServerType = 1; /* SMB Server */
3950 v2ref->ReferralFlags = 0x03;
3951 v2ref->Proximity = 0; /* closest */
3952 v2ref->TimeToLive = 3600; /* seconds */
3953 v2ref->DfsPathOffset = idx * 2;
3954 v2ref->DfsAlternativePathOffset = idx * 2;
3955 v2ref->NetworkAddressOffset = 0;
3956 for ( i=0;i<=refLen; i++ )
3957 sp[i+idx] = referralPath[i];
3961 code = CM_ERROR_NOSUCHPATH;
3966 cm_ReleaseSCache(dscp);
3968 cm_ReleaseSCache(scp);
3970 cm_ReleaseUser(userp);
3972 smb_SendTran2Packet(vcp, outp, op);
3974 smb_SendTran2Error(vcp, p, op, code);
3976 smb_FreeTran2Packet(outp);
3979 #else /* DFS_SUPPORT */
3980 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3981 return CM_ERROR_NOSUCHDEVICE;
3982 #endif /* DFS_SUPPORT */
3985 /* TRANS2_REPORT_DFS_INCONSISTENCY */
3987 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3989 /* This is a UNICODE only request (bit15 of Flags2) */
3991 /* There is nothing we can do about this operation. The client is going to
3992 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3993 * Unfortunately, there is really nothing we can do about it other then log it
3994 * somewhere. Even then I don't think there is anything for us to do.
3995 * So let's return an error value.
3998 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3999 return CM_ERROR_BADOP;
4003 smb_ApplyV3DirListPatches(cm_scache_t *dscp, smb_dirListPatch_t **dirPatchespp,
4004 clientchar_t * tidPathp, clientchar_t * relPathp,
4005 int infoLevel, cm_user_t *userp, cm_req_t *reqp)
4009 cm_scache_t *targetScp; /* target if scp is a symlink */
4012 unsigned short attr;
4013 unsigned long lattr;
4014 smb_dirListPatch_t *patchp;
4015 smb_dirListPatch_t *npatchp;
4017 afs_int32 mustFake = 0;
4018 clientchar_t path[AFSPATHMAX];
4020 code = cm_FindACLCache(dscp, userp, &rights);
4022 lock_ObtainWrite(&dscp->rw);
4023 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4024 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4026 cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4027 lock_ReleaseWrite(&dscp->rw);
4028 if (code == CM_ERROR_NOACCESS) {
4036 if (!mustFake) { /* Bulk Stat */
4038 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4040 memset(bsp, 0, sizeof(cm_bulkStat_t));
4042 for (patchp = *dirPatchespp, count=0;
4044 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4045 cm_scache_t *tscp = NULL;
4048 code = cm_GetSCache(&patchp->fid, &tscp, userp, reqp);
4050 if (lock_TryWrite(&tscp->rw)) {
4051 /* we have an entry that we can look at */
4052 #ifdef AFS_FREELANCE_CLIENT
4053 if (dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID && dscp->fid.volume == AFS_FAKE_ROOT_VOL_ID) {
4054 code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
4055 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4057 cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4059 lock_ReleaseWrite(&tscp->rw);
4060 cm_ReleaseSCache(tscp);
4063 #endif /* AFS_FREELANCE_CLIENT */
4064 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4065 /* we have a callback on it. Don't bother
4066 * fetching this stat entry, since we're happy
4067 * with the info we have.
4069 lock_ReleaseWrite(&tscp->rw);
4070 cm_ReleaseSCache(tscp);
4073 lock_ReleaseWrite(&tscp->rw);
4075 cm_ReleaseSCache(tscp);
4079 bsp->fids[i].Volume = patchp->fid.volume;
4080 bsp->fids[i].Vnode = patchp->fid.vnode;
4081 bsp->fids[i].Unique = patchp->fid.unique;
4083 if (bsp->counter == AFSCBMAX) {
4084 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4085 memset(bsp, 0, sizeof(cm_bulkStat_t));
4089 if (bsp->counter > 0)
4090 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4095 for( patchp = *dirPatchespp;
4097 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4098 cm_ClientStrPrintfN(path, lengthof(path),_C("%s\\%S"),
4099 relPathp ? relPathp : _C(""), patchp->dep->name);
4100 reqp->relPathp = path;
4101 reqp->tidPathp = tidPathp;
4103 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4104 reqp->relPathp = reqp->tidPathp = NULL;
4108 lock_ObtainWrite(&scp->rw);
4109 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4110 lock_ReleaseWrite(&scp->rw);
4112 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4113 errors in the client. */
4114 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4115 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4117 /* 1969-12-31 23:59:59 +00 */
4118 ft.dwHighDateTime = 0x19DB200;
4119 ft.dwLowDateTime = 0x5BB78980;
4121 /* copy to Creation Time */
4122 fa->creationTime = ft;
4123 fa->lastAccessTime = ft;
4124 fa->lastWriteTime = ft;
4125 fa->lastChangeTime = ft;
4127 switch (scp->fileType) {
4128 case CM_SCACHETYPE_DIRECTORY:
4129 case CM_SCACHETYPE_MOUNTPOINT:
4130 case CM_SCACHETYPE_SYMLINK:
4131 case CM_SCACHETYPE_INVALID:
4132 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4135 /* if we get here we either have a normal file
4136 * or we have a file for which we have never
4137 * received status info. In this case, we can
4138 * check the even/odd value of the entry's vnode.
4139 * even means it is to be treated as a directory
4140 * and odd means it is to be treated as a file.
4142 if (mustFake && (scp->fid.vnode & 0x1))
4143 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4145 fa->extFileAttributes = SMB_ATTR_NORMAL;
4147 /* merge in hidden attribute */
4148 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4149 fa->extFileAttributes |= SMB_ATTR_HIDDEN;
4152 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4154 /* 1969-12-31 23:59:58 +00*/
4155 dosTime = 0xEBBFBF7D;
4157 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4158 fa->lastAccessDateTime = fa->creationDateTime;
4159 fa->lastWriteDateTime = fa->creationDateTime;
4161 /* set the attribute */
4162 switch (scp->fileType) {
4163 case CM_SCACHETYPE_DIRECTORY:
4164 case CM_SCACHETYPE_MOUNTPOINT:
4165 case CM_SCACHETYPE_SYMLINK:
4166 case CM_SCACHETYPE_INVALID:
4167 fa->attributes = SMB_ATTR_DIRECTORY;
4170 /* if we get here we either have a normal file
4171 * or we have a file for which we have never
4172 * received status info. In this case, we can
4173 * check the even/odd value of the entry's vnode.
4174 * even means it is to be treated as a directory
4175 * and odd means it is to be treated as a file.
4177 if (mustFake && (scp->fid.vnode & 0x1))
4178 fa->attributes = SMB_ATTR_DIRECTORY;
4180 fa->attributes = SMB_ATTR_NORMAL;
4183 /* merge in hidden (dot file) attribute */
4184 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4185 fa->attributes |= SMB_ATTR_HIDDEN;
4189 cm_ReleaseSCache(scp);
4193 /* now watch for a symlink */
4195 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
4196 lock_ReleaseWrite(&scp->rw);
4197 cm_ClientStrPrintfN(path, lengthof(path), _C("%s\\%S"),
4198 relPathp ? relPathp : _C(""), patchp->dep->name);
4199 reqp->relPathp = path;
4200 reqp->tidPathp = tidPathp;
4201 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
4202 reqp->relPathp = reqp->tidPathp = NULL;
4204 /* we have a more accurate file to use (the
4205 * target of the symbolic link). Otherwise,
4206 * we'll just use the symlink anyway.
4208 osi_Log2(smb_logp, "symlink vp %x to vp %x",
4210 cm_ReleaseSCache(scp);
4213 lock_ObtainWrite(&scp->rw);
4216 lock_ConvertWToR(&scp->rw);
4218 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4219 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4222 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4224 fa->creationTime = ft;
4225 fa->lastAccessTime = ft;
4226 fa->lastWriteTime = ft;
4227 fa->lastChangeTime = ft;
4229 /* Use length for both file length and alloc length */
4230 fa->endOfFile = scp->length;
4231 fa->allocationSize = scp->length;
4233 /* Copy attributes */
4234 lattr = smb_ExtAttributes(scp);
4235 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK ||
4236 code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4237 if (lattr == SMB_ATTR_NORMAL)
4238 lattr = SMB_ATTR_DIRECTORY;
4240 lattr |= SMB_ATTR_DIRECTORY;
4242 /* merge in hidden (dot file) attribute */
4243 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4244 if (lattr == SMB_ATTR_NORMAL)
4245 lattr = SMB_ATTR_HIDDEN;
4247 lattr |= SMB_ATTR_HIDDEN;
4250 fa->extFileAttributes = lattr;
4252 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4255 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4257 fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
4258 fa->lastAccessDateTime = fa->creationDateTime;
4259 fa->lastWriteDateTime = fa->creationDateTime;
4261 /* copy out file length and alloc length,
4262 * using the same for both
4264 fa->dataSize = scp->length.LowPart;
4265 fa->allocationSize = scp->length.LowPart;
4267 /* finally copy out attributes as short */
4268 attr = smb_Attributes(scp);
4269 /* merge in hidden (dot file) attribute */
4270 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4271 if (lattr == SMB_ATTR_NORMAL)
4272 lattr = SMB_ATTR_HIDDEN;
4274 lattr |= SMB_ATTR_HIDDEN;
4276 fa->attributes = attr;
4279 lock_ReleaseRead(&scp->rw);
4280 cm_ReleaseSCache(scp);
4283 /* now free the patches */
4284 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4285 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4289 /* and mark the list as empty */
4290 *dirPatchespp = NULL;
4296 /* smb_ReceiveTran2SearchDir implements both
4297 * Tran2_Find_First and Tran2_Find_Next
4299 #define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
4300 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
4301 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
4302 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
4303 #define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
4305 /* this is an optimized handler for T2SearchDir that handles the case
4306 where there are no wildcards in the search path. I.e. an
4307 application is using FindFirst(Ex) to get information about a
4308 single file or directory. It will attempt to do a single lookup.
4309 If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4310 the usual mechanism.
4312 This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4314 TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
4316 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4320 long code = 0, code2 = 0;
4321 clientchar_t *pathp = 0;
4323 smb_dirListPatch_t *dirListPatchesp;
4324 smb_dirListPatch_t *curPatchp;
4325 size_t orbytes; /* # of bytes in this output record */
4326 size_t ohbytes; /* # of bytes, except file name */
4327 size_t onbytes; /* # of bytes in name, incl. term. null */
4328 cm_scache_t *scp = NULL;
4329 cm_scache_t *targetscp = NULL;
4330 cm_user_t *userp = NULL;
4331 char *op; /* output data ptr */
4332 char *origOp; /* original value of op */
4333 cm_space_t *spacep; /* for pathname buffer */
4334 unsigned long maxReturnData; /* max # of return data */
4335 long maxReturnParms; /* max # of return parms */
4336 long bytesInBuffer; /* # data bytes in the output buffer */
4337 clientchar_t *maskp; /* mask part of path */
4341 smb_tran2Packet_t *outp; /* response packet */
4342 clientchar_t *tidPathp = 0;
4344 clientchar_t shortName[13]; /* 8.3 name if needed */
4346 clientchar_t *shortNameEnd;
4347 cm_dirEntry_t * dep = NULL;
4350 void * attrp = NULL;
4351 smb_tran2Find_t * fp;
4356 osi_assertx(p->opcode == 1, "invalid opcode");
4358 /* find first; obtain basic parameters from request */
4360 /* note that since we are going to failover to regular
4361 * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4362 * modify any of the input parameters here. */
4363 attribute = p->parmsp[0];
4364 maxCount = p->parmsp[1];
4365 infoLevel = p->parmsp[3];
4366 searchFlags = p->parmsp[2];
4367 pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4369 maskp = cm_ClientStrRChr(pathp, '\\');
4373 maskp++; /* skip over backslash */
4374 /* track if this is likely to match a lot of entries */
4376 osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%S], mask[%S]",
4377 osi_LogSaveClientString(smb_logp, pathp),
4378 osi_LogSaveClientString(smb_logp, maskp));
4380 switch ( infoLevel ) {
4381 case SMB_INFO_STANDARD:
4383 ohbytes = sizeof(fp->u.FstandardInfo);
4386 case SMB_INFO_QUERY_EA_SIZE:
4387 ohbytes = sizeof(fp->u.FeaSizeInfo);
4388 s = "InfoQueryEaSize";
4391 case SMB_INFO_QUERY_EAS_FROM_LIST:
4392 ohbytes = sizeof(fp->u.FeasFromListInfo);
4393 s = "InfoQueryEasFromList";
4396 case SMB_FIND_FILE_DIRECTORY_INFO:
4397 s = "FindFileDirectoryInfo";
4398 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4401 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4402 s = "FindFileFullDirectoryInfo";
4403 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4406 case SMB_FIND_FILE_NAMES_INFO:
4407 s = "FindFileNamesInfo";
4408 ohbytes = sizeof(fp->u.FfileNamesInfo);
4411 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4412 s = "FindFileBothDirectoryInfo";
4413 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4417 s = "unknownInfoLevel";
4421 osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
4424 "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4425 attribute, infoLevel, maxCount, searchFlags);
4428 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4429 return CM_ERROR_INVAL;
4432 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4433 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4435 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4438 dirListPatchesp = NULL;
4440 maxReturnData = p->maxReturnData;
4441 maxReturnParms = 10; /* return params for findfirst, which
4442 is the only one we handle.*/
4444 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4447 osi_Log2(smb_logp, "T2SDSingle search dir count %d [%S]",
4448 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4450 /* bail out if request looks bad */
4452 smb_FreeTran2Packet(outp);
4453 return CM_ERROR_BADSMB;
4456 userp = smb_GetTran2User(vcp, p);
4458 osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
4459 smb_FreeTran2Packet(outp);
4460 return CM_ERROR_BADSMB;
4463 /* try to get the vnode for the path name next */
4464 spacep = cm_GetSpace();
4465 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4466 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4468 cm_ReleaseUser(userp);
4469 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4470 smb_FreeTran2Packet(outp);
4474 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4475 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4476 userp, tidPathp, &req, &scp);
4477 cm_FreeSpace(spacep);
4480 cm_ReleaseUser(userp);
4481 smb_SendTran2Error(vcp, p, opx, code);
4482 smb_FreeTran2Packet(outp);
4486 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4487 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4488 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
4489 cm_ReleaseSCache(scp);
4490 cm_ReleaseUser(userp);
4491 if ( WANTS_DFS_PATHNAMES(p) || pnc )
4492 code = CM_ERROR_PATH_NOT_COVERED;
4494 code = CM_ERROR_BADSHARENAME;
4495 smb_SendTran2Error(vcp, p, opx, code);
4496 smb_FreeTran2Packet(outp);
4499 #endif /* DFS_SUPPORT */
4500 osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
4502 /* now do a single case sensitive lookup for the file in question */
4503 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
4505 /* if a case sensitive match failed, we try a case insensitive one
4507 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
4508 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
4511 if (code == 0 && targetscp->fid.vnode == 0) {
4512 cm_ReleaseSCache(targetscp);
4513 code = CM_ERROR_NOSUCHFILE;
4517 /* if we can't find the directory entry, this block will
4518 return CM_ERROR_NOSUCHFILE, which we will pass on to
4519 smb_ReceiveTran2SearchDir(). */
4520 cm_ReleaseSCache(scp);
4521 cm_ReleaseUser(userp);
4522 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4523 smb_SendTran2Error(vcp, p, opx, code);
4526 smb_FreeTran2Packet(outp);
4530 /* now that we have the target in sight, we proceed with filling
4531 up the return data. */
4533 op = origOp = outp->datap;
4536 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4537 /* skip over resume key */
4541 fp = (smb_tran2Find_t *) op;
4543 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4544 && targetscp->fid.vnode != 0
4545 && !cm_Is8Dot3(maskp)) {
4548 dfid.vnode = htonl(targetscp->fid.vnode);
4549 dfid.unique = htonl(targetscp->fid.unique);
4551 cm_Gen8Dot3NameIntW(maskp, &dfid, shortName, &shortNameEnd);
4557 osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %S (%S)",
4558 htonl(targetscp->fid.vnode),
4559 htonl(targetscp->fid.unique),
4560 osi_LogSaveClientString(smb_logp, pathp),
4561 (NeedShortName)? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
4563 /* Eliminate entries that don't match requested attributes */
4564 if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
4565 smb_IsDotFile(maskp)) {
4567 code = CM_ERROR_NOSUCHFILE;
4568 osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
4573 if (!(attribute & SMB_ATTR_DIRECTORY) &&
4574 (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
4575 targetscp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4576 targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
4577 targetscp->fileType == CM_SCACHETYPE_INVALID)) {
4579 code = CM_ERROR_NOSUCHFILE;
4580 osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
4585 /* add header to name & term. null */
4587 smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
4588 orbytes = ohbytes + onbytes;
4590 /* now, we round up the record to a 4 byte alignment, and we make
4591 * sure that we have enough room here for even the aligned version
4592 * (so we don't have to worry about an * overflow when we pad
4593 * things out below). That's the reason for the alignment
4596 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4597 align = (4 - (orbytes & 3)) & 3;
4601 if (orbytes + align > maxReturnData) {
4603 /* even though this request is unlikely to succeed with a
4604 failover, we do it anyway. */
4605 code = CM_ERROR_NOSUCHFILE;
4606 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4611 /* this is one of the entries to use: it is not deleted and it
4612 * matches the star pattern we're looking for. Put out the name,
4613 * preceded by its length.
4615 /* First zero everything else */
4616 memset(origOp, 0, orbytes);
4619 smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
4621 switch (infoLevel) {
4622 case SMB_INFO_STANDARD:
4623 fp->u.FstandardInfo.fileNameLength = onbytes;
4624 attrp = &fp->u.FstandardInfo.fileAttrs;
4627 case SMB_INFO_QUERY_EA_SIZE:
4628 fp->u.FeaSizeInfo.fileNameLength = onbytes;
4629 attrp = &fp->u.FeaSizeInfo.fileAttrs;
4630 fp->u.FeaSizeInfo.eaSize = 0;
4633 case SMB_INFO_QUERY_EAS_FROM_LIST:
4634 fp->u.FeasFromListInfo.fileNameLength = onbytes;
4635 attrp = &fp->u.FeasFromListInfo.fileAttrs;
4636 fp->u.FeasFromListInfo.eaSize = 0;
4639 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4640 if (NeedShortName) {
4644 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
4645 fp->u.FfileBothDirectoryInfo.shortName,
4646 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
4648 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
4650 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
4651 fp->u.FfileBothDirectoryInfo.reserved = 0;
4653 strcpy(fp->u.FfileBothDirectoryInfo.shortName,
4655 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
4660 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4661 fp->u.FfileFullDirectoryInfo.eaSize = 0;
4664 case SMB_FIND_FILE_DIRECTORY_INFO:
4665 fp->u.FfileDirectoryInfo.nextEntryOffset = 0;
4666 fp->u.FfileDirectoryInfo.fileIndex = 0;
4667 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
4668 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
4671 case SMB_FIND_FILE_NAMES_INFO:
4672 fp->u.FfileNamesInfo.nextEntryOffset = 0;
4673 fp->u.FfileNamesInfo.fileIndex = 0;
4674 fp->u.FfileNamesInfo.fileNameLength = onbytes;
4678 /* we shouldn't hit this case */
4679 osi_assertx(FALSE, "Unknown query type");
4682 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4683 osi_assert(attrp != NULL);
4685 curPatchp = malloc(sizeof(*curPatchp));
4686 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4688 curPatchp->dptr = attrp;
4690 if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
4691 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4693 curPatchp->flags = 0;
4696 cm_SetFid(&curPatchp->fid, targetscp->fid.cell, targetscp->fid.volume, targetscp->fid.vnode, targetscp->fid.unique);
4700 int namelen = cm_ClientStringToFsString(maskp, -1, NULL, 0);
4701 dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+namelen);
4702 cm_ClientStringToFsString(maskp, -1, dep->name, namelen);
4704 dep->fid.vnode = targetscp->fid.vnode;
4705 dep->fid.unique = targetscp->fid.unique;
4706 curPatchp->dep = dep;
4709 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4710 /* put out resume key */
4711 *((u_long *)origOp) = 0;
4714 /* Adjust byte ptr and count */
4715 origOp += orbytes; /* skip entire record */
4716 bytesInBuffer += orbytes;
4718 /* and pad the record out */
4719 while (--align >= 0) {
4724 /* apply the patches */
4725 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->wdata, infoLevel, userp, &req);
4727 outp->parmsp[0] = 0;
4728 outp->parmsp[1] = 1; /* number of names returned */
4729 outp->parmsp[2] = 1; /* end of search */
4730 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4731 outp->parmsp[4] = 0;
4733 outp->totalParms = 10; /* in bytes */
4735 outp->totalData = bytesInBuffer;
4737 osi_Log0(smb_logp, "T2SDSingle done.");
4739 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4741 smb_SendTran2Error(vcp, p, opx, code);
4743 smb_SendTran2Packet(vcp, outp, opx);
4748 smb_FreeTran2Packet(outp);
4752 cm_ReleaseSCache(scp);
4753 cm_ReleaseSCache(targetscp);
4754 cm_ReleaseUser(userp);
4760 /* TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2 */
4761 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4766 long code = 0, code2 = 0;
4767 clientchar_t *pathp;
4768 cm_dirEntry_t *dep = 0;
4770 smb_dirListPatch_t *dirListPatchesp = 0;
4771 smb_dirListPatch_t *curPatchp = 0;
4774 size_t orbytes; /* # of bytes in this output record */
4775 size_t ohbytes; /* # of bytes, except file name */
4776 size_t onbytes; /* # of bytes in name, incl. term. null */
4777 osi_hyper_t dirLength;
4778 osi_hyper_t bufferOffset;
4779 osi_hyper_t curOffset;
4781 smb_dirSearch_t *dsp;
4785 cm_pageHeader_t *pageHeaderp;
4786 cm_user_t *userp = NULL;
4789 long nextEntryCookie;
4790 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4791 char *op; /* output data ptr */
4792 char *origOp; /* original value of op */
4793 cm_space_t *spacep; /* for pathname buffer */
4794 unsigned long maxReturnData; /* max # of return data */
4795 unsigned long maxReturnParms; /* max # of return parms */
4796 long bytesInBuffer; /* # data bytes in the output buffer */
4798 clientchar_t *maskp; /* mask part of path */
4802 smb_tran2Packet_t *outp; /* response packet */
4803 clientchar_t *tidPathp;
4805 clientchar_t shortName[13]; /* 8.3 name if needed */
4808 clientchar_t *shortNameEnd;
4814 smb_tran2Find_t * fp;
4819 if (p->opcode == 1) {
4820 /* find first; obtain basic parameters from request */
4821 attribute = p->parmsp[0];
4822 maxCount = p->parmsp[1];
4823 infoLevel = p->parmsp[3];
4824 searchFlags = p->parmsp[2];
4825 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4827 maskp = cm_ClientStrRChr(pathp, '\\');
4831 maskp++; /* skip over backslash */
4833 /* track if this is likely to match a lot of entries */
4834 starPattern = smb_V3IsStarMask(maskp);
4836 #ifndef NOFINDFIRSTOPTIMIZE
4838 /* if this is for a single directory or file, we let the
4839 optimized routine handle it. The only error it
4840 returns is CM_ERROR_NOSUCHFILE. The */
4841 code = smb_T2SearchDirSingle(vcp, p, opx);
4843 /* we only failover if we see a CM_ERROR_NOSUCHFILE */
4844 if (code != CM_ERROR_NOSUCHFILE) {
4846 /* unless we are using the BPlusTree */
4847 if (code == CM_ERROR_BPLUS_NOMATCH)
4848 code = CM_ERROR_NOSUCHFILE;
4849 #endif /* USE_BPLUS */
4853 #endif /* NOFINDFIRSTOPTIMIZE */
4856 dsp = smb_NewDirSearch(1);
4857 dsp->attribute = attribute;
4858 cm_ClientStrCpy(dsp->mask, lengthof(dsp->mask), maskp); /* and save mask */
4861 osi_assertx(p->opcode == 2, "invalid opcode");
4862 /* find next; obtain basic parameters from request or open dir file */
4863 dsp = smb_FindDirSearch(p->parmsp[0]);
4864 maxCount = p->parmsp[1];
4865 infoLevel = p->parmsp[2];
4866 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4867 searchFlags = p->parmsp[5];
4869 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4870 p->parmsp[0], nextCookie);
4871 return CM_ERROR_BADFD;
4873 attribute = dsp->attribute;
4876 starPattern = 1; /* assume, since required a Find Next */
4879 switch ( infoLevel ) {
4880 case SMB_INFO_STANDARD:
4882 ohbytes = sizeof(fp->u.FstandardInfo);
4885 case SMB_INFO_QUERY_EA_SIZE:
4886 ohbytes = sizeof(fp->u.FeaSizeInfo);
4887 s = "InfoQueryEaSize";
4890 case SMB_INFO_QUERY_EAS_FROM_LIST:
4891 ohbytes = sizeof(fp->u.FeasFromListInfo);
4892 s = "InfoQueryEasFromList";
4895 case SMB_FIND_FILE_DIRECTORY_INFO:
4896 s = "FindFileDirectoryInfo";
4897 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4900 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4901 s = "FindFileFullDirectoryInfo";
4902 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4905 case SMB_FIND_FILE_NAMES_INFO:
4906 s = "FindFileNamesInfo";
4907 ohbytes = sizeof(fp->u.FfileNamesInfo);
4910 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4911 s = "FindFileBothDirectoryInfo";
4912 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4916 s = "unknownInfoLevel";
4920 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
4923 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4924 attribute, infoLevel, maxCount, searchFlags);
4926 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
4927 p->opcode, dsp->cookie, nextCookie);
4930 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4931 smb_ReleaseDirSearch(dsp);
4932 return CM_ERROR_INVAL;
4935 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4936 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4938 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4941 dirListPatchesp = NULL;
4943 maxReturnData = p->maxReturnData;
4944 if (p->opcode == 1) /* find first */
4945 maxReturnParms = 10; /* bytes */
4947 maxReturnParms = 8; /* bytes */
4949 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4955 osi_Log2(smb_logp, "T2 receive search dir count %d [%S]",
4956 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4958 /* bail out if request looks bad */
4959 if (p->opcode == 1 && !pathp) {
4960 smb_ReleaseDirSearch(dsp);
4961 smb_FreeTran2Packet(outp);
4962 return CM_ERROR_BADSMB;
4965 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
4966 dsp->cookie, nextCookie, attribute);
4968 userp = smb_GetTran2User(vcp, p);
4970 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
4971 smb_ReleaseDirSearch(dsp);
4972 smb_FreeTran2Packet(outp);
4973 return CM_ERROR_BADSMB;
4976 /* try to get the vnode for the path name next */
4977 lock_ObtainMutex(&dsp->mx);
4980 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4984 spacep = cm_GetSpace();
4985 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4986 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4988 cm_ReleaseUser(userp);
4989 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4990 smb_FreeTran2Packet(outp);
4991 lock_ReleaseMutex(&dsp->mx);
4992 smb_DeleteDirSearch(dsp);
4993 smb_ReleaseDirSearch(dsp);
4997 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4998 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
5000 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
5001 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5002 userp, tidPathp, &req, &scp);
5003 cm_FreeSpace(spacep);
5006 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
5007 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5008 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
5009 cm_ReleaseSCache(scp);
5010 cm_ReleaseUser(userp);
5011 if ( WANTS_DFS_PATHNAMES(p) || pnc )
5012 code = CM_ERROR_PATH_NOT_COVERED;
5014 code = CM_ERROR_BADSHARENAME;
5015 smb_SendTran2Error(vcp, p, opx, code);
5016 smb_FreeTran2Packet(outp);
5017 lock_ReleaseMutex(&dsp->mx);
5018 smb_DeleteDirSearch(dsp);
5019 smb_ReleaseDirSearch(dsp);
5022 #endif /* DFS_SUPPORT */
5024 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5025 /* we need one hold for the entry we just stored into,
5026 * and one for our own processing. When we're done
5027 * with this function, we'll drop the one for our own
5028 * processing. We held it once from the namei call,
5029 * and so we do another hold now.
5032 dsp->flags |= SMB_DIRSEARCH_BULKST;
5035 lock_ReleaseMutex(&dsp->mx);
5037 cm_ReleaseUser(userp);
5038 smb_FreeTran2Packet(outp);
5039 smb_DeleteDirSearch(dsp);
5040 smb_ReleaseDirSearch(dsp);
5044 /* get the directory size */
5045 lock_ObtainWrite(&scp->rw);
5046 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5047 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5049 lock_ReleaseWrite(&scp->rw);
5050 cm_ReleaseSCache(scp);
5051 cm_ReleaseUser(userp);
5052 smb_FreeTran2Packet(outp);
5053 smb_DeleteDirSearch(dsp);
5054 smb_ReleaseDirSearch(dsp);
5058 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5061 dirLength = scp->length;
5063 bufferOffset.LowPart = bufferOffset.HighPart = 0;
5064 curOffset.HighPart = 0;
5065 curOffset.LowPart = nextCookie;
5066 origOp = outp->datap;
5073 normchar_t normName[MAX_PATH]; /* Normalized name */
5074 clientchar_t cfileName[MAX_PATH]; /* Non-normalized name */
5077 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5078 /* skip over resume key */
5081 fp = (smb_tran2Find_t *) op;
5083 /* make sure that curOffset.LowPart doesn't point to the first
5084 * 32 bytes in the 2nd through last dir page, and that it doesn't
5085 * point at the first 13 32-byte chunks in the first dir page,
5086 * since those are dir and page headers, and don't contain useful
5089 temp = curOffset.LowPart & (2048-1);
5090 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5091 /* we're in the first page */
5092 if (temp < 13*32) temp = 13*32;
5095 /* we're in a later dir page */
5096 if (temp < 32) temp = 32;
5099 /* make sure the low order 5 bits are zero */
5102 /* now put temp bits back ito curOffset.LowPart */
5103 curOffset.LowPart &= ~(2048-1);
5104 curOffset.LowPart |= temp;
5106 /* check if we've passed the dir's EOF */
5107 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
5108 osi_Log0(smb_logp, "T2 search dir passed eof");
5113 /* check if we've returned all the names that will fit in the
5114 * response packet; we check return count as well as the number
5115 * of bytes requested. We check the # of bytes after we find
5116 * the dir entry, since we'll need to check its size.
5118 if (returnedNames >= maxCount) {
5119 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
5120 returnedNames, maxCount);
5124 /* when we have obtained as many entries as can be processed in
5125 * a single Bulk Status call to the file server, apply the dir listing
5128 if (returnedNames > 0 && returnedNames % AFSCBMAX == 0) {
5129 lock_ReleaseWrite(&scp->rw);
5130 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5131 dsp->relPath, infoLevel, userp, &req);
5132 lock_ObtainWrite(&scp->rw);
5134 /* Then check to see if we have time left to process more entries */
5135 if (GetTickCount() - req.startTime > (RDRtimeout - 15) * 1000) {
5136 osi_Log0(smb_logp, "T2 search dir RDRtimeout exceeded");
5140 /* see if we can use the bufferp we have now; compute in which
5141 * page the current offset would be, and check whether that's
5142 * the offset of the buffer we have. If not, get the buffer.
5144 thyper.HighPart = curOffset.HighPart;
5145 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5146 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5149 buf_Release(bufferp);
5152 lock_ReleaseWrite(&scp->rw);
5153 code = buf_Get(scp, &thyper, &bufferp);
5154 lock_ObtainWrite(&scp->rw);
5156 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
5160 bufferOffset = thyper;
5162 /* now get the data in the cache */
5164 code = cm_SyncOp(scp, bufferp, userp, &req,
5166 CM_SCACHESYNC_NEEDCALLBACK
5167 | CM_SCACHESYNC_READ);
5169 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5173 if (cm_HaveBuffer(scp, bufferp, 0)) {
5174 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5175 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5179 /* otherwise, load the buffer and try again */
5180 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5182 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5184 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5185 scp, bufferp, code);
5190 buf_Release(bufferp);
5194 } /* if (wrong buffer) ... */
5196 /* now we have the buffer containing the entry we're interested
5197 * in; copy it out if it represents a non-deleted entry.
5199 entryInDir = curOffset.LowPart & (2048-1);
5200 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5202 /* page header will help tell us which entries are free. Page
5203 * header can change more often than once per buffer, since
5204 * AFS 3 dir page size may be less than (but not more than)
5205 * a buffer package buffer.
5207 /* only look intra-buffer */
5208 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5209 temp &= ~(2048 - 1); /* turn off intra-page bits */
5210 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5212 /* now determine which entry we're looking at in the page.
5213 * If it is free (there's a free bitmap at the start of the
5214 * dir), we should skip these 32 bytes.
5216 slotInPage = (entryInDir & 0x7e0) >> 5;
5217 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5218 (1 << (slotInPage & 0x7)))) {
5219 /* this entry is free */
5220 numDirChunks = 1; /* only skip this guy */
5224 tp = bufferp->datap + entryInBuffer;
5225 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5227 /* while we're here, compute the next entry's location, too,
5228 * since we'll need it when writing out the cookie into the dir
5231 * XXXX Probably should do more sanity checking.
5233 numDirChunks = cm_NameEntries(dep->name, &onbytes);
5235 /* compute offset of cookie representing next entry */
5236 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5238 if (dep->fid.vnode == 0)
5239 goto nextEntry; /* This entry is not in use */
5241 cm_FsStringToClientString(dep->name, -1, cfileName, lengthof(cfileName));
5242 cm_ClientStringToNormString(cfileName, -1, normName, lengthof(normName));
5244 /* Need 8.3 name? */
5246 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
5247 !cm_Is8Dot3(cfileName)) {
5248 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5252 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %S (%S)",
5253 dep->fid.vnode, dep->fid.unique,
5254 osi_LogSaveClientString(smb_logp, cfileName),
5255 NeedShortName ? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
5257 /* When matching, we are using doing a case fold if we have a wildcard mask.
5258 * If we get a non-wildcard match, it's a lookup for a specific file.
5260 if (cm_MatchMask(normName, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5261 (NeedShortName && cm_MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))
5263 /* Eliminate entries that don't match requested attributes */
5264 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5265 smb_IsDotFile(cfileName)) {
5266 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5267 goto nextEntry; /* no hidden files */
5270 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5272 /* We have already done the cm_TryBulkStat above */
5273 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume,
5274 ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5275 fileType = cm_FindFileType(&fid);
5276 /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5277 * "has filetype %d", dep->name, fileType);
5279 if ( fileType == CM_SCACHETYPE_DIRECTORY ||
5280 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5281 fileType == CM_SCACHETYPE_DFSLINK ||
5282 fileType == CM_SCACHETYPE_INVALID)
5283 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5287 /* finally check if this name will fit */
5289 smb_UnparseString(opx, NULL, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5290 orbytes = ohbytes + onbytes;
5292 /* now, we round up the record to a 4 byte alignment,
5293 * and we make sure that we have enough room here for
5294 * even the aligned version (so we don't have to worry
5295 * about an overflow when we pad things out below).
5296 * That's the reason for the alignment arithmetic below.
5298 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5299 align = (4 - (orbytes & 3)) & 3;
5303 if (orbytes + bytesInBuffer + align > maxReturnData) {
5304 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5309 /* this is one of the entries to use: it is not deleted
5310 * and it matches the star pattern we're looking for.
5311 * Put out the name, preceded by its length.
5313 /* First zero everything else */
5314 memset(origOp, 0, orbytes);
5317 smb_UnparseString(opx, origOp + ohbytes, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5319 switch (infoLevel) {
5320 case SMB_INFO_STANDARD:
5321 fp->u.FstandardInfo.fileNameLength = onbytes;
5322 attrp = &fp->u.FstandardInfo.fileAttrs;
5325 case SMB_INFO_QUERY_EA_SIZE:
5326 fp->u.FeaSizeInfo.fileNameLength = onbytes;
5327 attrp = &fp->u.FeaSizeInfo.fileAttrs;
5328 fp->u.FeaSizeInfo.eaSize = 0;
5331 case SMB_INFO_QUERY_EAS_FROM_LIST:
5332 fp->u.FeasFromListInfo.fileNameLength = onbytes;
5333 attrp = &fp->u.FeasFromListInfo.fileAttrs;
5334 fp->u.FeasFromListInfo.eaSize = 0;
5337 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5338 if (NeedShortName) {
5342 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
5343 fp->u.FfileBothDirectoryInfo.shortName,
5344 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
5346 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
5348 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5349 fp->u.FfileBothDirectoryInfo.reserved = 0;
5351 cm_ClientStrCpy(fp->u.FfileBothDirectoryInfo.shortName,
5352 lengthof(fp->u.FfileBothDirectoryInfo.shortName),
5354 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
5359 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5360 fp->u.FfileFullDirectoryInfo.eaSize = 0;
5363 case SMB_FIND_FILE_DIRECTORY_INFO:
5364 fp->u.FfileDirectoryInfo.nextEntryOffset = orbytes + align;
5365 fp->u.FfileDirectoryInfo.fileIndex = nextEntryCookie;
5366 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5367 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5370 case SMB_FIND_FILE_NAMES_INFO:
5371 fp->u.FfileNamesInfo.nextEntryOffset = orbytes + align;
5372 fp->u.FfileNamesInfo.fileIndex = nextEntryCookie;
5373 fp->u.FfileNamesInfo.fileNameLength = onbytes;
5378 /* we shouldn't hit this case */
5379 osi_assertx(FALSE, "Unknown query type");
5382 /* now, adjust the # of entries copied */
5385 /* now we emit the attribute. This is tricky, since
5386 * we need to really stat the file to find out what
5387 * type of entry we've got. Right now, we're copying
5388 * out data from a buffer, while holding the scp
5389 * locked, so it isn't really convenient to stat
5390 * something now. We'll put in a place holder
5391 * now, and make a second pass before returning this
5392 * to get the real attributes. So, we just skip the
5393 * data for now, and adjust it later. We allocate a
5394 * patch record to make it easy to find this point
5395 * later. The replay will happen at a time when it is
5396 * safe to unlock the directory.
5398 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5399 osi_assert(attrp != NULL);
5400 curPatchp = malloc(sizeof(*curPatchp));
5401 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5402 curPatchp->dptr = attrp;
5404 if (smb_hideDotFiles && smb_IsDotFile(cfileName)) {
5405 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5407 curPatchp->flags = 0;
5410 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5413 curPatchp->dep = dep;
5416 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5417 /* put out resume key */
5418 *((u_long *)origOp) = nextEntryCookie;
5420 /* Adjust byte ptr and count */
5421 origOp += orbytes; /* skip entire record */
5422 bytesInBuffer += orbytes;
5424 /* and pad the record out */
5425 while (align-- > 0) {
5429 } /* if we're including this name */
5430 else if (!starPattern &&
5432 cm_MatchMask(normName, maskp, CM_FLAG_CASEFOLD)) {
5433 /* We were looking for exact matches, but here's an inexact one*/
5438 /* and adjust curOffset to be where the new cookie is */
5439 thyper.HighPart = 0;
5440 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5441 curOffset = LargeIntegerAdd(thyper, curOffset);
5442 } /* while copying data for dir listing */
5444 /* If we didn't get a star pattern, we did an exact match during the first pass.
5445 * If there were no exact matches found, we fail over to inexact matches by
5446 * marking the query as a star pattern (matches all case permutations), and
5447 * re-running the query.
5449 if (returnedNames == 0 && !starPattern && foundInexact) {
5450 osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
5455 /* release the mutex */
5456 lock_ReleaseWrite(&scp->rw);
5458 buf_Release(bufferp);
5463 * Finally, process whatever entries we have left.
5465 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5466 dsp->relPath, infoLevel, userp, &req);
5468 /* now put out the final parameters */
5469 if (returnedNames == 0)
5471 if (p->opcode == 1) {
5473 outp->parmsp[0] = (unsigned short) dsp->cookie;
5474 outp->parmsp[1] = returnedNames;
5475 outp->parmsp[2] = eos;
5476 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5477 outp->parmsp[4] = 0;
5478 /* don't need last name to continue
5479 * search, cookie is enough. Normally,
5480 * this is the offset of the file name
5481 * of the last entry returned.
5483 outp->totalParms = 10; /* in bytes */
5487 outp->parmsp[0] = returnedNames;
5488 outp->parmsp[1] = eos;
5489 outp->parmsp[2] = 0; /* EAS error */
5490 outp->parmsp[3] = 0; /* last name, as above */
5491 outp->totalParms = 8; /* in bytes */
5494 /* return # of bytes in the buffer */
5495 outp->totalData = bytesInBuffer;
5497 /* Return error code if unsuccessful on first request */
5498 if (code == 0 && p->opcode == 1 && returnedNames == 0)
5499 code = CM_ERROR_NOSUCHFILE;
5501 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
5502 p->opcode, dsp->cookie, returnedNames, code);
5504 /* if we're supposed to close the search after this request, or if
5505 * we're supposed to close the search if we're done, and we're done,
5506 * or if something went wrong, close the search.
5508 if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
5509 (returnedNames == 0) ||
5510 ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
5512 smb_DeleteDirSearch(dsp);
5515 smb_SendTran2Error(vcp, p, opx, code);
5517 smb_SendTran2Packet(vcp, outp, opx);
5519 smb_FreeTran2Packet(outp);
5520 smb_ReleaseDirSearch(dsp);
5521 cm_ReleaseSCache(scp);
5522 cm_ReleaseUser(userp);
5526 /* SMB_COM_FIND_CLOSE2 */
5527 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5530 smb_dirSearch_t *dsp;
5532 dirHandle = smb_GetSMBParm(inp, 0);
5534 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
5536 dsp = smb_FindDirSearch(dirHandle);
5539 return CM_ERROR_BADFD;
5541 /* otherwise, we have an FD to destroy */
5542 smb_DeleteDirSearch(dsp);
5543 smb_ReleaseDirSearch(dsp);
5545 /* and return results */
5546 smb_SetSMBDataLength(outp, 0);
5552 /* SMB_COM_FIND_NOTIFY_CLOSE */
5553 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5555 smb_SetSMBDataLength(outp, 0);
5559 /* SMB_COM_OPEN_ANDX */
5560 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5562 clientchar_t *pathp;
5567 cm_scache_t *dscp; /* dir we're dealing with */
5568 cm_scache_t *scp; /* file we're creating */
5570 int initialModeBits;
5573 clientchar_t *lastNamep;
5574 unsigned long dosTime;
5580 int parmSlot; /* which parm we're dealing with */
5581 clientchar_t *tidPathp;
5589 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
5590 openFun = smb_GetSMBParm(inp, 8); /* open function */
5591 excl = ((openFun & 3) == 0);
5592 trunc = ((openFun & 3) == 2); /* truncate it */
5593 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
5594 openAction = 0; /* tracks what we did */
5596 attributes = smb_GetSMBParm(inp, 5);
5597 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
5599 /* compute initial mode bits based on read-only flag in attributes */
5600 initialModeBits = 0666;
5601 if (attributes & SMB_ATTR_READONLY)
5602 initialModeBits &= ~0222;
5604 pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
5607 spacep = inp->spacep;
5608 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5611 (cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
5612 cm_ClientStrCmpIA(lastNamep, _C("\\srvsvc")) == 0 ||
5613 cm_ClientStrCmpIA(lastNamep, _C("\\wkssvc")) == 0 ||
5614 cm_ClientStrCmpIA(lastNamep, _C("ipc$")) == 0)) {
5615 /* special case magic file name for receiving IOCTL requests
5616 * (since IOCTL calls themselves aren't getting through).
5619 osi_Log0(smb_logp, "IOCTL Open");
5622 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5623 smb_SetupIoctlFid(fidp, spacep);
5625 /* set inp->fid so that later read calls in same msg can find fid */
5626 inp->fid = fidp->fid;
5628 /* copy out remainder of the parms */
5630 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5632 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
5633 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
5634 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5635 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
5636 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
5637 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5638 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5639 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5641 /* and the final "always present" stuff */
5642 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
5643 /* next write out the "unique" ID */
5644 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
5645 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
5646 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5647 smb_SetSMBDataLength(outp, 0);
5649 /* and clean up fid reference */
5650 smb_ReleaseFID(fidp);
5654 #ifdef DEBUG_VERBOSE
5656 char *hexp, *asciip;
5657 asciip = (lastNamep ? lastNamep : pathp );
5658 hexp = osi_HexifyString(asciip);
5659 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
5663 userp = smb_GetUserFromVCP(vcp, inp);
5666 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5668 cm_ReleaseUser(userp);
5669 return CM_ERROR_NOSUCHPATH;
5671 code = cm_NameI(cm_data.rootSCachep, pathp,
5672 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5673 userp, tidPathp, &req, &scp);
5676 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5677 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5678 cm_ReleaseSCache(scp);
5679 cm_ReleaseUser(userp);
5680 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5681 return CM_ERROR_PATH_NOT_COVERED;
5683 return CM_ERROR_BADSHARENAME;
5685 #endif /* DFS_SUPPORT */
5688 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
5689 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5690 userp, tidPathp, &req, &dscp);
5692 cm_ReleaseUser(userp);
5697 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5698 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5700 cm_ReleaseSCache(dscp);
5701 cm_ReleaseUser(userp);
5702 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5703 return CM_ERROR_PATH_NOT_COVERED;
5705 return CM_ERROR_BADSHARENAME;
5707 #endif /* DFS_SUPPORT */
5708 /* otherwise, scp points to the parent directory. Do a lookup,
5709 * and truncate the file if we find it, otherwise we create the
5716 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
5718 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5719 cm_ReleaseSCache(dscp);
5720 cm_ReleaseUser(userp);
5725 /* if we get here, if code is 0, the file exists and is represented by
5726 * scp. Otherwise, we have to create it. The dir may be represented
5727 * by dscp, or we may have found the file directly. If code is non-zero,
5731 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
5733 if (dscp) cm_ReleaseSCache(dscp);
5734 cm_ReleaseSCache(scp);
5735 cm_ReleaseUser(userp);
5740 /* oops, file shouldn't be there */
5742 cm_ReleaseSCache(dscp);
5743 cm_ReleaseSCache(scp);
5744 cm_ReleaseUser(userp);
5745 return CM_ERROR_EXISTS;
5749 setAttr.mask = CM_ATTRMASK_LENGTH;
5750 setAttr.length.LowPart = 0;
5751 setAttr.length.HighPart = 0;
5752 code = cm_SetAttr(scp, &setAttr, userp, &req);
5753 openAction = 3; /* truncated existing file */
5755 else openAction = 1; /* found existing file */
5757 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
5758 /* don't create if not found */
5759 if (dscp) cm_ReleaseSCache(dscp);
5760 cm_ReleaseUser(userp);
5761 return CM_ERROR_NOSUCHFILE;
5764 osi_assertx(dscp != NULL, "null cm_scache_t");
5765 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %S",
5766 osi_LogSaveClientString(smb_logp, lastNamep));
5767 openAction = 2; /* created file */
5768 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5769 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5770 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5774 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5775 smb_NotifyChange(FILE_ACTION_ADDED,
5776 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5777 dscp, lastNamep, NULL, TRUE);
5778 } else if (!excl && code == CM_ERROR_EXISTS) {
5779 /* not an exclusive create, and someone else tried
5780 * creating it already, then we open it anyway. We
5781 * don't bother retrying after this, since if this next
5782 * fails, that means that the file was deleted after we
5783 * started this call.
5785 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5789 setAttr.mask = CM_ATTRMASK_LENGTH;
5790 setAttr.length.LowPart = 0;
5791 setAttr.length.HighPart = 0;
5792 code = cm_SetAttr(scp, &setAttr, userp, &req);
5794 } /* lookup succeeded */
5798 /* we don't need this any longer */
5800 cm_ReleaseSCache(dscp);
5803 /* something went wrong creating or truncating the file */
5805 cm_ReleaseSCache(scp);
5806 cm_ReleaseUser(userp);
5810 /* make sure we're about to open a file */
5811 if (scp->fileType != CM_SCACHETYPE_FILE) {
5812 cm_ReleaseSCache(scp);
5813 cm_ReleaseUser(userp);
5814 return CM_ERROR_ISDIR;
5817 /* now all we have to do is open the file itself */
5818 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5819 osi_assertx(fidp, "null smb_fid_t");
5822 lock_ObtainMutex(&fidp->mx);
5823 /* save a pointer to the vnode */
5825 lock_ObtainWrite(&scp->rw);
5826 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5827 lock_ReleaseWrite(&scp->rw);
5828 osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
5830 fidp->userp = userp;
5832 /* compute open mode */
5834 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5835 if (openMode == 1 || openMode == 2)
5836 fidp->flags |= SMB_FID_OPENWRITE;
5838 /* remember if the file was newly created */
5840 fidp->flags |= SMB_FID_CREATED;
5842 lock_ReleaseMutex(&fidp->mx);
5843 smb_ReleaseFID(fidp);
5845 cm_Open(scp, 0, userp);
5847 /* set inp->fid so that later read calls in same msg can find fid */
5848 inp->fid = fidp->fid;
5850 /* copy out remainder of the parms */
5852 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5853 lock_ObtainRead(&scp->rw);
5855 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5856 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5857 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5858 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5859 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5860 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5861 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5862 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5863 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5865 /* and the final "always present" stuff */
5866 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5867 /* next write out the "unique" ID */
5868 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5869 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5870 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5871 lock_ReleaseRead(&scp->rw);
5872 smb_SetSMBDataLength(outp, 0);
5874 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5876 cm_ReleaseUser(userp);
5877 /* leave scp held since we put it in fidp->scp */
5881 static void smb_GetLockParams(unsigned char LockType,
5883 unsigned int * ppid,
5884 LARGE_INTEGER * pOffset,
5885 LARGE_INTEGER * pLength)
5887 if (LockType & LOCKING_ANDX_LARGE_FILES) {
5889 *ppid = *((USHORT *) *buf);
5890 pOffset->HighPart = *((LONG *)(*buf + 4));
5891 pOffset->LowPart = *((DWORD *)(*buf + 8));
5892 pLength->HighPart = *((LONG *)(*buf + 12));
5893 pLength->LowPart = *((DWORD *)(*buf + 16));
5897 /* Not Large Files */
5898 *ppid = *((USHORT *) *buf);
5899 pOffset->HighPart = 0;
5900 pOffset->LowPart = *((DWORD *)(*buf + 2));
5901 pLength->HighPart = 0;
5902 pLength->LowPart = *((DWORD *)(*buf + 6));
5907 /* SMB_COM_LOCKING_ANDX */
5908 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5915 unsigned char LockType;
5916 unsigned short NumberOfUnlocks, NumberOfLocks;
5920 LARGE_INTEGER LOffset, LLength;
5921 smb_waitingLockRequest_t *wlRequest = NULL;
5922 cm_file_lock_t *lockp;
5930 fid = smb_GetSMBParm(inp, 2);
5931 fid = smb_ChainFID(fid, inp);
5933 fidp = smb_FindFID(vcp, fid, 0);
5935 return CM_ERROR_BADFD;
5937 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
5938 smb_CloseFID(vcp, fidp, NULL, 0);
5939 smb_ReleaseFID(fidp);
5940 return CM_ERROR_NOSUCHFILE;
5943 lock_ObtainMutex(&fidp->mx);
5944 if (fidp->flags & SMB_FID_IOCTL) {
5945 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
5946 lock_ReleaseMutex(&fidp->mx);
5947 smb_ReleaseFID(fidp);
5948 return CM_ERROR_BADFD;
5951 osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
5953 lock_ReleaseMutex(&fidp->mx);
5955 /* set inp->fid so that later read calls in same msg can find fid */
5958 userp = smb_GetUserFromVCP(vcp, inp);
5961 lock_ObtainWrite(&scp->rw);
5962 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5963 CM_SCACHESYNC_NEEDCALLBACK
5964 | CM_SCACHESYNC_GETSTATUS
5965 | CM_SCACHESYNC_LOCK);
5967 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
5971 LockType = smb_GetSMBParm(inp, 3) & 0xff;
5972 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
5973 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
5974 NumberOfLocks = smb_GetSMBParm(inp, 7);
5976 if (!(fidp->flags & SMB_FID_OPENWRITE) &&
5977 !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
5978 /* somebody wants exclusive locks on a file that they only
5979 opened for reading. We downgrade this to a shared lock. */
5980 osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
5981 LockType |= LOCKING_ANDX_SHARED_LOCK;
5984 if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
5985 /* AFS does not support atomic changes of lock types from read or write and vice-versa */
5986 osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]");
5987 code = CM_ERROR_BADOP;
5992 op = smb_GetSMBData(inp, NULL);
5994 if (LockType & LOCKING_ANDX_CANCEL_LOCK) {
5995 /* Cancel outstanding lock requests */
5996 smb_waitingLock_t * wl;
5998 for (i=0; i<NumberOfLocks; i++) {
5999 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6001 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6003 lock_ObtainWrite(&smb_globalLock);
6004 for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
6006 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
6007 if (wl->key == key && LargeIntegerEqualTo(wl->LOffset, LOffset) &&
6008 LargeIntegerEqualTo(wl->LLength, LLength)) {
6009 wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
6010 goto found_lock_request;
6015 lock_ReleaseWrite(&smb_globalLock);
6018 smb_SetSMBDataLength(outp, 0);
6023 for (i=0; i<NumberOfUnlocks; i++) {
6024 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6026 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6028 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
6036 for (i=0; i<NumberOfLocks; i++) {
6037 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6039 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6041 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
6042 userp, &req, &lockp);
6044 if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
6045 (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
6047 code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
6048 userp, &req, &lockp);
6051 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
6052 smb_waitingLock_t * wLock;
6054 /* Put on waiting list */
6055 if(wlRequest == NULL) {
6059 LARGE_INTEGER tOffset, tLength;
6061 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
6063 osi_assertx(wlRequest != NULL, "null wlRequest");
6065 wlRequest->vcp = vcp;
6067 wlRequest->scp = scp;
6068 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
6070 wlRequest->inp = smb_CopyPacket(inp);
6071 wlRequest->outp = smb_CopyPacket(outp);
6072 wlRequest->lockType = LockType;
6073 wlRequest->msTimeout = Timeout;
6074 wlRequest->start_t = osi_Time();
6075 wlRequest->locks = NULL;
6077 /* The waiting lock request needs to have enough
6078 information to undo all the locks in the request.
6079 We do the following to store info about locks that
6080 have already been granted. Sure, we can get most
6081 of the info from the packet, but the packet doesn't
6082 hold the result of cm_Lock call. In practice we
6083 only receive packets with one or two locks, so we
6084 are only wasting a few bytes here and there and
6085 only for a limited period of time until the waiting
6086 lock times out or is freed. */
6088 for(opt = op_locks, j=i; j > 0; j--) {
6089 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
6091 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6093 wLock = malloc(sizeof(smb_waitingLock_t));
6095 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6098 wLock->LOffset = tOffset;
6099 wLock->LLength = tLength;
6100 wLock->lockp = NULL;
6101 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
6102 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6107 wLock = malloc(sizeof(smb_waitingLock_t));
6109 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6112 wLock->LOffset = LOffset;
6113 wLock->LLength = LLength;
6114 wLock->lockp = lockp;
6115 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
6116 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6119 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
6127 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
6134 /* Since something went wrong with the lock number i, we now
6135 have to go ahead and release any locks acquired before the
6136 failure. All locks before lock number i (of which there
6137 are i of them) have either been successful or are waiting.
6138 Either case requires calling cm_Unlock(). */
6140 /* And purge the waiting lock */
6141 if(wlRequest != NULL) {
6142 smb_waitingLock_t * wl;
6143 smb_waitingLock_t * wlNext;
6146 for(wl = wlRequest->locks; wl; wl = wlNext) {
6148 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
6150 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
6153 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
6155 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
6158 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
6163 smb_ReleaseVC(wlRequest->vcp);
6164 cm_ReleaseSCache(wlRequest->scp);
6165 smb_FreePacket(wlRequest->inp);
6166 smb_FreePacket(wlRequest->outp);
6175 if (wlRequest != NULL) {
6177 lock_ObtainWrite(&smb_globalLock);
6178 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
6180 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
6181 lock_ReleaseWrite(&smb_globalLock);
6183 /* don't send reply immediately */
6184 outp->flags |= SMB_PACKETFLAG_NOSEND;
6187 smb_SetSMBDataLength(outp, 0);
6191 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
6194 lock_ReleaseWrite(&scp->rw);
6195 cm_ReleaseSCache(scp);
6196 cm_ReleaseUser(userp);
6197 smb_ReleaseFID(fidp);
6202 /* SMB_COM_QUERY_INFORMATION2 */
6203 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6209 afs_uint32 searchTime;
6216 fid = smb_GetSMBParm(inp, 0);
6217 fid = smb_ChainFID(fid, inp);
6219 fidp = smb_FindFID(vcp, fid, 0);
6221 return CM_ERROR_BADFD;
6223 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6224 smb_CloseFID(vcp, fidp, NULL, 0);
6225 smb_ReleaseFID(fidp);
6226 return CM_ERROR_NOSUCHFILE;
6229 lock_ObtainMutex(&fidp->mx);
6230 if (fidp->flags & SMB_FID_IOCTL) {
6231 lock_ReleaseMutex(&fidp->mx);
6232 smb_ReleaseFID(fidp);
6233 return CM_ERROR_BADFD;
6236 osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6238 lock_ReleaseMutex(&fidp->mx);
6240 userp = smb_GetUserFromVCP(vcp, inp);
6243 /* otherwise, stat the file */
6244 lock_ObtainWrite(&scp->rw);
6245 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6246 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6250 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6252 lock_ConvertWToR(&scp->rw);
6255 /* decode times. We need a search time, but the response to this
6256 * call provides the date first, not the time, as returned in the
6257 * searchTime variable. So we take the high-order bits first.
6259 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
6260 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
6261 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
6262 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
6263 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
6264 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
6265 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
6267 /* now handle file size and allocation size */
6268 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
6269 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
6270 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
6271 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
6273 /* file attribute */
6274 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
6276 /* and finalize stuff */
6277 smb_SetSMBDataLength(outp, 0);
6282 lock_ReleaseRead(&scp->rw);
6284 lock_ReleaseWrite(&scp->rw);
6285 cm_ReleaseSCache(scp);
6286 cm_ReleaseUser(userp);
6287 smb_ReleaseFID(fidp);
6291 /* SMB_COM_SET_INFORMATION2 */
6292 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6298 afs_uint32 searchTime;
6306 fid = smb_GetSMBParm(inp, 0);
6307 fid = smb_ChainFID(fid, inp);
6309 fidp = smb_FindFID(vcp, fid, 0);
6311 return CM_ERROR_BADFD;
6313 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6314 smb_CloseFID(vcp, fidp, NULL, 0);
6315 smb_ReleaseFID(fidp);
6316 return CM_ERROR_NOSUCHFILE;
6319 lock_ObtainMutex(&fidp->mx);
6320 if (fidp->flags & SMB_FID_IOCTL) {
6321 lock_ReleaseMutex(&fidp->mx);
6322 smb_ReleaseFID(fidp);
6323 return CM_ERROR_BADFD;
6326 osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6328 lock_ReleaseMutex(&fidp->mx);
6330 userp = smb_GetUserFromVCP(vcp, inp);
6333 /* now prepare to call cm_setattr. This message only sets various times,
6334 * and AFS only implements mtime, and we'll set the mtime if that's
6335 * requested. The others we'll ignore.
6337 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
6339 if (searchTime != 0) {
6340 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
6342 if ( unixTime != -1 ) {
6343 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
6344 attrs.clientModTime = unixTime;
6345 code = cm_SetAttr(scp, &attrs, userp, &req);
6347 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
6349 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
6355 cm_ReleaseSCache(scp);
6356 cm_ReleaseUser(userp);
6357 smb_ReleaseFID(fidp);
6361 /* SMB_COM_WRITE_ANDX */
6362 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6365 long count, written = 0, total_written = 0;
6369 smb_t *smbp = (smb_t*) inp;
6373 int inDataBlockCount;
6375 fd = smb_GetSMBParm(inp, 2);
6376 count = smb_GetSMBParm(inp, 10);
6378 offset.HighPart = 0;
6379 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6381 if (*inp->wctp == 14) {
6382 /* we have a request with 64-bit file offsets */
6383 #ifdef AFS_LARGEFILES
6384 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6386 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6388 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
6389 /* we shouldn't have received this op if we didn't specify
6390 largefile support */
6391 return CM_ERROR_BADOP;
6396 op = inp->data + smb_GetSMBParm(inp, 11);
6397 inDataBlockCount = count;
6399 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
6400 fd, offset.HighPart, offset.LowPart, count);
6402 fd = smb_ChainFID(fd, inp);
6403 fidp = smb_FindFID(vcp, fd, 0);
6405 return CM_ERROR_BADFD;
6407 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6408 smb_CloseFID(vcp, fidp, NULL, 0);
6409 smb_ReleaseFID(fidp);
6410 return CM_ERROR_NOSUCHFILE;
6413 lock_ObtainMutex(&fidp->mx);
6414 if (fidp->flags & SMB_FID_IOCTL) {
6415 lock_ReleaseMutex(&fidp->mx);
6416 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
6417 smb_ReleaseFID(fidp);
6420 lock_ReleaseMutex(&fidp->mx);
6421 userp = smb_GetUserFromVCP(vcp, inp);
6423 /* special case: 0 bytes transferred means there is no data
6424 transferred. A slight departure from SMB_COM_WRITE where this
6425 means that we are supposed to truncate the file at this
6430 LARGE_INTEGER LOffset;
6431 LARGE_INTEGER LLength;
6435 key = cm_GenerateKey(vcp->vcID, pid, fd);
6437 LOffset.HighPart = offset.HighPart;
6438 LOffset.LowPart = offset.LowPart;
6439 LLength.HighPart = 0;
6440 LLength.LowPart = count;
6443 lock_ObtainWrite(&scp->rw);
6444 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
6445 lock_ReleaseWrite(&scp->rw);
6452 * Work around bug in NT client
6454 * When copying a file, the NT client should first copy the data,
6455 * then copy the last write time. But sometimes the NT client does
6456 * these in the wrong order, so the data copies would inadvertently
6457 * cause the last write time to be overwritten. We try to detect this,
6458 * and don't set client mod time if we think that would go against the
6461 lock_ObtainMutex(&fidp->mx);
6462 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6463 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6464 fidp->scp->clientModTime = time(NULL);
6466 lock_ReleaseMutex(&fidp->mx);
6469 while ( code == 0 && count > 0 ) {
6470 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6471 if (code == 0 && written == 0)
6472 code = CM_ERROR_PARTIALWRITE;
6474 offset = LargeIntegerAdd(offset,
6475 ConvertLongToLargeInteger(written));
6477 total_written += written;
6481 /* slots 0 and 1 are reserved for request chaining and will be
6482 filled in when we return. */
6483 smb_SetSMBParm(outp, 2, total_written);
6484 smb_SetSMBParm(outp, 3, 0); /* reserved */
6485 smb_SetSMBParm(outp, 4, 0); /* reserved */
6486 smb_SetSMBParm(outp, 5, 0); /* reserved */
6487 smb_SetSMBDataLength(outp, 0);
6490 cm_ReleaseUser(userp);
6491 smb_ReleaseFID(fidp);
6496 /* SMB_COM_READ_ANDX */
6497 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6501 long finalCount = 0;
6505 smb_t *smbp = (smb_t*) inp;
6511 fd = smb_GetSMBParm(inp, 2);
6512 count = smb_GetSMBParm(inp, 5);
6513 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6515 if (*inp->wctp == 12) {
6516 /* a request with 64-bit offsets */
6517 #ifdef AFS_LARGEFILES
6518 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
6520 if (LargeIntegerLessThanZero(offset)) {
6521 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
6522 offset.HighPart, offset.LowPart);
6523 return CM_ERROR_BADSMB;
6526 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
6527 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
6528 return CM_ERROR_BADSMB;
6530 offset.HighPart = 0;
6534 offset.HighPart = 0;
6537 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
6538 fd, offset.HighPart, offset.LowPart, count);
6540 fd = smb_ChainFID(fd, inp);
6541 fidp = smb_FindFID(vcp, fd, 0);
6543 return CM_ERROR_BADFD;
6546 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6547 smb_CloseFID(vcp, fidp, NULL, 0);
6548 smb_ReleaseFID(fidp);
6549 return CM_ERROR_NOSUCHFILE;
6553 key = cm_GenerateKey(vcp->vcID, pid, fd);
6555 LARGE_INTEGER LOffset, LLength;
6558 LOffset.HighPart = offset.HighPart;
6559 LOffset.LowPart = offset.LowPart;
6560 LLength.HighPart = 0;
6561 LLength.LowPart = count;
6564 lock_ObtainWrite(&scp->rw);
6565 code = cm_LockCheckRead(scp, LOffset, LLength, key);
6566 lock_ReleaseWrite(&scp->rw);
6570 smb_ReleaseFID(fidp);
6574 /* set inp->fid so that later read calls in same msg can find fid */
6577 lock_ObtainMutex(&fidp->mx);
6578 if (fidp->flags & SMB_FID_IOCTL) {
6579 lock_ReleaseMutex(&fidp->mx);
6580 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
6581 smb_ReleaseFID(fidp);
6584 lock_ReleaseMutex(&fidp->mx);
6586 userp = smb_GetUserFromVCP(vcp, inp);
6588 /* 0 and 1 are reserved for request chaining, were setup by our caller,
6589 * and will be further filled in after we return.
6591 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
6592 smb_SetSMBParm(outp, 3, 0); /* resvd */
6593 smb_SetSMBParm(outp, 4, 0); /* resvd */
6594 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
6595 /* fill in #6 when we have all the parameters' space reserved */
6596 smb_SetSMBParm(outp, 7, 0); /* resv'd */
6597 smb_SetSMBParm(outp, 8, 0); /* resv'd */
6598 smb_SetSMBParm(outp, 9, 0); /* resv'd */
6599 smb_SetSMBParm(outp, 10, 0); /* resv'd */
6600 smb_SetSMBParm(outp, 11, 0); /* reserved */
6602 /* get op ptr after putting in the parms, since otherwise we don't
6603 * know where the data really is.
6605 op = smb_GetSMBData(outp, NULL);
6607 /* now fill in offset from start of SMB header to first data byte (to op) */
6608 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
6610 /* set the packet data length the count of the # of bytes */
6611 smb_SetSMBDataLength(outp, count);
6613 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6615 /* fix some things up */
6616 smb_SetSMBParm(outp, 5, finalCount);
6617 smb_SetSMBDataLength(outp, finalCount);
6619 cm_ReleaseUser(userp);
6620 smb_ReleaseFID(fidp);
6625 * Values for createDisp, copied from NTDDK.H
6627 #define FILE_SUPERSEDE 0 // (???)
6628 #define FILE_OPEN 1 // (open)
6629 #define FILE_CREATE 2 // (exclusive)
6630 #define FILE_OPEN_IF 3 // (non-exclusive)
6631 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
6632 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
6635 #define REQUEST_OPLOCK 2
6636 #define REQUEST_BATCH_OPLOCK 4
6637 #define OPEN_DIRECTORY 8
6638 #define EXTENDED_RESPONSE_REQUIRED 0x10
6640 /* CreateOptions field. */
6641 #define FILE_DIRECTORY_FILE 0x0001
6642 #define FILE_WRITE_THROUGH 0x0002
6643 #define FILE_SEQUENTIAL_ONLY 0x0004
6644 #define FILE_NON_DIRECTORY_FILE 0x0040
6645 #define FILE_NO_EA_KNOWLEDGE 0x0200
6646 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
6647 #define FILE_RANDOM_ACCESS 0x0800
6648 #define FILE_DELETE_ON_CLOSE 0x1000
6649 #define FILE_OPEN_BY_FILE_ID 0x2000
6651 /* SMB_COM_NT_CREATE_ANDX */
6652 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6654 clientchar_t *pathp, *realPathp;
6658 cm_scache_t *dscp; /* parent dir */
6659 cm_scache_t *scp; /* file to create or open */
6660 cm_scache_t *targetScp; /* if scp is a symlink */
6662 clientchar_t *lastNamep;
6663 clientchar_t *treeStartp;
6664 unsigned short nameLength;
6666 unsigned int requestOpLock;
6667 unsigned int requestBatchOpLock;
6668 unsigned int mustBeDir;
6669 unsigned int extendedRespRequired;
6670 unsigned int treeCreate;
6672 unsigned int desiredAccess;
6673 unsigned int extAttributes;
6674 unsigned int createDisp;
6675 unsigned int createOptions;
6676 unsigned int shareAccess;
6677 int initialModeBits;
6678 unsigned short baseFid;
6679 smb_fid_t *baseFidp;
6681 cm_scache_t *baseDirp;
6682 unsigned short openAction;
6687 clientchar_t *tidPathp;
6691 cm_lock_data_t *ldp = NULL;
6695 /* This code is very long and has a lot of if-then-else clauses
6696 * scp and dscp get reused frequently and we need to ensure that
6697 * we don't lose a reference. Start by ensuring that they are NULL.
6704 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
6705 flags = smb_GetSMBOffsetParm(inp, 3, 1)
6706 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
6707 requestOpLock = flags & REQUEST_OPLOCK;
6708 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6709 mustBeDir = flags & OPEN_DIRECTORY;
6710 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6713 * Why all of a sudden 32-bit FID?
6714 * We will reject all bits higher than 16.
6716 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
6717 return CM_ERROR_INVAL;
6718 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
6719 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
6720 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6721 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
6722 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
6723 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
6724 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
6725 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
6726 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
6727 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
6728 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
6730 /* mustBeDir is never set; createOptions directory bit seems to be
6733 if (createOptions & FILE_DIRECTORY_FILE)
6735 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6741 * compute initial mode bits based on read-only flag in
6742 * extended attributes
6744 initialModeBits = 0666;
6745 if (extAttributes & SMB_ATTR_READONLY)
6746 initialModeBits &= ~0222;
6748 pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
6749 NULL, SMB_STRF_ANSIPATH);
6751 /* Sometimes path is not null-terminated, so we make a copy. */
6752 realPathp = malloc(nameLength+sizeof(clientchar_t));
6753 memcpy(realPathp, pathp, nameLength+sizeof(clientchar_t));
6754 realPathp[nameLength/sizeof(clientchar_t)] = 0;
6756 spacep = inp->spacep;
6757 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
6759 osi_Log1(smb_logp,"NTCreateX for [%S]",osi_LogSaveClientString(smb_logp,realPathp));
6760 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
6761 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%S]", shareAccess, flags, osi_LogSaveClientString(smb_logp,(lastNamep?lastNamep:_C("null"))));
6764 (cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
6765 cm_ClientStrCmpIA(lastNamep, _C("\\srvsvc")) == 0 ||
6766 cm_ClientStrCmpIA(lastNamep, _C("\\wkssvc")) == 0 ||
6767 cm_ClientStrCmpIA(lastNamep, _C("ipc$")) == 0)) {
6768 /* special case magic file name for receiving IOCTL requests
6769 * (since IOCTL calls themselves aren't getting through).
6771 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6772 smb_SetupIoctlFid(fidp, spacep);
6773 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
6775 /* set inp->fid so that later read calls in same msg can find fid */
6776 inp->fid = fidp->fid;
6780 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6781 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6782 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
6784 memset(&ft, 0, sizeof(ft));
6785 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6786 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6787 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6788 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6789 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
6790 sz.HighPart = 0x7fff; sz.LowPart = 0;
6791 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
6792 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
6793 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6794 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6795 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
6796 smb_SetSMBDataLength(outp, 0);
6798 /* clean up fid reference */
6799 smb_ReleaseFID(fidp);
6804 #ifdef DEBUG_VERBOSE
6806 char *hexp, *asciip;
6807 asciip = (lastNamep? lastNamep : realPathp);
6808 hexp = osi_HexifyString( asciip );
6809 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
6814 userp = smb_GetUserFromVCP(vcp, inp);
6816 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
6818 return CM_ERROR_INVAL;
6823 baseDirp = cm_data.rootSCachep;
6824 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6825 if (code == CM_ERROR_TIDIPC) {
6826 /* Attempt to use a TID allocated for IPC. The client
6827 * is probably looking for DCE RPC end points which we
6828 * don't support OR it could be looking to make a DFS
6831 osi_Log0(smb_logp, "NTCreateX received IPC TID");
6834 cm_ReleaseUser(userp);
6835 return CM_ERROR_NOSUCHFILE;
6836 #endif /* DFS_SUPPORT */
6839 baseFidp = smb_FindFID(vcp, baseFid, 0);
6841 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
6843 cm_ReleaseUser(userp);
6844 return CM_ERROR_INVAL;
6847 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6849 cm_ReleaseUser(userp);
6850 smb_CloseFID(vcp, baseFidp, NULL, 0);
6851 smb_ReleaseFID(baseFidp);
6852 return CM_ERROR_NOSUCHPATH;
6855 baseDirp = baseFidp->scp;
6859 osi_Log1(smb_logp, "NTCreateX tidPathp=[%S]", (tidPathp==NULL)?_C("null"): osi_LogSaveClientString(smb_logp,tidPathp));
6861 /* compute open mode */
6863 if (desiredAccess & DELETE)
6864 fidflags |= SMB_FID_OPENDELETE;
6865 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
6866 fidflags |= SMB_FID_OPENREAD_LISTDIR;
6867 if (desiredAccess & AFS_ACCESS_WRITE)
6868 fidflags |= SMB_FID_OPENWRITE;
6869 if (createOptions & FILE_DELETE_ON_CLOSE)
6870 fidflags |= SMB_FID_DELONCLOSE;
6871 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6872 fidflags |= SMB_FID_SEQUENTIAL;
6873 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6874 fidflags |= SMB_FID_RANDOM;
6875 if (smb_IsExecutableFileName(lastNamep))
6876 fidflags |= SMB_FID_EXECUTABLE;
6878 /* and the share mode */
6879 if (shareAccess & FILE_SHARE_READ)
6880 fidflags |= SMB_FID_SHARE_READ;
6881 if (shareAccess & FILE_SHARE_WRITE)
6882 fidflags |= SMB_FID_SHARE_WRITE;
6884 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
6887 /* For an exclusive create, we want to do a case sensitive match for the last component. */
6888 if ( createDisp == FILE_CREATE ||
6889 createDisp == FILE_OVERWRITE ||
6890 createDisp == FILE_OVERWRITE_IF) {
6891 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6892 userp, tidPathp, &req, &dscp);
6895 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6896 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
6898 cm_ReleaseSCache(dscp);
6899 cm_ReleaseUser(userp);
6902 smb_ReleaseFID(baseFidp);
6903 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6904 return CM_ERROR_PATH_NOT_COVERED;
6906 return CM_ERROR_BADSHARENAME;
6908 #endif /* DFS_SUPPORT */
6909 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6911 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
6912 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6913 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6914 if (code == 0 && realDirFlag == 1) {
6915 cm_ReleaseSCache(scp);
6916 cm_ReleaseSCache(dscp);
6917 cm_ReleaseUser(userp);
6920 smb_ReleaseFID(baseFidp);
6921 return CM_ERROR_EXISTS;
6925 /* we have both scp and dscp */
6927 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6928 userp, tidPathp, &req, &scp);
6930 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6931 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
6932 cm_ReleaseSCache(scp);
6933 cm_ReleaseUser(userp);
6936 smb_ReleaseFID(baseFidp);
6937 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6938 return CM_ERROR_PATH_NOT_COVERED;
6940 return CM_ERROR_BADSHARENAME;
6942 #endif /* DFS_SUPPORT */
6943 /* we might have scp but not dscp */
6949 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6950 /* look up parent directory */
6951 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
6952 * the immediate parent. We have to work our way up realPathp until we hit something that we
6956 /* we might or might not have scp */
6962 code = cm_NameI(baseDirp, spacep->wdata,
6963 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6964 userp, tidPathp, &req, &dscp);
6967 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6968 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
6971 cm_ReleaseSCache(scp);
6972 cm_ReleaseSCache(dscp);
6973 cm_ReleaseUser(userp);
6976 smb_ReleaseFID(baseFidp);
6977 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6978 return CM_ERROR_PATH_NOT_COVERED;
6980 return CM_ERROR_BADSHARENAME;
6982 #endif /* DFS_SUPPORT */
6985 (tp = cm_ClientStrRChr(spacep->wdata, '\\')) &&
6986 (createDisp == FILE_CREATE) &&
6987 (realDirFlag == 1)) {
6990 treeStartp = realPathp + (tp - spacep->wdata);
6992 if (*tp && !smb_IsLegalFilename(tp)) {
6993 cm_ReleaseUser(userp);
6995 smb_ReleaseFID(baseFidp);
6998 cm_ReleaseSCache(scp);
6999 return CM_ERROR_BADNTFILENAME;
7003 } while (dscp == NULL && code == 0);
7007 /* we might have scp and we might have dscp */
7010 smb_ReleaseFID(baseFidp);
7013 osi_Log0(smb_logp,"NTCreateX parent not found");
7015 cm_ReleaseSCache(scp);
7017 cm_ReleaseSCache(dscp);
7018 cm_ReleaseUser(userp);
7023 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
7024 /* A file exists where we want a directory. */
7026 cm_ReleaseSCache(scp);
7027 cm_ReleaseSCache(dscp);
7028 cm_ReleaseUser(userp);
7030 return CM_ERROR_EXISTS;
7034 lastNamep = realPathp;
7038 if (!smb_IsLegalFilename(lastNamep)) {
7040 cm_ReleaseSCache(scp);
7042 cm_ReleaseSCache(dscp);
7043 cm_ReleaseUser(userp);
7045 return CM_ERROR_BADNTFILENAME;
7048 if (!foundscp && !treeCreate) {
7049 if ( createDisp == FILE_CREATE ||
7050 createDisp == FILE_OVERWRITE ||
7051 createDisp == FILE_OVERWRITE_IF)
7053 code = cm_Lookup(dscp, lastNamep,
7054 CM_FLAG_FOLLOW, userp, &req, &scp);
7056 code = cm_Lookup(dscp, lastNamep,
7057 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7060 if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
7062 cm_ReleaseSCache(dscp);
7063 cm_ReleaseUser(userp);
7068 /* we have scp and dscp */
7070 /* we have scp but not dscp */
7072 smb_ReleaseFID(baseFidp);
7075 /* if we get here, if code is 0, the file exists and is represented by
7076 * scp. Otherwise, we have to create it. The dir may be represented
7077 * by dscp, or we may have found the file directly. If code is non-zero,
7080 if (code == 0 && !treeCreate) {
7081 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7084 cm_ReleaseSCache(dscp);
7086 cm_ReleaseSCache(scp);
7087 cm_ReleaseUser(userp);
7092 if (createDisp == FILE_CREATE) {
7093 /* oops, file shouldn't be there */
7094 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7096 cm_ReleaseSCache(dscp);
7098 cm_ReleaseSCache(scp);
7099 cm_ReleaseUser(userp);
7101 return CM_ERROR_EXISTS;
7104 if ( createDisp == FILE_OVERWRITE ||
7105 createDisp == FILE_OVERWRITE_IF) {
7107 setAttr.mask = CM_ATTRMASK_LENGTH;
7108 setAttr.length.LowPart = 0;
7109 setAttr.length.HighPart = 0;
7110 /* now watch for a symlink */
7112 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7114 osi_assertx(dscp != NULL, "null cm_scache_t");
7115 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7117 /* we have a more accurate file to use (the
7118 * target of the symbolic link). Otherwise,
7119 * we'll just use the symlink anyway.
7121 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7123 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7124 cm_ReleaseSCache(scp);
7126 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7129 cm_ReleaseSCache(dscp);
7131 cm_ReleaseSCache(scp);
7132 cm_ReleaseUser(userp);
7138 code = cm_SetAttr(scp, &setAttr, userp, &req);
7139 openAction = 3; /* truncated existing file */
7142 openAction = 1; /* found existing file */
7144 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7145 /* don't create if not found */
7147 cm_ReleaseSCache(dscp);
7149 cm_ReleaseSCache(scp);
7150 cm_ReleaseUser(userp);
7152 return CM_ERROR_NOSUCHFILE;
7153 } else if (realDirFlag == 0 || realDirFlag == -1) {
7154 osi_assertx(dscp != NULL, "null cm_scache_t");
7155 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %S",
7156 osi_LogSaveClientString(smb_logp, lastNamep));
7157 openAction = 2; /* created file */
7158 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7159 setAttr.clientModTime = time(NULL);
7160 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
7163 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7164 smb_NotifyChange(FILE_ACTION_ADDED,
7165 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7166 dscp, lastNamep, NULL, TRUE);
7167 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7168 /* Not an exclusive create, and someone else tried
7169 * creating it already, then we open it anyway. We
7170 * don't bother retrying after this, since if this next
7171 * fails, that means that the file was deleted after we
7172 * started this call.
7174 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7177 if (createDisp == FILE_OVERWRITE_IF) {
7178 setAttr.mask = CM_ATTRMASK_LENGTH;
7179 setAttr.length.LowPart = 0;
7180 setAttr.length.HighPart = 0;
7182 /* now watch for a symlink */
7184 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7186 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7188 /* we have a more accurate file to use (the
7189 * target of the symbolic link). Otherwise,
7190 * we'll just use the symlink anyway.
7192 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7194 cm_ReleaseSCache(scp);
7198 code = cm_SetAttr(scp, &setAttr, userp, &req);
7200 } /* lookup succeeded */
7203 clientchar_t *tp, *pp;
7204 clientchar_t *cp; /* This component */
7205 int clen = 0; /* length of component */
7206 cm_scache_t *tscp1, *tscp2;
7209 /* create directory */
7211 treeStartp = lastNamep;
7212 osi_assertx(dscp != NULL, "null cm_scache_t");
7213 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%S]",
7214 osi_LogSaveClientString(smb_logp, treeStartp));
7215 openAction = 2; /* created directory */
7217 /* if the request is to create the root directory
7218 * it will appear as a directory name of the nul-string
7219 * and a code of CM_ERROR_NOSUCHFILE
7221 if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
7222 code = CM_ERROR_EXISTS;
7224 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7225 setAttr.clientModTime = time(NULL);
7230 cm_HoldSCache(tscp1);
7234 tp = cm_ClientStrChr(pp, '\\');
7236 cm_ClientStrCpy(cp, lengthof(spacep->wdata) - (cp - spacep->wdata), pp);
7237 clen = (int)cm_ClientStrLen(cp);
7238 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
7240 clen = (int)(tp - pp);
7241 cm_ClientStrCpyN(cp, lengthof(spacep->wdata) - (cp - spacep->wdata),
7249 continue; /* the supplied path can't have consecutive slashes either , but */
7251 /* cp is the next component to be created. */
7252 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req, NULL);
7253 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
7254 smb_NotifyChange(FILE_ACTION_ADDED,
7255 FILE_NOTIFY_CHANGE_DIR_NAME,
7256 tscp1, cp, NULL, TRUE);
7258 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7259 /* Not an exclusive create, and someone else tried
7260 * creating it already, then we open it anyway. We
7261 * don't bother retrying after this, since if this next
7262 * fails, that means that the file was deleted after we
7263 * started this call.
7265 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
7266 userp, &req, &tscp2);
7271 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
7272 cm_ReleaseSCache(tscp1);
7273 tscp1 = tscp2; /* Newly created directory will be next parent */
7274 /* the hold is transfered to tscp1 from tscp2 */
7279 cm_ReleaseSCache(dscp);
7282 cm_ReleaseSCache(scp);
7285 * if we get here and code == 0, then scp is the last directory created, and dscp is the
7291 /* something went wrong creating or truncating the file */
7293 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7295 cm_ReleaseSCache(scp);
7297 cm_ReleaseSCache(dscp);
7298 cm_ReleaseUser(userp);
7303 /* make sure we have file vs. dir right (only applies for single component case) */
7304 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7305 /* now watch for a symlink */
7307 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7308 cm_scache_t * targetScp = 0;
7309 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7311 /* we have a more accurate file to use (the
7312 * target of the symbolic link). Otherwise,
7313 * we'll just use the symlink anyway.
7315 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
7317 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7318 cm_ReleaseSCache(scp);
7323 if (scp->fileType != CM_SCACHETYPE_FILE) {
7325 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7327 cm_ReleaseSCache(dscp);
7328 cm_ReleaseSCache(scp);
7329 cm_ReleaseUser(userp);
7331 return CM_ERROR_ISDIR;
7335 /* (only applies to single component case) */
7336 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7338 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7339 cm_ReleaseSCache(scp);
7341 cm_ReleaseSCache(dscp);
7342 cm_ReleaseUser(userp);
7344 return CM_ERROR_NOTDIR;
7347 /* open the file itself */
7348 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7349 osi_assertx(fidp, "null smb_fid_t");
7351 /* save a reference to the user */
7353 fidp->userp = userp;
7355 /* If we are restricting sharing, we should do so with a suitable
7357 if (scp->fileType == CM_SCACHETYPE_FILE &&
7358 !(fidflags & SMB_FID_SHARE_WRITE)) {
7360 LARGE_INTEGER LOffset, LLength;
7363 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7364 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7365 LLength.HighPart = 0;
7366 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7368 /* If we are not opening the file for writing, then we don't
7369 try to get an exclusive lock. No one else should be able to
7370 get an exclusive lock on the file anyway, although someone
7371 else can get a shared lock. */
7372 if ((fidflags & SMB_FID_SHARE_READ) ||
7373 !(fidflags & SMB_FID_OPENWRITE)) {
7374 sLockType = LOCKING_ANDX_SHARED_LOCK;
7379 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7381 lock_ObtainWrite(&scp->rw);
7382 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7383 lock_ReleaseWrite(&scp->rw);
7387 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7388 cm_ReleaseSCache(scp);
7390 cm_ReleaseSCache(dscp);
7391 cm_ReleaseUser(userp);
7392 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7393 smb_CloseFID(vcp, fidp, NULL, 0);
7394 smb_ReleaseFID(fidp);
7400 /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
7402 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7404 lock_ObtainMutex(&fidp->mx);
7405 /* save a pointer to the vnode */
7406 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
7407 lock_ObtainWrite(&scp->rw);
7408 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7409 lock_ReleaseWrite(&scp->rw);
7410 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
7412 fidp->flags = fidflags;
7414 /* remember if the file was newly created */
7416 fidp->flags |= SMB_FID_CREATED;
7418 /* save parent dir and pathname for delete or change notification */
7419 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7420 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
7421 fidp->flags |= SMB_FID_NTOPEN;
7422 fidp->NTopen_dscp = dscp;
7424 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
7426 fidp->NTopen_wholepathp = realPathp;
7427 lock_ReleaseMutex(&fidp->mx);
7429 /* we don't need this any longer */
7431 cm_ReleaseSCache(dscp);
7435 cm_Open(scp, 0, userp);
7437 /* set inp->fid so that later read calls in same msg can find fid */
7438 inp->fid = fidp->fid;
7442 lock_ObtainRead(&scp->rw);
7443 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7444 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7445 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7446 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7447 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7448 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7449 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7450 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7451 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7453 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7454 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7455 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
7456 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
7457 smb_SetSMBParmByte(outp, parmSlot,
7458 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7459 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7460 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7461 smb_SetSMBDataLength(outp, 0);
7463 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
7464 LargeIntegerGreaterThanZero(fidp->scp->length) &&
7465 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
7466 cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
7467 fidp->scp->length.LowPart, fidp->scp->length.HighPart,
7470 lock_ReleaseRead(&scp->rw);
7472 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %S", fidp->fid,
7473 osi_LogSaveClientString(smb_logp, realPathp));
7475 cm_ReleaseUser(userp);
7476 smb_ReleaseFID(fidp);
7478 /* Can't free realPathp if we get here since
7479 fidp->NTopen_wholepathp is pointing there */
7481 /* leave scp held since we put it in fidp->scp */
7486 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
7487 * Instead, ultimately, would like to use a subroutine for common code.
7490 /* NT_TRANSACT_CREATE (SMB_COM_NT_TRANSACT) */
7491 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7493 clientchar_t *pathp, *realPathp;
7497 cm_scache_t *dscp; /* parent dir */
7498 cm_scache_t *scp; /* file to create or open */
7499 cm_scache_t *targetScp; /* if scp is a symlink */
7501 clientchar_t *lastNamep;
7502 unsigned long nameLength;
7504 unsigned int requestOpLock;
7505 unsigned int requestBatchOpLock;
7506 unsigned int mustBeDir;
7507 unsigned int extendedRespRequired;
7509 unsigned int desiredAccess;
7510 unsigned int allocSize;
7511 unsigned int shareAccess;
7512 unsigned int extAttributes;
7513 unsigned int createDisp;
7516 unsigned int impLevel;
7517 unsigned int secFlags;
7518 unsigned int createOptions;
7519 int initialModeBits;
7520 unsigned short baseFid;
7521 smb_fid_t *baseFidp;
7523 cm_scache_t *baseDirp;
7524 unsigned short openAction;
7528 clientchar_t *tidPathp;
7530 int parmOffset, dataOffset;
7536 cm_lock_data_t *ldp = NULL;
7543 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7544 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7545 parmp = inp->data + parmOffset;
7546 lparmp = (ULONG *) parmp;
7549 requestOpLock = flags & REQUEST_OPLOCK;
7550 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7551 mustBeDir = flags & OPEN_DIRECTORY;
7552 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7555 * Why all of a sudden 32-bit FID?
7556 * We will reject all bits higher than 16.
7558 if (lparmp[1] & 0xFFFF0000)
7559 return CM_ERROR_INVAL;
7560 baseFid = (unsigned short)lparmp[1];
7561 desiredAccess = lparmp[2];
7562 allocSize = lparmp[3];
7563 extAttributes = lparmp[5];
7564 shareAccess = lparmp[6];
7565 createDisp = lparmp[7];
7566 createOptions = lparmp[8];
7569 nameLength = lparmp[11]; /* spec says chars but appears to be bytes */
7570 impLevel = lparmp[12];
7571 secFlags = lparmp[13];
7573 /* mustBeDir is never set; createOptions directory bit seems to be
7576 if (createOptions & FILE_DIRECTORY_FILE)
7578 else if (createOptions & FILE_NON_DIRECTORY_FILE)
7584 * compute initial mode bits based on read-only flag in
7585 * extended attributes
7587 initialModeBits = 0666;
7588 if (extAttributes & SMB_ATTR_READONLY)
7589 initialModeBits &= ~0222;
7591 pathp = smb_ParseStringCb(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
7592 nameLength, NULL, SMB_STRF_ANSIPATH);
7593 /* Sometimes path is not nul-terminated, so we make a copy. */
7594 realPathp = malloc(nameLength+sizeof(clientchar_t));
7595 memcpy(realPathp, pathp, nameLength);
7596 realPathp[nameLength/sizeof(clientchar_t)] = 0;
7597 spacep = cm_GetSpace();
7598 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
7600 osi_Log1(smb_logp,"NTTranCreate %S",osi_LogSaveStringW(smb_logp,realPathp));
7601 osi_Log4(smb_logp,"... da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
7602 osi_Log4(smb_logp,"... co[%x],sdl[%x],eal[%x],as[%x],flags[%x]",createOptions,sdLen,eaLen,allocSize);
7603 osi_Log3(smb_logp,"... imp[%x],sec[%x],flags[%x]", impLevel, secFlags, flags);
7606 * Nothing here to handle SMB_IOCTL_FILENAME.
7607 * Will add it if necessary.
7610 #ifdef DEBUG_VERBOSE
7612 char *hexp, *asciip;
7613 asciip = (lastNamep? lastNamep : realPathp);
7614 hexp = osi_HexifyString( asciip );
7615 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
7620 userp = smb_GetUserFromVCP(vcp, inp);
7622 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
7624 return CM_ERROR_INVAL;
7629 baseDirp = cm_data.rootSCachep;
7630 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7631 if (code == CM_ERROR_TIDIPC) {
7632 /* Attempt to use a TID allocated for IPC. The client
7633 * is probably looking for DCE RPC end points which we
7634 * don't support OR it could be looking to make a DFS
7637 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
7640 cm_ReleaseUser(userp);
7641 return CM_ERROR_NOSUCHPATH;
7645 baseFidp = smb_FindFID(vcp, baseFid, 0);
7647 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
7649 cm_ReleaseUser(userp);
7650 return CM_ERROR_BADFD;
7653 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7655 cm_ReleaseUser(userp);
7656 smb_CloseFID(vcp, baseFidp, NULL, 0);
7657 smb_ReleaseFID(baseFidp);
7658 return CM_ERROR_NOSUCHPATH;
7661 baseDirp = baseFidp->scp;
7665 /* compute open mode */
7667 if (desiredAccess & DELETE)
7668 fidflags |= SMB_FID_OPENDELETE;
7669 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
7670 fidflags |= SMB_FID_OPENREAD_LISTDIR;
7671 if (desiredAccess & AFS_ACCESS_WRITE)
7672 fidflags |= SMB_FID_OPENWRITE;
7673 if (createOptions & FILE_DELETE_ON_CLOSE)
7674 fidflags |= SMB_FID_DELONCLOSE;
7675 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7676 fidflags |= SMB_FID_SEQUENTIAL;
7677 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7678 fidflags |= SMB_FID_RANDOM;
7679 if (smb_IsExecutableFileName(lastNamep))
7680 fidflags |= SMB_FID_EXECUTABLE;
7682 /* And the share mode */
7683 if (shareAccess & FILE_SHARE_READ)
7684 fidflags |= SMB_FID_SHARE_READ;
7685 if (shareAccess & FILE_SHARE_WRITE)
7686 fidflags |= SMB_FID_SHARE_WRITE;
7690 if ( createDisp == FILE_OPEN ||
7691 createDisp == FILE_OVERWRITE ||
7692 createDisp == FILE_OVERWRITE_IF) {
7693 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7694 userp, tidPathp, &req, &dscp);
7697 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7698 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7699 cm_ReleaseSCache(dscp);
7700 cm_ReleaseUser(userp);
7703 smb_ReleaseFID(baseFidp);
7704 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7705 return CM_ERROR_PATH_NOT_COVERED;
7707 return CM_ERROR_BADSHARENAME;
7709 #endif /* DFS_SUPPORT */
7710 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7712 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7713 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7714 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7715 if (code == 0 && realDirFlag == 1) {
7716 cm_ReleaseSCache(scp);
7717 cm_ReleaseSCache(dscp);
7718 cm_ReleaseUser(userp);
7721 smb_ReleaseFID(baseFidp);
7722 return CM_ERROR_EXISTS;
7728 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7729 userp, tidPathp, &req, &scp);
7731 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7732 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7733 cm_ReleaseSCache(scp);
7734 cm_ReleaseUser(userp);
7737 smb_ReleaseFID(baseFidp);
7738 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7739 return CM_ERROR_PATH_NOT_COVERED;
7741 return CM_ERROR_BADSHARENAME;
7743 #endif /* DFS_SUPPORT */
7749 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7750 /* look up parent directory */
7752 code = cm_NameI(baseDirp, spacep->wdata,
7753 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7754 userp, tidPathp, &req, &dscp);
7756 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7757 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7758 cm_ReleaseSCache(dscp);
7759 cm_ReleaseUser(userp);
7762 smb_ReleaseFID(baseFidp);
7763 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7764 return CM_ERROR_PATH_NOT_COVERED;
7766 return CM_ERROR_BADSHARENAME;
7768 #endif /* DFS_SUPPORT */
7772 cm_FreeSpace(spacep);
7775 smb_ReleaseFID(baseFidp);
7778 cm_ReleaseUser(userp);
7784 lastNamep = realPathp;
7788 if (!smb_IsLegalFilename(lastNamep))
7789 return CM_ERROR_BADNTFILENAME;
7792 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
7793 code = cm_Lookup(dscp, lastNamep,
7794 CM_FLAG_FOLLOW, userp, &req, &scp);
7796 code = cm_Lookup(dscp, lastNamep,
7797 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7800 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7801 cm_ReleaseSCache(dscp);
7802 cm_ReleaseUser(userp);
7809 smb_ReleaseFID(baseFidp);
7810 cm_FreeSpace(spacep);
7813 /* if we get here, if code is 0, the file exists and is represented by
7814 * scp. Otherwise, we have to create it. The dir may be represented
7815 * by dscp, or we may have found the file directly. If code is non-zero,
7819 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7822 cm_ReleaseSCache(dscp);
7823 cm_ReleaseSCache(scp);
7824 cm_ReleaseUser(userp);
7829 if (createDisp == FILE_CREATE) {
7830 /* oops, file shouldn't be there */
7831 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7833 cm_ReleaseSCache(dscp);
7834 cm_ReleaseSCache(scp);
7835 cm_ReleaseUser(userp);
7837 return CM_ERROR_EXISTS;
7840 if (createDisp == FILE_OVERWRITE ||
7841 createDisp == FILE_OVERWRITE_IF) {
7842 setAttr.mask = CM_ATTRMASK_LENGTH;
7843 setAttr.length.LowPart = 0;
7844 setAttr.length.HighPart = 0;
7846 /* now watch for a symlink */
7848 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7850 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7852 /* we have a more accurate file to use (the
7853 * target of the symbolic link). Otherwise,
7854 * we'll just use the symlink anyway.
7856 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7858 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7859 cm_ReleaseSCache(scp);
7861 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7864 cm_ReleaseSCache(dscp);
7866 cm_ReleaseSCache(scp);
7867 cm_ReleaseUser(userp);
7873 code = cm_SetAttr(scp, &setAttr, userp, &req);
7874 openAction = 3; /* truncated existing file */
7876 else openAction = 1; /* found existing file */
7878 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7879 /* don't create if not found */
7881 cm_ReleaseSCache(dscp);
7882 cm_ReleaseUser(userp);
7884 return CM_ERROR_NOSUCHFILE;
7886 else if (realDirFlag == 0 || realDirFlag == -1) {
7887 osi_assertx(dscp != NULL, "null cm_scache_t");
7888 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %S",
7889 osi_LogSaveClientString(smb_logp, lastNamep));
7890 openAction = 2; /* created file */
7891 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7892 setAttr.clientModTime = time(NULL);
7893 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7897 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7898 smb_NotifyChange(FILE_ACTION_ADDED,
7899 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7900 dscp, lastNamep, NULL, TRUE);
7901 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7902 /* Not an exclusive create, and someone else tried
7903 * creating it already, then we open it anyway. We
7904 * don't bother retrying after this, since if this next
7905 * fails, that means that the file was deleted after we
7906 * started this call.
7908 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7911 if (createDisp == FILE_OVERWRITE_IF) {
7912 setAttr.mask = CM_ATTRMASK_LENGTH;
7913 setAttr.length.LowPart = 0;
7914 setAttr.length.HighPart = 0;
7916 /* now watch for a symlink */
7918 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7920 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7922 /* we have a more accurate file to use (the
7923 * target of the symbolic link). Otherwise,
7924 * we'll just use the symlink anyway.
7926 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7928 cm_ReleaseSCache(scp);
7932 code = cm_SetAttr(scp, &setAttr, userp, &req);
7934 } /* lookup succeeded */
7937 /* create directory */
7938 osi_assertx(dscp != NULL, "null cm_scache_t");
7940 "smb_ReceiveNTTranCreate creating directory %S",
7941 osi_LogSaveClientString(smb_logp, lastNamep));
7942 openAction = 2; /* created directory */
7943 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7944 setAttr.clientModTime = time(NULL);
7945 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
7946 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7947 smb_NotifyChange(FILE_ACTION_ADDED,
7948 FILE_NOTIFY_CHANGE_DIR_NAME,
7949 dscp, lastNamep, NULL, TRUE);
7951 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7952 /* Not an exclusive create, and someone else tried
7953 * creating it already, then we open it anyway. We
7954 * don't bother retrying after this, since if this next
7955 * fails, that means that the file was deleted after we
7956 * started this call.
7958 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7964 /* something went wrong creating or truncating the file */
7966 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7968 cm_ReleaseSCache(scp);
7969 cm_ReleaseUser(userp);
7974 /* make sure we have file vs. dir right */
7975 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7976 /* now watch for a symlink */
7978 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7980 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7982 /* we have a more accurate file to use (the
7983 * target of the symbolic link). Otherwise,
7984 * we'll just use the symlink anyway.
7986 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7989 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7990 cm_ReleaseSCache(scp);
7995 if (scp->fileType != CM_SCACHETYPE_FILE) {
7997 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7998 cm_ReleaseSCache(scp);
7999 cm_ReleaseUser(userp);
8001 return CM_ERROR_ISDIR;
8005 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8007 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8008 cm_ReleaseSCache(scp);
8009 cm_ReleaseUser(userp);
8011 return CM_ERROR_NOTDIR;
8014 /* open the file itself */
8015 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8016 osi_assertx(fidp, "null smb_fid_t");
8018 /* save a reference to the user */
8020 fidp->userp = userp;
8022 /* If we are restricting sharing, we should do so with a suitable
8024 if (scp->fileType == CM_SCACHETYPE_FILE &&
8025 !(fidflags & SMB_FID_SHARE_WRITE)) {
8027 LARGE_INTEGER LOffset, LLength;
8030 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8031 LOffset.LowPart = SMB_FID_QLOCK_LOW;
8032 LLength.HighPart = 0;
8033 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8035 /* Similar to what we do in handling NTCreateX. We get a
8036 shared lock if we are only opening the file for reading. */
8037 if ((fidflags & SMB_FID_SHARE_READ) ||
8038 !(fidflags & SMB_FID_OPENWRITE)) {
8039 sLockType = LOCKING_ANDX_SHARED_LOCK;
8044 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8046 lock_ObtainWrite(&scp->rw);
8047 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8048 lock_ReleaseWrite(&scp->rw);
8052 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8053 cm_ReleaseSCache(scp);
8054 cm_ReleaseUser(userp);
8055 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
8056 smb_CloseFID(vcp, fidp, NULL, 0);
8057 smb_ReleaseFID(fidp);
8059 return CM_ERROR_SHARING_VIOLATION;
8063 /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
8065 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8067 lock_ObtainMutex(&fidp->mx);
8068 /* save a pointer to the vnode */
8070 lock_ObtainWrite(&scp->rw);
8071 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8072 lock_ReleaseWrite(&scp->rw);
8073 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
8075 fidp->flags = fidflags;
8077 /* remember if the file was newly created */
8079 fidp->flags |= SMB_FID_CREATED;
8081 /* save parent dir and pathname for deletion or change notification */
8082 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8083 fidp->flags |= SMB_FID_NTOPEN;
8084 fidp->NTopen_dscp = dscp;
8085 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
8087 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
8089 fidp->NTopen_wholepathp = realPathp;
8090 lock_ReleaseMutex(&fidp->mx);
8092 /* we don't need this any longer */
8094 cm_ReleaseSCache(dscp);
8096 cm_Open(scp, 0, userp);
8098 /* set inp->fid so that later read calls in same msg can find fid */
8099 inp->fid = fidp->fid;
8101 /* check whether we are required to send an extended response */
8102 if (!extendedRespRequired) {
8104 parmOffset = 8*4 + 39;
8105 parmOffset += 1; /* pad to 4 */
8106 dataOffset = parmOffset + 70;
8110 /* Total Parameter Count */
8111 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8112 /* Total Data Count */
8113 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8114 /* Parameter Count */
8115 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8116 /* Parameter Offset */
8117 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8118 /* Parameter Displacement */
8119 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8121 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8123 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8124 /* Data Displacement */
8125 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8126 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8127 smb_SetSMBDataLength(outp, 70);
8129 lock_ObtainRead(&scp->rw);
8130 outData = smb_GetSMBData(outp, NULL);
8131 outData++; /* round to get to parmOffset */
8132 *outData = 0; outData++; /* oplock */
8133 *outData = 0; outData++; /* reserved */
8134 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8135 *((ULONG *)outData) = openAction; outData += 4;
8136 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8137 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8138 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8139 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8140 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8141 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8142 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8143 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8144 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8145 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8146 *((USHORT *)outData) = 0; outData += 2; /* dev state */
8147 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8148 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8149 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8150 outData += 2; /* is a dir? */
8153 parmOffset = 8*4 + 39;
8154 parmOffset += 1; /* pad to 4 */
8155 dataOffset = parmOffset + 104;
8159 /* Total Parameter Count */
8160 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8161 /* Total Data Count */
8162 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8163 /* Parameter Count */
8164 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8165 /* Parameter Offset */
8166 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8167 /* Parameter Displacement */
8168 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8170 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8172 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8173 /* Data Displacement */
8174 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8175 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8176 smb_SetSMBDataLength(outp, 105);
8178 lock_ObtainRead(&scp->rw);
8179 outData = smb_GetSMBData(outp, NULL);
8180 outData++; /* round to get to parmOffset */
8181 *outData = 0; outData++; /* oplock */
8182 *outData = 1; outData++; /* response type */
8183 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8184 *((ULONG *)outData) = openAction; outData += 4;
8185 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8186 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8187 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8188 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8189 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8190 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8191 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8192 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8193 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8194 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8195 *((USHORT *)outData) = 0; outData += 2; /* dev state */
8196 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8197 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8198 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8199 outData += 1; /* is a dir? */
8200 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
8201 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
8202 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
8205 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
8206 LargeIntegerGreaterThanZero(fidp->scp->length) &&
8207 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
8208 cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
8209 fidp->scp->length.LowPart, fidp->scp->length.HighPart,
8212 lock_ReleaseRead(&scp->rw);
8214 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
8216 cm_ReleaseUser(userp);
8217 smb_ReleaseFID(fidp);
8219 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
8220 /* leave scp held since we put it in fidp->scp */
8224 /* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
8225 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
8228 smb_packet_t *savedPacketp;
8230 USHORT fid, watchtree;
8234 filter = smb_GetSMBParm(inp, 19) |
8235 (smb_GetSMBParm(inp, 20) << 16);
8236 fid = smb_GetSMBParm(inp, 21);
8237 watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
8239 fidp = smb_FindFID(vcp, fid, 0);
8241 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
8242 return CM_ERROR_BADFD;
8245 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8246 smb_CloseFID(vcp, fidp, NULL, 0);
8247 smb_ReleaseFID(fidp);
8248 return CM_ERROR_NOSUCHFILE;
8251 /* Create a copy of the Directory Watch Packet to use when sending the
8252 * notification if in the future a matching change is detected.
8254 savedPacketp = smb_CopyPacket(inp);
8255 if (vcp != savedPacketp->vcp) {
8257 if (savedPacketp->vcp)
8258 smb_ReleaseVC(savedPacketp->vcp);
8259 savedPacketp->vcp = vcp;
8262 /* Add the watch to the list of events to send notifications for */
8263 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8264 savedPacketp->nextp = smb_Directory_Watches;
8265 smb_Directory_Watches = savedPacketp;
8266 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8269 osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%S\"",
8270 fidp, scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp));
8271 osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
8272 filter, fid, watchtree);
8273 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8274 osi_Log0(smb_logp, " Notify Change File Name");
8275 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8276 osi_Log0(smb_logp, " Notify Change Directory Name");
8277 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8278 osi_Log0(smb_logp, " Notify Change Attributes");
8279 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8280 osi_Log0(smb_logp, " Notify Change Size");
8281 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8282 osi_Log0(smb_logp, " Notify Change Last Write");
8283 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8284 osi_Log0(smb_logp, " Notify Change Last Access");
8285 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8286 osi_Log0(smb_logp, " Notify Change Creation");
8287 if (filter & FILE_NOTIFY_CHANGE_EA)
8288 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8289 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8290 osi_Log0(smb_logp, " Notify Change Security");
8291 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8292 osi_Log0(smb_logp, " Notify Change Stream Name");
8293 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8294 osi_Log0(smb_logp, " Notify Change Stream Size");
8295 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8296 osi_Log0(smb_logp, " Notify Change Stream Write");
8298 lock_ObtainWrite(&scp->rw);
8300 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
8302 scp->flags |= CM_SCACHEFLAG_WATCHED;
8303 lock_ReleaseWrite(&scp->rw);
8304 smb_ReleaseFID(fidp);
8306 outp->flags |= SMB_PACKETFLAG_NOSEND;
8310 unsigned char nullSecurityDesc[36] = {
8311 0x01, /* security descriptor revision */
8312 0x00, /* reserved, should be zero */
8313 0x00, 0x80, /* security descriptor control;
8314 * 0x8000 : self-relative format */
8315 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
8316 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
8317 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
8318 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
8319 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8320 /* "null SID" owner SID */
8321 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
8322 /* "null SID" group SID */
8325 /* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
8326 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8328 int parmOffset, parmCount, dataOffset, dataCount;
8336 ULONG securityInformation;
8338 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8339 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8340 parmp = inp->data + parmOffset;
8341 sparmp = (USHORT *) parmp;
8342 lparmp = (ULONG *) parmp;
8345 securityInformation = lparmp[1];
8347 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
8348 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
8356 parmOffset = 8*4 + 39;
8357 parmOffset += 1; /* pad to 4 */
8359 dataOffset = parmOffset + parmCount;
8363 /* Total Parameter Count */
8364 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8365 /* Total Data Count */
8366 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8367 /* Parameter Count */
8368 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8369 /* Parameter Offset */
8370 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8371 /* Parameter Displacement */
8372 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8374 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8376 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8377 /* Data Displacement */
8378 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8379 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8380 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
8382 outData = smb_GetSMBData(outp, NULL);
8383 outData++; /* round to get to parmOffset */
8384 *((ULONG *)outData) = 36; outData += 4; /* length */
8386 if (maxData >= 36) {
8387 memcpy(outData, nullSecurityDesc, 36);
8391 return CM_ERROR_BUFFERTOOSMALL;
8394 /* SMB_COM_NT_TRANSACT
8396 SMB_COM_NT_TRANSACT_SECONDARY should also be handled here.
8398 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8400 unsigned short function;
8402 function = smb_GetSMBParm(inp, 18);
8404 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
8406 /* We can handle long names */
8407 if (vcp->flags & SMB_VCFLAG_USENT)
8408 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
8411 case 1: /* NT_TRANSACT_CREATE */
8412 return smb_ReceiveNTTranCreate(vcp, inp, outp);
8413 case 2: /* NT_TRANSACT_IOCTL */
8414 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
8416 case 3: /* NT_TRANSACT_SET_SECURITY_DESC */
8417 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
8419 case 4: /* NT_TRANSACT_NOTIFY_CHANGE */
8420 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
8421 case 5: /* NT_TRANSACT_RENAME */
8422 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
8424 case 6: /* NT_TRANSACT_QUERY_SECURITY_DESC */
8425 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
8427 osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
8430 osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
8433 return CM_ERROR_INVAL;
8437 * smb_NotifyChange -- find relevant change notification messages and
8440 * If we don't know the file name (i.e. a callback break), filename is
8441 * NULL, and we return a zero-length list.
8443 * At present there is not a single call to smb_NotifyChange that
8444 * has the isDirectParent parameter set to FALSE.
8446 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
8447 cm_scache_t *dscp, clientchar_t *filename, clientchar_t *otherFilename,
8448 BOOL isDirectParent)
8450 smb_packet_t *watch, *lastWatch, *nextWatch;
8451 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen = 0;
8452 char *outData, *oldOutData;
8456 BOOL twoEntries = FALSE;
8457 ULONG otherNameLen, oldParmCount = 0;
8461 /* Get ready for rename within directory */
8462 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
8464 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
8467 osi_Log4(smb_logp,"in smb_NotifyChange for file [%S] dscp [%p] notification 0x%x parent %d",
8468 osi_LogSaveClientString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
8470 osi_Log0(smb_logp," FILE_ACTION_NONE");
8471 if (action == FILE_ACTION_ADDED)
8472 osi_Log0(smb_logp," FILE_ACTION_ADDED");
8473 if (action == FILE_ACTION_REMOVED)
8474 osi_Log0(smb_logp," FILE_ACTION_REMOVED");
8475 if (action == FILE_ACTION_MODIFIED)
8476 osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
8477 if (action == FILE_ACTION_RENAMED_OLD_NAME)
8478 osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
8479 if (action == FILE_ACTION_RENAMED_NEW_NAME)
8480 osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
8482 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8483 watch = smb_Directory_Watches;
8485 filter = smb_GetSMBParm(watch, 19)
8486 | (smb_GetSMBParm(watch, 20) << 16);
8487 fid = smb_GetSMBParm(watch, 21);
8488 wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
8490 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
8491 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
8494 * Strange hack - bug in NT Client and NT Server that we must emulate?
8496 if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
8497 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
8499 fidp = smb_FindFID(watch->vcp, fid, 0);
8501 osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
8503 watch = watch->nextp;
8507 if (fidp->scp != dscp ||
8508 fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
8509 (filter & notifyFilter) == 0 ||
8510 (!isDirectParent && !wtree))
8512 osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
8514 watch = watch->nextp;
8515 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8516 smb_ReleaseFID(fidp);
8517 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8522 "Sending Change Notification for fid %d filter 0x%x wtree %d file %S",
8523 fid, filter, wtree, osi_LogSaveClientString(smb_logp, filename));
8524 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8525 osi_Log0(smb_logp, " Notify Change File Name");
8526 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8527 osi_Log0(smb_logp, " Notify Change Directory Name");
8528 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8529 osi_Log0(smb_logp, " Notify Change Attributes");
8530 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8531 osi_Log0(smb_logp, " Notify Change Size");
8532 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8533 osi_Log0(smb_logp, " Notify Change Last Write");
8534 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8535 osi_Log0(smb_logp, " Notify Change Last Access");
8536 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8537 osi_Log0(smb_logp, " Notify Change Creation");
8538 if (filter & FILE_NOTIFY_CHANGE_EA)
8539 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8540 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8541 osi_Log0(smb_logp, " Notify Change Security");
8542 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8543 osi_Log0(smb_logp, " Notify Change Stream Name");
8544 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8545 osi_Log0(smb_logp, " Notify Change Stream Size");
8546 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8547 osi_Log0(smb_logp, " Notify Change Stream Write");
8549 /* A watch can only be notified once. Remove it from the list */
8550 nextWatch = watch->nextp;
8551 if (watch == smb_Directory_Watches)
8552 smb_Directory_Watches = nextWatch;
8554 lastWatch->nextp = nextWatch;
8556 /* The watch is off the list, its ours now, safe to drop the lock */
8557 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8559 /* Turn off WATCHED flag in dscp */
8560 lock_ObtainWrite(&dscp->rw);
8562 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8564 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
8565 lock_ReleaseWrite(&dscp->rw);
8567 /* Convert to response packet */
8568 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
8569 #ifdef SEND_CANONICAL_PATHNAMES
8570 ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
8572 ((smb_t *) watch)->wct = 0;
8575 if (filename == NULL) {
8578 nameLen = (ULONG)cm_ClientStrLen(filename);
8579 parmCount = 3*4 + nameLen*2;
8580 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8582 otherNameLen = (ULONG)cm_ClientStrLen(otherFilename);
8583 oldParmCount = parmCount;
8584 parmCount += 3*4 + otherNameLen*2;
8585 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8587 if (maxLen < parmCount)
8588 parmCount = 0; /* not enough room */
8590 parmOffset = 8*4 + 39;
8591 parmOffset += 1; /* pad to 4 */
8592 dataOffset = parmOffset + parmCount;
8596 /* Total Parameter Count */
8597 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8598 /* Total Data Count */
8599 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8600 /* Parameter Count */
8601 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8602 /* Parameter Offset */
8603 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
8604 /* Parameter Displacement */
8605 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8607 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8609 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
8610 /* Data Displacement */
8611 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8612 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
8613 smb_SetSMBDataLength(watch, parmCount + 1);
8615 if (parmCount != 0) {
8616 outData = smb_GetSMBData(watch, NULL);
8617 outData++; /* round to get to parmOffset */
8618 oldOutData = outData;
8619 *((DWORD *)outData) = oldParmCount; outData += 4;
8620 /* Next Entry Offset */
8621 *((DWORD *)outData) = action; outData += 4;
8623 *((DWORD *)outData) = nameLen*2; outData += 4;
8624 /* File Name Length */
8626 smb_UnparseString(watch, outData, filename, NULL, 0);
8630 outData = oldOutData + oldParmCount;
8631 *((DWORD *)outData) = 0; outData += 4;
8632 /* Next Entry Offset */
8633 *((DWORD *)outData) = otherAction; outData += 4;
8635 *((DWORD *)outData) = otherNameLen*2;
8636 outData += 4; /* File Name Length */
8637 smb_UnparseString(watch, outData, otherFilename, NULL, 0);
8642 * If filename is null, we don't know the cause of the
8643 * change notification. We return zero data (see above),
8644 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
8645 * (= 0x010C). We set the error code here by hand, without
8646 * modifying wct and bcc.
8648 if (filename == NULL) {
8649 ((smb_t *) watch)->rcls = 0x0C;
8650 ((smb_t *) watch)->reh = 0x01;
8651 ((smb_t *) watch)->errLow = 0;
8652 ((smb_t *) watch)->errHigh = 0;
8653 /* Set NT Status codes flag */
8654 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8657 smb_SendPacket(watch->vcp, watch);
8658 smb_FreePacket(watch);
8660 smb_ReleaseFID(fidp);
8661 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8664 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8667 /* SMB_COM_NT_CANCEL */
8668 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8670 unsigned char *replyWctp;
8671 smb_packet_t *watch, *lastWatch;
8672 USHORT fid, watchtree;
8676 osi_Log0(smb_logp, "SMB3 receive NT cancel");
8678 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8679 watch = smb_Directory_Watches;
8681 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
8682 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
8683 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
8684 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
8685 if (watch == smb_Directory_Watches)
8686 smb_Directory_Watches = watch->nextp;
8688 lastWatch->nextp = watch->nextp;
8689 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8691 /* Turn off WATCHED flag in scp */
8692 fid = smb_GetSMBParm(watch, 21);
8693 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
8695 if (vcp != watch->vcp)
8696 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
8699 fidp = smb_FindFID(vcp, fid, 0);
8701 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %S",
8703 (fidp ? osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp) :_C("")));
8706 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
8707 lock_ObtainWrite(&scp->rw);
8709 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8711 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
8712 lock_ReleaseWrite(&scp->rw);
8713 smb_ReleaseFID(fidp);
8715 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
8718 /* assume STATUS32; return 0xC0000120 (CANCELED) */
8719 replyWctp = watch->wctp;
8723 ((smb_t *)watch)->rcls = 0x20;
8724 ((smb_t *)watch)->reh = 0x1;
8725 ((smb_t *)watch)->errLow = 0;
8726 ((smb_t *)watch)->errHigh = 0xC0;
8727 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8728 smb_SendPacket(vcp, watch);
8729 smb_FreePacket(watch);
8733 watch = watch->nextp;
8735 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8741 * NT rename also does hard links.
8744 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
8745 #define RENAME_FLAG_HARD_LINK 0x103
8746 #define RENAME_FLAG_RENAME 0x104
8747 #define RENAME_FLAG_COPY 0x105
8749 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8751 clientchar_t *oldPathp, *newPathp;
8757 attrs = smb_GetSMBParm(inp, 0);
8758 rename_type = smb_GetSMBParm(inp, 1);
8760 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
8761 osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
8762 return CM_ERROR_NOACCESS;
8765 tp = smb_GetSMBData(inp, NULL);
8766 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
8767 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
8769 osi_Log3(smb_logp, "NTRename for [%S]->[%S] type [%s]",
8770 osi_LogSaveClientString(smb_logp, oldPathp),
8771 osi_LogSaveClientString(smb_logp, newPathp),
8772 ((rename_type==RENAME_FLAG_RENAME)?"rename":(rename_type==RENAME_FLAG_HARD_LINK)?"hardlink":"other"));
8774 if (rename_type == RENAME_FLAG_RENAME) {
8775 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
8776 } else if (rename_type == RENAME_FLAG_HARD_LINK) { /* RENAME_FLAG_HARD_LINK */
8777 code = smb_Link(vcp,inp,oldPathp,newPathp);
8779 code = CM_ERROR_BADOP;
8785 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock", LOCK_HIERARCHY_SMB_DIRWATCH);
8788 cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
8790 smb_username_t *unp;
8793 unp = smb_FindUserByName(usern, machine, flags);
8795 lock_ObtainMutex(&unp->mx);
8796 unp->userp = cm_NewUser();
8797 lock_ReleaseMutex(&unp->mx);
8798 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
8800 osi_Log2(smb_logp,"smb_FindCMUserByName Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
8804 smb_ReleaseUsername(unp);