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;
689 int maxBufferSize = 0;
693 /* Check for bad conns */
694 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
695 return CM_ERROR_REMOTECONN;
698 maxBufferSize = smb_GetSMBParm(inp, 2);
699 maxMpxCount = smb_GetSMBParm(inp, 3);
700 vcNumber = smb_GetSMBParm(inp, 4);
702 osi_Log3(smb_logp, "SESSION_SETUP_ANDX with MaxBufferSize=%d, MaxMpxCount=%d, VCNumber=%d",
703 maxBufferSize, maxMpxCount, vcNumber);
705 if (maxMpxCount > smb_maxMpxRequests) {
706 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_MPX_COUNT, maxMpxCount, smb_maxMpxRequests);
707 osi_Log2(smb_logp, "MaxMpxCount for client is too large (Client=%d, Server=%d)",
708 maxMpxCount, smb_maxMpxRequests);
711 if (maxBufferSize < SMB_PACKETSIZE) {
712 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_BUFFER_SIZE, maxBufferSize, SMB_PACKETSIZE);
713 osi_Log2(smb_logp, "MaxBufferSize for client is too small (Client=%d, Server=%d)",
714 maxBufferSize, SMB_PACKETSIZE);
718 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_RESET_ALL_VCS);
719 osi_Log0(smb_logp, "Resetting all VCs");
720 smb_MarkAllVCsDead(vcp);
723 if (vcp->flags & SMB_VCFLAG_USENT) {
724 if (smb_authType == SMB_AUTH_EXTENDED) {
725 /* extended authentication */
729 OutputDebugF(_C("NT Session Setup: Extended"));
731 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
732 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
735 secBlobInLength = smb_GetSMBParm(inp, 7);
736 secBlobIn = smb_GetSMBData(inp, NULL);
738 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
740 if (code == CM_ERROR_GSSCONTINUE) {
743 smb_SetSMBParm(outp, 2, 0);
744 smb_SetSMBParm(outp, 3, secBlobOutLength);
746 tp = smb_GetSMBData(outp, NULL);
747 if (secBlobOutLength) {
748 memcpy(tp, secBlobOut, secBlobOutLength);
750 tp += secBlobOutLength;
751 cb_data += secBlobOutLength;
753 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
754 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
755 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
757 smb_SetSMBDataLength(outp, cb_data);
760 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
762 unsigned ciPwdLength, csPwdLength;
764 clientchar_t *accountName;
765 clientchar_t *primaryDomain;
768 if (smb_authType == SMB_AUTH_NTLM)
769 OutputDebugF(_C("NT Session Setup: NTLM"));
771 OutputDebugF(_C("NT Session Setup: None"));
773 /* TODO: parse for extended auth as well */
774 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
775 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
777 tp = smb_GetSMBData(inp, &datalen);
779 OutputDebugF(_C("Session packet data size [%d]"),datalen);
786 accountName = smb_ParseString(inp, tp, &tp, 0);
787 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
789 OutputDebugF(_C("Account Name: %s"),accountName);
790 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
791 OutputDebugF(_C("Case Sensitive Password: %s"),
792 csPwd && csPwd[0] ? _C("yes") : _C("no"));
793 OutputDebugF(_C("Case Insensitive Password: %s"),
794 ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
796 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
797 /* shouldn't happen */
798 code = CM_ERROR_BADSMB;
799 goto after_read_packet;
802 /* capabilities are only valid for first session packet */
803 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
804 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
807 if (smb_authType == SMB_AUTH_NTLM) {
808 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
810 OutputDebugF(_C("LM authentication failed [%d]"), code);
812 OutputDebugF(_C("LM authentication succeeded"));
816 unsigned ciPwdLength;
818 clientchar_t *accountName;
819 clientchar_t *primaryDomain;
821 switch ( smb_authType ) {
822 case SMB_AUTH_EXTENDED:
823 OutputDebugF(_C("V3 Session Setup: Extended"));
826 OutputDebugF(_C("V3 Session Setup: NTLM"));
829 OutputDebugF(_C("V3 Session Setup: None"));
831 ciPwdLength = smb_GetSMBParm(inp, 7);
832 tp = smb_GetSMBData(inp, NULL);
836 accountName = smb_ParseString(inp, tp, &tp, 0);
837 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
839 OutputDebugF(_C("Account Name: %s"),accountName);
840 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
841 OutputDebugF(_C("Case Insensitive Password: %s"), ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
843 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
844 /* shouldn't happen */
845 code = CM_ERROR_BADSMB;
846 goto after_read_packet;
849 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
852 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
853 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
855 OutputDebugF(_C("LM authentication failed [%d]"), code);
857 OutputDebugF(_C("LM authentication succeeded"));
862 /* note down that we received a session setup X and set the capabilities flag */
863 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
864 lock_ObtainMutex(&vcp->mx);
865 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
866 /* for the moment we can only deal with NTSTATUS */
867 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
868 vcp->flags |= SMB_VCFLAG_STATUS32;
872 if ((caps & NTNEGOTIATE_CAPABILITY_UNICODE) && smb_UseUnicode) {
873 vcp->flags |= SMB_VCFLAG_USEUNICODE;
876 lock_ReleaseMutex(&vcp->mx);
879 /* code would be non-zero if there was an authentication failure.
880 Ideally we would like to invalidate the uid for this session or break
881 early to avoid accidently stealing someone else's tokens. */
887 OutputDebugF(_C("Received username=[%s]"), usern);
889 /* On Windows 2000, this function appears to be called more often than
890 it is expected to be called. This resulted in multiple smb_user_t
891 records existing all for the same user session which results in all
892 of the users tokens disappearing.
894 To avoid this problem, we look for an existing smb_user_t record
895 based on the users name, and use that one if we find it.
898 uidp = smb_FindUserByNameThisSession(vcp, usern);
899 if (uidp) { /* already there, so don't create a new one */
901 newUid = uidp->userID;
902 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
903 vcp->lana,vcp->lsn,newUid);
904 smb_ReleaseUID(uidp);
909 /* do a global search for the username/machine name pair */
910 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
911 lock_ObtainMutex(&unp->mx);
912 if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
913 /* clear the afslogon flag so that the tickets can now
914 * be freed when the refCount returns to zero.
916 unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
918 lock_ReleaseMutex(&unp->mx);
920 /* Create a new UID and cm_user_t structure */
923 userp = cm_NewUser();
924 cm_HoldUserVCRef(userp);
925 lock_ObtainMutex(&vcp->mx);
926 if (!vcp->uidCounter)
927 vcp->uidCounter++; /* handle unlikely wraparounds */
928 newUid = (cm_ClientStrLen(usern)==0)?0:vcp->uidCounter++;
929 lock_ReleaseMutex(&vcp->mx);
931 /* Create a new smb_user_t structure and connect them up */
932 lock_ObtainMutex(&unp->mx);
934 lock_ReleaseMutex(&unp->mx);
936 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
938 lock_ObtainMutex(&uidp->mx);
940 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
941 lock_ReleaseMutex(&uidp->mx);
942 smb_ReleaseUID(uidp);
946 /* Return UID to the client */
947 ((smb_t *)outp)->uid = newUid;
948 /* Also to the next chained message */
949 ((smb_t *)inp)->uid = newUid;
951 osi_Log3(smb_logp, "SMB3 session setup name %S creating ID %d%S",
952 osi_LogSaveClientString(smb_logp, usern), newUid,
953 osi_LogSaveClientString(smb_logp, s1));
955 smb_SetSMBParm(outp, 2, 0);
957 if (vcp->flags & SMB_VCFLAG_USENT) {
958 if (smb_authType == SMB_AUTH_EXTENDED) {
961 smb_SetSMBParm(outp, 3, secBlobOutLength);
963 tp = smb_GetSMBData(outp, NULL);
964 if (secBlobOutLength) {
965 memcpy(tp, secBlobOut, secBlobOutLength);
967 tp += secBlobOutLength;
968 cb_data += secBlobOutLength;
971 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
972 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
973 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
975 smb_SetSMBDataLength(outp, cb_data);
977 smb_SetSMBDataLength(outp, 0);
980 if (smb_authType == SMB_AUTH_EXTENDED) {
983 tp = smb_GetSMBData(outp, NULL);
985 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
986 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
987 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
989 smb_SetSMBDataLength(outp, cb_data);
991 smb_SetSMBDataLength(outp, 0);
998 /* SMB_COM_LOGOFF_ANDX */
999 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1003 /* find the tree and free it */
1004 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1006 smb_username_t * unp;
1008 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %S", uidp->userID,
1009 osi_LogSaveClientString(smb_logp, (uidp->unp) ? uidp->unp->name: _C(" ")));
1011 lock_ObtainMutex(&uidp->mx);
1012 uidp->flags |= SMB_USERFLAG_DELETE;
1014 * it doesn't get deleted right away
1015 * because the vcp points to it
1018 lock_ReleaseMutex(&uidp->mx);
1021 /* we can't do this. we get logoff messages prior to a session
1022 * disconnect even though it doesn't mean the user is logging out.
1023 * we need to create a new pioctl and EventLogoff handler to set
1024 * SMB_USERNAMEFLAG_LOGOFF.
1026 if (unp && smb_LogoffTokenTransfer) {
1027 lock_ObtainMutex(&unp->mx);
1028 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
1029 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
1030 lock_ReleaseMutex(&unp->mx);
1034 smb_ReleaseUID(uidp);
1037 osi_Log0(smb_logp, "SMB3 user logoffX");
1039 smb_SetSMBDataLength(outp, 0);
1043 #define SMB_SUPPORT_SEARCH_BITS 0x0001
1044 #define SMB_SHARE_IS_IN_DFS 0x0002
1046 /* SMB_COM_TREE_CONNECT_ANDX */
1047 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1050 smb_user_t *uidp = NULL;
1051 unsigned short newTid;
1052 clientchar_t shareName[AFSPATHMAX];
1053 clientchar_t *sharePath;
1056 clientchar_t *slashp;
1057 clientchar_t *pathp;
1058 clientchar_t *passwordp;
1059 clientchar_t *servicep;
1060 cm_user_t *userp = NULL;
1063 osi_Log0(smb_logp, "SMB3 receive tree connect");
1065 /* parse input parameters */
1066 tp = smb_GetSMBData(inp, NULL);
1067 passwordp = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1068 pathp = smb_ParseString(inp, tp, &tp, SMB_STRF_ANSIPATH);
1069 servicep = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1071 slashp = cm_ClientStrRChr(pathp, '\\');
1073 return CM_ERROR_BADSMB;
1075 cm_ClientStrCpy(shareName, lengthof(shareName), slashp+1);
1077 osi_Log3(smb_logp, "Tree connect pathp[%S] shareName[%S] service[%S]",
1078 osi_LogSaveClientString(smb_logp, pathp),
1079 osi_LogSaveClientString(smb_logp, shareName),
1080 osi_LogSaveClientString(smb_logp, servicep));
1082 if (cm_ClientStrCmp(servicep, _C("IPC")) == 0 ||
1083 cm_ClientStrCmp(shareName, _C("IPC$")) == 0) {
1085 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1088 return CM_ERROR_NOIPC;
1092 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1094 userp = smb_GetUserFromUID(uidp);
1096 lock_ObtainMutex(&vcp->mx);
1097 newTid = vcp->tidCounter++;
1098 lock_ReleaseMutex(&vcp->mx);
1100 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1103 if (!cm_ClientStrCmp(shareName, _C("*.")))
1104 cm_ClientStrCpy(shareName, lengthof(shareName), _C("all"));
1105 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1108 smb_ReleaseUID(uidp);
1109 smb_ReleaseTID(tidp, FALSE);
1110 return CM_ERROR_BADSHARENAME;
1113 if (vcp->flags & SMB_VCFLAG_USENT)
1115 int policy = smb_FindShareCSCPolicy(shareName);
1118 DWORD dwAdvertiseDFS = 0, dwSize = sizeof(DWORD);
1120 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1121 0, KEY_QUERY_VALUE, &parmKey);
1122 if (code == ERROR_SUCCESS) {
1123 code = RegQueryValueEx(parmKey, "AdvertiseDFS", NULL, NULL,
1124 (BYTE *)&dwAdvertiseDFS, &dwSize);
1125 if (code != ERROR_SUCCESS)
1127 RegCloseKey (parmKey);
1129 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1130 (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
1134 smb_SetSMBParm(outp, 2, 0);
1138 smb_ReleaseUID(uidp);
1140 lock_ObtainMutex(&tidp->mx);
1141 tidp->userp = userp;
1142 tidp->pathname = sharePath;
1144 tidp->flags |= SMB_TIDFLAG_IPC;
1145 lock_ReleaseMutex(&tidp->mx);
1146 smb_ReleaseTID(tidp, FALSE);
1148 ((smb_t *)outp)->tid = newTid;
1149 ((smb_t *)inp)->tid = newTid;
1150 tp = smb_GetSMBData(outp, NULL);
1154 tp = smb_UnparseString(outp, tp, _C("A:"), &cb_data, SMB_STRF_FORCEASCII);
1155 tp = smb_UnparseString(outp, tp, _C("AFS"), &cb_data, 0);
1156 smb_SetSMBDataLength(outp, cb_data);
1160 tp = smb_UnparseString(outp, tp, _C("IPC"), &cb_data, SMB_STRF_FORCEASCII);
1161 smb_SetSMBDataLength(outp, cb_data);
1164 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1168 /* must be called with global tran lock held */
1169 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1171 smb_tran2Packet_t *tp;
1174 smbp = (smb_t *) inp->data;
1175 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1176 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1182 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1183 int totalParms, int totalData)
1185 smb_tran2Packet_t *tp;
1188 smbp = (smb_t *) inp->data;
1189 tp = malloc(sizeof(*tp));
1190 memset(tp, 0, sizeof(*tp));
1193 tp->curData = tp->curParms = 0;
1194 tp->totalData = totalData;
1195 tp->totalParms = totalParms;
1196 tp->tid = smbp->tid;
1197 tp->mid = smbp->mid;
1198 tp->uid = smbp->uid;
1199 tp->pid = smbp->pid;
1200 tp->res[0] = smbp->res[0];
1201 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1202 if (totalParms != 0)
1203 tp->parmsp = malloc(totalParms);
1205 tp->datap = malloc(totalData);
1206 if (smbp->com == 0x25 || smbp->com == 0x26)
1209 tp->opcode = smb_GetSMBParm(inp, 14);
1212 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1214 if (WANTS_UNICODE(inp) && (vcp->flags & SMB_VCFLAG_USEUNICODE))
1215 tp->flags |= SMB_TRAN2PFLAG_USEUNICODE;
1220 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1221 smb_tran2Packet_t *inp, smb_packet_t *outp,
1222 int totalParms, int totalData)
1224 smb_tran2Packet_t *tp;
1225 unsigned short parmOffset;
1226 unsigned short dataOffset;
1227 unsigned short dataAlign;
1229 tp = malloc(sizeof(*tp));
1230 memset(tp, 0, sizeof(*tp));
1233 tp->curData = tp->curParms = 0;
1234 tp->totalData = totalData;
1235 tp->totalParms = totalParms;
1236 tp->oldTotalParms = totalParms;
1241 tp->res[0] = inp->res[0];
1242 tp->opcode = inp->opcode;
1246 * We calculate where the parameters and data will start.
1247 * This calculation must parallel the calculation in
1248 * smb_SendTran2Packet.
1251 parmOffset = 10*2 + 35;
1252 parmOffset++; /* round to even */
1253 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1255 dataOffset = parmOffset + totalParms;
1256 dataAlign = dataOffset & 2; /* quad-align */
1257 dataOffset += dataAlign;
1258 tp->datap = outp->data + dataOffset;
1263 /* free a tran2 packet */
1264 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1267 smb_ReleaseVC(t2p->vcp);
1270 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1276 while (t2p->stringsp) {
1280 t2p->stringsp = ns->nextp;
1286 clientchar_t *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
1287 char ** chainpp, int flags)
1292 if (!(p->flags & SMB_TRAN2PFLAG_USEUNICODE))
1293 flags |= SMB_STRF_FORCEASCII;
1296 cb = p->totalParms - (inp - (char *)p->parmsp);
1297 if (inp < (char *) p->parmsp ||
1298 inp >= ((char *) p->parmsp) + p->totalParms) {
1299 #ifdef DEBUG_UNICODE
1305 return smb_ParseStringBuf((unsigned char *) p->parmsp, &p->stringsp,
1306 inp, &cb, chainpp, flags);
1309 /* called with a VC, an input packet to respond to, and an error code.
1310 * sends an error response.
1312 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1313 smb_packet_t *tp, long code)
1316 unsigned short errCode;
1317 unsigned char errClass;
1318 unsigned long NTStatus;
1320 if (vcp->flags & SMB_VCFLAG_STATUS32)
1321 smb_MapNTError(code, &NTStatus);
1323 smb_MapCoreError(code, vcp, &errCode, &errClass);
1325 smb_FormatResponsePacket(vcp, NULL, tp);
1326 smbp = (smb_t *) tp;
1328 /* We can handle long names */
1329 if (vcp->flags & SMB_VCFLAG_USENT)
1330 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1332 /* now copy important fields from the tran 2 packet */
1333 smbp->com = t2p->com;
1334 smbp->tid = t2p->tid;
1335 smbp->mid = t2p->mid;
1336 smbp->pid = t2p->pid;
1337 smbp->uid = t2p->uid;
1338 smbp->res[0] = t2p->res[0];
1339 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1340 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1341 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1342 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1343 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1344 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1347 smbp->rcls = errClass;
1348 smbp->errLow = (unsigned char) (errCode & 0xff);
1349 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1353 smb_SendPacket(vcp, tp);
1356 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1359 unsigned short parmOffset;
1360 unsigned short dataOffset;
1361 unsigned short totalLength;
1362 unsigned short dataAlign;
1365 smb_FormatResponsePacket(vcp, NULL, tp);
1366 smbp = (smb_t *) tp;
1368 /* We can handle long names */
1369 if (vcp->flags & SMB_VCFLAG_USENT)
1370 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1372 /* now copy important fields from the tran 2 packet */
1373 smbp->com = t2p->com;
1374 smbp->tid = t2p->tid;
1375 smbp->mid = t2p->mid;
1376 smbp->pid = t2p->pid;
1377 smbp->uid = t2p->uid;
1378 smbp->res[0] = t2p->res[0];
1380 totalLength = 1 + t2p->totalData + t2p->totalParms;
1382 /* now add the core parameters (tran2 info) to the packet */
1383 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1384 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1385 smb_SetSMBParm(tp, 2, 0); /* reserved */
1386 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1387 parmOffset = 10*2 + 35; /* parm offset in packet */
1388 parmOffset++; /* round to even */
1389 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1390 * hdr, bcc and wct */
1391 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1392 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1393 dataOffset = parmOffset + t2p->oldTotalParms;
1394 dataAlign = dataOffset & 2; /* quad-align */
1395 dataOffset += dataAlign;
1396 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1397 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1398 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1401 datap = smb_GetSMBData(tp, NULL);
1402 *datap++ = 0; /* we rounded to even */
1404 totalLength += dataAlign;
1405 smb_SetSMBDataLength(tp, totalLength);
1407 /* next, send the datagram */
1408 smb_SendPacket(vcp, tp);
1412 /* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
1413 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1415 smb_tran2Packet_t *asp;
1428 /* We sometimes see 0 word count. What to do? */
1429 if (*inp->wctp == 0) {
1430 osi_Log0(smb_logp, "Transaction2 word count = 0");
1431 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1433 smb_SetSMBDataLength(outp, 0);
1434 smb_SendPacket(vcp, outp);
1438 totalParms = smb_GetSMBParm(inp, 0);
1439 totalData = smb_GetSMBParm(inp, 1);
1441 firstPacket = (inp->inCom == 0x25);
1443 /* find the packet we're reassembling */
1444 lock_ObtainWrite(&smb_globalLock);
1445 asp = smb_FindTran2Packet(vcp, inp);
1447 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1449 lock_ReleaseWrite(&smb_globalLock);
1451 /* now merge in this latest packet; start by looking up offsets */
1453 parmDisp = dataDisp = 0;
1454 parmOffset = smb_GetSMBParm(inp, 10);
1455 dataOffset = smb_GetSMBParm(inp, 12);
1456 parmCount = smb_GetSMBParm(inp, 9);
1457 dataCount = smb_GetSMBParm(inp, 11);
1458 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1459 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1461 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1462 totalData, dataCount, asp->maxReturnData);
1465 parmDisp = smb_GetSMBParm(inp, 4);
1466 parmOffset = smb_GetSMBParm(inp, 3);
1467 dataDisp = smb_GetSMBParm(inp, 7);
1468 dataOffset = smb_GetSMBParm(inp, 6);
1469 parmCount = smb_GetSMBParm(inp, 2);
1470 dataCount = smb_GetSMBParm(inp, 5);
1472 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1473 parmCount, dataCount);
1476 /* now copy the parms and data */
1477 if ( asp->totalParms > 0 && parmCount != 0 )
1479 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1481 if ( asp->totalData > 0 && dataCount != 0 ) {
1482 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1485 /* account for new bytes */
1486 asp->curData += dataCount;
1487 asp->curParms += parmCount;
1489 /* finally, if we're done, remove the packet from the queue and dispatch it */
1490 if (asp->totalParms > 0 &&
1491 asp->curParms > 0 &&
1492 asp->totalData <= asp->curData &&
1493 asp->totalParms <= asp->curParms) {
1494 /* we've received it all */
1495 lock_ObtainWrite(&smb_globalLock);
1496 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1497 lock_ReleaseWrite(&smb_globalLock);
1499 /* now dispatch it */
1500 rapOp = asp->parmsp[0];
1502 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1503 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1504 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1505 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
1508 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1509 code = CM_ERROR_BADOP;
1512 /* if an error is returned, we're supposed to send an error packet,
1513 * otherwise the dispatched function already did the data sending.
1514 * We give dispatched proc the responsibility since it knows how much
1515 * space to allocate.
1518 smb_SendTran2Error(vcp, asp, outp, code);
1521 /* free the input tran 2 packet */
1522 smb_FreeTran2Packet(asp);
1524 else if (firstPacket) {
1525 /* the first packet in a multi-packet request, we need to send an
1526 * ack to get more data.
1528 smb_SetSMBDataLength(outp, 0);
1529 smb_SendPacket(vcp, outp);
1535 /* ANSI versions. */
1537 #pragma pack(push, 1)
1539 typedef struct smb_rap_share_info_0 {
1540 BYTE shi0_netname[13];
1541 } smb_rap_share_info_0_t;
1543 typedef struct smb_rap_share_info_1 {
1544 BYTE shi1_netname[13];
1547 DWORD shi1_remark; /* char *shi1_remark; data offset */
1548 } smb_rap_share_info_1_t;
1550 typedef struct smb_rap_share_info_2 {
1551 BYTE shi2_netname[13];
1554 DWORD shi2_remark; /* char *shi2_remark; data offset */
1555 WORD shi2_permissions;
1557 WORD shi2_current_uses;
1558 DWORD shi2_path; /* char *shi2_path; data offset */
1559 WORD shi2_passwd[9];
1561 } smb_rap_share_info_2_t;
1563 #define SMB_RAP_MAX_SHARES 512
1565 typedef struct smb_rap_share_list {
1568 smb_rap_share_info_0_t * shares;
1569 } smb_rap_share_list_t;
1573 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1574 smb_rap_share_list_t * sp;
1576 if (dep->name[0] == '.' && (!dep->name[1] || (dep->name[1] == '.' && !dep->name[2])))
1577 return 0; /* skip over '.' and '..' */
1579 sp = (smb_rap_share_list_t *) vrockp;
1581 strncpy(sp->shares[sp->cShare].shi0_netname, dep->name, 12);
1582 sp->shares[sp->cShare].shi0_netname[12] = 0;
1586 if (sp->cShare >= sp->maxShares)
1587 return CM_ERROR_STOPNOW;
1592 /* RAP NetShareEnumRequest */
1593 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1595 smb_tran2Packet_t *outp;
1596 unsigned short * tp;
1600 int outParmsTotal; /* total parameter bytes */
1601 int outDataTotal; /* total data bytes */
1604 DWORD allSubmount = 0;
1606 DWORD nRegShares = 0;
1607 DWORD nSharesRet = 0;
1609 HKEY hkSubmount = NULL;
1610 smb_rap_share_info_1_t * shares;
1613 clientchar_t thisShare[AFSPATHMAX];
1617 smb_rap_share_list_t rootShares;
1622 tp = p->parmsp + 1; /* skip over function number (always 0) */
1625 clientchar_t * cdescp;
1627 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1628 if (cm_ClientStrCmp(cdescp, _C("WrLeh")))
1629 return CM_ERROR_INVAL;
1630 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1631 if (cm_ClientStrCmp(cdescp, _C("B13BWz")))
1632 return CM_ERROR_INVAL;
1638 if (infoLevel != 1) {
1639 return CM_ERROR_INVAL;
1642 /* We are supposed to use the same ASCII data structure even if
1643 Unicode is negotiated, which ultimately means that the share
1644 names that we return must be at most 13 characters in length,
1645 including the NULL terminator.
1647 The RAP specification states that shares with names longer than
1648 12 characters should not be included in the enumeration.
1649 However, since we support prefix cell references and since many
1650 cell names are going to exceed 12 characters, we lie and send
1651 the first 12 characters.
1654 /* first figure out how many shares there are */
1655 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1656 KEY_QUERY_VALUE, &hkParam);
1657 if (rv == ERROR_SUCCESS) {
1658 len = sizeof(allSubmount);
1659 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1660 (BYTE *) &allSubmount, &len);
1661 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1664 RegCloseKey (hkParam);
1667 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1668 0, KEY_QUERY_VALUE, &hkSubmount);
1669 if (rv == ERROR_SUCCESS) {
1670 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1671 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1672 if (rv != ERROR_SUCCESS)
1678 /* fetch the root shares */
1679 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1680 rootShares.cShare = 0;
1681 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1685 userp = smb_GetTran2User(vcp,p);
1687 thyper.HighPart = 0;
1690 cm_HoldSCache(cm_data.rootSCachep);
1691 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1692 cm_ReleaseSCache(cm_data.rootSCachep);
1694 cm_ReleaseUser(userp);
1696 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1698 #define REMARK_LEN 1
1699 outParmsTotal = 8; /* 4 dwords */
1700 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1701 if(outDataTotal > bufsize) {
1702 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1703 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1706 nSharesRet = nShares;
1709 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1711 /* now for the submounts */
1712 shares = (smb_rap_share_info_1_t *) outp->datap;
1713 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1715 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1718 StringCchCopyA(shares[cshare].shi1_netname,
1719 lengthof(shares[cshare].shi1_netname), "all" );
1720 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1721 /* type and pad are zero already */
1727 for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
1728 len = sizeof(thisShare);
1729 rv = RegEnumValueW(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
1730 if (rv == ERROR_SUCCESS &&
1731 cm_ClientStrLen(thisShare) &&
1732 (!allSubmount || cm_ClientStrCmpI(thisShare,_C("all")))) {
1733 cm_ClientStringToUtf8(thisShare, -1, shares[cshare].shi1_netname,
1734 lengthof( shares[cshare].shi1_netname ));
1735 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1736 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1741 nShares--; /* uncount key */
1744 RegCloseKey(hkSubmount);
1747 nonrootShares = cshare;
1749 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1750 /* in case there are collisions with submounts, submounts have
1752 for (j=0; j < nonrootShares; j++)
1753 if (!cm_stricmp_utf8(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1756 if (j < nonrootShares) {
1757 nShares--; /* uncount */
1761 StringCchCopyA(shares[cshare].shi1_netname, lengthof(shares[cshare].shi1_netname),
1762 rootShares.shares[i].shi0_netname);
1763 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1768 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1769 outp->parmsp[1] = 0;
1770 outp->parmsp[2] = cshare;
1771 outp->parmsp[3] = nShares;
1773 outp->totalData = (int)(cstrp - outp->datap);
1774 outp->totalParms = outParmsTotal;
1776 smb_SendTran2Packet(vcp, outp, op);
1777 smb_FreeTran2Packet(outp);
1779 free(rootShares.shares);
1784 /* RAP NetShareGetInfo */
1785 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1787 smb_tran2Packet_t *outp;
1788 unsigned short * tp;
1789 clientchar_t * shareName;
1790 BOOL shareFound = FALSE;
1791 unsigned short infoLevel;
1792 unsigned short bufsize;
1801 cm_scache_t *scp = NULL;
1807 tp = p->parmsp + 1; /* skip over function number (always 1) */
1810 clientchar_t * cdescp;
1812 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1813 if (cm_ClientStrCmp(cdescp, _C("zWrLh")))
1815 return CM_ERROR_INVAL;
1817 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1818 if (cm_ClientStrCmp(cdescp, _C("B13")) &&
1819 cm_ClientStrCmp(cdescp, _C("B13BWz")) &&
1820 cm_ClientStrCmp(cdescp, _C("B13BWzWWWzB9B")))
1822 return CM_ERROR_INVAL;
1824 shareName = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1832 totalData = sizeof(smb_rap_share_info_0_t);
1833 else if(infoLevel == SMB_INFO_STANDARD)
1834 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1835 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1836 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1838 return CM_ERROR_INVAL;
1840 if(!cm_ClientStrCmpI(shareName, _C("all")) || !cm_ClientStrCmp(shareName,_C("*."))) {
1841 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1842 KEY_QUERY_VALUE, &hkParam);
1843 if (rv == ERROR_SUCCESS) {
1844 len = sizeof(allSubmount);
1845 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1846 (BYTE *) &allSubmount, &len);
1847 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1850 RegCloseKey (hkParam);
1857 userp = smb_GetTran2User(vcp, p);
1859 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
1860 return CM_ERROR_BADSMB;
1862 code = cm_NameI(cm_data.rootSCachep, shareName,
1863 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
1864 userp, NULL, &req, &scp);
1866 cm_ReleaseSCache(scp);
1869 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1870 KEY_QUERY_VALUE, &hkSubmount);
1871 if (rv == ERROR_SUCCESS) {
1872 rv = RegQueryValueExW(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1873 if (rv == ERROR_SUCCESS) {
1876 RegCloseKey(hkSubmount);
1882 return CM_ERROR_BADSHARENAME;
1884 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1885 memset(outp->datap, 0, totalData);
1887 outp->parmsp[0] = 0;
1888 outp->parmsp[1] = 0;
1889 outp->parmsp[2] = totalData;
1891 if (infoLevel == 0) {
1892 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1893 cm_ClientStringToUtf8(shareName, -1, info->shi0_netname,
1894 lengthof(info->shi0_netname));
1895 } else if(infoLevel == SMB_INFO_STANDARD) {
1896 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1897 cm_ClientStringToUtf8(shareName, -1, info->shi1_netname, lengthof(info->shi1_netname));
1898 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1899 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1900 /* type and pad are already zero */
1901 } else { /* infoLevel==2 */
1902 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1903 cm_ClientStringToUtf8(shareName, -1, info->shi2_netname, lengthof(info->shi2_netname));
1904 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1905 info->shi2_permissions = ACCESS_ALL;
1906 info->shi2_max_uses = (unsigned short) -1;
1907 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
1910 outp->totalData = totalData;
1911 outp->totalParms = totalParam;
1913 smb_SendTran2Packet(vcp, outp, op);
1914 smb_FreeTran2Packet(outp);
1919 #pragma pack(push, 1)
1921 typedef struct smb_rap_wksta_info_10 {
1922 DWORD wki10_computername; /*char *wki10_computername;*/
1923 DWORD wki10_username; /* char *wki10_username; */
1924 DWORD wki10_langroup; /* char *wki10_langroup;*/
1925 BYTE wki10_ver_major;
1926 BYTE wki10_ver_minor;
1927 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1928 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1929 } smb_rap_wksta_info_10_t;
1933 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1935 smb_tran2Packet_t *outp;
1939 unsigned short * tp;
1942 smb_rap_wksta_info_10_t * info;
1946 tp = p->parmsp + 1; /* Skip over function number */
1949 clientchar_t * cdescp;
1951 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
1952 SMB_STRF_FORCEASCII);
1953 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
1954 return CM_ERROR_INVAL;
1956 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
1957 SMB_STRF_FORCEASCII);
1958 if (cm_ClientStrCmp(cdescp, _C("zzzBBzz")))
1959 return CM_ERROR_INVAL;
1965 if (infoLevel != 10) {
1966 return CM_ERROR_INVAL;
1972 totalData = sizeof(*info) + /* info */
1973 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1974 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1975 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1976 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1977 1; /* wki10_oth_domains (null)*/
1979 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1981 memset(outp->parmsp,0,totalParams);
1982 memset(outp->datap,0,totalData);
1984 info = (smb_rap_wksta_info_10_t *) outp->datap;
1985 cstrp = (char *) (info + 1);
1987 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1988 StringCbCopyA(cstrp, totalData, smb_localNamep);
1989 cstrp += strlen(cstrp) + 1;
1991 info->wki10_username = (DWORD) (cstrp - outp->datap);
1992 uidp = smb_FindUID(vcp, p->uid, 0);
1994 lock_ObtainMutex(&uidp->mx);
1995 if(uidp->unp && uidp->unp->name)
1996 cm_ClientStringToUtf8(uidp->unp->name, -1,
1997 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
1998 lock_ReleaseMutex(&uidp->mx);
1999 smb_ReleaseUID(uidp);
2001 cstrp += strlen(cstrp) + 1;
2003 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
2004 StringCbCopyA(cstrp, totalData - (cstrp - outp->datap)*sizeof(char), "WORKGROUP");
2005 cstrp += strlen(cstrp) + 1;
2007 /* TODO: Not sure what values these should take, but these work */
2008 info->wki10_ver_major = 5;
2009 info->wki10_ver_minor = 1;
2011 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
2012 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
2013 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2014 cstrp += strlen(cstrp) + 1;
2016 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
2017 cstrp ++; /* no other domains */
2019 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
2020 outp->parmsp[2] = outp->totalData;
2021 outp->totalParms = totalParams;
2023 smb_SendTran2Packet(vcp,outp,op);
2024 smb_FreeTran2Packet(outp);
2029 #pragma pack(push, 1)
2031 typedef struct smb_rap_server_info_0 {
2033 } smb_rap_server_info_0_t;
2035 typedef struct smb_rap_server_info_1 {
2037 BYTE sv1_version_major;
2038 BYTE sv1_version_minor;
2040 DWORD sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
2041 } smb_rap_server_info_1_t;
2045 char smb_ServerComment[] = "OpenAFS Client";
2046 int smb_ServerCommentLen = sizeof(smb_ServerComment);
2048 #define SMB_SV_TYPE_SERVER 0x00000002L
2049 #define SMB_SV_TYPE_NT 0x00001000L
2050 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
2052 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2054 smb_tran2Packet_t *outp;
2058 unsigned short * tp;
2061 smb_rap_server_info_0_t * info0;
2062 smb_rap_server_info_1_t * info1;
2065 tp = p->parmsp + 1; /* Skip over function number */
2068 clientchar_t * cdescp;
2070 cdescp = smb_ParseStringT2Parm(p, (unsigned char *) tp, (char **) &tp,
2071 SMB_STRF_FORCEASCII);
2072 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2073 return CM_ERROR_INVAL;
2074 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2075 SMB_STRF_FORCEASCII);
2076 if (cm_ClientStrCmp(cdescp, _C("B16")) ||
2077 cm_ClientStrCmp(cdescp, _C("B16BBDz")))
2078 return CM_ERROR_INVAL;
2084 if (infoLevel != 0 && infoLevel != 1) {
2085 return CM_ERROR_INVAL;
2091 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
2092 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
2094 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2096 memset(outp->parmsp,0,totalParams);
2097 memset(outp->datap,0,totalData);
2099 if (infoLevel == 0) {
2100 info0 = (smb_rap_server_info_0_t *) outp->datap;
2101 cstrp = (char *) (info0 + 1);
2102 StringCchCopyA(info0->sv0_name, lengthof(info0->sv0_name), "AFS");
2103 } else { /* infoLevel == SMB_INFO_STANDARD */
2104 info1 = (smb_rap_server_info_1_t *) outp->datap;
2105 cstrp = (char *) (info1 + 1);
2106 StringCchCopyA(info1->sv1_name, lengthof(info1->sv1_name), "AFS");
2109 SMB_SV_TYPE_SERVER |
2111 SMB_SV_TYPE_SERVER_NT;
2113 info1->sv1_version_major = 5;
2114 info1->sv1_version_minor = 1;
2115 info1->sv1_comment_or_master_browser = (DWORD) (cstrp - outp->datap);
2117 StringCbCopyA(cstrp, smb_ServerCommentLen, smb_ServerComment);
2119 cstrp += smb_ServerCommentLen / sizeof(char);
2122 totalData = (DWORD)(cstrp - outp->datap);
2123 outp->totalData = min(bufsize,totalData); /* actual data size */
2124 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
2125 outp->parmsp[2] = totalData;
2126 outp->totalParms = totalParams;
2128 smb_SendTran2Packet(vcp,outp,op);
2129 smb_FreeTran2Packet(outp);
2134 /* SMB_COM_TRANSACTION2 and SMB_COM_TRANSACTION2_SECONDARY */
2135 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2137 smb_tran2Packet_t *asp;
2148 DWORD oldTime, newTime;
2150 /* We sometimes see 0 word count. What to do? */
2151 if (*inp->wctp == 0) {
2152 osi_Log0(smb_logp, "Transaction2 word count = 0");
2153 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
2155 smb_SetSMBDataLength(outp, 0);
2156 smb_SendPacket(vcp, outp);
2160 totalParms = smb_GetSMBParm(inp, 0);
2161 totalData = smb_GetSMBParm(inp, 1);
2163 firstPacket = (inp->inCom == 0x32);
2165 /* find the packet we're reassembling */
2166 lock_ObtainWrite(&smb_globalLock);
2167 asp = smb_FindTran2Packet(vcp, inp);
2169 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
2171 lock_ReleaseWrite(&smb_globalLock);
2173 /* now merge in this latest packet; start by looking up offsets */
2175 parmDisp = dataDisp = 0;
2176 parmOffset = smb_GetSMBParm(inp, 10);
2177 dataOffset = smb_GetSMBParm(inp, 12);
2178 parmCount = smb_GetSMBParm(inp, 9);
2179 dataCount = smb_GetSMBParm(inp, 11);
2180 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2181 asp->maxReturnData = smb_GetSMBParm(inp, 3);
2183 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2184 totalData, dataCount, asp->maxReturnData);
2187 parmDisp = smb_GetSMBParm(inp, 4);
2188 parmOffset = smb_GetSMBParm(inp, 3);
2189 dataDisp = smb_GetSMBParm(inp, 7);
2190 dataOffset = smb_GetSMBParm(inp, 6);
2191 parmCount = smb_GetSMBParm(inp, 2);
2192 dataCount = smb_GetSMBParm(inp, 5);
2194 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2195 parmCount, dataCount);
2198 /* now copy the parms and data */
2199 if ( asp->totalParms > 0 && parmCount != 0 )
2201 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2203 if ( asp->totalData > 0 && dataCount != 0 ) {
2204 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2207 /* account for new bytes */
2208 asp->curData += dataCount;
2209 asp->curParms += parmCount;
2211 /* finally, if we're done, remove the packet from the queue and dispatch it */
2212 if (asp->totalParms > 0 &&
2213 asp->curParms > 0 &&
2214 asp->totalData <= asp->curData &&
2215 asp->totalParms <= asp->curParms) {
2216 /* we've received it all */
2217 lock_ObtainWrite(&smb_globalLock);
2218 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2219 lock_ReleaseWrite(&smb_globalLock);
2221 oldTime = GetTickCount();
2223 /* now dispatch it */
2224 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2225 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2226 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2229 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2230 code = CM_ERROR_BADOP;
2233 /* if an error is returned, we're supposed to send an error packet,
2234 * otherwise the dispatched function already did the data sending.
2235 * We give dispatched proc the responsibility since it knows how much
2236 * space to allocate.
2239 smb_SendTran2Error(vcp, asp, outp, code);
2242 newTime = GetTickCount();
2243 if (newTime - oldTime > 45000) {
2246 clientchar_t *treepath = NULL; /* do not free */
2247 clientchar_t *pathname = NULL;
2248 cm_fid_t afid = {0,0,0,0,0};
2250 uidp = smb_FindUID(vcp, asp->uid, 0);
2251 smb_LookupTIDPath(vcp, asp->tid, &treepath);
2252 fidp = smb_FindFID(vcp, inp->fid, 0);
2255 lock_ObtainMutex(&fidp->mx);
2256 if (fidp->NTopen_pathp)
2257 pathname = fidp->NTopen_pathp;
2259 afid = fidp->scp->fid;
2261 if (inp->stringsp->wdata)
2262 pathname = inp->stringsp->wdata;
2265 afsi_log("Request %s duration %d ms user %S tid \"%S\" path? \"%S\" afid (%d.%d.%d.%d)",
2266 myCrt_2Dispatch(asp->opcode), newTime - oldTime,
2267 uidp ? uidp->unp->name : NULL,
2270 afid.cell, afid.volume, afid.vnode, afid.unique);
2273 lock_ReleaseMutex(&fidp->mx);
2276 smb_ReleaseUID(uidp);
2278 smb_ReleaseFID(fidp);
2281 /* free the input tran 2 packet */
2282 smb_FreeTran2Packet(asp);
2284 else if (firstPacket) {
2285 /* the first packet in a multi-packet request, we need to send an
2286 * ack to get more data.
2288 smb_SetSMBDataLength(outp, 0);
2289 smb_SendPacket(vcp, outp);
2296 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2298 clientchar_t *pathp;
2299 smb_tran2Packet_t *outp;
2304 cm_scache_t *dscp; /* dir we're dealing with */
2305 cm_scache_t *scp; /* file we're creating */
2307 int initialModeBits;
2310 clientchar_t *lastNamep;
2317 int parmSlot; /* which parm we're dealing with */
2318 long returnEALength;
2319 clientchar_t *tidPathp;
2327 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2328 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2330 openFun = p->parmsp[6]; /* open function */
2331 excl = ((openFun & 3) == 0);
2332 trunc = ((openFun & 3) == 2); /* truncate it */
2333 openMode = (p->parmsp[1] & 0x7);
2334 openAction = 0; /* tracks what we did */
2336 attributes = p->parmsp[3];
2337 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2339 /* compute initial mode bits based on read-only flag in attributes */
2340 initialModeBits = 0666;
2341 if (attributes & SMB_ATTR_READONLY)
2342 initialModeBits &= ~0222;
2344 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
2347 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2349 spacep = cm_GetSpace();
2350 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2353 (cm_ClientStrCmpI(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
2354 cm_ClientStrCmpI(lastNamep, _C("\\srvsvc")) == 0 ||
2355 cm_ClientStrCmpI(lastNamep, _C("\\wkssvc")) == 0 ||
2356 cm_ClientStrCmpI(lastNamep, _C("\\ipc$")) == 0)) {
2357 /* special case magic file name for receiving IOCTL requests
2358 * (since IOCTL calls themselves aren't getting through).
2360 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2361 smb_SetupIoctlFid(fidp, spacep);
2363 /* copy out remainder of the parms */
2365 outp->parmsp[parmSlot++] = fidp->fid;
2367 outp->parmsp[parmSlot++] = 0; /* attrs */
2368 outp->parmsp[parmSlot++] = 0; /* mod time */
2369 outp->parmsp[parmSlot++] = 0;
2370 outp->parmsp[parmSlot++] = 0; /* len */
2371 outp->parmsp[parmSlot++] = 0x7fff;
2372 outp->parmsp[parmSlot++] = openMode;
2373 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2374 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2376 /* and the final "always present" stuff */
2377 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2378 /* next write out the "unique" ID */
2379 outp->parmsp[parmSlot++] = 0x1234;
2380 outp->parmsp[parmSlot++] = 0x5678;
2381 outp->parmsp[parmSlot++] = 0;
2382 if (returnEALength) {
2383 outp->parmsp[parmSlot++] = 0;
2384 outp->parmsp[parmSlot++] = 0;
2387 outp->totalData = 0;
2388 outp->totalParms = parmSlot * 2;
2390 smb_SendTran2Packet(vcp, outp, op);
2392 smb_FreeTran2Packet(outp);
2394 /* and clean up fid reference */
2395 smb_ReleaseFID(fidp);
2399 if (!cm_IsValidClientString(pathp)) {
2401 clientchar_t * hexp;
2403 hexp = cm_GetRawCharsAlloc(pathp, -1);
2404 osi_Log1(smb_logp, "Tran2Open rejecting invalid name. [%S]",
2405 osi_LogSaveClientString(smb_logp, hexp));
2409 osi_Log0(smb_logp, "Tran2Open rejecting invalid name");
2411 smb_FreeTran2Packet(outp);
2412 return CM_ERROR_BADNTFILENAME;
2415 #ifdef DEBUG_VERBOSE
2417 char *hexp, *asciip;
2418 asciip = (lastNamep ? lastNamep : pathp);
2419 hexp = osi_HexifyString( asciip );
2420 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2425 userp = smb_GetTran2User(vcp, p);
2426 /* In the off chance that userp is NULL, we log and abandon */
2428 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2429 smb_FreeTran2Packet(outp);
2430 return CM_ERROR_BADSMB;
2433 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2434 if (code == CM_ERROR_TIDIPC) {
2435 /* Attempt to use a TID allocated for IPC. The client
2436 * is probably looking for DCE RPC end points which we
2437 * don't support OR it could be looking to make a DFS
2440 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2442 cm_ReleaseUser(userp);
2443 smb_FreeTran2Packet(outp);
2444 return CM_ERROR_NOSUCHPATH;
2449 code = cm_NameI(cm_data.rootSCachep, pathp,
2450 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2451 userp, tidPathp, &req, &scp);
2453 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2454 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2455 userp, tidPathp, &req, &dscp);
2456 cm_FreeSpace(spacep);
2459 cm_ReleaseUser(userp);
2460 smb_FreeTran2Packet(outp);
2465 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2466 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2467 (clientchar_t*) spacep->data);
2468 cm_ReleaseSCache(dscp);
2469 cm_ReleaseUser(userp);
2470 smb_FreeTran2Packet(outp);
2471 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2472 return CM_ERROR_PATH_NOT_COVERED;
2474 return CM_ERROR_BADSHARENAME;
2476 #endif /* DFS_SUPPORT */
2478 /* otherwise, scp points to the parent directory. Do a lookup,
2479 * and truncate the file if we find it, otherwise we create the
2486 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2488 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2489 cm_ReleaseSCache(dscp);
2490 cm_ReleaseUser(userp);
2491 smb_FreeTran2Packet(outp);
2496 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2497 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2498 cm_ReleaseSCache(scp);
2499 cm_ReleaseUser(userp);
2500 smb_FreeTran2Packet(outp);
2501 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2502 return CM_ERROR_PATH_NOT_COVERED;
2504 return CM_ERROR_BADSHARENAME;
2506 #endif /* DFS_SUPPORT */
2508 /* macintosh is expensive to program for it */
2509 cm_FreeSpace(spacep);
2512 /* if we get here, if code is 0, the file exists and is represented by
2513 * scp. Otherwise, we have to create it.
2516 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2519 cm_ReleaseSCache(dscp);
2520 cm_ReleaseSCache(scp);
2521 cm_ReleaseUser(userp);
2522 smb_FreeTran2Packet(outp);
2527 /* oops, file shouldn't be there */
2529 cm_ReleaseSCache(dscp);
2530 cm_ReleaseSCache(scp);
2531 cm_ReleaseUser(userp);
2532 smb_FreeTran2Packet(outp);
2533 return CM_ERROR_EXISTS;
2537 setAttr.mask = CM_ATTRMASK_LENGTH;
2538 setAttr.length.LowPart = 0;
2539 setAttr.length.HighPart = 0;
2540 code = cm_SetAttr(scp, &setAttr, userp, &req);
2541 openAction = 3; /* truncated existing file */
2544 openAction = 1; /* found existing file */
2546 else if (!(openFun & 0x10)) {
2547 /* don't create if not found */
2549 cm_ReleaseSCache(dscp);
2550 osi_assertx(scp == NULL, "null cm_scache_t");
2551 cm_ReleaseUser(userp);
2552 smb_FreeTran2Packet(outp);
2553 return CM_ERROR_NOSUCHFILE;
2556 osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2557 openAction = 2; /* created file */
2558 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2559 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2560 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2564 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2565 smb_NotifyChange(FILE_ACTION_ADDED,
2566 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2567 dscp, lastNamep, NULL, TRUE);
2568 } else if (!excl && code == CM_ERROR_EXISTS) {
2569 /* not an exclusive create, and someone else tried
2570 * creating it already, then we open it anyway. We
2571 * don't bother retrying after this, since if this next
2572 * fails, that means that the file was deleted after we
2573 * started this call.
2575 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2579 setAttr.mask = CM_ATTRMASK_LENGTH;
2580 setAttr.length.LowPart = 0;
2581 setAttr.length.HighPart = 0;
2582 code = cm_SetAttr(scp, &setAttr, userp,
2585 } /* lookup succeeded */
2589 /* we don't need this any longer */
2591 cm_ReleaseSCache(dscp);
2594 /* something went wrong creating or truncating the file */
2596 cm_ReleaseSCache(scp);
2597 cm_ReleaseUser(userp);
2598 smb_FreeTran2Packet(outp);
2602 /* make sure we're about to open a file */
2603 if (scp->fileType != CM_SCACHETYPE_FILE) {
2605 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2606 cm_scache_t * targetScp = 0;
2607 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2609 /* we have a more accurate file to use (the
2610 * target of the symbolic link). Otherwise,
2611 * we'll just use the symlink anyway.
2613 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2615 cm_ReleaseSCache(scp);
2619 if (scp->fileType != CM_SCACHETYPE_FILE) {
2620 cm_ReleaseSCache(scp);
2621 cm_ReleaseUser(userp);
2622 smb_FreeTran2Packet(outp);
2623 return CM_ERROR_ISDIR;
2627 /* now all we have to do is open the file itself */
2628 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2629 osi_assertx(fidp, "null smb_fid_t");
2632 lock_ObtainMutex(&fidp->mx);
2633 /* save a pointer to the vnode */
2634 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2636 lock_ObtainWrite(&scp->rw);
2637 scp->flags |= CM_SCACHEFLAG_SMB_FID;
2638 lock_ReleaseWrite(&scp->rw);
2641 fidp->userp = userp;
2643 /* compute open mode */
2645 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
2646 if (openMode == 1 || openMode == 2)
2647 fidp->flags |= SMB_FID_OPENWRITE;
2649 /* remember that the file was newly created */
2651 fidp->flags |= SMB_FID_CREATED;
2653 lock_ReleaseMutex(&fidp->mx);
2655 smb_ReleaseFID(fidp);
2657 cm_Open(scp, 0, userp);
2659 /* copy out remainder of the parms */
2661 outp->parmsp[parmSlot++] = fidp->fid;
2662 lock_ObtainRead(&scp->rw);
2664 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2665 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2666 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2667 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2668 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2669 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2670 outp->parmsp[parmSlot++] = openMode;
2671 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2672 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2674 /* and the final "always present" stuff */
2675 outp->parmsp[parmSlot++] = openAction;
2676 /* next write out the "unique" ID */
2677 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2678 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2679 outp->parmsp[parmSlot++] = 0;
2680 if (returnEALength) {
2681 outp->parmsp[parmSlot++] = 0;
2682 outp->parmsp[parmSlot++] = 0;
2684 lock_ReleaseRead(&scp->rw);
2685 outp->totalData = 0; /* total # of data bytes */
2686 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2688 smb_SendTran2Packet(vcp, outp, op);
2690 smb_FreeTran2Packet(outp);
2692 cm_ReleaseUser(userp);
2693 /* leave scp held since we put it in fidp->scp */
2697 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2700 unsigned short infolevel;
2702 infolevel = p->parmsp[0];
2704 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2706 return CM_ERROR_BAD_LEVEL;
2709 /* TRANS2_QUERY_FS_INFORMATION */
2710 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2712 smb_tran2Packet_t *outp;
2713 smb_tran2QFSInfo_t qi;
2717 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2719 switch (p->parmsp[0]) {
2720 case SMB_INFO_ALLOCATION:
2722 responseSize = sizeof(qi.u.allocInfo);
2724 qi.u.allocInfo.FSID = 0;
2725 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2726 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2727 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2728 qi.u.allocInfo.bytesPerSector = 1024;
2731 case SMB_INFO_VOLUME:
2733 qi.u.volumeInfo.vsn = 1234; /* Volume serial number */
2734 qi.u.volumeInfo.vnCount = 3; /* Number of characters in label (AFS\0)*/
2736 /* we're supposed to pad it out with zeroes to the end */
2737 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2738 smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
2740 responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
2743 case SMB_QUERY_FS_VOLUME_INFO:
2744 /* FS volume info */
2745 responseSize = sizeof(qi.u.FSvolumeInfo);
2748 FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
2749 memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
2752 qi.u.FSvolumeInfo.vsn = 1234;
2753 qi.u.FSvolumeInfo.vnCount = 6; /* This is always in Unicode */
2754 memset(&qi.u.FSvolumeInfo.label, 0, sizeof(qi.u.FSvolumeInfo.label));
2755 memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
2758 case SMB_QUERY_FS_SIZE_INFO:
2760 responseSize = sizeof(qi.u.FSsizeInfo);
2762 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2763 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2764 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2765 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2766 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2767 qi.u.FSsizeInfo.bytesPerSector = 1024;
2770 case SMB_QUERY_FS_DEVICE_INFO:
2771 /* FS device info */
2772 responseSize = sizeof(qi.u.FSdeviceInfo);
2774 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2775 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2778 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2779 /* FS attribute info */
2781 /* attributes, defined in WINNT.H:
2782 * FILE_CASE_SENSITIVE_SEARCH 0x1
2783 * FILE_CASE_PRESERVED_NAMES 0x2
2784 * FILE_UNICODE_ON_DISK 0x4
2785 * FILE_VOLUME_QUOTAS 0x10
2786 * <no name defined> 0x4000
2787 * If bit 0x4000 is not set, Windows 95 thinks
2788 * we can't handle long (non-8.3) names,
2789 * despite our protestations to the contrary.
2791 qi.u.FSattributeInfo.attributes = 0x4003;
2792 /* The maxCompLength is supposed to be in bytes */
2794 qi.u.FSattributeInfo.attributes |= 0x04;
2796 qi.u.FSattributeInfo.maxCompLength = 255;
2797 smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
2798 qi.u.FSattributeInfo.FSnameLength = sz;
2801 sizeof(qi.u.FSattributeInfo.attributes) +
2802 sizeof(qi.u.FSattributeInfo.maxCompLength) +
2803 sizeof(qi.u.FSattributeInfo.FSnameLength) +
2808 case SMB_INFO_UNIX: /* CIFS Unix Info */
2809 case SMB_INFO_MACOS: /* Mac FS Info */
2811 return CM_ERROR_BADOP;
2814 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2816 /* copy out return data, and set corresponding sizes */
2817 outp->totalParms = 0;
2818 outp->totalData = responseSize;
2819 memcpy(outp->datap, &qi, responseSize);
2821 /* send and free the packets */
2822 smb_SendTran2Packet(vcp, outp, op);
2823 smb_FreeTran2Packet(outp);
2828 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2830 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2831 return CM_ERROR_BADOP;
2834 struct smb_ShortNameRock {
2835 clientchar_t *maskp;
2837 clientchar_t *shortName;
2838 size_t shortNameLen;
2841 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2844 struct smb_ShortNameRock *rockp;
2845 normchar_t normName[MAX_PATH];
2846 clientchar_t *shortNameEnd;
2850 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t)) == 0) {
2851 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
2852 osi_LogSaveString(smb_logp, dep->name));
2856 /* compare both names and vnodes, though probably just comparing vnodes
2857 * would be safe enough.
2859 if (cm_NormStrCmpI(normName, rockp->maskp) != 0)
2861 if (ntohl(dep->fid.vnode) != rockp->vnode)
2864 /* This is the entry */
2865 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2866 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2868 return CM_ERROR_STOPNOW;
2871 long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
2872 clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
2874 struct smb_ShortNameRock rock;
2875 clientchar_t *lastNamep;
2878 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2882 spacep = cm_GetSpace();
2883 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2885 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2886 caseFold, userp, tidPathp,
2888 cm_FreeSpace(spacep);
2893 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2894 cm_ReleaseSCache(dscp);
2895 cm_ReleaseUser(userp);
2899 return CM_ERROR_PATH_NOT_COVERED;
2901 #endif /* DFS_SUPPORT */
2903 if (!lastNamep) lastNamep = pathp;
2906 thyper.HighPart = 0;
2907 rock.shortName = shortName;
2909 rock.maskp = lastNamep;
2910 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2912 cm_ReleaseSCache(dscp);
2915 return CM_ERROR_NOSUCHFILE;
2916 if (code == CM_ERROR_STOPNOW) {
2917 *shortNameLenp = rock.shortNameLen;
2923 /* TRANS2_QUERY_PATH_INFORMATION */
2924 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2926 smb_tran2Packet_t *outp;
2929 unsigned short infoLevel;
2930 smb_tran2QPathInfo_t qpi;
2932 unsigned short attributes;
2933 unsigned long extAttributes;
2934 clientchar_t shortName[13];
2938 cm_scache_t *scp, *dscp;
2939 int scp_rw_held = 0;
2942 clientchar_t *pathp;
2943 clientchar_t *tidPathp;
2944 clientchar_t *lastComp;
2949 infoLevel = p->parmsp[0];
2950 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2952 else if (infoLevel == SMB_INFO_STANDARD)
2953 responseSize = sizeof(qpi.u.QPstandardInfo);
2954 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2955 responseSize = sizeof(qpi.u.QPeaSizeInfo);
2956 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2957 responseSize = sizeof(qpi.u.QPfileBasicInfo);
2958 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2959 responseSize = sizeof(qpi.u.QPfileStandardInfo);
2960 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2961 responseSize = sizeof(qpi.u.QPfileEaInfo);
2962 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2963 responseSize = sizeof(qpi.u.QPfileNameInfo);
2964 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
2965 responseSize = sizeof(qpi.u.QPfileAllInfo);
2966 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2967 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2969 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2970 p->opcode, infoLevel);
2971 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
2975 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
2976 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %S", infoLevel,
2977 osi_LogSaveClientString(smb_logp, pathp));
2979 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2981 if (infoLevel > 0x100)
2982 outp->totalParms = 2;
2984 outp->totalParms = 0;
2985 outp->totalData = responseSize;
2987 /* now, if we're at infoLevel 6, we're only being asked to check
2988 * the syntax, so we just OK things now. In particular, we're *not*
2989 * being asked to verify anything about the state of any parent dirs.
2991 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2992 smb_SendTran2Packet(vcp, outp, opx);
2993 smb_FreeTran2Packet(outp);
2997 userp = smb_GetTran2User(vcp, p);
2999 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
3000 smb_FreeTran2Packet(outp);
3001 return CM_ERROR_BADSMB;
3004 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3006 cm_ReleaseUser(userp);
3007 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
3008 smb_FreeTran2Packet(outp);
3013 * XXX Strange hack XXX
3015 * As of Patch 7 (13 January 98), we are having the following problem:
3016 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3017 * requests to look up "desktop.ini" in all the subdirectories.
3018 * This can cause zillions of timeouts looking up non-existent cells
3019 * and volumes, especially in the top-level directory.
3021 * We have not found any way to avoid this or work around it except
3022 * to explicitly ignore the requests for mount points that haven't
3023 * yet been evaluated and for directories that haven't yet been
3026 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3027 spacep = cm_GetSpace();
3028 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3029 #ifndef SPECIAL_FOLDERS
3030 /* Make sure that lastComp is not NULL */
3032 if (cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
3033 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3037 userp, tidPathp, &req, &dscp);
3040 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3041 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3043 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3044 code = CM_ERROR_PATH_NOT_COVERED;
3046 code = CM_ERROR_BADSHARENAME;
3048 #endif /* DFS_SUPPORT */
3049 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3050 code = CM_ERROR_NOSUCHFILE;
3051 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3052 cm_buf_t *bp = buf_Find(dscp, &hzero);
3058 code = CM_ERROR_NOSUCHFILE;
3060 cm_ReleaseSCache(dscp);
3062 cm_FreeSpace(spacep);
3063 cm_ReleaseUser(userp);
3064 smb_SendTran2Error(vcp, p, opx, code);
3065 smb_FreeTran2Packet(outp);
3071 #endif /* SPECIAL_FOLDERS */
3073 cm_FreeSpace(spacep);
3076 /* now do namei and stat, and copy out the info */
3077 code = cm_NameI(cm_data.rootSCachep, pathp,
3078 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3081 cm_ReleaseUser(userp);
3082 smb_SendTran2Error(vcp, p, opx, code);
3083 smb_FreeTran2Packet(outp);
3088 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3089 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3090 cm_ReleaseSCache(scp);
3091 cm_ReleaseUser(userp);
3092 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3093 code = CM_ERROR_PATH_NOT_COVERED;
3095 code = CM_ERROR_BADSHARENAME;
3096 smb_SendTran2Error(vcp, p, opx, code);
3097 smb_FreeTran2Packet(outp);
3100 #endif /* DFS_SUPPORT */
3102 lock_ObtainWrite(&scp->rw);
3104 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3105 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3109 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3111 lock_ConvertWToR(&scp->rw);
3116 /* now we have the status in the cache entry, and everything is locked.
3117 * Marshall the output data.
3119 /* for info level 108, figure out short name */
3120 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3121 code = cm_GetShortName(pathp, userp, &req,
3122 tidPathp, scp->fid.vnode, shortName,
3128 smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
3129 qpi.u.QPfileAltNameInfo.fileNameLength = len;
3133 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3134 smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3135 qpi.u.QPfileNameInfo.fileNameLength = len;
3139 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3140 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3141 qpi.u.QPstandardInfo.creationDateTime = dosTime;
3142 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3143 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3144 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3145 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3146 attributes = smb_Attributes(scp);
3147 qpi.u.QPstandardInfo.attributes = attributes;
3148 qpi.u.QPstandardInfo.eaSize = 0;
3150 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3151 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3152 qpi.u.QPfileBasicInfo.creationTime = ft;
3153 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3154 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3155 qpi.u.QPfileBasicInfo.changeTime = ft;
3156 extAttributes = smb_ExtAttributes(scp);
3157 qpi.u.QPfileBasicInfo.attributes = extAttributes;
3158 qpi.u.QPfileBasicInfo.reserved = 0;
3160 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3163 lock_ReleaseRead(&scp->rw);
3165 fidp = smb_FindFIDByScache(vcp, scp);
3167 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3168 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3169 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3170 qpi.u.QPfileStandardInfo.directory =
3171 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3172 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3173 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3174 qpi.u.QPfileStandardInfo.reserved = 0;
3177 lock_ObtainMutex(&fidp->mx);
3178 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3179 lock_ReleaseMutex(&fidp->mx);
3180 smb_ReleaseFID(fidp);
3182 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3184 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3185 qpi.u.QPfileEaInfo.eaSize = 0;
3187 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3188 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3189 qpi.u.QPfileAllInfo.creationTime = ft;
3190 qpi.u.QPfileAllInfo.lastAccessTime = ft;
3191 qpi.u.QPfileAllInfo.lastWriteTime = ft;
3192 qpi.u.QPfileAllInfo.changeTime = ft;
3193 extAttributes = smb_ExtAttributes(scp);
3194 qpi.u.QPfileAllInfo.attributes = extAttributes;
3195 qpi.u.QPfileAllInfo.allocationSize = scp->length;
3196 qpi.u.QPfileAllInfo.endOfFile = scp->length;
3197 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3198 qpi.u.QPfileAllInfo.deletePending = 0;
3199 qpi.u.QPfileAllInfo.directory =
3200 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3201 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3202 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3203 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
3204 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
3205 qpi.u.QPfileAllInfo.eaSize = 0;
3206 qpi.u.QPfileAllInfo.accessFlags = 0;
3207 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
3208 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
3209 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3210 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3211 qpi.u.QPfileAllInfo.mode = 0;
3212 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3214 smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3215 qpi.u.QPfileAllInfo.fileNameLength = len;
3218 /* send and free the packets */
3220 switch (scp_rw_held) {
3222 lock_ReleaseRead(&scp->rw);
3225 lock_ReleaseWrite(&scp->rw);
3229 cm_ReleaseSCache(scp);
3230 cm_ReleaseUser(userp);
3232 memcpy(outp->datap, &qpi, responseSize);
3233 smb_SendTran2Packet(vcp, outp, opx);
3235 smb_SendTran2Error(vcp, p, opx, code);
3237 smb_FreeTran2Packet(outp);
3242 /* TRANS2_SET_PATH_INFORMATION */
3243 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3246 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
3247 return CM_ERROR_BADOP;
3250 unsigned short infoLevel;
3251 clientchar_t * pathp;
3252 smb_tran2Packet_t *outp;
3253 smb_tran2QPathInfo_t *spi;
3255 cm_scache_t *scp, *dscp;
3258 clientchar_t *tidPathp;
3259 clientchar_t *lastComp;
3263 infoLevel = p->parmsp[0];
3264 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
3265 if (infoLevel != SMB_INFO_STANDARD &&
3266 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
3267 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
3268 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3269 p->opcode, infoLevel);
3270 smb_SendTran2Error(vcp, p, opx,
3271 infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3275 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3277 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
3278 osi_LogSaveClientString(smb_logp, pathp));
3280 userp = smb_GetTran2User(vcp, p);
3282 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3283 code = CM_ERROR_BADSMB;
3287 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3288 if (code == CM_ERROR_TIDIPC) {
3289 /* Attempt to use a TID allocated for IPC. The client
3290 * is probably looking for DCE RPC end points which we
3291 * don't support OR it could be looking to make a DFS
3294 osi_Log0(smb_logp, "Tran2Open received IPC TID");
3295 cm_ReleaseUser(userp);
3296 return CM_ERROR_NOSUCHPATH;
3300 * XXX Strange hack XXX
3302 * As of Patch 7 (13 January 98), we are having the following problem:
3303 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3304 * requests to look up "desktop.ini" in all the subdirectories.
3305 * This can cause zillions of timeouts looking up non-existent cells
3306 * and volumes, especially in the top-level directory.
3308 * We have not found any way to avoid this or work around it except
3309 * to explicitly ignore the requests for mount points that haven't
3310 * yet been evaluated and for directories that haven't yet been
3313 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3314 spacep = cm_GetSpace();
3315 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3316 #ifndef SPECIAL_FOLDERS
3317 /* Make sure that lastComp is not NULL */
3319 if (cm_ClientStrCmpI(lastComp, _C("\\desktop.ini")) == 0) {
3320 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3324 userp, tidPathp, &req, &dscp);
3327 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3328 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3330 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3331 code = CM_ERROR_PATH_NOT_COVERED;
3333 code = CM_ERROR_BADSHARENAME;
3335 #endif /* DFS_SUPPORT */
3336 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3337 code = CM_ERROR_NOSUCHFILE;
3338 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3339 cm_buf_t *bp = buf_Find(dscp, &hzero);
3345 code = CM_ERROR_NOSUCHFILE;
3347 cm_ReleaseSCache(dscp);
3349 cm_FreeSpace(spacep);
3350 cm_ReleaseUser(userp);
3351 smb_SendTran2Error(vcp, p, opx, code);
3357 #endif /* SPECIAL_FOLDERS */
3359 cm_FreeSpace(spacep);
3362 /* now do namei and stat, and copy out the info */
3363 code = cm_NameI(cm_data.rootSCachep, pathp,
3364 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3366 cm_ReleaseUser(userp);
3367 smb_SendTran2Error(vcp, p, opx, code);
3371 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3373 outp->totalParms = 2;
3374 outp->totalData = 0;
3376 spi = (smb_tran2QPathInfo_t *)p->datap;
3377 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3380 /* lock the vnode with a callback; we need the current status
3381 * to determine what the new status is, in some cases.
3383 lock_ObtainWrite(&scp->rw);
3384 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3385 CM_SCACHESYNC_GETSTATUS
3386 | CM_SCACHESYNC_NEEDCALLBACK);
3388 lock_ReleaseWrite(&scp->rw);
3391 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3393 /* prepare for setattr call */
3394 attr.mask = CM_ATTRMASK_LENGTH;
3395 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3396 attr.length.HighPart = 0;
3398 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3399 smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3400 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3403 if (spi->u.QPstandardInfo.attributes != 0) {
3404 if ((scp->unixModeBits & 0222)
3405 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3406 /* make a writable file read-only */
3407 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3408 attr.unixModeBits = scp->unixModeBits & ~0222;
3410 else if ((scp->unixModeBits & 0222) == 0
3411 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3412 /* make a read-only file writable */
3413 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3414 attr.unixModeBits = scp->unixModeBits | 0222;
3417 lock_ReleaseRead(&scp->rw);
3421 code = cm_SetAttr(scp, &attr, userp, &req);
3425 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3426 /* we don't support EAs */
3427 code = CM_ERROR_EAS_NOT_SUPPORTED;
3431 cm_ReleaseSCache(scp);
3432 cm_ReleaseUser(userp);
3434 smb_SendTran2Packet(vcp, outp, opx);
3436 smb_SendTran2Error(vcp, p, opx, code);
3437 smb_FreeTran2Packet(outp);
3443 /* TRANS2_QUERY_FILE_INFORMATION */
3444 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3446 smb_tran2Packet_t *outp;
3448 unsigned long attributes;
3449 unsigned short infoLevel;
3456 smb_tran2QFileInfo_t qfi;
3464 fidp = smb_FindFID(vcp, fid, 0);
3467 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3471 lock_ObtainMutex(&fidp->mx);
3472 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3473 lock_ReleaseMutex(&fidp->mx);
3474 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3475 smb_CloseFID(vcp, fidp, NULL, 0);
3476 smb_ReleaseFID(fidp);
3479 lock_ReleaseMutex(&fidp->mx);
3481 infoLevel = p->parmsp[1];
3482 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3483 responseSize = sizeof(qfi.u.QFbasicInfo);
3484 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3485 responseSize = sizeof(qfi.u.QFstandardInfo);
3486 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3487 responseSize = sizeof(qfi.u.QFeaInfo);
3488 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3489 responseSize = sizeof(qfi.u.QFfileNameInfo);
3491 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3492 p->opcode, infoLevel);
3493 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3494 smb_ReleaseFID(fidp);
3497 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3499 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3501 if (infoLevel > 0x100)
3502 outp->totalParms = 2;
3504 outp->totalParms = 0;
3505 outp->totalData = responseSize;
3507 userp = smb_GetTran2User(vcp, p);
3509 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3510 code = CM_ERROR_BADSMB;
3514 lock_ObtainMutex(&fidp->mx);
3515 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3517 osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3519 lock_ReleaseMutex(&fidp->mx);
3520 lock_ObtainWrite(&scp->rw);
3521 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3522 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3526 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3528 lock_ConvertWToR(&scp->rw);
3531 /* now we have the status in the cache entry, and everything is locked.
3532 * Marshall the output data.
3534 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3535 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3536 qfi.u.QFbasicInfo.creationTime = ft;
3537 qfi.u.QFbasicInfo.lastAccessTime = ft;
3538 qfi.u.QFbasicInfo.lastWriteTime = ft;
3539 qfi.u.QFbasicInfo.lastChangeTime = ft;
3540 attributes = smb_ExtAttributes(scp);
3541 qfi.u.QFbasicInfo.attributes = attributes;
3543 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3544 qfi.u.QFstandardInfo.allocationSize = scp->length;
3545 qfi.u.QFstandardInfo.endOfFile = scp->length;
3546 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3547 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3548 qfi.u.QFstandardInfo.directory =
3549 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3550 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3551 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3553 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3554 qfi.u.QFeaInfo.eaSize = 0;
3556 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3560 lock_ReleaseRead(&scp->rw);
3561 lock_ObtainMutex(&fidp->mx);
3562 lock_ObtainRead(&scp->rw);
3563 if (fidp->NTopen_wholepathp)
3564 name = fidp->NTopen_wholepathp;
3566 name = _C("\\"); /* probably can't happen */
3567 lock_ReleaseMutex(&fidp->mx);
3569 smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, SMB_STRF_IGNORENUL);
3570 outp->totalData = len + 4; /* this is actually what we want to return */
3571 qfi.u.QFfileNameInfo.fileNameLength = len;
3574 /* send and free the packets */
3577 lock_ReleaseRead(&scp->rw);
3579 lock_ReleaseWrite(&scp->rw);
3580 cm_ReleaseSCache(scp);
3581 cm_ReleaseUser(userp);
3582 smb_ReleaseFID(fidp);
3584 memcpy(outp->datap, &qfi, responseSize);
3585 smb_SendTran2Packet(vcp, outp, opx);
3587 smb_SendTran2Error(vcp, p, opx, code);
3589 smb_FreeTran2Packet(outp);
3595 /* TRANS2_SET_FILE_INFORMATION */
3596 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3601 unsigned short infoLevel;
3602 smb_tran2Packet_t *outp;
3603 cm_user_t *userp = NULL;
3604 cm_scache_t *scp = NULL;
3610 fidp = smb_FindFID(vcp, fid, 0);
3613 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3617 infoLevel = p->parmsp[1];
3618 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3619 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3620 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3621 p->opcode, infoLevel);
3622 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3623 smb_ReleaseFID(fidp);
3627 lock_ObtainMutex(&fidp->mx);
3628 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3629 lock_ReleaseMutex(&fidp->mx);
3630 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3631 smb_CloseFID(vcp, fidp, NULL, 0);
3632 smb_ReleaseFID(fidp);
3636 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
3637 !(fidp->flags & SMB_FID_OPENDELETE)) {
3638 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3639 fidp, fidp->scp, fidp->flags);
3640 lock_ReleaseMutex(&fidp->mx);
3641 smb_ReleaseFID(fidp);
3642 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3645 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3646 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3647 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3648 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3649 fidp, fidp->scp, fidp->flags);
3650 lock_ReleaseMutex(&fidp->mx);
3651 smb_ReleaseFID(fidp);
3652 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3657 osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3659 lock_ReleaseMutex(&fidp->mx);
3661 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3663 outp->totalParms = 2;
3664 outp->totalData = 0;
3666 userp = smb_GetTran2User(vcp, p);
3668 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3669 code = CM_ERROR_BADSMB;
3673 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3675 unsigned int attribute;
3677 smb_tran2QFileInfo_t *sfi;
3679 sfi = (smb_tran2QFileInfo_t *)p->datap;
3681 /* lock the vnode with a callback; we need the current status
3682 * to determine what the new status is, in some cases.
3684 lock_ObtainWrite(&scp->rw);
3685 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3686 CM_SCACHESYNC_GETSTATUS
3687 | CM_SCACHESYNC_NEEDCALLBACK);
3689 lock_ReleaseWrite(&scp->rw);
3693 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3695 lock_ReleaseWrite(&scp->rw);
3696 lock_ObtainMutex(&fidp->mx);
3697 lock_ObtainRead(&scp->rw);
3699 /* prepare for setattr call */
3702 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3703 /* when called as result of move a b, lastMod is (-1, -1).
3704 * If the check for -1 is not present, timestamp
3705 * of the resulting file will be 1969 (-1)
3707 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3708 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3709 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3710 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3711 fidp->flags |= SMB_FID_MTIMESETDONE;
3714 attribute = sfi->u.QFbasicInfo.attributes;
3715 if (attribute != 0) {
3716 if ((scp->unixModeBits & 0222)
3717 && (attribute & SMB_ATTR_READONLY) != 0) {
3718 /* make a writable file read-only */
3719 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3720 attr.unixModeBits = scp->unixModeBits & ~0222;
3722 else if ((scp->unixModeBits & 0222) == 0
3723 && (attribute & SMB_ATTR_READONLY) == 0) {
3724 /* make a read-only file writable */
3725 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3726 attr.unixModeBits = scp->unixModeBits | 0222;
3729 lock_ReleaseRead(&scp->rw);
3730 lock_ReleaseMutex(&fidp->mx);
3734 code = cm_SetAttr(scp, &attr, userp, &req);
3738 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3739 int delflag = *((char *)(p->datap));
3740 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
3741 delflag, fidp, scp);
3742 if (*((char *)(p->datap))) { /* File is Deleted */
3743 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3746 lock_ObtainMutex(&fidp->mx);
3747 fidp->flags |= SMB_FID_DELONCLOSE;
3748 lock_ReleaseMutex(&fidp->mx);
3750 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
3756 lock_ObtainMutex(&fidp->mx);
3757 fidp->flags &= ~SMB_FID_DELONCLOSE;
3758 lock_ReleaseMutex(&fidp->mx);
3761 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3762 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3763 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3766 attr.mask = CM_ATTRMASK_LENGTH;
3767 attr.length.LowPart = size.LowPart;
3768 attr.length.HighPart = size.HighPart;
3769 code = cm_SetAttr(scp, &attr, userp, &req);
3773 cm_ReleaseSCache(scp);
3774 cm_ReleaseUser(userp);
3775 smb_ReleaseFID(fidp);
3777 smb_SendTran2Packet(vcp, outp, opx);
3779 smb_SendTran2Error(vcp, p, opx, code);
3780 smb_FreeTran2Packet(outp);
3787 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3789 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3790 return CM_ERROR_BADOP;
3795 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3797 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3798 return CM_ERROR_BADOP;
3801 /* TRANS2_FIND_NOTIFY_FIRST */
3803 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3805 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3806 return CM_ERROR_BADOP;
3809 /* TRANS2_FIND_NOTIFY_NEXT */
3811 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3813 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3814 return CM_ERROR_BADOP;
3817 /* TRANS2_CREATE_DIRECTORY */
3819 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3821 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3822 return CM_ERROR_BADOP;
3825 /* TRANS2_SESSION_SETUP */
3827 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3829 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3830 return CM_ERROR_BADOP;
3833 struct smb_v2_referral {
3835 USHORT ReferralFlags;
3838 USHORT DfsPathOffset;
3839 USHORT DfsAlternativePathOffset;
3840 USHORT NetworkAddressOffset;
3843 /* TRANS2_GET_DFS_REFERRAL */
3845 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3847 /* This is a UNICODE only request (bit15 of Flags2) */
3848 /* The TID must be IPC$ */
3850 /* The documentation for the Flags response field is contradictory */
3852 /* Use Version 1 Referral Element Format */
3853 /* ServerType = 0; indicates the next server should be queried for the file */
3854 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3855 /* Node = UnicodeString of UNC path of the next share name */
3858 int maxReferralLevel = 0;
3859 clientchar_t requestFileName[1024] = _C("");
3860 clientchar_t referralPath[1024] = _C("");
3861 smb_tran2Packet_t *outp = 0;
3862 cm_user_t *userp = 0;
3863 cm_scache_t *scp = 0;
3864 cm_scache_t *dscp = 0;
3866 CPINFO CodePageInfo;
3867 int i, nbnLen, reqLen, refLen;
3872 maxReferralLevel = p->parmsp[0];
3874 GetCPInfo(CP_ACP, &CodePageInfo);
3875 cm_Utf16ToClientString(&p->parmsp[1], -1, requestFileName, lengthof(requestFileName));
3877 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%S]",
3878 maxReferralLevel, osi_LogSaveClientString(smb_logp, requestFileName));
3880 nbnLen = (int)cm_ClientStrLen(cm_NetbiosNameC);
3881 reqLen = (int)cm_ClientStrLen(requestFileName);
3883 if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
3884 !cm_ClientStrCmpNI(cm_NetbiosNameC, &requestFileName[1], nbnLen) &&
3885 requestFileName[nbnLen+1] == '\\')
3889 if (!cm_ClientStrCmpNI(_C("all"), &requestFileName[nbnLen+2], 3) ||
3890 !cm_ClientStrCmpNI(_C("*."), &requestFileName[nbnLen+2], 2)) {
3892 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
3895 userp = smb_GetTran2User(vcp, p);
3897 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3898 code = CM_ERROR_BADSMB;
3903 * We have a requested path. Check to see if it is something
3906 * But be careful because the name that we might be searching
3907 * for might be a known name with the final character stripped
3910 code = cm_NameI(cm_data.rootSCachep, &requestFileName[nbnLen+2],
3911 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
3912 userp, NULL, &req, &scp);
3916 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
3918 } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
3919 clientchar_t temp[1024];
3920 clientchar_t pathName[1024];
3921 clientchar_t *lastComponent;
3923 * we have a msdfs link somewhere in the path
3924 * we should figure out where in the path the link is.
3927 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%S]", requestFileName);
3929 cm_ClientStrCpy(temp, lengthof(temp), &requestFileName[nbnLen+2]);
3933 cm_ReleaseSCache(dscp);
3937 cm_ReleaseSCache(scp);
3940 smb_StripLastComponent(pathName, &lastComponent, temp);
3942 code = cm_NameI(cm_data.rootSCachep, pathName,
3943 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3944 userp, NULL, &req, &dscp);
3946 code = cm_NameI(dscp, ++lastComponent,
3948 userp, NULL, &req, &scp);
3949 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK)
3952 } while (code == CM_ERROR_PATH_NOT_COVERED);
3954 /* scp should now be the DfsLink we are looking for */
3956 /* figure out how much of the input path was used */
3957 reqLen = (int)(nbnLen+2 + cm_ClientStrLen(pathName) + 1 + cm_ClientStrLen(lastComponent));
3959 cm_FsStringToClientString(&scp->mountPointStringp[strlen("msdfs:")], -1,
3960 referralPath, lengthof(referralPath));
3961 refLen = (int)cm_ClientStrLen(referralPath);
3965 clientchar_t shareName[MAX_PATH + 1];
3966 clientchar_t *p, *q;
3967 /* we may have a sharename that is a volume reference */
3969 for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
3975 if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
3976 code = cm_NameI(cm_data.rootSCachep, _C(""),
3977 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
3978 userp, p, &req, &scp);
3983 cm_ClientStrCpy(referralPath, lengthof(referralPath),
3994 struct smb_v2_referral * v2ref;
3995 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (refLen + 8));
3997 sp = (USHORT *)outp->datap;
3999 sp[idx++] = reqLen; /* path consumed */
4000 sp[idx++] = 1; /* number of referrals */
4001 sp[idx++] = 0x03; /* flags */
4002 #ifdef DFS_VERSION_1
4003 sp[idx++] = 1; /* Version Number */
4004 sp[idx++] = refLen + 4; /* Referral Size */
4005 sp[idx++] = 1; /* Type = SMB Server */
4006 sp[idx++] = 0; /* Do not strip path consumed */
4007 for ( i=0;i<=refLen; i++ )
4008 sp[i+idx] = referralPath[i];
4009 #else /* DFS_VERSION_2 */
4010 sp[idx++] = 2; /* Version Number */
4011 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
4012 idx += (sizeof(struct smb_v2_referral) / 2);
4013 v2ref = (struct smb_v2_referral *) &sp[5];
4014 v2ref->ServerType = 1; /* SMB Server */
4015 v2ref->ReferralFlags = 0x03;
4016 v2ref->Proximity = 0; /* closest */
4017 v2ref->TimeToLive = 3600; /* seconds */
4018 v2ref->DfsPathOffset = idx * 2;
4019 v2ref->DfsAlternativePathOffset = idx * 2;
4020 v2ref->NetworkAddressOffset = 0;
4021 for ( i=0;i<=refLen; i++ )
4022 sp[i+idx] = referralPath[i];
4026 code = CM_ERROR_NOSUCHPATH;
4031 cm_ReleaseSCache(dscp);
4033 cm_ReleaseSCache(scp);
4035 cm_ReleaseUser(userp);
4037 smb_SendTran2Packet(vcp, outp, op);
4039 smb_SendTran2Error(vcp, p, op, code);
4041 smb_FreeTran2Packet(outp);
4044 #else /* DFS_SUPPORT */
4045 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
4046 return CM_ERROR_NOSUCHDEVICE;
4047 #endif /* DFS_SUPPORT */
4050 /* TRANS2_REPORT_DFS_INCONSISTENCY */
4052 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4054 /* This is a UNICODE only request (bit15 of Flags2) */
4056 /* There is nothing we can do about this operation. The client is going to
4057 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
4058 * Unfortunately, there is really nothing we can do about it other then log it
4059 * somewhere. Even then I don't think there is anything for us to do.
4060 * So let's return an error value.
4063 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
4064 return CM_ERROR_BADOP;
4068 smb_ApplyV3DirListPatches(cm_scache_t *dscp, smb_dirListPatch_t **dirPatchespp,
4069 clientchar_t * tidPathp, clientchar_t * relPathp,
4070 int infoLevel, cm_user_t *userp, cm_req_t *reqp)
4074 cm_scache_t *targetScp; /* target if scp is a symlink */
4077 unsigned short attr;
4078 unsigned long lattr;
4079 smb_dirListPatch_t *patchp;
4080 smb_dirListPatch_t *npatchp;
4082 afs_int32 mustFake = 0;
4083 clientchar_t path[AFSPATHMAX];
4085 code = cm_FindACLCache(dscp, userp, &rights);
4087 lock_ObtainWrite(&dscp->rw);
4088 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4089 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4091 cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4092 lock_ReleaseWrite(&dscp->rw);
4093 if (code == CM_ERROR_NOACCESS) {
4101 if (!mustFake) { /* Bulk Stat */
4103 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4105 memset(bsp, 0, sizeof(cm_bulkStat_t));
4107 for (patchp = *dirPatchespp, count=0;
4109 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4110 cm_scache_t *tscp = NULL;
4113 code = cm_GetSCache(&patchp->fid, &tscp, userp, reqp);
4115 if (lock_TryWrite(&tscp->rw)) {
4116 /* we have an entry that we can look at */
4117 #ifdef AFS_FREELANCE_CLIENT
4118 if (dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID && dscp->fid.volume == AFS_FAKE_ROOT_VOL_ID) {
4119 code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
4120 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4122 cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4124 lock_ReleaseWrite(&tscp->rw);
4125 cm_ReleaseSCache(tscp);
4128 #endif /* AFS_FREELANCE_CLIENT */
4129 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4130 /* we have a callback on it. Don't bother
4131 * fetching this stat entry, since we're happy
4132 * with the info we have.
4134 lock_ReleaseWrite(&tscp->rw);
4135 cm_ReleaseSCache(tscp);
4138 lock_ReleaseWrite(&tscp->rw);
4140 cm_ReleaseSCache(tscp);
4144 bsp->fids[i].Volume = patchp->fid.volume;
4145 bsp->fids[i].Vnode = patchp->fid.vnode;
4146 bsp->fids[i].Unique = patchp->fid.unique;
4148 if (bsp->counter == AFSCBMAX) {
4149 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4150 memset(bsp, 0, sizeof(cm_bulkStat_t));
4154 if (bsp->counter > 0)
4155 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4160 for( patchp = *dirPatchespp;
4162 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4163 cm_ClientStrPrintfN(path, lengthof(path),_C("%s\\%S"),
4164 relPathp ? relPathp : _C(""), patchp->dep->name);
4165 reqp->relPathp = path;
4166 reqp->tidPathp = tidPathp;
4168 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4169 reqp->relPathp = reqp->tidPathp = NULL;
4173 lock_ObtainWrite(&scp->rw);
4174 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4175 lock_ReleaseWrite(&scp->rw);
4177 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4178 errors in the client. */
4179 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4180 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4182 /* 1969-12-31 23:59:59 +00 */
4183 ft.dwHighDateTime = 0x19DB200;
4184 ft.dwLowDateTime = 0x5BB78980;
4186 /* copy to Creation Time */
4187 fa->creationTime = ft;
4188 fa->lastAccessTime = ft;
4189 fa->lastWriteTime = ft;
4190 fa->lastChangeTime = ft;
4192 switch (scp->fileType) {
4193 case CM_SCACHETYPE_DIRECTORY:
4194 case CM_SCACHETYPE_MOUNTPOINT:
4195 case CM_SCACHETYPE_INVALID:
4196 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4198 case CM_SCACHETYPE_SYMLINK:
4199 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4200 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4202 fa->extFileAttributes = SMB_ATTR_NORMAL;
4205 /* if we get here we either have a normal file
4206 * or we have a file for which we have never
4207 * received status info. In this case, we can
4208 * check the even/odd value of the entry's vnode.
4209 * odd means it is to be treated as a directory
4210 * and even means it is to be treated as a file.
4212 if (mustFake && (scp->fid.vnode & 0x1))
4213 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4215 fa->extFileAttributes = SMB_ATTR_NORMAL;
4217 /* merge in hidden attribute */
4218 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4219 fa->extFileAttributes |= SMB_ATTR_HIDDEN;
4222 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4224 /* 1969-12-31 23:59:58 +00*/
4225 dosTime = 0xEBBFBF7D;
4227 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4228 fa->lastAccessDateTime = fa->creationDateTime;
4229 fa->lastWriteDateTime = fa->creationDateTime;
4231 /* set the attribute */
4232 switch (scp->fileType) {
4233 case CM_SCACHETYPE_DIRECTORY:
4234 case CM_SCACHETYPE_MOUNTPOINT:
4235 case CM_SCACHETYPE_INVALID:
4236 fa->attributes = SMB_ATTR_DIRECTORY;
4238 case CM_SCACHETYPE_SYMLINK:
4239 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4240 fa->attributes = SMB_ATTR_DIRECTORY;
4242 fa->attributes = SMB_ATTR_NORMAL;
4245 /* if we get here we either have a normal file
4246 * or we have a file for which we have never
4247 * received status info. In this case, we can
4248 * check the even/odd value of the entry's vnode.
4249 * even means it is to be treated as a directory
4250 * and odd means it is to be treated as a file.
4252 if (mustFake && (scp->fid.vnode & 0x1))
4253 fa->attributes = SMB_ATTR_DIRECTORY;
4255 fa->attributes = SMB_ATTR_NORMAL;
4258 /* merge in hidden (dot file) attribute */
4259 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4260 fa->attributes |= SMB_ATTR_HIDDEN;
4264 cm_ReleaseSCache(scp);
4268 /* now watch for a symlink */
4270 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
4271 lock_ReleaseWrite(&scp->rw);
4272 cm_ClientStrPrintfN(path, lengthof(path), _C("%s\\%S"),
4273 relPathp ? relPathp : _C(""), patchp->dep->name);
4274 reqp->relPathp = path;
4275 reqp->tidPathp = tidPathp;
4276 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
4277 reqp->relPathp = reqp->tidPathp = NULL;
4279 /* we have a more accurate file to use (the
4280 * target of the symbolic link). Otherwise,
4281 * we'll just use the symlink anyway.
4283 osi_Log2(smb_logp, "symlink vp %x to vp %x",
4285 cm_ReleaseSCache(scp);
4288 lock_ObtainWrite(&scp->rw);
4291 lock_ConvertWToR(&scp->rw);
4293 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4294 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4297 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4299 fa->creationTime = ft;
4300 fa->lastAccessTime = ft;
4301 fa->lastWriteTime = ft;
4302 fa->lastChangeTime = ft;
4304 /* Use length for both file length and alloc length */
4305 fa->endOfFile = scp->length;
4306 fa->allocationSize = scp->length;
4308 /* Copy attributes */
4309 lattr = smb_ExtAttributes(scp);
4310 if ((code == CM_ERROR_NOSUCHPATH &&
4311 (scp->fileType == CM_SCACHETYPE_SYMLINK &&
4312 cm_TargetPerceivedAsDirectory(scp->mountPointStringp))) ||
4313 code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4314 if (lattr == SMB_ATTR_NORMAL)
4315 lattr = SMB_ATTR_DIRECTORY;
4317 lattr |= SMB_ATTR_DIRECTORY;
4319 /* merge in hidden (dot file) attribute */
4320 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4321 if (lattr == SMB_ATTR_NORMAL)
4322 lattr = SMB_ATTR_HIDDEN;
4324 lattr |= SMB_ATTR_HIDDEN;
4327 fa->extFileAttributes = lattr;
4329 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4332 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4334 fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
4335 fa->lastAccessDateTime = fa->creationDateTime;
4336 fa->lastWriteDateTime = fa->creationDateTime;
4338 /* copy out file length and alloc length,
4339 * using the same for both
4341 fa->dataSize = scp->length.LowPart;
4342 fa->allocationSize = scp->length.LowPart;
4344 /* finally copy out attributes as short */
4345 attr = smb_Attributes(scp);
4346 /* merge in hidden (dot file) attribute */
4347 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4348 if (lattr == SMB_ATTR_NORMAL)
4349 lattr = SMB_ATTR_HIDDEN;
4351 lattr |= SMB_ATTR_HIDDEN;
4353 fa->attributes = attr;
4356 lock_ReleaseRead(&scp->rw);
4357 cm_ReleaseSCache(scp);
4360 /* now free the patches */
4361 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4362 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4366 /* and mark the list as empty */
4367 *dirPatchespp = NULL;
4373 /* smb_ReceiveTran2SearchDir implements both
4374 * Tran2_Find_First and Tran2_Find_Next
4376 #define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
4377 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
4378 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
4379 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
4380 #define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
4382 /* this is an optimized handler for T2SearchDir that handles the case
4383 where there are no wildcards in the search path. I.e. an
4384 application is using FindFirst(Ex) to get information about a
4385 single file or directory. It will attempt to do a single lookup.
4386 If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4387 the usual mechanism.
4389 This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4391 TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
4393 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4397 long code = 0, code2 = 0;
4398 clientchar_t *pathp = 0;
4400 smb_dirListPatch_t *dirListPatchesp;
4401 smb_dirListPatch_t *curPatchp;
4402 size_t orbytes; /* # of bytes in this output record */
4403 size_t ohbytes; /* # of bytes, except file name */
4404 size_t onbytes; /* # of bytes in name, incl. term. null */
4405 cm_scache_t *scp = NULL;
4406 cm_scache_t *targetscp = NULL;
4407 cm_user_t *userp = NULL;
4408 char *op; /* output data ptr */
4409 char *origOp; /* original value of op */
4410 cm_space_t *spacep; /* for pathname buffer */
4411 unsigned long maxReturnData; /* max # of return data */
4412 long maxReturnParms; /* max # of return parms */
4413 long bytesInBuffer; /* # data bytes in the output buffer */
4414 clientchar_t *maskp; /* mask part of path */
4418 smb_tran2Packet_t *outp; /* response packet */
4419 clientchar_t *tidPathp = 0;
4421 clientchar_t shortName[13]; /* 8.3 name if needed */
4423 clientchar_t *shortNameEnd;
4424 cm_dirEntry_t * dep = NULL;
4427 void * attrp = NULL;
4428 smb_tran2Find_t * fp;
4433 osi_assertx(p->opcode == 1, "invalid opcode");
4435 /* find first; obtain basic parameters from request */
4437 /* note that since we are going to failover to regular
4438 * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4439 * modify any of the input parameters here. */
4440 attribute = p->parmsp[0];
4441 maxCount = p->parmsp[1];
4442 infoLevel = p->parmsp[3];
4443 searchFlags = p->parmsp[2];
4444 pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4446 maskp = cm_ClientStrRChr(pathp, '\\');
4450 maskp++; /* skip over backslash */
4451 /* track if this is likely to match a lot of entries */
4453 osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%S], mask[%S]",
4454 osi_LogSaveClientString(smb_logp, pathp),
4455 osi_LogSaveClientString(smb_logp, maskp));
4457 switch ( infoLevel ) {
4458 case SMB_INFO_STANDARD:
4460 ohbytes = sizeof(fp->u.FstandardInfo);
4463 case SMB_INFO_QUERY_EA_SIZE:
4464 ohbytes = sizeof(fp->u.FeaSizeInfo);
4465 s = "InfoQueryEaSize";
4468 case SMB_INFO_QUERY_EAS_FROM_LIST:
4469 ohbytes = sizeof(fp->u.FeasFromListInfo);
4470 s = "InfoQueryEasFromList";
4473 case SMB_FIND_FILE_DIRECTORY_INFO:
4474 s = "FindFileDirectoryInfo";
4475 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4478 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4479 s = "FindFileFullDirectoryInfo";
4480 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4483 case SMB_FIND_FILE_NAMES_INFO:
4484 s = "FindFileNamesInfo";
4485 ohbytes = sizeof(fp->u.FfileNamesInfo);
4488 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4489 s = "FindFileBothDirectoryInfo";
4490 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4494 s = "unknownInfoLevel";
4498 osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
4501 "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4502 attribute, infoLevel, maxCount, searchFlags);
4505 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4506 return CM_ERROR_INVAL;
4509 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4510 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4512 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4515 dirListPatchesp = NULL;
4517 maxReturnData = p->maxReturnData;
4518 maxReturnParms = 10; /* return params for findfirst, which
4519 is the only one we handle.*/
4521 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4524 osi_Log2(smb_logp, "T2SDSingle search dir count %d [%S]",
4525 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4527 /* bail out if request looks bad */
4529 smb_FreeTran2Packet(outp);
4530 return CM_ERROR_BADSMB;
4533 userp = smb_GetTran2User(vcp, p);
4535 osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
4536 smb_FreeTran2Packet(outp);
4537 return CM_ERROR_BADSMB;
4540 /* try to get the vnode for the path name next */
4541 spacep = cm_GetSpace();
4542 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4543 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4545 cm_ReleaseUser(userp);
4546 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4547 smb_FreeTran2Packet(outp);
4551 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4552 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4553 userp, tidPathp, &req, &scp);
4554 cm_FreeSpace(spacep);
4557 cm_ReleaseUser(userp);
4558 smb_SendTran2Error(vcp, p, opx, code);
4559 smb_FreeTran2Packet(outp);
4563 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4564 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4565 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
4566 cm_ReleaseSCache(scp);
4567 cm_ReleaseUser(userp);
4568 if ( WANTS_DFS_PATHNAMES(p) || pnc )
4569 code = CM_ERROR_PATH_NOT_COVERED;
4571 code = CM_ERROR_BADSHARENAME;
4572 smb_SendTran2Error(vcp, p, opx, code);
4573 smb_FreeTran2Packet(outp);
4576 #endif /* DFS_SUPPORT */
4577 osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
4579 /* now do a single case sensitive lookup for the file in question */
4580 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
4582 /* if a case sensitive match failed, we try a case insensitive one
4584 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
4585 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
4588 if (code == 0 && targetscp->fid.vnode == 0) {
4589 cm_ReleaseSCache(targetscp);
4590 code = CM_ERROR_NOSUCHFILE;
4594 /* if we can't find the directory entry, this block will
4595 return CM_ERROR_NOSUCHFILE, which we will pass on to
4596 smb_ReceiveTran2SearchDir(). */
4597 cm_ReleaseSCache(scp);
4598 cm_ReleaseUser(userp);
4599 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4600 smb_SendTran2Error(vcp, p, opx, code);
4603 smb_FreeTran2Packet(outp);
4607 /* now that we have the target in sight, we proceed with filling
4608 up the return data. */
4610 op = origOp = outp->datap;
4613 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4614 /* skip over resume key */
4618 fp = (smb_tran2Find_t *) op;
4620 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4621 && targetscp->fid.vnode != 0
4622 && !cm_Is8Dot3(maskp)) {
4625 dfid.vnode = htonl(targetscp->fid.vnode);
4626 dfid.unique = htonl(targetscp->fid.unique);
4628 cm_Gen8Dot3NameIntW(maskp, &dfid, shortName, &shortNameEnd);
4634 osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %S (%S)",
4635 htonl(targetscp->fid.vnode),
4636 htonl(targetscp->fid.unique),
4637 osi_LogSaveClientString(smb_logp, pathp),
4638 (NeedShortName)? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
4640 /* Eliminate entries that don't match requested attributes */
4641 if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
4642 smb_IsDotFile(maskp)) {
4644 code = CM_ERROR_NOSUCHFILE;
4645 osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
4650 if (!(attribute & SMB_ATTR_DIRECTORY) &&
4651 (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
4652 targetscp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4653 targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
4654 targetscp->fileType == CM_SCACHETYPE_INVALID)) {
4656 code = CM_ERROR_NOSUCHFILE;
4657 osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
4662 /* add header to name & term. null */
4664 smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
4665 orbytes = ohbytes + onbytes;
4667 /* now, we round up the record to a 4 byte alignment, and we make
4668 * sure that we have enough room here for even the aligned version
4669 * (so we don't have to worry about an * overflow when we pad
4670 * things out below). That's the reason for the alignment
4673 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4674 align = (4 - (orbytes & 3)) & 3;
4678 if (orbytes + align > maxReturnData) {
4680 /* even though this request is unlikely to succeed with a
4681 failover, we do it anyway. */
4682 code = CM_ERROR_NOSUCHFILE;
4683 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4688 /* this is one of the entries to use: it is not deleted and it
4689 * matches the star pattern we're looking for. Put out the name,
4690 * preceded by its length.
4692 /* First zero everything else */
4693 memset(origOp, 0, orbytes);
4696 smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
4698 switch (infoLevel) {
4699 case SMB_INFO_STANDARD:
4700 fp->u.FstandardInfo.fileNameLength = onbytes;
4701 attrp = &fp->u.FstandardInfo.fileAttrs;
4704 case SMB_INFO_QUERY_EA_SIZE:
4705 fp->u.FeaSizeInfo.fileNameLength = onbytes;
4706 attrp = &fp->u.FeaSizeInfo.fileAttrs;
4707 fp->u.FeaSizeInfo.eaSize = 0;
4710 case SMB_INFO_QUERY_EAS_FROM_LIST:
4711 fp->u.FeasFromListInfo.fileNameLength = onbytes;
4712 attrp = &fp->u.FeasFromListInfo.fileAttrs;
4713 fp->u.FeasFromListInfo.eaSize = 0;
4716 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4717 if (NeedShortName) {
4721 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
4722 fp->u.FfileBothDirectoryInfo.shortName,
4723 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
4725 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
4727 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
4728 fp->u.FfileBothDirectoryInfo.reserved = 0;
4730 strcpy(fp->u.FfileBothDirectoryInfo.shortName,
4732 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
4737 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4738 fp->u.FfileFullDirectoryInfo.eaSize = 0;
4741 case SMB_FIND_FILE_DIRECTORY_INFO:
4742 fp->u.FfileDirectoryInfo.nextEntryOffset = 0;
4743 fp->u.FfileDirectoryInfo.fileIndex = 0;
4744 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
4745 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
4748 case SMB_FIND_FILE_NAMES_INFO:
4749 fp->u.FfileNamesInfo.nextEntryOffset = 0;
4750 fp->u.FfileNamesInfo.fileIndex = 0;
4751 fp->u.FfileNamesInfo.fileNameLength = onbytes;
4755 /* we shouldn't hit this case */
4756 osi_assertx(FALSE, "Unknown query type");
4759 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4760 osi_assert(attrp != NULL);
4762 curPatchp = malloc(sizeof(*curPatchp));
4763 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4765 curPatchp->dptr = attrp;
4767 if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
4768 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4770 curPatchp->flags = 0;
4773 cm_SetFid(&curPatchp->fid, targetscp->fid.cell, targetscp->fid.volume, targetscp->fid.vnode, targetscp->fid.unique);
4777 int namelen = cm_ClientStringToFsString(maskp, -1, NULL, 0);
4778 dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+namelen);
4779 cm_ClientStringToFsString(maskp, -1, dep->name, namelen);
4781 dep->fid.vnode = targetscp->fid.vnode;
4782 dep->fid.unique = targetscp->fid.unique;
4783 curPatchp->dep = dep;
4786 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4787 /* put out resume key */
4788 *((u_long *)origOp) = 0;
4791 /* Adjust byte ptr and count */
4792 origOp += orbytes; /* skip entire record */
4793 bytesInBuffer += orbytes;
4795 /* and pad the record out */
4796 while (--align >= 0) {
4801 /* apply the patches */
4802 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->wdata, infoLevel, userp, &req);
4804 outp->parmsp[0] = 0;
4805 outp->parmsp[1] = 1; /* number of names returned */
4806 outp->parmsp[2] = 1; /* end of search */
4807 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4808 outp->parmsp[4] = 0;
4810 outp->totalParms = 10; /* in bytes */
4812 outp->totalData = bytesInBuffer;
4814 osi_Log0(smb_logp, "T2SDSingle done.");
4816 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4818 smb_SendTran2Error(vcp, p, opx, code);
4820 smb_SendTran2Packet(vcp, outp, opx);
4825 smb_FreeTran2Packet(outp);
4829 cm_ReleaseSCache(scp);
4830 cm_ReleaseSCache(targetscp);
4831 cm_ReleaseUser(userp);
4837 /* TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2 */
4838 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4843 long code = 0, code2 = 0;
4844 clientchar_t *pathp;
4845 cm_dirEntry_t *dep = 0;
4847 smb_dirListPatch_t *dirListPatchesp = 0;
4848 smb_dirListPatch_t *curPatchp = 0;
4851 size_t orbytes; /* # of bytes in this output record */
4852 size_t ohbytes; /* # of bytes, except file name */
4853 size_t onbytes; /* # of bytes in name, incl. term. null */
4854 osi_hyper_t dirLength;
4855 osi_hyper_t bufferOffset;
4856 osi_hyper_t curOffset;
4858 smb_dirSearch_t *dsp;
4862 cm_pageHeader_t *pageHeaderp;
4863 cm_user_t *userp = NULL;
4866 long nextEntryCookie;
4867 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4868 char *op; /* output data ptr */
4869 char *origOp; /* original value of op */
4870 cm_space_t *spacep; /* for pathname buffer */
4871 unsigned long maxReturnData; /* max # of return data */
4872 unsigned long maxReturnParms; /* max # of return parms */
4873 long bytesInBuffer; /* # data bytes in the output buffer */
4875 clientchar_t *maskp; /* mask part of path */
4879 smb_tran2Packet_t *outp; /* response packet */
4880 clientchar_t *tidPathp;
4882 clientchar_t shortName[13]; /* 8.3 name if needed */
4885 clientchar_t *shortNameEnd;
4891 smb_tran2Find_t * fp;
4896 if (p->opcode == 1) {
4897 /* find first; obtain basic parameters from request */
4898 attribute = p->parmsp[0];
4899 maxCount = p->parmsp[1];
4900 infoLevel = p->parmsp[3];
4901 searchFlags = p->parmsp[2];
4902 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4904 maskp = cm_ClientStrRChr(pathp, '\\');
4908 maskp++; /* skip over backslash */
4910 /* track if this is likely to match a lot of entries */
4911 starPattern = smb_V3IsStarMask(maskp);
4913 #ifndef NOFINDFIRSTOPTIMIZE
4915 /* if this is for a single directory or file, we let the
4916 optimized routine handle it. The only error it
4917 returns is CM_ERROR_NOSUCHFILE. The */
4918 code = smb_T2SearchDirSingle(vcp, p, opx);
4920 /* we only failover if we see a CM_ERROR_NOSUCHFILE */
4921 if (code != CM_ERROR_NOSUCHFILE) {
4923 /* unless we are using the BPlusTree */
4924 if (code == CM_ERROR_BPLUS_NOMATCH)
4925 code = CM_ERROR_NOSUCHFILE;
4926 #endif /* USE_BPLUS */
4930 #endif /* NOFINDFIRSTOPTIMIZE */
4933 dsp = smb_NewDirSearch(1);
4934 dsp->attribute = attribute;
4935 cm_ClientStrCpy(dsp->mask, lengthof(dsp->mask), maskp); /* and save mask */
4938 osi_assertx(p->opcode == 2, "invalid opcode");
4939 /* find next; obtain basic parameters from request or open dir file */
4940 dsp = smb_FindDirSearch(p->parmsp[0]);
4941 maxCount = p->parmsp[1];
4942 infoLevel = p->parmsp[2];
4943 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4944 searchFlags = p->parmsp[5];
4946 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4947 p->parmsp[0], nextCookie);
4948 return CM_ERROR_BADFD;
4950 attribute = dsp->attribute;
4953 starPattern = 1; /* assume, since required a Find Next */
4956 switch ( infoLevel ) {
4957 case SMB_INFO_STANDARD:
4959 ohbytes = sizeof(fp->u.FstandardInfo);
4962 case SMB_INFO_QUERY_EA_SIZE:
4963 ohbytes = sizeof(fp->u.FeaSizeInfo);
4964 s = "InfoQueryEaSize";
4967 case SMB_INFO_QUERY_EAS_FROM_LIST:
4968 ohbytes = sizeof(fp->u.FeasFromListInfo);
4969 s = "InfoQueryEasFromList";
4972 case SMB_FIND_FILE_DIRECTORY_INFO:
4973 s = "FindFileDirectoryInfo";
4974 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4977 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4978 s = "FindFileFullDirectoryInfo";
4979 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4982 case SMB_FIND_FILE_NAMES_INFO:
4983 s = "FindFileNamesInfo";
4984 ohbytes = sizeof(fp->u.FfileNamesInfo);
4987 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4988 s = "FindFileBothDirectoryInfo";
4989 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4993 s = "unknownInfoLevel";
4997 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
5000 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
5001 attribute, infoLevel, maxCount, searchFlags);
5003 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
5004 p->opcode, dsp->cookie, nextCookie);
5007 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
5008 smb_ReleaseDirSearch(dsp);
5009 return CM_ERROR_INVAL;
5012 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5013 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
5015 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5018 dirListPatchesp = NULL;
5020 maxReturnData = p->maxReturnData;
5021 if (p->opcode == 1) /* find first */
5022 maxReturnParms = 10; /* bytes */
5024 maxReturnParms = 8; /* bytes */
5026 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
5032 osi_Log2(smb_logp, "T2 receive search dir count %d [%S]",
5033 maxCount, osi_LogSaveClientString(smb_logp, pathp));
5035 /* bail out if request looks bad */
5036 if (p->opcode == 1 && !pathp) {
5037 smb_ReleaseDirSearch(dsp);
5038 smb_FreeTran2Packet(outp);
5039 return CM_ERROR_BADSMB;
5042 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
5043 dsp->cookie, nextCookie, attribute);
5045 userp = smb_GetTran2User(vcp, p);
5047 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
5048 smb_ReleaseDirSearch(dsp);
5049 smb_FreeTran2Packet(outp);
5050 return CM_ERROR_BADSMB;
5053 /* try to get the vnode for the path name next */
5054 lock_ObtainMutex(&dsp->mx);
5057 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5061 spacep = cm_GetSpace();
5062 smb_StripLastComponent(spacep->wdata, NULL, pathp);
5063 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
5065 cm_ReleaseUser(userp);
5066 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
5067 smb_FreeTran2Packet(outp);
5068 lock_ReleaseMutex(&dsp->mx);
5069 smb_DeleteDirSearch(dsp);
5070 smb_ReleaseDirSearch(dsp);
5074 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
5075 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
5077 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
5078 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5079 userp, tidPathp, &req, &scp);
5080 cm_FreeSpace(spacep);
5083 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
5084 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5085 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
5086 cm_ReleaseSCache(scp);
5087 cm_ReleaseUser(userp);
5088 if ( WANTS_DFS_PATHNAMES(p) || pnc )
5089 code = CM_ERROR_PATH_NOT_COVERED;
5091 code = CM_ERROR_BADSHARENAME;
5092 smb_SendTran2Error(vcp, p, opx, code);
5093 smb_FreeTran2Packet(outp);
5094 lock_ReleaseMutex(&dsp->mx);
5095 smb_DeleteDirSearch(dsp);
5096 smb_ReleaseDirSearch(dsp);
5099 #endif /* DFS_SUPPORT */
5101 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5102 /* we need one hold for the entry we just stored into,
5103 * and one for our own processing. When we're done
5104 * with this function, we'll drop the one for our own
5105 * processing. We held it once from the namei call,
5106 * and so we do another hold now.
5109 dsp->flags |= SMB_DIRSEARCH_BULKST;
5112 lock_ReleaseMutex(&dsp->mx);
5114 cm_ReleaseUser(userp);
5115 smb_FreeTran2Packet(outp);
5116 smb_DeleteDirSearch(dsp);
5117 smb_ReleaseDirSearch(dsp);
5121 /* get the directory size */
5122 lock_ObtainWrite(&scp->rw);
5123 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5124 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5126 lock_ReleaseWrite(&scp->rw);
5127 cm_ReleaseSCache(scp);
5128 cm_ReleaseUser(userp);
5129 smb_FreeTran2Packet(outp);
5130 smb_DeleteDirSearch(dsp);
5131 smb_ReleaseDirSearch(dsp);
5135 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5138 dirLength = scp->length;
5140 bufferOffset.LowPart = bufferOffset.HighPart = 0;
5141 curOffset.HighPart = 0;
5142 curOffset.LowPart = nextCookie;
5143 origOp = outp->datap;
5150 normchar_t normName[MAX_PATH]; /* Normalized name */
5151 clientchar_t cfileName[MAX_PATH]; /* Non-normalized name */
5154 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5155 /* skip over resume key */
5158 fp = (smb_tran2Find_t *) op;
5160 /* make sure that curOffset.LowPart doesn't point to the first
5161 * 32 bytes in the 2nd through last dir page, and that it doesn't
5162 * point at the first 13 32-byte chunks in the first dir page,
5163 * since those are dir and page headers, and don't contain useful
5166 temp = curOffset.LowPart & (2048-1);
5167 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5168 /* we're in the first page */
5169 if (temp < 13*32) temp = 13*32;
5172 /* we're in a later dir page */
5173 if (temp < 32) temp = 32;
5176 /* make sure the low order 5 bits are zero */
5179 /* now put temp bits back ito curOffset.LowPart */
5180 curOffset.LowPart &= ~(2048-1);
5181 curOffset.LowPart |= temp;
5183 /* check if we've passed the dir's EOF */
5184 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
5185 osi_Log0(smb_logp, "T2 search dir passed eof");
5190 /* check if we've returned all the names that will fit in the
5191 * response packet; we check return count as well as the number
5192 * of bytes requested. We check the # of bytes after we find
5193 * the dir entry, since we'll need to check its size.
5195 if (returnedNames >= maxCount) {
5196 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
5197 returnedNames, maxCount);
5201 /* when we have obtained as many entries as can be processed in
5202 * a single Bulk Status call to the file server, apply the dir listing
5205 if (returnedNames > 0 && returnedNames % AFSCBMAX == 0) {
5206 lock_ReleaseWrite(&scp->rw);
5207 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5208 dsp->relPath, infoLevel, userp, &req);
5209 lock_ObtainWrite(&scp->rw);
5211 /* Then check to see if we have time left to process more entries */
5212 if (GetTickCount() - req.startTime > (RDRtimeout - 15) * 1000) {
5213 osi_Log0(smb_logp, "T2 search dir RDRtimeout exceeded");
5217 /* see if we can use the bufferp we have now; compute in which
5218 * page the current offset would be, and check whether that's
5219 * the offset of the buffer we have. If not, get the buffer.
5221 thyper.HighPart = curOffset.HighPart;
5222 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5223 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5226 buf_Release(bufferp);
5229 lock_ReleaseWrite(&scp->rw);
5230 code = buf_Get(scp, &thyper, &bufferp);
5231 lock_ObtainWrite(&scp->rw);
5233 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
5237 bufferOffset = thyper;
5239 /* now get the data in the cache */
5241 code = cm_SyncOp(scp, bufferp, userp, &req,
5243 CM_SCACHESYNC_NEEDCALLBACK
5244 | CM_SCACHESYNC_READ);
5246 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5250 if (cm_HaveBuffer(scp, bufferp, 0)) {
5251 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5252 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5256 /* otherwise, load the buffer and try again */
5257 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5259 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5261 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5262 scp, bufferp, code);
5267 buf_Release(bufferp);
5271 } /* if (wrong buffer) ... */
5273 /* now we have the buffer containing the entry we're interested
5274 * in; copy it out if it represents a non-deleted entry.
5276 entryInDir = curOffset.LowPart & (2048-1);
5277 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5279 /* page header will help tell us which entries are free. Page
5280 * header can change more often than once per buffer, since
5281 * AFS 3 dir page size may be less than (but not more than)
5282 * a buffer package buffer.
5284 /* only look intra-buffer */
5285 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5286 temp &= ~(2048 - 1); /* turn off intra-page bits */
5287 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5289 /* now determine which entry we're looking at in the page.
5290 * If it is free (there's a free bitmap at the start of the
5291 * dir), we should skip these 32 bytes.
5293 slotInPage = (entryInDir & 0x7e0) >> 5;
5294 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5295 (1 << (slotInPage & 0x7)))) {
5296 /* this entry is free */
5297 numDirChunks = 1; /* only skip this guy */
5301 tp = bufferp->datap + entryInBuffer;
5302 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5304 /* while we're here, compute the next entry's location, too,
5305 * since we'll need it when writing out the cookie into the dir
5308 * XXXX Probably should do more sanity checking.
5310 numDirChunks = cm_NameEntries(dep->name, &onbytes);
5312 /* compute offset of cookie representing next entry */
5313 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5315 if (dep->fid.vnode == 0)
5316 goto nextEntry; /* This entry is not in use */
5318 if (cm_FsStringToClientString(dep->name, -1, cfileName, lengthof(cfileName)) == 0 ||
5319 cm_ClientStringToNormString(cfileName, -1, normName, lengthof(normName)) == 0) {
5321 osi_Log1(smb_logp, "Skipping entry [%s]. Can't convert or normalize FS String",
5322 osi_LogSaveString(smb_logp, dep->name));
5326 /* Need 8.3 name? */
5328 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
5329 !cm_Is8Dot3(cfileName)) {
5330 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5334 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %S (%S)",
5335 dep->fid.vnode, dep->fid.unique,
5336 osi_LogSaveClientString(smb_logp, cfileName),
5337 NeedShortName ? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
5339 /* When matching, we are using doing a case fold if we have a wildcard mask.
5340 * If we get a non-wildcard match, it's a lookup for a specific file.
5342 if (cm_MatchMask(normName, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5343 (NeedShortName && cm_MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))
5345 /* Eliminate entries that don't match requested attributes */
5346 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5347 smb_IsDotFile(cfileName)) {
5348 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5349 goto nextEntry; /* no hidden files */
5352 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5354 /* We have already done the cm_TryBulkStat above */
5355 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume,
5356 ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5357 fileType = cm_FindFileType(&fid);
5358 /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5359 * "has filetype %d", dep->name, fileType);
5361 if ( fileType == CM_SCACHETYPE_DIRECTORY ||
5362 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5363 fileType == CM_SCACHETYPE_DFSLINK ||
5364 fileType == CM_SCACHETYPE_INVALID)
5365 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5369 /* finally check if this name will fit */
5371 smb_UnparseString(opx, NULL, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5372 orbytes = ohbytes + onbytes;
5374 /* now, we round up the record to a 4 byte alignment,
5375 * and we make sure that we have enough room here for
5376 * even the aligned version (so we don't have to worry
5377 * about an overflow when we pad things out below).
5378 * That's the reason for the alignment arithmetic below.
5380 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5381 align = (4 - (orbytes & 3)) & 3;
5385 if (orbytes + bytesInBuffer + align > maxReturnData) {
5386 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5391 /* this is one of the entries to use: it is not deleted
5392 * and it matches the star pattern we're looking for.
5393 * Put out the name, preceded by its length.
5395 /* First zero everything else */
5396 memset(origOp, 0, orbytes);
5399 smb_UnparseString(opx, origOp + ohbytes, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5401 switch (infoLevel) {
5402 case SMB_INFO_STANDARD:
5403 fp->u.FstandardInfo.fileNameLength = onbytes;
5404 attrp = &fp->u.FstandardInfo.fileAttrs;
5407 case SMB_INFO_QUERY_EA_SIZE:
5408 fp->u.FeaSizeInfo.fileNameLength = onbytes;
5409 attrp = &fp->u.FeaSizeInfo.fileAttrs;
5410 fp->u.FeaSizeInfo.eaSize = 0;
5413 case SMB_INFO_QUERY_EAS_FROM_LIST:
5414 fp->u.FeasFromListInfo.fileNameLength = onbytes;
5415 attrp = &fp->u.FeasFromListInfo.fileAttrs;
5416 fp->u.FeasFromListInfo.eaSize = 0;
5419 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5420 if (NeedShortName) {
5424 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
5425 fp->u.FfileBothDirectoryInfo.shortName,
5426 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
5428 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
5430 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5431 fp->u.FfileBothDirectoryInfo.reserved = 0;
5433 cm_ClientStrCpy(fp->u.FfileBothDirectoryInfo.shortName,
5434 lengthof(fp->u.FfileBothDirectoryInfo.shortName),
5436 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
5441 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5442 fp->u.FfileFullDirectoryInfo.eaSize = 0;
5445 case SMB_FIND_FILE_DIRECTORY_INFO:
5446 fp->u.FfileDirectoryInfo.nextEntryOffset = orbytes + align;
5447 fp->u.FfileDirectoryInfo.fileIndex = nextEntryCookie;
5448 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5449 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5452 case SMB_FIND_FILE_NAMES_INFO:
5453 fp->u.FfileNamesInfo.nextEntryOffset = orbytes + align;
5454 fp->u.FfileNamesInfo.fileIndex = nextEntryCookie;
5455 fp->u.FfileNamesInfo.fileNameLength = onbytes;
5460 /* we shouldn't hit this case */
5461 osi_assertx(FALSE, "Unknown query type");
5464 /* now, adjust the # of entries copied */
5467 /* now we emit the attribute. This is tricky, since
5468 * we need to really stat the file to find out what
5469 * type of entry we've got. Right now, we're copying
5470 * out data from a buffer, while holding the scp
5471 * locked, so it isn't really convenient to stat
5472 * something now. We'll put in a place holder
5473 * now, and make a second pass before returning this
5474 * to get the real attributes. So, we just skip the
5475 * data for now, and adjust it later. We allocate a
5476 * patch record to make it easy to find this point
5477 * later. The replay will happen at a time when it is
5478 * safe to unlock the directory.
5480 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5481 osi_assert(attrp != NULL);
5482 curPatchp = malloc(sizeof(*curPatchp));
5483 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5484 curPatchp->dptr = attrp;
5486 if (smb_hideDotFiles && smb_IsDotFile(cfileName)) {
5487 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5489 curPatchp->flags = 0;
5492 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5495 curPatchp->dep = dep;
5498 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5499 /* put out resume key */
5500 *((u_long *)origOp) = nextEntryCookie;
5502 /* Adjust byte ptr and count */
5503 origOp += orbytes; /* skip entire record */
5504 bytesInBuffer += orbytes;
5506 /* and pad the record out */
5507 while (align-- > 0) {
5511 } /* if we're including this name */
5512 else if (!starPattern &&
5514 cm_MatchMask(normName, maskp, CM_FLAG_CASEFOLD)) {
5515 /* We were looking for exact matches, but here's an inexact one*/
5520 /* and adjust curOffset to be where the new cookie is */
5521 thyper.HighPart = 0;
5522 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5523 curOffset = LargeIntegerAdd(thyper, curOffset);
5524 } /* while copying data for dir listing */
5526 /* If we didn't get a star pattern, we did an exact match during the first pass.
5527 * If there were no exact matches found, we fail over to inexact matches by
5528 * marking the query as a star pattern (matches all case permutations), and
5529 * re-running the query.
5531 if (returnedNames == 0 && !starPattern && foundInexact) {
5532 osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
5537 /* release the mutex */
5538 lock_ReleaseWrite(&scp->rw);
5540 buf_Release(bufferp);
5545 * Finally, process whatever entries we have left.
5547 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5548 dsp->relPath, infoLevel, userp, &req);
5550 /* now put out the final parameters */
5551 if (returnedNames == 0)
5553 if (p->opcode == 1) {
5555 outp->parmsp[0] = (unsigned short) dsp->cookie;
5556 outp->parmsp[1] = returnedNames;
5557 outp->parmsp[2] = eos;
5558 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5559 outp->parmsp[4] = 0;
5560 /* don't need last name to continue
5561 * search, cookie is enough. Normally,
5562 * this is the offset of the file name
5563 * of the last entry returned.
5565 outp->totalParms = 10; /* in bytes */
5569 outp->parmsp[0] = returnedNames;
5570 outp->parmsp[1] = eos;
5571 outp->parmsp[2] = 0; /* EAS error */
5572 outp->parmsp[3] = 0; /* last name, as above */
5573 outp->totalParms = 8; /* in bytes */
5576 /* return # of bytes in the buffer */
5577 outp->totalData = bytesInBuffer;
5579 /* Return error code if unsuccessful on first request */
5580 if (code == 0 && p->opcode == 1 && returnedNames == 0)
5581 code = CM_ERROR_NOSUCHFILE;
5583 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
5584 p->opcode, dsp->cookie, returnedNames, code);
5586 /* if we're supposed to close the search after this request, or if
5587 * we're supposed to close the search if we're done, and we're done,
5588 * or if something went wrong, close the search.
5590 if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
5591 (returnedNames == 0) ||
5592 ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
5594 smb_DeleteDirSearch(dsp);
5597 smb_SendTran2Error(vcp, p, opx, code);
5599 smb_SendTran2Packet(vcp, outp, opx);
5601 smb_FreeTran2Packet(outp);
5602 smb_ReleaseDirSearch(dsp);
5603 cm_ReleaseSCache(scp);
5604 cm_ReleaseUser(userp);
5608 /* SMB_COM_FIND_CLOSE2 */
5609 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5612 smb_dirSearch_t *dsp;
5614 dirHandle = smb_GetSMBParm(inp, 0);
5616 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
5618 dsp = smb_FindDirSearch(dirHandle);
5621 return CM_ERROR_BADFD;
5623 /* otherwise, we have an FD to destroy */
5624 smb_DeleteDirSearch(dsp);
5625 smb_ReleaseDirSearch(dsp);
5627 /* and return results */
5628 smb_SetSMBDataLength(outp, 0);
5634 /* SMB_COM_FIND_NOTIFY_CLOSE */
5635 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5637 smb_SetSMBDataLength(outp, 0);
5641 /* SMB_COM_OPEN_ANDX */
5642 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5644 clientchar_t *pathp;
5649 cm_scache_t *dscp; /* dir we're dealing with */
5650 cm_scache_t *scp; /* file we're creating */
5652 int initialModeBits;
5655 clientchar_t *lastNamep;
5656 unsigned long dosTime;
5662 int parmSlot; /* which parm we're dealing with */
5663 clientchar_t *tidPathp;
5671 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
5672 openFun = smb_GetSMBParm(inp, 8); /* open function */
5673 excl = ((openFun & 3) == 0);
5674 trunc = ((openFun & 3) == 2); /* truncate it */
5675 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
5676 openAction = 0; /* tracks what we did */
5678 attributes = smb_GetSMBParm(inp, 5);
5679 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
5681 /* compute initial mode bits based on read-only flag in attributes */
5682 initialModeBits = 0666;
5683 if (attributes & SMB_ATTR_READONLY)
5684 initialModeBits &= ~0222;
5686 pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
5689 return CM_ERROR_BADSMB;
5691 spacep = inp->spacep;
5692 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5695 (cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
5696 cm_ClientStrCmpIA(lastNamep, _C("\\srvsvc")) == 0 ||
5697 cm_ClientStrCmpIA(lastNamep, _C("\\wkssvc")) == 0 ||
5698 cm_ClientStrCmpIA(lastNamep, _C("ipc$")) == 0)) {
5699 /* special case magic file name for receiving IOCTL requests
5700 * (since IOCTL calls themselves aren't getting through).
5703 osi_Log0(smb_logp, "IOCTL Open");
5706 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5707 smb_SetupIoctlFid(fidp, spacep);
5709 /* set inp->fid so that later read calls in same msg can find fid */
5710 inp->fid = fidp->fid;
5712 /* copy out remainder of the parms */
5714 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5716 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
5717 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
5718 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5719 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
5720 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
5721 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5722 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5723 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5725 /* and the final "always present" stuff */
5726 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
5727 /* next write out the "unique" ID */
5728 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
5729 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
5730 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5731 smb_SetSMBDataLength(outp, 0);
5733 /* and clean up fid reference */
5734 smb_ReleaseFID(fidp);
5738 if (!cm_IsValidClientString(pathp)) {
5740 clientchar_t * hexp;
5742 hexp = cm_GetRawCharsAlloc(pathp, -1);
5743 osi_Log1(smb_logp, "NTOpenX rejecting invalid name. [%S]",
5744 osi_LogSaveClientString(smb_logp, hexp));
5748 osi_Log0(smb_logp, "NTOpenX rejecting invalid name");
5750 return CM_ERROR_BADNTFILENAME;
5753 #ifdef DEBUG_VERBOSE
5755 char *hexp, *asciip;
5756 asciip = (lastNamep ? lastNamep : pathp );
5757 hexp = osi_HexifyString(asciip);
5758 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
5762 userp = smb_GetUserFromVCP(vcp, inp);
5765 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5767 cm_ReleaseUser(userp);
5768 return CM_ERROR_NOSUCHPATH;
5770 code = cm_NameI(cm_data.rootSCachep, pathp,
5771 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5772 userp, tidPathp, &req, &scp);
5775 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5776 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5777 cm_ReleaseSCache(scp);
5778 cm_ReleaseUser(userp);
5779 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5780 return CM_ERROR_PATH_NOT_COVERED;
5782 return CM_ERROR_BADSHARENAME;
5784 #endif /* DFS_SUPPORT */
5787 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
5788 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5789 userp, tidPathp, &req, &dscp);
5791 cm_ReleaseUser(userp);
5796 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5797 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5799 cm_ReleaseSCache(dscp);
5800 cm_ReleaseUser(userp);
5801 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5802 return CM_ERROR_PATH_NOT_COVERED;
5804 return CM_ERROR_BADSHARENAME;
5806 #endif /* DFS_SUPPORT */
5807 /* otherwise, scp points to the parent directory. Do a lookup,
5808 * and truncate the file if we find it, otherwise we create the
5815 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
5817 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5818 cm_ReleaseSCache(dscp);
5819 cm_ReleaseUser(userp);
5824 /* if we get here, if code is 0, the file exists and is represented by
5825 * scp. Otherwise, we have to create it. The dir may be represented
5826 * by dscp, or we may have found the file directly. If code is non-zero,
5830 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
5832 if (dscp) cm_ReleaseSCache(dscp);
5833 cm_ReleaseSCache(scp);
5834 cm_ReleaseUser(userp);
5839 /* oops, file shouldn't be there */
5841 cm_ReleaseSCache(dscp);
5842 cm_ReleaseSCache(scp);
5843 cm_ReleaseUser(userp);
5844 return CM_ERROR_EXISTS;
5848 setAttr.mask = CM_ATTRMASK_LENGTH;
5849 setAttr.length.LowPart = 0;
5850 setAttr.length.HighPart = 0;
5851 code = cm_SetAttr(scp, &setAttr, userp, &req);
5852 openAction = 3; /* truncated existing file */
5854 else openAction = 1; /* found existing file */
5856 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
5857 /* don't create if not found */
5858 if (dscp) cm_ReleaseSCache(dscp);
5859 cm_ReleaseUser(userp);
5860 return CM_ERROR_NOSUCHFILE;
5863 osi_assertx(dscp != NULL, "null cm_scache_t");
5864 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %S",
5865 osi_LogSaveClientString(smb_logp, lastNamep));
5866 openAction = 2; /* created file */
5867 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5868 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5869 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5873 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5874 smb_NotifyChange(FILE_ACTION_ADDED,
5875 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5876 dscp, lastNamep, NULL, TRUE);
5877 } else if (!excl && code == CM_ERROR_EXISTS) {
5878 /* not an exclusive create, and someone else tried
5879 * creating it already, then we open it anyway. We
5880 * don't bother retrying after this, since if this next
5881 * fails, that means that the file was deleted after we
5882 * started this call.
5884 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5888 setAttr.mask = CM_ATTRMASK_LENGTH;
5889 setAttr.length.LowPart = 0;
5890 setAttr.length.HighPart = 0;
5891 code = cm_SetAttr(scp, &setAttr, userp, &req);
5893 } /* lookup succeeded */
5897 /* we don't need this any longer */
5899 cm_ReleaseSCache(dscp);
5902 /* something went wrong creating or truncating the file */
5904 cm_ReleaseSCache(scp);
5905 cm_ReleaseUser(userp);
5909 /* make sure we're about to open a file */
5910 if (scp->fileType != CM_SCACHETYPE_FILE) {
5911 cm_ReleaseSCache(scp);
5912 cm_ReleaseUser(userp);
5913 return CM_ERROR_ISDIR;
5916 /* now all we have to do is open the file itself */
5917 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5918 osi_assertx(fidp, "null smb_fid_t");
5921 lock_ObtainMutex(&fidp->mx);
5922 /* save a pointer to the vnode */
5924 lock_ObtainWrite(&scp->rw);
5925 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5926 lock_ReleaseWrite(&scp->rw);
5927 osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
5929 fidp->userp = userp;
5931 /* compute open mode */
5933 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5934 if (openMode == 1 || openMode == 2)
5935 fidp->flags |= SMB_FID_OPENWRITE;
5937 /* remember if the file was newly created */
5939 fidp->flags |= SMB_FID_CREATED;
5941 lock_ReleaseMutex(&fidp->mx);
5942 smb_ReleaseFID(fidp);
5944 cm_Open(scp, 0, userp);
5946 /* set inp->fid so that later read calls in same msg can find fid */
5947 inp->fid = fidp->fid;
5949 /* copy out remainder of the parms */
5951 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5952 lock_ObtainRead(&scp->rw);
5954 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5955 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5956 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5957 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5958 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5959 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5960 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5961 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5962 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5964 /* and the final "always present" stuff */
5965 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5966 /* next write out the "unique" ID */
5967 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5968 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5969 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5970 lock_ReleaseRead(&scp->rw);
5971 smb_SetSMBDataLength(outp, 0);
5973 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5975 cm_ReleaseUser(userp);
5976 /* leave scp held since we put it in fidp->scp */
5980 static void smb_GetLockParams(unsigned char LockType,
5982 unsigned int * ppid,
5983 LARGE_INTEGER * pOffset,
5984 LARGE_INTEGER * pLength)
5986 if (LockType & LOCKING_ANDX_LARGE_FILES) {
5988 *ppid = *((USHORT *) *buf);
5989 pOffset->HighPart = *((LONG *)(*buf + 4));
5990 pOffset->LowPart = *((DWORD *)(*buf + 8));
5991 pLength->HighPart = *((LONG *)(*buf + 12));
5992 pLength->LowPart = *((DWORD *)(*buf + 16));
5996 /* Not Large Files */
5997 *ppid = *((USHORT *) *buf);
5998 pOffset->HighPart = 0;
5999 pOffset->LowPart = *((DWORD *)(*buf + 2));
6000 pLength->HighPart = 0;
6001 pLength->LowPart = *((DWORD *)(*buf + 6));
6006 /* SMB_COM_LOCKING_ANDX */
6007 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6014 unsigned char LockType;
6015 unsigned short NumberOfUnlocks, NumberOfLocks;
6019 LARGE_INTEGER LOffset, LLength;
6020 smb_waitingLockRequest_t *wlRequest = NULL;
6021 cm_file_lock_t *lockp;
6029 fid = smb_GetSMBParm(inp, 2);
6030 fid = smb_ChainFID(fid, inp);
6032 fidp = smb_FindFID(vcp, fid, 0);
6034 return CM_ERROR_BADFD;
6036 lock_ObtainMutex(&fidp->mx);
6037 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6038 lock_ReleaseMutex(&fidp->mx);
6039 smb_CloseFID(vcp, fidp, NULL, 0);
6040 smb_ReleaseFID(fidp);
6041 return CM_ERROR_NOSUCHFILE;
6044 if (fidp->flags & SMB_FID_IOCTL) {
6045 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
6046 lock_ReleaseMutex(&fidp->mx);
6047 smb_ReleaseFID(fidp);
6048 return CM_ERROR_BADFD;
6051 osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
6053 lock_ReleaseMutex(&fidp->mx);
6055 /* set inp->fid so that later read calls in same msg can find fid */
6058 userp = smb_GetUserFromVCP(vcp, inp);
6060 lock_ObtainWrite(&scp->rw);
6061 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6062 CM_SCACHESYNC_NEEDCALLBACK
6063 | CM_SCACHESYNC_GETSTATUS
6064 | CM_SCACHESYNC_LOCK);
6066 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
6070 LockType = smb_GetSMBParm(inp, 3) & 0xff;
6071 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
6072 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
6073 NumberOfLocks = smb_GetSMBParm(inp, 7);
6075 if (!(fidp->flags & SMB_FID_OPENWRITE) &&
6076 !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
6077 /* somebody wants exclusive locks on a file that they only
6078 opened for reading. We downgrade this to a shared lock. */
6079 osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
6080 LockType |= LOCKING_ANDX_SHARED_LOCK;
6083 if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
6084 /* AFS does not support atomic changes of lock types from read or write and vice-versa */
6085 osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]");
6086 code = CM_ERROR_BADOP;
6091 op = smb_GetSMBData(inp, NULL);
6093 if (LockType & LOCKING_ANDX_CANCEL_LOCK) {
6094 /* Cancel outstanding lock requests */
6095 smb_waitingLock_t * wl;
6097 for (i=0; i<NumberOfLocks; i++) {
6098 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6100 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6102 lock_ObtainWrite(&smb_globalLock);
6103 for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
6105 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
6106 if (cm_KeyEquals(&wl->key, &key, 0) && LargeIntegerEqualTo(wl->LOffset, LOffset) &&
6107 LargeIntegerEqualTo(wl->LLength, LLength)) {
6108 wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
6109 goto found_lock_request;
6114 lock_ReleaseWrite(&smb_globalLock);
6117 smb_SetSMBDataLength(outp, 0);
6122 for (i=0; i<NumberOfUnlocks; i++) {
6123 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6125 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6127 code = cm_Unlock(scp, LockType, LOffset, LLength, key, 0, userp, &req);
6135 for (i=0; i<NumberOfLocks; i++) {
6136 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6138 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6140 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
6141 userp, &req, &lockp);
6143 if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
6144 (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
6146 code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
6147 userp, &req, &lockp);
6150 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
6151 smb_waitingLock_t * wLock;
6153 /* Put on waiting list */
6154 if(wlRequest == NULL) {
6158 LARGE_INTEGER tOffset, tLength;
6160 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
6162 osi_assertx(wlRequest != NULL, "null wlRequest");
6164 wlRequest->vcp = vcp;
6166 wlRequest->scp = scp;
6167 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
6169 wlRequest->inp = smb_CopyPacket(inp);
6170 wlRequest->outp = smb_CopyPacket(outp);
6171 wlRequest->lockType = LockType;
6172 wlRequest->msTimeout = Timeout;
6173 wlRequest->start_t = osi_Time();
6174 wlRequest->locks = NULL;
6176 /* The waiting lock request needs to have enough
6177 information to undo all the locks in the request.
6178 We do the following to store info about locks that
6179 have already been granted. Sure, we can get most
6180 of the info from the packet, but the packet doesn't
6181 hold the result of cm_Lock call. In practice we
6182 only receive packets with one or two locks, so we
6183 are only wasting a few bytes here and there and
6184 only for a limited period of time until the waiting
6185 lock times out or is freed. */
6187 for(opt = op_locks, j=i; j > 0; j--) {
6188 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
6190 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6192 wLock = malloc(sizeof(smb_waitingLock_t));
6194 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6197 wLock->LOffset = tOffset;
6198 wLock->LLength = tLength;
6199 wLock->lockp = NULL;
6200 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
6201 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6206 wLock = malloc(sizeof(smb_waitingLock_t));
6208 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6211 wLock->LOffset = LOffset;
6212 wLock->LLength = LLength;
6213 wLock->lockp = lockp;
6214 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
6215 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6218 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
6226 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
6233 /* Since something went wrong with the lock number i, we now
6234 have to go ahead and release any locks acquired before the
6235 failure. All locks before lock number i (of which there
6236 are i of them) have either been successful or are waiting.
6237 Either case requires calling cm_Unlock(). */
6239 /* And purge the waiting lock */
6240 if(wlRequest != NULL) {
6241 smb_waitingLock_t * wl;
6242 smb_waitingLock_t * wlNext;
6245 for(wl = wlRequest->locks; wl; wl = wlNext) {
6247 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
6249 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, 0, userp, &req);
6252 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
6254 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
6257 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
6262 smb_ReleaseVC(wlRequest->vcp);
6263 cm_ReleaseSCache(wlRequest->scp);
6264 smb_FreePacket(wlRequest->inp);
6265 smb_FreePacket(wlRequest->outp);
6274 if (wlRequest != NULL) {
6276 lock_ObtainWrite(&smb_globalLock);
6277 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
6279 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
6280 lock_ReleaseWrite(&smb_globalLock);
6282 /* don't send reply immediately */
6283 outp->flags |= SMB_PACKETFLAG_NOSEND;
6286 smb_SetSMBDataLength(outp, 0);
6290 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
6293 lock_ReleaseWrite(&scp->rw);
6294 cm_ReleaseSCache(scp);
6295 cm_ReleaseUser(userp);
6296 smb_ReleaseFID(fidp);
6301 /* SMB_COM_QUERY_INFORMATION2 */
6302 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6308 afs_uint32 searchTime;
6315 fid = smb_GetSMBParm(inp, 0);
6316 fid = smb_ChainFID(fid, inp);
6318 fidp = smb_FindFID(vcp, fid, 0);
6320 return CM_ERROR_BADFD;
6322 lock_ObtainMutex(&fidp->mx);
6323 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6324 lock_ReleaseMutex(&fidp->mx);
6325 smb_CloseFID(vcp, fidp, NULL, 0);
6326 smb_ReleaseFID(fidp);
6327 return CM_ERROR_NOSUCHFILE;
6330 if (fidp->flags & SMB_FID_IOCTL) {
6331 lock_ReleaseMutex(&fidp->mx);
6332 smb_ReleaseFID(fidp);
6333 return CM_ERROR_BADFD;
6336 osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6338 lock_ReleaseMutex(&fidp->mx);
6340 userp = smb_GetUserFromVCP(vcp, inp);
6343 /* otherwise, stat the file */
6344 lock_ObtainWrite(&scp->rw);
6345 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6346 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6350 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6352 lock_ConvertWToR(&scp->rw);
6355 /* decode times. We need a search time, but the response to this
6356 * call provides the date first, not the time, as returned in the
6357 * searchTime variable. So we take the high-order bits first.
6359 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
6360 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
6361 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
6362 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
6363 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
6364 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
6365 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
6367 /* now handle file size and allocation size */
6368 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
6369 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
6370 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
6371 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
6373 /* file attribute */
6374 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
6376 /* and finalize stuff */
6377 smb_SetSMBDataLength(outp, 0);
6382 lock_ReleaseRead(&scp->rw);
6384 lock_ReleaseWrite(&scp->rw);
6385 cm_ReleaseSCache(scp);
6386 cm_ReleaseUser(userp);
6387 smb_ReleaseFID(fidp);
6391 /* SMB_COM_SET_INFORMATION2 */
6392 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6398 afs_uint32 searchTime;
6406 fid = smb_GetSMBParm(inp, 0);
6407 fid = smb_ChainFID(fid, inp);
6409 fidp = smb_FindFID(vcp, fid, 0);
6411 return CM_ERROR_BADFD;
6413 lock_ObtainMutex(&fidp->mx);
6414 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6415 lock_ReleaseMutex(&fidp->mx);
6416 smb_CloseFID(vcp, fidp, NULL, 0);
6417 smb_ReleaseFID(fidp);
6418 return CM_ERROR_NOSUCHFILE;
6421 if (fidp->flags & SMB_FID_IOCTL) {
6422 lock_ReleaseMutex(&fidp->mx);
6423 smb_ReleaseFID(fidp);
6424 return CM_ERROR_BADFD;
6427 osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6429 lock_ReleaseMutex(&fidp->mx);
6431 userp = smb_GetUserFromVCP(vcp, inp);
6433 /* now prepare to call cm_setattr. This message only sets various times,
6434 * and AFS only implements mtime, and we'll set the mtime if that's
6435 * requested. The others we'll ignore.
6437 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
6439 if (searchTime != 0) {
6440 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
6442 if ( unixTime != -1 ) {
6443 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
6444 attrs.clientModTime = unixTime;
6445 code = cm_SetAttr(scp, &attrs, userp, &req);
6447 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
6449 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
6455 cm_ReleaseSCache(scp);
6456 cm_ReleaseUser(userp);
6457 smb_ReleaseFID(fidp);
6461 /* SMB_COM_WRITE_ANDX */
6462 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6465 long count, written = 0, total_written = 0;
6469 smb_t *smbp = (smb_t*) inp;
6474 int inDataBlockCount;
6476 fd = smb_GetSMBParm(inp, 2);
6477 count = smb_GetSMBParm(inp, 10);
6479 offset.HighPart = 0;
6480 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6482 if (*inp->wctp == 14) {
6483 /* we have a request with 64-bit file offsets */
6484 #ifdef AFS_LARGEFILES
6485 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6487 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6489 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
6490 /* we shouldn't have received this op if we didn't specify
6491 largefile support */
6492 return CM_ERROR_BADOP;
6497 op = inp->data + smb_GetSMBParm(inp, 11);
6498 inDataBlockCount = count;
6500 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
6501 fd, offset.HighPart, offset.LowPart, count);
6503 fd = smb_ChainFID(fd, inp);
6504 fidp = smb_FindFID(vcp, fd, 0);
6506 return CM_ERROR_BADFD;
6508 lock_ObtainMutex(&fidp->mx);
6509 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6510 lock_ReleaseMutex(&fidp->mx);
6511 smb_CloseFID(vcp, fidp, NULL, 0);
6512 smb_ReleaseFID(fidp);
6513 return CM_ERROR_NOSUCHFILE;
6516 if (fidp->flags & SMB_FID_IOCTL) {
6517 lock_ReleaseMutex(&fidp->mx);
6518 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
6519 smb_ReleaseFID(fidp);
6524 lock_ReleaseMutex(&fidp->mx);
6525 smb_ReleaseFID(fidp);
6526 return CM_ERROR_BADFDOP;
6531 lock_ReleaseMutex(&fidp->mx);
6533 userp = smb_GetUserFromVCP(vcp, inp);
6535 /* special case: 0 bytes transferred means there is no data
6536 transferred. A slight departure from SMB_COM_WRITE where this
6537 means that we are supposed to truncate the file at this
6542 LARGE_INTEGER LOffset;
6543 LARGE_INTEGER LLength;
6546 key = cm_GenerateKey(vcp->vcID, pid, fd);
6548 LOffset.HighPart = offset.HighPart;
6549 LOffset.LowPart = offset.LowPart;
6550 LLength.HighPart = 0;
6551 LLength.LowPart = count;
6553 lock_ObtainWrite(&scp->rw);
6554 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
6555 lock_ReleaseWrite(&scp->rw);
6562 * Work around bug in NT client
6564 * When copying a file, the NT client should first copy the data,
6565 * then copy the last write time. But sometimes the NT client does
6566 * these in the wrong order, so the data copies would inadvertently
6567 * cause the last write time to be overwritten. We try to detect this,
6568 * and don't set client mod time if we think that would go against the
6571 lock_ObtainMutex(&fidp->mx);
6572 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6573 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6574 scp->clientModTime = time(NULL);
6576 lock_ReleaseMutex(&fidp->mx);
6579 while ( code == 0 && count > 0 ) {
6580 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6581 if (code == 0 && written == 0)
6582 code = CM_ERROR_PARTIALWRITE;
6584 offset = LargeIntegerAdd(offset,
6585 ConvertLongToLargeInteger(written));
6587 total_written += written;
6591 /* slots 0 and 1 are reserved for request chaining and will be
6592 filled in when we return. */
6593 smb_SetSMBParm(outp, 2, total_written);
6594 smb_SetSMBParm(outp, 3, 0); /* reserved */
6595 smb_SetSMBParm(outp, 4, 0); /* reserved */
6596 smb_SetSMBParm(outp, 5, 0); /* reserved */
6597 smb_SetSMBDataLength(outp, 0);
6601 cm_ReleaseSCache(scp);
6602 cm_ReleaseUser(userp);
6603 smb_ReleaseFID(fidp);
6608 /* SMB_COM_READ_ANDX */
6609 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6613 long finalCount = 0;
6617 smb_t *smbp = (smb_t*) inp;
6624 fd = smb_GetSMBParm(inp, 2);
6625 count = smb_GetSMBParm(inp, 5);
6626 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6628 if (*inp->wctp == 12) {
6629 /* a request with 64-bit offsets */
6630 #ifdef AFS_LARGEFILES
6631 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
6633 if (LargeIntegerLessThanZero(offset)) {
6634 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
6635 offset.HighPart, offset.LowPart);
6636 return CM_ERROR_BADSMB;
6639 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
6640 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
6641 return CM_ERROR_BADSMB;
6643 offset.HighPart = 0;
6647 offset.HighPart = 0;
6650 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
6651 fd, offset.HighPart, offset.LowPart, count);
6653 fd = smb_ChainFID(fd, inp);
6654 fidp = smb_FindFID(vcp, fd, 0);
6656 return CM_ERROR_BADFD;
6659 lock_ObtainMutex(&fidp->mx);
6660 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6661 lock_ReleaseMutex(&fidp->mx);
6662 smb_CloseFID(vcp, fidp, NULL, 0);
6663 smb_ReleaseFID(fidp);
6664 return CM_ERROR_NOSUCHFILE;
6668 lock_ReleaseMutex(&fidp->mx);
6669 smb_ReleaseFID(fidp);
6670 return CM_ERROR_BADFDOP;
6675 lock_ReleaseMutex(&fidp->mx);
6678 key = cm_GenerateKey(vcp->vcID, pid, fd);
6680 LARGE_INTEGER LOffset, LLength;
6682 LOffset.HighPart = offset.HighPart;
6683 LOffset.LowPart = offset.LowPart;
6684 LLength.HighPart = 0;
6685 LLength.LowPart = count;
6687 lock_ObtainWrite(&scp->rw);
6688 code = cm_LockCheckRead(scp, LOffset, LLength, key);
6689 lock_ReleaseWrite(&scp->rw);
6691 cm_ReleaseSCache(scp);
6694 smb_ReleaseFID(fidp);
6698 /* set inp->fid so that later read calls in same msg can find fid */
6701 lock_ObtainMutex(&fidp->mx);
6702 if (fidp->flags & SMB_FID_IOCTL) {
6703 lock_ReleaseMutex(&fidp->mx);
6704 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
6705 smb_ReleaseFID(fidp);
6708 lock_ReleaseMutex(&fidp->mx);
6710 userp = smb_GetUserFromVCP(vcp, inp);
6712 /* 0 and 1 are reserved for request chaining, were setup by our caller,
6713 * and will be further filled in after we return.
6715 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
6716 smb_SetSMBParm(outp, 3, 0); /* resvd */
6717 smb_SetSMBParm(outp, 4, 0); /* resvd */
6718 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
6719 /* fill in #6 when we have all the parameters' space reserved */
6720 smb_SetSMBParm(outp, 7, 0); /* resv'd */
6721 smb_SetSMBParm(outp, 8, 0); /* resv'd */
6722 smb_SetSMBParm(outp, 9, 0); /* resv'd */
6723 smb_SetSMBParm(outp, 10, 0); /* resv'd */
6724 smb_SetSMBParm(outp, 11, 0); /* reserved */
6726 /* get op ptr after putting in the parms, since otherwise we don't
6727 * know where the data really is.
6729 op = smb_GetSMBData(outp, NULL);
6731 /* now fill in offset from start of SMB header to first data byte (to op) */
6732 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
6734 /* set the packet data length the count of the # of bytes */
6735 smb_SetSMBDataLength(outp, count);
6737 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6739 /* fix some things up */
6740 smb_SetSMBParm(outp, 5, finalCount);
6741 smb_SetSMBDataLength(outp, finalCount);
6743 cm_ReleaseUser(userp);
6744 smb_ReleaseFID(fidp);
6749 * Values for createDisp, copied from NTDDK.H
6751 #define FILE_SUPERSEDE 0 // (???)
6752 #define FILE_OPEN 1 // (open)
6753 #define FILE_CREATE 2 // (exclusive)
6754 #define FILE_OPEN_IF 3 // (non-exclusive)
6755 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
6756 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
6759 #define REQUEST_OPLOCK 2
6760 #define REQUEST_BATCH_OPLOCK 4
6761 #define OPEN_DIRECTORY 8
6762 #define EXTENDED_RESPONSE_REQUIRED 0x10
6764 /* CreateOptions field. */
6765 #define FILE_DIRECTORY_FILE 0x0001
6766 #define FILE_WRITE_THROUGH 0x0002
6767 #define FILE_SEQUENTIAL_ONLY 0x0004
6768 #define FILE_NON_DIRECTORY_FILE 0x0040
6769 #define FILE_NO_EA_KNOWLEDGE 0x0200
6770 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
6771 #define FILE_RANDOM_ACCESS 0x0800
6772 #define FILE_DELETE_ON_CLOSE 0x1000
6773 #define FILE_OPEN_BY_FILE_ID 0x2000
6774 #define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000
6775 #define FILE_NO_COMPRESSION 0x00008000
6776 #define FILE_RESERVE_OPFILTER 0x00100000
6777 #define FILE_OPEN_REPARSE_POINT 0x00200000
6778 #define FILE_OPEN_NO_RECALL 0x00400000
6779 #define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000
6781 /* SMB_COM_NT_CREATE_ANDX */
6782 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6784 clientchar_t *pathp, *realPathp;
6788 cm_scache_t *dscp; /* parent dir */
6789 cm_scache_t *scp; /* file to create or open */
6790 cm_scache_t *targetScp; /* if scp is a symlink */
6792 clientchar_t *lastNamep;
6793 clientchar_t *treeStartp;
6794 unsigned short nameLength;
6796 unsigned int requestOpLock;
6797 unsigned int requestBatchOpLock;
6798 unsigned int mustBeDir;
6799 unsigned int extendedRespRequired;
6800 unsigned int treeCreate;
6802 unsigned int desiredAccess;
6803 unsigned int extAttributes;
6804 unsigned int createDisp;
6805 unsigned int createOptions;
6806 unsigned int shareAccess;
6807 int initialModeBits;
6808 unsigned short baseFid;
6809 smb_fid_t *baseFidp;
6811 cm_scache_t *baseDirp;
6812 unsigned short openAction;
6817 clientchar_t *tidPathp;
6822 int checkDoneRequired = 0;
6823 cm_lock_data_t *ldp = NULL;
6827 /* This code is very long and has a lot of if-then-else clauses
6828 * scp and dscp get reused frequently and we need to ensure that
6829 * we don't lose a reference. Start by ensuring that they are NULL.
6836 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
6837 flags = smb_GetSMBOffsetParm(inp, 3, 1)
6838 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
6839 requestOpLock = flags & REQUEST_OPLOCK;
6840 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6841 mustBeDir = flags & OPEN_DIRECTORY;
6842 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6845 * Why all of a sudden 32-bit FID?
6846 * We will reject all bits higher than 16.
6848 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
6849 return CM_ERROR_INVAL;
6850 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
6851 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
6852 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6853 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
6854 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
6855 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
6856 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
6857 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
6858 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
6859 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
6860 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
6862 /* mustBeDir is never set; createOptions directory bit seems to be
6865 if (createOptions & FILE_DIRECTORY_FILE)
6867 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6873 * compute initial mode bits based on read-only flag in
6874 * extended attributes
6876 initialModeBits = 0666;
6877 if (extAttributes & SMB_ATTR_READONLY)
6878 initialModeBits &= ~0222;
6880 pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
6881 NULL, SMB_STRF_ANSIPATH);
6883 /* Sometimes path is not null-terminated, so we make a copy. */
6884 realPathp = malloc(nameLength+sizeof(clientchar_t));
6885 memcpy(realPathp, pathp, nameLength+sizeof(clientchar_t));
6886 realPathp[nameLength/sizeof(clientchar_t)] = 0;
6888 spacep = inp->spacep;
6889 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
6891 osi_Log1(smb_logp,"NTCreateX for [%S]",osi_LogSaveClientString(smb_logp,realPathp));
6892 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
6893 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%S]", shareAccess, flags, osi_LogSaveClientString(smb_logp,(lastNamep?lastNamep:_C("null"))));
6896 (cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
6897 cm_ClientStrCmpIA(lastNamep, _C("\\srvsvc")) == 0 ||
6898 cm_ClientStrCmpIA(lastNamep, _C("\\wkssvc")) == 0 ||
6899 cm_ClientStrCmpIA(lastNamep, _C("ipc$")) == 0)) {
6900 /* special case magic file name for receiving IOCTL requests
6901 * (since IOCTL calls themselves aren't getting through).
6903 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6904 smb_SetupIoctlFid(fidp, spacep);
6905 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
6907 /* set inp->fid so that later read calls in same msg can find fid */
6908 inp->fid = fidp->fid;
6912 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6913 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6914 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
6916 memset(&ft, 0, sizeof(ft));
6917 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6918 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6919 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6920 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6921 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
6922 sz.HighPart = 0x7fff; sz.LowPart = 0;
6923 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
6924 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
6925 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6926 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6927 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
6928 smb_SetSMBDataLength(outp, 0);
6930 /* clean up fid reference */
6931 smb_ReleaseFID(fidp);
6936 if (!cm_IsValidClientString(realPathp)) {
6938 clientchar_t * hexp;
6940 hexp = cm_GetRawCharsAlloc(realPathp, -1);
6941 osi_Log1(smb_logp, "NTCreateX rejecting invalid name. [%S]",
6942 osi_LogSaveClientString(smb_logp, hexp));
6946 osi_Log0(smb_logp, "NTCreateX rejecting invalid name");
6949 return CM_ERROR_BADNTFILENAME;
6952 userp = smb_GetUserFromVCP(vcp, inp);
6954 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
6956 return CM_ERROR_INVAL;
6961 baseDirp = cm_data.rootSCachep;
6962 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6963 if (code == CM_ERROR_TIDIPC) {
6964 /* Attempt to use a TID allocated for IPC. The client
6965 * is probably looking for DCE RPC end points which we
6966 * don't support OR it could be looking to make a DFS
6969 osi_Log0(smb_logp, "NTCreateX received IPC TID");
6972 cm_ReleaseUser(userp);
6973 return CM_ERROR_NOSUCHFILE;
6974 #endif /* DFS_SUPPORT */
6977 baseFidp = smb_FindFID(vcp, baseFid, 0);
6979 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
6981 cm_ReleaseUser(userp);
6982 return CM_ERROR_INVAL;
6985 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6987 cm_ReleaseUser(userp);
6988 smb_CloseFID(vcp, baseFidp, NULL, 0);
6989 smb_ReleaseFID(baseFidp);
6990 return CM_ERROR_NOSUCHPATH;
6993 baseDirp = baseFidp->scp;
6997 osi_Log1(smb_logp, "NTCreateX tidPathp=[%S]", (tidPathp==NULL)?_C("null"): osi_LogSaveClientString(smb_logp,tidPathp));
6999 /* compute open mode */
7001 if (desiredAccess & DELETE)
7002 fidflags |= SMB_FID_OPENDELETE;
7003 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
7004 fidflags |= SMB_FID_OPENREAD_LISTDIR;
7005 if (desiredAccess & AFS_ACCESS_WRITE)
7006 fidflags |= SMB_FID_OPENWRITE;
7007 if (createOptions & FILE_DELETE_ON_CLOSE)
7008 fidflags |= SMB_FID_DELONCLOSE;
7009 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7010 fidflags |= SMB_FID_SEQUENTIAL;
7011 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7012 fidflags |= SMB_FID_RANDOM;
7013 if (createOptions & FILE_OPEN_REPARSE_POINT)
7014 osi_Log0(smb_logp, "NTCreateX Open Reparse Point");
7015 if (smb_IsExecutableFileName(lastNamep))
7016 fidflags |= SMB_FID_EXECUTABLE;
7018 /* and the share mode */
7019 if (shareAccess & FILE_SHARE_READ)
7020 fidflags |= SMB_FID_SHARE_READ;
7021 if (shareAccess & FILE_SHARE_WRITE)
7022 fidflags |= SMB_FID_SHARE_WRITE;
7024 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
7027 /* For an exclusive create, we want to do a case sensitive match for the last component. */
7028 if ( createDisp == FILE_CREATE ||
7029 createDisp == FILE_OVERWRITE ||
7030 createDisp == FILE_OVERWRITE_IF) {
7031 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7032 userp, tidPathp, &req, &dscp);
7035 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7036 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7038 cm_ReleaseSCache(dscp);
7039 cm_ReleaseUser(userp);
7042 smb_ReleaseFID(baseFidp);
7043 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7044 return CM_ERROR_PATH_NOT_COVERED;
7046 return CM_ERROR_BADSHARENAME;
7048 #endif /* DFS_SUPPORT */
7049 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7051 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7052 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7053 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7054 if (code == 0 && realDirFlag == 1) {
7055 cm_ReleaseSCache(scp);
7056 cm_ReleaseSCache(dscp);
7057 cm_ReleaseUser(userp);
7060 smb_ReleaseFID(baseFidp);
7061 return CM_ERROR_EXISTS;
7065 /* we have both scp and dscp */
7067 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7068 userp, tidPathp, &req, &scp);
7070 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7071 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7072 cm_ReleaseSCache(scp);
7073 cm_ReleaseUser(userp);
7076 smb_ReleaseFID(baseFidp);
7077 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7078 return CM_ERROR_PATH_NOT_COVERED;
7080 return CM_ERROR_BADSHARENAME;
7082 #endif /* DFS_SUPPORT */
7083 /* we might have scp but not dscp */
7089 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7090 /* look up parent directory */
7091 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
7092 * the immediate parent. We have to work our way up realPathp until we hit something that we
7096 /* we might or might not have scp */
7102 code = cm_NameI(baseDirp, spacep->wdata,
7103 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7104 userp, tidPathp, &req, &dscp);
7107 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7108 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7111 cm_ReleaseSCache(scp);
7112 cm_ReleaseSCache(dscp);
7113 cm_ReleaseUser(userp);
7116 smb_ReleaseFID(baseFidp);
7117 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7118 return CM_ERROR_PATH_NOT_COVERED;
7120 return CM_ERROR_BADSHARENAME;
7122 #endif /* DFS_SUPPORT */
7125 (tp = cm_ClientStrRChr(spacep->wdata, '\\')) &&
7126 (createDisp == FILE_CREATE) &&
7127 (realDirFlag == 1)) {
7130 treeStartp = realPathp + (tp - spacep->wdata);
7132 if (*tp && !smb_IsLegalFilename(tp)) {
7133 cm_ReleaseUser(userp);
7135 smb_ReleaseFID(baseFidp);
7138 cm_ReleaseSCache(scp);
7139 return CM_ERROR_BADNTFILENAME;
7143 } while (dscp == NULL && code == 0);
7147 /* we might have scp and we might have dscp */
7150 smb_ReleaseFID(baseFidp);
7153 osi_Log0(smb_logp,"NTCreateX parent not found");
7155 cm_ReleaseSCache(scp);
7157 cm_ReleaseSCache(dscp);
7158 cm_ReleaseUser(userp);
7163 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
7164 /* A file exists where we want a directory. */
7166 cm_ReleaseSCache(scp);
7167 cm_ReleaseSCache(dscp);
7168 cm_ReleaseUser(userp);
7170 return CM_ERROR_EXISTS;
7174 lastNamep = realPathp;
7178 if (!smb_IsLegalFilename(lastNamep)) {
7180 cm_ReleaseSCache(scp);
7182 cm_ReleaseSCache(dscp);
7183 cm_ReleaseUser(userp);
7185 return CM_ERROR_BADNTFILENAME;
7188 if (!foundscp && !treeCreate) {
7189 if ( createDisp == FILE_CREATE ||
7190 createDisp == FILE_OVERWRITE ||
7191 createDisp == FILE_OVERWRITE_IF)
7193 code = cm_Lookup(dscp, lastNamep,
7194 CM_FLAG_FOLLOW, userp, &req, &scp);
7196 code = cm_Lookup(dscp, lastNamep,
7197 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7200 if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
7202 cm_ReleaseSCache(dscp);
7203 cm_ReleaseUser(userp);
7208 /* we have scp and dscp */
7210 /* we have scp but not dscp */
7212 smb_ReleaseFID(baseFidp);
7215 /* if we get here, if code is 0, the file exists and is represented by
7216 * scp. Otherwise, we have to create it. The dir may be represented
7217 * by dscp, or we may have found the file directly. If code is non-zero,
7220 if (code == 0 && !treeCreate) {
7221 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7223 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7225 cm_ReleaseSCache(dscp);
7227 cm_ReleaseSCache(scp);
7228 cm_ReleaseUser(userp);
7232 checkDoneRequired = 1;
7234 if (createDisp == FILE_CREATE) {
7235 /* oops, file shouldn't be there */
7236 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7238 cm_ReleaseSCache(dscp);
7240 cm_ReleaseSCache(scp);
7241 cm_ReleaseUser(userp);
7243 return CM_ERROR_EXISTS;
7246 if ( createDisp == FILE_OVERWRITE ||
7247 createDisp == FILE_OVERWRITE_IF) {
7249 setAttr.mask = CM_ATTRMASK_LENGTH;
7250 setAttr.length.LowPart = 0;
7251 setAttr.length.HighPart = 0;
7252 /* now watch for a symlink */
7254 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7256 osi_assertx(dscp != NULL, "null cm_scache_t");
7257 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7259 /* we have a more accurate file to use (the
7260 * target of the symbolic link). Otherwise,
7261 * we'll just use the symlink anyway.
7263 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7265 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7266 cm_ReleaseSCache(scp);
7268 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7270 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7272 cm_ReleaseSCache(dscp);
7274 cm_ReleaseSCache(scp);
7275 cm_ReleaseUser(userp);
7281 code = cm_SetAttr(scp, &setAttr, userp, &req);
7282 openAction = 3; /* truncated existing file */
7285 openAction = 1; /* found existing file */
7287 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7288 /* don't create if not found */
7290 cm_ReleaseSCache(dscp);
7292 cm_ReleaseSCache(scp);
7293 cm_ReleaseUser(userp);
7295 return CM_ERROR_NOSUCHFILE;
7296 } else if (realDirFlag == 0 || realDirFlag == -1) {
7297 osi_assertx(dscp != NULL, "null cm_scache_t");
7298 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %S",
7299 osi_LogSaveClientString(smb_logp, lastNamep));
7300 openAction = 2; /* created file */
7301 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7302 setAttr.clientModTime = time(NULL);
7303 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
7306 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7307 smb_NotifyChange(FILE_ACTION_ADDED,
7308 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7309 dscp, lastNamep, NULL, TRUE);
7310 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7311 /* Not an exclusive create, and someone else tried
7312 * creating it already, then we open it anyway. We
7313 * don't bother retrying after this, since if this next
7314 * fails, that means that the file was deleted after we
7315 * started this call.
7317 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7320 if (createDisp == FILE_OVERWRITE_IF) {
7321 setAttr.mask = CM_ATTRMASK_LENGTH;
7322 setAttr.length.LowPart = 0;
7323 setAttr.length.HighPart = 0;
7325 /* now watch for a symlink */
7327 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7329 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7331 /* we have a more accurate file to use (the
7332 * target of the symbolic link). Otherwise,
7333 * we'll just use the symlink anyway.
7335 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7337 cm_ReleaseSCache(scp);
7341 code = cm_SetAttr(scp, &setAttr, userp, &req);
7343 } /* lookup succeeded */
7346 clientchar_t *tp, *pp;
7347 clientchar_t *cp; /* This component */
7348 int clen = 0; /* length of component */
7349 cm_scache_t *tscp1, *tscp2;
7352 /* create directory */
7354 treeStartp = lastNamep;
7355 osi_assertx(dscp != NULL, "null cm_scache_t");
7356 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%S]",
7357 osi_LogSaveClientString(smb_logp, treeStartp));
7358 openAction = 2; /* created directory */
7360 /* if the request is to create the root directory
7361 * it will appear as a directory name of the nul-string
7362 * and a code of CM_ERROR_NOSUCHFILE
7364 if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
7365 code = CM_ERROR_EXISTS;
7367 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7368 setAttr.clientModTime = time(NULL);
7373 cm_HoldSCache(tscp1);
7377 tp = cm_ClientStrChr(pp, '\\');
7379 cm_ClientStrCpy(cp, lengthof(spacep->wdata) - (cp - spacep->wdata), pp);
7380 clen = (int)cm_ClientStrLen(cp);
7381 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
7383 clen = (int)(tp - pp);
7384 cm_ClientStrCpyN(cp, lengthof(spacep->wdata) - (cp - spacep->wdata),
7392 continue; /* the supplied path can't have consecutive slashes either , but */
7394 /* cp is the next component to be created. */
7395 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req, NULL);
7396 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
7397 smb_NotifyChange(FILE_ACTION_ADDED,
7398 FILE_NOTIFY_CHANGE_DIR_NAME,
7399 tscp1, cp, NULL, TRUE);
7401 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7402 /* Not an exclusive create, and someone else tried
7403 * creating it already, then we open it anyway. We
7404 * don't bother retrying after this, since if this next
7405 * fails, that means that the file was deleted after we
7406 * started this call.
7408 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
7409 userp, &req, &tscp2);
7414 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
7415 cm_ReleaseSCache(tscp1);
7416 tscp1 = tscp2; /* Newly created directory will be next parent */
7417 /* the hold is transfered to tscp1 from tscp2 */
7422 cm_ReleaseSCache(dscp);
7425 cm_ReleaseSCache(scp);
7428 * if we get here and code == 0, then scp is the last directory created, and dscp is the
7434 /* something went wrong creating or truncating the file */
7435 if (checkDoneRequired)
7436 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7438 cm_ReleaseSCache(scp);
7440 cm_ReleaseSCache(dscp);
7441 cm_ReleaseUser(userp);
7446 /* make sure we have file vs. dir right (only applies for single component case) */
7447 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7448 /* now watch for a symlink */
7450 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7451 cm_scache_t * targetScp = 0;
7452 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7454 /* we have a more accurate file to use (the
7455 * target of the symbolic link). Otherwise,
7456 * we'll just use the symlink anyway.
7458 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
7459 if (checkDoneRequired) {
7460 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7461 checkDoneRequired = 0;
7463 cm_ReleaseSCache(scp);
7468 if (scp->fileType != CM_SCACHETYPE_FILE) {
7469 if (checkDoneRequired)
7470 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7472 cm_ReleaseSCache(dscp);
7473 cm_ReleaseSCache(scp);
7474 cm_ReleaseUser(userp);
7476 return CM_ERROR_ISDIR;
7480 /* (only applies to single component case) */
7481 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7482 if (checkDoneRequired)
7483 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7484 cm_ReleaseSCache(scp);
7486 cm_ReleaseSCache(dscp);
7487 cm_ReleaseUser(userp);
7489 return CM_ERROR_NOTDIR;
7492 /* open the file itself */
7493 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7494 osi_assertx(fidp, "null smb_fid_t");
7496 /* save a reference to the user */
7498 fidp->userp = userp;
7500 /* If we are restricting sharing, we should do so with a suitable
7502 if (scp->fileType == CM_SCACHETYPE_FILE &&
7503 !(fidflags & SMB_FID_SHARE_WRITE)) {
7505 LARGE_INTEGER LOffset, LLength;
7508 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7509 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7510 LLength.HighPart = 0;
7511 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7513 /* If we are not opening the file for writing, then we don't
7514 try to get an exclusive lock. No one else should be able to
7515 get an exclusive lock on the file anyway, although someone
7516 else can get a shared lock. */
7517 if ((fidflags & SMB_FID_SHARE_READ) ||
7518 !(fidflags & SMB_FID_OPENWRITE)) {
7519 sLockType = LOCKING_ANDX_SHARED_LOCK;
7524 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7526 lock_ObtainWrite(&scp->rw);
7527 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7528 lock_ReleaseWrite(&scp->rw);
7531 if (checkDoneRequired)
7532 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7533 cm_ReleaseSCache(scp);
7535 cm_ReleaseSCache(dscp);
7536 cm_ReleaseUser(userp);
7537 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7538 smb_CloseFID(vcp, fidp, NULL, 0);
7539 smb_ReleaseFID(fidp);
7545 /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
7546 if (checkDoneRequired) {
7547 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7548 checkDoneRequired = 0;
7551 lock_ObtainMutex(&fidp->mx);
7552 /* save a pointer to the vnode */
7553 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
7554 lock_ObtainWrite(&scp->rw);
7555 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7556 lock_ReleaseWrite(&scp->rw);
7557 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
7559 fidp->flags = fidflags;
7561 /* remember if the file was newly created */
7563 fidp->flags |= SMB_FID_CREATED;
7565 /* save parent dir and pathname for delete or change notification */
7566 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7567 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
7568 fidp->flags |= SMB_FID_NTOPEN;
7569 fidp->NTopen_dscp = dscp;
7571 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
7573 fidp->NTopen_wholepathp = realPathp;
7574 lock_ReleaseMutex(&fidp->mx);
7576 /* we don't need this any longer */
7578 cm_ReleaseSCache(dscp);
7582 cm_Open(scp, 0, userp);
7584 /* set inp->fid so that later read calls in same msg can find fid */
7585 inp->fid = fidp->fid;
7589 lock_ObtainRead(&scp->rw);
7590 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7591 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7592 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7593 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7594 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7595 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7596 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7597 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7598 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7600 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7601 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7602 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
7603 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
7604 smb_SetSMBParmByte(outp, parmSlot,
7605 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7606 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7607 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7608 smb_SetSMBDataLength(outp, 0);
7610 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
7611 LargeIntegerGreaterThanZero(scp->length) &&
7612 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
7615 lock_ReleaseRead(&scp->rw);
7618 cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
7619 scp->length.LowPart, scp->length.HighPart,
7623 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %S", fidp->fid,
7624 osi_LogSaveClientString(smb_logp, realPathp));
7626 cm_ReleaseUser(userp);
7627 smb_ReleaseFID(fidp);
7629 /* Can't free realPathp if we get here since
7630 fidp->NTopen_wholepathp is pointing there */
7632 /* leave scp held since we put it in fidp->scp */
7637 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
7638 * Instead, ultimately, would like to use a subroutine for common code.
7641 /* NT_TRANSACT_CREATE (SMB_COM_NT_TRANSACT) */
7642 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7644 clientchar_t *pathp, *realPathp;
7648 cm_scache_t *dscp; /* parent dir */
7649 cm_scache_t *scp; /* file to create or open */
7650 cm_scache_t *targetScp; /* if scp is a symlink */
7652 clientchar_t *lastNamep;
7653 unsigned long nameLength;
7655 unsigned int requestOpLock;
7656 unsigned int requestBatchOpLock;
7657 unsigned int mustBeDir;
7658 unsigned int extendedRespRequired;
7660 unsigned int desiredAccess;
7661 unsigned int allocSize;
7662 unsigned int shareAccess;
7663 unsigned int extAttributes;
7664 unsigned int createDisp;
7667 unsigned int impLevel;
7668 unsigned int secFlags;
7669 unsigned int createOptions;
7670 int initialModeBits;
7671 unsigned short baseFid;
7672 smb_fid_t *baseFidp;
7674 cm_scache_t *baseDirp;
7675 unsigned short openAction;
7679 clientchar_t *tidPathp;
7681 int parmOffset, dataOffset;
7688 cm_lock_data_t *ldp = NULL;
7689 int checkDoneRequired = 0;
7696 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7697 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7698 parmp = inp->data + parmOffset;
7699 lparmp = (ULONG *) parmp;
7702 requestOpLock = flags & REQUEST_OPLOCK;
7703 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7704 mustBeDir = flags & OPEN_DIRECTORY;
7705 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7708 * Why all of a sudden 32-bit FID?
7709 * We will reject all bits higher than 16.
7711 if (lparmp[1] & 0xFFFF0000)
7712 return CM_ERROR_INVAL;
7713 baseFid = (unsigned short)lparmp[1];
7714 desiredAccess = lparmp[2];
7715 allocSize = lparmp[3];
7716 extAttributes = lparmp[5];
7717 shareAccess = lparmp[6];
7718 createDisp = lparmp[7];
7719 createOptions = lparmp[8];
7722 nameLength = lparmp[11]; /* spec says chars but appears to be bytes */
7723 impLevel = lparmp[12];
7724 secFlags = lparmp[13];
7726 /* mustBeDir is never set; createOptions directory bit seems to be
7729 if (createOptions & FILE_DIRECTORY_FILE)
7731 else if (createOptions & FILE_NON_DIRECTORY_FILE)
7737 * compute initial mode bits based on read-only flag in
7738 * extended attributes
7740 initialModeBits = 0666;
7741 if (extAttributes & SMB_ATTR_READONLY)
7742 initialModeBits &= ~0222;
7744 pathp = smb_ParseStringCb(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
7745 nameLength, NULL, SMB_STRF_ANSIPATH);
7746 /* Sometimes path is not nul-terminated, so we make a copy. */
7747 realPathp = malloc(nameLength+sizeof(clientchar_t));
7748 memcpy(realPathp, pathp, nameLength);
7749 realPathp[nameLength/sizeof(clientchar_t)] = 0;
7750 spacep = cm_GetSpace();
7751 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
7753 osi_Log1(smb_logp,"NTTranCreate %S",osi_LogSaveStringW(smb_logp,realPathp));
7754 osi_Log4(smb_logp,"... da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
7755 osi_Log4(smb_logp,"... co[%x],sdl[%x],eal[%x],as[%x],flags[%x]",createOptions,sdLen,eaLen,allocSize);
7756 osi_Log3(smb_logp,"... imp[%x],sec[%x],flags[%x]", impLevel, secFlags, flags);
7759 * Nothing here to handle SMB_IOCTL_FILENAME.
7760 * Will add it if necessary.
7763 if (!cm_IsValidClientString(realPathp)) {
7765 clientchar_t * hexp;
7767 hexp = cm_GetRawCharsAlloc(realPathp, -1);
7768 osi_Log1(smb_logp, "NTTranCreate rejecting invalid name. [%S]",
7769 osi_LogSaveClientString(smb_logp, hexp));
7773 osi_Log0(smb_logp, "NTTranCreate rejecting invalid name.");
7776 return CM_ERROR_BADNTFILENAME;
7779 userp = smb_GetUserFromVCP(vcp, inp);
7781 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
7783 return CM_ERROR_INVAL;
7788 baseDirp = cm_data.rootSCachep;
7789 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7790 if (code == CM_ERROR_TIDIPC) {
7791 /* Attempt to use a TID allocated for IPC. The client
7792 * is probably looking for DCE RPC end points which we
7793 * don't support OR it could be looking to make a DFS
7796 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
7799 cm_ReleaseUser(userp);
7800 return CM_ERROR_NOSUCHPATH;
7804 baseFidp = smb_FindFID(vcp, baseFid, 0);
7806 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
7808 cm_ReleaseUser(userp);
7809 return CM_ERROR_BADFD;
7812 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7814 cm_ReleaseUser(userp);
7815 smb_CloseFID(vcp, baseFidp, NULL, 0);
7816 smb_ReleaseFID(baseFidp);
7817 return CM_ERROR_NOSUCHPATH;
7820 baseDirp = baseFidp->scp;
7824 /* compute open mode */
7826 if (desiredAccess & DELETE)
7827 fidflags |= SMB_FID_OPENDELETE;
7828 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
7829 fidflags |= SMB_FID_OPENREAD_LISTDIR;
7830 if (desiredAccess & AFS_ACCESS_WRITE)
7831 fidflags |= SMB_FID_OPENWRITE;
7832 if (createOptions & FILE_DELETE_ON_CLOSE)
7833 fidflags |= SMB_FID_DELONCLOSE;
7834 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7835 fidflags |= SMB_FID_SEQUENTIAL;
7836 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7837 fidflags |= SMB_FID_RANDOM;
7838 if (createOptions & FILE_OPEN_REPARSE_POINT)
7839 osi_Log0(smb_logp, "NTTranCreate Open Reparse Point");
7840 if (smb_IsExecutableFileName(lastNamep))
7841 fidflags |= SMB_FID_EXECUTABLE;
7843 /* And the share mode */
7844 if (shareAccess & FILE_SHARE_READ)
7845 fidflags |= SMB_FID_SHARE_READ;
7846 if (shareAccess & FILE_SHARE_WRITE)
7847 fidflags |= SMB_FID_SHARE_WRITE;
7851 if ( createDisp == FILE_OPEN ||
7852 createDisp == FILE_OVERWRITE ||
7853 createDisp == FILE_OVERWRITE_IF) {
7854 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7855 userp, tidPathp, &req, &dscp);
7858 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7859 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7860 cm_ReleaseSCache(dscp);
7861 cm_ReleaseUser(userp);
7864 smb_ReleaseFID(baseFidp);
7865 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7866 return CM_ERROR_PATH_NOT_COVERED;
7868 return CM_ERROR_BADSHARENAME;
7870 #endif /* DFS_SUPPORT */
7871 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7873 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7874 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7875 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7876 if (code == 0 && realDirFlag == 1) {
7877 cm_ReleaseSCache(scp);
7878 cm_ReleaseSCache(dscp);
7879 cm_ReleaseUser(userp);
7882 smb_ReleaseFID(baseFidp);
7883 return CM_ERROR_EXISTS;
7889 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7890 userp, tidPathp, &req, &scp);
7892 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7893 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7894 cm_ReleaseSCache(scp);
7895 cm_ReleaseUser(userp);
7898 smb_ReleaseFID(baseFidp);
7899 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7900 return CM_ERROR_PATH_NOT_COVERED;
7902 return CM_ERROR_BADSHARENAME;
7904 #endif /* DFS_SUPPORT */
7910 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7911 /* look up parent directory */
7913 code = cm_NameI(baseDirp, spacep->wdata,
7914 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7915 userp, tidPathp, &req, &dscp);
7917 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7918 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7919 cm_ReleaseSCache(dscp);
7920 cm_ReleaseUser(userp);
7923 smb_ReleaseFID(baseFidp);
7924 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7925 return CM_ERROR_PATH_NOT_COVERED;
7927 return CM_ERROR_BADSHARENAME;
7929 #endif /* DFS_SUPPORT */
7933 cm_FreeSpace(spacep);
7936 smb_ReleaseFID(baseFidp);
7939 cm_ReleaseUser(userp);
7945 lastNamep = realPathp;
7949 if (!smb_IsLegalFilename(lastNamep))
7950 return CM_ERROR_BADNTFILENAME;
7953 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
7954 code = cm_Lookup(dscp, lastNamep,
7955 CM_FLAG_FOLLOW, userp, &req, &scp);
7957 code = cm_Lookup(dscp, lastNamep,
7958 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7961 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7962 cm_ReleaseSCache(dscp);
7963 cm_ReleaseUser(userp);
7970 smb_ReleaseFID(baseFidp);
7971 cm_FreeSpace(spacep);
7974 /* if we get here, if code is 0, the file exists and is represented by
7975 * scp. Otherwise, we have to create it. The dir may be represented
7976 * by dscp, or we may have found the file directly. If code is non-zero,
7980 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7982 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7984 cm_ReleaseSCache(dscp);
7985 cm_ReleaseSCache(scp);
7986 cm_ReleaseUser(userp);
7990 checkDoneRequired = 1;
7992 if (createDisp == FILE_CREATE) {
7993 /* oops, file shouldn't be there */
7994 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7996 cm_ReleaseSCache(dscp);
7997 cm_ReleaseSCache(scp);
7998 cm_ReleaseUser(userp);
8000 return CM_ERROR_EXISTS;
8003 if (createDisp == FILE_OVERWRITE ||
8004 createDisp == FILE_OVERWRITE_IF) {
8005 setAttr.mask = CM_ATTRMASK_LENGTH;
8006 setAttr.length.LowPart = 0;
8007 setAttr.length.HighPart = 0;
8009 /* now watch for a symlink */
8011 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8013 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8015 /* we have a more accurate file to use (the
8016 * target of the symbolic link). Otherwise,
8017 * we'll just use the symlink anyway.
8019 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8021 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8022 cm_ReleaseSCache(scp);
8024 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
8026 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8028 cm_ReleaseSCache(dscp);
8030 cm_ReleaseSCache(scp);
8031 cm_ReleaseUser(userp);
8037 code = cm_SetAttr(scp, &setAttr, userp, &req);
8038 openAction = 3; /* truncated existing file */
8040 else openAction = 1; /* found existing file */
8042 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
8043 /* don't create if not found */
8045 cm_ReleaseSCache(dscp);
8046 cm_ReleaseUser(userp);
8048 return CM_ERROR_NOSUCHFILE;
8050 else if (realDirFlag == 0 || realDirFlag == -1) {
8051 osi_assertx(dscp != NULL, "null cm_scache_t");
8052 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %S",
8053 osi_LogSaveClientString(smb_logp, lastNamep));
8054 openAction = 2; /* created file */
8055 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8056 setAttr.clientModTime = time(NULL);
8057 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8061 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8062 smb_NotifyChange(FILE_ACTION_ADDED,
8063 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8064 dscp, lastNamep, NULL, TRUE);
8065 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
8066 /* Not an exclusive create, and someone else tried
8067 * creating it already, then we open it anyway. We
8068 * don't bother retrying after this, since if this next
8069 * fails, that means that the file was deleted after we
8070 * started this call.
8072 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8075 if (createDisp == FILE_OVERWRITE_IF) {
8076 setAttr.mask = CM_ATTRMASK_LENGTH;
8077 setAttr.length.LowPart = 0;
8078 setAttr.length.HighPart = 0;
8080 /* now watch for a symlink */
8082 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8084 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8086 /* we have a more accurate file to use (the
8087 * target of the symbolic link). Otherwise,
8088 * we'll just use the symlink anyway.
8090 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8092 cm_ReleaseSCache(scp);
8096 code = cm_SetAttr(scp, &setAttr, userp, &req);
8098 } /* lookup succeeded */
8101 /* create directory */
8102 osi_assertx(dscp != NULL, "null cm_scache_t");
8104 "smb_ReceiveNTTranCreate creating directory %S",
8105 osi_LogSaveClientString(smb_logp, lastNamep));
8106 openAction = 2; /* created directory */
8107 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8108 setAttr.clientModTime = time(NULL);
8109 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8110 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8111 smb_NotifyChange(FILE_ACTION_ADDED,
8112 FILE_NOTIFY_CHANGE_DIR_NAME,
8113 dscp, lastNamep, NULL, TRUE);
8115 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
8116 /* Not an exclusive create, and someone else tried
8117 * creating it already, then we open it anyway. We
8118 * don't bother retrying after this, since if this next
8119 * fails, that means that the file was deleted after we
8120 * started this call.
8122 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8128 /* something went wrong creating or truncating the file */
8129 if (checkDoneRequired)
8130 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8132 cm_ReleaseSCache(scp);
8133 cm_ReleaseUser(userp);
8138 /* make sure we have file vs. dir right */
8139 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
8140 /* now watch for a symlink */
8142 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8144 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8146 /* we have a more accurate file to use (the
8147 * target of the symbolic link). Otherwise,
8148 * we'll just use the symlink anyway.
8150 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8152 if (checkDoneRequired) {
8153 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8154 checkDoneRequired = 0;
8156 cm_ReleaseSCache(scp);
8161 if (scp->fileType != CM_SCACHETYPE_FILE) {
8162 if (checkDoneRequired)
8163 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8164 cm_ReleaseSCache(scp);
8165 cm_ReleaseUser(userp);
8167 return CM_ERROR_ISDIR;
8171 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8172 if (checkDoneRequired)
8173 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8174 cm_ReleaseSCache(scp);
8175 cm_ReleaseUser(userp);
8177 return CM_ERROR_NOTDIR;
8180 /* open the file itself */
8181 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8182 osi_assertx(fidp, "null smb_fid_t");
8184 /* save a reference to the user */
8186 fidp->userp = userp;
8188 /* If we are restricting sharing, we should do so with a suitable
8190 if (scp->fileType == CM_SCACHETYPE_FILE &&
8191 !(fidflags & SMB_FID_SHARE_WRITE)) {
8193 LARGE_INTEGER LOffset, LLength;
8196 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8197 LOffset.LowPart = SMB_FID_QLOCK_LOW;
8198 LLength.HighPart = 0;
8199 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8201 /* Similar to what we do in handling NTCreateX. We get a
8202 shared lock if we are only opening the file for reading. */
8203 if ((fidflags & SMB_FID_SHARE_READ) ||
8204 !(fidflags & SMB_FID_OPENWRITE)) {
8205 sLockType = LOCKING_ANDX_SHARED_LOCK;
8210 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8212 lock_ObtainWrite(&scp->rw);
8213 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8214 lock_ReleaseWrite(&scp->rw);
8217 if (checkDoneRequired)
8218 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8219 cm_ReleaseSCache(scp);
8220 cm_ReleaseUser(userp);
8221 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
8222 smb_CloseFID(vcp, fidp, NULL, 0);
8223 smb_ReleaseFID(fidp);
8225 return CM_ERROR_SHARING_VIOLATION;
8229 /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
8230 if (checkDoneRequired) {
8231 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8232 checkDoneRequired = 0;
8235 lock_ObtainMutex(&fidp->mx);
8236 /* save a pointer to the vnode */
8238 lock_ObtainWrite(&scp->rw);
8239 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8240 lock_ReleaseWrite(&scp->rw);
8241 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
8243 fidp->flags = fidflags;
8245 /* remember if the file was newly created */
8247 fidp->flags |= SMB_FID_CREATED;
8249 /* save parent dir and pathname for deletion or change notification */
8250 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8251 fidp->flags |= SMB_FID_NTOPEN;
8252 fidp->NTopen_dscp = dscp;
8253 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
8255 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
8257 fidp->NTopen_wholepathp = realPathp;
8258 lock_ReleaseMutex(&fidp->mx);
8260 /* we don't need this any longer */
8262 cm_ReleaseSCache(dscp);
8264 cm_Open(scp, 0, userp);
8266 /* set inp->fid so that later read calls in same msg can find fid */
8267 inp->fid = fidp->fid;
8269 /* check whether we are required to send an extended response */
8270 if (!extendedRespRequired) {
8272 parmOffset = 8*4 + 39;
8273 parmOffset += 1; /* pad to 4 */
8274 dataOffset = parmOffset + 70;
8278 /* Total Parameter Count */
8279 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8280 /* Total Data Count */
8281 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8282 /* Parameter Count */
8283 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8284 /* Parameter Offset */
8285 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8286 /* Parameter Displacement */
8287 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8289 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8291 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8292 /* Data Displacement */
8293 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8294 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8295 smb_SetSMBDataLength(outp, 70);
8297 lock_ObtainRead(&scp->rw);
8298 outData = smb_GetSMBData(outp, NULL);
8299 outData++; /* round to get to parmOffset */
8300 *outData = 0; outData++; /* oplock */
8301 *outData = 0; outData++; /* reserved */
8302 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8303 *((ULONG *)outData) = openAction; outData += 4;
8304 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8305 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8306 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8307 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8308 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8309 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8310 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8311 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8312 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8313 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8314 *((USHORT *)outData) = 0; outData += 2; /* dev state */
8315 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8316 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8317 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8318 outData += 2; /* is a dir? */
8321 parmOffset = 8*4 + 39;
8322 parmOffset += 1; /* pad to 4 */
8323 dataOffset = parmOffset + 104;
8327 /* Total Parameter Count */
8328 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8329 /* Total Data Count */
8330 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8331 /* Parameter Count */
8332 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8333 /* Parameter Offset */
8334 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8335 /* Parameter Displacement */
8336 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8338 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8340 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8341 /* Data Displacement */
8342 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8343 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8344 smb_SetSMBDataLength(outp, 105);
8346 lock_ObtainRead(&scp->rw);
8347 outData = smb_GetSMBData(outp, NULL);
8348 outData++; /* round to get to parmOffset */
8349 *outData = 0; outData++; /* oplock */
8350 *outData = 1; outData++; /* response type */
8351 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8352 *((ULONG *)outData) = openAction; outData += 4;
8353 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8354 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8355 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8356 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8357 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8358 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8359 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8360 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8361 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8362 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8363 *((USHORT *)outData) = 0; outData += 2; /* dev state */
8364 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8365 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8366 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8367 outData += 1; /* is a dir? */
8368 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
8369 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
8370 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
8373 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
8374 LargeIntegerGreaterThanZero(scp->length) &&
8375 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
8378 lock_ReleaseRead(&scp->rw);
8381 cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
8382 scp->length.LowPart, scp->length.HighPart,
8385 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
8387 cm_ReleaseUser(userp);
8388 smb_ReleaseFID(fidp);
8390 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
8391 /* leave scp held since we put it in fidp->scp */
8395 /* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
8396 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
8399 smb_packet_t *savedPacketp;
8401 USHORT fid, watchtree;
8405 filter = smb_GetSMBParm(inp, 19) |
8406 (smb_GetSMBParm(inp, 20) << 16);
8407 fid = smb_GetSMBParm(inp, 21);
8408 watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
8410 fidp = smb_FindFID(vcp, fid, 0);
8412 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
8413 return CM_ERROR_BADFD;
8416 lock_ObtainMutex(&fidp->mx);
8417 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8418 lock_ReleaseMutex(&fidp->mx);
8419 smb_CloseFID(vcp, fidp, NULL, 0);
8420 smb_ReleaseFID(fidp);
8421 return CM_ERROR_NOSUCHFILE;
8425 lock_ReleaseMutex(&fidp->mx);
8427 /* Create a copy of the Directory Watch Packet to use when sending the
8428 * notification if in the future a matching change is detected.
8430 savedPacketp = smb_CopyPacket(inp);
8431 if (vcp != savedPacketp->vcp) {
8433 if (savedPacketp->vcp)
8434 smb_ReleaseVC(savedPacketp->vcp);
8435 savedPacketp->vcp = vcp;
8438 /* Add the watch to the list of events to send notifications for */
8439 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8440 savedPacketp->nextp = smb_Directory_Watches;
8441 smb_Directory_Watches = savedPacketp;
8442 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8444 osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%S\"",
8445 fidp, scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp));
8446 osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
8447 filter, fid, watchtree);
8448 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8449 osi_Log0(smb_logp, " Notify Change File Name");
8450 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8451 osi_Log0(smb_logp, " Notify Change Directory Name");
8452 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8453 osi_Log0(smb_logp, " Notify Change Attributes");
8454 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8455 osi_Log0(smb_logp, " Notify Change Size");
8456 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8457 osi_Log0(smb_logp, " Notify Change Last Write");
8458 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8459 osi_Log0(smb_logp, " Notify Change Last Access");
8460 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8461 osi_Log0(smb_logp, " Notify Change Creation");
8462 if (filter & FILE_NOTIFY_CHANGE_EA)
8463 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8464 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8465 osi_Log0(smb_logp, " Notify Change Security");
8466 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8467 osi_Log0(smb_logp, " Notify Change Stream Name");
8468 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8469 osi_Log0(smb_logp, " Notify Change Stream Size");
8470 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8471 osi_Log0(smb_logp, " Notify Change Stream Write");
8473 lock_ObtainWrite(&scp->rw);
8475 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
8477 scp->flags |= CM_SCACHEFLAG_WATCHED;
8478 lock_ReleaseWrite(&scp->rw);
8479 cm_ReleaseSCache(scp);
8480 smb_ReleaseFID(fidp);
8482 outp->flags |= SMB_PACKETFLAG_NOSEND;
8486 unsigned char nullSecurityDesc[36] = {
8487 0x01, /* security descriptor revision */
8488 0x00, /* reserved, should be zero */
8489 0x00, 0x80, /* security descriptor control;
8490 * 0x8000 : self-relative format */
8491 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
8492 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
8493 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
8494 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
8495 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8496 /* "null SID" owner SID */
8497 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
8498 /* "null SID" group SID */
8501 /* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
8502 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8504 int parmOffset, parmCount, dataOffset, dataCount;
8512 ULONG securityInformation;
8514 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8515 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8516 parmp = inp->data + parmOffset;
8517 sparmp = (USHORT *) parmp;
8518 lparmp = (ULONG *) parmp;
8521 securityInformation = lparmp[1];
8523 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
8524 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
8532 parmOffset = 8*4 + 39;
8533 parmOffset += 1; /* pad to 4 */
8535 dataOffset = parmOffset + parmCount;
8539 /* Total Parameter Count */
8540 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8541 /* Total Data Count */
8542 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8543 /* Parameter Count */
8544 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8545 /* Parameter Offset */
8546 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8547 /* Parameter Displacement */
8548 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8550 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8552 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8553 /* Data Displacement */
8554 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8555 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8556 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
8558 outData = smb_GetSMBData(outp, NULL);
8559 outData++; /* round to get to parmOffset */
8560 *((ULONG *)outData) = 36; outData += 4; /* length */
8562 if (maxData >= 36) {
8563 memcpy(outData, nullSecurityDesc, 36);
8567 return CM_ERROR_BUFFERTOOSMALL;
8570 /* SMB_COM_NT_TRANSACT
8572 SMB_COM_NT_TRANSACT_SECONDARY should also be handled here.
8574 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8576 unsigned short function;
8578 function = smb_GetSMBParm(inp, 18);
8580 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
8582 /* We can handle long names */
8583 if (vcp->flags & SMB_VCFLAG_USENT)
8584 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
8587 case 1: /* NT_TRANSACT_CREATE */
8588 return smb_ReceiveNTTranCreate(vcp, inp, outp);
8589 case 2: /* NT_TRANSACT_IOCTL */
8590 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
8592 case 3: /* NT_TRANSACT_SET_SECURITY_DESC */
8593 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
8595 case 4: /* NT_TRANSACT_NOTIFY_CHANGE */
8596 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
8597 case 5: /* NT_TRANSACT_RENAME */
8598 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
8600 case 6: /* NT_TRANSACT_QUERY_SECURITY_DESC */
8601 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
8603 osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
8606 osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
8609 return CM_ERROR_INVAL;
8613 * smb_NotifyChange -- find relevant change notification messages and
8616 * If we don't know the file name (i.e. a callback break), filename is
8617 * NULL, and we return a zero-length list.
8619 * At present there is not a single call to smb_NotifyChange that
8620 * has the isDirectParent parameter set to FALSE.
8622 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
8623 cm_scache_t *dscp, clientchar_t *filename, clientchar_t *otherFilename,
8624 BOOL isDirectParent)
8626 smb_packet_t *watch, *lastWatch, *nextWatch;
8627 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen = 0;
8628 char *outData, *oldOutData;
8632 BOOL twoEntries = FALSE;
8633 ULONG otherNameLen, oldParmCount = 0;
8637 /* Get ready for rename within directory */
8638 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
8640 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
8643 osi_Log4(smb_logp,"in smb_NotifyChange for file [%S] dscp [%p] notification 0x%x parent %d",
8644 osi_LogSaveClientString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
8646 osi_Log0(smb_logp," FILE_ACTION_NONE");
8647 if (action == FILE_ACTION_ADDED)
8648 osi_Log0(smb_logp," FILE_ACTION_ADDED");
8649 if (action == FILE_ACTION_REMOVED)
8650 osi_Log0(smb_logp," FILE_ACTION_REMOVED");
8651 if (action == FILE_ACTION_MODIFIED)
8652 osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
8653 if (action == FILE_ACTION_RENAMED_OLD_NAME)
8654 osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
8655 if (action == FILE_ACTION_RENAMED_NEW_NAME)
8656 osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
8658 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8659 watch = smb_Directory_Watches;
8661 filter = smb_GetSMBParm(watch, 19)
8662 | (smb_GetSMBParm(watch, 20) << 16);
8663 fid = smb_GetSMBParm(watch, 21);
8664 wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
8666 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
8667 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
8670 * Strange hack - bug in NT Client and NT Server that we must emulate?
8672 if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
8673 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
8675 fidp = smb_FindFID(watch->vcp, fid, 0);
8677 osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
8679 watch = watch->nextp;
8683 if (fidp->scp != dscp ||
8684 fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
8685 (filter & notifyFilter) == 0 ||
8686 (!isDirectParent && !wtree))
8688 osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
8690 watch = watch->nextp;
8691 smb_ReleaseFID(fidp);
8696 "Sending Change Notification for fid %d filter 0x%x wtree %d file %S",
8697 fid, filter, wtree, osi_LogSaveClientString(smb_logp, filename));
8698 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8699 osi_Log0(smb_logp, " Notify Change File Name");
8700 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8701 osi_Log0(smb_logp, " Notify Change Directory Name");
8702 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8703 osi_Log0(smb_logp, " Notify Change Attributes");
8704 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8705 osi_Log0(smb_logp, " Notify Change Size");
8706 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8707 osi_Log0(smb_logp, " Notify Change Last Write");
8708 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8709 osi_Log0(smb_logp, " Notify Change Last Access");
8710 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8711 osi_Log0(smb_logp, " Notify Change Creation");
8712 if (filter & FILE_NOTIFY_CHANGE_EA)
8713 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8714 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8715 osi_Log0(smb_logp, " Notify Change Security");
8716 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8717 osi_Log0(smb_logp, " Notify Change Stream Name");
8718 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8719 osi_Log0(smb_logp, " Notify Change Stream Size");
8720 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8721 osi_Log0(smb_logp, " Notify Change Stream Write");
8723 /* A watch can only be notified once. Remove it from the list */
8724 nextWatch = watch->nextp;
8725 if (watch == smb_Directory_Watches)
8726 smb_Directory_Watches = nextWatch;
8728 lastWatch->nextp = nextWatch;
8730 /* Turn off WATCHED flag in dscp */
8731 lock_ObtainWrite(&dscp->rw);
8733 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8735 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
8736 lock_ReleaseWrite(&dscp->rw);
8738 /* Convert to response packet */
8739 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
8740 #ifdef SEND_CANONICAL_PATHNAMES
8741 ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
8743 ((smb_t *) watch)->wct = 0;
8746 if (filename == NULL) {
8749 nameLen = (ULONG)cm_ClientStrLen(filename);
8750 parmCount = 3*4 + nameLen*2;
8751 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8753 otherNameLen = (ULONG)cm_ClientStrLen(otherFilename);
8754 oldParmCount = parmCount;
8755 parmCount += 3*4 + otherNameLen*2;
8756 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8758 if (maxLen < parmCount)
8759 parmCount = 0; /* not enough room */
8761 parmOffset = 8*4 + 39;
8762 parmOffset += 1; /* pad to 4 */
8763 dataOffset = parmOffset + parmCount;
8767 /* Total Parameter Count */
8768 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8769 /* Total Data Count */
8770 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8771 /* Parameter Count */
8772 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8773 /* Parameter Offset */
8774 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
8775 /* Parameter Displacement */
8776 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8778 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8780 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
8781 /* Data Displacement */
8782 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8783 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
8784 smb_SetSMBDataLength(watch, parmCount + 1);
8786 if (parmCount != 0) {
8787 outData = smb_GetSMBData(watch, NULL);
8788 outData++; /* round to get to parmOffset */
8789 oldOutData = outData;
8790 *((DWORD *)outData) = oldParmCount; outData += 4;
8791 /* Next Entry Offset */
8792 *((DWORD *)outData) = action; outData += 4;
8794 *((DWORD *)outData) = nameLen*2; outData += 4;
8795 /* File Name Length */
8797 smb_UnparseString(watch, outData, filename, NULL, 0);
8801 outData = oldOutData + oldParmCount;
8802 *((DWORD *)outData) = 0; outData += 4;
8803 /* Next Entry Offset */
8804 *((DWORD *)outData) = otherAction; outData += 4;
8806 *((DWORD *)outData) = otherNameLen*2;
8807 outData += 4; /* File Name Length */
8808 smb_UnparseString(watch, outData, otherFilename, NULL, 0);
8813 * If filename is null, we don't know the cause of the
8814 * change notification. We return zero data (see above),
8815 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
8816 * (= 0x010C). We set the error code here by hand, without
8817 * modifying wct and bcc.
8819 if (filename == NULL) {
8820 ((smb_t *) watch)->rcls = 0x0C;
8821 ((smb_t *) watch)->reh = 0x01;
8822 ((smb_t *) watch)->errLow = 0;
8823 ((smb_t *) watch)->errHigh = 0;
8824 /* Set NT Status codes flag */
8825 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8828 smb_SendPacket(watch->vcp, watch);
8829 smb_FreePacket(watch);
8831 smb_ReleaseFID(fidp);
8834 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8837 /* SMB_COM_NT_CANCEL */
8838 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8840 unsigned char *replyWctp;
8841 smb_packet_t *watch, *lastWatch;
8842 USHORT fid, watchtree;
8846 osi_Log0(smb_logp, "SMB3 receive NT cancel");
8848 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8849 watch = smb_Directory_Watches;
8851 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
8852 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
8853 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
8854 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
8855 if (watch == smb_Directory_Watches)
8856 smb_Directory_Watches = watch->nextp;
8858 lastWatch->nextp = watch->nextp;
8859 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8861 /* Turn off WATCHED flag in scp */
8862 fid = smb_GetSMBParm(watch, 21);
8863 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
8865 if (vcp != watch->vcp)
8866 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
8869 fidp = smb_FindFID(vcp, fid, 0);
8871 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %S",
8873 (fidp ? osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp) :_C("")));
8876 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
8878 lock_ObtainWrite(&scp->rw);
8880 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8882 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
8883 lock_ReleaseWrite(&scp->rw);
8885 smb_ReleaseFID(fidp);
8887 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
8890 /* assume STATUS32; return 0xC0000120 (CANCELED) */
8891 replyWctp = watch->wctp;
8895 ((smb_t *)watch)->rcls = 0x20;
8896 ((smb_t *)watch)->reh = 0x1;
8897 ((smb_t *)watch)->errLow = 0;
8898 ((smb_t *)watch)->errHigh = 0xC0;
8899 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8900 smb_SendPacket(vcp, watch);
8901 smb_FreePacket(watch);
8905 watch = watch->nextp;
8907 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8913 * NT rename also does hard links.
8916 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
8917 #define RENAME_FLAG_HARD_LINK 0x103
8918 #define RENAME_FLAG_RENAME 0x104
8919 #define RENAME_FLAG_COPY 0x105
8921 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8923 clientchar_t *oldPathp, *newPathp;
8929 attrs = smb_GetSMBParm(inp, 0);
8930 rename_type = smb_GetSMBParm(inp, 1);
8932 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
8933 osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
8934 return CM_ERROR_NOACCESS;
8937 tp = smb_GetSMBData(inp, NULL);
8938 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
8940 return CM_ERROR_BADSMB;
8941 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
8943 return CM_ERROR_BADSMB;
8945 osi_Log3(smb_logp, "NTRename for [%S]->[%S] type [%s]",
8946 osi_LogSaveClientString(smb_logp, oldPathp),
8947 osi_LogSaveClientString(smb_logp, newPathp),
8948 ((rename_type==RENAME_FLAG_RENAME)?"rename":(rename_type==RENAME_FLAG_HARD_LINK)?"hardlink":"other"));
8950 if (rename_type == RENAME_FLAG_RENAME) {
8951 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
8952 } else if (rename_type == RENAME_FLAG_HARD_LINK) { /* RENAME_FLAG_HARD_LINK */
8953 code = smb_Link(vcp,inp,oldPathp,newPathp);
8955 code = CM_ERROR_BADOP;
8961 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock", LOCK_HIERARCHY_SMB_DIRWATCH);
8964 cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
8966 smb_username_t *unp;
8969 unp = smb_FindUserByName(usern, machine, flags);
8971 lock_ObtainMutex(&unp->mx);
8972 unp->userp = cm_NewUser();
8973 lock_ReleaseMutex(&unp->mx);
8974 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
8976 osi_Log2(smb_logp,"smb_FindCMUserByName Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
8980 smb_ReleaseUsername(unp);