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));
149 void OutputDebugHexDump(unsigned char * buffer, int len) {
152 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
154 OutputDebugF(_C("Hexdump length [%d]"),len);
156 for (i=0;i<len;i++) {
159 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
161 StringCchPrintfA(buf, lengthof(buf), "%5x", i);
162 memset(buf+5,' ',80);
167 j = j*3 + 7 + ((j>7)?1:0);
170 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
173 j = j + 56 + ((j>7)?1:0);
175 buf[j] = (k>32 && k<127)?k:'.';
178 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
182 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
184 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
185 SECURITY_STATUS status, istatus;
186 CredHandle creds = {0,0};
188 SecBufferDesc secOut;
196 OutputDebugF(_C("Negotiating Extended Security"));
198 status = AcquireCredentialsHandle( NULL,
199 SMB_EXT_SEC_PACKAGE_NAME,
208 if (status != SEC_E_OK) {
209 /* Really bad. We return an empty security blob */
210 OutputDebugF(_C("AcquireCredentialsHandle failed with %lX"), status);
215 secOut.pBuffers = &secTok;
216 secOut.ulVersion = SECBUFFER_VERSION;
218 secTok.BufferType = SECBUFFER_TOKEN;
220 secTok.pvBuffer = NULL;
222 ctx.dwLower = ctx.dwUpper = 0;
224 status = AcceptSecurityContext( &creds,
227 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
228 SECURITY_NETWORK_DREP,
235 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
236 OutputDebugF(_C("Completing token..."));
237 istatus = CompleteAuthToken(&ctx, &secOut);
238 if ( istatus != SEC_E_OK )
239 OutputDebugF(_C("Token completion failed: %x"), istatus);
242 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
243 if (secTok.pvBuffer) {
244 *secBlobLength = secTok.cbBuffer;
245 *secBlob = malloc( secTok.cbBuffer );
246 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
249 if ( status != SEC_E_OK )
250 OutputDebugF(_C("AcceptSecurityContext status != CONTINUE %lX"), status);
253 /* Discard partial security context */
254 DeleteSecurityContext(&ctx);
256 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
258 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
259 FreeCredentialsHandle(&creds);
265 struct smb_ext_context {
272 long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern,
273 char * secBlobIn, int secBlobInLength,
274 char ** secBlobOut, int * secBlobOutLength) {
275 SECURITY_STATUS status, istatus;
279 SecBufferDesc secBufIn;
281 SecBufferDesc secBufOut;
284 struct smb_ext_context * secCtx = NULL;
285 struct smb_ext_context * newSecCtx = NULL;
286 void * assembledBlob = NULL;
287 int assembledBlobLength = 0;
290 OutputDebugF(_C("In smb_AuthenticateUserExt"));
293 *secBlobOutLength = 0;
295 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
296 secCtx = vcp->secCtx;
297 lock_ObtainMutex(&vcp->mx);
298 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
300 lock_ReleaseMutex(&vcp->mx);
304 OutputDebugF(_C("Received incoming token:"));
305 OutputDebugHexDump(secBlobIn,secBlobInLength);
309 OutputDebugF(_C("Continuing with existing context."));
310 creds = secCtx->creds;
313 if (secCtx->partialToken) {
314 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
315 assembledBlob = malloc(assembledBlobLength);
316 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
317 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
320 status = AcquireCredentialsHandle( NULL,
321 SMB_EXT_SEC_PACKAGE_NAME,
330 if (status != SEC_E_OK) {
331 OutputDebugF(_C("Can't acquire Credentials handle [%lX]"), status);
332 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
340 secBufIn.cBuffers = 1;
341 secBufIn.pBuffers = &secTokIn;
342 secBufIn.ulVersion = SECBUFFER_VERSION;
344 secTokIn.BufferType = SECBUFFER_TOKEN;
346 secTokIn.cbBuffer = assembledBlobLength;
347 secTokIn.pvBuffer = assembledBlob;
349 secTokIn.cbBuffer = secBlobInLength;
350 secTokIn.pvBuffer = secBlobIn;
353 secBufOut.cBuffers = 1;
354 secBufOut.pBuffers = &secTokOut;
355 secBufOut.ulVersion = SECBUFFER_VERSION;
357 secTokOut.BufferType = SECBUFFER_TOKEN;
358 secTokOut.cbBuffer = 0;
359 secTokOut.pvBuffer = NULL;
361 status = AcceptSecurityContext( &creds,
362 ((secCtx)?&ctx:NULL),
364 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
365 SECURITY_NETWORK_DREP,
372 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
373 OutputDebugF(_C("Completing token..."));
374 istatus = CompleteAuthToken(&ctx, &secBufOut);
375 if ( istatus != SEC_E_OK )
376 OutputDebugF(_C("Token completion failed: %lX"), istatus);
379 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
380 OutputDebugF(_C("Continue needed"));
382 newSecCtx = malloc(sizeof(*newSecCtx));
384 newSecCtx->creds = creds;
385 newSecCtx->ctx = ctx;
386 newSecCtx->partialToken = NULL;
387 newSecCtx->partialTokenLen = 0;
389 lock_ObtainMutex( &vcp->mx );
390 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
391 vcp->secCtx = newSecCtx;
392 lock_ReleaseMutex( &vcp->mx );
394 code = CM_ERROR_GSSCONTINUE;
397 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
398 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
399 secTokOut.pvBuffer) {
400 OutputDebugF(_C("Need to send token back to client"));
402 *secBlobOutLength = secTokOut.cbBuffer;
403 *secBlobOut = malloc(secTokOut.cbBuffer);
404 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
406 OutputDebugF(_C("Outgoing token:"));
407 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
408 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
409 OutputDebugF(_C("Incomplete message"));
411 newSecCtx = malloc(sizeof(*newSecCtx));
413 newSecCtx->creds = creds;
414 newSecCtx->ctx = ctx;
415 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
416 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
417 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
419 lock_ObtainMutex( &vcp->mx );
420 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
421 vcp->secCtx = newSecCtx;
422 lock_ReleaseMutex( &vcp->mx );
424 code = CM_ERROR_GSSCONTINUE;
427 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
429 SecPkgContext_NamesW names;
431 OutputDebugF(_C("Authentication completed"));
432 OutputDebugF(_C("Returned flags : [%lX]"), flags);
434 if (!QueryContextAttributesW(&ctx, SECPKG_ATTR_NAMES, &names)) {
435 OutputDebugF(_C("Received name [%s]"), names.sUserName);
436 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, names.sUserName);
437 cm_ClientStrLwr(usern); /* in tandem with smb_GetNormalizedUsername */
438 FreeContextBuffer(names.sUserName);
440 /* Force the user to retry if the context is invalid */
441 OutputDebugF(_C("QueryContextAttributes Names failed [%x]"), GetLastError());
442 code = CM_ERROR_BADPASSWORD;
446 case SEC_E_INVALID_TOKEN:
447 OutputDebugF(_C("Returning bad password :: INVALID_TOKEN"));
449 case SEC_E_INVALID_HANDLE:
450 OutputDebugF(_C("Returning bad password :: INVALID_HANDLE"));
452 case SEC_E_LOGON_DENIED:
453 OutputDebugF(_C("Returning bad password :: LOGON_DENIED"));
455 case SEC_E_UNKNOWN_CREDENTIALS:
456 OutputDebugF(_C("Returning bad password :: UNKNOWN_CREDENTIALS"));
458 case SEC_E_NO_CREDENTIALS:
459 OutputDebugF(_C("Returning bad password :: NO_CREDENTIALS"));
461 case SEC_E_CONTEXT_EXPIRED:
462 OutputDebugF(_C("Returning bad password :: CONTEXT_EXPIRED"));
464 case SEC_E_INCOMPLETE_CREDENTIALS:
465 OutputDebugF(_C("Returning bad password :: INCOMPLETE_CREDENTIALS"));
467 case SEC_E_WRONG_PRINCIPAL:
468 OutputDebugF(_C("Returning bad password :: WRONG_PRINCIPAL"));
470 case SEC_E_TIME_SKEW:
471 OutputDebugF(_C("Returning bad password :: TIME_SKEW"));
474 OutputDebugF(_C("Returning bad password :: Status == %lX"), status);
476 code = CM_ERROR_BADPASSWORD;
480 if (secCtx->partialToken) free(secCtx->partialToken);
488 if (secTokOut.pvBuffer)
489 FreeContextBuffer(secTokOut.pvBuffer);
491 if (code != CM_ERROR_GSSCONTINUE) {
492 DeleteSecurityContext(&ctx);
493 FreeCredentialsHandle(&creds);
501 #define P_RESP_LEN 128
503 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
504 So put stuff in a struct. */
505 struct Lm20AuthBlob {
506 MSV1_0_LM20_LOGON lmlogon;
507 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
508 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
509 WCHAR accountNameW[P_LEN];
510 WCHAR primaryDomainW[P_LEN];
511 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
512 TOKEN_GROUPS tgroups;
513 TOKEN_SOURCE tsource;
516 long smb_AuthenticateUserLM(smb_vc_t *vcp, clientchar_t * accountName, clientchar_t * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
519 struct Lm20AuthBlob lmAuth;
520 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
521 QUOTA_LIMITS quotaLimits;
523 ULONG lmprofilepSize;
527 OutputDebugF(_C("In smb_AuthenticateUser for user [%s] domain [%s]"), accountName, primaryDomain);
528 OutputDebugF(_C("ciPwdLength is %d and csPwdLength is %d"), ciPwdLength, csPwdLength);
530 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
531 OutputDebugF(_C("ciPwdLength or csPwdLength is too long"));
532 return CM_ERROR_BADPASSWORD;
535 memset(&lmAuth,0,sizeof(lmAuth));
537 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
539 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
540 cm_ClientStringToUtf16(primaryDomain, -1, lmAuth.primaryDomainW, P_LEN);
541 lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
542 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
544 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
545 cm_ClientStringToUtf16(accountName, -1, lmAuth.accountNameW, P_LEN);
546 lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
547 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
549 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
550 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
551 size = MAX_COMPUTERNAME_LENGTH + 1;
552 GetComputerNameW(lmAuth.workstationW, &size);
553 lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
555 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
557 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
558 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
559 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
560 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
562 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
563 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
564 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
565 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
567 lmAuth.lmlogon.ParameterControl = 0;
569 lmAuth.tgroups.GroupCount = 0;
570 lmAuth.tgroups.Groups[0].Sid = NULL;
571 lmAuth.tgroups.Groups[0].Attributes = 0;
574 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
576 lmAuth.tsource.SourceIdentifier.HighPart = 0;
578 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
579 StringCchCopyA(lmAuth.tsource.SourceName, lengthof(lmAuth.tsource.SourceName),
580 "OpenAFS"); /* 8 char limit */
582 nts = LsaLogonUser( smb_lsaHandle,
597 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
598 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
601 OutputDebugF(_C("Return from LsaLogonUser is 0x%lX"), nts);
602 OutputDebugF(_C("Extended status is 0x%lX"), ntsEx);
604 if (nts == ERROR_SUCCESS) {
606 LsaFreeReturnBuffer(lmprofilep);
607 CloseHandle(lmToken);
611 if (nts == 0xC000015BL)
612 return CM_ERROR_BADLOGONTYPE;
613 else /* our catchall is a bad password though we could be more specific */
614 return CM_ERROR_BADPASSWORD;
618 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
619 long smb_GetNormalizedUsername(clientchar_t * usern, const clientchar_t * accountName, const clientchar_t * domainName)
621 clientchar_t * atsign;
622 const clientchar_t * domain;
624 /* check if we have sane input */
625 if ((cm_ClientStrLen(accountName) + cm_ClientStrLen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
628 /* we could get : [accountName][domainName]
634 atsign = cm_ClientStrChr(accountName, '@');
636 if (atsign) /* [user@domain][] -> [user@domain][domain] */
641 /* if for some reason the client doesn't know what domain to use,
642 it will either return an empty string or a '?' */
643 if (!domain[0] || domain[0] == '?')
644 /* Empty domains and empty usernames are usually sent from tokenless contexts.
645 This way such logins will get an empty username (easy to check). I don't know
646 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
647 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, accountName);
649 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
650 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, domain);
651 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, _C("\\"));
653 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
655 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
658 cm_ClientStrLwr(usern);
663 /* When using SMB auth, all SMB sessions have to pass through here
664 * first to authenticate the user.
666 * Caveat: If not using SMB auth, the protocol does not require
667 * sending a session setup packet, which means that we can't rely on a
668 * UID in subsequent packets. Though in practice we get one anyway.
670 /* SMB_COM_SESSION_SETUP_ANDX */
671 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
675 unsigned short newUid;
676 unsigned long caps = 0;
678 clientchar_t *s1 = _C(" ");
680 clientchar_t usern[SMB_MAX_USERNAME_LENGTH];
681 char *secBlobOut = NULL;
682 int secBlobOutLength = 0;
683 int maxBufferSize = 0;
687 /* Check for bad conns */
688 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
689 return CM_ERROR_REMOTECONN;
692 maxBufferSize = smb_GetSMBParm(inp, 2);
693 maxMpxCount = smb_GetSMBParm(inp, 3);
694 vcNumber = smb_GetSMBParm(inp, 4);
696 osi_Log3(smb_logp, "SESSION_SETUP_ANDX with MaxBufferSize=%d, MaxMpxCount=%d, VCNumber=%d",
697 maxBufferSize, maxMpxCount, vcNumber);
699 if (maxMpxCount > smb_maxMpxRequests) {
700 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_MPX_COUNT, maxMpxCount, smb_maxMpxRequests);
701 osi_Log2(smb_logp, "MaxMpxCount for client is too large (Client=%d, Server=%d)",
702 maxMpxCount, smb_maxMpxRequests);
705 if (maxBufferSize < SMB_PACKETSIZE) {
706 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_BUFFER_SIZE, maxBufferSize, SMB_PACKETSIZE);
707 osi_Log2(smb_logp, "MaxBufferSize for client is too small (Client=%d, Server=%d)",
708 maxBufferSize, SMB_PACKETSIZE);
712 osi_Log0(smb_logp, "Resetting all VCs");
713 smb_MarkAllVCsDead(vcp);
716 if (vcp->flags & SMB_VCFLAG_USENT) {
717 if (smb_authType == SMB_AUTH_EXTENDED) {
718 /* extended authentication */
722 OutputDebugF(_C("NT Session Setup: Extended"));
724 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
725 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
728 secBlobInLength = smb_GetSMBParm(inp, 7);
729 secBlobIn = smb_GetSMBData(inp, NULL);
731 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
733 if (code == CM_ERROR_GSSCONTINUE) {
736 smb_SetSMBParm(outp, 2, 0);
737 smb_SetSMBParm(outp, 3, secBlobOutLength);
739 tp = smb_GetSMBData(outp, NULL);
740 if (secBlobOutLength) {
741 memcpy(tp, secBlobOut, secBlobOutLength);
743 tp += secBlobOutLength;
744 cb_data += secBlobOutLength;
746 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
747 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
748 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
750 smb_SetSMBDataLength(outp, cb_data);
753 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
755 unsigned ciPwdLength, csPwdLength;
757 clientchar_t *accountName;
758 clientchar_t *primaryDomain;
761 if (smb_authType == SMB_AUTH_NTLM)
762 OutputDebugF(_C("NT Session Setup: NTLM"));
764 OutputDebugF(_C("NT Session Setup: None"));
766 /* TODO: parse for extended auth as well */
767 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
768 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
770 tp = smb_GetSMBData(inp, &datalen);
772 OutputDebugF(_C("Session packet data size [%d]"),datalen);
779 accountName = smb_ParseString(inp, tp, &tp, 0);
780 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
782 OutputDebugF(_C("Account Name: %s"),accountName);
783 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
784 OutputDebugF(_C("Case Sensitive Password: %s"),
785 csPwd && csPwd[0] ? _C("yes") : _C("no"));
786 OutputDebugF(_C("Case Insensitive Password: %s"),
787 ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
789 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
790 /* shouldn't happen */
791 code = CM_ERROR_BADSMB;
792 goto after_read_packet;
795 /* capabilities are only valid for first session packet */
796 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
797 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
800 if (smb_authType == SMB_AUTH_NTLM) {
801 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
803 OutputDebugF(_C("LM authentication failed [%d]"), code);
805 OutputDebugF(_C("LM authentication succeeded"));
809 unsigned ciPwdLength;
811 clientchar_t *accountName;
812 clientchar_t *primaryDomain;
814 switch ( smb_authType ) {
815 case SMB_AUTH_EXTENDED:
816 OutputDebugF(_C("V3 Session Setup: Extended"));
819 OutputDebugF(_C("V3 Session Setup: NTLM"));
822 OutputDebugF(_C("V3 Session Setup: None"));
824 ciPwdLength = smb_GetSMBParm(inp, 7);
825 tp = smb_GetSMBData(inp, NULL);
829 accountName = smb_ParseString(inp, tp, &tp, 0);
830 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
832 OutputDebugF(_C("Account Name: %s"),accountName);
833 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
834 OutputDebugF(_C("Case Insensitive Password: %s"), ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
836 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
837 /* shouldn't happen */
838 code = CM_ERROR_BADSMB;
839 goto after_read_packet;
842 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
845 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
846 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
848 OutputDebugF(_C("LM authentication failed [%d]"), code);
850 OutputDebugF(_C("LM authentication succeeded"));
855 /* note down that we received a session setup X and set the capabilities flag */
856 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
857 lock_ObtainMutex(&vcp->mx);
858 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
859 /* for the moment we can only deal with NTSTATUS */
860 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
861 vcp->flags |= SMB_VCFLAG_STATUS32;
865 if ((caps & NTNEGOTIATE_CAPABILITY_UNICODE) && smb_UseUnicode) {
866 vcp->flags |= SMB_VCFLAG_USEUNICODE;
869 lock_ReleaseMutex(&vcp->mx);
872 /* code would be non-zero if there was an authentication failure.
873 Ideally we would like to invalidate the uid for this session or break
874 early to avoid accidently stealing someone else's tokens. */
880 OutputDebugF(_C("Received username=[%s]"), usern);
882 /* On Windows 2000, this function appears to be called more often than
883 it is expected to be called. This resulted in multiple smb_user_t
884 records existing all for the same user session which results in all
885 of the users tokens disappearing.
887 To avoid this problem, we look for an existing smb_user_t record
888 based on the users name, and use that one if we find it.
891 uidp = smb_FindUserByNameThisSession(vcp, usern);
892 if (uidp) { /* already there, so don't create a new one */
894 newUid = uidp->userID;
895 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
896 vcp->lana,vcp->lsn,newUid);
897 smb_ReleaseUID(uidp);
902 /* do a global search for the username/machine name pair */
903 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
904 lock_ObtainMutex(&unp->mx);
905 if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
906 /* clear the afslogon flag so that the tickets can now
907 * be freed when the refCount returns to zero.
909 unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
911 lock_ReleaseMutex(&unp->mx);
913 /* Create a new UID and cm_user_t structure */
916 userp = cm_NewUser();
917 cm_HoldUserVCRef(userp);
918 lock_ObtainMutex(&vcp->mx);
919 if (!vcp->uidCounter)
920 vcp->uidCounter++; /* handle unlikely wraparounds */
921 newUid = (cm_ClientStrLen(usern)==0)?0:vcp->uidCounter++;
922 lock_ReleaseMutex(&vcp->mx);
924 /* Create a new smb_user_t structure and connect them up */
925 lock_ObtainMutex(&unp->mx);
927 lock_ReleaseMutex(&unp->mx);
929 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
931 lock_ObtainMutex(&uidp->mx);
933 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
934 lock_ReleaseMutex(&uidp->mx);
935 smb_ReleaseUID(uidp);
939 /* Return UID to the client */
940 ((smb_t *)outp)->uid = newUid;
941 /* Also to the next chained message */
942 ((smb_t *)inp)->uid = newUid;
944 osi_Log3(smb_logp, "SMB3 session setup name %S creating ID %d%S",
945 osi_LogSaveClientString(smb_logp, usern), newUid,
946 osi_LogSaveClientString(smb_logp, s1));
948 smb_SetSMBParm(outp, 2, 0);
950 if (vcp->flags & SMB_VCFLAG_USENT) {
951 if (smb_authType == SMB_AUTH_EXTENDED) {
954 smb_SetSMBParm(outp, 3, secBlobOutLength);
956 tp = smb_GetSMBData(outp, NULL);
957 if (secBlobOutLength) {
958 memcpy(tp, secBlobOut, secBlobOutLength);
960 tp += secBlobOutLength;
961 cb_data += secBlobOutLength;
964 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
965 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
966 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
968 smb_SetSMBDataLength(outp, cb_data);
970 smb_SetSMBDataLength(outp, 0);
973 if (smb_authType == SMB_AUTH_EXTENDED) {
976 tp = smb_GetSMBData(outp, NULL);
978 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
979 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
980 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
982 smb_SetSMBDataLength(outp, cb_data);
984 smb_SetSMBDataLength(outp, 0);
991 /* SMB_COM_LOGOFF_ANDX */
992 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
996 /* find the tree and free it */
997 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
999 smb_username_t * unp;
1001 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %S", uidp->userID,
1002 osi_LogSaveClientString(smb_logp, (uidp->unp) ? uidp->unp->name: _C(" ")));
1004 lock_ObtainMutex(&uidp->mx);
1005 uidp->flags |= SMB_USERFLAG_DELETE;
1007 * it doesn't get deleted right away
1008 * because the vcp points to it
1011 lock_ReleaseMutex(&uidp->mx);
1014 /* we can't do this. we get logoff messages prior to a session
1015 * disconnect even though it doesn't mean the user is logging out.
1016 * we need to create a new pioctl and EventLogoff handler to set
1017 * SMB_USERNAMEFLAG_LOGOFF.
1019 if (unp && smb_LogoffTokenTransfer) {
1020 lock_ObtainMutex(&unp->mx);
1021 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
1022 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
1023 lock_ReleaseMutex(&unp->mx);
1027 smb_ReleaseUID(uidp);
1030 osi_Log0(smb_logp, "SMB3 user logoffX");
1032 smb_SetSMBDataLength(outp, 0);
1036 #define SMB_SUPPORT_SEARCH_BITS 0x0001
1037 #define SMB_SHARE_IS_IN_DFS 0x0002
1039 /* SMB_COM_TREE_CONNECT_ANDX */
1040 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1043 smb_user_t *uidp = NULL;
1044 unsigned short newTid;
1045 clientchar_t shareName[AFSPATHMAX];
1046 clientchar_t *sharePath;
1049 clientchar_t *slashp;
1050 clientchar_t *pathp;
1051 clientchar_t *passwordp;
1052 clientchar_t *servicep;
1053 cm_user_t *userp = NULL;
1056 osi_Log0(smb_logp, "SMB3 receive tree connect");
1058 /* parse input parameters */
1059 tp = smb_GetSMBData(inp, NULL);
1060 passwordp = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1061 pathp = smb_ParseString(inp, tp, &tp, SMB_STRF_ANSIPATH);
1062 servicep = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1064 slashp = cm_ClientStrRChr(pathp, '\\');
1066 return CM_ERROR_BADSMB;
1068 cm_ClientStrCpy(shareName, lengthof(shareName), slashp+1);
1070 osi_Log3(smb_logp, "Tree connect pathp[%S] shareName[%S] service[%S]",
1071 osi_LogSaveClientString(smb_logp, pathp),
1072 osi_LogSaveClientString(smb_logp, shareName),
1073 osi_LogSaveClientString(smb_logp, servicep));
1075 if (cm_ClientStrCmp(servicep, _C("IPC")) == 0 ||
1076 cm_ClientStrCmp(shareName, _C("IPC$")) == 0) {
1078 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1081 return CM_ERROR_NOIPC;
1085 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1087 userp = smb_GetUserFromUID(uidp);
1089 lock_ObtainMutex(&vcp->mx);
1090 newTid = vcp->tidCounter++;
1091 lock_ReleaseMutex(&vcp->mx);
1093 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1096 if (!cm_ClientStrCmp(shareName, _C("*.")))
1097 cm_ClientStrCpy(shareName, lengthof(shareName), _C("all"));
1098 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1101 smb_ReleaseUID(uidp);
1102 smb_ReleaseTID(tidp, FALSE);
1103 return CM_ERROR_BADSHARENAME;
1106 if (vcp->flags & SMB_VCFLAG_USENT)
1108 int policy = smb_FindShareCSCPolicy(shareName);
1111 DWORD dwAdvertiseDFS = 0, dwSize = sizeof(DWORD);
1113 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1114 0, KEY_QUERY_VALUE, &parmKey);
1115 if (code == ERROR_SUCCESS) {
1116 code = RegQueryValueEx(parmKey, "AdvertiseDFS", NULL, NULL,
1117 (BYTE *)&dwAdvertiseDFS, &dwSize);
1118 if (code != ERROR_SUCCESS)
1120 RegCloseKey (parmKey);
1122 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1123 (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
1127 smb_SetSMBParm(outp, 2, 0);
1131 smb_ReleaseUID(uidp);
1133 lock_ObtainMutex(&tidp->mx);
1134 tidp->userp = userp;
1135 tidp->pathname = sharePath;
1137 tidp->flags |= SMB_TIDFLAG_IPC;
1138 lock_ReleaseMutex(&tidp->mx);
1139 smb_ReleaseTID(tidp, FALSE);
1141 ((smb_t *)outp)->tid = newTid;
1142 ((smb_t *)inp)->tid = newTid;
1143 tp = smb_GetSMBData(outp, NULL);
1147 tp = smb_UnparseString(outp, tp, _C("A:"), &cb_data, SMB_STRF_FORCEASCII);
1148 tp = smb_UnparseString(outp, tp, _C("AFS"), &cb_data, 0);
1149 smb_SetSMBDataLength(outp, cb_data);
1153 tp = smb_UnparseString(outp, tp, _C("IPC"), &cb_data, SMB_STRF_FORCEASCII);
1154 smb_SetSMBDataLength(outp, cb_data);
1157 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1161 /* must be called with global tran lock held */
1162 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1164 smb_tran2Packet_t *tp;
1167 smbp = (smb_t *) inp->data;
1168 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1169 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1175 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1176 int totalParms, int totalData)
1178 smb_tran2Packet_t *tp;
1181 smbp = (smb_t *) inp->data;
1182 tp = malloc(sizeof(*tp));
1183 memset(tp, 0, sizeof(*tp));
1186 tp->curData = tp->curParms = 0;
1187 tp->totalData = totalData;
1188 tp->totalParms = totalParms;
1189 tp->tid = smbp->tid;
1190 tp->mid = smbp->mid;
1191 tp->uid = smbp->uid;
1192 tp->pid = smbp->pid;
1193 tp->res[0] = smbp->res[0];
1194 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1195 if (totalParms != 0)
1196 tp->parmsp = malloc(totalParms);
1198 tp->datap = malloc(totalData);
1199 if (smbp->com == 0x25 || smbp->com == 0x26)
1202 tp->opcode = smb_GetSMBParm(inp, 14);
1205 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1207 if (WANTS_UNICODE(inp) && (vcp->flags & SMB_VCFLAG_USEUNICODE))
1208 tp->flags |= SMB_TRAN2PFLAG_USEUNICODE;
1213 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1214 smb_tran2Packet_t *inp, smb_packet_t *outp,
1215 int totalParms, int totalData)
1217 smb_tran2Packet_t *tp;
1218 unsigned short parmOffset;
1219 unsigned short dataOffset;
1220 unsigned short dataAlign;
1222 tp = malloc(sizeof(*tp));
1223 memset(tp, 0, sizeof(*tp));
1226 tp->curData = tp->curParms = 0;
1227 tp->totalData = totalData;
1228 tp->totalParms = totalParms;
1229 tp->oldTotalParms = totalParms;
1234 tp->res[0] = inp->res[0];
1235 tp->opcode = inp->opcode;
1239 * We calculate where the parameters and data will start.
1240 * This calculation must parallel the calculation in
1241 * smb_SendTran2Packet.
1244 parmOffset = 10*2 + 35;
1245 parmOffset++; /* round to even */
1246 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1248 dataOffset = parmOffset + totalParms;
1249 dataAlign = dataOffset & 2; /* quad-align */
1250 dataOffset += dataAlign;
1251 tp->datap = outp->data + dataOffset;
1256 /* free a tran2 packet */
1257 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1260 smb_ReleaseVC(t2p->vcp);
1263 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1269 while (t2p->stringsp) {
1273 t2p->stringsp = ns->nextp;
1279 clientchar_t *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
1280 char ** chainpp, int flags)
1285 if (!(p->flags & SMB_TRAN2PFLAG_USEUNICODE))
1286 flags |= SMB_STRF_FORCEASCII;
1289 cb = p->totalParms - (inp - (char *)p->parmsp);
1290 if (inp < (char *) p->parmsp ||
1291 inp >= ((char *) p->parmsp) + p->totalParms) {
1292 #ifdef DEBUG_UNICODE
1298 return smb_ParseStringBuf((unsigned char *) p->parmsp, &p->stringsp,
1299 inp, &cb, chainpp, flags);
1302 /* called with a VC, an input packet to respond to, and an error code.
1303 * sends an error response.
1305 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1306 smb_packet_t *tp, long code)
1309 unsigned short errCode;
1310 unsigned char errClass;
1311 unsigned long NTStatus;
1313 if (vcp->flags & SMB_VCFLAG_STATUS32)
1314 smb_MapNTError(code, &NTStatus);
1316 smb_MapCoreError(code, vcp, &errCode, &errClass);
1318 smb_FormatResponsePacket(vcp, NULL, tp);
1319 smbp = (smb_t *) tp;
1321 /* We can handle long names */
1322 if (vcp->flags & SMB_VCFLAG_USENT)
1323 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1325 /* now copy important fields from the tran 2 packet */
1326 smbp->com = t2p->com;
1327 smbp->tid = t2p->tid;
1328 smbp->mid = t2p->mid;
1329 smbp->pid = t2p->pid;
1330 smbp->uid = t2p->uid;
1331 smbp->res[0] = t2p->res[0];
1332 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1333 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1334 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1335 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1336 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1337 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1340 smbp->rcls = errClass;
1341 smbp->errLow = (unsigned char) (errCode & 0xff);
1342 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1346 smb_SendPacket(vcp, tp);
1349 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1352 unsigned short parmOffset;
1353 unsigned short dataOffset;
1354 unsigned short totalLength;
1355 unsigned short dataAlign;
1358 smb_FormatResponsePacket(vcp, NULL, tp);
1359 smbp = (smb_t *) tp;
1361 /* We can handle long names */
1362 if (vcp->flags & SMB_VCFLAG_USENT)
1363 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1365 /* now copy important fields from the tran 2 packet */
1366 smbp->com = t2p->com;
1367 smbp->tid = t2p->tid;
1368 smbp->mid = t2p->mid;
1369 smbp->pid = t2p->pid;
1370 smbp->uid = t2p->uid;
1371 smbp->res[0] = t2p->res[0];
1373 totalLength = 1 + t2p->totalData + t2p->totalParms;
1375 /* now add the core parameters (tran2 info) to the packet */
1376 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1377 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1378 smb_SetSMBParm(tp, 2, 0); /* reserved */
1379 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1380 parmOffset = 10*2 + 35; /* parm offset in packet */
1381 parmOffset++; /* round to even */
1382 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1383 * hdr, bcc and wct */
1384 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1385 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1386 dataOffset = parmOffset + t2p->oldTotalParms;
1387 dataAlign = dataOffset & 2; /* quad-align */
1388 dataOffset += dataAlign;
1389 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1390 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1391 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1394 datap = smb_GetSMBData(tp, NULL);
1395 *datap++ = 0; /* we rounded to even */
1397 totalLength += dataAlign;
1398 smb_SetSMBDataLength(tp, totalLength);
1400 /* next, send the datagram */
1401 smb_SendPacket(vcp, tp);
1405 /* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
1406 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1408 smb_tran2Packet_t *asp;
1421 /* We sometimes see 0 word count. What to do? */
1422 if (*inp->wctp == 0) {
1423 osi_Log0(smb_logp, "Transaction2 word count = 0");
1424 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1426 smb_SetSMBDataLength(outp, 0);
1427 smb_SendPacket(vcp, outp);
1431 totalParms = smb_GetSMBParm(inp, 0);
1432 totalData = smb_GetSMBParm(inp, 1);
1434 firstPacket = (inp->inCom == 0x25);
1436 /* find the packet we're reassembling */
1437 lock_ObtainWrite(&smb_globalLock);
1438 asp = smb_FindTran2Packet(vcp, inp);
1440 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1442 lock_ReleaseWrite(&smb_globalLock);
1444 /* now merge in this latest packet; start by looking up offsets */
1446 parmDisp = dataDisp = 0;
1447 parmOffset = smb_GetSMBParm(inp, 10);
1448 dataOffset = smb_GetSMBParm(inp, 12);
1449 parmCount = smb_GetSMBParm(inp, 9);
1450 dataCount = smb_GetSMBParm(inp, 11);
1451 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1452 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1454 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1455 totalData, dataCount, asp->maxReturnData);
1458 parmDisp = smb_GetSMBParm(inp, 4);
1459 parmOffset = smb_GetSMBParm(inp, 3);
1460 dataDisp = smb_GetSMBParm(inp, 7);
1461 dataOffset = smb_GetSMBParm(inp, 6);
1462 parmCount = smb_GetSMBParm(inp, 2);
1463 dataCount = smb_GetSMBParm(inp, 5);
1465 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1466 parmCount, dataCount);
1469 /* now copy the parms and data */
1470 if ( asp->totalParms > 0 && parmCount != 0 )
1472 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1474 if ( asp->totalData > 0 && dataCount != 0 ) {
1475 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1478 /* account for new bytes */
1479 asp->curData += dataCount;
1480 asp->curParms += parmCount;
1482 /* finally, if we're done, remove the packet from the queue and dispatch it */
1483 if (asp->totalParms > 0 &&
1484 asp->curParms > 0 &&
1485 asp->totalData <= asp->curData &&
1486 asp->totalParms <= asp->curParms) {
1487 /* we've received it all */
1488 lock_ObtainWrite(&smb_globalLock);
1489 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1490 lock_ReleaseWrite(&smb_globalLock);
1492 /* now dispatch it */
1493 rapOp = asp->parmsp[0];
1495 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1496 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1497 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1498 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
1501 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1502 code = CM_ERROR_BADOP;
1505 /* if an error is returned, we're supposed to send an error packet,
1506 * otherwise the dispatched function already did the data sending.
1507 * We give dispatched proc the responsibility since it knows how much
1508 * space to allocate.
1511 smb_SendTran2Error(vcp, asp, outp, code);
1514 /* free the input tran 2 packet */
1515 smb_FreeTran2Packet(asp);
1517 else if (firstPacket) {
1518 /* the first packet in a multi-packet request, we need to send an
1519 * ack to get more data.
1521 smb_SetSMBDataLength(outp, 0);
1522 smb_SendPacket(vcp, outp);
1528 /* ANSI versions. */
1530 #pragma pack(push, 1)
1532 typedef struct smb_rap_share_info_0 {
1533 BYTE shi0_netname[13];
1534 } smb_rap_share_info_0_t;
1536 typedef struct smb_rap_share_info_1 {
1537 BYTE shi1_netname[13];
1540 DWORD shi1_remark; /* char *shi1_remark; data offset */
1541 } smb_rap_share_info_1_t;
1543 typedef struct smb_rap_share_info_2 {
1544 BYTE shi2_netname[13];
1547 DWORD shi2_remark; /* char *shi2_remark; data offset */
1548 WORD shi2_permissions;
1550 WORD shi2_current_uses;
1551 DWORD shi2_path; /* char *shi2_path; data offset */
1552 WORD shi2_passwd[9];
1554 } smb_rap_share_info_2_t;
1556 #define SMB_RAP_MAX_SHARES 512
1558 typedef struct smb_rap_share_list {
1561 smb_rap_share_info_0_t * shares;
1562 } smb_rap_share_list_t;
1566 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1567 smb_rap_share_list_t * sp;
1569 if (dep->name[0] == '.' && (!dep->name[1] || (dep->name[1] == '.' && !dep->name[2])))
1570 return 0; /* skip over '.' and '..' */
1572 sp = (smb_rap_share_list_t *) vrockp;
1574 strncpy(sp->shares[sp->cShare].shi0_netname, dep->name, 12);
1575 sp->shares[sp->cShare].shi0_netname[12] = 0;
1579 if (sp->cShare >= sp->maxShares)
1580 return CM_ERROR_STOPNOW;
1585 /* RAP NetShareEnumRequest */
1586 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1588 smb_tran2Packet_t *outp;
1589 unsigned short * tp;
1593 int outParmsTotal; /* total parameter bytes */
1594 int outDataTotal; /* total data bytes */
1597 DWORD allSubmount = 0;
1599 DWORD nRegShares = 0;
1600 DWORD nSharesRet = 0;
1602 HKEY hkSubmount = NULL;
1603 smb_rap_share_info_1_t * shares;
1606 clientchar_t thisShare[AFSPATHMAX];
1610 smb_rap_share_list_t rootShares;
1615 tp = p->parmsp + 1; /* skip over function number (always 0) */
1618 clientchar_t * cdescp;
1620 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1621 if (cm_ClientStrCmp(cdescp, _C("WrLeh")))
1622 return CM_ERROR_INVAL;
1623 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1624 if (cm_ClientStrCmp(cdescp, _C("B13BWz")))
1625 return CM_ERROR_INVAL;
1631 if (infoLevel != 1) {
1632 return CM_ERROR_INVAL;
1635 /* We are supposed to use the same ASCII data structure even if
1636 Unicode is negotiated, which ultimately means that the share
1637 names that we return must be at most 13 characters in length,
1638 including the NULL terminator.
1640 The RAP specification states that shares with names longer than
1641 12 characters should not be included in the enumeration.
1642 However, since we support prefix cell references and since many
1643 cell names are going to exceed 12 characters, we lie and send
1644 the first 12 characters.
1647 /* first figure out how many shares there are */
1648 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1649 KEY_QUERY_VALUE, &hkParam);
1650 if (rv == ERROR_SUCCESS) {
1651 len = sizeof(allSubmount);
1652 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1653 (BYTE *) &allSubmount, &len);
1654 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1657 RegCloseKey (hkParam);
1660 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1661 0, KEY_QUERY_VALUE, &hkSubmount);
1662 if (rv == ERROR_SUCCESS) {
1663 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1664 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1665 if (rv != ERROR_SUCCESS)
1671 /* fetch the root shares */
1672 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1673 rootShares.cShare = 0;
1674 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1678 userp = smb_GetTran2User(vcp,p);
1680 thyper.HighPart = 0;
1683 cm_HoldSCache(cm_data.rootSCachep);
1684 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1685 cm_ReleaseSCache(cm_data.rootSCachep);
1687 cm_ReleaseUser(userp);
1689 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1691 #define REMARK_LEN 1
1692 outParmsTotal = 8; /* 4 dwords */
1693 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1694 if(outDataTotal > bufsize) {
1695 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1696 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1699 nSharesRet = nShares;
1702 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1704 /* now for the submounts */
1705 shares = (smb_rap_share_info_1_t *) outp->datap;
1706 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1708 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1711 StringCchCopyA(shares[cshare].shi1_netname,
1712 lengthof(shares[cshare].shi1_netname), "all" );
1713 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1714 /* type and pad are zero already */
1720 for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
1721 len = sizeof(thisShare);
1722 rv = RegEnumValueW(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
1723 if (rv == ERROR_SUCCESS &&
1724 cm_ClientStrLen(thisShare) &&
1725 (!allSubmount || cm_ClientStrCmpI(thisShare,_C("all")))) {
1726 cm_ClientStringToUtf8(thisShare, -1, shares[cshare].shi1_netname,
1727 lengthof( shares[cshare].shi1_netname ));
1728 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1729 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1734 nShares--; /* uncount key */
1737 RegCloseKey(hkSubmount);
1740 nonrootShares = cshare;
1742 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1743 /* in case there are collisions with submounts, submounts have
1745 for (j=0; j < nonrootShares; j++)
1746 if (!cm_stricmp_utf8(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1749 if (j < nonrootShares) {
1750 nShares--; /* uncount */
1754 StringCchCopyA(shares[cshare].shi1_netname, lengthof(shares[cshare].shi1_netname),
1755 rootShares.shares[i].shi0_netname);
1756 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1761 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1762 outp->parmsp[1] = 0;
1763 outp->parmsp[2] = cshare;
1764 outp->parmsp[3] = nShares;
1766 outp->totalData = (int)(cstrp - outp->datap);
1767 outp->totalParms = outParmsTotal;
1769 smb_SendTran2Packet(vcp, outp, op);
1770 smb_FreeTran2Packet(outp);
1772 free(rootShares.shares);
1777 /* RAP NetShareGetInfo */
1778 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1780 smb_tran2Packet_t *outp;
1781 unsigned short * tp;
1782 clientchar_t * shareName;
1783 BOOL shareFound = FALSE;
1784 unsigned short infoLevel;
1785 unsigned short bufsize;
1794 cm_scache_t *scp = NULL;
1800 tp = p->parmsp + 1; /* skip over function number (always 1) */
1803 clientchar_t * cdescp;
1805 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1806 if (cm_ClientStrCmp(cdescp, _C("zWrLh")))
1808 return CM_ERROR_INVAL;
1810 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1811 if (cm_ClientStrCmp(cdescp, _C("B13")) &&
1812 cm_ClientStrCmp(cdescp, _C("B13BWz")) &&
1813 cm_ClientStrCmp(cdescp, _C("B13BWzWWWzB9B")))
1815 return CM_ERROR_INVAL;
1817 shareName = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1825 totalData = sizeof(smb_rap_share_info_0_t);
1826 else if(infoLevel == SMB_INFO_STANDARD)
1827 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1828 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1829 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1831 return CM_ERROR_INVAL;
1833 if(!cm_ClientStrCmpI(shareName, _C("all")) || !cm_ClientStrCmp(shareName,_C("*."))) {
1834 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1835 KEY_QUERY_VALUE, &hkParam);
1836 if (rv == ERROR_SUCCESS) {
1837 len = sizeof(allSubmount);
1838 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1839 (BYTE *) &allSubmount, &len);
1840 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1843 RegCloseKey (hkParam);
1850 userp = smb_GetTran2User(vcp, p);
1852 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
1853 return CM_ERROR_BADSMB;
1855 code = cm_NameI(cm_data.rootSCachep, shareName,
1856 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
1857 userp, NULL, &req, &scp);
1859 cm_ReleaseSCache(scp);
1862 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1863 KEY_QUERY_VALUE, &hkSubmount);
1864 if (rv == ERROR_SUCCESS) {
1865 rv = RegQueryValueExW(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1866 if (rv == ERROR_SUCCESS) {
1869 RegCloseKey(hkSubmount);
1875 return CM_ERROR_BADSHARENAME;
1877 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1878 memset(outp->datap, 0, totalData);
1880 outp->parmsp[0] = 0;
1881 outp->parmsp[1] = 0;
1882 outp->parmsp[2] = totalData;
1884 if (infoLevel == 0) {
1885 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1886 cm_ClientStringToUtf8(shareName, -1, info->shi0_netname,
1887 lengthof(info->shi0_netname));
1888 } else if(infoLevel == SMB_INFO_STANDARD) {
1889 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1890 cm_ClientStringToUtf8(shareName, -1, info->shi1_netname, lengthof(info->shi1_netname));
1891 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1892 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1893 /* type and pad are already zero */
1894 } else { /* infoLevel==2 */
1895 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1896 cm_ClientStringToUtf8(shareName, -1, info->shi2_netname, lengthof(info->shi2_netname));
1897 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1898 info->shi2_permissions = ACCESS_ALL;
1899 info->shi2_max_uses = (unsigned short) -1;
1900 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
1903 outp->totalData = totalData;
1904 outp->totalParms = totalParam;
1906 smb_SendTran2Packet(vcp, outp, op);
1907 smb_FreeTran2Packet(outp);
1912 #pragma pack(push, 1)
1914 typedef struct smb_rap_wksta_info_10 {
1915 DWORD wki10_computername; /*char *wki10_computername;*/
1916 DWORD wki10_username; /* char *wki10_username; */
1917 DWORD wki10_langroup; /* char *wki10_langroup;*/
1918 BYTE wki10_ver_major;
1919 BYTE wki10_ver_minor;
1920 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1921 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1922 } smb_rap_wksta_info_10_t;
1926 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1928 smb_tran2Packet_t *outp;
1932 unsigned short * tp;
1935 smb_rap_wksta_info_10_t * info;
1939 tp = p->parmsp + 1; /* Skip over function number */
1942 clientchar_t * cdescp;
1944 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
1945 SMB_STRF_FORCEASCII);
1946 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
1947 return CM_ERROR_INVAL;
1949 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
1950 SMB_STRF_FORCEASCII);
1951 if (cm_ClientStrCmp(cdescp, _C("zzzBBzz")))
1952 return CM_ERROR_INVAL;
1958 if (infoLevel != 10) {
1959 return CM_ERROR_INVAL;
1965 totalData = sizeof(*info) + /* info */
1966 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1967 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1968 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1969 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1970 1; /* wki10_oth_domains (null)*/
1972 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1974 memset(outp->parmsp,0,totalParams);
1975 memset(outp->datap,0,totalData);
1977 info = (smb_rap_wksta_info_10_t *) outp->datap;
1978 cstrp = (char *) (info + 1);
1980 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1981 StringCbCopyA(cstrp, totalData, smb_localNamep);
1982 cstrp += strlen(cstrp) + 1;
1984 info->wki10_username = (DWORD) (cstrp - outp->datap);
1985 uidp = smb_FindUID(vcp, p->uid, 0);
1987 lock_ObtainMutex(&uidp->mx);
1988 if(uidp->unp && uidp->unp->name)
1989 cm_ClientStringToUtf8(uidp->unp->name, -1,
1990 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
1991 lock_ReleaseMutex(&uidp->mx);
1992 smb_ReleaseUID(uidp);
1994 cstrp += strlen(cstrp) + 1;
1996 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1997 StringCbCopyA(cstrp, totalData - (cstrp - outp->datap)*sizeof(char), "WORKGROUP");
1998 cstrp += strlen(cstrp) + 1;
2000 /* TODO: Not sure what values these should take, but these work */
2001 info->wki10_ver_major = 5;
2002 info->wki10_ver_minor = 1;
2004 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
2005 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
2006 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2007 cstrp += strlen(cstrp) + 1;
2009 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
2010 cstrp ++; /* no other domains */
2012 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
2013 outp->parmsp[2] = outp->totalData;
2014 outp->totalParms = totalParams;
2016 smb_SendTran2Packet(vcp,outp,op);
2017 smb_FreeTran2Packet(outp);
2022 #pragma pack(push, 1)
2024 typedef struct smb_rap_server_info_0 {
2026 } smb_rap_server_info_0_t;
2028 typedef struct smb_rap_server_info_1 {
2030 BYTE sv1_version_major;
2031 BYTE sv1_version_minor;
2033 DWORD sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
2034 } smb_rap_server_info_1_t;
2038 char smb_ServerComment[] = "OpenAFS Client";
2039 int smb_ServerCommentLen = sizeof(smb_ServerComment);
2041 #define SMB_SV_TYPE_SERVER 0x00000002L
2042 #define SMB_SV_TYPE_NT 0x00001000L
2043 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
2045 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2047 smb_tran2Packet_t *outp;
2051 unsigned short * tp;
2054 smb_rap_server_info_0_t * info0;
2055 smb_rap_server_info_1_t * info1;
2058 tp = p->parmsp + 1; /* Skip over function number */
2061 clientchar_t * cdescp;
2063 cdescp = smb_ParseStringT2Parm(p, (unsigned char *) tp, (char **) &tp,
2064 SMB_STRF_FORCEASCII);
2065 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2066 return CM_ERROR_INVAL;
2067 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2068 SMB_STRF_FORCEASCII);
2069 if (cm_ClientStrCmp(cdescp, _C("B16")) ||
2070 cm_ClientStrCmp(cdescp, _C("B16BBDz")))
2071 return CM_ERROR_INVAL;
2077 if (infoLevel != 0 && infoLevel != 1) {
2078 return CM_ERROR_INVAL;
2084 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
2085 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
2087 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2089 memset(outp->parmsp,0,totalParams);
2090 memset(outp->datap,0,totalData);
2092 if (infoLevel == 0) {
2093 info0 = (smb_rap_server_info_0_t *) outp->datap;
2094 cstrp = (char *) (info0 + 1);
2095 StringCchCopyA(info0->sv0_name, lengthof(info0->sv0_name), "AFS");
2096 } else { /* infoLevel == SMB_INFO_STANDARD */
2097 info1 = (smb_rap_server_info_1_t *) outp->datap;
2098 cstrp = (char *) (info1 + 1);
2099 StringCchCopyA(info1->sv1_name, lengthof(info1->sv1_name), "AFS");
2102 SMB_SV_TYPE_SERVER |
2104 SMB_SV_TYPE_SERVER_NT;
2106 info1->sv1_version_major = 5;
2107 info1->sv1_version_minor = 1;
2108 info1->sv1_comment_or_master_browser = (DWORD) (cstrp - outp->datap);
2110 StringCbCopyA(cstrp, smb_ServerCommentLen, smb_ServerComment);
2112 cstrp += smb_ServerCommentLen / sizeof(char);
2115 totalData = (DWORD)(cstrp - outp->datap);
2116 outp->totalData = min(bufsize,totalData); /* actual data size */
2117 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
2118 outp->parmsp[2] = totalData;
2119 outp->totalParms = totalParams;
2121 smb_SendTran2Packet(vcp,outp,op);
2122 smb_FreeTran2Packet(outp);
2127 /* SMB_COM_TRANSACTION2 and SMB_COM_TRANSACTION2_SECONDARY */
2128 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2130 smb_tran2Packet_t *asp;
2141 DWORD oldTime, newTime;
2143 /* We sometimes see 0 word count. What to do? */
2144 if (*inp->wctp == 0) {
2145 osi_Log0(smb_logp, "Transaction2 word count = 0");
2146 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
2148 smb_SetSMBDataLength(outp, 0);
2149 smb_SendPacket(vcp, outp);
2153 totalParms = smb_GetSMBParm(inp, 0);
2154 totalData = smb_GetSMBParm(inp, 1);
2156 firstPacket = (inp->inCom == 0x32);
2158 /* find the packet we're reassembling */
2159 lock_ObtainWrite(&smb_globalLock);
2160 asp = smb_FindTran2Packet(vcp, inp);
2162 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
2164 lock_ReleaseWrite(&smb_globalLock);
2166 /* now merge in this latest packet; start by looking up offsets */
2168 parmDisp = dataDisp = 0;
2169 parmOffset = smb_GetSMBParm(inp, 10);
2170 dataOffset = smb_GetSMBParm(inp, 12);
2171 parmCount = smb_GetSMBParm(inp, 9);
2172 dataCount = smb_GetSMBParm(inp, 11);
2173 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2174 asp->maxReturnData = smb_GetSMBParm(inp, 3);
2176 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2177 totalData, dataCount, asp->maxReturnData);
2180 parmDisp = smb_GetSMBParm(inp, 4);
2181 parmOffset = smb_GetSMBParm(inp, 3);
2182 dataDisp = smb_GetSMBParm(inp, 7);
2183 dataOffset = smb_GetSMBParm(inp, 6);
2184 parmCount = smb_GetSMBParm(inp, 2);
2185 dataCount = smb_GetSMBParm(inp, 5);
2187 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2188 parmCount, dataCount);
2191 /* now copy the parms and data */
2192 if ( asp->totalParms > 0 && parmCount != 0 )
2194 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2196 if ( asp->totalData > 0 && dataCount != 0 ) {
2197 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2200 /* account for new bytes */
2201 asp->curData += dataCount;
2202 asp->curParms += parmCount;
2204 /* finally, if we're done, remove the packet from the queue and dispatch it */
2205 if (asp->totalParms > 0 &&
2206 asp->curParms > 0 &&
2207 asp->totalData <= asp->curData &&
2208 asp->totalParms <= asp->curParms) {
2209 /* we've received it all */
2210 lock_ObtainWrite(&smb_globalLock);
2211 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2212 lock_ReleaseWrite(&smb_globalLock);
2214 oldTime = GetTickCount();
2216 /* now dispatch it */
2217 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2218 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2219 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2222 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2223 code = CM_ERROR_BADOP;
2226 /* if an error is returned, we're supposed to send an error packet,
2227 * otherwise the dispatched function already did the data sending.
2228 * We give dispatched proc the responsibility since it knows how much
2229 * space to allocate.
2232 smb_SendTran2Error(vcp, asp, outp, code);
2235 newTime = GetTickCount();
2236 if (newTime - oldTime > 45000) {
2239 clientchar_t *treepath = NULL; /* do not free */
2240 clientchar_t *pathname = NULL;
2241 cm_fid_t afid = {0,0,0,0,0};
2243 uidp = smb_FindUID(vcp, asp->uid, 0);
2244 smb_LookupTIDPath(vcp, asp->tid, &treepath);
2245 fidp = smb_FindFID(vcp, inp->fid, 0);
2248 lock_ObtainMutex(&fidp->mx);
2249 if (fidp->NTopen_pathp)
2250 pathname = fidp->NTopen_pathp;
2252 afid = fidp->scp->fid;
2254 if (inp->stringsp->wdata)
2255 pathname = inp->stringsp->wdata;
2258 afsi_log("Request %s duration %d ms user 0x%x \"%S\" pid 0x%x mid 0x%x tid 0x%x \"%S\" path? \"%S\" afid (%d.%d.%d.%d)",
2259 myCrt_2Dispatch(asp->opcode), newTime - oldTime,
2260 asp->uid, uidp ? uidp->unp->name : NULL,
2261 asp->pid, asp->mid, asp->tid,
2264 afid.cell, afid.volume, afid.vnode, afid.unique);
2267 lock_ReleaseMutex(&fidp->mx);
2270 smb_ReleaseUID(uidp);
2272 smb_ReleaseFID(fidp);
2275 /* free the input tran 2 packet */
2276 smb_FreeTran2Packet(asp);
2278 else if (firstPacket) {
2279 /* the first packet in a multi-packet request, we need to send an
2280 * ack to get more data.
2282 smb_SetSMBDataLength(outp, 0);
2283 smb_SendPacket(vcp, outp);
2290 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2292 clientchar_t *pathp;
2293 smb_tran2Packet_t *outp;
2298 cm_scache_t *dscp; /* dir we're dealing with */
2299 cm_scache_t *scp; /* file we're creating */
2301 int initialModeBits;
2304 clientchar_t *lastNamep;
2311 int parmSlot; /* which parm we're dealing with */
2312 long returnEALength;
2313 clientchar_t *tidPathp;
2321 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2322 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2324 openFun = p->parmsp[6]; /* open function */
2325 excl = ((openFun & 3) == 0);
2326 trunc = ((openFun & 3) == 2); /* truncate it */
2327 openMode = (p->parmsp[1] & 0x7);
2328 openAction = 0; /* tracks what we did */
2330 attributes = p->parmsp[3];
2331 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2333 /* compute initial mode bits based on read-only flag in attributes */
2334 initialModeBits = 0666;
2335 if (attributes & SMB_ATTR_READONLY)
2336 initialModeBits &= ~0222;
2338 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
2341 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2343 spacep = cm_GetSpace();
2344 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2347 (cm_ClientStrCmpI(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
2348 cm_ClientStrCmpI(lastNamep, _C("\\srvsvc")) == 0 ||
2349 cm_ClientStrCmpI(lastNamep, _C("\\wkssvc")) == 0 ||
2350 cm_ClientStrCmpI(lastNamep, _C("\\ipc$")) == 0)) {
2351 /* special case magic file name for receiving IOCTL requests
2352 * (since IOCTL calls themselves aren't getting through).
2354 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2355 smb_SetupIoctlFid(fidp, spacep);
2357 /* copy out remainder of the parms */
2359 outp->parmsp[parmSlot++] = fidp->fid;
2361 outp->parmsp[parmSlot++] = 0; /* attrs */
2362 outp->parmsp[parmSlot++] = 0; /* mod time */
2363 outp->parmsp[parmSlot++] = 0;
2364 outp->parmsp[parmSlot++] = 0; /* len */
2365 outp->parmsp[parmSlot++] = 0x7fff;
2366 outp->parmsp[parmSlot++] = openMode;
2367 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2368 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2370 /* and the final "always present" stuff */
2371 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2372 /* next write out the "unique" ID */
2373 outp->parmsp[parmSlot++] = 0x1234;
2374 outp->parmsp[parmSlot++] = 0x5678;
2375 outp->parmsp[parmSlot++] = 0;
2376 if (returnEALength) {
2377 outp->parmsp[parmSlot++] = 0;
2378 outp->parmsp[parmSlot++] = 0;
2381 outp->totalData = 0;
2382 outp->totalParms = parmSlot * 2;
2384 smb_SendTran2Packet(vcp, outp, op);
2386 smb_FreeTran2Packet(outp);
2388 /* and clean up fid reference */
2389 smb_ReleaseFID(fidp);
2393 if (!cm_IsValidClientString(pathp)) {
2395 clientchar_t * hexp;
2397 hexp = cm_GetRawCharsAlloc(pathp, -1);
2398 osi_Log1(smb_logp, "Tran2Open rejecting invalid name. [%S]",
2399 osi_LogSaveClientString(smb_logp, hexp));
2403 osi_Log0(smb_logp, "Tran2Open rejecting invalid name");
2405 smb_FreeTran2Packet(outp);
2406 return CM_ERROR_BADNTFILENAME;
2409 #ifdef DEBUG_VERBOSE
2411 char *hexp, *asciip;
2412 asciip = (lastNamep ? lastNamep : pathp);
2413 hexp = osi_HexifyString( asciip );
2414 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2419 userp = smb_GetTran2User(vcp, p);
2420 /* In the off chance that userp is NULL, we log and abandon */
2422 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2423 smb_FreeTran2Packet(outp);
2424 return CM_ERROR_BADSMB;
2427 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2428 if (code == CM_ERROR_TIDIPC) {
2429 /* Attempt to use a TID allocated for IPC. The client
2430 * is probably looking for DCE RPC end points which we
2431 * don't support OR it could be looking to make a DFS
2434 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2436 cm_ReleaseUser(userp);
2437 smb_FreeTran2Packet(outp);
2438 return CM_ERROR_NOSUCHPATH;
2443 code = cm_NameI(cm_data.rootSCachep, pathp,
2444 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2445 userp, tidPathp, &req, &scp);
2447 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2448 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2449 userp, tidPathp, &req, &dscp);
2450 cm_FreeSpace(spacep);
2453 cm_ReleaseUser(userp);
2454 smb_FreeTran2Packet(outp);
2459 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2460 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2461 (clientchar_t*) spacep->data);
2462 cm_ReleaseSCache(dscp);
2463 cm_ReleaseUser(userp);
2464 smb_FreeTran2Packet(outp);
2465 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2466 return CM_ERROR_PATH_NOT_COVERED;
2468 return CM_ERROR_NOSUCHPATH;
2470 #endif /* DFS_SUPPORT */
2472 /* otherwise, scp points to the parent directory. Do a lookup,
2473 * and truncate the file if we find it, otherwise we create the
2480 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2482 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2483 cm_ReleaseSCache(dscp);
2484 cm_ReleaseUser(userp);
2485 smb_FreeTran2Packet(outp);
2490 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2491 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2492 cm_ReleaseSCache(scp);
2493 cm_ReleaseUser(userp);
2494 smb_FreeTran2Packet(outp);
2495 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2496 return CM_ERROR_PATH_NOT_COVERED;
2498 return CM_ERROR_NOSUCHPATH;
2500 #endif /* DFS_SUPPORT */
2502 /* macintosh is expensive to program for it */
2503 cm_FreeSpace(spacep);
2506 /* if we get here, if code is 0, the file exists and is represented by
2507 * scp. Otherwise, we have to create it.
2510 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2513 cm_ReleaseSCache(dscp);
2514 cm_ReleaseSCache(scp);
2515 cm_ReleaseUser(userp);
2516 smb_FreeTran2Packet(outp);
2521 /* oops, file shouldn't be there */
2523 cm_ReleaseSCache(dscp);
2524 cm_ReleaseSCache(scp);
2525 cm_ReleaseUser(userp);
2526 smb_FreeTran2Packet(outp);
2527 return CM_ERROR_EXISTS;
2531 setAttr.mask = CM_ATTRMASK_LENGTH;
2532 setAttr.length.LowPart = 0;
2533 setAttr.length.HighPart = 0;
2534 code = cm_SetAttr(scp, &setAttr, userp, &req);
2535 openAction = 3; /* truncated existing file */
2538 openAction = 1; /* found existing file */
2540 else if (!(openFun & 0x10)) {
2541 /* don't create if not found */
2543 cm_ReleaseSCache(dscp);
2544 osi_assertx(scp == NULL, "null cm_scache_t");
2545 cm_ReleaseUser(userp);
2546 smb_FreeTran2Packet(outp);
2547 return CM_ERROR_NOSUCHFILE;
2550 osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2551 openAction = 2; /* created file */
2552 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2553 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2554 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2558 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2559 smb_NotifyChange(FILE_ACTION_ADDED,
2560 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2561 dscp, lastNamep, NULL, TRUE);
2562 } else if (!excl && code == CM_ERROR_EXISTS) {
2563 /* not an exclusive create, and someone else tried
2564 * creating it already, then we open it anyway. We
2565 * don't bother retrying after this, since if this next
2566 * fails, that means that the file was deleted after we
2567 * started this call.
2569 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2573 setAttr.mask = CM_ATTRMASK_LENGTH;
2574 setAttr.length.LowPart = 0;
2575 setAttr.length.HighPart = 0;
2576 code = cm_SetAttr(scp, &setAttr, userp,
2579 } /* lookup succeeded */
2583 /* we don't need this any longer */
2585 cm_ReleaseSCache(dscp);
2588 /* something went wrong creating or truncating the file */
2590 cm_ReleaseSCache(scp);
2591 cm_ReleaseUser(userp);
2592 smb_FreeTran2Packet(outp);
2596 /* make sure we're about to open a file */
2597 if (scp->fileType != CM_SCACHETYPE_FILE) {
2599 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2600 cm_scache_t * targetScp = 0;
2601 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2603 /* we have a more accurate file to use (the
2604 * target of the symbolic link). Otherwise,
2605 * we'll just use the symlink anyway.
2607 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2609 cm_ReleaseSCache(scp);
2613 if (scp->fileType != CM_SCACHETYPE_FILE) {
2614 cm_ReleaseSCache(scp);
2615 cm_ReleaseUser(userp);
2616 smb_FreeTran2Packet(outp);
2617 return CM_ERROR_ISDIR;
2621 /* now all we have to do is open the file itself */
2622 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2623 osi_assertx(fidp, "null smb_fid_t");
2626 lock_ObtainMutex(&fidp->mx);
2627 /* save a pointer to the vnode */
2628 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2630 lock_ObtainWrite(&scp->rw);
2631 scp->flags |= CM_SCACHEFLAG_SMB_FID;
2632 lock_ReleaseWrite(&scp->rw);
2635 fidp->userp = userp;
2637 /* compute open mode */
2639 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
2640 if (openMode == 1 || openMode == 2)
2641 fidp->flags |= SMB_FID_OPENWRITE;
2643 /* remember that the file was newly created */
2645 fidp->flags |= SMB_FID_CREATED;
2647 lock_ReleaseMutex(&fidp->mx);
2649 smb_ReleaseFID(fidp);
2651 cm_Open(scp, 0, userp);
2653 /* copy out remainder of the parms */
2655 outp->parmsp[parmSlot++] = fidp->fid;
2656 lock_ObtainRead(&scp->rw);
2658 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2659 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2660 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2661 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2662 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2663 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2664 outp->parmsp[parmSlot++] = openMode;
2665 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2666 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2668 /* and the final "always present" stuff */
2669 outp->parmsp[parmSlot++] = openAction;
2670 /* next write out the "unique" ID */
2671 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2672 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2673 outp->parmsp[parmSlot++] = 0;
2674 if (returnEALength) {
2675 outp->parmsp[parmSlot++] = 0;
2676 outp->parmsp[parmSlot++] = 0;
2678 lock_ReleaseRead(&scp->rw);
2679 outp->totalData = 0; /* total # of data bytes */
2680 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2682 smb_SendTran2Packet(vcp, outp, op);
2684 smb_FreeTran2Packet(outp);
2686 cm_ReleaseUser(userp);
2687 /* leave scp held since we put it in fidp->scp */
2691 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2694 unsigned short infolevel;
2696 infolevel = p->parmsp[0];
2698 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2700 return CM_ERROR_BAD_LEVEL;
2703 /* TRANS2_QUERY_FS_INFORMATION */
2704 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2706 smb_tran2Packet_t *outp;
2707 smb_tran2QFSInfo_t qi;
2711 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2713 switch (p->parmsp[0]) {
2714 case SMB_INFO_ALLOCATION:
2716 responseSize = sizeof(qi.u.allocInfo);
2718 qi.u.allocInfo.FSID = 0;
2719 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2720 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2721 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2722 qi.u.allocInfo.bytesPerSector = 1024;
2725 case SMB_INFO_VOLUME:
2727 qi.u.volumeInfo.vsn = 1234; /* Volume serial number */
2728 qi.u.volumeInfo.vnCount = 3; /* Number of characters in label (AFS\0)*/
2730 /* we're supposed to pad it out with zeroes to the end */
2731 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2732 smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
2734 responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
2737 case SMB_QUERY_FS_VOLUME_INFO:
2738 /* FS volume info */
2739 responseSize = sizeof(qi.u.FSvolumeInfo);
2742 FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
2743 memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
2746 qi.u.FSvolumeInfo.vsn = 1234;
2747 qi.u.FSvolumeInfo.vnCount = 6; /* This is always in Unicode */
2748 memset(&qi.u.FSvolumeInfo.label, 0, sizeof(qi.u.FSvolumeInfo.label));
2749 memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
2752 case SMB_QUERY_FS_SIZE_INFO:
2754 responseSize = sizeof(qi.u.FSsizeInfo);
2756 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2757 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2758 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2759 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2760 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2761 qi.u.FSsizeInfo.bytesPerSector = 1024;
2764 case SMB_QUERY_FS_DEVICE_INFO:
2765 /* FS device info */
2766 responseSize = sizeof(qi.u.FSdeviceInfo);
2768 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2769 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2772 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2773 /* FS attribute info */
2775 /* attributes, defined in WINNT.H:
2776 * FILE_CASE_SENSITIVE_SEARCH 0x1
2777 * FILE_CASE_PRESERVED_NAMES 0x2
2778 * FILE_UNICODE_ON_DISK 0x4
2779 * FILE_VOLUME_QUOTAS 0x10
2780 * <no name defined> 0x4000
2781 * If bit 0x4000 is not set, Windows 95 thinks
2782 * we can't handle long (non-8.3) names,
2783 * despite our protestations to the contrary.
2785 qi.u.FSattributeInfo.attributes = 0x4003;
2786 /* The maxCompLength is supposed to be in bytes */
2788 qi.u.FSattributeInfo.attributes |= 0x04;
2790 qi.u.FSattributeInfo.maxCompLength = 255;
2791 smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
2792 qi.u.FSattributeInfo.FSnameLength = sz;
2795 sizeof(qi.u.FSattributeInfo.attributes) +
2796 sizeof(qi.u.FSattributeInfo.maxCompLength) +
2797 sizeof(qi.u.FSattributeInfo.FSnameLength) +
2802 case SMB_INFO_UNIX: /* CIFS Unix Info */
2803 case SMB_INFO_MACOS: /* Mac FS Info */
2805 return CM_ERROR_BADOP;
2808 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2810 /* copy out return data, and set corresponding sizes */
2811 outp->totalParms = 0;
2812 outp->totalData = responseSize;
2813 memcpy(outp->datap, &qi, responseSize);
2815 /* send and free the packets */
2816 smb_SendTran2Packet(vcp, outp, op);
2817 smb_FreeTran2Packet(outp);
2822 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2824 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2825 return CM_ERROR_BADOP;
2828 struct smb_ShortNameRock {
2829 clientchar_t *maskp;
2831 clientchar_t *shortName;
2832 size_t shortNameLen;
2835 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2838 struct smb_ShortNameRock *rockp;
2839 normchar_t normName[MAX_PATH];
2840 clientchar_t *shortNameEnd;
2844 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t)) == 0) {
2845 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
2846 osi_LogSaveString(smb_logp, dep->name));
2850 /* compare both names and vnodes, though probably just comparing vnodes
2851 * would be safe enough.
2853 if (cm_NormStrCmpI(normName, rockp->maskp) != 0)
2855 if (ntohl(dep->fid.vnode) != rockp->vnode)
2858 /* This is the entry */
2859 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2860 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2862 return CM_ERROR_STOPNOW;
2865 long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
2866 clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
2868 struct smb_ShortNameRock rock;
2869 clientchar_t *lastNamep;
2872 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2876 spacep = cm_GetSpace();
2877 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2879 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2880 caseFold, userp, tidPathp,
2882 cm_FreeSpace(spacep);
2887 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2888 cm_ReleaseSCache(dscp);
2889 cm_ReleaseUser(userp);
2893 return CM_ERROR_PATH_NOT_COVERED;
2895 #endif /* DFS_SUPPORT */
2897 if (!lastNamep) lastNamep = pathp;
2900 thyper.HighPart = 0;
2901 rock.shortName = shortName;
2903 rock.maskp = lastNamep;
2904 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2906 cm_ReleaseSCache(dscp);
2909 return CM_ERROR_NOSUCHFILE;
2910 if (code == CM_ERROR_STOPNOW) {
2911 *shortNameLenp = rock.shortNameLen;
2917 /* TRANS2_QUERY_PATH_INFORMATION */
2918 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2920 smb_tran2Packet_t *outp;
2923 unsigned short infoLevel;
2924 smb_tran2QPathInfo_t qpi;
2926 unsigned short attributes;
2927 unsigned long extAttributes;
2928 clientchar_t shortName[13];
2932 cm_scache_t *scp, *dscp;
2933 int scp_rw_held = 0;
2936 clientchar_t *pathp;
2937 clientchar_t *tidPathp;
2938 clientchar_t *lastComp;
2943 infoLevel = p->parmsp[0];
2944 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2946 else if (infoLevel == SMB_INFO_STANDARD)
2947 responseSize = sizeof(qpi.u.QPstandardInfo);
2948 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2949 responseSize = sizeof(qpi.u.QPeaSizeInfo);
2950 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2951 responseSize = sizeof(qpi.u.QPfileBasicInfo);
2952 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2953 responseSize = sizeof(qpi.u.QPfileStandardInfo);
2954 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2955 responseSize = sizeof(qpi.u.QPfileEaInfo);
2956 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2957 responseSize = sizeof(qpi.u.QPfileNameInfo);
2958 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
2959 responseSize = sizeof(qpi.u.QPfileAllInfo);
2960 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2961 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2963 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2964 p->opcode, infoLevel);
2965 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
2969 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
2970 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %S", infoLevel,
2971 osi_LogSaveClientString(smb_logp, pathp));
2973 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2975 if (infoLevel > 0x100)
2976 outp->totalParms = 2;
2978 outp->totalParms = 0;
2979 outp->totalData = responseSize;
2981 /* now, if we're at infoLevel 6, we're only being asked to check
2982 * the syntax, so we just OK things now. In particular, we're *not*
2983 * being asked to verify anything about the state of any parent dirs.
2985 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2986 smb_SendTran2Packet(vcp, outp, opx);
2987 smb_FreeTran2Packet(outp);
2991 userp = smb_GetTran2User(vcp, p);
2993 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2994 smb_FreeTran2Packet(outp);
2995 return CM_ERROR_BADSMB;
2998 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3000 cm_ReleaseUser(userp);
3001 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
3002 smb_FreeTran2Packet(outp);
3007 * XXX Strange hack XXX
3009 * As of Patch 7 (13 January 98), we are having the following problem:
3010 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3011 * requests to look up "desktop.ini" in all the subdirectories.
3012 * This can cause zillions of timeouts looking up non-existent cells
3013 * and volumes, especially in the top-level directory.
3015 * We have not found any way to avoid this or work around it except
3016 * to explicitly ignore the requests for mount points that haven't
3017 * yet been evaluated and for directories that haven't yet been
3020 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3021 spacep = cm_GetSpace();
3022 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3023 #ifndef SPECIAL_FOLDERS
3024 /* Make sure that lastComp is not NULL */
3026 if (cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
3027 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3031 userp, tidPathp, &req, &dscp);
3034 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3035 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3037 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3038 code = CM_ERROR_PATH_NOT_COVERED;
3040 code = CM_ERROR_NOSUCHPATH;
3042 #endif /* DFS_SUPPORT */
3043 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3044 code = CM_ERROR_NOSUCHFILE;
3045 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3046 cm_buf_t *bp = buf_Find(dscp, &hzero);
3052 code = CM_ERROR_NOSUCHFILE;
3054 cm_ReleaseSCache(dscp);
3056 cm_FreeSpace(spacep);
3057 cm_ReleaseUser(userp);
3058 smb_SendTran2Error(vcp, p, opx, code);
3059 smb_FreeTran2Packet(outp);
3065 #endif /* SPECIAL_FOLDERS */
3067 cm_FreeSpace(spacep);
3070 /* now do namei and stat, and copy out the info */
3071 code = cm_NameI(cm_data.rootSCachep, pathp,
3072 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3075 cm_ReleaseUser(userp);
3076 smb_SendTran2Error(vcp, p, opx, code);
3077 smb_FreeTran2Packet(outp);
3082 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3083 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3084 cm_ReleaseSCache(scp);
3085 cm_ReleaseUser(userp);
3086 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3087 code = CM_ERROR_PATH_NOT_COVERED;
3089 code = CM_ERROR_NOSUCHPATH;
3090 smb_SendTran2Error(vcp, p, opx, code);
3091 smb_FreeTran2Packet(outp);
3094 #endif /* DFS_SUPPORT */
3096 lock_ObtainWrite(&scp->rw);
3098 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3099 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3103 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3105 lock_ConvertWToR(&scp->rw);
3110 /* now we have the status in the cache entry, and everything is locked.
3111 * Marshall the output data.
3113 /* for info level 108, figure out short name */
3114 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3115 code = cm_GetShortName(pathp, userp, &req,
3116 tidPathp, scp->fid.vnode, shortName,
3122 smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
3123 qpi.u.QPfileAltNameInfo.fileNameLength = len;
3127 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3128 smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3129 qpi.u.QPfileNameInfo.fileNameLength = len;
3133 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3134 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3135 qpi.u.QPstandardInfo.creationDateTime = dosTime;
3136 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3137 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3138 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3139 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3140 attributes = smb_Attributes(scp);
3141 qpi.u.QPstandardInfo.attributes = attributes;
3142 qpi.u.QPstandardInfo.eaSize = 0;
3144 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3145 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3146 qpi.u.QPfileBasicInfo.creationTime = ft;
3147 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3148 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3149 qpi.u.QPfileBasicInfo.changeTime = ft;
3150 extAttributes = smb_ExtAttributes(scp);
3151 qpi.u.QPfileBasicInfo.attributes = extAttributes;
3152 qpi.u.QPfileBasicInfo.reserved = 0;
3154 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3157 lock_ReleaseRead(&scp->rw);
3159 fidp = smb_FindFIDByScache(vcp, scp);
3161 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3162 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3163 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3164 qpi.u.QPfileStandardInfo.directory =
3165 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3166 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3167 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3168 qpi.u.QPfileStandardInfo.reserved = 0;
3171 lock_ObtainMutex(&fidp->mx);
3172 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3173 lock_ReleaseMutex(&fidp->mx);
3174 smb_ReleaseFID(fidp);
3176 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3178 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3179 qpi.u.QPfileEaInfo.eaSize = 0;
3181 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3182 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3183 qpi.u.QPfileAllInfo.creationTime = ft;
3184 qpi.u.QPfileAllInfo.lastAccessTime = ft;
3185 qpi.u.QPfileAllInfo.lastWriteTime = ft;
3186 qpi.u.QPfileAllInfo.changeTime = ft;
3187 extAttributes = smb_ExtAttributes(scp);
3188 qpi.u.QPfileAllInfo.attributes = extAttributes;
3189 qpi.u.QPfileAllInfo.allocationSize = scp->length;
3190 qpi.u.QPfileAllInfo.endOfFile = scp->length;
3191 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3192 qpi.u.QPfileAllInfo.deletePending = 0;
3193 qpi.u.QPfileAllInfo.directory =
3194 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3195 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3196 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3197 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
3198 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
3199 qpi.u.QPfileAllInfo.eaSize = 0;
3200 qpi.u.QPfileAllInfo.accessFlags = 0;
3201 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
3202 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
3203 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3204 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3205 qpi.u.QPfileAllInfo.mode = 0;
3206 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3208 smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3209 qpi.u.QPfileAllInfo.fileNameLength = len;
3212 /* send and free the packets */
3214 switch (scp_rw_held) {
3216 lock_ReleaseRead(&scp->rw);
3219 lock_ReleaseWrite(&scp->rw);
3223 cm_ReleaseSCache(scp);
3224 cm_ReleaseUser(userp);
3226 memcpy(outp->datap, &qpi, responseSize);
3227 smb_SendTran2Packet(vcp, outp, opx);
3229 smb_SendTran2Error(vcp, p, opx, code);
3231 smb_FreeTran2Packet(outp);
3236 /* TRANS2_SET_PATH_INFORMATION */
3237 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3240 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
3241 return CM_ERROR_BADOP;
3244 unsigned short infoLevel;
3245 clientchar_t * pathp;
3246 smb_tran2Packet_t *outp;
3247 smb_tran2QPathInfo_t *spi;
3249 cm_scache_t *scp, *dscp;
3252 clientchar_t *tidPathp;
3253 clientchar_t *lastComp;
3257 infoLevel = p->parmsp[0];
3258 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
3259 if (infoLevel != SMB_INFO_STANDARD &&
3260 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
3261 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
3262 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3263 p->opcode, infoLevel);
3264 smb_SendTran2Error(vcp, p, opx,
3265 infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3269 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3271 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
3272 osi_LogSaveClientString(smb_logp, pathp));
3274 userp = smb_GetTran2User(vcp, p);
3276 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3277 code = CM_ERROR_BADSMB;
3281 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3282 if (code == CM_ERROR_TIDIPC) {
3283 /* Attempt to use a TID allocated for IPC. The client
3284 * is probably looking for DCE RPC end points which we
3285 * don't support OR it could be looking to make a DFS
3288 osi_Log0(smb_logp, "Tran2Open received IPC TID");
3289 cm_ReleaseUser(userp);
3290 return CM_ERROR_NOSUCHPATH;
3294 * XXX Strange hack XXX
3296 * As of Patch 7 (13 January 98), we are having the following problem:
3297 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3298 * requests to look up "desktop.ini" in all the subdirectories.
3299 * This can cause zillions of timeouts looking up non-existent cells
3300 * and volumes, especially in the top-level directory.
3302 * We have not found any way to avoid this or work around it except
3303 * to explicitly ignore the requests for mount points that haven't
3304 * yet been evaluated and for directories that haven't yet been
3307 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3308 spacep = cm_GetSpace();
3309 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3310 #ifndef SPECIAL_FOLDERS
3311 /* Make sure that lastComp is not NULL */
3313 if (cm_ClientStrCmpI(lastComp, _C("\\desktop.ini")) == 0) {
3314 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3318 userp, tidPathp, &req, &dscp);
3321 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3322 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3324 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3325 code = CM_ERROR_PATH_NOT_COVERED;
3327 code = CM_ERROR_NOSUCHPATH;
3329 #endif /* DFS_SUPPORT */
3330 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3331 code = CM_ERROR_NOSUCHFILE;
3332 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3333 cm_buf_t *bp = buf_Find(dscp, &hzero);
3339 code = CM_ERROR_NOSUCHFILE;
3341 cm_ReleaseSCache(dscp);
3343 cm_FreeSpace(spacep);
3344 cm_ReleaseUser(userp);
3345 smb_SendTran2Error(vcp, p, opx, code);
3351 #endif /* SPECIAL_FOLDERS */
3353 cm_FreeSpace(spacep);
3356 /* now do namei and stat, and copy out the info */
3357 code = cm_NameI(cm_data.rootSCachep, pathp,
3358 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3360 cm_ReleaseUser(userp);
3361 smb_SendTran2Error(vcp, p, opx, code);
3365 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3367 outp->totalParms = 2;
3368 outp->totalData = 0;
3370 spi = (smb_tran2QPathInfo_t *)p->datap;
3371 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3374 /* lock the vnode with a callback; we need the current status
3375 * to determine what the new status is, in some cases.
3377 lock_ObtainWrite(&scp->rw);
3378 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3379 CM_SCACHESYNC_GETSTATUS
3380 | CM_SCACHESYNC_NEEDCALLBACK);
3382 lock_ReleaseWrite(&scp->rw);
3385 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3387 /* prepare for setattr call */
3388 attr.mask = CM_ATTRMASK_LENGTH;
3389 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3390 attr.length.HighPart = 0;
3392 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3393 smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3394 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3397 if (spi->u.QPstandardInfo.attributes != 0) {
3398 if ((scp->unixModeBits & 0222)
3399 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3400 /* make a writable file read-only */
3401 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3402 attr.unixModeBits = scp->unixModeBits & ~0222;
3404 else if ((scp->unixModeBits & 0222) == 0
3405 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3406 /* make a read-only file writable */
3407 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3408 attr.unixModeBits = scp->unixModeBits | 0222;
3411 lock_ReleaseRead(&scp->rw);
3415 code = cm_SetAttr(scp, &attr, userp, &req);
3419 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3420 /* we don't support EAs */
3421 code = CM_ERROR_EAS_NOT_SUPPORTED;
3425 cm_ReleaseSCache(scp);
3426 cm_ReleaseUser(userp);
3428 smb_SendTran2Packet(vcp, outp, opx);
3430 smb_SendTran2Error(vcp, p, opx, code);
3431 smb_FreeTran2Packet(outp);
3437 /* TRANS2_QUERY_FILE_INFORMATION */
3438 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3440 smb_tran2Packet_t *outp;
3442 unsigned long attributes;
3443 unsigned short infoLevel;
3450 smb_tran2QFileInfo_t qfi;
3458 fidp = smb_FindFID(vcp, fid, 0);
3461 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3465 lock_ObtainMutex(&fidp->mx);
3466 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3467 lock_ReleaseMutex(&fidp->mx);
3468 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3469 smb_CloseFID(vcp, fidp, NULL, 0);
3470 smb_ReleaseFID(fidp);
3473 lock_ReleaseMutex(&fidp->mx);
3475 infoLevel = p->parmsp[1];
3476 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3477 responseSize = sizeof(qfi.u.QFbasicInfo);
3478 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3479 responseSize = sizeof(qfi.u.QFstandardInfo);
3480 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3481 responseSize = sizeof(qfi.u.QFeaInfo);
3482 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3483 responseSize = sizeof(qfi.u.QFfileNameInfo);
3485 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3486 p->opcode, infoLevel);
3487 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3488 smb_ReleaseFID(fidp);
3491 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3493 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3495 if (infoLevel > 0x100)
3496 outp->totalParms = 2;
3498 outp->totalParms = 0;
3499 outp->totalData = responseSize;
3501 userp = smb_GetTran2User(vcp, p);
3503 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3504 code = CM_ERROR_BADSMB;
3508 lock_ObtainMutex(&fidp->mx);
3509 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3511 osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3513 lock_ReleaseMutex(&fidp->mx);
3514 lock_ObtainWrite(&scp->rw);
3515 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3516 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3520 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3522 lock_ConvertWToR(&scp->rw);
3525 /* now we have the status in the cache entry, and everything is locked.
3526 * Marshall the output data.
3528 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3529 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3530 qfi.u.QFbasicInfo.creationTime = ft;
3531 qfi.u.QFbasicInfo.lastAccessTime = ft;
3532 qfi.u.QFbasicInfo.lastWriteTime = ft;
3533 qfi.u.QFbasicInfo.lastChangeTime = ft;
3534 attributes = smb_ExtAttributes(scp);
3535 qfi.u.QFbasicInfo.attributes = attributes;
3537 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3538 qfi.u.QFstandardInfo.allocationSize = scp->length;
3539 qfi.u.QFstandardInfo.endOfFile = scp->length;
3540 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3541 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3542 qfi.u.QFstandardInfo.directory =
3543 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3544 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3545 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3547 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3548 qfi.u.QFeaInfo.eaSize = 0;
3550 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3554 lock_ReleaseRead(&scp->rw);
3555 lock_ObtainMutex(&fidp->mx);
3556 lock_ObtainRead(&scp->rw);
3557 if (fidp->NTopen_wholepathp)
3558 name = fidp->NTopen_wholepathp;
3560 name = _C("\\"); /* probably can't happen */
3561 lock_ReleaseMutex(&fidp->mx);
3563 smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, SMB_STRF_IGNORENUL);
3564 outp->totalData = len + 4; /* this is actually what we want to return */
3565 qfi.u.QFfileNameInfo.fileNameLength = len;
3568 /* send and free the packets */
3571 lock_ReleaseRead(&scp->rw);
3573 lock_ReleaseWrite(&scp->rw);
3574 cm_ReleaseSCache(scp);
3575 cm_ReleaseUser(userp);
3576 smb_ReleaseFID(fidp);
3578 memcpy(outp->datap, &qfi, responseSize);
3579 smb_SendTran2Packet(vcp, outp, opx);
3581 smb_SendTran2Error(vcp, p, opx, code);
3583 smb_FreeTran2Packet(outp);
3589 /* TRANS2_SET_FILE_INFORMATION */
3590 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3595 unsigned short infoLevel;
3596 smb_tran2Packet_t *outp;
3597 cm_user_t *userp = NULL;
3598 cm_scache_t *scp = NULL;
3604 fidp = smb_FindFID(vcp, fid, 0);
3607 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3611 infoLevel = p->parmsp[1];
3612 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3613 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3614 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3615 p->opcode, infoLevel);
3616 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3617 smb_ReleaseFID(fidp);
3621 lock_ObtainMutex(&fidp->mx);
3622 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3623 lock_ReleaseMutex(&fidp->mx);
3624 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3625 smb_CloseFID(vcp, fidp, NULL, 0);
3626 smb_ReleaseFID(fidp);
3630 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
3631 !(fidp->flags & SMB_FID_OPENDELETE)) {
3632 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3633 fidp, fidp->scp, fidp->flags);
3634 lock_ReleaseMutex(&fidp->mx);
3635 smb_ReleaseFID(fidp);
3636 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3639 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3640 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3641 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3642 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3643 fidp, fidp->scp, fidp->flags);
3644 lock_ReleaseMutex(&fidp->mx);
3645 smb_ReleaseFID(fidp);
3646 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3651 osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3653 lock_ReleaseMutex(&fidp->mx);
3655 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3657 outp->totalParms = 2;
3658 outp->totalData = 0;
3660 userp = smb_GetTran2User(vcp, p);
3662 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3663 code = CM_ERROR_BADSMB;
3667 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3669 unsigned int attribute;
3671 smb_tran2QFileInfo_t *sfi;
3673 sfi = (smb_tran2QFileInfo_t *)p->datap;
3675 /* lock the vnode with a callback; we need the current status
3676 * to determine what the new status is, in some cases.
3678 lock_ObtainWrite(&scp->rw);
3679 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3680 CM_SCACHESYNC_GETSTATUS
3681 | CM_SCACHESYNC_NEEDCALLBACK);
3683 lock_ReleaseWrite(&scp->rw);
3687 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3689 lock_ReleaseWrite(&scp->rw);
3690 lock_ObtainMutex(&fidp->mx);
3691 lock_ObtainRead(&scp->rw);
3693 /* prepare for setattr call */
3696 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3697 /* when called as result of move a b, lastMod is (-1, -1).
3698 * If the check for -1 is not present, timestamp
3699 * of the resulting file will be 1969 (-1)
3701 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3702 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3703 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3704 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3705 fidp->flags |= SMB_FID_MTIMESETDONE;
3708 attribute = sfi->u.QFbasicInfo.attributes;
3709 if (attribute != 0) {
3710 if ((scp->unixModeBits & 0222)
3711 && (attribute & SMB_ATTR_READONLY) != 0) {
3712 /* make a writable file read-only */
3713 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3714 attr.unixModeBits = scp->unixModeBits & ~0222;
3716 else if ((scp->unixModeBits & 0222) == 0
3717 && (attribute & SMB_ATTR_READONLY) == 0) {
3718 /* make a read-only file writable */
3719 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3720 attr.unixModeBits = scp->unixModeBits | 0222;
3723 lock_ReleaseRead(&scp->rw);
3724 lock_ReleaseMutex(&fidp->mx);
3728 code = cm_SetAttr(scp, &attr, userp, &req);
3732 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3733 int delflag = *((char *)(p->datap));
3734 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
3735 delflag, fidp, scp);
3736 if (*((char *)(p->datap))) { /* File is Deleted */
3737 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3740 lock_ObtainMutex(&fidp->mx);
3741 fidp->flags |= SMB_FID_DELONCLOSE;
3742 lock_ReleaseMutex(&fidp->mx);
3744 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
3750 lock_ObtainMutex(&fidp->mx);
3751 fidp->flags &= ~SMB_FID_DELONCLOSE;
3752 lock_ReleaseMutex(&fidp->mx);
3755 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3756 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3757 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3760 attr.mask = CM_ATTRMASK_LENGTH;
3761 attr.length.LowPart = size.LowPart;
3762 attr.length.HighPart = size.HighPart;
3763 code = cm_SetAttr(scp, &attr, userp, &req);
3767 cm_ReleaseSCache(scp);
3768 cm_ReleaseUser(userp);
3769 smb_ReleaseFID(fidp);
3771 smb_SendTran2Packet(vcp, outp, opx);
3773 smb_SendTran2Error(vcp, p, opx, code);
3774 smb_FreeTran2Packet(outp);
3781 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3783 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3784 return CM_ERROR_BADOP;
3789 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3791 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3792 return CM_ERROR_BADOP;
3795 /* TRANS2_FIND_NOTIFY_FIRST */
3797 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3799 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3800 return CM_ERROR_BADOP;
3803 /* TRANS2_FIND_NOTIFY_NEXT */
3805 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3807 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3808 return CM_ERROR_BADOP;
3811 /* TRANS2_CREATE_DIRECTORY */
3813 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3815 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3816 return CM_ERROR_BADOP;
3819 /* TRANS2_SESSION_SETUP */
3821 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3823 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3824 return CM_ERROR_BADOP;
3827 struct smb_v2_referral {
3829 USHORT ReferralFlags;
3832 USHORT DfsPathOffset;
3833 USHORT DfsAlternativePathOffset;
3834 USHORT NetworkAddressOffset;
3837 /* TRANS2_GET_DFS_REFERRAL */
3839 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3841 /* This is a UNICODE only request (bit15 of Flags2) */
3842 /* The TID must be IPC$ */
3844 /* The documentation for the Flags response field is contradictory */
3846 /* Use Version 1 Referral Element Format */
3847 /* ServerType = 0; indicates the next server should be queried for the file */
3848 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3849 /* Node = UnicodeString of UNC path of the next share name */
3852 int maxReferralLevel = 0;
3853 clientchar_t requestFileName[1024] = _C("");
3854 clientchar_t referralPath[1024] = _C("");
3855 smb_tran2Packet_t *outp = 0;
3856 cm_user_t *userp = 0;
3857 cm_scache_t *scp = 0;
3858 cm_scache_t *dscp = 0;
3860 CPINFO CodePageInfo;
3861 int i, nbnLen, reqLen, refLen;
3866 maxReferralLevel = p->parmsp[0];
3868 GetCPInfo(CP_ACP, &CodePageInfo);
3869 cm_Utf16ToClientString(&p->parmsp[1], -1, requestFileName, lengthof(requestFileName));
3871 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%S]",
3872 maxReferralLevel, osi_LogSaveClientString(smb_logp, requestFileName));
3874 nbnLen = (int)cm_ClientStrLen(cm_NetbiosNameC);
3875 reqLen = (int)cm_ClientStrLen(requestFileName);
3877 if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
3878 !cm_ClientStrCmpNI(cm_NetbiosNameC, &requestFileName[1], nbnLen) &&
3879 requestFileName[nbnLen+1] == '\\')
3883 if (!cm_ClientStrCmpNI(_C("all"), &requestFileName[nbnLen+2], 3) ||
3884 !cm_ClientStrCmpNI(_C("*."), &requestFileName[nbnLen+2], 2)) {
3886 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
3889 userp = smb_GetTran2User(vcp, p);
3891 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3892 code = CM_ERROR_BADSMB;
3897 * We have a requested path. Check to see if it is something
3900 * But be careful because the name that we might be searching
3901 * for might be a known name with the final character stripped
3904 code = cm_NameI(cm_data.rootSCachep, &requestFileName[nbnLen+2],
3905 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
3906 userp, NULL, &req, &scp);
3910 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
3912 } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
3913 clientchar_t temp[1024];
3914 clientchar_t pathName[1024];
3915 clientchar_t *lastComponent;
3917 * we have a msdfs link somewhere in the path
3918 * we should figure out where in the path the link is.
3921 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%S]", requestFileName);
3923 cm_ClientStrCpy(temp, lengthof(temp), &requestFileName[nbnLen+2]);
3927 cm_ReleaseSCache(dscp);
3931 cm_ReleaseSCache(scp);
3934 smb_StripLastComponent(pathName, &lastComponent, temp);
3936 code = cm_NameI(cm_data.rootSCachep, pathName,
3937 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3938 userp, NULL, &req, &dscp);
3940 code = cm_NameI(dscp, ++lastComponent,
3942 userp, NULL, &req, &scp);
3943 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK)
3946 } while (code == CM_ERROR_PATH_NOT_COVERED);
3948 /* scp should now be the DfsLink we are looking for */
3950 /* figure out how much of the input path was used */
3951 reqLen = (int)(nbnLen+2 + cm_ClientStrLen(pathName) + 1 + cm_ClientStrLen(lastComponent));
3953 cm_FsStringToClientString(&scp->mountPointStringp[strlen("msdfs:")], -1,
3954 referralPath, lengthof(referralPath));
3955 refLen = (int)cm_ClientStrLen(referralPath);
3959 clientchar_t shareName[MAX_PATH + 1];
3960 clientchar_t *p, *q;
3961 /* we may have a sharename that is a volume reference */
3963 for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
3969 if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
3970 code = cm_NameI(cm_data.rootSCachep, _C(""),
3971 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
3972 userp, p, &req, &scp);
3977 cm_ClientStrCpy(referralPath, lengthof(referralPath),
3988 struct smb_v2_referral * v2ref;
3989 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (refLen + 8));
3991 sp = (USHORT *)outp->datap;
3993 sp[idx++] = reqLen; /* path consumed */
3994 sp[idx++] = 1; /* number of referrals */
3995 sp[idx++] = 0x03; /* flags */
3996 #ifdef DFS_VERSION_1
3997 sp[idx++] = 1; /* Version Number */
3998 sp[idx++] = refLen + 4; /* Referral Size */
3999 sp[idx++] = 1; /* Type = SMB Server */
4000 sp[idx++] = 0; /* Do not strip path consumed */
4001 for ( i=0;i<=refLen; i++ )
4002 sp[i+idx] = referralPath[i];
4003 #else /* DFS_VERSION_2 */
4004 sp[idx++] = 2; /* Version Number */
4005 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
4006 idx += (sizeof(struct smb_v2_referral) / 2);
4007 v2ref = (struct smb_v2_referral *) &sp[5];
4008 v2ref->ServerType = 1; /* SMB Server */
4009 v2ref->ReferralFlags = 0x03;
4010 v2ref->Proximity = 0; /* closest */
4011 v2ref->TimeToLive = 3600; /* seconds */
4012 v2ref->DfsPathOffset = idx * 2;
4013 v2ref->DfsAlternativePathOffset = idx * 2;
4014 v2ref->NetworkAddressOffset = 0;
4015 for ( i=0;i<=refLen; i++ )
4016 sp[i+idx] = referralPath[i];
4020 code = CM_ERROR_NOSUCHPATH;
4025 cm_ReleaseSCache(dscp);
4027 cm_ReleaseSCache(scp);
4029 cm_ReleaseUser(userp);
4031 smb_SendTran2Packet(vcp, outp, op);
4033 smb_SendTran2Error(vcp, p, op, code);
4035 smb_FreeTran2Packet(outp);
4038 #else /* DFS_SUPPORT */
4039 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
4040 return CM_ERROR_NOSUCHDEVICE;
4041 #endif /* DFS_SUPPORT */
4044 /* TRANS2_REPORT_DFS_INCONSISTENCY */
4046 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4048 /* This is a UNICODE only request (bit15 of Flags2) */
4050 /* There is nothing we can do about this operation. The client is going to
4051 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
4052 * Unfortunately, there is really nothing we can do about it other then log it
4053 * somewhere. Even then I don't think there is anything for us to do.
4054 * So let's return an error value.
4057 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
4058 return CM_ERROR_BADOP;
4062 smb_ApplyV3DirListPatches(cm_scache_t *dscp, smb_dirListPatch_t **dirPatchespp,
4063 clientchar_t * tidPathp, clientchar_t * relPathp,
4064 int infoLevel, cm_user_t *userp, cm_req_t *reqp)
4068 cm_scache_t *targetScp; /* target if scp is a symlink */
4071 unsigned short attr;
4072 unsigned long lattr;
4073 smb_dirListPatch_t *patchp;
4074 smb_dirListPatch_t *npatchp;
4076 afs_int32 mustFake = 0;
4077 clientchar_t path[AFSPATHMAX];
4079 code = cm_FindACLCache(dscp, userp, &rights);
4081 lock_ObtainWrite(&dscp->rw);
4082 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4083 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4085 cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4086 lock_ReleaseWrite(&dscp->rw);
4087 if (code == CM_ERROR_NOACCESS) {
4095 if (!mustFake) { /* Bulk Stat */
4097 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4099 memset(bsp, 0, sizeof(cm_bulkStat_t));
4101 for (patchp = *dirPatchespp, count=0;
4103 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4104 cm_scache_t *tscp = NULL;
4107 code = cm_GetSCache(&patchp->fid, &tscp, userp, reqp);
4109 if (lock_TryWrite(&tscp->rw)) {
4110 /* we have an entry that we can look at */
4111 #ifdef AFS_FREELANCE_CLIENT
4112 if (dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID && dscp->fid.volume == AFS_FAKE_ROOT_VOL_ID) {
4113 code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
4114 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4116 cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4118 lock_ReleaseWrite(&tscp->rw);
4119 cm_ReleaseSCache(tscp);
4122 #endif /* AFS_FREELANCE_CLIENT */
4123 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4124 /* we have a callback on it. Don't bother
4125 * fetching this stat entry, since we're happy
4126 * with the info we have.
4128 lock_ReleaseWrite(&tscp->rw);
4129 cm_ReleaseSCache(tscp);
4132 lock_ReleaseWrite(&tscp->rw);
4134 cm_ReleaseSCache(tscp);
4138 bsp->fids[i].Volume = patchp->fid.volume;
4139 bsp->fids[i].Vnode = patchp->fid.vnode;
4140 bsp->fids[i].Unique = patchp->fid.unique;
4142 if (bsp->counter == AFSCBMAX) {
4143 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4144 memset(bsp, 0, sizeof(cm_bulkStat_t));
4148 if (bsp->counter > 0)
4149 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4154 for( patchp = *dirPatchespp;
4156 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4157 cm_ClientStrPrintfN(path, lengthof(path),_C("%s\\%S"),
4158 relPathp ? relPathp : _C(""), patchp->dep->name);
4159 reqp->relPathp = path;
4160 reqp->tidPathp = tidPathp;
4162 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4163 reqp->relPathp = reqp->tidPathp = NULL;
4167 lock_ObtainWrite(&scp->rw);
4168 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4169 lock_ReleaseWrite(&scp->rw);
4171 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4172 errors in the client. */
4173 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4174 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4176 /* 1969-12-31 23:59:59 +00 */
4177 ft.dwHighDateTime = 0x19DB200;
4178 ft.dwLowDateTime = 0x5BB78980;
4180 /* copy to Creation Time */
4181 fa->creationTime = ft;
4182 fa->lastAccessTime = ft;
4183 fa->lastWriteTime = ft;
4184 fa->lastChangeTime = ft;
4186 switch (scp->fileType) {
4187 case CM_SCACHETYPE_DIRECTORY:
4188 case CM_SCACHETYPE_MOUNTPOINT:
4189 case CM_SCACHETYPE_INVALID:
4190 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4192 case CM_SCACHETYPE_SYMLINK:
4193 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4194 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4196 fa->extFileAttributes = SMB_ATTR_NORMAL;
4199 /* if we get here we either have a normal file
4200 * or we have a file for which we have never
4201 * received status info. In this case, we can
4202 * check the even/odd value of the entry's vnode.
4203 * odd means it is to be treated as a directory
4204 * and even means it is to be treated as a file.
4206 if (mustFake && (scp->fid.vnode & 0x1))
4207 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4209 fa->extFileAttributes = SMB_ATTR_NORMAL;
4211 /* merge in hidden attribute */
4212 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4213 fa->extFileAttributes |= SMB_ATTR_HIDDEN;
4216 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4218 /* 1969-12-31 23:59:58 +00*/
4219 dosTime = 0xEBBFBF7D;
4221 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4222 fa->lastAccessDateTime = fa->creationDateTime;
4223 fa->lastWriteDateTime = fa->creationDateTime;
4225 /* set the attribute */
4226 switch (scp->fileType) {
4227 case CM_SCACHETYPE_DIRECTORY:
4228 case CM_SCACHETYPE_MOUNTPOINT:
4229 case CM_SCACHETYPE_INVALID:
4230 fa->attributes = SMB_ATTR_DIRECTORY;
4232 case CM_SCACHETYPE_SYMLINK:
4233 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4234 fa->attributes = SMB_ATTR_DIRECTORY;
4236 fa->attributes = SMB_ATTR_NORMAL;
4239 /* if we get here we either have a normal file
4240 * or we have a file for which we have never
4241 * received status info. In this case, we can
4242 * check the even/odd value of the entry's vnode.
4243 * even means it is to be treated as a directory
4244 * and odd means it is to be treated as a file.
4246 if (mustFake && (scp->fid.vnode & 0x1))
4247 fa->attributes = SMB_ATTR_DIRECTORY;
4249 fa->attributes = SMB_ATTR_NORMAL;
4252 /* merge in hidden (dot file) attribute */
4253 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4254 fa->attributes |= SMB_ATTR_HIDDEN;
4258 cm_ReleaseSCache(scp);
4262 /* now watch for a symlink */
4264 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
4265 lock_ReleaseWrite(&scp->rw);
4266 cm_ClientStrPrintfN(path, lengthof(path), _C("%s\\%S"),
4267 relPathp ? relPathp : _C(""), patchp->dep->name);
4268 reqp->relPathp = path;
4269 reqp->tidPathp = tidPathp;
4270 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
4271 reqp->relPathp = reqp->tidPathp = NULL;
4273 /* we have a more accurate file to use (the
4274 * target of the symbolic link). Otherwise,
4275 * we'll just use the symlink anyway.
4277 osi_Log2(smb_logp, "symlink vp %x to vp %x",
4279 cm_ReleaseSCache(scp);
4282 lock_ObtainWrite(&scp->rw);
4285 lock_ConvertWToR(&scp->rw);
4287 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4288 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4291 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4293 fa->creationTime = ft;
4294 fa->lastAccessTime = ft;
4295 fa->lastWriteTime = ft;
4296 fa->lastChangeTime = ft;
4298 /* Use length for both file length and alloc length */
4299 fa->endOfFile = scp->length;
4300 fa->allocationSize = scp->length;
4302 /* Copy attributes */
4303 lattr = smb_ExtAttributes(scp);
4304 if ((code == CM_ERROR_NOSUCHPATH &&
4305 (scp->fileType == CM_SCACHETYPE_SYMLINK &&
4306 cm_TargetPerceivedAsDirectory(scp->mountPointStringp))) ||
4307 code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4308 if (lattr == SMB_ATTR_NORMAL)
4309 lattr = SMB_ATTR_DIRECTORY;
4311 lattr |= SMB_ATTR_DIRECTORY;
4313 /* merge in hidden (dot file) attribute */
4314 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4315 if (lattr == SMB_ATTR_NORMAL)
4316 lattr = SMB_ATTR_HIDDEN;
4318 lattr |= SMB_ATTR_HIDDEN;
4321 fa->extFileAttributes = lattr;
4323 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4326 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4328 fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
4329 fa->lastAccessDateTime = fa->creationDateTime;
4330 fa->lastWriteDateTime = fa->creationDateTime;
4332 /* copy out file length and alloc length,
4333 * using the same for both
4335 fa->dataSize = scp->length.LowPart;
4336 fa->allocationSize = scp->length.LowPart;
4338 /* finally copy out attributes as short */
4339 attr = smb_Attributes(scp);
4340 /* merge in hidden (dot file) attribute */
4341 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4342 if (lattr == SMB_ATTR_NORMAL)
4343 lattr = SMB_ATTR_HIDDEN;
4345 lattr |= SMB_ATTR_HIDDEN;
4347 fa->attributes = attr;
4350 lock_ReleaseRead(&scp->rw);
4351 cm_ReleaseSCache(scp);
4354 /* now free the patches */
4355 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4356 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4360 /* and mark the list as empty */
4361 *dirPatchespp = NULL;
4367 /* smb_ReceiveTran2SearchDir implements both
4368 * Tran2_Find_First and Tran2_Find_Next
4370 #define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
4371 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
4372 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
4373 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
4374 #define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
4376 /* this is an optimized handler for T2SearchDir that handles the case
4377 where there are no wildcards in the search path. I.e. an
4378 application is using FindFirst(Ex) to get information about a
4379 single file or directory. It will attempt to do a single lookup.
4380 If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4381 the usual mechanism.
4383 This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4385 TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
4387 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4391 long code = 0, code2 = 0;
4392 clientchar_t *pathp = 0;
4394 smb_dirListPatch_t *dirListPatchesp;
4395 smb_dirListPatch_t *curPatchp;
4396 size_t orbytes; /* # of bytes in this output record */
4397 size_t ohbytes; /* # of bytes, except file name */
4398 size_t onbytes; /* # of bytes in name, incl. term. null */
4399 cm_scache_t *scp = NULL;
4400 cm_scache_t *targetscp = NULL;
4401 cm_user_t *userp = NULL;
4402 char *op; /* output data ptr */
4403 char *origOp; /* original value of op */
4404 cm_space_t *spacep; /* for pathname buffer */
4405 unsigned long maxReturnData; /* max # of return data */
4406 long maxReturnParms; /* max # of return parms */
4407 long bytesInBuffer; /* # data bytes in the output buffer */
4408 clientchar_t *maskp; /* mask part of path */
4412 smb_tran2Packet_t *outp; /* response packet */
4413 clientchar_t *tidPathp = 0;
4415 clientchar_t shortName[13]; /* 8.3 name if needed */
4417 clientchar_t *shortNameEnd;
4418 cm_dirEntry_t * dep = NULL;
4421 void * attrp = NULL;
4422 smb_tran2Find_t * fp;
4427 osi_assertx(p->opcode == 1, "invalid opcode");
4429 /* find first; obtain basic parameters from request */
4431 /* note that since we are going to failover to regular
4432 * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4433 * modify any of the input parameters here. */
4434 attribute = p->parmsp[0];
4435 maxCount = p->parmsp[1];
4436 infoLevel = p->parmsp[3];
4437 searchFlags = p->parmsp[2];
4438 pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4440 maskp = cm_ClientStrRChr(pathp, '\\');
4444 maskp++; /* skip over backslash */
4445 /* track if this is likely to match a lot of entries */
4447 osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%S], mask[%S]",
4448 osi_LogSaveClientString(smb_logp, pathp),
4449 osi_LogSaveClientString(smb_logp, maskp));
4451 switch ( infoLevel ) {
4452 case SMB_INFO_STANDARD:
4454 ohbytes = sizeof(fp->u.FstandardInfo);
4457 case SMB_INFO_QUERY_EA_SIZE:
4458 ohbytes = sizeof(fp->u.FeaSizeInfo);
4459 s = "InfoQueryEaSize";
4462 case SMB_INFO_QUERY_EAS_FROM_LIST:
4463 ohbytes = sizeof(fp->u.FeasFromListInfo);
4464 s = "InfoQueryEasFromList";
4467 case SMB_FIND_FILE_DIRECTORY_INFO:
4468 s = "FindFileDirectoryInfo";
4469 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4472 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4473 s = "FindFileFullDirectoryInfo";
4474 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4477 case SMB_FIND_FILE_NAMES_INFO:
4478 s = "FindFileNamesInfo";
4479 ohbytes = sizeof(fp->u.FfileNamesInfo);
4482 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4483 s = "FindFileBothDirectoryInfo";
4484 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4488 s = "unknownInfoLevel";
4492 osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
4495 "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4496 attribute, infoLevel, maxCount, searchFlags);
4499 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4500 return CM_ERROR_INVAL;
4503 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4504 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4506 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4509 dirListPatchesp = NULL;
4511 maxReturnData = p->maxReturnData;
4512 maxReturnParms = 10; /* return params for findfirst, which
4513 is the only one we handle.*/
4515 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4518 osi_Log2(smb_logp, "T2SDSingle search dir count %d [%S]",
4519 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4521 /* bail out if request looks bad */
4523 smb_FreeTran2Packet(outp);
4524 return CM_ERROR_BADSMB;
4527 userp = smb_GetTran2User(vcp, p);
4529 osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
4530 smb_FreeTran2Packet(outp);
4531 return CM_ERROR_BADSMB;
4534 /* try to get the vnode for the path name next */
4535 spacep = cm_GetSpace();
4536 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4537 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4539 cm_ReleaseUser(userp);
4540 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4541 smb_FreeTran2Packet(outp);
4545 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4546 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4547 userp, tidPathp, &req, &scp);
4548 cm_FreeSpace(spacep);
4551 cm_ReleaseUser(userp);
4552 smb_SendTran2Error(vcp, p, opx, code);
4553 smb_FreeTran2Packet(outp);
4557 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4558 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4559 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
4560 cm_ReleaseSCache(scp);
4561 cm_ReleaseUser(userp);
4562 if ( WANTS_DFS_PATHNAMES(p) || pnc )
4563 code = CM_ERROR_PATH_NOT_COVERED;
4565 code = CM_ERROR_NOSUCHPATH;
4566 smb_SendTran2Error(vcp, p, opx, code);
4567 smb_FreeTran2Packet(outp);
4570 #endif /* DFS_SUPPORT */
4571 osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
4573 /* now do a single case sensitive lookup for the file in question */
4574 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
4576 /* if a case sensitive match failed, we try a case insensitive one
4578 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
4579 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
4582 if (code == 0 && targetscp->fid.vnode == 0) {
4583 cm_ReleaseSCache(targetscp);
4584 code = CM_ERROR_NOSUCHFILE;
4588 /* if we can't find the directory entry, this block will
4589 return CM_ERROR_NOSUCHFILE, which we will pass on to
4590 smb_ReceiveTran2SearchDir(). */
4591 cm_ReleaseSCache(scp);
4592 cm_ReleaseUser(userp);
4593 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4594 smb_SendTran2Error(vcp, p, opx, code);
4597 smb_FreeTran2Packet(outp);
4601 /* now that we have the target in sight, we proceed with filling
4602 up the return data. */
4604 op = origOp = outp->datap;
4607 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4608 /* skip over resume key */
4612 fp = (smb_tran2Find_t *) op;
4614 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4615 && targetscp->fid.vnode != 0
4616 && !cm_Is8Dot3(maskp)) {
4619 dfid.vnode = htonl(targetscp->fid.vnode);
4620 dfid.unique = htonl(targetscp->fid.unique);
4622 cm_Gen8Dot3NameIntW(maskp, &dfid, shortName, &shortNameEnd);
4628 osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %S (%S)",
4629 htonl(targetscp->fid.vnode),
4630 htonl(targetscp->fid.unique),
4631 osi_LogSaveClientString(smb_logp, pathp),
4632 (NeedShortName)? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
4634 /* Eliminate entries that don't match requested attributes */
4635 if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
4636 smb_IsDotFile(maskp)) {
4638 code = CM_ERROR_NOSUCHFILE;
4639 osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
4644 if (!(attribute & SMB_ATTR_DIRECTORY) &&
4645 (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
4646 targetscp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4647 targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
4648 targetscp->fileType == CM_SCACHETYPE_INVALID)) {
4650 code = CM_ERROR_NOSUCHFILE;
4651 osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
4656 /* add header to name & term. null */
4658 smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
4659 orbytes = ohbytes + onbytes;
4661 /* now, we round up the record to a 4 byte alignment, and we make
4662 * sure that we have enough room here for even the aligned version
4663 * (so we don't have to worry about an * overflow when we pad
4664 * things out below). That's the reason for the alignment
4667 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4668 align = (4 - (orbytes & 3)) & 3;
4672 if (orbytes + align > maxReturnData) {
4674 /* even though this request is unlikely to succeed with a
4675 failover, we do it anyway. */
4676 code = CM_ERROR_NOSUCHFILE;
4677 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4682 /* this is one of the entries to use: it is not deleted and it
4683 * matches the star pattern we're looking for. Put out the name,
4684 * preceded by its length.
4686 /* First zero everything else */
4687 memset(origOp, 0, orbytes);
4690 smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
4692 switch (infoLevel) {
4693 case SMB_INFO_STANDARD:
4694 fp->u.FstandardInfo.fileNameLength = onbytes;
4695 attrp = &fp->u.FstandardInfo.fileAttrs;
4698 case SMB_INFO_QUERY_EA_SIZE:
4699 fp->u.FeaSizeInfo.fileNameLength = onbytes;
4700 attrp = &fp->u.FeaSizeInfo.fileAttrs;
4701 fp->u.FeaSizeInfo.eaSize = 0;
4704 case SMB_INFO_QUERY_EAS_FROM_LIST:
4705 fp->u.FeasFromListInfo.fileNameLength = onbytes;
4706 attrp = &fp->u.FeasFromListInfo.fileAttrs;
4707 fp->u.FeasFromListInfo.eaSize = 0;
4710 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4711 if (NeedShortName) {
4715 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
4716 fp->u.FfileBothDirectoryInfo.shortName,
4717 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
4719 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
4721 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
4722 fp->u.FfileBothDirectoryInfo.reserved = 0;
4724 strcpy(fp->u.FfileBothDirectoryInfo.shortName,
4726 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
4731 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4732 fp->u.FfileFullDirectoryInfo.eaSize = 0;
4735 case SMB_FIND_FILE_DIRECTORY_INFO:
4736 fp->u.FfileDirectoryInfo.nextEntryOffset = 0;
4737 fp->u.FfileDirectoryInfo.fileIndex = 0;
4738 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
4739 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
4742 case SMB_FIND_FILE_NAMES_INFO:
4743 fp->u.FfileNamesInfo.nextEntryOffset = 0;
4744 fp->u.FfileNamesInfo.fileIndex = 0;
4745 fp->u.FfileNamesInfo.fileNameLength = onbytes;
4749 /* we shouldn't hit this case */
4750 osi_assertx(FALSE, "Unknown query type");
4753 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4754 osi_assert(attrp != NULL);
4756 curPatchp = malloc(sizeof(*curPatchp));
4757 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4759 curPatchp->dptr = attrp;
4761 if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
4762 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4764 curPatchp->flags = 0;
4767 cm_SetFid(&curPatchp->fid, targetscp->fid.cell, targetscp->fid.volume, targetscp->fid.vnode, targetscp->fid.unique);
4771 int namelen = cm_ClientStringToFsString(maskp, -1, NULL, 0);
4772 dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+namelen);
4773 cm_ClientStringToFsString(maskp, -1, dep->name, namelen);
4775 dep->fid.vnode = targetscp->fid.vnode;
4776 dep->fid.unique = targetscp->fid.unique;
4777 curPatchp->dep = dep;
4780 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4781 /* put out resume key */
4782 *((u_long *)origOp) = 0;
4785 /* Adjust byte ptr and count */
4786 origOp += orbytes; /* skip entire record */
4787 bytesInBuffer += orbytes;
4789 /* and pad the record out */
4790 while (--align >= 0) {
4795 /* apply the patches */
4796 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->wdata, infoLevel, userp, &req);
4798 outp->parmsp[0] = 0;
4799 outp->parmsp[1] = 1; /* number of names returned */
4800 outp->parmsp[2] = 1; /* end of search */
4801 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4802 outp->parmsp[4] = 0;
4804 outp->totalParms = 10; /* in bytes */
4806 outp->totalData = bytesInBuffer;
4808 osi_Log0(smb_logp, "T2SDSingle done.");
4810 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4812 smb_SendTran2Error(vcp, p, opx, code);
4814 smb_SendTran2Packet(vcp, outp, opx);
4819 smb_FreeTran2Packet(outp);
4823 cm_ReleaseSCache(scp);
4824 cm_ReleaseSCache(targetscp);
4825 cm_ReleaseUser(userp);
4831 /* TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2 */
4832 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4837 long code = 0, code2 = 0;
4838 clientchar_t *pathp;
4839 cm_dirEntry_t *dep = 0;
4841 smb_dirListPatch_t *dirListPatchesp = 0;
4842 smb_dirListPatch_t *curPatchp = 0;
4845 size_t orbytes; /* # of bytes in this output record */
4846 size_t ohbytes; /* # of bytes, except file name */
4847 size_t onbytes; /* # of bytes in name, incl. term. null */
4848 osi_hyper_t dirLength;
4849 osi_hyper_t bufferOffset;
4850 osi_hyper_t curOffset;
4852 smb_dirSearch_t *dsp;
4856 cm_pageHeader_t *pageHeaderp;
4857 cm_user_t *userp = NULL;
4860 long nextEntryCookie;
4861 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4862 char *op; /* output data ptr */
4863 char *origOp; /* original value of op */
4864 cm_space_t *spacep; /* for pathname buffer */
4865 unsigned long maxReturnData; /* max # of return data */
4866 unsigned long maxReturnParms; /* max # of return parms */
4867 long bytesInBuffer; /* # data bytes in the output buffer */
4869 clientchar_t *maskp; /* mask part of path */
4873 smb_tran2Packet_t *outp; /* response packet */
4874 clientchar_t *tidPathp;
4876 clientchar_t shortName[13]; /* 8.3 name if needed */
4879 clientchar_t *shortNameEnd;
4885 smb_tran2Find_t * fp;
4890 if (p->opcode == 1) {
4891 /* find first; obtain basic parameters from request */
4892 attribute = p->parmsp[0];
4893 maxCount = p->parmsp[1];
4894 infoLevel = p->parmsp[3];
4895 searchFlags = p->parmsp[2];
4896 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4898 maskp = cm_ClientStrRChr(pathp, '\\');
4902 maskp++; /* skip over backslash */
4904 /* track if this is likely to match a lot of entries */
4905 starPattern = smb_V3IsStarMask(maskp);
4907 #ifndef NOFINDFIRSTOPTIMIZE
4909 /* if this is for a single directory or file, we let the
4910 optimized routine handle it. The only error it
4911 returns is CM_ERROR_NOSUCHFILE. The */
4912 code = smb_T2SearchDirSingle(vcp, p, opx);
4914 /* we only failover if we see a CM_ERROR_NOSUCHFILE */
4915 if (code != CM_ERROR_NOSUCHFILE) {
4917 /* unless we are using the BPlusTree */
4918 if (code == CM_ERROR_BPLUS_NOMATCH)
4919 code = CM_ERROR_NOSUCHFILE;
4920 #endif /* USE_BPLUS */
4924 #endif /* NOFINDFIRSTOPTIMIZE */
4927 dsp = smb_NewDirSearch(1);
4928 dsp->attribute = attribute;
4929 cm_ClientStrCpy(dsp->mask, lengthof(dsp->mask), maskp); /* and save mask */
4932 osi_assertx(p->opcode == 2, "invalid opcode");
4933 /* find next; obtain basic parameters from request or open dir file */
4934 dsp = smb_FindDirSearch(p->parmsp[0]);
4935 maxCount = p->parmsp[1];
4936 infoLevel = p->parmsp[2];
4937 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4938 searchFlags = p->parmsp[5];
4940 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4941 p->parmsp[0], nextCookie);
4942 return CM_ERROR_BADFD;
4944 attribute = dsp->attribute;
4947 starPattern = 1; /* assume, since required a Find Next */
4950 switch ( infoLevel ) {
4951 case SMB_INFO_STANDARD:
4953 ohbytes = sizeof(fp->u.FstandardInfo);
4956 case SMB_INFO_QUERY_EA_SIZE:
4957 ohbytes = sizeof(fp->u.FeaSizeInfo);
4958 s = "InfoQueryEaSize";
4961 case SMB_INFO_QUERY_EAS_FROM_LIST:
4962 ohbytes = sizeof(fp->u.FeasFromListInfo);
4963 s = "InfoQueryEasFromList";
4966 case SMB_FIND_FILE_DIRECTORY_INFO:
4967 s = "FindFileDirectoryInfo";
4968 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4971 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4972 s = "FindFileFullDirectoryInfo";
4973 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4976 case SMB_FIND_FILE_NAMES_INFO:
4977 s = "FindFileNamesInfo";
4978 ohbytes = sizeof(fp->u.FfileNamesInfo);
4981 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4982 s = "FindFileBothDirectoryInfo";
4983 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4987 s = "unknownInfoLevel";
4991 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
4994 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4995 attribute, infoLevel, maxCount, searchFlags);
4997 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
4998 p->opcode, dsp->cookie, nextCookie);
5001 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
5002 smb_ReleaseDirSearch(dsp);
5003 return CM_ERROR_INVAL;
5006 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5007 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
5009 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5012 dirListPatchesp = NULL;
5014 maxReturnData = p->maxReturnData;
5015 if (p->opcode == 1) /* find first */
5016 maxReturnParms = 10; /* bytes */
5018 maxReturnParms = 8; /* bytes */
5020 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
5026 osi_Log2(smb_logp, "T2 receive search dir count %d [%S]",
5027 maxCount, osi_LogSaveClientString(smb_logp, pathp));
5029 /* bail out if request looks bad */
5030 if (p->opcode == 1 && !pathp) {
5031 smb_ReleaseDirSearch(dsp);
5032 smb_FreeTran2Packet(outp);
5033 return CM_ERROR_BADSMB;
5036 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
5037 dsp->cookie, nextCookie, attribute);
5039 userp = smb_GetTran2User(vcp, p);
5041 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
5042 smb_ReleaseDirSearch(dsp);
5043 smb_FreeTran2Packet(outp);
5044 return CM_ERROR_BADSMB;
5047 /* try to get the vnode for the path name next */
5048 lock_ObtainMutex(&dsp->mx);
5051 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5055 spacep = cm_GetSpace();
5056 smb_StripLastComponent(spacep->wdata, NULL, pathp);
5057 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
5059 cm_ReleaseUser(userp);
5060 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
5061 smb_FreeTran2Packet(outp);
5062 lock_ReleaseMutex(&dsp->mx);
5063 smb_DeleteDirSearch(dsp);
5064 smb_ReleaseDirSearch(dsp);
5068 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
5069 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
5071 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
5072 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5073 userp, tidPathp, &req, &scp);
5074 cm_FreeSpace(spacep);
5077 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
5078 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5079 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
5080 cm_ReleaseSCache(scp);
5081 cm_ReleaseUser(userp);
5082 if ( WANTS_DFS_PATHNAMES(p) || pnc )
5083 code = CM_ERROR_PATH_NOT_COVERED;
5085 code = CM_ERROR_NOSUCHPATH;
5086 smb_SendTran2Error(vcp, p, opx, code);
5087 smb_FreeTran2Packet(outp);
5088 lock_ReleaseMutex(&dsp->mx);
5089 smb_DeleteDirSearch(dsp);
5090 smb_ReleaseDirSearch(dsp);
5093 #endif /* DFS_SUPPORT */
5095 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5096 /* we need one hold for the entry we just stored into,
5097 * and one for our own processing. When we're done
5098 * with this function, we'll drop the one for our own
5099 * processing. We held it once from the namei call,
5100 * and so we do another hold now.
5103 dsp->flags |= SMB_DIRSEARCH_BULKST;
5106 lock_ReleaseMutex(&dsp->mx);
5108 cm_ReleaseUser(userp);
5109 smb_FreeTran2Packet(outp);
5110 smb_DeleteDirSearch(dsp);
5111 smb_ReleaseDirSearch(dsp);
5115 /* get the directory size */
5116 lock_ObtainWrite(&scp->rw);
5117 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5118 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5120 lock_ReleaseWrite(&scp->rw);
5121 cm_ReleaseSCache(scp);
5122 cm_ReleaseUser(userp);
5123 smb_FreeTran2Packet(outp);
5124 smb_DeleteDirSearch(dsp);
5125 smb_ReleaseDirSearch(dsp);
5129 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5132 dirLength = scp->length;
5134 bufferOffset.LowPart = bufferOffset.HighPart = 0;
5135 curOffset.HighPart = 0;
5136 curOffset.LowPart = nextCookie;
5137 origOp = outp->datap;
5144 normchar_t normName[MAX_PATH]; /* Normalized name */
5145 clientchar_t cfileName[MAX_PATH]; /* Non-normalized name */
5148 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5149 /* skip over resume key */
5152 fp = (smb_tran2Find_t *) op;
5154 /* make sure that curOffset.LowPart doesn't point to the first
5155 * 32 bytes in the 2nd through last dir page, and that it doesn't
5156 * point at the first 13 32-byte chunks in the first dir page,
5157 * since those are dir and page headers, and don't contain useful
5160 temp = curOffset.LowPart & (2048-1);
5161 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5162 /* we're in the first page */
5163 if (temp < 13*32) temp = 13*32;
5166 /* we're in a later dir page */
5167 if (temp < 32) temp = 32;
5170 /* make sure the low order 5 bits are zero */
5173 /* now put temp bits back ito curOffset.LowPart */
5174 curOffset.LowPart &= ~(2048-1);
5175 curOffset.LowPart |= temp;
5177 /* check if we've passed the dir's EOF */
5178 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
5179 osi_Log0(smb_logp, "T2 search dir passed eof");
5184 /* check if we've returned all the names that will fit in the
5185 * response packet; we check return count as well as the number
5186 * of bytes requested. We check the # of bytes after we find
5187 * the dir entry, since we'll need to check its size.
5189 if (returnedNames >= maxCount) {
5190 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
5191 returnedNames, maxCount);
5195 /* when we have obtained as many entries as can be processed in
5196 * a single Bulk Status call to the file server, apply the dir listing
5199 if (returnedNames > 0 && returnedNames % AFSCBMAX == 0) {
5200 lock_ReleaseWrite(&scp->rw);
5201 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5202 dsp->relPath, infoLevel, userp, &req);
5203 lock_ObtainWrite(&scp->rw);
5205 /* Then check to see if we have time left to process more entries */
5206 if (GetTickCount() - req.startTime > (RDRtimeout - 15) * 1000) {
5207 osi_Log0(smb_logp, "T2 search dir RDRtimeout exceeded");
5211 /* see if we can use the bufferp we have now; compute in which
5212 * page the current offset would be, and check whether that's
5213 * the offset of the buffer we have. If not, get the buffer.
5215 thyper.HighPart = curOffset.HighPart;
5216 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5217 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5220 buf_Release(bufferp);
5223 lock_ReleaseWrite(&scp->rw);
5224 code = buf_Get(scp, &thyper, &bufferp);
5225 lock_ObtainWrite(&scp->rw);
5227 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
5231 bufferOffset = thyper;
5233 /* now get the data in the cache */
5235 code = cm_SyncOp(scp, bufferp, userp, &req,
5237 CM_SCACHESYNC_NEEDCALLBACK
5238 | CM_SCACHESYNC_READ);
5240 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5244 if (cm_HaveBuffer(scp, bufferp, 0)) {
5245 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5246 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5250 /* otherwise, load the buffer and try again */
5251 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5253 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5255 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5256 scp, bufferp, code);
5261 buf_Release(bufferp);
5265 } /* if (wrong buffer) ... */
5267 /* now we have the buffer containing the entry we're interested
5268 * in; copy it out if it represents a non-deleted entry.
5270 entryInDir = curOffset.LowPart & (2048-1);
5271 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5273 /* page header will help tell us which entries are free. Page
5274 * header can change more often than once per buffer, since
5275 * AFS 3 dir page size may be less than (but not more than)
5276 * a buffer package buffer.
5278 /* only look intra-buffer */
5279 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5280 temp &= ~(2048 - 1); /* turn off intra-page bits */
5281 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5283 /* now determine which entry we're looking at in the page.
5284 * If it is free (there's a free bitmap at the start of the
5285 * dir), we should skip these 32 bytes.
5287 slotInPage = (entryInDir & 0x7e0) >> 5;
5288 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5289 (1 << (slotInPage & 0x7)))) {
5290 /* this entry is free */
5291 numDirChunks = 1; /* only skip this guy */
5295 tp = bufferp->datap + entryInBuffer;
5296 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5298 /* while we're here, compute the next entry's location, too,
5299 * since we'll need it when writing out the cookie into the dir
5302 * XXXX Probably should do more sanity checking.
5304 numDirChunks = cm_NameEntries(dep->name, &onbytes);
5306 /* compute offset of cookie representing next entry */
5307 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5309 if (dep->fid.vnode == 0)
5310 goto nextEntry; /* This entry is not in use */
5312 if (cm_FsStringToClientString(dep->name, -1, cfileName, lengthof(cfileName)) == 0 ||
5313 cm_ClientStringToNormString(cfileName, -1, normName, lengthof(normName)) == 0) {
5315 osi_Log1(smb_logp, "Skipping entry [%s]. Can't convert or normalize FS String",
5316 osi_LogSaveString(smb_logp, dep->name));
5320 /* Need 8.3 name? */
5322 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
5323 !cm_Is8Dot3(cfileName)) {
5324 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5328 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %S (%S)",
5329 dep->fid.vnode, dep->fid.unique,
5330 osi_LogSaveClientString(smb_logp, cfileName),
5331 NeedShortName ? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
5333 /* When matching, we are using doing a case fold if we have a wildcard mask.
5334 * If we get a non-wildcard match, it's a lookup for a specific file.
5336 if (cm_MatchMask(normName, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5337 (NeedShortName && cm_MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))
5339 /* Eliminate entries that don't match requested attributes */
5340 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5341 smb_IsDotFile(cfileName)) {
5342 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5343 goto nextEntry; /* no hidden files */
5346 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5348 /* We have already done the cm_TryBulkStat above */
5349 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume,
5350 ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5351 fileType = cm_FindFileType(&fid);
5352 /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5353 * "has filetype %d", dep->name, fileType);
5355 if ( fileType == CM_SCACHETYPE_DIRECTORY ||
5356 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5357 fileType == CM_SCACHETYPE_DFSLINK ||
5358 fileType == CM_SCACHETYPE_INVALID)
5359 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5363 /* finally check if this name will fit */
5365 smb_UnparseString(opx, NULL, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5366 orbytes = ohbytes + onbytes;
5368 /* now, we round up the record to a 4 byte alignment,
5369 * and we make sure that we have enough room here for
5370 * even the aligned version (so we don't have to worry
5371 * about an overflow when we pad things out below).
5372 * That's the reason for the alignment arithmetic below.
5374 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5375 align = (4 - (orbytes & 3)) & 3;
5379 if (orbytes + bytesInBuffer + align > maxReturnData) {
5380 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5385 /* this is one of the entries to use: it is not deleted
5386 * and it matches the star pattern we're looking for.
5387 * Put out the name, preceded by its length.
5389 /* First zero everything else */
5390 memset(origOp, 0, orbytes);
5393 smb_UnparseString(opx, origOp + ohbytes, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5395 switch (infoLevel) {
5396 case SMB_INFO_STANDARD:
5397 fp->u.FstandardInfo.fileNameLength = onbytes;
5398 attrp = &fp->u.FstandardInfo.fileAttrs;
5401 case SMB_INFO_QUERY_EA_SIZE:
5402 fp->u.FeaSizeInfo.fileNameLength = onbytes;
5403 attrp = &fp->u.FeaSizeInfo.fileAttrs;
5404 fp->u.FeaSizeInfo.eaSize = 0;
5407 case SMB_INFO_QUERY_EAS_FROM_LIST:
5408 fp->u.FeasFromListInfo.fileNameLength = onbytes;
5409 attrp = &fp->u.FeasFromListInfo.fileAttrs;
5410 fp->u.FeasFromListInfo.eaSize = 0;
5413 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5414 if (NeedShortName) {
5418 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
5419 fp->u.FfileBothDirectoryInfo.shortName,
5420 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
5422 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
5424 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5425 fp->u.FfileBothDirectoryInfo.reserved = 0;
5427 cm_ClientStrCpy(fp->u.FfileBothDirectoryInfo.shortName,
5428 lengthof(fp->u.FfileBothDirectoryInfo.shortName),
5430 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
5435 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5436 fp->u.FfileFullDirectoryInfo.eaSize = 0;
5439 case SMB_FIND_FILE_DIRECTORY_INFO:
5440 fp->u.FfileDirectoryInfo.nextEntryOffset = orbytes + align;
5441 fp->u.FfileDirectoryInfo.fileIndex = nextEntryCookie;
5442 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5443 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5446 case SMB_FIND_FILE_NAMES_INFO:
5447 fp->u.FfileNamesInfo.nextEntryOffset = orbytes + align;
5448 fp->u.FfileNamesInfo.fileIndex = nextEntryCookie;
5449 fp->u.FfileNamesInfo.fileNameLength = onbytes;
5454 /* we shouldn't hit this case */
5455 osi_assertx(FALSE, "Unknown query type");
5458 /* now, adjust the # of entries copied */
5461 /* now we emit the attribute. This is tricky, since
5462 * we need to really stat the file to find out what
5463 * type of entry we've got. Right now, we're copying
5464 * out data from a buffer, while holding the scp
5465 * locked, so it isn't really convenient to stat
5466 * something now. We'll put in a place holder
5467 * now, and make a second pass before returning this
5468 * to get the real attributes. So, we just skip the
5469 * data for now, and adjust it later. We allocate a
5470 * patch record to make it easy to find this point
5471 * later. The replay will happen at a time when it is
5472 * safe to unlock the directory.
5474 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5475 osi_assert(attrp != NULL);
5476 curPatchp = malloc(sizeof(*curPatchp));
5477 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5478 curPatchp->dptr = attrp;
5480 if (smb_hideDotFiles && smb_IsDotFile(cfileName)) {
5481 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5483 curPatchp->flags = 0;
5486 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5489 curPatchp->dep = dep;
5492 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5493 /* put out resume key */
5494 *((u_long *)origOp) = nextEntryCookie;
5496 /* Adjust byte ptr and count */
5497 origOp += orbytes; /* skip entire record */
5498 bytesInBuffer += orbytes;
5500 /* and pad the record out */
5501 while (align-- > 0) {
5505 } /* if we're including this name */
5506 else if (!starPattern &&
5508 cm_MatchMask(normName, maskp, CM_FLAG_CASEFOLD)) {
5509 /* We were looking for exact matches, but here's an inexact one*/
5514 /* and adjust curOffset to be where the new cookie is */
5515 thyper.HighPart = 0;
5516 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5517 curOffset = LargeIntegerAdd(thyper, curOffset);
5518 } /* while copying data for dir listing */
5520 /* If we didn't get a star pattern, we did an exact match during the first pass.
5521 * If there were no exact matches found, we fail over to inexact matches by
5522 * marking the query as a star pattern (matches all case permutations), and
5523 * re-running the query.
5525 if (returnedNames == 0 && !starPattern && foundInexact) {
5526 osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
5531 /* release the mutex */
5532 lock_ReleaseWrite(&scp->rw);
5534 buf_Release(bufferp);
5539 * Finally, process whatever entries we have left.
5541 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5542 dsp->relPath, infoLevel, userp, &req);
5544 /* now put out the final parameters */
5545 if (returnedNames == 0)
5547 if (p->opcode == 1) {
5549 outp->parmsp[0] = (unsigned short) dsp->cookie;
5550 outp->parmsp[1] = returnedNames;
5551 outp->parmsp[2] = eos;
5552 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5553 outp->parmsp[4] = 0;
5554 /* don't need last name to continue
5555 * search, cookie is enough. Normally,
5556 * this is the offset of the file name
5557 * of the last entry returned.
5559 outp->totalParms = 10; /* in bytes */
5563 outp->parmsp[0] = returnedNames;
5564 outp->parmsp[1] = eos;
5565 outp->parmsp[2] = 0; /* EAS error */
5566 outp->parmsp[3] = 0; /* last name, as above */
5567 outp->totalParms = 8; /* in bytes */
5570 /* return # of bytes in the buffer */
5571 outp->totalData = bytesInBuffer;
5573 /* Return error code if unsuccessful on first request */
5574 if (code == 0 && p->opcode == 1 && returnedNames == 0)
5575 code = CM_ERROR_NOSUCHFILE;
5577 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
5578 p->opcode, dsp->cookie, returnedNames, code);
5580 /* if we're supposed to close the search after this request, or if
5581 * we're supposed to close the search if we're done, and we're done,
5582 * or if something went wrong, close the search.
5584 if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
5585 (returnedNames == 0) ||
5586 ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
5588 smb_DeleteDirSearch(dsp);
5591 smb_SendTran2Error(vcp, p, opx, code);
5593 smb_SendTran2Packet(vcp, outp, opx);
5595 smb_FreeTran2Packet(outp);
5596 smb_ReleaseDirSearch(dsp);
5597 cm_ReleaseSCache(scp);
5598 cm_ReleaseUser(userp);
5602 /* SMB_COM_FIND_CLOSE2 */
5603 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5606 smb_dirSearch_t *dsp;
5608 dirHandle = smb_GetSMBParm(inp, 0);
5610 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
5612 dsp = smb_FindDirSearch(dirHandle);
5615 return CM_ERROR_BADFD;
5617 /* otherwise, we have an FD to destroy */
5618 smb_DeleteDirSearch(dsp);
5619 smb_ReleaseDirSearch(dsp);
5621 /* and return results */
5622 smb_SetSMBDataLength(outp, 0);
5628 /* SMB_COM_FIND_NOTIFY_CLOSE */
5629 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5631 smb_SetSMBDataLength(outp, 0);
5635 /* SMB_COM_OPEN_ANDX */
5636 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5638 clientchar_t *pathp;
5643 cm_scache_t *dscp; /* dir we're dealing with */
5644 cm_scache_t *scp; /* file we're creating */
5646 int initialModeBits;
5649 clientchar_t *lastNamep;
5650 unsigned long dosTime;
5656 int parmSlot; /* which parm we're dealing with */
5657 clientchar_t *tidPathp;
5665 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
5666 openFun = smb_GetSMBParm(inp, 8); /* open function */
5667 excl = ((openFun & 3) == 0);
5668 trunc = ((openFun & 3) == 2); /* truncate it */
5669 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
5670 openAction = 0; /* tracks what we did */
5672 attributes = smb_GetSMBParm(inp, 5);
5673 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
5675 /* compute initial mode bits based on read-only flag in attributes */
5676 initialModeBits = 0666;
5677 if (attributes & SMB_ATTR_READONLY)
5678 initialModeBits &= ~0222;
5680 pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
5683 return CM_ERROR_BADSMB;
5685 spacep = inp->spacep;
5686 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5689 (cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
5690 cm_ClientStrCmpIA(lastNamep, _C("\\srvsvc")) == 0 ||
5691 cm_ClientStrCmpIA(lastNamep, _C("\\wkssvc")) == 0 ||
5692 cm_ClientStrCmpIA(lastNamep, _C("ipc$")) == 0)) {
5693 /* special case magic file name for receiving IOCTL requests
5694 * (since IOCTL calls themselves aren't getting through).
5697 osi_Log0(smb_logp, "IOCTL Open");
5700 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5701 smb_SetupIoctlFid(fidp, spacep);
5703 /* set inp->fid so that later read calls in same msg can find fid */
5704 inp->fid = fidp->fid;
5706 /* copy out remainder of the parms */
5708 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5710 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
5711 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
5712 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5713 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
5714 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
5715 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5716 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5717 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5719 /* and the final "always present" stuff */
5720 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
5721 /* next write out the "unique" ID */
5722 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
5723 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
5724 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5725 smb_SetSMBDataLength(outp, 0);
5727 /* and clean up fid reference */
5728 smb_ReleaseFID(fidp);
5732 if (!cm_IsValidClientString(pathp)) {
5734 clientchar_t * hexp;
5736 hexp = cm_GetRawCharsAlloc(pathp, -1);
5737 osi_Log1(smb_logp, "NTOpenX rejecting invalid name. [%S]",
5738 osi_LogSaveClientString(smb_logp, hexp));
5742 osi_Log0(smb_logp, "NTOpenX rejecting invalid name");
5744 return CM_ERROR_BADNTFILENAME;
5747 #ifdef DEBUG_VERBOSE
5749 char *hexp, *asciip;
5750 asciip = (lastNamep ? lastNamep : pathp );
5751 hexp = osi_HexifyString(asciip);
5752 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
5756 userp = smb_GetUserFromVCP(vcp, inp);
5759 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5761 cm_ReleaseUser(userp);
5762 return CM_ERROR_NOSUCHPATH;
5764 code = cm_NameI(cm_data.rootSCachep, pathp,
5765 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5766 userp, tidPathp, &req, &scp);
5769 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5770 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5771 cm_ReleaseSCache(scp);
5772 cm_ReleaseUser(userp);
5773 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5774 return CM_ERROR_PATH_NOT_COVERED;
5776 return CM_ERROR_NOSUCHPATH;
5778 #endif /* DFS_SUPPORT */
5781 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
5782 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5783 userp, tidPathp, &req, &dscp);
5785 cm_ReleaseUser(userp);
5790 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5791 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5793 cm_ReleaseSCache(dscp);
5794 cm_ReleaseUser(userp);
5795 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5796 return CM_ERROR_PATH_NOT_COVERED;
5798 return CM_ERROR_NOSUCHPATH;
5800 #endif /* DFS_SUPPORT */
5801 /* otherwise, scp points to the parent directory. Do a lookup,
5802 * and truncate the file if we find it, otherwise we create the
5809 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
5811 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5812 cm_ReleaseSCache(dscp);
5813 cm_ReleaseUser(userp);
5818 /* if we get here, if code is 0, the file exists and is represented by
5819 * scp. Otherwise, we have to create it. The dir may be represented
5820 * by dscp, or we may have found the file directly. If code is non-zero,
5824 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
5826 if (dscp) cm_ReleaseSCache(dscp);
5827 cm_ReleaseSCache(scp);
5828 cm_ReleaseUser(userp);
5833 /* oops, file shouldn't be there */
5835 cm_ReleaseSCache(dscp);
5836 cm_ReleaseSCache(scp);
5837 cm_ReleaseUser(userp);
5838 return CM_ERROR_EXISTS;
5842 setAttr.mask = CM_ATTRMASK_LENGTH;
5843 setAttr.length.LowPart = 0;
5844 setAttr.length.HighPart = 0;
5845 code = cm_SetAttr(scp, &setAttr, userp, &req);
5846 openAction = 3; /* truncated existing file */
5848 else openAction = 1; /* found existing file */
5850 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
5851 /* don't create if not found */
5852 if (dscp) cm_ReleaseSCache(dscp);
5853 cm_ReleaseUser(userp);
5854 return CM_ERROR_NOSUCHFILE;
5857 osi_assertx(dscp != NULL, "null cm_scache_t");
5858 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %S",
5859 osi_LogSaveClientString(smb_logp, lastNamep));
5860 openAction = 2; /* created file */
5861 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5862 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5863 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5867 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5868 smb_NotifyChange(FILE_ACTION_ADDED,
5869 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5870 dscp, lastNamep, NULL, TRUE);
5871 } else if (!excl && code == CM_ERROR_EXISTS) {
5872 /* not an exclusive create, and someone else tried
5873 * creating it already, then we open it anyway. We
5874 * don't bother retrying after this, since if this next
5875 * fails, that means that the file was deleted after we
5876 * started this call.
5878 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5882 setAttr.mask = CM_ATTRMASK_LENGTH;
5883 setAttr.length.LowPart = 0;
5884 setAttr.length.HighPart = 0;
5885 code = cm_SetAttr(scp, &setAttr, userp, &req);
5887 } /* lookup succeeded */
5891 /* we don't need this any longer */
5893 cm_ReleaseSCache(dscp);
5896 /* something went wrong creating or truncating the file */
5898 cm_ReleaseSCache(scp);
5899 cm_ReleaseUser(userp);
5903 /* make sure we're about to open a file */
5904 if (scp->fileType != CM_SCACHETYPE_FILE) {
5905 cm_ReleaseSCache(scp);
5906 cm_ReleaseUser(userp);
5907 return CM_ERROR_ISDIR;
5910 /* now all we have to do is open the file itself */
5911 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5912 osi_assertx(fidp, "null smb_fid_t");
5915 lock_ObtainMutex(&fidp->mx);
5916 /* save a pointer to the vnode */
5918 lock_ObtainWrite(&scp->rw);
5919 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5920 lock_ReleaseWrite(&scp->rw);
5921 osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
5923 fidp->userp = userp;
5925 /* compute open mode */
5927 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5928 if (openMode == 1 || openMode == 2)
5929 fidp->flags |= SMB_FID_OPENWRITE;
5931 /* remember if the file was newly created */
5933 fidp->flags |= SMB_FID_CREATED;
5935 lock_ReleaseMutex(&fidp->mx);
5936 smb_ReleaseFID(fidp);
5938 cm_Open(scp, 0, userp);
5940 /* set inp->fid so that later read calls in same msg can find fid */
5941 inp->fid = fidp->fid;
5943 /* copy out remainder of the parms */
5945 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5946 lock_ObtainRead(&scp->rw);
5948 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5949 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5950 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5951 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5952 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5953 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5954 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5955 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5956 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5958 /* and the final "always present" stuff */
5959 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5960 /* next write out the "unique" ID */
5961 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5962 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5963 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5964 lock_ReleaseRead(&scp->rw);
5965 smb_SetSMBDataLength(outp, 0);
5967 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5969 cm_ReleaseUser(userp);
5970 /* leave scp held since we put it in fidp->scp */
5974 static void smb_GetLockParams(unsigned char LockType,
5976 unsigned int * ppid,
5977 LARGE_INTEGER * pOffset,
5978 LARGE_INTEGER * pLength)
5980 if (LockType & LOCKING_ANDX_LARGE_FILES) {
5982 *ppid = *((USHORT *) *buf);
5983 pOffset->HighPart = *((LONG *)(*buf + 4));
5984 pOffset->LowPart = *((DWORD *)(*buf + 8));
5985 pLength->HighPart = *((LONG *)(*buf + 12));
5986 pLength->LowPart = *((DWORD *)(*buf + 16));
5990 /* Not Large Files */
5991 *ppid = *((USHORT *) *buf);
5992 pOffset->HighPart = 0;
5993 pOffset->LowPart = *((DWORD *)(*buf + 2));
5994 pLength->HighPart = 0;
5995 pLength->LowPart = *((DWORD *)(*buf + 6));
6000 /* SMB_COM_LOCKING_ANDX */
6001 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6008 unsigned char LockType;
6009 unsigned short NumberOfUnlocks, NumberOfLocks;
6013 LARGE_INTEGER LOffset, LLength;
6014 smb_waitingLockRequest_t *wlRequest = NULL;
6015 cm_file_lock_t *lockp;
6023 fid = smb_GetSMBParm(inp, 2);
6024 fid = smb_ChainFID(fid, inp);
6026 fidp = smb_FindFID(vcp, fid, 0);
6028 return CM_ERROR_BADFD;
6030 lock_ObtainMutex(&fidp->mx);
6031 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6032 lock_ReleaseMutex(&fidp->mx);
6033 smb_CloseFID(vcp, fidp, NULL, 0);
6034 smb_ReleaseFID(fidp);
6035 return CM_ERROR_NOSUCHFILE;
6038 if (fidp->flags & SMB_FID_IOCTL) {
6039 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
6040 lock_ReleaseMutex(&fidp->mx);
6041 smb_ReleaseFID(fidp);
6042 return CM_ERROR_BADFD;
6045 osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
6047 lock_ReleaseMutex(&fidp->mx);
6049 /* set inp->fid so that later read calls in same msg can find fid */
6052 userp = smb_GetUserFromVCP(vcp, inp);
6054 lock_ObtainWrite(&scp->rw);
6055 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6056 CM_SCACHESYNC_NEEDCALLBACK
6057 | CM_SCACHESYNC_GETSTATUS
6058 | CM_SCACHESYNC_LOCK);
6060 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
6064 LockType = smb_GetSMBParm(inp, 3) & 0xff;
6065 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
6066 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
6067 NumberOfLocks = smb_GetSMBParm(inp, 7);
6069 if (!(fidp->flags & SMB_FID_OPENWRITE) &&
6070 !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
6071 /* somebody wants exclusive locks on a file that they only
6072 opened for reading. We downgrade this to a shared lock. */
6073 osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
6074 LockType |= LOCKING_ANDX_SHARED_LOCK;
6077 if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
6078 /* AFS does not support atomic changes of lock types from read or write and vice-versa */
6079 osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]");
6080 code = CM_ERROR_BADOP;
6085 op = smb_GetSMBData(inp, NULL);
6087 if (LockType & LOCKING_ANDX_CANCEL_LOCK) {
6088 /* Cancel outstanding lock requests */
6089 smb_waitingLock_t * wl;
6091 for (i=0; i<NumberOfLocks; i++) {
6092 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6094 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6096 lock_ObtainWrite(&smb_globalLock);
6097 for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
6099 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
6100 if (cm_KeyEquals(&wl->key, &key, 0) && LargeIntegerEqualTo(wl->LOffset, LOffset) &&
6101 LargeIntegerEqualTo(wl->LLength, LLength)) {
6102 wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
6103 goto found_lock_request;
6108 lock_ReleaseWrite(&smb_globalLock);
6111 smb_SetSMBDataLength(outp, 0);
6116 for (i=0; i<NumberOfUnlocks; i++) {
6117 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6119 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6121 code = cm_Unlock(scp, LockType, LOffset, LLength, key, 0, userp, &req);
6129 for (i=0; i<NumberOfLocks; i++) {
6130 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6132 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6134 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
6135 userp, &req, &lockp);
6137 if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
6138 (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
6140 code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
6141 userp, &req, &lockp);
6144 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
6145 smb_waitingLock_t * wLock;
6147 /* Put on waiting list */
6148 if(wlRequest == NULL) {
6152 LARGE_INTEGER tOffset, tLength;
6154 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
6156 osi_assertx(wlRequest != NULL, "null wlRequest");
6158 wlRequest->vcp = vcp;
6160 wlRequest->scp = scp;
6161 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
6163 wlRequest->inp = smb_CopyPacket(inp);
6164 wlRequest->outp = smb_CopyPacket(outp);
6165 wlRequest->lockType = LockType;
6166 wlRequest->msTimeout = Timeout;
6167 wlRequest->start_t = osi_Time();
6168 wlRequest->locks = NULL;
6170 /* The waiting lock request needs to have enough
6171 information to undo all the locks in the request.
6172 We do the following to store info about locks that
6173 have already been granted. Sure, we can get most
6174 of the info from the packet, but the packet doesn't
6175 hold the result of cm_Lock call. In practice we
6176 only receive packets with one or two locks, so we
6177 are only wasting a few bytes here and there and
6178 only for a limited period of time until the waiting
6179 lock times out or is freed. */
6181 for(opt = op_locks, j=i; j > 0; j--) {
6182 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
6184 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6186 wLock = malloc(sizeof(smb_waitingLock_t));
6188 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6191 wLock->LOffset = tOffset;
6192 wLock->LLength = tLength;
6193 wLock->lockp = NULL;
6194 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
6195 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6200 wLock = malloc(sizeof(smb_waitingLock_t));
6202 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6205 wLock->LOffset = LOffset;
6206 wLock->LLength = LLength;
6207 wLock->lockp = lockp;
6208 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
6209 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6212 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
6220 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
6227 /* Since something went wrong with the lock number i, we now
6228 have to go ahead and release any locks acquired before the
6229 failure. All locks before lock number i (of which there
6230 are i of them) have either been successful or are waiting.
6231 Either case requires calling cm_Unlock(). */
6233 /* And purge the waiting lock */
6234 if(wlRequest != NULL) {
6235 smb_waitingLock_t * wl;
6236 smb_waitingLock_t * wlNext;
6239 for(wl = wlRequest->locks; wl; wl = wlNext) {
6241 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
6243 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, 0, userp, &req);
6246 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
6248 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
6251 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
6256 smb_ReleaseVC(wlRequest->vcp);
6257 cm_ReleaseSCache(wlRequest->scp);
6258 smb_FreePacket(wlRequest->inp);
6259 smb_FreePacket(wlRequest->outp);
6268 if (wlRequest != NULL) {
6270 lock_ObtainWrite(&smb_globalLock);
6271 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
6273 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
6274 lock_ReleaseWrite(&smb_globalLock);
6276 /* don't send reply immediately */
6277 outp->flags |= SMB_PACKETFLAG_NOSEND;
6280 smb_SetSMBDataLength(outp, 0);
6284 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
6287 lock_ReleaseWrite(&scp->rw);
6288 cm_ReleaseSCache(scp);
6289 cm_ReleaseUser(userp);
6290 smb_ReleaseFID(fidp);
6295 /* SMB_COM_QUERY_INFORMATION2 */
6296 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6302 afs_uint32 searchTime;
6309 fid = smb_GetSMBParm(inp, 0);
6310 fid = smb_ChainFID(fid, inp);
6312 fidp = smb_FindFID(vcp, fid, 0);
6314 return CM_ERROR_BADFD;
6316 lock_ObtainMutex(&fidp->mx);
6317 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6318 lock_ReleaseMutex(&fidp->mx);
6319 smb_CloseFID(vcp, fidp, NULL, 0);
6320 smb_ReleaseFID(fidp);
6321 return CM_ERROR_NOSUCHFILE;
6324 if (fidp->flags & SMB_FID_IOCTL) {
6325 lock_ReleaseMutex(&fidp->mx);
6326 smb_ReleaseFID(fidp);
6327 return CM_ERROR_BADFD;
6330 osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6332 lock_ReleaseMutex(&fidp->mx);
6334 userp = smb_GetUserFromVCP(vcp, inp);
6337 /* otherwise, stat the file */
6338 lock_ObtainWrite(&scp->rw);
6339 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6340 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6344 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6346 lock_ConvertWToR(&scp->rw);
6349 /* decode times. We need a search time, but the response to this
6350 * call provides the date first, not the time, as returned in the
6351 * searchTime variable. So we take the high-order bits first.
6353 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
6354 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
6355 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
6356 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
6357 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
6358 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
6359 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
6361 /* now handle file size and allocation size */
6362 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
6363 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
6364 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
6365 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
6367 /* file attribute */
6368 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
6370 /* and finalize stuff */
6371 smb_SetSMBDataLength(outp, 0);
6376 lock_ReleaseRead(&scp->rw);
6378 lock_ReleaseWrite(&scp->rw);
6379 cm_ReleaseSCache(scp);
6380 cm_ReleaseUser(userp);
6381 smb_ReleaseFID(fidp);
6385 /* SMB_COM_SET_INFORMATION2 */
6386 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6392 afs_uint32 searchTime;
6400 fid = smb_GetSMBParm(inp, 0);
6401 fid = smb_ChainFID(fid, inp);
6403 fidp = smb_FindFID(vcp, fid, 0);
6405 return CM_ERROR_BADFD;
6407 lock_ObtainMutex(&fidp->mx);
6408 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6409 lock_ReleaseMutex(&fidp->mx);
6410 smb_CloseFID(vcp, fidp, NULL, 0);
6411 smb_ReleaseFID(fidp);
6412 return CM_ERROR_NOSUCHFILE;
6415 if (fidp->flags & SMB_FID_IOCTL) {
6416 lock_ReleaseMutex(&fidp->mx);
6417 smb_ReleaseFID(fidp);
6418 return CM_ERROR_BADFD;
6421 osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6423 lock_ReleaseMutex(&fidp->mx);
6425 userp = smb_GetUserFromVCP(vcp, inp);
6427 /* now prepare to call cm_setattr. This message only sets various times,
6428 * and AFS only implements mtime, and we'll set the mtime if that's
6429 * requested. The others we'll ignore.
6431 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
6433 if (searchTime != 0) {
6434 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
6436 if ( unixTime != -1 ) {
6437 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
6438 attrs.clientModTime = unixTime;
6439 code = cm_SetAttr(scp, &attrs, userp, &req);
6441 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
6443 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
6449 cm_ReleaseSCache(scp);
6450 cm_ReleaseUser(userp);
6451 smb_ReleaseFID(fidp);
6455 /* SMB_COM_WRITE_ANDX */
6456 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6459 long count, written = 0, total_written = 0;
6463 smb_t *smbp = (smb_t*) inp;
6468 int inDataBlockCount;
6470 fd = smb_GetSMBParm(inp, 2);
6471 count = smb_GetSMBParm(inp, 10);
6473 offset.HighPart = 0;
6474 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6476 if (*inp->wctp == 14) {
6477 /* we have a request with 64-bit file offsets */
6478 #ifdef AFS_LARGEFILES
6479 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6481 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6483 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
6484 /* we shouldn't have received this op if we didn't specify
6485 largefile support */
6486 return CM_ERROR_BADOP;
6491 op = inp->data + smb_GetSMBParm(inp, 11);
6492 inDataBlockCount = count;
6494 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
6495 fd, offset.HighPart, offset.LowPart, count);
6497 fd = smb_ChainFID(fd, inp);
6498 fidp = smb_FindFID(vcp, fd, 0);
6500 return CM_ERROR_BADFD;
6502 lock_ObtainMutex(&fidp->mx);
6503 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6504 lock_ReleaseMutex(&fidp->mx);
6505 smb_CloseFID(vcp, fidp, NULL, 0);
6506 smb_ReleaseFID(fidp);
6507 return CM_ERROR_NOSUCHFILE;
6510 if (fidp->flags & SMB_FID_IOCTL) {
6511 lock_ReleaseMutex(&fidp->mx);
6512 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
6513 smb_ReleaseFID(fidp);
6518 lock_ReleaseMutex(&fidp->mx);
6519 smb_ReleaseFID(fidp);
6520 return CM_ERROR_BADFDOP;
6525 lock_ReleaseMutex(&fidp->mx);
6527 userp = smb_GetUserFromVCP(vcp, inp);
6529 /* special case: 0 bytes transferred means there is no data
6530 transferred. A slight departure from SMB_COM_WRITE where this
6531 means that we are supposed to truncate the file at this
6536 LARGE_INTEGER LOffset;
6537 LARGE_INTEGER LLength;
6540 key = cm_GenerateKey(vcp->vcID, pid, fd);
6542 LOffset.HighPart = offset.HighPart;
6543 LOffset.LowPart = offset.LowPart;
6544 LLength.HighPart = 0;
6545 LLength.LowPart = count;
6547 lock_ObtainWrite(&scp->rw);
6548 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
6549 lock_ReleaseWrite(&scp->rw);
6556 * Work around bug in NT client
6558 * When copying a file, the NT client should first copy the data,
6559 * then copy the last write time. But sometimes the NT client does
6560 * these in the wrong order, so the data copies would inadvertently
6561 * cause the last write time to be overwritten. We try to detect this,
6562 * and don't set client mod time if we think that would go against the
6565 lock_ObtainMutex(&fidp->mx);
6566 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6567 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6568 scp->clientModTime = time(NULL);
6570 lock_ReleaseMutex(&fidp->mx);
6573 while ( code == 0 && count > 0 ) {
6574 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6575 if (code == 0 && written == 0)
6576 code = CM_ERROR_PARTIALWRITE;
6578 offset = LargeIntegerAdd(offset,
6579 ConvertLongToLargeInteger(written));
6581 total_written += written;
6585 /* slots 0 and 1 are reserved for request chaining and will be
6586 filled in when we return. */
6587 smb_SetSMBParm(outp, 2, total_written);
6588 smb_SetSMBParm(outp, 3, 0); /* reserved */
6589 smb_SetSMBParm(outp, 4, 0); /* reserved */
6590 smb_SetSMBParm(outp, 5, 0); /* reserved */
6591 smb_SetSMBDataLength(outp, 0);
6595 cm_ReleaseSCache(scp);
6596 cm_ReleaseUser(userp);
6597 smb_ReleaseFID(fidp);
6602 /* SMB_COM_READ_ANDX */
6603 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6607 long finalCount = 0;
6611 smb_t *smbp = (smb_t*) inp;
6618 fd = smb_GetSMBParm(inp, 2);
6619 count = smb_GetSMBParm(inp, 5);
6620 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6622 if (*inp->wctp == 12) {
6623 /* a request with 64-bit offsets */
6624 #ifdef AFS_LARGEFILES
6625 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
6627 if (LargeIntegerLessThanZero(offset)) {
6628 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
6629 offset.HighPart, offset.LowPart);
6630 return CM_ERROR_BADSMB;
6633 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
6634 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
6635 return CM_ERROR_BADSMB;
6637 offset.HighPart = 0;
6641 offset.HighPart = 0;
6644 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
6645 fd, offset.HighPart, offset.LowPart, count);
6647 fd = smb_ChainFID(fd, inp);
6648 fidp = smb_FindFID(vcp, fd, 0);
6650 return CM_ERROR_BADFD;
6653 lock_ObtainMutex(&fidp->mx);
6654 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6655 lock_ReleaseMutex(&fidp->mx);
6656 smb_CloseFID(vcp, fidp, NULL, 0);
6657 smb_ReleaseFID(fidp);
6658 return CM_ERROR_NOSUCHFILE;
6662 lock_ReleaseMutex(&fidp->mx);
6663 smb_ReleaseFID(fidp);
6664 return CM_ERROR_BADFDOP;
6669 lock_ReleaseMutex(&fidp->mx);
6672 key = cm_GenerateKey(vcp->vcID, pid, fd);
6674 LARGE_INTEGER LOffset, LLength;
6676 LOffset.HighPart = offset.HighPart;
6677 LOffset.LowPart = offset.LowPart;
6678 LLength.HighPart = 0;
6679 LLength.LowPart = count;
6681 lock_ObtainWrite(&scp->rw);
6682 code = cm_LockCheckRead(scp, LOffset, LLength, key);
6683 lock_ReleaseWrite(&scp->rw);
6685 cm_ReleaseSCache(scp);
6688 smb_ReleaseFID(fidp);
6692 /* set inp->fid so that later read calls in same msg can find fid */
6695 lock_ObtainMutex(&fidp->mx);
6696 if (fidp->flags & SMB_FID_IOCTL) {
6697 lock_ReleaseMutex(&fidp->mx);
6698 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
6699 smb_ReleaseFID(fidp);
6702 lock_ReleaseMutex(&fidp->mx);
6704 userp = smb_GetUserFromVCP(vcp, inp);
6706 /* 0 and 1 are reserved for request chaining, were setup by our caller,
6707 * and will be further filled in after we return.
6709 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
6710 smb_SetSMBParm(outp, 3, 0); /* resvd */
6711 smb_SetSMBParm(outp, 4, 0); /* resvd */
6712 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
6713 /* fill in #6 when we have all the parameters' space reserved */
6714 smb_SetSMBParm(outp, 7, 0); /* resv'd */
6715 smb_SetSMBParm(outp, 8, 0); /* resv'd */
6716 smb_SetSMBParm(outp, 9, 0); /* resv'd */
6717 smb_SetSMBParm(outp, 10, 0); /* resv'd */
6718 smb_SetSMBParm(outp, 11, 0); /* reserved */
6720 /* get op ptr after putting in the parms, since otherwise we don't
6721 * know where the data really is.
6723 op = smb_GetSMBData(outp, NULL);
6725 /* now fill in offset from start of SMB header to first data byte (to op) */
6726 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
6728 /* set the packet data length the count of the # of bytes */
6729 smb_SetSMBDataLength(outp, count);
6731 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6733 /* fix some things up */
6734 smb_SetSMBParm(outp, 5, finalCount);
6735 smb_SetSMBDataLength(outp, finalCount);
6737 cm_ReleaseUser(userp);
6738 smb_ReleaseFID(fidp);
6743 * Values for createDisp, copied from NTDDK.H
6745 #define FILE_SUPERSEDE 0 // (???)
6746 #define FILE_OPEN 1 // (open)
6747 #define FILE_CREATE 2 // (exclusive)
6748 #define FILE_OPEN_IF 3 // (non-exclusive)
6749 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
6750 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
6753 #define REQUEST_OPLOCK 2
6754 #define REQUEST_BATCH_OPLOCK 4
6755 #define OPEN_DIRECTORY 8
6756 #define EXTENDED_RESPONSE_REQUIRED 0x10
6758 /* CreateOptions field. */
6759 #define FILE_DIRECTORY_FILE 0x0001
6760 #define FILE_WRITE_THROUGH 0x0002
6761 #define FILE_SEQUENTIAL_ONLY 0x0004
6762 #define FILE_NON_DIRECTORY_FILE 0x0040
6763 #define FILE_NO_EA_KNOWLEDGE 0x0200
6764 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
6765 #define FILE_RANDOM_ACCESS 0x0800
6766 #define FILE_DELETE_ON_CLOSE 0x1000
6767 #define FILE_OPEN_BY_FILE_ID 0x2000
6768 #define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000
6769 #define FILE_NO_COMPRESSION 0x00008000
6770 #define FILE_RESERVE_OPFILTER 0x00100000
6771 #define FILE_OPEN_REPARSE_POINT 0x00200000
6772 #define FILE_OPEN_NO_RECALL 0x00400000
6773 #define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000
6775 /* SMB_COM_NT_CREATE_ANDX */
6776 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6778 clientchar_t *pathp, *realPathp;
6782 cm_scache_t *dscp; /* parent dir */
6783 cm_scache_t *scp; /* file to create or open */
6784 cm_scache_t *targetScp; /* if scp is a symlink */
6786 clientchar_t *lastNamep;
6787 clientchar_t *treeStartp;
6788 unsigned short nameLength;
6790 unsigned int requestOpLock;
6791 unsigned int requestBatchOpLock;
6792 unsigned int mustBeDir;
6793 unsigned int extendedRespRequired;
6794 unsigned int treeCreate;
6796 unsigned int desiredAccess;
6797 unsigned int extAttributes;
6798 unsigned int createDisp;
6799 unsigned int createOptions;
6800 unsigned int shareAccess;
6801 int initialModeBits;
6802 unsigned short baseFid;
6803 smb_fid_t *baseFidp;
6805 cm_scache_t *baseDirp;
6806 unsigned short openAction;
6811 clientchar_t *tidPathp;
6816 int checkDoneRequired = 0;
6817 cm_lock_data_t *ldp = NULL;
6821 /* This code is very long and has a lot of if-then-else clauses
6822 * scp and dscp get reused frequently and we need to ensure that
6823 * we don't lose a reference. Start by ensuring that they are NULL.
6830 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
6831 flags = smb_GetSMBOffsetParm(inp, 3, 1)
6832 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
6833 requestOpLock = flags & REQUEST_OPLOCK;
6834 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6835 mustBeDir = flags & OPEN_DIRECTORY;
6836 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6839 * Why all of a sudden 32-bit FID?
6840 * We will reject all bits higher than 16.
6842 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
6843 return CM_ERROR_INVAL;
6844 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
6845 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
6846 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6847 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
6848 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
6849 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
6850 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
6851 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
6852 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
6853 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
6854 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
6856 /* mustBeDir is never set; createOptions directory bit seems to be
6859 if (createOptions & FILE_DIRECTORY_FILE)
6861 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6867 * compute initial mode bits based on read-only flag in
6868 * extended attributes
6870 initialModeBits = 0666;
6871 if (extAttributes & SMB_ATTR_READONLY)
6872 initialModeBits &= ~0222;
6874 pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
6875 NULL, SMB_STRF_ANSIPATH);
6877 /* Sometimes path is not null-terminated, so we make a copy. */
6878 realPathp = malloc(nameLength+sizeof(clientchar_t));
6879 memcpy(realPathp, pathp, nameLength+sizeof(clientchar_t));
6880 realPathp[nameLength/sizeof(clientchar_t)] = 0;
6882 spacep = inp->spacep;
6883 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
6885 osi_Log1(smb_logp,"NTCreateX for [%S]",osi_LogSaveClientString(smb_logp,realPathp));
6886 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
6887 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%S]", shareAccess, flags, osi_LogSaveClientString(smb_logp,(lastNamep?lastNamep:_C("null"))));
6890 (cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
6891 cm_ClientStrCmpIA(lastNamep, _C("\\srvsvc")) == 0 ||
6892 cm_ClientStrCmpIA(lastNamep, _C("\\wkssvc")) == 0 ||
6893 cm_ClientStrCmpIA(lastNamep, _C("ipc$")) == 0)) {
6894 /* special case magic file name for receiving IOCTL requests
6895 * (since IOCTL calls themselves aren't getting through).
6897 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6898 smb_SetupIoctlFid(fidp, spacep);
6899 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
6901 /* set inp->fid so that later read calls in same msg can find fid */
6902 inp->fid = fidp->fid;
6906 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6907 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6908 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
6910 memset(&ft, 0, sizeof(ft));
6911 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6912 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6913 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6914 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6915 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
6916 sz.HighPart = 0x7fff; sz.LowPart = 0;
6917 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
6918 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
6919 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6920 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6921 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
6922 smb_SetSMBDataLength(outp, 0);
6924 /* clean up fid reference */
6925 smb_ReleaseFID(fidp);
6930 if (!cm_IsValidClientString(realPathp)) {
6932 clientchar_t * hexp;
6934 hexp = cm_GetRawCharsAlloc(realPathp, -1);
6935 osi_Log1(smb_logp, "NTCreateX rejecting invalid name. [%S]",
6936 osi_LogSaveClientString(smb_logp, hexp));
6940 osi_Log0(smb_logp, "NTCreateX rejecting invalid name");
6943 return CM_ERROR_BADNTFILENAME;
6946 userp = smb_GetUserFromVCP(vcp, inp);
6948 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
6950 return CM_ERROR_INVAL;
6955 baseDirp = cm_data.rootSCachep;
6956 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6957 if (code == CM_ERROR_TIDIPC) {
6958 /* Attempt to use a TID allocated for IPC. The client
6959 * is probably looking for DCE RPC end points which we
6960 * don't support OR it could be looking to make a DFS
6963 osi_Log0(smb_logp, "NTCreateX received IPC TID");
6966 cm_ReleaseUser(userp);
6967 return CM_ERROR_NOSUCHFILE;
6968 #endif /* DFS_SUPPORT */
6971 baseFidp = smb_FindFID(vcp, baseFid, 0);
6973 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
6975 cm_ReleaseUser(userp);
6976 return CM_ERROR_INVAL;
6979 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6981 cm_ReleaseUser(userp);
6982 smb_CloseFID(vcp, baseFidp, NULL, 0);
6983 smb_ReleaseFID(baseFidp);
6984 return CM_ERROR_NOSUCHPATH;
6987 baseDirp = baseFidp->scp;
6991 osi_Log1(smb_logp, "NTCreateX tidPathp=[%S]", (tidPathp==NULL)?_C("null"): osi_LogSaveClientString(smb_logp,tidPathp));
6993 /* compute open mode */
6995 if (desiredAccess & DELETE)
6996 fidflags |= SMB_FID_OPENDELETE;
6997 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
6998 fidflags |= SMB_FID_OPENREAD_LISTDIR;
6999 if (desiredAccess & AFS_ACCESS_WRITE)
7000 fidflags |= SMB_FID_OPENWRITE;
7001 if (createOptions & FILE_DELETE_ON_CLOSE)
7002 fidflags |= SMB_FID_DELONCLOSE;
7003 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7004 fidflags |= SMB_FID_SEQUENTIAL;
7005 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7006 fidflags |= SMB_FID_RANDOM;
7007 if (createOptions & FILE_OPEN_REPARSE_POINT)
7008 osi_Log0(smb_logp, "NTCreateX Open Reparse Point");
7009 if (smb_IsExecutableFileName(lastNamep))
7010 fidflags |= SMB_FID_EXECUTABLE;
7012 /* and the share mode */
7013 if (shareAccess & FILE_SHARE_READ)
7014 fidflags |= SMB_FID_SHARE_READ;
7015 if (shareAccess & FILE_SHARE_WRITE)
7016 fidflags |= SMB_FID_SHARE_WRITE;
7018 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
7021 /* For an exclusive create, we want to do a case sensitive match for the last component. */
7022 if ( createDisp == FILE_CREATE ||
7023 createDisp == FILE_OVERWRITE ||
7024 createDisp == FILE_OVERWRITE_IF) {
7025 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7026 userp, tidPathp, &req, &dscp);
7029 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7030 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7032 cm_ReleaseSCache(dscp);
7033 cm_ReleaseUser(userp);
7036 smb_ReleaseFID(baseFidp);
7037 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7038 return CM_ERROR_PATH_NOT_COVERED;
7040 return CM_ERROR_NOSUCHPATH;
7042 #endif /* DFS_SUPPORT */
7043 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7045 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7046 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7047 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7048 if (code == 0 && realDirFlag == 1) {
7049 cm_ReleaseSCache(scp);
7050 cm_ReleaseSCache(dscp);
7051 cm_ReleaseUser(userp);
7054 smb_ReleaseFID(baseFidp);
7055 return CM_ERROR_EXISTS;
7059 /* we have both scp and dscp */
7061 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7062 userp, tidPathp, &req, &scp);
7064 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7065 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7066 cm_ReleaseSCache(scp);
7067 cm_ReleaseUser(userp);
7070 smb_ReleaseFID(baseFidp);
7071 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7072 return CM_ERROR_PATH_NOT_COVERED;
7074 return CM_ERROR_NOSUCHPATH;
7076 #endif /* DFS_SUPPORT */
7077 /* we might have scp but not dscp */
7083 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7084 /* look up parent directory */
7085 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
7086 * the immediate parent. We have to work our way up realPathp until we hit something that we
7090 /* we might or might not have scp */
7096 code = cm_NameI(baseDirp, spacep->wdata,
7097 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7098 userp, tidPathp, &req, &dscp);
7101 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7102 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7105 cm_ReleaseSCache(scp);
7106 cm_ReleaseSCache(dscp);
7107 cm_ReleaseUser(userp);
7110 smb_ReleaseFID(baseFidp);
7111 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7112 return CM_ERROR_PATH_NOT_COVERED;
7114 return CM_ERROR_NOSUCHPATH;
7116 #endif /* DFS_SUPPORT */
7119 (tp = cm_ClientStrRChr(spacep->wdata, '\\')) &&
7120 (createDisp == FILE_CREATE) &&
7121 (realDirFlag == 1)) {
7124 treeStartp = realPathp + (tp - spacep->wdata);
7126 if (*tp && !smb_IsLegalFilename(tp)) {
7127 cm_ReleaseUser(userp);
7129 smb_ReleaseFID(baseFidp);
7132 cm_ReleaseSCache(scp);
7133 return CM_ERROR_BADNTFILENAME;
7137 } while (dscp == NULL && code == 0);
7141 /* we might have scp and we might have dscp */
7144 smb_ReleaseFID(baseFidp);
7147 osi_Log0(smb_logp,"NTCreateX parent not found");
7149 cm_ReleaseSCache(scp);
7151 cm_ReleaseSCache(dscp);
7152 cm_ReleaseUser(userp);
7157 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
7158 /* A file exists where we want a directory. */
7160 cm_ReleaseSCache(scp);
7161 cm_ReleaseSCache(dscp);
7162 cm_ReleaseUser(userp);
7164 return CM_ERROR_EXISTS;
7168 lastNamep = realPathp;
7172 if (!smb_IsLegalFilename(lastNamep)) {
7174 cm_ReleaseSCache(scp);
7176 cm_ReleaseSCache(dscp);
7177 cm_ReleaseUser(userp);
7179 return CM_ERROR_BADNTFILENAME;
7182 if (!foundscp && !treeCreate) {
7183 if ( createDisp == FILE_CREATE ||
7184 createDisp == FILE_OVERWRITE ||
7185 createDisp == FILE_OVERWRITE_IF)
7187 code = cm_Lookup(dscp, lastNamep,
7188 CM_FLAG_FOLLOW, userp, &req, &scp);
7190 code = cm_Lookup(dscp, lastNamep,
7191 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7194 if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
7196 cm_ReleaseSCache(dscp);
7197 cm_ReleaseUser(userp);
7202 /* we have scp and dscp */
7204 /* we have scp but not dscp */
7206 smb_ReleaseFID(baseFidp);
7209 /* if we get here, if code is 0, the file exists and is represented by
7210 * scp. Otherwise, we have to create it. The dir may be represented
7211 * by dscp, or we may have found the file directly. If code is non-zero,
7214 if (code == 0 && !treeCreate) {
7215 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7217 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7219 cm_ReleaseSCache(dscp);
7221 cm_ReleaseSCache(scp);
7222 cm_ReleaseUser(userp);
7226 checkDoneRequired = 1;
7228 if (createDisp == FILE_CREATE) {
7229 /* oops, file shouldn't be there */
7230 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7232 cm_ReleaseSCache(dscp);
7234 cm_ReleaseSCache(scp);
7235 cm_ReleaseUser(userp);
7237 return CM_ERROR_EXISTS;
7240 if ( createDisp == FILE_OVERWRITE ||
7241 createDisp == FILE_OVERWRITE_IF) {
7243 setAttr.mask = CM_ATTRMASK_LENGTH;
7244 setAttr.length.LowPart = 0;
7245 setAttr.length.HighPart = 0;
7246 /* now watch for a symlink */
7248 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7250 osi_assertx(dscp != NULL, "null cm_scache_t");
7251 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7253 /* we have a more accurate file to use (the
7254 * target of the symbolic link). Otherwise,
7255 * we'll just use the symlink anyway.
7257 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7259 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7260 cm_ReleaseSCache(scp);
7262 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7264 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7266 cm_ReleaseSCache(dscp);
7268 cm_ReleaseSCache(scp);
7269 cm_ReleaseUser(userp);
7275 code = cm_SetAttr(scp, &setAttr, userp, &req);
7276 openAction = 3; /* truncated existing file */
7279 openAction = 1; /* found existing file */
7281 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7282 /* don't create if not found */
7284 cm_ReleaseSCache(dscp);
7286 cm_ReleaseSCache(scp);
7287 cm_ReleaseUser(userp);
7289 return CM_ERROR_NOSUCHFILE;
7290 } else if (realDirFlag == 0 || realDirFlag == -1) {
7291 osi_assertx(dscp != NULL, "null cm_scache_t");
7292 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %S",
7293 osi_LogSaveClientString(smb_logp, lastNamep));
7294 openAction = 2; /* created file */
7295 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7296 setAttr.clientModTime = time(NULL);
7297 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
7300 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7301 smb_NotifyChange(FILE_ACTION_ADDED,
7302 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7303 dscp, lastNamep, NULL, TRUE);
7304 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7305 /* Not an exclusive create, and someone else tried
7306 * creating it already, then we open it anyway. We
7307 * don't bother retrying after this, since if this next
7308 * fails, that means that the file was deleted after we
7309 * started this call.
7311 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7314 if (createDisp == FILE_OVERWRITE_IF) {
7315 setAttr.mask = CM_ATTRMASK_LENGTH;
7316 setAttr.length.LowPart = 0;
7317 setAttr.length.HighPart = 0;
7319 /* now watch for a symlink */
7321 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7323 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7325 /* we have a more accurate file to use (the
7326 * target of the symbolic link). Otherwise,
7327 * we'll just use the symlink anyway.
7329 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7331 cm_ReleaseSCache(scp);
7335 code = cm_SetAttr(scp, &setAttr, userp, &req);
7337 } /* lookup succeeded */
7340 clientchar_t *tp, *pp;
7341 clientchar_t *cp; /* This component */
7342 int clen = 0; /* length of component */
7343 cm_scache_t *tscp1, *tscp2;
7346 /* create directory */
7348 treeStartp = lastNamep;
7349 osi_assertx(dscp != NULL, "null cm_scache_t");
7350 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%S]",
7351 osi_LogSaveClientString(smb_logp, treeStartp));
7352 openAction = 2; /* created directory */
7354 /* if the request is to create the root directory
7355 * it will appear as a directory name of the nul-string
7356 * and a code of CM_ERROR_NOSUCHFILE
7358 if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
7359 code = CM_ERROR_EXISTS;
7361 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7362 setAttr.clientModTime = time(NULL);
7367 cm_HoldSCache(tscp1);
7371 tp = cm_ClientStrChr(pp, '\\');
7373 cm_ClientStrCpy(cp, lengthof(spacep->wdata) - (cp - spacep->wdata), pp);
7374 clen = (int)cm_ClientStrLen(cp);
7375 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
7377 clen = (int)(tp - pp);
7378 cm_ClientStrCpyN(cp, lengthof(spacep->wdata) - (cp - spacep->wdata),
7386 continue; /* the supplied path can't have consecutive slashes either , but */
7388 /* cp is the next component to be created. */
7389 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req, NULL);
7390 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
7391 smb_NotifyChange(FILE_ACTION_ADDED,
7392 FILE_NOTIFY_CHANGE_DIR_NAME,
7393 tscp1, cp, NULL, TRUE);
7395 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7396 /* Not an exclusive create, and someone else tried
7397 * creating it already, then we open it anyway. We
7398 * don't bother retrying after this, since if this next
7399 * fails, that means that the file was deleted after we
7400 * started this call.
7402 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
7403 userp, &req, &tscp2);
7408 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
7409 cm_ReleaseSCache(tscp1);
7410 tscp1 = tscp2; /* Newly created directory will be next parent */
7411 /* the hold is transfered to tscp1 from tscp2 */
7416 cm_ReleaseSCache(dscp);
7419 cm_ReleaseSCache(scp);
7422 * if we get here and code == 0, then scp is the last directory created, and dscp is the
7428 /* something went wrong creating or truncating the file */
7429 if (checkDoneRequired)
7430 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7432 cm_ReleaseSCache(scp);
7434 cm_ReleaseSCache(dscp);
7435 cm_ReleaseUser(userp);
7440 /* make sure we have file vs. dir right (only applies for single component case) */
7441 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7442 /* now watch for a symlink */
7444 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7445 cm_scache_t * targetScp = 0;
7446 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7448 /* we have a more accurate file to use (the
7449 * target of the symbolic link). Otherwise,
7450 * we'll just use the symlink anyway.
7452 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
7453 if (checkDoneRequired) {
7454 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7455 checkDoneRequired = 0;
7457 cm_ReleaseSCache(scp);
7462 if (scp->fileType != CM_SCACHETYPE_FILE) {
7463 if (checkDoneRequired)
7464 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7466 cm_ReleaseSCache(dscp);
7467 cm_ReleaseSCache(scp);
7468 cm_ReleaseUser(userp);
7470 return CM_ERROR_ISDIR;
7474 /* (only applies to single component case) */
7475 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7476 if (checkDoneRequired)
7477 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7478 cm_ReleaseSCache(scp);
7480 cm_ReleaseSCache(dscp);
7481 cm_ReleaseUser(userp);
7483 return CM_ERROR_NOTDIR;
7486 /* open the file itself */
7487 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7488 osi_assertx(fidp, "null smb_fid_t");
7490 /* save a reference to the user */
7492 fidp->userp = userp;
7494 /* If we are restricting sharing, we should do so with a suitable
7496 if (scp->fileType == CM_SCACHETYPE_FILE &&
7497 !(fidflags & SMB_FID_SHARE_WRITE)) {
7499 LARGE_INTEGER LOffset, LLength;
7502 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7503 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7504 LLength.HighPart = 0;
7505 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7507 /* If we are not opening the file for writing, then we don't
7508 try to get an exclusive lock. No one else should be able to
7509 get an exclusive lock on the file anyway, although someone
7510 else can get a shared lock. */
7511 if ((fidflags & SMB_FID_SHARE_READ) ||
7512 !(fidflags & SMB_FID_OPENWRITE)) {
7513 sLockType = LOCKING_ANDX_SHARED_LOCK;
7518 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7520 lock_ObtainWrite(&scp->rw);
7521 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7522 lock_ReleaseWrite(&scp->rw);
7525 if (checkDoneRequired)
7526 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7527 cm_ReleaseSCache(scp);
7529 cm_ReleaseSCache(dscp);
7530 cm_ReleaseUser(userp);
7531 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7532 smb_CloseFID(vcp, fidp, NULL, 0);
7533 smb_ReleaseFID(fidp);
7539 /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
7540 if (checkDoneRequired) {
7541 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7542 checkDoneRequired = 0;
7545 lock_ObtainMutex(&fidp->mx);
7546 /* save a pointer to the vnode */
7547 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
7548 lock_ObtainWrite(&scp->rw);
7549 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7550 lock_ReleaseWrite(&scp->rw);
7551 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
7553 fidp->flags = fidflags;
7555 /* remember if the file was newly created */
7557 fidp->flags |= SMB_FID_CREATED;
7559 /* save parent dir and pathname for delete or change notification */
7560 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7561 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
7562 fidp->flags |= SMB_FID_NTOPEN;
7563 fidp->NTopen_dscp = dscp;
7565 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
7567 fidp->NTopen_wholepathp = realPathp;
7568 lock_ReleaseMutex(&fidp->mx);
7570 /* we don't need this any longer */
7572 cm_ReleaseSCache(dscp);
7576 cm_Open(scp, 0, userp);
7578 /* set inp->fid so that later read calls in same msg can find fid */
7579 inp->fid = fidp->fid;
7583 lock_ObtainRead(&scp->rw);
7584 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7585 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7586 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7587 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7588 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7589 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7590 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7591 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7592 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7594 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7595 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7596 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
7597 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
7598 smb_SetSMBParmByte(outp, parmSlot,
7599 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7600 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7601 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7602 smb_SetSMBDataLength(outp, 0);
7604 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
7605 LargeIntegerGreaterThanZero(scp->length) &&
7606 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
7609 lock_ReleaseRead(&scp->rw);
7612 cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
7613 scp->length.LowPart, scp->length.HighPart,
7617 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %S", fidp->fid,
7618 osi_LogSaveClientString(smb_logp, realPathp));
7620 cm_ReleaseUser(userp);
7621 smb_ReleaseFID(fidp);
7623 /* Can't free realPathp if we get here since
7624 fidp->NTopen_wholepathp is pointing there */
7626 /* leave scp held since we put it in fidp->scp */
7631 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
7632 * Instead, ultimately, would like to use a subroutine for common code.
7635 /* NT_TRANSACT_CREATE (SMB_COM_NT_TRANSACT) */
7636 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7638 clientchar_t *pathp, *realPathp;
7642 cm_scache_t *dscp; /* parent dir */
7643 cm_scache_t *scp; /* file to create or open */
7644 cm_scache_t *targetScp; /* if scp is a symlink */
7646 clientchar_t *lastNamep;
7647 unsigned long nameLength;
7649 unsigned int requestOpLock;
7650 unsigned int requestBatchOpLock;
7651 unsigned int mustBeDir;
7652 unsigned int extendedRespRequired;
7654 unsigned int desiredAccess;
7655 unsigned int allocSize;
7656 unsigned int shareAccess;
7657 unsigned int extAttributes;
7658 unsigned int createDisp;
7661 unsigned int impLevel;
7662 unsigned int secFlags;
7663 unsigned int createOptions;
7664 int initialModeBits;
7665 unsigned short baseFid;
7666 smb_fid_t *baseFidp;
7668 cm_scache_t *baseDirp;
7669 unsigned short openAction;
7673 clientchar_t *tidPathp;
7675 int parmOffset, dataOffset;
7682 cm_lock_data_t *ldp = NULL;
7683 int checkDoneRequired = 0;
7690 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7691 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7692 parmp = inp->data + parmOffset;
7693 lparmp = (ULONG *) parmp;
7696 requestOpLock = flags & REQUEST_OPLOCK;
7697 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7698 mustBeDir = flags & OPEN_DIRECTORY;
7699 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7702 * Why all of a sudden 32-bit FID?
7703 * We will reject all bits higher than 16.
7705 if (lparmp[1] & 0xFFFF0000)
7706 return CM_ERROR_INVAL;
7707 baseFid = (unsigned short)lparmp[1];
7708 desiredAccess = lparmp[2];
7709 allocSize = lparmp[3];
7710 extAttributes = lparmp[5];
7711 shareAccess = lparmp[6];
7712 createDisp = lparmp[7];
7713 createOptions = lparmp[8];
7716 nameLength = lparmp[11]; /* spec says chars but appears to be bytes */
7717 impLevel = lparmp[12];
7718 secFlags = lparmp[13];
7720 /* mustBeDir is never set; createOptions directory bit seems to be
7723 if (createOptions & FILE_DIRECTORY_FILE)
7725 else if (createOptions & FILE_NON_DIRECTORY_FILE)
7731 * compute initial mode bits based on read-only flag in
7732 * extended attributes
7734 initialModeBits = 0666;
7735 if (extAttributes & SMB_ATTR_READONLY)
7736 initialModeBits &= ~0222;
7738 pathp = smb_ParseStringCb(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
7739 nameLength, NULL, SMB_STRF_ANSIPATH);
7740 /* Sometimes path is not nul-terminated, so we make a copy. */
7741 realPathp = malloc(nameLength+sizeof(clientchar_t));
7742 memcpy(realPathp, pathp, nameLength);
7743 realPathp[nameLength/sizeof(clientchar_t)] = 0;
7744 spacep = cm_GetSpace();
7745 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
7747 osi_Log1(smb_logp,"NTTranCreate %S",osi_LogSaveStringW(smb_logp,realPathp));
7748 osi_Log4(smb_logp,"... da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
7749 osi_Log4(smb_logp,"... co[%x],sdl[%x],eal[%x],as[%x],flags[%x]",createOptions,sdLen,eaLen,allocSize);
7750 osi_Log3(smb_logp,"... imp[%x],sec[%x],flags[%x]", impLevel, secFlags, flags);
7753 * Nothing here to handle SMB_IOCTL_FILENAME.
7754 * Will add it if necessary.
7757 if (!cm_IsValidClientString(realPathp)) {
7759 clientchar_t * hexp;
7761 hexp = cm_GetRawCharsAlloc(realPathp, -1);
7762 osi_Log1(smb_logp, "NTTranCreate rejecting invalid name. [%S]",
7763 osi_LogSaveClientString(smb_logp, hexp));
7767 osi_Log0(smb_logp, "NTTranCreate rejecting invalid name.");
7770 return CM_ERROR_BADNTFILENAME;
7773 userp = smb_GetUserFromVCP(vcp, inp);
7775 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
7777 return CM_ERROR_INVAL;
7782 baseDirp = cm_data.rootSCachep;
7783 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7784 if (code == CM_ERROR_TIDIPC) {
7785 /* Attempt to use a TID allocated for IPC. The client
7786 * is probably looking for DCE RPC end points which we
7787 * don't support OR it could be looking to make a DFS
7790 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
7793 cm_ReleaseUser(userp);
7794 return CM_ERROR_NOSUCHPATH;
7798 baseFidp = smb_FindFID(vcp, baseFid, 0);
7800 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
7802 cm_ReleaseUser(userp);
7803 return CM_ERROR_BADFD;
7806 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7808 cm_ReleaseUser(userp);
7809 smb_CloseFID(vcp, baseFidp, NULL, 0);
7810 smb_ReleaseFID(baseFidp);
7811 return CM_ERROR_NOSUCHPATH;
7814 baseDirp = baseFidp->scp;
7818 /* compute open mode */
7820 if (desiredAccess & DELETE)
7821 fidflags |= SMB_FID_OPENDELETE;
7822 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
7823 fidflags |= SMB_FID_OPENREAD_LISTDIR;
7824 if (desiredAccess & AFS_ACCESS_WRITE)
7825 fidflags |= SMB_FID_OPENWRITE;
7826 if (createOptions & FILE_DELETE_ON_CLOSE)
7827 fidflags |= SMB_FID_DELONCLOSE;
7828 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7829 fidflags |= SMB_FID_SEQUENTIAL;
7830 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7831 fidflags |= SMB_FID_RANDOM;
7832 if (createOptions & FILE_OPEN_REPARSE_POINT)
7833 osi_Log0(smb_logp, "NTTranCreate Open Reparse Point");
7834 if (smb_IsExecutableFileName(lastNamep))
7835 fidflags |= SMB_FID_EXECUTABLE;
7837 /* And the share mode */
7838 if (shareAccess & FILE_SHARE_READ)
7839 fidflags |= SMB_FID_SHARE_READ;
7840 if (shareAccess & FILE_SHARE_WRITE)
7841 fidflags |= SMB_FID_SHARE_WRITE;
7845 if ( createDisp == FILE_OPEN ||
7846 createDisp == FILE_OVERWRITE ||
7847 createDisp == FILE_OVERWRITE_IF) {
7848 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7849 userp, tidPathp, &req, &dscp);
7852 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7853 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7854 cm_ReleaseSCache(dscp);
7855 cm_ReleaseUser(userp);
7858 smb_ReleaseFID(baseFidp);
7859 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7860 return CM_ERROR_PATH_NOT_COVERED;
7862 return CM_ERROR_NOSUCHPATH;
7864 #endif /* DFS_SUPPORT */
7865 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7867 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7868 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7869 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7870 if (code == 0 && realDirFlag == 1) {
7871 cm_ReleaseSCache(scp);
7872 cm_ReleaseSCache(dscp);
7873 cm_ReleaseUser(userp);
7876 smb_ReleaseFID(baseFidp);
7877 return CM_ERROR_EXISTS;
7883 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7884 userp, tidPathp, &req, &scp);
7886 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7887 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7888 cm_ReleaseSCache(scp);
7889 cm_ReleaseUser(userp);
7892 smb_ReleaseFID(baseFidp);
7893 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7894 return CM_ERROR_PATH_NOT_COVERED;
7896 return CM_ERROR_NOSUCHPATH;
7898 #endif /* DFS_SUPPORT */
7904 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7905 /* look up parent directory */
7907 code = cm_NameI(baseDirp, spacep->wdata,
7908 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7909 userp, tidPathp, &req, &dscp);
7911 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7912 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7913 cm_ReleaseSCache(dscp);
7914 cm_ReleaseUser(userp);
7917 smb_ReleaseFID(baseFidp);
7918 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7919 return CM_ERROR_PATH_NOT_COVERED;
7921 return CM_ERROR_NOSUCHPATH;
7923 #endif /* DFS_SUPPORT */
7927 cm_FreeSpace(spacep);
7930 smb_ReleaseFID(baseFidp);
7933 cm_ReleaseUser(userp);
7939 lastNamep = realPathp;
7943 if (!smb_IsLegalFilename(lastNamep))
7944 return CM_ERROR_BADNTFILENAME;
7947 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
7948 code = cm_Lookup(dscp, lastNamep,
7949 CM_FLAG_FOLLOW, userp, &req, &scp);
7951 code = cm_Lookup(dscp, lastNamep,
7952 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7955 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7956 cm_ReleaseSCache(dscp);
7957 cm_ReleaseUser(userp);
7964 smb_ReleaseFID(baseFidp);
7965 cm_FreeSpace(spacep);
7968 /* if we get here, if code is 0, the file exists and is represented by
7969 * scp. Otherwise, we have to create it. The dir may be represented
7970 * by dscp, or we may have found the file directly. If code is non-zero,
7974 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7976 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7978 cm_ReleaseSCache(dscp);
7979 cm_ReleaseSCache(scp);
7980 cm_ReleaseUser(userp);
7984 checkDoneRequired = 1;
7986 if (createDisp == FILE_CREATE) {
7987 /* oops, file shouldn't be there */
7988 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7990 cm_ReleaseSCache(dscp);
7991 cm_ReleaseSCache(scp);
7992 cm_ReleaseUser(userp);
7994 return CM_ERROR_EXISTS;
7997 if (createDisp == FILE_OVERWRITE ||
7998 createDisp == FILE_OVERWRITE_IF) {
7999 setAttr.mask = CM_ATTRMASK_LENGTH;
8000 setAttr.length.LowPart = 0;
8001 setAttr.length.HighPart = 0;
8003 /* now watch for a symlink */
8005 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8007 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8009 /* we have a more accurate file to use (the
8010 * target of the symbolic link). Otherwise,
8011 * we'll just use the symlink anyway.
8013 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8015 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8016 cm_ReleaseSCache(scp);
8018 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
8020 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8022 cm_ReleaseSCache(dscp);
8024 cm_ReleaseSCache(scp);
8025 cm_ReleaseUser(userp);
8031 code = cm_SetAttr(scp, &setAttr, userp, &req);
8032 openAction = 3; /* truncated existing file */
8034 else openAction = 1; /* found existing file */
8036 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
8037 /* don't create if not found */
8039 cm_ReleaseSCache(dscp);
8040 cm_ReleaseUser(userp);
8042 return CM_ERROR_NOSUCHFILE;
8044 else if (realDirFlag == 0 || realDirFlag == -1) {
8045 osi_assertx(dscp != NULL, "null cm_scache_t");
8046 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %S",
8047 osi_LogSaveClientString(smb_logp, lastNamep));
8048 openAction = 2; /* created file */
8049 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8050 setAttr.clientModTime = time(NULL);
8051 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8055 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8056 smb_NotifyChange(FILE_ACTION_ADDED,
8057 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8058 dscp, lastNamep, NULL, TRUE);
8059 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
8060 /* Not an exclusive create, and someone else tried
8061 * creating it already, then we open it anyway. We
8062 * don't bother retrying after this, since if this next
8063 * fails, that means that the file was deleted after we
8064 * started this call.
8066 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8069 if (createDisp == FILE_OVERWRITE_IF) {
8070 setAttr.mask = CM_ATTRMASK_LENGTH;
8071 setAttr.length.LowPart = 0;
8072 setAttr.length.HighPart = 0;
8074 /* now watch for a symlink */
8076 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8078 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8080 /* we have a more accurate file to use (the
8081 * target of the symbolic link). Otherwise,
8082 * we'll just use the symlink anyway.
8084 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8086 cm_ReleaseSCache(scp);
8090 code = cm_SetAttr(scp, &setAttr, userp, &req);
8092 } /* lookup succeeded */
8095 /* create directory */
8096 osi_assertx(dscp != NULL, "null cm_scache_t");
8098 "smb_ReceiveNTTranCreate creating directory %S",
8099 osi_LogSaveClientString(smb_logp, lastNamep));
8100 openAction = 2; /* created directory */
8101 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8102 setAttr.clientModTime = time(NULL);
8103 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8104 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8105 smb_NotifyChange(FILE_ACTION_ADDED,
8106 FILE_NOTIFY_CHANGE_DIR_NAME,
8107 dscp, lastNamep, NULL, TRUE);
8109 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
8110 /* Not an exclusive create, and someone else tried
8111 * creating it already, then we open it anyway. We
8112 * don't bother retrying after this, since if this next
8113 * fails, that means that the file was deleted after we
8114 * started this call.
8116 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8122 /* something went wrong creating or truncating the file */
8123 if (checkDoneRequired)
8124 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8126 cm_ReleaseSCache(scp);
8127 cm_ReleaseUser(userp);
8132 /* make sure we have file vs. dir right */
8133 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
8134 /* now watch for a symlink */
8136 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8138 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8140 /* we have a more accurate file to use (the
8141 * target of the symbolic link). Otherwise,
8142 * we'll just use the symlink anyway.
8144 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8146 if (checkDoneRequired) {
8147 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8148 checkDoneRequired = 0;
8150 cm_ReleaseSCache(scp);
8155 if (scp->fileType != CM_SCACHETYPE_FILE) {
8156 if (checkDoneRequired)
8157 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8158 cm_ReleaseSCache(scp);
8159 cm_ReleaseUser(userp);
8161 return CM_ERROR_ISDIR;
8165 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8166 if (checkDoneRequired)
8167 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8168 cm_ReleaseSCache(scp);
8169 cm_ReleaseUser(userp);
8171 return CM_ERROR_NOTDIR;
8174 /* open the file itself */
8175 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8176 osi_assertx(fidp, "null smb_fid_t");
8178 /* save a reference to the user */
8180 fidp->userp = userp;
8182 /* If we are restricting sharing, we should do so with a suitable
8184 if (scp->fileType == CM_SCACHETYPE_FILE &&
8185 !(fidflags & SMB_FID_SHARE_WRITE)) {
8187 LARGE_INTEGER LOffset, LLength;
8190 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8191 LOffset.LowPart = SMB_FID_QLOCK_LOW;
8192 LLength.HighPart = 0;
8193 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8195 /* Similar to what we do in handling NTCreateX. We get a
8196 shared lock if we are only opening the file for reading. */
8197 if ((fidflags & SMB_FID_SHARE_READ) ||
8198 !(fidflags & SMB_FID_OPENWRITE)) {
8199 sLockType = LOCKING_ANDX_SHARED_LOCK;
8204 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8206 lock_ObtainWrite(&scp->rw);
8207 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8208 lock_ReleaseWrite(&scp->rw);
8211 if (checkDoneRequired)
8212 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8213 cm_ReleaseSCache(scp);
8214 cm_ReleaseUser(userp);
8215 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
8216 smb_CloseFID(vcp, fidp, NULL, 0);
8217 smb_ReleaseFID(fidp);
8219 return CM_ERROR_SHARING_VIOLATION;
8223 /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
8224 if (checkDoneRequired) {
8225 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8226 checkDoneRequired = 0;
8229 lock_ObtainMutex(&fidp->mx);
8230 /* save a pointer to the vnode */
8232 lock_ObtainWrite(&scp->rw);
8233 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8234 lock_ReleaseWrite(&scp->rw);
8235 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
8237 fidp->flags = fidflags;
8239 /* remember if the file was newly created */
8241 fidp->flags |= SMB_FID_CREATED;
8243 /* save parent dir and pathname for deletion or change notification */
8244 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8245 fidp->flags |= SMB_FID_NTOPEN;
8246 fidp->NTopen_dscp = dscp;
8247 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
8249 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
8251 fidp->NTopen_wholepathp = realPathp;
8252 lock_ReleaseMutex(&fidp->mx);
8254 /* we don't need this any longer */
8256 cm_ReleaseSCache(dscp);
8258 cm_Open(scp, 0, userp);
8260 /* set inp->fid so that later read calls in same msg can find fid */
8261 inp->fid = fidp->fid;
8263 /* check whether we are required to send an extended response */
8264 if (!extendedRespRequired) {
8266 parmOffset = 8*4 + 39;
8267 parmOffset += 1; /* pad to 4 */
8268 dataOffset = parmOffset + 70;
8272 /* Total Parameter Count */
8273 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8274 /* Total Data Count */
8275 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8276 /* Parameter Count */
8277 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8278 /* Parameter Offset */
8279 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8280 /* Parameter Displacement */
8281 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8283 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8285 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8286 /* Data Displacement */
8287 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8288 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8289 smb_SetSMBDataLength(outp, 70);
8291 lock_ObtainRead(&scp->rw);
8292 outData = smb_GetSMBData(outp, NULL);
8293 outData++; /* round to get to parmOffset */
8294 *outData = 0; outData++; /* oplock */
8295 *outData = 0; outData++; /* reserved */
8296 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8297 *((ULONG *)outData) = openAction; outData += 4;
8298 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8299 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8300 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8301 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8302 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8303 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8304 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8305 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8306 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8307 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8308 *((USHORT *)outData) = 0; outData += 2; /* dev state */
8309 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8310 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8311 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8312 outData += 2; /* is a dir? */
8315 parmOffset = 8*4 + 39;
8316 parmOffset += 1; /* pad to 4 */
8317 dataOffset = parmOffset + 104;
8321 /* Total Parameter Count */
8322 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8323 /* Total Data Count */
8324 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8325 /* Parameter Count */
8326 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8327 /* Parameter Offset */
8328 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8329 /* Parameter Displacement */
8330 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8332 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8334 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8335 /* Data Displacement */
8336 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8337 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8338 smb_SetSMBDataLength(outp, 105);
8340 lock_ObtainRead(&scp->rw);
8341 outData = smb_GetSMBData(outp, NULL);
8342 outData++; /* round to get to parmOffset */
8343 *outData = 0; outData++; /* oplock */
8344 *outData = 1; outData++; /* response type */
8345 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8346 *((ULONG *)outData) = openAction; outData += 4;
8347 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8348 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8349 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8350 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8351 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8352 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8353 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8354 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8355 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8356 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8357 *((USHORT *)outData) = 0; outData += 2; /* dev state */
8358 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8359 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8360 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8361 outData += 1; /* is a dir? */
8362 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
8363 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
8364 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
8367 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
8368 LargeIntegerGreaterThanZero(scp->length) &&
8369 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
8372 lock_ReleaseRead(&scp->rw);
8375 cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
8376 scp->length.LowPart, scp->length.HighPart,
8379 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
8381 cm_ReleaseUser(userp);
8382 smb_ReleaseFID(fidp);
8384 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
8385 /* leave scp held since we put it in fidp->scp */
8389 /* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
8390 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
8393 smb_packet_t *savedPacketp;
8395 USHORT fid, watchtree;
8399 filter = smb_GetSMBParm(inp, 19) |
8400 (smb_GetSMBParm(inp, 20) << 16);
8401 fid = smb_GetSMBParm(inp, 21);
8402 watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
8404 fidp = smb_FindFID(vcp, fid, 0);
8406 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
8407 return CM_ERROR_BADFD;
8410 lock_ObtainMutex(&fidp->mx);
8411 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8412 lock_ReleaseMutex(&fidp->mx);
8413 smb_CloseFID(vcp, fidp, NULL, 0);
8414 smb_ReleaseFID(fidp);
8415 return CM_ERROR_NOSUCHFILE;
8419 lock_ReleaseMutex(&fidp->mx);
8421 /* Create a copy of the Directory Watch Packet to use when sending the
8422 * notification if in the future a matching change is detected.
8424 savedPacketp = smb_CopyPacket(inp);
8425 if (vcp != savedPacketp->vcp) {
8427 if (savedPacketp->vcp)
8428 smb_ReleaseVC(savedPacketp->vcp);
8429 savedPacketp->vcp = vcp;
8432 /* Add the watch to the list of events to send notifications for */
8433 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8434 savedPacketp->nextp = smb_Directory_Watches;
8435 smb_Directory_Watches = savedPacketp;
8436 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8438 osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%S\"",
8439 fidp, scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp));
8440 osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
8441 filter, fid, watchtree);
8442 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8443 osi_Log0(smb_logp, " Notify Change File Name");
8444 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8445 osi_Log0(smb_logp, " Notify Change Directory Name");
8446 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8447 osi_Log0(smb_logp, " Notify Change Attributes");
8448 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8449 osi_Log0(smb_logp, " Notify Change Size");
8450 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8451 osi_Log0(smb_logp, " Notify Change Last Write");
8452 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8453 osi_Log0(smb_logp, " Notify Change Last Access");
8454 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8455 osi_Log0(smb_logp, " Notify Change Creation");
8456 if (filter & FILE_NOTIFY_CHANGE_EA)
8457 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8458 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8459 osi_Log0(smb_logp, " Notify Change Security");
8460 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8461 osi_Log0(smb_logp, " Notify Change Stream Name");
8462 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8463 osi_Log0(smb_logp, " Notify Change Stream Size");
8464 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8465 osi_Log0(smb_logp, " Notify Change Stream Write");
8467 lock_ObtainWrite(&scp->rw);
8469 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
8471 scp->flags |= CM_SCACHEFLAG_WATCHED;
8472 lock_ReleaseWrite(&scp->rw);
8473 cm_ReleaseSCache(scp);
8474 smb_ReleaseFID(fidp);
8476 outp->flags |= SMB_PACKETFLAG_NOSEND;
8480 unsigned char nullSecurityDesc[36] = {
8481 0x01, /* security descriptor revision */
8482 0x00, /* reserved, should be zero */
8483 0x00, 0x80, /* security descriptor control;
8484 * 0x8000 : self-relative format */
8485 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
8486 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
8487 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
8488 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
8489 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8490 /* "null SID" owner SID */
8491 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
8492 /* "null SID" group SID */
8495 /* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
8496 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8498 int parmOffset, parmCount, dataOffset, dataCount;
8506 ULONG securityInformation;
8508 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8509 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8510 parmp = inp->data + parmOffset;
8511 sparmp = (USHORT *) parmp;
8512 lparmp = (ULONG *) parmp;
8515 securityInformation = lparmp[1];
8517 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
8518 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
8526 parmOffset = 8*4 + 39;
8527 parmOffset += 1; /* pad to 4 */
8529 dataOffset = parmOffset + parmCount;
8533 /* Total Parameter Count */
8534 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8535 /* Total Data Count */
8536 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8537 /* Parameter Count */
8538 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8539 /* Parameter Offset */
8540 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8541 /* Parameter Displacement */
8542 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8544 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8546 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8547 /* Data Displacement */
8548 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8549 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8550 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
8552 outData = smb_GetSMBData(outp, NULL);
8553 outData++; /* round to get to parmOffset */
8554 *((ULONG *)outData) = 36; outData += 4; /* length */
8556 if (maxData >= 36) {
8557 memcpy(outData, nullSecurityDesc, 36);
8561 return CM_ERROR_BUFFERTOOSMALL;
8564 /* SMB_COM_NT_TRANSACT
8566 SMB_COM_NT_TRANSACT_SECONDARY should also be handled here.
8568 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8570 unsigned short function;
8572 function = smb_GetSMBParm(inp, 18);
8574 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
8576 /* We can handle long names */
8577 if (vcp->flags & SMB_VCFLAG_USENT)
8578 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
8581 case 1: /* NT_TRANSACT_CREATE */
8582 return smb_ReceiveNTTranCreate(vcp, inp, outp);
8583 case 2: /* NT_TRANSACT_IOCTL */
8584 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
8586 case 3: /* NT_TRANSACT_SET_SECURITY_DESC */
8587 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
8589 case 4: /* NT_TRANSACT_NOTIFY_CHANGE */
8590 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
8591 case 5: /* NT_TRANSACT_RENAME */
8592 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
8594 case 6: /* NT_TRANSACT_QUERY_SECURITY_DESC */
8595 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
8597 osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
8600 osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
8603 return CM_ERROR_INVAL;
8607 * smb_NotifyChange -- find relevant change notification messages and
8610 * If we don't know the file name (i.e. a callback break), filename is
8611 * NULL, and we return a zero-length list.
8613 * At present there is not a single call to smb_NotifyChange that
8614 * has the isDirectParent parameter set to FALSE.
8616 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
8617 cm_scache_t *dscp, clientchar_t *filename, clientchar_t *otherFilename,
8618 BOOL isDirectParent)
8620 smb_packet_t *watch, *lastWatch, *nextWatch;
8621 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen = 0;
8622 char *outData, *oldOutData;
8626 BOOL twoEntries = FALSE;
8627 ULONG otherNameLen, oldParmCount = 0;
8631 /* Get ready for rename within directory */
8632 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
8634 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
8637 osi_Log4(smb_logp,"in smb_NotifyChange for file [%S] dscp [%p] notification 0x%x parent %d",
8638 osi_LogSaveClientString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
8640 osi_Log0(smb_logp," FILE_ACTION_NONE");
8641 if (action == FILE_ACTION_ADDED)
8642 osi_Log0(smb_logp," FILE_ACTION_ADDED");
8643 if (action == FILE_ACTION_REMOVED)
8644 osi_Log0(smb_logp," FILE_ACTION_REMOVED");
8645 if (action == FILE_ACTION_MODIFIED)
8646 osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
8647 if (action == FILE_ACTION_RENAMED_OLD_NAME)
8648 osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
8649 if (action == FILE_ACTION_RENAMED_NEW_NAME)
8650 osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
8652 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8653 watch = smb_Directory_Watches;
8655 filter = smb_GetSMBParm(watch, 19)
8656 | (smb_GetSMBParm(watch, 20) << 16);
8657 fid = smb_GetSMBParm(watch, 21);
8658 wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
8660 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
8661 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
8664 * Strange hack - bug in NT Client and NT Server that we must emulate?
8666 if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
8667 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
8669 fidp = smb_FindFID(watch->vcp, fid, 0);
8671 osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
8673 watch = watch->nextp;
8677 if (fidp->scp != dscp ||
8678 fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
8679 (filter & notifyFilter) == 0 ||
8680 (!isDirectParent && !wtree))
8682 osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
8684 watch = watch->nextp;
8685 smb_ReleaseFID(fidp);
8690 "Sending Change Notification for fid %d filter 0x%x wtree %d file %S",
8691 fid, filter, wtree, osi_LogSaveClientString(smb_logp, filename));
8692 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8693 osi_Log0(smb_logp, " Notify Change File Name");
8694 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8695 osi_Log0(smb_logp, " Notify Change Directory Name");
8696 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8697 osi_Log0(smb_logp, " Notify Change Attributes");
8698 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8699 osi_Log0(smb_logp, " Notify Change Size");
8700 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8701 osi_Log0(smb_logp, " Notify Change Last Write");
8702 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8703 osi_Log0(smb_logp, " Notify Change Last Access");
8704 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8705 osi_Log0(smb_logp, " Notify Change Creation");
8706 if (filter & FILE_NOTIFY_CHANGE_EA)
8707 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8708 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8709 osi_Log0(smb_logp, " Notify Change Security");
8710 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8711 osi_Log0(smb_logp, " Notify Change Stream Name");
8712 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8713 osi_Log0(smb_logp, " Notify Change Stream Size");
8714 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8715 osi_Log0(smb_logp, " Notify Change Stream Write");
8717 /* A watch can only be notified once. Remove it from the list */
8718 nextWatch = watch->nextp;
8719 if (watch == smb_Directory_Watches)
8720 smb_Directory_Watches = nextWatch;
8722 lastWatch->nextp = nextWatch;
8724 /* Turn off WATCHED flag in dscp */
8725 lock_ObtainWrite(&dscp->rw);
8727 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8729 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
8730 lock_ReleaseWrite(&dscp->rw);
8732 /* Convert to response packet */
8733 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
8734 #ifdef SEND_CANONICAL_PATHNAMES
8735 ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
8737 ((smb_t *) watch)->wct = 0;
8740 if (filename == NULL) {
8743 nameLen = (ULONG)cm_ClientStrLen(filename);
8744 parmCount = 3*4 + nameLen*2;
8745 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8747 otherNameLen = (ULONG)cm_ClientStrLen(otherFilename);
8748 oldParmCount = parmCount;
8749 parmCount += 3*4 + otherNameLen*2;
8750 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8752 if (maxLen < parmCount)
8753 parmCount = 0; /* not enough room */
8755 parmOffset = 8*4 + 39;
8756 parmOffset += 1; /* pad to 4 */
8757 dataOffset = parmOffset + parmCount;
8761 /* Total Parameter Count */
8762 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8763 /* Total Data Count */
8764 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8765 /* Parameter Count */
8766 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8767 /* Parameter Offset */
8768 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
8769 /* Parameter Displacement */
8770 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8772 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8774 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
8775 /* Data Displacement */
8776 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8777 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
8778 smb_SetSMBDataLength(watch, parmCount + 1);
8780 if (parmCount != 0) {
8781 outData = smb_GetSMBData(watch, NULL);
8782 outData++; /* round to get to parmOffset */
8783 oldOutData = outData;
8784 *((DWORD *)outData) = oldParmCount; outData += 4;
8785 /* Next Entry Offset */
8786 *((DWORD *)outData) = action; outData += 4;
8788 *((DWORD *)outData) = nameLen*2; outData += 4;
8789 /* File Name Length */
8791 smb_UnparseString(watch, outData, filename, NULL, 0);
8795 outData = oldOutData + oldParmCount;
8796 *((DWORD *)outData) = 0; outData += 4;
8797 /* Next Entry Offset */
8798 *((DWORD *)outData) = otherAction; outData += 4;
8800 *((DWORD *)outData) = otherNameLen*2;
8801 outData += 4; /* File Name Length */
8802 smb_UnparseString(watch, outData, otherFilename, NULL, 0);
8807 * If filename is null, we don't know the cause of the
8808 * change notification. We return zero data (see above),
8809 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
8810 * (= 0x010C). We set the error code here by hand, without
8811 * modifying wct and bcc.
8813 if (filename == NULL) {
8814 ((smb_t *) watch)->rcls = 0x0C;
8815 ((smb_t *) watch)->reh = 0x01;
8816 ((smb_t *) watch)->errLow = 0;
8817 ((smb_t *) watch)->errHigh = 0;
8818 /* Set NT Status codes flag */
8819 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8822 smb_SendPacket(watch->vcp, watch);
8823 smb_FreePacket(watch);
8825 smb_ReleaseFID(fidp);
8828 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8831 /* SMB_COM_NT_CANCEL */
8832 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8834 unsigned char *replyWctp;
8835 smb_packet_t *watch, *lastWatch;
8836 USHORT fid, watchtree;
8840 osi_Log0(smb_logp, "SMB3 receive NT cancel");
8842 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8843 watch = smb_Directory_Watches;
8845 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
8846 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
8847 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
8848 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
8849 if (watch == smb_Directory_Watches)
8850 smb_Directory_Watches = watch->nextp;
8852 lastWatch->nextp = watch->nextp;
8853 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8855 /* Turn off WATCHED flag in scp */
8856 fid = smb_GetSMBParm(watch, 21);
8857 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
8859 if (vcp != watch->vcp)
8860 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
8863 fidp = smb_FindFID(vcp, fid, 0);
8865 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %S",
8867 (fidp ? osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp) :_C("")));
8870 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
8872 lock_ObtainWrite(&scp->rw);
8874 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8876 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
8877 lock_ReleaseWrite(&scp->rw);
8879 smb_ReleaseFID(fidp);
8881 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
8884 /* assume STATUS32; return 0xC0000120 (CANCELED) */
8885 replyWctp = watch->wctp;
8889 ((smb_t *)watch)->rcls = 0x20;
8890 ((smb_t *)watch)->reh = 0x1;
8891 ((smb_t *)watch)->errLow = 0;
8892 ((smb_t *)watch)->errHigh = 0xC0;
8893 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8894 smb_SendPacket(vcp, watch);
8895 smb_FreePacket(watch);
8899 watch = watch->nextp;
8901 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8907 * NT rename also does hard links.
8910 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
8911 #define RENAME_FLAG_HARD_LINK 0x103
8912 #define RENAME_FLAG_RENAME 0x104
8913 #define RENAME_FLAG_COPY 0x105
8915 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8917 clientchar_t *oldPathp, *newPathp;
8923 attrs = smb_GetSMBParm(inp, 0);
8924 rename_type = smb_GetSMBParm(inp, 1);
8926 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
8927 osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
8928 return CM_ERROR_NOACCESS;
8931 tp = smb_GetSMBData(inp, NULL);
8932 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
8934 return CM_ERROR_BADSMB;
8935 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
8937 return CM_ERROR_BADSMB;
8939 osi_Log3(smb_logp, "NTRename for [%S]->[%S] type [%s]",
8940 osi_LogSaveClientString(smb_logp, oldPathp),
8941 osi_LogSaveClientString(smb_logp, newPathp),
8942 ((rename_type==RENAME_FLAG_RENAME)?"rename":(rename_type==RENAME_FLAG_HARD_LINK)?"hardlink":"other"));
8944 if (rename_type == RENAME_FLAG_RENAME) {
8945 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
8946 } else if (rename_type == RENAME_FLAG_HARD_LINK) { /* RENAME_FLAG_HARD_LINK */
8947 code = smb_Link(vcp,inp,oldPathp,newPathp);
8949 code = CM_ERROR_BADOP;
8955 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock", LOCK_HIERARCHY_SMB_DIRWATCH);
8958 cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
8960 smb_username_t *unp;
8963 unp = smb_FindUserByName(usern, machine, flags);
8965 lock_ObtainMutex(&unp->mx);
8966 unp->userp = cm_NewUser();
8967 lock_ReleaseMutex(&unp->mx);
8968 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
8970 osi_Log2(smb_logp,"smb_FindCMUserByName Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
8974 smb_ReleaseUsername(unp);