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) {
1273 while (t2p->stringsp) {
1277 t2p->stringsp = ns->nextp;
1283 clientchar_t *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
1284 char ** chainpp, int flags)
1289 if (!(p->flags & SMB_TRAN2PFLAG_USEUNICODE))
1290 flags |= SMB_STRF_FORCEASCII;
1293 cb = p->totalParms - (inp - (char *)p->parmsp);
1294 if (inp < (char *) p->parmsp ||
1295 inp >= ((char *) p->parmsp) + p->totalParms) {
1296 #ifdef DEBUG_UNICODE
1302 return smb_ParseStringBuf((unsigned char *) p->parmsp, &p->stringsp,
1303 inp, &cb, chainpp, flags);
1306 /* called with a VC, an input packet to respond to, and an error code.
1307 * sends an error response.
1309 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1310 smb_packet_t *tp, long code)
1313 unsigned short errCode;
1314 unsigned char errClass;
1315 unsigned long NTStatus;
1317 if (vcp->flags & SMB_VCFLAG_STATUS32)
1318 smb_MapNTError(code, &NTStatus);
1320 smb_MapCoreError(code, vcp, &errCode, &errClass);
1322 smb_FormatResponsePacket(vcp, NULL, tp);
1323 smbp = (smb_t *) tp;
1325 /* We can handle long names */
1326 if (vcp->flags & SMB_VCFLAG_USENT)
1327 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1329 /* now copy important fields from the tran 2 packet */
1330 smbp->com = t2p->com;
1331 smbp->tid = t2p->tid;
1332 smbp->mid = t2p->mid;
1333 smbp->pid = t2p->pid;
1334 smbp->uid = t2p->uid;
1335 smbp->res[0] = t2p->res[0];
1336 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1337 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1338 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1339 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1340 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1341 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1344 smbp->rcls = errClass;
1345 smbp->errLow = (unsigned char) (errCode & 0xff);
1346 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1350 smb_SendPacket(vcp, tp);
1353 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1356 unsigned short parmOffset;
1357 unsigned short dataOffset;
1358 unsigned short totalLength;
1359 unsigned short dataAlign;
1362 smb_FormatResponsePacket(vcp, NULL, tp);
1363 smbp = (smb_t *) tp;
1365 /* We can handle long names */
1366 if (vcp->flags & SMB_VCFLAG_USENT)
1367 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1369 /* now copy important fields from the tran 2 packet */
1370 smbp->com = t2p->com;
1371 smbp->tid = t2p->tid;
1372 smbp->mid = t2p->mid;
1373 smbp->pid = t2p->pid;
1374 smbp->uid = t2p->uid;
1375 smbp->res[0] = t2p->res[0];
1377 if (t2p->error_code) {
1378 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1379 unsigned long NTStatus;
1381 smb_MapNTError(t2p->error_code, &NTStatus);
1383 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1384 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1385 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1386 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1387 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1390 unsigned short errCode;
1391 unsigned char errClass;
1393 smb_MapCoreError(t2p->error_code, vcp, &errCode, &errClass);
1395 smbp->rcls = errClass;
1396 smbp->errLow = (unsigned char) (errCode & 0xff);
1397 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1401 totalLength = 1 + t2p->totalData + t2p->totalParms;
1403 /* now add the core parameters (tran2 info) to the packet */
1404 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1405 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1406 smb_SetSMBParm(tp, 2, 0); /* reserved */
1407 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1408 parmOffset = 10*2 + 35; /* parm offset in packet */
1409 parmOffset++; /* round to even */
1410 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1411 * hdr, bcc and wct */
1412 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1413 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1414 dataOffset = parmOffset + t2p->oldTotalParms;
1415 dataAlign = dataOffset & 2; /* quad-align */
1416 dataOffset += dataAlign;
1417 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1418 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1419 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1422 datap = smb_GetSMBData(tp, NULL);
1423 *datap++ = 0; /* we rounded to even */
1425 totalLength += dataAlign;
1426 smb_SetSMBDataLength(tp, totalLength);
1428 /* next, send the datagram */
1429 smb_SendPacket(vcp, tp);
1432 /* TRANS_SET_NMPIPE_STATE */
1433 long smb_nmpipeSetState(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1437 int pipeState = 0x0100; /* default */
1438 smb_tran2Packet_t *outp = NULL;
1441 if (p->totalParms > 0)
1442 pipeState = p->parmsp[0];
1444 osi_Log2(smb_logp, "smb_nmpipeSetState for fd[%d] with state[0x%x]", fd, pipeState);
1446 fidp = smb_FindFID(vcp, fd, 0);
1448 return CM_ERROR_BADFD;
1450 lock_ObtainMutex(&fidp->mx);
1451 if (pipeState & 0x8000)
1452 fidp->flags |= SMB_FID_BLOCKINGPIPE;
1453 if (pipeState & 0x0100)
1454 fidp->flags |= SMB_FID_MESSAGEMODEPIPE;
1455 lock_ReleaseMutex(&fidp->mx);
1457 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 0);
1458 smb_SendTran2Packet(vcp, outp, op);
1459 smb_FreeTran2Packet(outp);
1461 smb_ReleaseFID(fidp);
1466 long smb_nmpipeTransact(smb_vc_t * vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1476 osi_Log3(smb_logp, "smb_nmpipeTransact for fd[%d] %d bytes in, %d max bytes out",
1477 fd, p->totalData, p->maxReturnData);
1479 fidp = smb_FindFID(vcp, fd, 0);
1481 return CM_ERROR_BADFD;
1483 lock_ObtainMutex(&fidp->mx);
1484 if (fidp->flags & SMB_FID_RPC) {
1487 lock_ReleaseMutex(&fidp->mx);
1490 code = smb_RPCNmpipeTransact(fidp, vcp, p, op);
1491 smb_ReleaseFID(fidp);
1493 /* We only deal with RPC pipes */
1494 code = CM_ERROR_BADFD;
1501 /* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
1502 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1504 smb_tran2Packet_t *asp;
1517 /* We sometimes see 0 word count. What to do? */
1518 if (*inp->wctp == 0) {
1519 osi_Log0(smb_logp, "Transaction2 word count = 0");
1520 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1522 smb_SetSMBDataLength(outp, 0);
1523 smb_SendPacket(vcp, outp);
1527 totalParms = smb_GetSMBParm(inp, 0);
1528 totalData = smb_GetSMBParm(inp, 1);
1530 firstPacket = (inp->inCom == 0x25);
1532 /* find the packet we're reassembling */
1533 lock_ObtainWrite(&smb_globalLock);
1534 asp = smb_FindTran2Packet(vcp, inp);
1536 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1538 lock_ReleaseWrite(&smb_globalLock);
1540 /* now merge in this latest packet; start by looking up offsets */
1542 parmDisp = dataDisp = 0;
1543 parmOffset = smb_GetSMBParm(inp, 10);
1544 dataOffset = smb_GetSMBParm(inp, 12);
1545 parmCount = smb_GetSMBParm(inp, 9);
1546 dataCount = smb_GetSMBParm(inp, 11);
1547 asp->setupCount = smb_GetSMBParmByte(inp, 13);
1548 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1549 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1551 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1552 totalData, dataCount, asp->maxReturnData);
1554 if (asp->setupCount == 2) {
1555 clientchar_t * pname;
1557 asp->pipeCommand = smb_GetSMBParm(inp, 14);
1558 asp->pipeParam = smb_GetSMBParm(inp, 15);
1559 pname = smb_ParseString(inp, inp->wctp + 35, NULL, 0);
1561 asp->name = cm_ClientStrDup(pname);
1564 osi_Log2(smb_logp, " Named Pipe command id [%d] with name [%S]",
1565 asp->pipeCommand, osi_LogSaveClientString(smb_logp, asp->name));
1569 parmDisp = smb_GetSMBParm(inp, 4);
1570 parmOffset = smb_GetSMBParm(inp, 3);
1571 dataDisp = smb_GetSMBParm(inp, 7);
1572 dataOffset = smb_GetSMBParm(inp, 6);
1573 parmCount = smb_GetSMBParm(inp, 2);
1574 dataCount = smb_GetSMBParm(inp, 5);
1576 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1577 parmCount, dataCount);
1580 /* now copy the parms and data */
1581 if ( asp->totalParms > 0 && parmCount != 0 )
1583 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1585 if ( asp->totalData > 0 && dataCount != 0 ) {
1586 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1589 /* account for new bytes */
1590 asp->curData += dataCount;
1591 asp->curParms += parmCount;
1593 /* finally, if we're done, remove the packet from the queue and dispatch it */
1594 if (((asp->totalParms > 0 && asp->curParms > 0)
1595 || asp->setupCount == 2) &&
1596 asp->totalData <= asp->curData &&
1597 asp->totalParms <= asp->curParms) {
1599 /* we've received it all */
1600 lock_ObtainWrite(&smb_globalLock);
1601 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1602 lock_ReleaseWrite(&smb_globalLock);
1604 switch(asp->setupCount) {
1607 rapOp = asp->parmsp[0];
1609 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES &&
1610 smb_rapDispatchTable[rapOp].procp) {
1612 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",
1613 myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1615 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1617 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",
1618 code,vcp,vcp->lana,vcp->lsn);
1621 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]",
1622 rapOp, vcp, vcp->lana, vcp->lsn);
1624 code = CM_ERROR_BADOP;
1630 { /* Named pipe operation */
1631 osi_Log2(smb_logp, "Named Pipe: %s with name [%S]",
1632 myCrt_NmpipeDispatch(asp->pipeCommand),
1633 osi_LogSaveClientString(smb_logp, asp->name));
1635 code = CM_ERROR_BADOP;
1637 switch (asp->pipeCommand) {
1638 case SMB_TRANS_SET_NMPIPE_STATE:
1639 code = smb_nmpipeSetState(vcp, asp, outp);
1642 case SMB_TRANS_RAW_READ_NMPIPE:
1645 case SMB_TRANS_QUERY_NMPIPE_STATE:
1648 case SMB_TRANS_QUERY_NMPIPE_INFO:
1651 case SMB_TRANS_PEEK_NMPIPE:
1654 case SMB_TRANS_TRANSACT_NMPIPE:
1655 code = smb_nmpipeTransact(vcp, asp, outp);
1658 case SMB_TRANS_RAW_WRITE_NMPIPE:
1661 case SMB_TRANS_READ_NMPIPE:
1664 case SMB_TRANS_WRITE_NMPIPE:
1667 case SMB_TRANS_WAIT_NMPIPE:
1670 case SMB_TRANS_CALL_NMPIPE:
1677 code = CM_ERROR_BADOP;
1680 /* if an error is returned, we're supposed to send an error packet,
1681 * otherwise the dispatched function already did the data sending.
1682 * We give dispatched proc the responsibility since it knows how much
1683 * space to allocate.
1686 smb_SendTran2Error(vcp, asp, outp, code);
1689 /* free the input tran 2 packet */
1690 smb_FreeTran2Packet(asp);
1692 else if (firstPacket) {
1693 /* the first packet in a multi-packet request, we need to send an
1694 * ack to get more data.
1696 smb_SetSMBDataLength(outp, 0);
1697 smb_SendPacket(vcp, outp);
1703 /* ANSI versions. */
1705 #pragma pack(push, 1)
1707 typedef struct smb_rap_share_info_0 {
1708 BYTE shi0_netname[13];
1709 } smb_rap_share_info_0_t;
1711 typedef struct smb_rap_share_info_1 {
1712 BYTE shi1_netname[13];
1715 DWORD shi1_remark; /* char *shi1_remark; data offset */
1716 } smb_rap_share_info_1_t;
1718 typedef struct smb_rap_share_info_2 {
1719 BYTE shi2_netname[13];
1722 DWORD shi2_remark; /* char *shi2_remark; data offset */
1723 WORD shi2_permissions;
1725 WORD shi2_current_uses;
1726 DWORD shi2_path; /* char *shi2_path; data offset */
1727 WORD shi2_passwd[9];
1729 } smb_rap_share_info_2_t;
1731 #define SMB_RAP_MAX_SHARES 512
1733 typedef struct smb_rap_share_list {
1736 smb_rap_share_info_0_t * shares;
1737 } smb_rap_share_list_t;
1741 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1742 smb_rap_share_list_t * sp;
1744 if (dep->name[0] == '.' && (!dep->name[1] || (dep->name[1] == '.' && !dep->name[2])))
1745 return 0; /* skip over '.' and '..' */
1747 sp = (smb_rap_share_list_t *) vrockp;
1749 strncpy(sp->shares[sp->cShare].shi0_netname, dep->name, 12);
1750 sp->shares[sp->cShare].shi0_netname[12] = 0;
1754 if (sp->cShare >= sp->maxShares)
1755 return CM_ERROR_STOPNOW;
1760 /* RAP NetShareEnumRequest */
1761 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1763 smb_tran2Packet_t *outp;
1764 unsigned short * tp;
1768 int outParmsTotal; /* total parameter bytes */
1769 int outDataTotal; /* total data bytes */
1772 DWORD allSubmount = 0;
1774 DWORD nRegShares = 0;
1775 DWORD nSharesRet = 0;
1777 HKEY hkSubmount = NULL;
1778 smb_rap_share_info_1_t * shares;
1781 clientchar_t thisShare[AFSPATHMAX];
1785 smb_rap_share_list_t rootShares;
1790 tp = p->parmsp + 1; /* skip over function number (always 0) */
1793 clientchar_t * cdescp;
1795 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1796 if (cm_ClientStrCmp(cdescp, _C("WrLeh")))
1797 return CM_ERROR_INVAL;
1798 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1799 if (cm_ClientStrCmp(cdescp, _C("B13BWz")))
1800 return CM_ERROR_INVAL;
1806 if (infoLevel != 1) {
1807 return CM_ERROR_INVAL;
1810 /* We are supposed to use the same ASCII data structure even if
1811 Unicode is negotiated, which ultimately means that the share
1812 names that we return must be at most 13 characters in length,
1813 including the NULL terminator.
1815 The RAP specification states that shares with names longer than
1816 12 characters should not be included in the enumeration.
1817 However, since we support prefix cell references and since many
1818 cell names are going to exceed 12 characters, we lie and send
1819 the first 12 characters.
1822 /* first figure out how many shares there are */
1823 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1824 KEY_QUERY_VALUE, &hkParam);
1825 if (rv == ERROR_SUCCESS) {
1826 len = sizeof(allSubmount);
1827 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1828 (BYTE *) &allSubmount, &len);
1829 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1832 RegCloseKey (hkParam);
1835 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1836 0, KEY_QUERY_VALUE, &hkSubmount);
1837 if (rv == ERROR_SUCCESS) {
1838 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1839 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1840 if (rv != ERROR_SUCCESS)
1846 /* fetch the root shares */
1847 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1848 rootShares.cShare = 0;
1849 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1853 userp = smb_GetTran2User(vcp,p);
1855 thyper.HighPart = 0;
1858 cm_HoldSCache(cm_data.rootSCachep);
1859 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1860 cm_ReleaseSCache(cm_data.rootSCachep);
1862 cm_ReleaseUser(userp);
1864 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1866 #define REMARK_LEN 1
1867 outParmsTotal = 8; /* 4 dwords */
1868 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1869 if(outDataTotal > bufsize) {
1870 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1871 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1874 nSharesRet = nShares;
1877 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1879 /* now for the submounts */
1880 shares = (smb_rap_share_info_1_t *) outp->datap;
1881 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1883 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1886 StringCchCopyA(shares[cshare].shi1_netname,
1887 lengthof(shares[cshare].shi1_netname), "all" );
1888 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1889 /* type and pad are zero already */
1895 for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
1896 len = sizeof(thisShare);
1897 rv = RegEnumValueW(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
1898 if (rv == ERROR_SUCCESS &&
1899 cm_ClientStrLen(thisShare) &&
1900 (!allSubmount || cm_ClientStrCmpI(thisShare,_C("all")))) {
1901 cm_ClientStringToUtf8(thisShare, -1, shares[cshare].shi1_netname,
1902 lengthof( shares[cshare].shi1_netname ));
1903 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1904 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1909 nShares--; /* uncount key */
1912 RegCloseKey(hkSubmount);
1915 nonrootShares = cshare;
1917 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1918 /* in case there are collisions with submounts, submounts have
1920 for (j=0; j < nonrootShares; j++)
1921 if (!cm_stricmp_utf8(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1924 if (j < nonrootShares) {
1925 nShares--; /* uncount */
1929 StringCchCopyA(shares[cshare].shi1_netname, lengthof(shares[cshare].shi1_netname),
1930 rootShares.shares[i].shi0_netname);
1931 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1936 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1937 outp->parmsp[1] = 0;
1938 outp->parmsp[2] = cshare;
1939 outp->parmsp[3] = nShares;
1941 outp->totalData = (int)(cstrp - outp->datap);
1942 outp->totalParms = outParmsTotal;
1944 smb_SendTran2Packet(vcp, outp, op);
1945 smb_FreeTran2Packet(outp);
1947 free(rootShares.shares);
1952 /* RAP NetShareGetInfo */
1953 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1955 smb_tran2Packet_t *outp;
1956 unsigned short * tp;
1957 clientchar_t * shareName;
1958 BOOL shareFound = FALSE;
1959 unsigned short infoLevel;
1960 unsigned short bufsize;
1969 cm_scache_t *scp = NULL;
1975 tp = p->parmsp + 1; /* skip over function number (always 1) */
1978 clientchar_t * cdescp;
1980 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1981 if (cm_ClientStrCmp(cdescp, _C("zWrLh")))
1983 return CM_ERROR_INVAL;
1985 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1986 if (cm_ClientStrCmp(cdescp, _C("B13")) &&
1987 cm_ClientStrCmp(cdescp, _C("B13BWz")) &&
1988 cm_ClientStrCmp(cdescp, _C("B13BWzWWWzB9B")))
1990 return CM_ERROR_INVAL;
1992 shareName = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2000 totalData = sizeof(smb_rap_share_info_0_t);
2001 else if(infoLevel == SMB_INFO_STANDARD)
2002 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
2003 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
2004 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
2006 return CM_ERROR_INVAL;
2008 if(!cm_ClientStrCmpI(shareName, _C("all")) || !cm_ClientStrCmp(shareName,_C("*."))) {
2009 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
2010 KEY_QUERY_VALUE, &hkParam);
2011 if (rv == ERROR_SUCCESS) {
2012 len = sizeof(allSubmount);
2013 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
2014 (BYTE *) &allSubmount, &len);
2015 if (rv != ERROR_SUCCESS || allSubmount != 0) {
2018 RegCloseKey (hkParam);
2025 userp = smb_GetTran2User(vcp, p);
2027 osi_Log1(smb_logp,"ReceiveRAPNetShareGetInfo unable to resolve user [%d]", p->uid);
2028 return CM_ERROR_BADSMB;
2030 code = cm_NameI(cm_data.rootSCachep, shareName,
2031 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
2032 userp, NULL, &req, &scp);
2034 cm_ReleaseSCache(scp);
2037 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
2038 KEY_QUERY_VALUE, &hkSubmount);
2039 if (rv == ERROR_SUCCESS) {
2040 rv = RegQueryValueExW(hkSubmount, shareName, NULL, NULL, NULL, NULL);
2041 if (rv == ERROR_SUCCESS) {
2044 RegCloseKey(hkSubmount);
2050 return CM_ERROR_BADSHARENAME;
2052 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
2053 memset(outp->datap, 0, totalData);
2055 outp->parmsp[0] = 0;
2056 outp->parmsp[1] = 0;
2057 outp->parmsp[2] = totalData;
2059 if (infoLevel == 0) {
2060 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
2061 cm_ClientStringToUtf8(shareName, -1, info->shi0_netname,
2062 lengthof(info->shi0_netname));
2063 } else if(infoLevel == SMB_INFO_STANDARD) {
2064 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
2065 cm_ClientStringToUtf8(shareName, -1, info->shi1_netname, lengthof(info->shi1_netname));
2066 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
2067 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
2068 /* type and pad are already zero */
2069 } else { /* infoLevel==2 */
2070 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
2071 cm_ClientStringToUtf8(shareName, -1, info->shi2_netname, lengthof(info->shi2_netname));
2072 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
2073 info->shi2_permissions = ACCESS_ALL;
2074 info->shi2_max_uses = (unsigned short) -1;
2075 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
2078 outp->totalData = totalData;
2079 outp->totalParms = totalParam;
2081 smb_SendTran2Packet(vcp, outp, op);
2082 smb_FreeTran2Packet(outp);
2087 #pragma pack(push, 1)
2089 typedef struct smb_rap_wksta_info_10 {
2090 DWORD wki10_computername; /*char *wki10_computername;*/
2091 DWORD wki10_username; /* char *wki10_username; */
2092 DWORD wki10_langroup; /* char *wki10_langroup;*/
2093 BYTE wki10_ver_major;
2094 BYTE wki10_ver_minor;
2095 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
2096 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
2097 } smb_rap_wksta_info_10_t;
2101 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2103 smb_tran2Packet_t *outp;
2107 unsigned short * tp;
2110 smb_rap_wksta_info_10_t * info;
2114 tp = p->parmsp + 1; /* Skip over function number */
2117 clientchar_t * cdescp;
2119 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2120 SMB_STRF_FORCEASCII);
2121 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2122 return CM_ERROR_INVAL;
2124 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2125 SMB_STRF_FORCEASCII);
2126 if (cm_ClientStrCmp(cdescp, _C("zzzBBzz")))
2127 return CM_ERROR_INVAL;
2133 if (infoLevel != 10) {
2134 return CM_ERROR_INVAL;
2140 totalData = sizeof(*info) + /* info */
2141 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
2142 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
2143 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
2144 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
2145 1; /* wki10_oth_domains (null)*/
2147 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2149 memset(outp->parmsp,0,totalParams);
2150 memset(outp->datap,0,totalData);
2152 info = (smb_rap_wksta_info_10_t *) outp->datap;
2153 cstrp = (char *) (info + 1);
2155 info->wki10_computername = (DWORD) (cstrp - outp->datap);
2156 StringCbCopyA(cstrp, totalData, smb_localNamep);
2157 cstrp += strlen(cstrp) + 1;
2159 info->wki10_username = (DWORD) (cstrp - outp->datap);
2160 uidp = smb_FindUID(vcp, p->uid, 0);
2162 lock_ObtainMutex(&uidp->mx);
2163 if(uidp->unp && uidp->unp->name)
2164 cm_ClientStringToUtf8(uidp->unp->name, -1,
2165 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2166 lock_ReleaseMutex(&uidp->mx);
2167 smb_ReleaseUID(uidp);
2169 cstrp += strlen(cstrp) + 1;
2171 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
2172 StringCbCopyA(cstrp, totalData - (cstrp - outp->datap)*sizeof(char), "WORKGROUP");
2173 cstrp += strlen(cstrp) + 1;
2175 /* TODO: Not sure what values these should take, but these work */
2176 info->wki10_ver_major = 5;
2177 info->wki10_ver_minor = 1;
2179 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
2180 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
2181 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2182 cstrp += strlen(cstrp) + 1;
2184 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
2185 cstrp ++; /* no other domains */
2187 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
2188 outp->parmsp[2] = outp->totalData;
2189 outp->totalParms = totalParams;
2191 smb_SendTran2Packet(vcp,outp,op);
2192 smb_FreeTran2Packet(outp);
2197 #pragma pack(push, 1)
2199 typedef struct smb_rap_server_info_0 {
2201 } smb_rap_server_info_0_t;
2203 typedef struct smb_rap_server_info_1 {
2205 BYTE sv1_version_major;
2206 BYTE sv1_version_minor;
2208 DWORD sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
2209 } smb_rap_server_info_1_t;
2213 char smb_ServerComment[] = "OpenAFS Client";
2214 int smb_ServerCommentLen = sizeof(smb_ServerComment);
2216 #define SMB_SV_TYPE_SERVER 0x00000002L
2217 #define SMB_SV_TYPE_NT 0x00001000L
2218 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
2220 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2222 smb_tran2Packet_t *outp;
2226 unsigned short * tp;
2229 smb_rap_server_info_0_t * info0;
2230 smb_rap_server_info_1_t * info1;
2233 tp = p->parmsp + 1; /* Skip over function number */
2236 clientchar_t * cdescp;
2238 cdescp = smb_ParseStringT2Parm(p, (unsigned char *) tp, (char **) &tp,
2239 SMB_STRF_FORCEASCII);
2240 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2241 return CM_ERROR_INVAL;
2242 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2243 SMB_STRF_FORCEASCII);
2244 if (cm_ClientStrCmp(cdescp, _C("B16")) ||
2245 cm_ClientStrCmp(cdescp, _C("B16BBDz")))
2246 return CM_ERROR_INVAL;
2252 if (infoLevel != 0 && infoLevel != 1) {
2253 return CM_ERROR_INVAL;
2259 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
2260 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
2262 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2264 memset(outp->parmsp,0,totalParams);
2265 memset(outp->datap,0,totalData);
2267 if (infoLevel == 0) {
2268 info0 = (smb_rap_server_info_0_t *) outp->datap;
2269 cstrp = (char *) (info0 + 1);
2270 StringCchCopyA(info0->sv0_name, lengthof(info0->sv0_name), "AFS");
2271 } else { /* infoLevel == SMB_INFO_STANDARD */
2272 info1 = (smb_rap_server_info_1_t *) outp->datap;
2273 cstrp = (char *) (info1 + 1);
2274 StringCchCopyA(info1->sv1_name, lengthof(info1->sv1_name), "AFS");
2277 SMB_SV_TYPE_SERVER |
2279 SMB_SV_TYPE_SERVER_NT;
2281 info1->sv1_version_major = 5;
2282 info1->sv1_version_minor = 1;
2283 info1->sv1_comment_or_master_browser = (DWORD) (cstrp - outp->datap);
2285 StringCbCopyA(cstrp, smb_ServerCommentLen, smb_ServerComment);
2287 cstrp += smb_ServerCommentLen / sizeof(char);
2290 totalData = (DWORD)(cstrp - outp->datap);
2291 outp->totalData = min(bufsize,totalData); /* actual data size */
2292 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
2293 outp->parmsp[2] = totalData;
2294 outp->totalParms = totalParams;
2296 smb_SendTran2Packet(vcp,outp,op);
2297 smb_FreeTran2Packet(outp);
2302 /* SMB_COM_TRANSACTION2 and SMB_COM_TRANSACTION2_SECONDARY */
2303 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2305 smb_tran2Packet_t *asp;
2316 DWORD oldTime, newTime;
2318 /* We sometimes see 0 word count. What to do? */
2319 if (*inp->wctp == 0) {
2320 osi_Log0(smb_logp, "Transaction2 word count = 0");
2321 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
2323 smb_SetSMBDataLength(outp, 0);
2324 smb_SendPacket(vcp, outp);
2328 totalParms = smb_GetSMBParm(inp, 0);
2329 totalData = smb_GetSMBParm(inp, 1);
2331 firstPacket = (inp->inCom == 0x32);
2333 /* find the packet we're reassembling */
2334 lock_ObtainWrite(&smb_globalLock);
2335 asp = smb_FindTran2Packet(vcp, inp);
2337 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
2339 lock_ReleaseWrite(&smb_globalLock);
2341 /* now merge in this latest packet; start by looking up offsets */
2343 parmDisp = dataDisp = 0;
2344 parmOffset = smb_GetSMBParm(inp, 10);
2345 dataOffset = smb_GetSMBParm(inp, 12);
2346 parmCount = smb_GetSMBParm(inp, 9);
2347 dataCount = smb_GetSMBParm(inp, 11);
2348 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2349 asp->maxReturnData = smb_GetSMBParm(inp, 3);
2351 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2352 totalData, dataCount, asp->maxReturnData);
2355 parmDisp = smb_GetSMBParm(inp, 4);
2356 parmOffset = smb_GetSMBParm(inp, 3);
2357 dataDisp = smb_GetSMBParm(inp, 7);
2358 dataOffset = smb_GetSMBParm(inp, 6);
2359 parmCount = smb_GetSMBParm(inp, 2);
2360 dataCount = smb_GetSMBParm(inp, 5);
2362 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2363 parmCount, dataCount);
2366 /* now copy the parms and data */
2367 if ( asp->totalParms > 0 && parmCount != 0 )
2369 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2371 if ( asp->totalData > 0 && dataCount != 0 ) {
2372 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2375 /* account for new bytes */
2376 asp->curData += dataCount;
2377 asp->curParms += parmCount;
2379 /* finally, if we're done, remove the packet from the queue and dispatch it */
2380 if (asp->totalParms > 0 &&
2381 asp->curParms > 0 &&
2382 asp->totalData <= asp->curData &&
2383 asp->totalParms <= asp->curParms) {
2384 /* we've received it all */
2385 lock_ObtainWrite(&smb_globalLock);
2386 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2387 lock_ReleaseWrite(&smb_globalLock);
2389 oldTime = GetTickCount();
2391 /* now dispatch it */
2392 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2393 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2394 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2397 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2398 code = CM_ERROR_BADOP;
2401 /* if an error is returned, we're supposed to send an error packet,
2402 * otherwise the dispatched function already did the data sending.
2403 * We give dispatched proc the responsibility since it knows how much
2404 * space to allocate.
2407 smb_SendTran2Error(vcp, asp, outp, code);
2410 newTime = GetTickCount();
2411 if (newTime - oldTime > 45000) {
2414 clientchar_t *treepath = NULL; /* do not free */
2415 clientchar_t *pathname = NULL;
2416 cm_fid_t afid = {0,0,0,0,0};
2418 uidp = smb_FindUID(vcp, asp->uid, 0);
2419 smb_LookupTIDPath(vcp, asp->tid, &treepath);
2420 fidp = smb_FindFID(vcp, inp->fid, 0);
2423 lock_ObtainMutex(&fidp->mx);
2424 if (fidp->NTopen_pathp)
2425 pathname = fidp->NTopen_pathp;
2427 afid = fidp->scp->fid;
2429 if (inp->stringsp->wdata)
2430 pathname = inp->stringsp->wdata;
2433 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)",
2434 myCrt_2Dispatch(asp->opcode), newTime - oldTime,
2435 asp->uid, uidp ? uidp->unp->name : NULL,
2436 asp->pid, asp->mid, asp->tid,
2439 afid.cell, afid.volume, afid.vnode, afid.unique);
2442 lock_ReleaseMutex(&fidp->mx);
2445 smb_ReleaseUID(uidp);
2447 smb_ReleaseFID(fidp);
2450 /* free the input tran 2 packet */
2451 smb_FreeTran2Packet(asp);
2453 else if (firstPacket) {
2454 /* the first packet in a multi-packet request, we need to send an
2455 * ack to get more data.
2457 smb_SetSMBDataLength(outp, 0);
2458 smb_SendPacket(vcp, outp);
2465 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2467 clientchar_t *pathp;
2468 smb_tran2Packet_t *outp;
2473 cm_scache_t *dscp; /* dir we're dealing with */
2474 cm_scache_t *scp; /* file we're creating */
2476 int initialModeBits;
2479 clientchar_t *lastNamep;
2486 int parmSlot; /* which parm we're dealing with */
2487 long returnEALength;
2488 clientchar_t *tidPathp;
2491 BOOL is_rpc = FALSE;
2497 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2498 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2500 openFun = p->parmsp[6]; /* open function */
2501 excl = ((openFun & 3) == 0);
2502 trunc = ((openFun & 3) == 2); /* truncate it */
2503 openMode = (p->parmsp[1] & 0x7);
2504 openAction = 0; /* tracks what we did */
2506 attributes = p->parmsp[3];
2507 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2509 /* compute initial mode bits based on read-only flag in attributes */
2510 initialModeBits = 0666;
2511 if (attributes & SMB_ATTR_READONLY)
2512 initialModeBits &= ~0222;
2514 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
2517 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2519 spacep = cm_GetSpace();
2520 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2522 /* The 'is_rpc' assignment to TRUE is intentional */
2524 (cm_ClientStrCmpI(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
2525 ((cm_ClientStrCmpI(lastNamep, _C("\\srvsvc")) == 0 ||
2526 cm_ClientStrCmpI(lastNamep, _C("\\wkssvc")) == 0 ||
2527 cm_ClientStrCmpI(lastNamep, _C("\\spoolss")) == 0 ||
2528 cm_ClientStrCmpI(lastNamep, _C("\\winreg")) == 0 ||
2529 cm_ClientStrCmpI(lastNamep, _C("\\ipc$")) == 0) && (is_rpc = TRUE)))) {
2531 unsigned short file_type = 0;
2532 unsigned short device_state = 0;
2534 /* special case magic file name for receiving IOCTL requests
2535 * (since IOCTL calls themselves aren't getting through).
2537 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2540 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
2541 osi_Log2(smb_logp, "smb_ReceiveTran2Open Creating RPC Fid [%d] code [%d]",
2544 smb_SetupIoctlFid(fidp, spacep);
2545 osi_Log1(smb_logp, "smb_ReceiveTran2Open Creating IOCTL Fid [%d]", fidp->fid);
2548 /* copy out remainder of the parms */
2550 outp->parmsp[parmSlot++] = fidp->fid;
2552 outp->parmsp[parmSlot++] = 0; /* attrs */
2553 outp->parmsp[parmSlot++] = 0; /* mod time */
2554 outp->parmsp[parmSlot++] = 0;
2555 outp->parmsp[parmSlot++] = 0; /* len */
2556 outp->parmsp[parmSlot++] = 0x7fff;
2557 outp->parmsp[parmSlot++] = openMode;
2558 outp->parmsp[parmSlot++] = file_type;
2559 outp->parmsp[parmSlot++] = device_state;
2561 /* and the final "always present" stuff */
2562 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2563 /* next write out the "unique" ID */
2564 outp->parmsp[parmSlot++] = 0x1234;
2565 outp->parmsp[parmSlot++] = 0x5678;
2566 outp->parmsp[parmSlot++] = 0;
2567 if (returnEALength) {
2568 outp->parmsp[parmSlot++] = 0;
2569 outp->parmsp[parmSlot++] = 0;
2572 outp->totalData = 0;
2573 outp->totalParms = parmSlot * 2;
2575 smb_SendTran2Packet(vcp, outp, op);
2577 smb_FreeTran2Packet(outp);
2579 /* and clean up fid reference */
2580 smb_ReleaseFID(fidp);
2584 if (!cm_IsValidClientString(pathp)) {
2586 clientchar_t * hexp;
2588 hexp = cm_GetRawCharsAlloc(pathp, -1);
2589 osi_Log1(smb_logp, "Tran2Open rejecting invalid name. [%S]",
2590 osi_LogSaveClientString(smb_logp, hexp));
2594 osi_Log0(smb_logp, "Tran2Open rejecting invalid name");
2596 smb_FreeTran2Packet(outp);
2597 return CM_ERROR_BADNTFILENAME;
2600 #ifdef DEBUG_VERBOSE
2602 char *hexp, *asciip;
2603 asciip = (lastNamep ? lastNamep : pathp);
2604 hexp = osi_HexifyString( asciip );
2605 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2610 userp = smb_GetTran2User(vcp, p);
2611 /* In the off chance that userp is NULL, we log and abandon */
2613 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2614 smb_FreeTran2Packet(outp);
2615 return CM_ERROR_BADSMB;
2618 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2619 if (code == CM_ERROR_TIDIPC) {
2620 /* Attempt to use a TID allocated for IPC. The client
2621 * is probably looking for DCE RPC end points which we
2622 * don't support OR it could be looking to make a DFS
2625 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2627 cm_ReleaseUser(userp);
2628 smb_FreeTran2Packet(outp);
2629 return CM_ERROR_NOSUCHPATH;
2634 code = cm_NameI(cm_data.rootSCachep, pathp,
2635 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2636 userp, tidPathp, &req, &scp);
2638 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2639 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2640 userp, tidPathp, &req, &dscp);
2641 cm_FreeSpace(spacep);
2644 cm_ReleaseUser(userp);
2645 smb_FreeTran2Packet(outp);
2650 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2651 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2652 (clientchar_t*) spacep->data);
2653 cm_ReleaseSCache(dscp);
2654 cm_ReleaseUser(userp);
2655 smb_FreeTran2Packet(outp);
2656 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2657 return CM_ERROR_PATH_NOT_COVERED;
2659 return CM_ERROR_NOSUCHPATH;
2661 #endif /* DFS_SUPPORT */
2663 /* otherwise, scp points to the parent directory. Do a lookup,
2664 * and truncate the file if we find it, otherwise we create the
2671 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2673 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2674 cm_ReleaseSCache(dscp);
2675 cm_ReleaseUser(userp);
2676 smb_FreeTran2Packet(outp);
2681 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2682 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2683 cm_ReleaseSCache(scp);
2684 cm_ReleaseUser(userp);
2685 smb_FreeTran2Packet(outp);
2686 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2687 return CM_ERROR_PATH_NOT_COVERED;
2689 return CM_ERROR_NOSUCHPATH;
2691 #endif /* DFS_SUPPORT */
2693 /* macintosh is expensive to program for it */
2694 cm_FreeSpace(spacep);
2697 /* if we get here, if code is 0, the file exists and is represented by
2698 * scp. Otherwise, we have to create it.
2701 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2704 cm_ReleaseSCache(dscp);
2705 cm_ReleaseSCache(scp);
2706 cm_ReleaseUser(userp);
2707 smb_FreeTran2Packet(outp);
2712 /* oops, file shouldn't be there */
2714 cm_ReleaseSCache(dscp);
2715 cm_ReleaseSCache(scp);
2716 cm_ReleaseUser(userp);
2717 smb_FreeTran2Packet(outp);
2718 return CM_ERROR_EXISTS;
2722 setAttr.mask = CM_ATTRMASK_LENGTH;
2723 setAttr.length.LowPart = 0;
2724 setAttr.length.HighPart = 0;
2725 code = cm_SetAttr(scp, &setAttr, userp, &req);
2726 openAction = 3; /* truncated existing file */
2729 openAction = 1; /* found existing file */
2731 else if (!(openFun & 0x10)) {
2732 /* don't create if not found */
2734 cm_ReleaseSCache(dscp);
2735 osi_assertx(scp == NULL, "null cm_scache_t");
2736 cm_ReleaseUser(userp);
2737 smb_FreeTran2Packet(outp);
2738 return CM_ERROR_NOSUCHFILE;
2741 osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2742 openAction = 2; /* created file */
2743 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2744 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2745 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2749 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2750 smb_NotifyChange(FILE_ACTION_ADDED,
2751 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2752 dscp, lastNamep, NULL, TRUE);
2753 } else if (!excl && code == CM_ERROR_EXISTS) {
2754 /* not an exclusive create, and someone else tried
2755 * creating it already, then we open it anyway. We
2756 * don't bother retrying after this, since if this next
2757 * fails, that means that the file was deleted after we
2758 * started this call.
2760 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2764 setAttr.mask = CM_ATTRMASK_LENGTH;
2765 setAttr.length.LowPart = 0;
2766 setAttr.length.HighPart = 0;
2767 code = cm_SetAttr(scp, &setAttr, userp,
2770 } /* lookup succeeded */
2774 /* we don't need this any longer */
2776 cm_ReleaseSCache(dscp);
2779 /* something went wrong creating or truncating the file */
2781 cm_ReleaseSCache(scp);
2782 cm_ReleaseUser(userp);
2783 smb_FreeTran2Packet(outp);
2787 /* make sure we're about to open a file */
2788 if (scp->fileType != CM_SCACHETYPE_FILE) {
2790 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2791 cm_scache_t * targetScp = 0;
2792 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2794 /* we have a more accurate file to use (the
2795 * target of the symbolic link). Otherwise,
2796 * we'll just use the symlink anyway.
2798 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2800 cm_ReleaseSCache(scp);
2804 if (scp->fileType != CM_SCACHETYPE_FILE) {
2805 cm_ReleaseSCache(scp);
2806 cm_ReleaseUser(userp);
2807 smb_FreeTran2Packet(outp);
2808 return CM_ERROR_ISDIR;
2812 /* now all we have to do is open the file itself */
2813 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2814 osi_assertx(fidp, "null smb_fid_t");
2817 lock_ObtainMutex(&fidp->mx);
2818 /* save a pointer to the vnode */
2819 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2821 lock_ObtainWrite(&scp->rw);
2822 scp->flags |= CM_SCACHEFLAG_SMB_FID;
2823 lock_ReleaseWrite(&scp->rw);
2826 fidp->userp = userp;
2828 /* compute open mode */
2830 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
2831 if (openMode == 1 || openMode == 2)
2832 fidp->flags |= SMB_FID_OPENWRITE;
2834 /* remember that the file was newly created */
2836 fidp->flags |= SMB_FID_CREATED;
2838 lock_ReleaseMutex(&fidp->mx);
2840 smb_ReleaseFID(fidp);
2842 cm_Open(scp, 0, userp);
2844 /* copy out remainder of the parms */
2846 outp->parmsp[parmSlot++] = fidp->fid;
2847 lock_ObtainRead(&scp->rw);
2849 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2850 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2851 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2852 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2853 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2854 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2855 outp->parmsp[parmSlot++] = openMode;
2856 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2857 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2859 /* and the final "always present" stuff */
2860 outp->parmsp[parmSlot++] = openAction;
2861 /* next write out the "unique" ID */
2862 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2863 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2864 outp->parmsp[parmSlot++] = 0;
2865 if (returnEALength) {
2866 outp->parmsp[parmSlot++] = 0;
2867 outp->parmsp[parmSlot++] = 0;
2869 lock_ReleaseRead(&scp->rw);
2870 outp->totalData = 0; /* total # of data bytes */
2871 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2873 smb_SendTran2Packet(vcp, outp, op);
2875 smb_FreeTran2Packet(outp);
2877 cm_ReleaseUser(userp);
2878 /* leave scp held since we put it in fidp->scp */
2882 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2885 unsigned short infolevel;
2887 infolevel = p->parmsp[0];
2889 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2891 return CM_ERROR_BAD_LEVEL;
2894 /* TRANS2_QUERY_FS_INFORMATION */
2895 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2897 smb_tran2Packet_t *outp;
2898 smb_tran2QFSInfo_t qi;
2902 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2904 switch (p->parmsp[0]) {
2905 case SMB_INFO_ALLOCATION:
2907 responseSize = sizeof(qi.u.allocInfo);
2909 qi.u.allocInfo.FSID = 0;
2910 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2911 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2912 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2913 qi.u.allocInfo.bytesPerSector = 1024;
2916 case SMB_INFO_VOLUME:
2918 qi.u.volumeInfo.vsn = 1234; /* Volume serial number */
2919 qi.u.volumeInfo.vnCount = 3; /* Number of characters in label (AFS\0)*/
2921 /* we're supposed to pad it out with zeroes to the end */
2922 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2923 smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
2925 responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
2928 case SMB_QUERY_FS_VOLUME_INFO:
2929 /* FS volume info */
2930 responseSize = sizeof(qi.u.FSvolumeInfo);
2933 FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
2934 memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
2937 qi.u.FSvolumeInfo.vsn = 1234;
2938 qi.u.FSvolumeInfo.vnCount = 6; /* This is always in Unicode */
2939 memset(&qi.u.FSvolumeInfo.label, 0, sizeof(qi.u.FSvolumeInfo.label));
2940 memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
2943 case SMB_QUERY_FS_SIZE_INFO:
2945 responseSize = sizeof(qi.u.FSsizeInfo);
2947 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2948 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2949 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2950 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2951 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2952 qi.u.FSsizeInfo.bytesPerSector = 1024;
2955 case SMB_QUERY_FS_DEVICE_INFO:
2956 /* FS device info */
2957 responseSize = sizeof(qi.u.FSdeviceInfo);
2959 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2960 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2963 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2964 /* FS attribute info */
2966 /* attributes, defined in WINNT.H:
2967 * FILE_CASE_SENSITIVE_SEARCH 0x1
2968 * FILE_CASE_PRESERVED_NAMES 0x2
2969 * FILE_UNICODE_ON_DISK 0x4
2970 * FILE_VOLUME_QUOTAS 0x10
2971 * <no name defined> 0x4000
2972 * If bit 0x4000 is not set, Windows 95 thinks
2973 * we can't handle long (non-8.3) names,
2974 * despite our protestations to the contrary.
2976 qi.u.FSattributeInfo.attributes = 0x4003;
2977 /* The maxCompLength is supposed to be in bytes */
2979 qi.u.FSattributeInfo.attributes |= 0x04;
2981 qi.u.FSattributeInfo.maxCompLength = 255;
2982 smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
2983 qi.u.FSattributeInfo.FSnameLength = sz;
2986 sizeof(qi.u.FSattributeInfo.attributes) +
2987 sizeof(qi.u.FSattributeInfo.maxCompLength) +
2988 sizeof(qi.u.FSattributeInfo.FSnameLength) +
2993 case SMB_INFO_UNIX: /* CIFS Unix Info */
2994 case SMB_INFO_MACOS: /* Mac FS Info */
2996 return CM_ERROR_BADOP;
2999 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
3001 /* copy out return data, and set corresponding sizes */
3002 outp->totalParms = 0;
3003 outp->totalData = responseSize;
3004 memcpy(outp->datap, &qi, responseSize);
3006 /* send and free the packets */
3007 smb_SendTran2Packet(vcp, outp, op);
3008 smb_FreeTran2Packet(outp);
3013 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3015 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
3016 return CM_ERROR_BADOP;
3019 struct smb_ShortNameRock {
3020 clientchar_t *maskp;
3022 clientchar_t *shortName;
3023 size_t shortNameLen;
3026 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
3029 struct smb_ShortNameRock *rockp;
3030 normchar_t normName[MAX_PATH];
3031 clientchar_t *shortNameEnd;
3035 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t)) == 0) {
3036 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
3037 osi_LogSaveString(smb_logp, dep->name));
3041 /* compare both names and vnodes, though probably just comparing vnodes
3042 * would be safe enough.
3044 if (cm_NormStrCmpI(normName, rockp->maskp) != 0)
3046 if (ntohl(dep->fid.vnode) != rockp->vnode)
3049 /* This is the entry */
3050 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
3051 rockp->shortNameLen = shortNameEnd - rockp->shortName;
3053 return CM_ERROR_STOPNOW;
3056 long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
3057 clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
3059 struct smb_ShortNameRock rock;
3060 clientchar_t *lastNamep;
3063 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
3067 spacep = cm_GetSpace();
3068 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
3070 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3071 caseFold, userp, tidPathp,
3073 cm_FreeSpace(spacep);
3078 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3079 cm_ReleaseSCache(dscp);
3080 cm_ReleaseUser(userp);
3084 return CM_ERROR_PATH_NOT_COVERED;
3086 #endif /* DFS_SUPPORT */
3088 if (!lastNamep) lastNamep = pathp;
3091 thyper.HighPart = 0;
3092 rock.shortName = shortName;
3094 rock.maskp = lastNamep;
3095 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
3097 cm_ReleaseSCache(dscp);
3100 return CM_ERROR_NOSUCHFILE;
3101 if (code == CM_ERROR_STOPNOW) {
3102 *shortNameLenp = rock.shortNameLen;
3108 /* TRANS2_QUERY_PATH_INFORMATION */
3109 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3111 smb_tran2Packet_t *outp;
3114 unsigned short infoLevel;
3115 smb_tran2QPathInfo_t qpi;
3117 unsigned short attributes;
3118 unsigned long extAttributes;
3119 clientchar_t shortName[13];
3123 cm_scache_t *scp, *dscp;
3124 int scp_rw_held = 0;
3127 clientchar_t *pathp;
3128 clientchar_t *tidPathp;
3129 clientchar_t *lastComp;
3134 infoLevel = p->parmsp[0];
3135 if (infoLevel == SMB_INFO_IS_NAME_VALID)
3137 else if (infoLevel == SMB_INFO_STANDARD)
3138 responseSize = sizeof(qpi.u.QPstandardInfo);
3139 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
3140 responseSize = sizeof(qpi.u.QPeaSizeInfo);
3141 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3142 responseSize = sizeof(qpi.u.QPfileBasicInfo);
3143 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3144 responseSize = sizeof(qpi.u.QPfileStandardInfo);
3145 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3146 responseSize = sizeof(qpi.u.QPfileEaInfo);
3147 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3148 responseSize = sizeof(qpi.u.QPfileNameInfo);
3149 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
3150 responseSize = sizeof(qpi.u.QPfileAllInfo);
3151 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
3152 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
3154 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3155 p->opcode, infoLevel);
3156 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3160 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3161 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %S", infoLevel,
3162 osi_LogSaveClientString(smb_logp, pathp));
3164 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3166 if (infoLevel > 0x100)
3167 outp->totalParms = 2;
3169 outp->totalParms = 0;
3170 outp->totalData = responseSize;
3172 /* now, if we're at infoLevel 6, we're only being asked to check
3173 * the syntax, so we just OK things now. In particular, we're *not*
3174 * being asked to verify anything about the state of any parent dirs.
3176 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
3177 smb_SendTran2Packet(vcp, outp, opx);
3178 smb_FreeTran2Packet(outp);
3182 userp = smb_GetTran2User(vcp, p);
3184 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
3185 smb_FreeTran2Packet(outp);
3186 return CM_ERROR_BADSMB;
3189 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3191 cm_ReleaseUser(userp);
3192 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
3193 smb_FreeTran2Packet(outp);
3198 * XXX Strange hack XXX
3200 * As of Patch 7 (13 January 98), we are having the following problem:
3201 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3202 * requests to look up "desktop.ini" in all the subdirectories.
3203 * This can cause zillions of timeouts looking up non-existent cells
3204 * and volumes, especially in the top-level directory.
3206 * We have not found any way to avoid this or work around it except
3207 * to explicitly ignore the requests for mount points that haven't
3208 * yet been evaluated and for directories that haven't yet been
3211 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3212 spacep = cm_GetSpace();
3213 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3214 #ifndef SPECIAL_FOLDERS
3215 /* Make sure that lastComp is not NULL */
3217 if (cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
3218 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3222 userp, tidPathp, &req, &dscp);
3225 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3226 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3228 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3229 code = CM_ERROR_PATH_NOT_COVERED;
3231 code = CM_ERROR_NOSUCHPATH;
3233 #endif /* DFS_SUPPORT */
3234 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3235 code = CM_ERROR_NOSUCHFILE;
3236 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3237 cm_buf_t *bp = buf_Find(dscp, &hzero);
3243 code = CM_ERROR_NOSUCHFILE;
3245 cm_ReleaseSCache(dscp);
3247 cm_FreeSpace(spacep);
3248 cm_ReleaseUser(userp);
3249 smb_SendTran2Error(vcp, p, opx, code);
3250 smb_FreeTran2Packet(outp);
3256 #endif /* SPECIAL_FOLDERS */
3258 cm_FreeSpace(spacep);
3261 /* now do namei and stat, and copy out the info */
3262 code = cm_NameI(cm_data.rootSCachep, pathp,
3263 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3266 cm_ReleaseUser(userp);
3267 smb_SendTran2Error(vcp, p, opx, code);
3268 smb_FreeTran2Packet(outp);
3273 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3274 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3275 cm_ReleaseSCache(scp);
3276 cm_ReleaseUser(userp);
3277 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3278 code = CM_ERROR_PATH_NOT_COVERED;
3280 code = CM_ERROR_NOSUCHPATH;
3281 smb_SendTran2Error(vcp, p, opx, code);
3282 smb_FreeTran2Packet(outp);
3285 #endif /* DFS_SUPPORT */
3287 lock_ObtainWrite(&scp->rw);
3289 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3290 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3294 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3296 lock_ConvertWToR(&scp->rw);
3301 /* now we have the status in the cache entry, and everything is locked.
3302 * Marshall the output data.
3304 /* for info level 108, figure out short name */
3305 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3306 code = cm_GetShortName(pathp, userp, &req,
3307 tidPathp, scp->fid.vnode, shortName,
3313 smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
3314 qpi.u.QPfileAltNameInfo.fileNameLength = len;
3318 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3319 smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3320 qpi.u.QPfileNameInfo.fileNameLength = len;
3324 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3325 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3326 qpi.u.QPstandardInfo.creationDateTime = dosTime;
3327 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3328 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3329 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3330 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3331 attributes = smb_Attributes(scp);
3332 qpi.u.QPstandardInfo.attributes = attributes;
3333 qpi.u.QPstandardInfo.eaSize = 0;
3335 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3336 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3337 qpi.u.QPfileBasicInfo.creationTime = ft;
3338 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3339 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3340 qpi.u.QPfileBasicInfo.changeTime = ft;
3341 extAttributes = smb_ExtAttributes(scp);
3342 qpi.u.QPfileBasicInfo.attributes = extAttributes;
3343 qpi.u.QPfileBasicInfo.reserved = 0;
3345 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3348 lock_ReleaseRead(&scp->rw);
3350 fidp = smb_FindFIDByScache(vcp, scp);
3352 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3353 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3354 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3355 qpi.u.QPfileStandardInfo.directory =
3356 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3357 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3358 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3359 qpi.u.QPfileStandardInfo.reserved = 0;
3362 lock_ObtainMutex(&fidp->mx);
3363 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3364 lock_ReleaseMutex(&fidp->mx);
3365 smb_ReleaseFID(fidp);
3367 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3369 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3370 qpi.u.QPfileEaInfo.eaSize = 0;
3372 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3373 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3374 qpi.u.QPfileAllInfo.creationTime = ft;
3375 qpi.u.QPfileAllInfo.lastAccessTime = ft;
3376 qpi.u.QPfileAllInfo.lastWriteTime = ft;
3377 qpi.u.QPfileAllInfo.changeTime = ft;
3378 extAttributes = smb_ExtAttributes(scp);
3379 qpi.u.QPfileAllInfo.attributes = extAttributes;
3380 qpi.u.QPfileAllInfo.allocationSize = scp->length;
3381 qpi.u.QPfileAllInfo.endOfFile = scp->length;
3382 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3383 qpi.u.QPfileAllInfo.deletePending = 0;
3384 qpi.u.QPfileAllInfo.directory =
3385 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3386 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3387 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3388 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
3389 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
3390 qpi.u.QPfileAllInfo.eaSize = 0;
3391 qpi.u.QPfileAllInfo.accessFlags = 0;
3392 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
3393 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
3394 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3395 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3396 qpi.u.QPfileAllInfo.mode = 0;
3397 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3399 smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3400 qpi.u.QPfileAllInfo.fileNameLength = len;
3403 /* send and free the packets */
3405 switch (scp_rw_held) {
3407 lock_ReleaseRead(&scp->rw);
3410 lock_ReleaseWrite(&scp->rw);
3414 cm_ReleaseSCache(scp);
3415 cm_ReleaseUser(userp);
3417 memcpy(outp->datap, &qpi, responseSize);
3418 smb_SendTran2Packet(vcp, outp, opx);
3420 smb_SendTran2Error(vcp, p, opx, code);
3422 smb_FreeTran2Packet(outp);
3427 /* TRANS2_SET_PATH_INFORMATION */
3428 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3431 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
3432 return CM_ERROR_BADOP;
3435 unsigned short infoLevel;
3436 clientchar_t * pathp;
3437 smb_tran2Packet_t *outp;
3438 smb_tran2QPathInfo_t *spi;
3440 cm_scache_t *scp, *dscp;
3443 clientchar_t *tidPathp;
3444 clientchar_t *lastComp;
3448 infoLevel = p->parmsp[0];
3449 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
3450 if (infoLevel != SMB_INFO_STANDARD &&
3451 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
3452 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
3453 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3454 p->opcode, infoLevel);
3455 smb_SendTran2Error(vcp, p, opx,
3456 infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3460 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3462 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
3463 osi_LogSaveClientString(smb_logp, pathp));
3465 userp = smb_GetTran2User(vcp, p);
3467 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3468 code = CM_ERROR_BADSMB;
3472 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3473 if (code == CM_ERROR_TIDIPC) {
3474 /* Attempt to use a TID allocated for IPC. The client
3475 * is probably looking for DCE RPC end points which we
3476 * don't support OR it could be looking to make a DFS
3479 osi_Log0(smb_logp, "Tran2Open received IPC TID");
3480 cm_ReleaseUser(userp);
3481 return CM_ERROR_NOSUCHPATH;
3485 * XXX Strange hack XXX
3487 * As of Patch 7 (13 January 98), we are having the following problem:
3488 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3489 * requests to look up "desktop.ini" in all the subdirectories.
3490 * This can cause zillions of timeouts looking up non-existent cells
3491 * and volumes, especially in the top-level directory.
3493 * We have not found any way to avoid this or work around it except
3494 * to explicitly ignore the requests for mount points that haven't
3495 * yet been evaluated and for directories that haven't yet been
3498 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3499 spacep = cm_GetSpace();
3500 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3501 #ifndef SPECIAL_FOLDERS
3502 /* Make sure that lastComp is not NULL */
3504 if (cm_ClientStrCmpI(lastComp, _C("\\desktop.ini")) == 0) {
3505 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3509 userp, tidPathp, &req, &dscp);
3512 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3513 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3515 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3516 code = CM_ERROR_PATH_NOT_COVERED;
3518 code = CM_ERROR_NOSUCHPATH;
3520 #endif /* DFS_SUPPORT */
3521 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3522 code = CM_ERROR_NOSUCHFILE;
3523 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3524 cm_buf_t *bp = buf_Find(dscp, &hzero);
3530 code = CM_ERROR_NOSUCHFILE;
3532 cm_ReleaseSCache(dscp);
3534 cm_FreeSpace(spacep);
3535 cm_ReleaseUser(userp);
3536 smb_SendTran2Error(vcp, p, opx, code);
3542 #endif /* SPECIAL_FOLDERS */
3544 cm_FreeSpace(spacep);
3547 /* now do namei and stat, and copy out the info */
3548 code = cm_NameI(cm_data.rootSCachep, pathp,
3549 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3551 cm_ReleaseUser(userp);
3552 smb_SendTran2Error(vcp, p, opx, code);
3556 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3558 outp->totalParms = 2;
3559 outp->totalData = 0;
3561 spi = (smb_tran2QPathInfo_t *)p->datap;
3562 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3565 /* lock the vnode with a callback; we need the current status
3566 * to determine what the new status is, in some cases.
3568 lock_ObtainWrite(&scp->rw);
3569 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3570 CM_SCACHESYNC_GETSTATUS
3571 | CM_SCACHESYNC_NEEDCALLBACK);
3573 lock_ReleaseWrite(&scp->rw);
3576 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3578 /* prepare for setattr call */
3579 attr.mask = CM_ATTRMASK_LENGTH;
3580 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3581 attr.length.HighPart = 0;
3583 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3584 smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3585 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3588 if (spi->u.QPstandardInfo.attributes != 0) {
3589 if ((scp->unixModeBits & 0222)
3590 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3591 /* make a writable file read-only */
3592 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3593 attr.unixModeBits = scp->unixModeBits & ~0222;
3595 else if ((scp->unixModeBits & 0222) == 0
3596 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3597 /* make a read-only file writable */
3598 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3599 attr.unixModeBits = scp->unixModeBits | 0222;
3602 lock_ReleaseRead(&scp->rw);
3606 code = cm_SetAttr(scp, &attr, userp, &req);
3610 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3611 /* we don't support EAs */
3612 code = CM_ERROR_EAS_NOT_SUPPORTED;
3616 cm_ReleaseSCache(scp);
3617 cm_ReleaseUser(userp);
3619 smb_SendTran2Packet(vcp, outp, opx);
3621 smb_SendTran2Error(vcp, p, opx, code);
3622 smb_FreeTran2Packet(outp);
3628 /* TRANS2_QUERY_FILE_INFORMATION */
3629 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3631 smb_tran2Packet_t *outp;
3633 unsigned long attributes;
3634 unsigned short infoLevel;
3641 smb_tran2QFileInfo_t qfi;
3649 fidp = smb_FindFID(vcp, fid, 0);
3652 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3656 lock_ObtainMutex(&fidp->mx);
3657 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3658 lock_ReleaseMutex(&fidp->mx);
3659 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3660 smb_CloseFID(vcp, fidp, NULL, 0);
3661 smb_ReleaseFID(fidp);
3664 lock_ReleaseMutex(&fidp->mx);
3666 infoLevel = p->parmsp[1];
3667 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3668 responseSize = sizeof(qfi.u.QFbasicInfo);
3669 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3670 responseSize = sizeof(qfi.u.QFstandardInfo);
3671 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3672 responseSize = sizeof(qfi.u.QFeaInfo);
3673 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3674 responseSize = sizeof(qfi.u.QFfileNameInfo);
3676 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3677 p->opcode, infoLevel);
3678 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3679 smb_ReleaseFID(fidp);
3682 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3684 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3686 if (infoLevel > 0x100)
3687 outp->totalParms = 2;
3689 outp->totalParms = 0;
3690 outp->totalData = responseSize;
3692 userp = smb_GetTran2User(vcp, p);
3694 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3695 code = CM_ERROR_BADSMB;
3699 lock_ObtainMutex(&fidp->mx);
3700 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3702 osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3704 lock_ReleaseMutex(&fidp->mx);
3705 lock_ObtainWrite(&scp->rw);
3706 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3707 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3711 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3713 lock_ConvertWToR(&scp->rw);
3716 /* now we have the status in the cache entry, and everything is locked.
3717 * Marshall the output data.
3719 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3720 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3721 qfi.u.QFbasicInfo.creationTime = ft;
3722 qfi.u.QFbasicInfo.lastAccessTime = ft;
3723 qfi.u.QFbasicInfo.lastWriteTime = ft;
3724 qfi.u.QFbasicInfo.lastChangeTime = ft;
3725 attributes = smb_ExtAttributes(scp);
3726 qfi.u.QFbasicInfo.attributes = attributes;
3728 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3729 qfi.u.QFstandardInfo.allocationSize = scp->length;
3730 qfi.u.QFstandardInfo.endOfFile = scp->length;
3731 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3732 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3733 qfi.u.QFstandardInfo.directory =
3734 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3735 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3736 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3738 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3739 qfi.u.QFeaInfo.eaSize = 0;
3741 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3745 lock_ReleaseRead(&scp->rw);
3746 lock_ObtainMutex(&fidp->mx);
3747 lock_ObtainRead(&scp->rw);
3748 if (fidp->NTopen_wholepathp)
3749 name = fidp->NTopen_wholepathp;
3751 name = _C("\\"); /* probably can't happen */
3752 lock_ReleaseMutex(&fidp->mx);
3754 smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, SMB_STRF_IGNORENUL);
3755 outp->totalData = len + 4; /* this is actually what we want to return */
3756 qfi.u.QFfileNameInfo.fileNameLength = len;
3759 /* send and free the packets */
3762 lock_ReleaseRead(&scp->rw);
3764 lock_ReleaseWrite(&scp->rw);
3765 cm_ReleaseSCache(scp);
3766 cm_ReleaseUser(userp);
3767 smb_ReleaseFID(fidp);
3769 memcpy(outp->datap, &qfi, responseSize);
3770 smb_SendTran2Packet(vcp, outp, opx);
3772 smb_SendTran2Error(vcp, p, opx, code);
3774 smb_FreeTran2Packet(outp);
3780 /* TRANS2_SET_FILE_INFORMATION */
3781 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3786 unsigned short infoLevel;
3787 smb_tran2Packet_t *outp;
3788 cm_user_t *userp = NULL;
3789 cm_scache_t *scp = NULL;
3795 fidp = smb_FindFID(vcp, fid, 0);
3798 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3802 infoLevel = p->parmsp[1];
3803 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3804 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3805 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3806 p->opcode, infoLevel);
3807 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3808 smb_ReleaseFID(fidp);
3812 lock_ObtainMutex(&fidp->mx);
3813 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3814 lock_ReleaseMutex(&fidp->mx);
3815 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3816 smb_CloseFID(vcp, fidp, NULL, 0);
3817 smb_ReleaseFID(fidp);
3821 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
3822 !(fidp->flags & SMB_FID_OPENDELETE)) {
3823 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3824 fidp, fidp->scp, fidp->flags);
3825 lock_ReleaseMutex(&fidp->mx);
3826 smb_ReleaseFID(fidp);
3827 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3830 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3831 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3832 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3833 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3834 fidp, fidp->scp, fidp->flags);
3835 lock_ReleaseMutex(&fidp->mx);
3836 smb_ReleaseFID(fidp);
3837 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3842 osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3844 lock_ReleaseMutex(&fidp->mx);
3846 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3848 outp->totalParms = 2;
3849 outp->totalData = 0;
3851 userp = smb_GetTran2User(vcp, p);
3853 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3854 code = CM_ERROR_BADSMB;
3858 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3860 unsigned int attribute;
3862 smb_tran2QFileInfo_t *sfi;
3864 sfi = (smb_tran2QFileInfo_t *)p->datap;
3866 /* lock the vnode with a callback; we need the current status
3867 * to determine what the new status is, in some cases.
3869 lock_ObtainWrite(&scp->rw);
3870 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3871 CM_SCACHESYNC_GETSTATUS
3872 | CM_SCACHESYNC_NEEDCALLBACK);
3874 lock_ReleaseWrite(&scp->rw);
3878 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3880 lock_ReleaseWrite(&scp->rw);
3881 lock_ObtainMutex(&fidp->mx);
3882 lock_ObtainRead(&scp->rw);
3884 /* prepare for setattr call */
3887 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3888 /* when called as result of move a b, lastMod is (-1, -1).
3889 * If the check for -1 is not present, timestamp
3890 * of the resulting file will be 1969 (-1)
3892 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3893 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3894 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3895 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3896 fidp->flags |= SMB_FID_MTIMESETDONE;
3899 attribute = sfi->u.QFbasicInfo.attributes;
3900 if (attribute != 0) {
3901 if ((scp->unixModeBits & 0222)
3902 && (attribute & SMB_ATTR_READONLY) != 0) {
3903 /* make a writable file read-only */
3904 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3905 attr.unixModeBits = scp->unixModeBits & ~0222;
3907 else if ((scp->unixModeBits & 0222) == 0
3908 && (attribute & SMB_ATTR_READONLY) == 0) {
3909 /* make a read-only file writable */
3910 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3911 attr.unixModeBits = scp->unixModeBits | 0222;
3914 lock_ReleaseRead(&scp->rw);
3915 lock_ReleaseMutex(&fidp->mx);
3919 code = cm_SetAttr(scp, &attr, userp, &req);
3923 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3924 int delflag = *((char *)(p->datap));
3925 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
3926 delflag, fidp, scp);
3927 if (*((char *)(p->datap))) { /* File is Deleted */
3928 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3931 lock_ObtainMutex(&fidp->mx);
3932 fidp->flags |= SMB_FID_DELONCLOSE;
3933 lock_ReleaseMutex(&fidp->mx);
3935 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
3941 lock_ObtainMutex(&fidp->mx);
3942 fidp->flags &= ~SMB_FID_DELONCLOSE;
3943 lock_ReleaseMutex(&fidp->mx);
3946 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3947 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3948 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3951 attr.mask = CM_ATTRMASK_LENGTH;
3952 attr.length.LowPart = size.LowPart;
3953 attr.length.HighPart = size.HighPart;
3954 code = cm_SetAttr(scp, &attr, userp, &req);
3958 cm_ReleaseSCache(scp);
3959 cm_ReleaseUser(userp);
3960 smb_ReleaseFID(fidp);
3962 smb_SendTran2Packet(vcp, outp, opx);
3964 smb_SendTran2Error(vcp, p, opx, code);
3965 smb_FreeTran2Packet(outp);
3972 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3974 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3975 return CM_ERROR_BADOP;
3980 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3982 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3983 return CM_ERROR_BADOP;
3986 /* TRANS2_FIND_NOTIFY_FIRST */
3988 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3990 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3991 return CM_ERROR_BADOP;
3994 /* TRANS2_FIND_NOTIFY_NEXT */
3996 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3998 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3999 return CM_ERROR_BADOP;
4002 /* TRANS2_CREATE_DIRECTORY */
4004 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4006 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
4007 return CM_ERROR_BADOP;
4010 /* TRANS2_SESSION_SETUP */
4012 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4014 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
4015 return CM_ERROR_BADOP;
4018 struct smb_v2_referral {
4020 USHORT ReferralFlags;
4023 USHORT DfsPathOffset;
4024 USHORT DfsAlternativePathOffset;
4025 USHORT NetworkAddressOffset;
4028 /* TRANS2_GET_DFS_REFERRAL */
4030 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
4032 /* This is a UNICODE only request (bit15 of Flags2) */
4033 /* The TID must be IPC$ */
4035 /* The documentation for the Flags response field is contradictory */
4037 /* Use Version 1 Referral Element Format */
4038 /* ServerType = 0; indicates the next server should be queried for the file */
4039 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
4040 /* Node = UnicodeString of UNC path of the next share name */
4043 int maxReferralLevel = 0;
4044 clientchar_t requestFileName[1024] = _C("");
4045 clientchar_t referralPath[1024] = _C("");
4046 smb_tran2Packet_t *outp = 0;
4047 cm_user_t *userp = 0;
4048 cm_scache_t *scp = 0;
4049 cm_scache_t *dscp = 0;
4051 CPINFO CodePageInfo;
4052 int i, nbnLen, reqLen, refLen;
4057 maxReferralLevel = p->parmsp[0];
4059 GetCPInfo(CP_ACP, &CodePageInfo);
4060 cm_Utf16ToClientString(&p->parmsp[1], -1, requestFileName, lengthof(requestFileName));
4062 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%S]",
4063 maxReferralLevel, osi_LogSaveClientString(smb_logp, requestFileName));
4065 nbnLen = (int)cm_ClientStrLen(cm_NetbiosNameC);
4066 reqLen = (int)cm_ClientStrLen(requestFileName);
4068 if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
4069 !cm_ClientStrCmpNI(cm_NetbiosNameC, &requestFileName[1], nbnLen) &&
4070 requestFileName[nbnLen+1] == '\\')
4074 if (!cm_ClientStrCmpNI(_C("all"), &requestFileName[nbnLen+2], 3) ||
4075 !cm_ClientStrCmpNI(_C("*."), &requestFileName[nbnLen+2], 2)) {
4077 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4080 userp = smb_GetTran2User(vcp, p);
4082 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
4083 code = CM_ERROR_BADSMB;
4088 * We have a requested path. Check to see if it is something
4091 * But be careful because the name that we might be searching
4092 * for might be a known name with the final character stripped
4095 code = cm_NameI(cm_data.rootSCachep, &requestFileName[nbnLen+2],
4096 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
4097 userp, NULL, &req, &scp);
4099 code == CM_ERROR_ALLDOWN ||
4100 code == CM_ERROR_ALLBUSY ||
4101 code == CM_ERROR_ALLOFFLINE ||
4102 code == CM_ERROR_NOSUCHCELL ||
4103 code == CM_ERROR_NOSUCHVOLUME ||
4104 code == CM_ERROR_NOACCESS) {
4107 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4109 } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
4110 clientchar_t temp[1024];
4111 clientchar_t pathName[1024];
4112 clientchar_t *lastComponent;
4114 * we have a msdfs link somewhere in the path
4115 * we should figure out where in the path the link is.
4118 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%S]", requestFileName);
4120 cm_ClientStrCpy(temp, lengthof(temp), &requestFileName[nbnLen+2]);
4124 cm_ReleaseSCache(dscp);
4128 cm_ReleaseSCache(scp);
4131 smb_StripLastComponent(pathName, &lastComponent, temp);
4133 code = cm_NameI(cm_data.rootSCachep, pathName,
4134 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4135 userp, NULL, &req, &dscp);
4137 code = cm_NameI(dscp, ++lastComponent,
4139 userp, NULL, &req, &scp);
4140 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK)
4143 } while (code == CM_ERROR_PATH_NOT_COVERED);
4145 /* scp should now be the DfsLink we are looking for */
4147 /* figure out how much of the input path was used */
4148 reqLen = (int)(nbnLen+2 + cm_ClientStrLen(pathName) + 1 + cm_ClientStrLen(lastComponent));
4150 cm_FsStringToClientString(&scp->mountPointStringp[strlen("msdfs:")], -1,
4151 referralPath, lengthof(referralPath));
4152 refLen = (int)cm_ClientStrLen(referralPath);
4156 clientchar_t shareName[MAX_PATH + 1];
4157 clientchar_t *p, *q;
4158 /* we may have a sharename that is a volume reference */
4160 for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
4166 if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
4167 code = cm_NameI(cm_data.rootSCachep, _C(""),
4168 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
4169 userp, p, &req, &scp);
4174 cm_ClientStrCpy(referralPath, lengthof(referralPath),
4185 struct smb_v2_referral * v2ref;
4186 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (refLen + 8));
4188 sp = (USHORT *)outp->datap;
4190 sp[idx++] = reqLen; /* path consumed */
4191 sp[idx++] = 1; /* number of referrals */
4192 sp[idx++] = 0x03; /* flags */
4193 #ifdef DFS_VERSION_1
4194 sp[idx++] = 1; /* Version Number */
4195 sp[idx++] = refLen + 4; /* Referral Size */
4196 sp[idx++] = 1; /* Type = SMB Server */
4197 sp[idx++] = 0; /* Do not strip path consumed */
4198 for ( i=0;i<=refLen; i++ )
4199 sp[i+idx] = referralPath[i];
4200 #else /* DFS_VERSION_2 */
4201 sp[idx++] = 2; /* Version Number */
4202 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
4203 idx += (sizeof(struct smb_v2_referral) / 2);
4204 v2ref = (struct smb_v2_referral *) &sp[5];
4205 v2ref->ServerType = 1; /* SMB Server */
4206 v2ref->ReferralFlags = 0x03;
4207 v2ref->Proximity = 0; /* closest */
4208 v2ref->TimeToLive = 3600; /* seconds */
4209 v2ref->DfsPathOffset = idx * 2;
4210 v2ref->DfsAlternativePathOffset = idx * 2;
4211 v2ref->NetworkAddressOffset = 0;
4212 for ( i=0;i<=refLen; i++ )
4213 sp[i+idx] = referralPath[i];
4216 code = CM_ERROR_NOSUCHPATH;
4219 code = CM_ERROR_NOSUCHPATH;
4224 cm_ReleaseSCache(dscp);
4226 cm_ReleaseSCache(scp);
4228 cm_ReleaseUser(userp);
4230 smb_SendTran2Packet(vcp, outp, op);
4232 smb_SendTran2Error(vcp, p, op, code);
4234 smb_FreeTran2Packet(outp);
4237 #else /* DFS_SUPPORT */
4238 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
4239 return CM_ERROR_NOSUCHDEVICE;
4240 #endif /* DFS_SUPPORT */
4243 /* TRANS2_REPORT_DFS_INCONSISTENCY */
4245 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4247 /* This is a UNICODE only request (bit15 of Flags2) */
4249 /* There is nothing we can do about this operation. The client is going to
4250 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
4251 * Unfortunately, there is really nothing we can do about it other then log it
4252 * somewhere. Even then I don't think there is anything for us to do.
4253 * So let's return an error value.
4256 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
4257 return CM_ERROR_BADOP;
4261 smb_ApplyV3DirListPatches(cm_scache_t *dscp, smb_dirListPatch_t **dirPatchespp,
4262 clientchar_t * tidPathp, clientchar_t * relPathp,
4263 int infoLevel, cm_user_t *userp, cm_req_t *reqp)
4267 cm_scache_t *targetScp; /* target if scp is a symlink */
4270 unsigned short attr;
4271 unsigned long lattr;
4272 smb_dirListPatch_t *patchp;
4273 smb_dirListPatch_t *npatchp;
4275 afs_int32 mustFake = 0;
4276 clientchar_t path[AFSPATHMAX];
4278 code = cm_FindACLCache(dscp, userp, &rights);
4280 lock_ObtainWrite(&dscp->rw);
4281 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4282 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4284 cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4285 lock_ReleaseWrite(&dscp->rw);
4286 if (code == CM_ERROR_NOACCESS) {
4294 if (!mustFake) { /* Bulk Stat */
4296 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4298 memset(bsp, 0, sizeof(cm_bulkStat_t));
4300 for (patchp = *dirPatchespp, count=0;
4302 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4303 cm_scache_t *tscp = NULL;
4306 code = cm_GetSCache(&patchp->fid, &tscp, userp, reqp);
4308 if (lock_TryWrite(&tscp->rw)) {
4309 /* we have an entry that we can look at */
4310 #ifdef AFS_FREELANCE_CLIENT
4311 if (dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID && dscp->fid.volume == AFS_FAKE_ROOT_VOL_ID) {
4312 code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
4313 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4315 cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4317 lock_ReleaseWrite(&tscp->rw);
4318 cm_ReleaseSCache(tscp);
4321 #endif /* AFS_FREELANCE_CLIENT */
4322 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4323 /* we have a callback on it. Don't bother
4324 * fetching this stat entry, since we're happy
4325 * with the info we have.
4327 lock_ReleaseWrite(&tscp->rw);
4328 cm_ReleaseSCache(tscp);
4331 lock_ReleaseWrite(&tscp->rw);
4333 cm_ReleaseSCache(tscp);
4337 bsp->fids[i].Volume = patchp->fid.volume;
4338 bsp->fids[i].Vnode = patchp->fid.vnode;
4339 bsp->fids[i].Unique = patchp->fid.unique;
4341 if (bsp->counter == AFSCBMAX) {
4342 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4343 memset(bsp, 0, sizeof(cm_bulkStat_t));
4347 if (bsp->counter > 0)
4348 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4353 for( patchp = *dirPatchespp;
4355 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4356 cm_ClientStrPrintfN(path, lengthof(path),_C("%s\\%S"),
4357 relPathp ? relPathp : _C(""), patchp->dep->name);
4358 reqp->relPathp = path;
4359 reqp->tidPathp = tidPathp;
4361 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4362 reqp->relPathp = reqp->tidPathp = NULL;
4366 lock_ObtainWrite(&scp->rw);
4367 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4368 lock_ReleaseWrite(&scp->rw);
4370 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4371 errors in the client. */
4372 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4373 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4375 /* 1969-12-31 23:59:59 +00 */
4376 ft.dwHighDateTime = 0x19DB200;
4377 ft.dwLowDateTime = 0x5BB78980;
4379 /* copy to Creation Time */
4380 fa->creationTime = ft;
4381 fa->lastAccessTime = ft;
4382 fa->lastWriteTime = ft;
4383 fa->lastChangeTime = ft;
4385 switch (scp->fileType) {
4386 case CM_SCACHETYPE_DIRECTORY:
4387 case CM_SCACHETYPE_MOUNTPOINT:
4388 case CM_SCACHETYPE_INVALID:
4389 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4391 case CM_SCACHETYPE_SYMLINK:
4392 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4393 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4395 fa->extFileAttributes = SMB_ATTR_NORMAL;
4398 /* if we get here we either have a normal file
4399 * or we have a file for which we have never
4400 * received status info. In this case, we can
4401 * check the even/odd value of the entry's vnode.
4402 * odd means it is to be treated as a directory
4403 * and even means it is to be treated as a file.
4405 if (mustFake && (scp->fid.vnode & 0x1))
4406 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4408 fa->extFileAttributes = SMB_ATTR_NORMAL;
4410 /* merge in hidden attribute */
4411 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4412 fa->extFileAttributes |= SMB_ATTR_HIDDEN;
4415 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4417 /* 1969-12-31 23:59:58 +00*/
4418 dosTime = 0xEBBFBF7D;
4420 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4421 fa->lastAccessDateTime = fa->creationDateTime;
4422 fa->lastWriteDateTime = fa->creationDateTime;
4424 /* set the attribute */
4425 switch (scp->fileType) {
4426 case CM_SCACHETYPE_DIRECTORY:
4427 case CM_SCACHETYPE_MOUNTPOINT:
4428 case CM_SCACHETYPE_INVALID:
4429 fa->attributes = SMB_ATTR_DIRECTORY;
4431 case CM_SCACHETYPE_SYMLINK:
4432 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4433 fa->attributes = SMB_ATTR_DIRECTORY;
4435 fa->attributes = SMB_ATTR_NORMAL;
4438 /* if we get here we either have a normal file
4439 * or we have a file for which we have never
4440 * received status info. In this case, we can
4441 * check the even/odd value of the entry's vnode.
4442 * even means it is to be treated as a directory
4443 * and odd means it is to be treated as a file.
4445 if (mustFake && (scp->fid.vnode & 0x1))
4446 fa->attributes = SMB_ATTR_DIRECTORY;
4448 fa->attributes = SMB_ATTR_NORMAL;
4451 /* merge in hidden (dot file) attribute */
4452 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4453 fa->attributes |= SMB_ATTR_HIDDEN;
4457 cm_ReleaseSCache(scp);
4461 /* now watch for a symlink */
4463 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
4464 lock_ReleaseWrite(&scp->rw);
4465 cm_ClientStrPrintfN(path, lengthof(path), _C("%s\\%S"),
4466 relPathp ? relPathp : _C(""), patchp->dep->name);
4467 reqp->relPathp = path;
4468 reqp->tidPathp = tidPathp;
4469 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
4470 reqp->relPathp = reqp->tidPathp = NULL;
4472 /* we have a more accurate file to use (the
4473 * target of the symbolic link). Otherwise,
4474 * we'll just use the symlink anyway.
4476 osi_Log2(smb_logp, "symlink vp %x to vp %x",
4478 cm_ReleaseSCache(scp);
4481 lock_ObtainWrite(&scp->rw);
4484 lock_ConvertWToR(&scp->rw);
4486 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4487 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4490 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4492 fa->creationTime = ft;
4493 fa->lastAccessTime = ft;
4494 fa->lastWriteTime = ft;
4495 fa->lastChangeTime = ft;
4497 /* Use length for both file length and alloc length */
4498 fa->endOfFile = scp->length;
4499 fa->allocationSize = scp->length;
4501 /* Copy attributes */
4502 lattr = smb_ExtAttributes(scp);
4503 if ((code == CM_ERROR_NOSUCHPATH &&
4504 (scp->fileType == CM_SCACHETYPE_SYMLINK &&
4505 cm_TargetPerceivedAsDirectory(scp->mountPointStringp))) ||
4506 code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4507 if (lattr == SMB_ATTR_NORMAL)
4508 lattr = SMB_ATTR_DIRECTORY;
4510 lattr |= SMB_ATTR_DIRECTORY;
4512 /* merge in hidden (dot file) attribute */
4513 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4514 if (lattr == SMB_ATTR_NORMAL)
4515 lattr = SMB_ATTR_HIDDEN;
4517 lattr |= SMB_ATTR_HIDDEN;
4520 fa->extFileAttributes = lattr;
4522 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4525 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4527 fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
4528 fa->lastAccessDateTime = fa->creationDateTime;
4529 fa->lastWriteDateTime = fa->creationDateTime;
4531 /* copy out file length and alloc length,
4532 * using the same for both
4534 fa->dataSize = scp->length.LowPart;
4535 fa->allocationSize = scp->length.LowPart;
4537 /* finally copy out attributes as short */
4538 attr = smb_Attributes(scp);
4539 /* merge in hidden (dot file) attribute */
4540 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4541 if (lattr == SMB_ATTR_NORMAL)
4542 lattr = SMB_ATTR_HIDDEN;
4544 lattr |= SMB_ATTR_HIDDEN;
4546 fa->attributes = attr;
4549 lock_ReleaseRead(&scp->rw);
4550 cm_ReleaseSCache(scp);
4553 /* now free the patches */
4554 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4555 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4559 /* and mark the list as empty */
4560 *dirPatchespp = NULL;
4566 /* smb_ReceiveTran2SearchDir implements both
4567 * Tran2_Find_First and Tran2_Find_Next
4569 #define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
4570 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
4571 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
4572 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
4573 #define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
4575 /* this is an optimized handler for T2SearchDir that handles the case
4576 where there are no wildcards in the search path. I.e. an
4577 application is using FindFirst(Ex) to get information about a
4578 single file or directory. It will attempt to do a single lookup.
4579 If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4580 the usual mechanism.
4582 This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4584 TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
4586 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4590 long code = 0, code2 = 0;
4591 clientchar_t *pathp = 0;
4593 smb_dirListPatch_t *dirListPatchesp;
4594 smb_dirListPatch_t *curPatchp;
4595 size_t orbytes; /* # of bytes in this output record */
4596 size_t ohbytes; /* # of bytes, except file name */
4597 size_t onbytes; /* # of bytes in name, incl. term. null */
4598 cm_scache_t *scp = NULL;
4599 cm_scache_t *targetscp = NULL;
4600 cm_user_t *userp = NULL;
4601 char *op; /* output data ptr */
4602 char *origOp; /* original value of op */
4603 cm_space_t *spacep; /* for pathname buffer */
4604 unsigned long maxReturnData; /* max # of return data */
4605 long maxReturnParms; /* max # of return parms */
4606 long bytesInBuffer; /* # data bytes in the output buffer */
4607 clientchar_t *maskp; /* mask part of path */
4611 smb_tran2Packet_t *outp; /* response packet */
4612 clientchar_t *tidPathp = 0;
4614 clientchar_t shortName[13]; /* 8.3 name if needed */
4616 clientchar_t *shortNameEnd;
4617 cm_dirEntry_t * dep = NULL;
4620 void * attrp = NULL;
4621 smb_tran2Find_t * fp;
4626 osi_assertx(p->opcode == 1, "invalid opcode");
4628 /* find first; obtain basic parameters from request */
4630 /* note that since we are going to failover to regular
4631 * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4632 * modify any of the input parameters here. */
4633 attribute = p->parmsp[0];
4634 maxCount = p->parmsp[1];
4635 infoLevel = p->parmsp[3];
4636 searchFlags = p->parmsp[2];
4637 pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4639 maskp = cm_ClientStrRChr(pathp, '\\');
4643 maskp++; /* skip over backslash */
4644 /* track if this is likely to match a lot of entries */
4646 osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%S], mask[%S]",
4647 osi_LogSaveClientString(smb_logp, pathp),
4648 osi_LogSaveClientString(smb_logp, maskp));
4650 switch ( infoLevel ) {
4651 case SMB_INFO_STANDARD:
4653 ohbytes = sizeof(fp->u.FstandardInfo);
4656 case SMB_INFO_QUERY_EA_SIZE:
4657 ohbytes = sizeof(fp->u.FeaSizeInfo);
4658 s = "InfoQueryEaSize";
4661 case SMB_INFO_QUERY_EAS_FROM_LIST:
4662 ohbytes = sizeof(fp->u.FeasFromListInfo);
4663 s = "InfoQueryEasFromList";
4666 case SMB_FIND_FILE_DIRECTORY_INFO:
4667 s = "FindFileDirectoryInfo";
4668 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4671 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4672 s = "FindFileFullDirectoryInfo";
4673 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4676 case SMB_FIND_FILE_NAMES_INFO:
4677 s = "FindFileNamesInfo";
4678 ohbytes = sizeof(fp->u.FfileNamesInfo);
4681 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4682 s = "FindFileBothDirectoryInfo";
4683 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4687 s = "unknownInfoLevel";
4691 osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
4694 "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4695 attribute, infoLevel, maxCount, searchFlags);
4698 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4699 return CM_ERROR_INVAL;
4702 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4703 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4705 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4708 dirListPatchesp = NULL;
4710 maxReturnData = p->maxReturnData;
4711 maxReturnParms = 10; /* return params for findfirst, which
4712 is the only one we handle.*/
4714 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4717 osi_Log2(smb_logp, "T2SDSingle search dir count %d [%S]",
4718 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4720 /* bail out if request looks bad */
4722 smb_FreeTran2Packet(outp);
4723 return CM_ERROR_BADSMB;
4726 userp = smb_GetTran2User(vcp, p);
4728 osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
4729 smb_FreeTran2Packet(outp);
4730 return CM_ERROR_BADSMB;
4733 /* try to get the vnode for the path name next */
4734 spacep = cm_GetSpace();
4735 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4736 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4738 cm_ReleaseUser(userp);
4739 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4740 smb_FreeTran2Packet(outp);
4744 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4745 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4746 userp, tidPathp, &req, &scp);
4747 cm_FreeSpace(spacep);
4750 cm_ReleaseUser(userp);
4751 smb_SendTran2Error(vcp, p, opx, code);
4752 smb_FreeTran2Packet(outp);
4756 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4757 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4758 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
4759 cm_ReleaseSCache(scp);
4760 cm_ReleaseUser(userp);
4761 if ( WANTS_DFS_PATHNAMES(p) || pnc )
4762 code = CM_ERROR_PATH_NOT_COVERED;
4764 code = CM_ERROR_NOSUCHPATH;
4765 smb_SendTran2Error(vcp, p, opx, code);
4766 smb_FreeTran2Packet(outp);
4769 #endif /* DFS_SUPPORT */
4770 osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
4772 /* now do a single case sensitive lookup for the file in question */
4773 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
4775 /* if a case sensitive match failed, we try a case insensitive one
4777 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
4778 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
4781 if (code == 0 && targetscp->fid.vnode == 0) {
4782 cm_ReleaseSCache(targetscp);
4783 code = CM_ERROR_NOSUCHFILE;
4787 /* if we can't find the directory entry, this block will
4788 return CM_ERROR_NOSUCHFILE, which we will pass on to
4789 smb_ReceiveTran2SearchDir(). */
4790 cm_ReleaseSCache(scp);
4791 cm_ReleaseUser(userp);
4792 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4793 smb_SendTran2Error(vcp, p, opx, code);
4796 smb_FreeTran2Packet(outp);
4800 /* now that we have the target in sight, we proceed with filling
4801 up the return data. */
4803 op = origOp = outp->datap;
4806 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4807 /* skip over resume key */
4811 fp = (smb_tran2Find_t *) op;
4813 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4814 && targetscp->fid.vnode != 0
4815 && !cm_Is8Dot3(maskp)) {
4818 dfid.vnode = htonl(targetscp->fid.vnode);
4819 dfid.unique = htonl(targetscp->fid.unique);
4821 cm_Gen8Dot3NameIntW(maskp, &dfid, shortName, &shortNameEnd);
4827 osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %S (%S)",
4828 htonl(targetscp->fid.vnode),
4829 htonl(targetscp->fid.unique),
4830 osi_LogSaveClientString(smb_logp, pathp),
4831 (NeedShortName)? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
4833 /* Eliminate entries that don't match requested attributes */
4834 if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
4835 smb_IsDotFile(maskp)) {
4837 code = CM_ERROR_NOSUCHFILE;
4838 osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
4843 if (!(attribute & SMB_ATTR_DIRECTORY) &&
4844 (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
4845 targetscp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4846 targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
4847 targetscp->fileType == CM_SCACHETYPE_INVALID)) {
4849 code = CM_ERROR_NOSUCHFILE;
4850 osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
4855 /* add header to name & term. null */
4857 smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
4858 orbytes = ohbytes + onbytes;
4860 /* now, we round up the record to a 4 byte alignment, and we make
4861 * sure that we have enough room here for even the aligned version
4862 * (so we don't have to worry about an * overflow when we pad
4863 * things out below). That's the reason for the alignment
4866 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4867 align = (4 - (orbytes & 3)) & 3;
4871 if (orbytes + align > maxReturnData) {
4873 /* even though this request is unlikely to succeed with a
4874 failover, we do it anyway. */
4875 code = CM_ERROR_NOSUCHFILE;
4876 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4881 /* this is one of the entries to use: it is not deleted and it
4882 * matches the star pattern we're looking for. Put out the name,
4883 * preceded by its length.
4885 /* First zero everything else */
4886 memset(origOp, 0, orbytes);
4889 smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
4891 switch (infoLevel) {
4892 case SMB_INFO_STANDARD:
4893 fp->u.FstandardInfo.fileNameLength = onbytes;
4894 attrp = &fp->u.FstandardInfo.fileAttrs;
4897 case SMB_INFO_QUERY_EA_SIZE:
4898 fp->u.FeaSizeInfo.fileNameLength = onbytes;
4899 attrp = &fp->u.FeaSizeInfo.fileAttrs;
4900 fp->u.FeaSizeInfo.eaSize = 0;
4903 case SMB_INFO_QUERY_EAS_FROM_LIST:
4904 fp->u.FeasFromListInfo.fileNameLength = onbytes;
4905 attrp = &fp->u.FeasFromListInfo.fileAttrs;
4906 fp->u.FeasFromListInfo.eaSize = 0;
4909 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4910 if (NeedShortName) {
4914 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
4915 fp->u.FfileBothDirectoryInfo.shortName,
4916 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
4918 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
4920 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
4921 fp->u.FfileBothDirectoryInfo.reserved = 0;
4923 strcpy(fp->u.FfileBothDirectoryInfo.shortName,
4925 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
4930 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4931 fp->u.FfileFullDirectoryInfo.eaSize = 0;
4934 case SMB_FIND_FILE_DIRECTORY_INFO:
4935 fp->u.FfileDirectoryInfo.nextEntryOffset = 0;
4936 fp->u.FfileDirectoryInfo.fileIndex = 0;
4937 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
4938 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
4941 case SMB_FIND_FILE_NAMES_INFO:
4942 fp->u.FfileNamesInfo.nextEntryOffset = 0;
4943 fp->u.FfileNamesInfo.fileIndex = 0;
4944 fp->u.FfileNamesInfo.fileNameLength = onbytes;
4948 /* we shouldn't hit this case */
4949 osi_assertx(FALSE, "Unknown query type");
4952 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4953 osi_assert(attrp != NULL);
4955 curPatchp = malloc(sizeof(*curPatchp));
4956 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4958 curPatchp->dptr = attrp;
4960 if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
4961 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4963 curPatchp->flags = 0;
4966 cm_SetFid(&curPatchp->fid, targetscp->fid.cell, targetscp->fid.volume, targetscp->fid.vnode, targetscp->fid.unique);
4970 int namelen = cm_ClientStringToFsString(maskp, -1, NULL, 0);
4971 dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+namelen);
4972 cm_ClientStringToFsString(maskp, -1, dep->name, namelen);
4974 dep->fid.vnode = targetscp->fid.vnode;
4975 dep->fid.unique = targetscp->fid.unique;
4976 curPatchp->dep = dep;
4979 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4980 /* put out resume key */
4981 *((u_long *)origOp) = 0;
4984 /* Adjust byte ptr and count */
4985 origOp += orbytes; /* skip entire record */
4986 bytesInBuffer += orbytes;
4988 /* and pad the record out */
4989 while (--align >= 0) {
4994 /* apply the patches */
4995 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->wdata, infoLevel, userp, &req);
4997 outp->parmsp[0] = 0;
4998 outp->parmsp[1] = 1; /* number of names returned */
4999 outp->parmsp[2] = 1; /* end of search */
5000 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5001 outp->parmsp[4] = 0;
5003 outp->totalParms = 10; /* in bytes */
5005 outp->totalData = bytesInBuffer;
5007 osi_Log0(smb_logp, "T2SDSingle done.");
5009 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5011 smb_SendTran2Error(vcp, p, opx, code);
5013 smb_SendTran2Packet(vcp, outp, opx);
5018 smb_FreeTran2Packet(outp);
5022 cm_ReleaseSCache(scp);
5023 cm_ReleaseSCache(targetscp);
5024 cm_ReleaseUser(userp);
5030 /* TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2 */
5031 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
5036 long code = 0, code2 = 0;
5037 clientchar_t *pathp;
5038 cm_dirEntry_t *dep = 0;
5040 smb_dirListPatch_t *dirListPatchesp = 0;
5041 smb_dirListPatch_t *curPatchp = 0;
5044 size_t orbytes; /* # of bytes in this output record */
5045 size_t ohbytes; /* # of bytes, except file name */
5046 size_t onbytes; /* # of bytes in name, incl. term. null */
5047 osi_hyper_t dirLength;
5048 osi_hyper_t bufferOffset;
5049 osi_hyper_t curOffset;
5051 smb_dirSearch_t *dsp;
5055 cm_pageHeader_t *pageHeaderp;
5056 cm_user_t *userp = NULL;
5059 long nextEntryCookie;
5060 int numDirChunks; /* # of 32 byte dir chunks in this entry */
5061 char *op; /* output data ptr */
5062 char *origOp; /* original value of op */
5063 cm_space_t *spacep; /* for pathname buffer */
5064 unsigned long maxReturnData; /* max # of return data */
5065 unsigned long maxReturnParms; /* max # of return parms */
5066 long bytesInBuffer; /* # data bytes in the output buffer */
5068 clientchar_t *maskp; /* mask part of path */
5072 smb_tran2Packet_t *outp; /* response packet */
5073 clientchar_t *tidPathp;
5075 clientchar_t shortName[13]; /* 8.3 name if needed */
5078 clientchar_t *shortNameEnd;
5084 smb_tran2Find_t * fp;
5089 if (p->opcode == 1) {
5090 /* find first; obtain basic parameters from request */
5091 attribute = p->parmsp[0];
5092 maxCount = p->parmsp[1];
5093 infoLevel = p->parmsp[3];
5094 searchFlags = p->parmsp[2];
5095 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
5097 maskp = cm_ClientStrRChr(pathp, '\\');
5101 maskp++; /* skip over backslash */
5103 /* track if this is likely to match a lot of entries */
5104 starPattern = smb_V3IsStarMask(maskp);
5106 #ifndef NOFINDFIRSTOPTIMIZE
5108 /* if this is for a single directory or file, we let the
5109 optimized routine handle it. The only error it
5110 returns is CM_ERROR_NOSUCHFILE. The */
5111 code = smb_T2SearchDirSingle(vcp, p, opx);
5113 /* we only failover if we see a CM_ERROR_NOSUCHFILE */
5114 if (code != CM_ERROR_NOSUCHFILE) {
5116 /* unless we are using the BPlusTree */
5117 if (code == CM_ERROR_BPLUS_NOMATCH)
5118 code = CM_ERROR_NOSUCHFILE;
5119 #endif /* USE_BPLUS */
5123 #endif /* NOFINDFIRSTOPTIMIZE */
5126 dsp = smb_NewDirSearch(1);
5127 dsp->attribute = attribute;
5128 cm_ClientStrCpy(dsp->mask, lengthof(dsp->mask), maskp); /* and save mask */
5131 osi_assertx(p->opcode == 2, "invalid opcode");
5132 /* find next; obtain basic parameters from request or open dir file */
5133 dsp = smb_FindDirSearch(p->parmsp[0]);
5134 maxCount = p->parmsp[1];
5135 infoLevel = p->parmsp[2];
5136 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
5137 searchFlags = p->parmsp[5];
5139 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
5140 p->parmsp[0], nextCookie);
5141 return CM_ERROR_BADFD;
5143 attribute = dsp->attribute;
5146 starPattern = 1; /* assume, since required a Find Next */
5149 switch ( infoLevel ) {
5150 case SMB_INFO_STANDARD:
5152 ohbytes = sizeof(fp->u.FstandardInfo);
5155 case SMB_INFO_QUERY_EA_SIZE:
5156 ohbytes = sizeof(fp->u.FeaSizeInfo);
5157 s = "InfoQueryEaSize";
5160 case SMB_INFO_QUERY_EAS_FROM_LIST:
5161 ohbytes = sizeof(fp->u.FeasFromListInfo);
5162 s = "InfoQueryEasFromList";
5165 case SMB_FIND_FILE_DIRECTORY_INFO:
5166 s = "FindFileDirectoryInfo";
5167 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
5170 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5171 s = "FindFileFullDirectoryInfo";
5172 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
5175 case SMB_FIND_FILE_NAMES_INFO:
5176 s = "FindFileNamesInfo";
5177 ohbytes = sizeof(fp->u.FfileNamesInfo);
5180 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5181 s = "FindFileBothDirectoryInfo";
5182 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
5186 s = "unknownInfoLevel";
5190 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
5193 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
5194 attribute, infoLevel, maxCount, searchFlags);
5196 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
5197 p->opcode, dsp->cookie, nextCookie);
5200 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
5201 smb_ReleaseDirSearch(dsp);
5202 return CM_ERROR_INVAL;
5205 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5206 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
5208 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5211 dirListPatchesp = NULL;
5213 maxReturnData = p->maxReturnData;
5214 if (p->opcode == 1) /* find first */
5215 maxReturnParms = 10; /* bytes */
5217 maxReturnParms = 8; /* bytes */
5219 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
5225 osi_Log2(smb_logp, "T2 receive search dir count %d [%S]",
5226 maxCount, osi_LogSaveClientString(smb_logp, pathp));
5228 /* bail out if request looks bad */
5229 if (p->opcode == 1 && !pathp) {
5230 smb_ReleaseDirSearch(dsp);
5231 smb_FreeTran2Packet(outp);
5232 return CM_ERROR_BADSMB;
5235 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
5236 dsp->cookie, nextCookie, attribute);
5238 userp = smb_GetTran2User(vcp, p);
5240 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
5241 smb_ReleaseDirSearch(dsp);
5242 smb_FreeTran2Packet(outp);
5243 return CM_ERROR_BADSMB;
5246 /* try to get the vnode for the path name next */
5247 lock_ObtainMutex(&dsp->mx);
5250 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5254 spacep = cm_GetSpace();
5255 smb_StripLastComponent(spacep->wdata, NULL, pathp);
5256 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
5258 cm_ReleaseUser(userp);
5259 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
5260 smb_FreeTran2Packet(outp);
5261 lock_ReleaseMutex(&dsp->mx);
5262 smb_DeleteDirSearch(dsp);
5263 smb_ReleaseDirSearch(dsp);
5267 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
5268 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
5270 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
5271 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5272 userp, tidPathp, &req, &scp);
5273 cm_FreeSpace(spacep);
5276 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
5277 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5278 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
5279 cm_ReleaseSCache(scp);
5280 cm_ReleaseUser(userp);
5281 if ( WANTS_DFS_PATHNAMES(p) || pnc )
5282 code = CM_ERROR_PATH_NOT_COVERED;
5284 code = CM_ERROR_NOSUCHPATH;
5285 smb_SendTran2Error(vcp, p, opx, code);
5286 smb_FreeTran2Packet(outp);
5287 lock_ReleaseMutex(&dsp->mx);
5288 smb_DeleteDirSearch(dsp);
5289 smb_ReleaseDirSearch(dsp);
5292 #endif /* DFS_SUPPORT */
5294 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5295 /* we need one hold for the entry we just stored into,
5296 * and one for our own processing. When we're done
5297 * with this function, we'll drop the one for our own
5298 * processing. We held it once from the namei call,
5299 * and so we do another hold now.
5302 dsp->flags |= SMB_DIRSEARCH_BULKST;
5305 lock_ReleaseMutex(&dsp->mx);
5307 cm_ReleaseUser(userp);
5308 smb_FreeTran2Packet(outp);
5309 smb_DeleteDirSearch(dsp);
5310 smb_ReleaseDirSearch(dsp);
5314 /* get the directory size */
5315 lock_ObtainWrite(&scp->rw);
5316 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5317 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5319 lock_ReleaseWrite(&scp->rw);
5320 cm_ReleaseSCache(scp);
5321 cm_ReleaseUser(userp);
5322 smb_FreeTran2Packet(outp);
5323 smb_DeleteDirSearch(dsp);
5324 smb_ReleaseDirSearch(dsp);
5328 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5331 dirLength = scp->length;
5333 bufferOffset.LowPart = bufferOffset.HighPart = 0;
5334 curOffset.HighPart = 0;
5335 curOffset.LowPart = nextCookie;
5336 origOp = outp->datap;
5343 normchar_t normName[MAX_PATH]; /* Normalized name */
5344 clientchar_t cfileName[MAX_PATH]; /* Non-normalized name */
5347 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5348 /* skip over resume key */
5351 fp = (smb_tran2Find_t *) op;
5353 /* make sure that curOffset.LowPart doesn't point to the first
5354 * 32 bytes in the 2nd through last dir page, and that it doesn't
5355 * point at the first 13 32-byte chunks in the first dir page,
5356 * since those are dir and page headers, and don't contain useful
5359 temp = curOffset.LowPart & (2048-1);
5360 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5361 /* we're in the first page */
5362 if (temp < 13*32) temp = 13*32;
5365 /* we're in a later dir page */
5366 if (temp < 32) temp = 32;
5369 /* make sure the low order 5 bits are zero */
5372 /* now put temp bits back ito curOffset.LowPart */
5373 curOffset.LowPart &= ~(2048-1);
5374 curOffset.LowPart |= temp;
5376 /* check if we've passed the dir's EOF */
5377 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
5378 osi_Log0(smb_logp, "T2 search dir passed eof");
5383 /* check if we've returned all the names that will fit in the
5384 * response packet; we check return count as well as the number
5385 * of bytes requested. We check the # of bytes after we find
5386 * the dir entry, since we'll need to check its size.
5388 if (returnedNames >= maxCount) {
5389 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
5390 returnedNames, maxCount);
5394 /* when we have obtained as many entries as can be processed in
5395 * a single Bulk Status call to the file server, apply the dir listing
5398 if (returnedNames > 0 && returnedNames % AFSCBMAX == 0) {
5399 lock_ReleaseWrite(&scp->rw);
5400 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5401 dsp->relPath, infoLevel, userp, &req);
5402 lock_ObtainWrite(&scp->rw);
5404 /* Then check to see if we have time left to process more entries */
5405 if (GetTickCount() - req.startTime > (RDRtimeout - 15) * 1000) {
5406 osi_Log0(smb_logp, "T2 search dir RDRtimeout exceeded");
5410 /* see if we can use the bufferp we have now; compute in which
5411 * page the current offset would be, and check whether that's
5412 * the offset of the buffer we have. If not, get the buffer.
5414 thyper.HighPart = curOffset.HighPart;
5415 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5416 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5419 buf_Release(bufferp);
5422 lock_ReleaseWrite(&scp->rw);
5423 code = buf_Get(scp, &thyper, &req, &bufferp);
5424 lock_ObtainWrite(&scp->rw);
5426 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
5430 bufferOffset = thyper;
5432 /* now get the data in the cache */
5434 code = cm_SyncOp(scp, bufferp, userp, &req,
5436 CM_SCACHESYNC_NEEDCALLBACK
5437 | CM_SCACHESYNC_READ);
5439 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5443 if (cm_HaveBuffer(scp, bufferp, 0)) {
5444 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5445 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5449 /* otherwise, load the buffer and try again */
5450 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5452 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5454 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5455 scp, bufferp, code);
5460 buf_Release(bufferp);
5464 } /* if (wrong buffer) ... */
5466 /* now we have the buffer containing the entry we're interested
5467 * in; copy it out if it represents a non-deleted entry.
5469 entryInDir = curOffset.LowPart & (2048-1);
5470 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5472 /* page header will help tell us which entries are free. Page
5473 * header can change more often than once per buffer, since
5474 * AFS 3 dir page size may be less than (but not more than)
5475 * a buffer package buffer.
5477 /* only look intra-buffer */
5478 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5479 temp &= ~(2048 - 1); /* turn off intra-page bits */
5480 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5482 /* now determine which entry we're looking at in the page.
5483 * If it is free (there's a free bitmap at the start of the
5484 * dir), we should skip these 32 bytes.
5486 slotInPage = (entryInDir & 0x7e0) >> 5;
5487 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5488 (1 << (slotInPage & 0x7)))) {
5489 /* this entry is free */
5490 numDirChunks = 1; /* only skip this guy */
5494 tp = bufferp->datap + entryInBuffer;
5495 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5497 /* while we're here, compute the next entry's location, too,
5498 * since we'll need it when writing out the cookie into the dir
5501 * XXXX Probably should do more sanity checking.
5503 numDirChunks = cm_NameEntries(dep->name, &onbytes);
5505 /* compute offset of cookie representing next entry */
5506 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5508 if (dep->fid.vnode == 0)
5509 goto nextEntry; /* This entry is not in use */
5511 if (cm_FsStringToClientString(dep->name, -1, cfileName, lengthof(cfileName)) == 0 ||
5512 cm_ClientStringToNormString(cfileName, -1, normName, lengthof(normName)) == 0) {
5514 osi_Log1(smb_logp, "Skipping entry [%s]. Can't convert or normalize FS String",
5515 osi_LogSaveString(smb_logp, dep->name));
5519 /* Need 8.3 name? */
5521 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
5522 !cm_Is8Dot3(cfileName)) {
5523 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5527 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %S (%S)",
5528 dep->fid.vnode, dep->fid.unique,
5529 osi_LogSaveClientString(smb_logp, cfileName),
5530 NeedShortName ? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
5532 /* When matching, we are using doing a case fold if we have a wildcard mask.
5533 * If we get a non-wildcard match, it's a lookup for a specific file.
5535 if (cm_MatchMask(normName, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5536 (NeedShortName && cm_MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))
5538 /* Eliminate entries that don't match requested attributes */
5539 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5540 smb_IsDotFile(cfileName)) {
5541 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5542 goto nextEntry; /* no hidden files */
5545 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5547 /* We have already done the cm_TryBulkStat above */
5548 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume,
5549 ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5550 fileType = cm_FindFileType(&fid);
5551 /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5552 * "has filetype %d", dep->name, fileType);
5554 if ( fileType == CM_SCACHETYPE_DIRECTORY ||
5555 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5556 fileType == CM_SCACHETYPE_DFSLINK ||
5557 fileType == CM_SCACHETYPE_INVALID)
5558 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5562 /* finally check if this name will fit */
5564 smb_UnparseString(opx, NULL, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5565 orbytes = ohbytes + onbytes;
5567 /* now, we round up the record to a 4 byte alignment,
5568 * and we make sure that we have enough room here for
5569 * even the aligned version (so we don't have to worry
5570 * about an overflow when we pad things out below).
5571 * That's the reason for the alignment arithmetic below.
5573 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5574 align = (4 - (orbytes & 3)) & 3;
5578 if (orbytes + bytesInBuffer + align > maxReturnData) {
5579 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5584 /* this is one of the entries to use: it is not deleted
5585 * and it matches the star pattern we're looking for.
5586 * Put out the name, preceded by its length.
5588 /* First zero everything else */
5589 memset(origOp, 0, orbytes);
5592 smb_UnparseString(opx, origOp + ohbytes, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5594 switch (infoLevel) {
5595 case SMB_INFO_STANDARD:
5596 fp->u.FstandardInfo.fileNameLength = onbytes;
5597 attrp = &fp->u.FstandardInfo.fileAttrs;
5600 case SMB_INFO_QUERY_EA_SIZE:
5601 fp->u.FeaSizeInfo.fileNameLength = onbytes;
5602 attrp = &fp->u.FeaSizeInfo.fileAttrs;
5603 fp->u.FeaSizeInfo.eaSize = 0;
5606 case SMB_INFO_QUERY_EAS_FROM_LIST:
5607 fp->u.FeasFromListInfo.fileNameLength = onbytes;
5608 attrp = &fp->u.FeasFromListInfo.fileAttrs;
5609 fp->u.FeasFromListInfo.eaSize = 0;
5612 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5613 if (NeedShortName) {
5617 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
5618 fp->u.FfileBothDirectoryInfo.shortName,
5619 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
5621 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
5623 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5624 fp->u.FfileBothDirectoryInfo.reserved = 0;
5626 cm_ClientStrCpy(fp->u.FfileBothDirectoryInfo.shortName,
5627 lengthof(fp->u.FfileBothDirectoryInfo.shortName),
5629 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
5634 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5635 fp->u.FfileFullDirectoryInfo.eaSize = 0;
5638 case SMB_FIND_FILE_DIRECTORY_INFO:
5639 fp->u.FfileDirectoryInfo.nextEntryOffset = orbytes + align;
5640 fp->u.FfileDirectoryInfo.fileIndex = nextEntryCookie;
5641 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5642 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5645 case SMB_FIND_FILE_NAMES_INFO:
5646 fp->u.FfileNamesInfo.nextEntryOffset = orbytes + align;
5647 fp->u.FfileNamesInfo.fileIndex = nextEntryCookie;
5648 fp->u.FfileNamesInfo.fileNameLength = onbytes;
5653 /* we shouldn't hit this case */
5654 osi_assertx(FALSE, "Unknown query type");
5657 /* now, adjust the # of entries copied */
5660 /* now we emit the attribute. This is tricky, since
5661 * we need to really stat the file to find out what
5662 * type of entry we've got. Right now, we're copying
5663 * out data from a buffer, while holding the scp
5664 * locked, so it isn't really convenient to stat
5665 * something now. We'll put in a place holder
5666 * now, and make a second pass before returning this
5667 * to get the real attributes. So, we just skip the
5668 * data for now, and adjust it later. We allocate a
5669 * patch record to make it easy to find this point
5670 * later. The replay will happen at a time when it is
5671 * safe to unlock the directory.
5673 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5674 osi_assert(attrp != NULL);
5675 curPatchp = malloc(sizeof(*curPatchp));
5676 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5677 curPatchp->dptr = attrp;
5679 if (smb_hideDotFiles && smb_IsDotFile(cfileName)) {
5680 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5682 curPatchp->flags = 0;
5685 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5688 curPatchp->dep = dep;
5691 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5692 /* put out resume key */
5693 *((u_long *)origOp) = nextEntryCookie;
5695 /* Adjust byte ptr and count */
5696 origOp += orbytes; /* skip entire record */
5697 bytesInBuffer += orbytes;
5699 /* and pad the record out */
5700 while (align-- > 0) {
5704 } /* if we're including this name */
5705 else if (!starPattern &&
5707 cm_MatchMask(normName, maskp, CM_FLAG_CASEFOLD)) {
5708 /* We were looking for exact matches, but here's an inexact one*/
5713 /* and adjust curOffset to be where the new cookie is */
5714 thyper.HighPart = 0;
5715 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5716 curOffset = LargeIntegerAdd(thyper, curOffset);
5717 } /* while copying data for dir listing */
5719 /* If we didn't get a star pattern, we did an exact match during the first pass.
5720 * If there were no exact matches found, we fail over to inexact matches by
5721 * marking the query as a star pattern (matches all case permutations), and
5722 * re-running the query.
5724 if (returnedNames == 0 && !starPattern && foundInexact) {
5725 osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
5730 /* release the mutex */
5731 lock_ReleaseWrite(&scp->rw);
5733 buf_Release(bufferp);
5738 * Finally, process whatever entries we have left.
5740 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5741 dsp->relPath, infoLevel, userp, &req);
5743 /* now put out the final parameters */
5744 if (returnedNames == 0)
5746 if (p->opcode == 1) {
5748 outp->parmsp[0] = (unsigned short) dsp->cookie;
5749 outp->parmsp[1] = returnedNames;
5750 outp->parmsp[2] = eos;
5751 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5752 outp->parmsp[4] = 0;
5753 /* don't need last name to continue
5754 * search, cookie is enough. Normally,
5755 * this is the offset of the file name
5756 * of the last entry returned.
5758 outp->totalParms = 10; /* in bytes */
5762 outp->parmsp[0] = returnedNames;
5763 outp->parmsp[1] = eos;
5764 outp->parmsp[2] = 0; /* EAS error */
5765 outp->parmsp[3] = 0; /* last name, as above */
5766 outp->totalParms = 8; /* in bytes */
5769 /* return # of bytes in the buffer */
5770 outp->totalData = bytesInBuffer;
5772 /* Return error code if unsuccessful on first request */
5773 if (code == 0 && p->opcode == 1 && returnedNames == 0)
5774 code = CM_ERROR_NOSUCHFILE;
5776 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
5777 p->opcode, dsp->cookie, returnedNames, code);
5779 /* if we're supposed to close the search after this request, or if
5780 * we're supposed to close the search if we're done, and we're done,
5781 * or if something went wrong, close the search.
5783 if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
5784 (returnedNames == 0) ||
5785 ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
5787 smb_DeleteDirSearch(dsp);
5790 smb_SendTran2Error(vcp, p, opx, code);
5792 smb_SendTran2Packet(vcp, outp, opx);
5794 smb_FreeTran2Packet(outp);
5795 smb_ReleaseDirSearch(dsp);
5796 cm_ReleaseSCache(scp);
5797 cm_ReleaseUser(userp);
5801 /* SMB_COM_FIND_CLOSE2 */
5802 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5805 smb_dirSearch_t *dsp;
5807 dirHandle = smb_GetSMBParm(inp, 0);
5809 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
5811 dsp = smb_FindDirSearch(dirHandle);
5814 return CM_ERROR_BADFD;
5816 /* otherwise, we have an FD to destroy */
5817 smb_DeleteDirSearch(dsp);
5818 smb_ReleaseDirSearch(dsp);
5820 /* and return results */
5821 smb_SetSMBDataLength(outp, 0);
5827 /* SMB_COM_FIND_NOTIFY_CLOSE */
5828 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5830 smb_SetSMBDataLength(outp, 0);
5834 /* SMB_COM_OPEN_ANDX */
5835 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5837 clientchar_t *pathp;
5842 cm_scache_t *dscp; /* dir we're dealing with */
5843 cm_scache_t *scp; /* file we're creating */
5845 int initialModeBits;
5848 clientchar_t *lastNamep;
5849 unsigned long dosTime;
5855 int parmSlot; /* which parm we're dealing with */
5856 clientchar_t *tidPathp;
5859 BOOL is_rpc = FALSE;
5865 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
5866 openFun = smb_GetSMBParm(inp, 8); /* open function */
5867 excl = ((openFun & 3) == 0);
5868 trunc = ((openFun & 3) == 2); /* truncate it */
5869 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
5870 openAction = 0; /* tracks what we did */
5872 attributes = smb_GetSMBParm(inp, 5);
5873 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
5875 /* compute initial mode bits based on read-only flag in attributes */
5876 initialModeBits = 0666;
5877 if (attributes & SMB_ATTR_READONLY)
5878 initialModeBits &= ~0222;
5880 pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
5883 return CM_ERROR_BADSMB;
5885 spacep = inp->spacep;
5886 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5888 /* The 'is_rpc' assignment to TRUE is intentional */
5890 (cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
5891 ((cm_ClientStrCmpIA(lastNamep, _C("\\srvsvc")) == 0 ||
5892 cm_ClientStrCmpIA(lastNamep, _C("\\wkssvc")) == 0 ||
5893 cm_ClientStrCmpIA(lastNamep, _C("\\spoolss")) == 0 ||
5894 cm_ClientStrCmpIA(lastNamep, _C("\\winreg")) == 0 ||
5895 cm_ClientStrCmpIA(lastNamep, _C("ipc$")) == 0) && (is_rpc = TRUE)))) {
5897 unsigned short file_type = 0;
5898 unsigned short device_state = 0;
5900 /* special case magic file name for receiving IOCTL requests
5901 * (since IOCTL calls themselves aren't getting through).
5904 osi_Log0(smb_logp, "IOCTL Open");
5907 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5909 smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
5910 osi_Log1(smb_logp, "OpenAndX Setting up RPC on fid[%d]", fidp->fid);
5912 smb_SetupIoctlFid(fidp, spacep);
5913 osi_Log1(smb_logp, "OpenAndX Setting up IOCTL on fid[%d]", fidp->fid);
5916 /* set inp->fid so that later read calls in same msg can find fid */
5917 inp->fid = fidp->fid;
5919 /* copy out remainder of the parms */
5921 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5923 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
5924 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
5925 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5926 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
5927 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
5928 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5929 smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++;
5930 smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++;
5932 /* and the final "always present" stuff */
5933 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
5934 /* next write out the "unique" ID */
5935 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
5936 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
5937 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5938 smb_SetSMBDataLength(outp, 0);
5940 /* and clean up fid reference */
5941 smb_ReleaseFID(fidp);
5945 if (!cm_IsValidClientString(pathp)) {
5947 clientchar_t * hexp;
5949 hexp = cm_GetRawCharsAlloc(pathp, -1);
5950 osi_Log1(smb_logp, "NTOpenX rejecting invalid name. [%S]",
5951 osi_LogSaveClientString(smb_logp, hexp));
5955 osi_Log0(smb_logp, "NTOpenX rejecting invalid name");
5957 return CM_ERROR_BADNTFILENAME;
5960 #ifdef DEBUG_VERBOSE
5962 char *hexp, *asciip;
5963 asciip = (lastNamep ? lastNamep : pathp );
5964 hexp = osi_HexifyString(asciip);
5965 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
5969 userp = smb_GetUserFromVCP(vcp, inp);
5972 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5974 cm_ReleaseUser(userp);
5975 return CM_ERROR_NOSUCHPATH;
5977 code = cm_NameI(cm_data.rootSCachep, pathp,
5978 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5979 userp, tidPathp, &req, &scp);
5982 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5983 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5984 cm_ReleaseSCache(scp);
5985 cm_ReleaseUser(userp);
5986 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5987 return CM_ERROR_PATH_NOT_COVERED;
5989 return CM_ERROR_NOSUCHPATH;
5991 #endif /* DFS_SUPPORT */
5994 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
5995 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5996 userp, tidPathp, &req, &dscp);
5998 cm_ReleaseUser(userp);
6003 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6004 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
6006 cm_ReleaseSCache(dscp);
6007 cm_ReleaseUser(userp);
6008 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6009 return CM_ERROR_PATH_NOT_COVERED;
6011 return CM_ERROR_NOSUCHPATH;
6013 #endif /* DFS_SUPPORT */
6014 /* otherwise, scp points to the parent directory. Do a lookup,
6015 * and truncate the file if we find it, otherwise we create the
6022 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
6024 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
6025 cm_ReleaseSCache(dscp);
6026 cm_ReleaseUser(userp);
6031 /* if we get here, if code is 0, the file exists and is represented by
6032 * scp. Otherwise, we have to create it. The dir may be represented
6033 * by dscp, or we may have found the file directly. If code is non-zero,
6037 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
6039 if (dscp) cm_ReleaseSCache(dscp);
6040 cm_ReleaseSCache(scp);
6041 cm_ReleaseUser(userp);
6046 /* oops, file shouldn't be there */
6048 cm_ReleaseSCache(dscp);
6049 cm_ReleaseSCache(scp);
6050 cm_ReleaseUser(userp);
6051 return CM_ERROR_EXISTS;
6055 setAttr.mask = CM_ATTRMASK_LENGTH;
6056 setAttr.length.LowPart = 0;
6057 setAttr.length.HighPart = 0;
6058 code = cm_SetAttr(scp, &setAttr, userp, &req);
6059 openAction = 3; /* truncated existing file */
6061 else openAction = 1; /* found existing file */
6063 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
6064 /* don't create if not found */
6065 if (dscp) cm_ReleaseSCache(dscp);
6066 cm_ReleaseUser(userp);
6067 return CM_ERROR_NOSUCHFILE;
6070 osi_assertx(dscp != NULL, "null cm_scache_t");
6071 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %S",
6072 osi_LogSaveClientString(smb_logp, lastNamep));
6073 openAction = 2; /* created file */
6074 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6075 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6076 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6080 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6081 smb_NotifyChange(FILE_ACTION_ADDED,
6082 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6083 dscp, lastNamep, NULL, TRUE);
6084 } else if (!excl && code == CM_ERROR_EXISTS) {
6085 /* not an exclusive create, and someone else tried
6086 * creating it already, then we open it anyway. We
6087 * don't bother retrying after this, since if this next
6088 * fails, that means that the file was deleted after we
6089 * started this call.
6091 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6095 setAttr.mask = CM_ATTRMASK_LENGTH;
6096 setAttr.length.LowPart = 0;
6097 setAttr.length.HighPart = 0;
6098 code = cm_SetAttr(scp, &setAttr, userp, &req);
6100 } /* lookup succeeded */
6104 /* we don't need this any longer */
6106 cm_ReleaseSCache(dscp);
6109 /* something went wrong creating or truncating the file */
6111 cm_ReleaseSCache(scp);
6112 cm_ReleaseUser(userp);
6116 /* make sure we're about to open a file */
6117 if (scp->fileType != CM_SCACHETYPE_FILE) {
6118 cm_ReleaseSCache(scp);
6119 cm_ReleaseUser(userp);
6120 return CM_ERROR_ISDIR;
6123 /* now all we have to do is open the file itself */
6124 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6125 osi_assertx(fidp, "null smb_fid_t");
6128 lock_ObtainMutex(&fidp->mx);
6129 /* save a pointer to the vnode */
6131 lock_ObtainWrite(&scp->rw);
6132 scp->flags |= CM_SCACHEFLAG_SMB_FID;
6133 lock_ReleaseWrite(&scp->rw);
6134 osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
6136 fidp->userp = userp;
6138 /* compute open mode */
6140 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
6141 if (openMode == 1 || openMode == 2)
6142 fidp->flags |= SMB_FID_OPENWRITE;
6144 /* remember if the file was newly created */
6146 fidp->flags |= SMB_FID_CREATED;
6148 lock_ReleaseMutex(&fidp->mx);
6149 smb_ReleaseFID(fidp);
6151 cm_Open(scp, 0, userp);
6153 /* set inp->fid so that later read calls in same msg can find fid */
6154 inp->fid = fidp->fid;
6156 /* copy out remainder of the parms */
6158 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6159 lock_ObtainRead(&scp->rw);
6161 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
6162 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
6163 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
6164 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
6165 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
6166 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
6167 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
6168 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
6169 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
6171 /* and the final "always present" stuff */
6172 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
6173 /* next write out the "unique" ID */
6174 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
6175 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
6176 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6177 lock_ReleaseRead(&scp->rw);
6178 smb_SetSMBDataLength(outp, 0);
6180 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
6182 cm_ReleaseUser(userp);
6183 /* leave scp held since we put it in fidp->scp */
6187 static void smb_GetLockParams(unsigned char LockType,
6189 unsigned int * ppid,
6190 LARGE_INTEGER * pOffset,
6191 LARGE_INTEGER * pLength)
6193 if (LockType & LOCKING_ANDX_LARGE_FILES) {
6195 *ppid = *((USHORT *) *buf);
6196 pOffset->HighPart = *((LONG *)(*buf + 4));
6197 pOffset->LowPart = *((DWORD *)(*buf + 8));
6198 pLength->HighPart = *((LONG *)(*buf + 12));
6199 pLength->LowPart = *((DWORD *)(*buf + 16));
6203 /* Not Large Files */
6204 *ppid = *((USHORT *) *buf);
6205 pOffset->HighPart = 0;
6206 pOffset->LowPart = *((DWORD *)(*buf + 2));
6207 pLength->HighPart = 0;
6208 pLength->LowPart = *((DWORD *)(*buf + 6));
6213 /* SMB_COM_LOCKING_ANDX */
6214 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6221 unsigned char LockType;
6222 unsigned short NumberOfUnlocks, NumberOfLocks;
6226 LARGE_INTEGER LOffset, LLength;
6227 smb_waitingLockRequest_t *wlRequest = NULL;
6228 cm_file_lock_t *lockp;
6236 fid = smb_GetSMBParm(inp, 2);
6237 fid = smb_ChainFID(fid, inp);
6239 fidp = smb_FindFID(vcp, fid, 0);
6241 return CM_ERROR_BADFD;
6243 lock_ObtainMutex(&fidp->mx);
6244 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6245 lock_ReleaseMutex(&fidp->mx);
6246 smb_CloseFID(vcp, fidp, NULL, 0);
6247 smb_ReleaseFID(fidp);
6248 return CM_ERROR_NOSUCHFILE;
6251 if (fidp->flags & SMB_FID_IOCTL) {
6252 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
6253 lock_ReleaseMutex(&fidp->mx);
6254 smb_ReleaseFID(fidp);
6255 return CM_ERROR_BADFD;
6258 osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
6260 lock_ReleaseMutex(&fidp->mx);
6262 /* set inp->fid so that later read calls in same msg can find fid */
6265 userp = smb_GetUserFromVCP(vcp, inp);
6267 lock_ObtainWrite(&scp->rw);
6268 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6269 CM_SCACHESYNC_NEEDCALLBACK
6270 | CM_SCACHESYNC_GETSTATUS
6271 | CM_SCACHESYNC_LOCK);
6273 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
6277 LockType = smb_GetSMBParm(inp, 3) & 0xff;
6278 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
6279 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
6280 NumberOfLocks = smb_GetSMBParm(inp, 7);
6282 if (!(fidp->flags & SMB_FID_OPENWRITE) &&
6283 !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
6284 /* somebody wants exclusive locks on a file that they only
6285 opened for reading. We downgrade this to a shared lock. */
6286 osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
6287 LockType |= LOCKING_ANDX_SHARED_LOCK;
6290 if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
6291 /* AFS does not support atomic changes of lock types from read or write and vice-versa */
6292 osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]");
6293 code = CM_ERROR_BADOP;
6298 op = smb_GetSMBData(inp, NULL);
6300 if (LockType & LOCKING_ANDX_CANCEL_LOCK) {
6301 /* Cancel outstanding lock requests */
6302 smb_waitingLock_t * wl;
6304 for (i=0; i<NumberOfLocks; i++) {
6305 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6307 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6309 lock_ObtainWrite(&smb_globalLock);
6310 for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
6312 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
6313 if (cm_KeyEquals(&wl->key, &key, 0) && LargeIntegerEqualTo(wl->LOffset, LOffset) &&
6314 LargeIntegerEqualTo(wl->LLength, LLength)) {
6315 wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
6316 goto found_lock_request;
6321 lock_ReleaseWrite(&smb_globalLock);
6324 smb_SetSMBDataLength(outp, 0);
6329 for (i=0; i<NumberOfUnlocks; i++) {
6330 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6332 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6334 code = cm_Unlock(scp, LockType, LOffset, LLength, key, 0, userp, &req);
6342 for (i=0; i<NumberOfLocks; i++) {
6343 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6345 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6347 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
6348 userp, &req, &lockp);
6350 if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
6351 (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
6353 code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
6354 userp, &req, &lockp);
6357 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
6358 smb_waitingLock_t * wLock;
6360 /* Put on waiting list */
6361 if(wlRequest == NULL) {
6365 LARGE_INTEGER tOffset, tLength;
6367 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
6369 osi_assertx(wlRequest != NULL, "null wlRequest");
6371 wlRequest->vcp = vcp;
6373 wlRequest->scp = scp;
6374 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
6376 wlRequest->inp = smb_CopyPacket(inp);
6377 wlRequest->outp = smb_CopyPacket(outp);
6378 wlRequest->lockType = LockType;
6379 wlRequest->msTimeout = Timeout;
6380 wlRequest->start_t = osi_Time();
6381 wlRequest->locks = NULL;
6383 /* The waiting lock request needs to have enough
6384 information to undo all the locks in the request.
6385 We do the following to store info about locks that
6386 have already been granted. Sure, we can get most
6387 of the info from the packet, but the packet doesn't
6388 hold the result of cm_Lock call. In practice we
6389 only receive packets with one or two locks, so we
6390 are only wasting a few bytes here and there and
6391 only for a limited period of time until the waiting
6392 lock times out or is freed. */
6394 for(opt = op_locks, j=i; j > 0; j--) {
6395 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
6397 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6399 wLock = malloc(sizeof(smb_waitingLock_t));
6401 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6404 wLock->LOffset = tOffset;
6405 wLock->LLength = tLength;
6406 wLock->lockp = NULL;
6407 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
6408 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6413 wLock = malloc(sizeof(smb_waitingLock_t));
6415 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6418 wLock->LOffset = LOffset;
6419 wLock->LLength = LLength;
6420 wLock->lockp = lockp;
6421 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
6422 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6425 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
6433 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
6440 /* Since something went wrong with the lock number i, we now
6441 have to go ahead and release any locks acquired before the
6442 failure. All locks before lock number i (of which there
6443 are i of them) have either been successful or are waiting.
6444 Either case requires calling cm_Unlock(). */
6446 /* And purge the waiting lock */
6447 if(wlRequest != NULL) {
6448 smb_waitingLock_t * wl;
6449 smb_waitingLock_t * wlNext;
6452 for(wl = wlRequest->locks; wl; wl = wlNext) {
6454 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
6456 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, 0, userp, &req);
6459 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
6461 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
6464 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
6469 smb_ReleaseVC(wlRequest->vcp);
6470 cm_ReleaseSCache(wlRequest->scp);
6471 smb_FreePacket(wlRequest->inp);
6472 smb_FreePacket(wlRequest->outp);
6481 if (wlRequest != NULL) {
6483 lock_ObtainWrite(&smb_globalLock);
6484 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
6486 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
6487 lock_ReleaseWrite(&smb_globalLock);
6489 /* don't send reply immediately */
6490 outp->flags |= SMB_PACKETFLAG_NOSEND;
6493 smb_SetSMBDataLength(outp, 0);
6497 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
6500 lock_ReleaseWrite(&scp->rw);
6501 cm_ReleaseSCache(scp);
6502 cm_ReleaseUser(userp);
6503 smb_ReleaseFID(fidp);
6508 /* SMB_COM_QUERY_INFORMATION2 */
6509 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6515 afs_uint32 searchTime;
6522 fid = smb_GetSMBParm(inp, 0);
6523 fid = smb_ChainFID(fid, inp);
6525 fidp = smb_FindFID(vcp, fid, 0);
6527 return CM_ERROR_BADFD;
6529 lock_ObtainMutex(&fidp->mx);
6530 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6531 lock_ReleaseMutex(&fidp->mx);
6532 smb_CloseFID(vcp, fidp, NULL, 0);
6533 smb_ReleaseFID(fidp);
6534 return CM_ERROR_NOSUCHFILE;
6537 if (fidp->flags & SMB_FID_IOCTL) {
6538 lock_ReleaseMutex(&fidp->mx);
6539 smb_ReleaseFID(fidp);
6540 return CM_ERROR_BADFD;
6543 osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6545 lock_ReleaseMutex(&fidp->mx);
6547 userp = smb_GetUserFromVCP(vcp, inp);
6550 /* otherwise, stat the file */
6551 lock_ObtainWrite(&scp->rw);
6552 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6553 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6557 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6559 lock_ConvertWToR(&scp->rw);
6562 /* decode times. We need a search time, but the response to this
6563 * call provides the date first, not the time, as returned in the
6564 * searchTime variable. So we take the high-order bits first.
6566 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
6567 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
6568 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
6569 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
6570 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
6571 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
6572 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
6574 /* now handle file size and allocation size */
6575 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
6576 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
6577 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
6578 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
6580 /* file attribute */
6581 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
6583 /* and finalize stuff */
6584 smb_SetSMBDataLength(outp, 0);
6589 lock_ReleaseRead(&scp->rw);
6591 lock_ReleaseWrite(&scp->rw);
6592 cm_ReleaseSCache(scp);
6593 cm_ReleaseUser(userp);
6594 smb_ReleaseFID(fidp);
6598 /* SMB_COM_SET_INFORMATION2 */
6599 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6605 afs_uint32 searchTime;
6613 fid = smb_GetSMBParm(inp, 0);
6614 fid = smb_ChainFID(fid, inp);
6616 fidp = smb_FindFID(vcp, fid, 0);
6618 return CM_ERROR_BADFD;
6620 lock_ObtainMutex(&fidp->mx);
6621 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6622 lock_ReleaseMutex(&fidp->mx);
6623 smb_CloseFID(vcp, fidp, NULL, 0);
6624 smb_ReleaseFID(fidp);
6625 return CM_ERROR_NOSUCHFILE;
6628 if (fidp->flags & SMB_FID_IOCTL) {
6629 lock_ReleaseMutex(&fidp->mx);
6630 smb_ReleaseFID(fidp);
6631 return CM_ERROR_BADFD;
6634 osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6636 lock_ReleaseMutex(&fidp->mx);
6638 userp = smb_GetUserFromVCP(vcp, inp);
6640 /* now prepare to call cm_setattr. This message only sets various times,
6641 * and AFS only implements mtime, and we'll set the mtime if that's
6642 * requested. The others we'll ignore.
6644 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
6646 if (searchTime != 0) {
6647 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
6649 if ( unixTime != -1 ) {
6650 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
6651 attrs.clientModTime = unixTime;
6652 code = cm_SetAttr(scp, &attrs, userp, &req);
6654 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
6656 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
6662 cm_ReleaseSCache(scp);
6663 cm_ReleaseUser(userp);
6664 smb_ReleaseFID(fidp);
6668 /* SMB_COM_WRITE_ANDX */
6669 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6672 long count, written = 0, total_written = 0;
6676 smb_t *smbp = (smb_t*) inp;
6681 int inDataBlockCount;
6683 fd = smb_GetSMBParm(inp, 2);
6684 count = smb_GetSMBParm(inp, 10);
6686 offset.HighPart = 0;
6687 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6689 if (*inp->wctp == 14) {
6690 /* we have a request with 64-bit file offsets */
6691 #ifdef AFS_LARGEFILES
6692 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6694 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6696 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
6697 /* we shouldn't have received this op if we didn't specify
6698 largefile support */
6699 return CM_ERROR_BADOP;
6704 op = inp->data + smb_GetSMBParm(inp, 11);
6705 inDataBlockCount = count;
6707 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
6708 fd, offset.HighPart, offset.LowPart, count);
6710 fd = smb_ChainFID(fd, inp);
6711 fidp = smb_FindFID(vcp, fd, 0);
6713 return CM_ERROR_BADFD;
6715 lock_ObtainMutex(&fidp->mx);
6716 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6717 lock_ReleaseMutex(&fidp->mx);
6718 smb_CloseFID(vcp, fidp, NULL, 0);
6719 smb_ReleaseFID(fidp);
6720 return CM_ERROR_NOSUCHFILE;
6723 if (fidp->flags & SMB_FID_IOCTL) {
6724 lock_ReleaseMutex(&fidp->mx);
6725 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
6726 smb_ReleaseFID(fidp);
6730 if (fidp->flags & SMB_FID_RPC) {
6731 lock_ReleaseMutex(&fidp->mx);
6732 code = smb_RPCV3Write(fidp, vcp, inp, outp);
6733 smb_ReleaseFID(fidp);
6738 lock_ReleaseMutex(&fidp->mx);
6739 smb_ReleaseFID(fidp);
6740 return CM_ERROR_BADFDOP;
6745 lock_ReleaseMutex(&fidp->mx);
6747 userp = smb_GetUserFromVCP(vcp, inp);
6749 /* special case: 0 bytes transferred means there is no data
6750 transferred. A slight departure from SMB_COM_WRITE where this
6751 means that we are supposed to truncate the file at this
6756 LARGE_INTEGER LOffset;
6757 LARGE_INTEGER LLength;
6760 key = cm_GenerateKey(vcp->vcID, pid, fd);
6762 LOffset.HighPart = offset.HighPart;
6763 LOffset.LowPart = offset.LowPart;
6764 LLength.HighPart = 0;
6765 LLength.LowPart = count;
6767 lock_ObtainWrite(&scp->rw);
6768 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
6769 lock_ReleaseWrite(&scp->rw);
6776 * Work around bug in NT client
6778 * When copying a file, the NT client should first copy the data,
6779 * then copy the last write time. But sometimes the NT client does
6780 * these in the wrong order, so the data copies would inadvertently
6781 * cause the last write time to be overwritten. We try to detect this,
6782 * and don't set client mod time if we think that would go against the
6785 lock_ObtainMutex(&fidp->mx);
6786 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6787 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6788 scp->clientModTime = time(NULL);
6790 lock_ReleaseMutex(&fidp->mx);
6793 while ( code == 0 && count > 0 ) {
6794 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6795 if (code == 0 && written == 0)
6796 code = CM_ERROR_PARTIALWRITE;
6798 offset = LargeIntegerAdd(offset,
6799 ConvertLongToLargeInteger(written));
6801 total_written += written;
6805 /* slots 0 and 1 are reserved for request chaining and will be
6806 filled in when we return. */
6807 smb_SetSMBParm(outp, 2, total_written);
6808 smb_SetSMBParm(outp, 3, 0); /* reserved */
6809 smb_SetSMBParm(outp, 4, 0); /* reserved */
6810 smb_SetSMBParm(outp, 5, 0); /* reserved */
6811 smb_SetSMBDataLength(outp, 0);
6815 cm_ReleaseSCache(scp);
6816 cm_ReleaseUser(userp);
6817 smb_ReleaseFID(fidp);
6822 /* SMB_COM_READ_ANDX */
6823 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6827 long finalCount = 0;
6831 smb_t *smbp = (smb_t*) inp;
6838 fd = smb_GetSMBParm(inp, 2); /* File ID */
6839 count = smb_GetSMBParm(inp, 5); /* MaxCount */
6840 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6842 if (*inp->wctp == 12) {
6843 /* a request with 64-bit offsets */
6844 #ifdef AFS_LARGEFILES
6845 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
6847 if (LargeIntegerLessThanZero(offset)) {
6848 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
6849 offset.HighPart, offset.LowPart);
6850 return CM_ERROR_BADSMB;
6853 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
6854 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
6855 return CM_ERROR_BADSMB;
6857 offset.HighPart = 0;
6861 offset.HighPart = 0;
6864 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
6865 fd, offset.HighPart, offset.LowPart, count);
6867 fd = smb_ChainFID(fd, inp);
6868 fidp = smb_FindFID(vcp, fd, 0);
6870 return CM_ERROR_BADFD;
6873 lock_ObtainMutex(&fidp->mx);
6875 if (fidp->flags & SMB_FID_IOCTL) {
6876 lock_ReleaseMutex(&fidp->mx);
6878 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
6879 smb_ReleaseFID(fidp);
6883 if (fidp->flags & SMB_FID_RPC) {
6884 lock_ReleaseMutex(&fidp->mx);
6886 code = smb_RPCV3Read(fidp, vcp, inp, outp);
6887 smb_ReleaseFID(fidp);
6891 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6892 lock_ReleaseMutex(&fidp->mx);
6893 smb_CloseFID(vcp, fidp, NULL, 0);
6894 smb_ReleaseFID(fidp);
6895 return CM_ERROR_NOSUCHFILE;
6899 lock_ReleaseMutex(&fidp->mx);
6900 smb_ReleaseFID(fidp);
6901 return CM_ERROR_BADFDOP;
6907 lock_ReleaseMutex(&fidp->mx);
6910 key = cm_GenerateKey(vcp->vcID, pid, fd);
6912 LARGE_INTEGER LOffset, LLength;
6914 LOffset.HighPart = offset.HighPart;
6915 LOffset.LowPart = offset.LowPart;
6916 LLength.HighPart = 0;
6917 LLength.LowPart = count;
6919 lock_ObtainWrite(&scp->rw);
6920 code = cm_LockCheckRead(scp, LOffset, LLength, key);
6921 lock_ReleaseWrite(&scp->rw);
6923 cm_ReleaseSCache(scp);
6926 smb_ReleaseFID(fidp);
6930 /* set inp->fid so that later read calls in same msg can find fid */
6933 userp = smb_GetUserFromVCP(vcp, inp);
6935 /* 0 and 1 are reserved for request chaining, were setup by our caller,
6936 * and will be further filled in after we return.
6938 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
6939 smb_SetSMBParm(outp, 3, 0); /* resvd */
6940 smb_SetSMBParm(outp, 4, 0); /* resvd */
6941 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
6942 /* fill in #6 when we have all the parameters' space reserved */
6943 smb_SetSMBParm(outp, 7, 0); /* resv'd */
6944 smb_SetSMBParm(outp, 8, 0); /* resv'd */
6945 smb_SetSMBParm(outp, 9, 0); /* resv'd */
6946 smb_SetSMBParm(outp, 10, 0); /* resv'd */
6947 smb_SetSMBParm(outp, 11, 0); /* reserved */
6949 /* get op ptr after putting in the parms, since otherwise we don't
6950 * know where the data really is.
6952 op = smb_GetSMBData(outp, NULL);
6954 /* now fill in offset from start of SMB header to first data byte (to op) */
6955 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
6957 /* set the packet data length the count of the # of bytes */
6958 smb_SetSMBDataLength(outp, count);
6960 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6962 /* fix some things up */
6963 smb_SetSMBParm(outp, 5, finalCount);
6964 smb_SetSMBDataLength(outp, finalCount);
6966 cm_ReleaseUser(userp);
6967 smb_ReleaseFID(fidp);
6972 * Values for createDisp, copied from NTDDK.H
6974 #define FILE_SUPERSEDE 0 // (???)
6975 #define FILE_OPEN 1 // (open)
6976 #define FILE_CREATE 2 // (exclusive)
6977 #define FILE_OPEN_IF 3 // (non-exclusive)
6978 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
6979 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
6982 #define REQUEST_OPLOCK 2
6983 #define REQUEST_BATCH_OPLOCK 4
6984 #define OPEN_DIRECTORY 8
6985 #define EXTENDED_RESPONSE_REQUIRED 0x10
6987 /* CreateOptions field. */
6988 #define FILE_DIRECTORY_FILE 0x0001
6989 #define FILE_WRITE_THROUGH 0x0002
6990 #define FILE_SEQUENTIAL_ONLY 0x0004
6991 #define FILE_NON_DIRECTORY_FILE 0x0040
6992 #define FILE_NO_EA_KNOWLEDGE 0x0200
6993 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
6994 #define FILE_RANDOM_ACCESS 0x0800
6995 #define FILE_DELETE_ON_CLOSE 0x1000
6996 #define FILE_OPEN_BY_FILE_ID 0x2000
6997 #define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000
6998 #define FILE_NO_COMPRESSION 0x00008000
6999 #define FILE_RESERVE_OPFILTER 0x00100000
7000 #define FILE_OPEN_REPARSE_POINT 0x00200000
7001 #define FILE_OPEN_NO_RECALL 0x00400000
7002 #define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000
7004 /* SMB_COM_NT_CREATE_ANDX */
7005 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7007 clientchar_t *pathp, *realPathp;
7011 cm_scache_t *dscp; /* parent dir */
7012 cm_scache_t *scp; /* file to create or open */
7013 cm_scache_t *targetScp; /* if scp is a symlink */
7015 clientchar_t *lastNamep;
7016 clientchar_t *treeStartp;
7017 unsigned short nameLength;
7019 unsigned int requestOpLock;
7020 unsigned int requestBatchOpLock;
7021 unsigned int mustBeDir;
7022 unsigned int extendedRespRequired;
7023 unsigned int treeCreate;
7025 unsigned int desiredAccess;
7026 unsigned int extAttributes;
7027 unsigned int createDisp;
7028 unsigned int createOptions;
7029 unsigned int shareAccess;
7030 int initialModeBits;
7031 unsigned short baseFid;
7032 smb_fid_t *baseFidp;
7034 cm_scache_t *baseDirp;
7035 unsigned short openAction;
7040 clientchar_t *tidPathp;
7045 int checkDoneRequired = 0;
7046 cm_lock_data_t *ldp = NULL;
7047 BOOL is_rpc = FALSE;
7051 /* This code is very long and has a lot of if-then-else clauses
7052 * scp and dscp get reused frequently and we need to ensure that
7053 * we don't lose a reference. Start by ensuring that they are NULL.
7060 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
7061 flags = smb_GetSMBOffsetParm(inp, 3, 1)
7062 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
7063 requestOpLock = flags & REQUEST_OPLOCK;
7064 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7065 mustBeDir = flags & OPEN_DIRECTORY;
7066 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7069 * Why all of a sudden 32-bit FID?
7070 * We will reject all bits higher than 16.
7072 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
7073 return CM_ERROR_INVAL;
7074 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
7075 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
7076 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
7077 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
7078 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
7079 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
7080 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
7081 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
7082 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
7083 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
7084 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
7086 /* mustBeDir is never set; createOptions directory bit seems to be
7089 if (createOptions & FILE_DIRECTORY_FILE)
7091 else if (createOptions & FILE_NON_DIRECTORY_FILE)
7097 * compute initial mode bits based on read-only flag in
7098 * extended attributes
7100 initialModeBits = 0666;
7101 if (extAttributes & SMB_ATTR_READONLY)
7102 initialModeBits &= ~0222;
7104 pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
7105 NULL, SMB_STRF_ANSIPATH);
7107 /* Sometimes path is not null-terminated, so we make a copy. */
7108 realPathp = malloc(nameLength+sizeof(clientchar_t));
7109 memcpy(realPathp, pathp, nameLength+sizeof(clientchar_t));
7110 realPathp[nameLength/sizeof(clientchar_t)] = 0;
7112 spacep = inp->spacep;
7113 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
7115 osi_Log1(smb_logp,"NTCreateX for [%S]",osi_LogSaveClientString(smb_logp,realPathp));
7116 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
7117 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%S]", shareAccess, flags, osi_LogSaveClientString(smb_logp,(lastNamep?lastNamep:_C("null"))));
7119 /* The 'is_rpc' assignment to TRUE is intentional */
7121 (((cm_ClientStrCmpIA(lastNamep, _C("\\srvsvc")) == 0 ||
7122 cm_ClientStrCmpIA(lastNamep, _C("\\wkssvc")) == 0 ||
7123 cm_ClientStrCmpIA(lastNamep, _C("\\spoolss")) == 0 ||
7124 cm_ClientStrCmpIA(lastNamep, _C("\\winreg")) == 0 ||
7125 cm_ClientStrCmpIA(lastNamep, _C("ipc$")) == 0) && (is_rpc = TRUE)) ||
7127 /* special case magic file name for receiving IOCTL requests
7128 * (since IOCTL calls themselves aren't getting through).
7130 cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0)) {
7132 unsigned short file_type = 0;
7133 unsigned short device_state = 0;
7135 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7138 smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
7139 osi_Log1(smb_logp, "NTCreateX Setting up RPC on fid[%d]", fidp->fid);
7141 smb_SetupIoctlFid(fidp, spacep);
7142 osi_Log1(smb_logp, "NTCreateX Setting up IOCTL on fid[%d]", fidp->fid);
7145 /* set inp->fid so that later read calls in same msg can find fid */
7146 inp->fid = fidp->fid;
7150 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7151 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7152 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
7154 memset(&ft, 0, sizeof(ft));
7155 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7156 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7157 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7158 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7159 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
7160 sz.HighPart = 0x7fff; sz.LowPart = 0;
7161 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
7162 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
7163 smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++; /* filetype */
7164 smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++; /* dev state */
7165 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
7166 smb_SetSMBDataLength(outp, 0);
7168 /* clean up fid reference */
7169 smb_ReleaseFID(fidp);
7174 if (!cm_IsValidClientString(realPathp)) {
7176 clientchar_t * hexp;
7178 hexp = cm_GetRawCharsAlloc(realPathp, -1);
7179 osi_Log1(smb_logp, "NTCreateX rejecting invalid name. [%S]",
7180 osi_LogSaveClientString(smb_logp, hexp));
7184 osi_Log0(smb_logp, "NTCreateX rejecting invalid name");
7187 return CM_ERROR_BADNTFILENAME;
7190 userp = smb_GetUserFromVCP(vcp, inp);
7192 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
7194 return CM_ERROR_INVAL;
7199 baseDirp = cm_data.rootSCachep;
7200 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7201 if (code == CM_ERROR_TIDIPC) {
7202 /* Attempt to use a TID allocated for IPC. The client
7203 * is probably looking for DCE RPC end points which we
7204 * don't support OR it could be looking to make a DFS
7207 osi_Log0(smb_logp, "NTCreateX received IPC TID");
7210 cm_ReleaseUser(userp);
7211 return CM_ERROR_NOSUCHFILE;
7212 #endif /* DFS_SUPPORT */
7215 baseFidp = smb_FindFID(vcp, baseFid, 0);
7217 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
7219 cm_ReleaseUser(userp);
7220 return CM_ERROR_INVAL;
7223 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7225 cm_ReleaseUser(userp);
7226 smb_CloseFID(vcp, baseFidp, NULL, 0);
7227 smb_ReleaseFID(baseFidp);
7228 return CM_ERROR_NOSUCHPATH;
7231 baseDirp = baseFidp->scp;
7235 osi_Log1(smb_logp, "NTCreateX tidPathp=[%S]", (tidPathp==NULL)?_C("null"): osi_LogSaveClientString(smb_logp,tidPathp));
7237 /* compute open mode */
7239 if (desiredAccess & DELETE)
7240 fidflags |= SMB_FID_OPENDELETE;
7241 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
7242 fidflags |= SMB_FID_OPENREAD_LISTDIR;
7243 if (desiredAccess & AFS_ACCESS_WRITE)
7244 fidflags |= SMB_FID_OPENWRITE;
7245 if (createOptions & FILE_DELETE_ON_CLOSE)
7246 fidflags |= SMB_FID_DELONCLOSE;
7247 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7248 fidflags |= SMB_FID_SEQUENTIAL;
7249 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7250 fidflags |= SMB_FID_RANDOM;
7251 if (createOptions & FILE_OPEN_REPARSE_POINT)
7252 osi_Log0(smb_logp, "NTCreateX Open Reparse Point");
7253 if (smb_IsExecutableFileName(lastNamep))
7254 fidflags |= SMB_FID_EXECUTABLE;
7256 /* and the share mode */
7257 if (shareAccess & FILE_SHARE_READ)
7258 fidflags |= SMB_FID_SHARE_READ;
7259 if (shareAccess & FILE_SHARE_WRITE)
7260 fidflags |= SMB_FID_SHARE_WRITE;
7262 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
7265 /* For an exclusive create, we want to do a case sensitive match for the last component. */
7266 if ( createDisp == FILE_CREATE ||
7267 createDisp == FILE_OVERWRITE ||
7268 createDisp == FILE_OVERWRITE_IF) {
7269 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7270 userp, tidPathp, &req, &dscp);
7273 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7274 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7276 cm_ReleaseSCache(dscp);
7277 cm_ReleaseUser(userp);
7280 smb_ReleaseFID(baseFidp);
7281 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7282 return CM_ERROR_PATH_NOT_COVERED;
7284 return CM_ERROR_NOSUCHPATH;
7286 #endif /* DFS_SUPPORT */
7287 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7289 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7290 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7291 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7292 if (code == 0 && realDirFlag == 1) {
7293 cm_ReleaseSCache(scp);
7294 cm_ReleaseSCache(dscp);
7295 cm_ReleaseUser(userp);
7298 smb_ReleaseFID(baseFidp);
7299 return CM_ERROR_EXISTS;
7303 /* we have both scp and dscp */
7305 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7306 userp, tidPathp, &req, &scp);
7308 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7309 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7310 cm_ReleaseSCache(scp);
7311 cm_ReleaseUser(userp);
7314 smb_ReleaseFID(baseFidp);
7315 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7316 return CM_ERROR_PATH_NOT_COVERED;
7318 return CM_ERROR_NOSUCHPATH;
7320 #endif /* DFS_SUPPORT */
7321 /* we might have scp but not dscp */
7327 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7328 /* look up parent directory */
7329 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
7330 * the immediate parent. We have to work our way up realPathp until we hit something that we
7334 /* we might or might not have scp */
7340 code = cm_NameI(baseDirp, spacep->wdata,
7341 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7342 userp, tidPathp, &req, &dscp);
7345 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7346 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7349 cm_ReleaseSCache(scp);
7350 cm_ReleaseSCache(dscp);
7351 cm_ReleaseUser(userp);
7354 smb_ReleaseFID(baseFidp);
7355 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7356 return CM_ERROR_PATH_NOT_COVERED;
7358 return CM_ERROR_NOSUCHPATH;
7360 #endif /* DFS_SUPPORT */
7363 (tp = cm_ClientStrRChr(spacep->wdata, '\\')) &&
7364 (createDisp == FILE_CREATE) &&
7365 (realDirFlag == 1)) {
7368 treeStartp = realPathp + (tp - spacep->wdata);
7370 if (*tp && !smb_IsLegalFilename(tp)) {
7371 cm_ReleaseUser(userp);
7373 smb_ReleaseFID(baseFidp);
7376 cm_ReleaseSCache(scp);
7377 return CM_ERROR_BADNTFILENAME;
7381 } while (dscp == NULL && code == 0);
7385 /* we might have scp and we might have dscp */
7388 smb_ReleaseFID(baseFidp);
7391 osi_Log0(smb_logp,"NTCreateX parent not found");
7393 cm_ReleaseSCache(scp);
7395 cm_ReleaseSCache(dscp);
7396 cm_ReleaseUser(userp);
7401 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
7402 /* A file exists where we want a directory. */
7404 cm_ReleaseSCache(scp);
7405 cm_ReleaseSCache(dscp);
7406 cm_ReleaseUser(userp);
7408 return CM_ERROR_EXISTS;
7412 lastNamep = realPathp;
7416 if (!smb_IsLegalFilename(lastNamep)) {
7418 cm_ReleaseSCache(scp);
7420 cm_ReleaseSCache(dscp);
7421 cm_ReleaseUser(userp);
7423 return CM_ERROR_BADNTFILENAME;
7426 if (!foundscp && !treeCreate) {
7427 if ( createDisp == FILE_CREATE ||
7428 createDisp == FILE_OVERWRITE ||
7429 createDisp == FILE_OVERWRITE_IF)
7431 code = cm_Lookup(dscp, lastNamep,
7432 CM_FLAG_FOLLOW, userp, &req, &scp);
7434 code = cm_Lookup(dscp, lastNamep,
7435 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7438 if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
7440 cm_ReleaseSCache(dscp);
7441 cm_ReleaseUser(userp);
7446 /* we have scp and dscp */
7448 /* we have scp but not dscp */
7450 smb_ReleaseFID(baseFidp);
7453 /* if we get here, if code is 0, the file exists and is represented by
7454 * scp. Otherwise, we have to create it. The dir may be represented
7455 * by dscp, or we may have found the file directly. If code is non-zero,
7458 if (code == 0 && !treeCreate) {
7459 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7461 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7463 cm_ReleaseSCache(dscp);
7465 cm_ReleaseSCache(scp);
7466 cm_ReleaseUser(userp);
7470 checkDoneRequired = 1;
7472 if (createDisp == FILE_CREATE) {
7473 /* oops, file shouldn't be there */
7474 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7476 cm_ReleaseSCache(dscp);
7478 cm_ReleaseSCache(scp);
7479 cm_ReleaseUser(userp);
7481 return CM_ERROR_EXISTS;
7484 if ( createDisp == FILE_OVERWRITE ||
7485 createDisp == FILE_OVERWRITE_IF) {
7487 setAttr.mask = CM_ATTRMASK_LENGTH;
7488 setAttr.length.LowPart = 0;
7489 setAttr.length.HighPart = 0;
7490 /* now watch for a symlink */
7492 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7494 osi_assertx(dscp != NULL, "null cm_scache_t");
7495 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7497 /* we have a more accurate file to use (the
7498 * target of the symbolic link). Otherwise,
7499 * we'll just use the symlink anyway.
7501 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7503 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7504 cm_ReleaseSCache(scp);
7506 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7508 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7510 cm_ReleaseSCache(dscp);
7512 cm_ReleaseSCache(scp);
7513 cm_ReleaseUser(userp);
7519 code = cm_SetAttr(scp, &setAttr, userp, &req);
7520 openAction = 3; /* truncated existing file */
7523 openAction = 1; /* found existing file */
7525 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7526 /* don't create if not found */
7528 cm_ReleaseSCache(dscp);
7530 cm_ReleaseSCache(scp);
7531 cm_ReleaseUser(userp);
7533 return CM_ERROR_NOSUCHFILE;
7534 } else if (realDirFlag == 0 || realDirFlag == -1) {
7535 osi_assertx(dscp != NULL, "null cm_scache_t");
7536 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %S",
7537 osi_LogSaveClientString(smb_logp, lastNamep));
7538 openAction = 2; /* created file */
7539 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7540 setAttr.clientModTime = time(NULL);
7541 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
7544 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7545 smb_NotifyChange(FILE_ACTION_ADDED,
7546 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7547 dscp, lastNamep, NULL, TRUE);
7548 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7549 /* Not an exclusive create, and someone else tried
7550 * creating it already, then we open it anyway. We
7551 * don't bother retrying after this, since if this next
7552 * fails, that means that the file was deleted after we
7553 * started this call.
7555 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7558 if (createDisp == FILE_OVERWRITE_IF) {
7559 setAttr.mask = CM_ATTRMASK_LENGTH;
7560 setAttr.length.LowPart = 0;
7561 setAttr.length.HighPart = 0;
7563 /* now watch for a symlink */
7565 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7567 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7569 /* we have a more accurate file to use (the
7570 * target of the symbolic link). Otherwise,
7571 * we'll just use the symlink anyway.
7573 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7575 cm_ReleaseSCache(scp);
7579 code = cm_SetAttr(scp, &setAttr, userp, &req);
7581 } /* lookup succeeded */
7584 clientchar_t *tp, *pp;
7585 clientchar_t *cp; /* This component */
7586 int clen = 0; /* length of component */
7587 cm_scache_t *tscp1, *tscp2;
7590 /* create directory */
7592 treeStartp = lastNamep;
7593 osi_assertx(dscp != NULL, "null cm_scache_t");
7594 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%S]",
7595 osi_LogSaveClientString(smb_logp, treeStartp));
7596 openAction = 2; /* created directory */
7598 /* if the request is to create the root directory
7599 * it will appear as a directory name of the nul-string
7600 * and a code of CM_ERROR_NOSUCHFILE
7602 if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
7603 code = CM_ERROR_EXISTS;
7605 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7606 setAttr.clientModTime = time(NULL);
7611 cm_HoldSCache(tscp1);
7615 tp = cm_ClientStrChr(pp, '\\');
7617 cm_ClientStrCpy(cp, lengthof(spacep->wdata) - (cp - spacep->wdata), pp);
7618 clen = (int)cm_ClientStrLen(cp);
7619 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
7621 clen = (int)(tp - pp);
7622 cm_ClientStrCpyN(cp, lengthof(spacep->wdata) - (cp - spacep->wdata),
7630 continue; /* the supplied path can't have consecutive slashes either , but */
7632 /* cp is the next component to be created. */
7633 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req, NULL);
7634 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
7635 smb_NotifyChange(FILE_ACTION_ADDED,
7636 FILE_NOTIFY_CHANGE_DIR_NAME,
7637 tscp1, cp, NULL, TRUE);
7639 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7640 /* Not an exclusive create, and someone else tried
7641 * creating it already, then we open it anyway. We
7642 * don't bother retrying after this, since if this next
7643 * fails, that means that the file was deleted after we
7644 * started this call.
7646 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
7647 userp, &req, &tscp2);
7652 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
7653 cm_ReleaseSCache(tscp1);
7654 tscp1 = tscp2; /* Newly created directory will be next parent */
7655 /* the hold is transfered to tscp1 from tscp2 */
7660 cm_ReleaseSCache(dscp);
7663 cm_ReleaseSCache(scp);
7666 * if we get here and code == 0, then scp is the last directory created, and dscp is the
7672 /* something went wrong creating or truncating the file */
7673 if (checkDoneRequired)
7674 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7676 cm_ReleaseSCache(scp);
7678 cm_ReleaseSCache(dscp);
7679 cm_ReleaseUser(userp);
7684 /* make sure we have file vs. dir right (only applies for single component case) */
7685 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7686 /* now watch for a symlink */
7688 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7689 cm_scache_t * targetScp = 0;
7690 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7692 /* we have a more accurate file to use (the
7693 * target of the symbolic link). Otherwise,
7694 * we'll just use the symlink anyway.
7696 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
7697 if (checkDoneRequired) {
7698 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7699 checkDoneRequired = 0;
7701 cm_ReleaseSCache(scp);
7706 if (scp->fileType != CM_SCACHETYPE_FILE) {
7707 if (checkDoneRequired)
7708 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7710 cm_ReleaseSCache(dscp);
7711 cm_ReleaseSCache(scp);
7712 cm_ReleaseUser(userp);
7714 return CM_ERROR_ISDIR;
7718 /* (only applies to single component case) */
7719 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7720 if (checkDoneRequired)
7721 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7722 cm_ReleaseSCache(scp);
7724 cm_ReleaseSCache(dscp);
7725 cm_ReleaseUser(userp);
7727 return CM_ERROR_NOTDIR;
7730 /* open the file itself */
7731 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7732 osi_assertx(fidp, "null smb_fid_t");
7734 /* save a reference to the user */
7736 fidp->userp = userp;
7738 /* If we are restricting sharing, we should do so with a suitable
7740 if (scp->fileType == CM_SCACHETYPE_FILE &&
7741 !(fidflags & SMB_FID_SHARE_WRITE)) {
7743 LARGE_INTEGER LOffset, LLength;
7746 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7747 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7748 LLength.HighPart = 0;
7749 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7751 /* If we are not opening the file for writing, then we don't
7752 try to get an exclusive lock. No one else should be able to
7753 get an exclusive lock on the file anyway, although someone
7754 else can get a shared lock. */
7755 if ((fidflags & SMB_FID_SHARE_READ) ||
7756 !(fidflags & SMB_FID_OPENWRITE)) {
7757 sLockType = LOCKING_ANDX_SHARED_LOCK;
7762 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7764 lock_ObtainWrite(&scp->rw);
7765 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7766 lock_ReleaseWrite(&scp->rw);
7769 if (checkDoneRequired)
7770 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7771 cm_ReleaseSCache(scp);
7773 cm_ReleaseSCache(dscp);
7774 cm_ReleaseUser(userp);
7775 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7776 smb_CloseFID(vcp, fidp, NULL, 0);
7777 smb_ReleaseFID(fidp);
7783 /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
7784 if (checkDoneRequired) {
7785 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7786 checkDoneRequired = 0;
7789 lock_ObtainMutex(&fidp->mx);
7790 /* save a pointer to the vnode */
7791 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
7792 lock_ObtainWrite(&scp->rw);
7793 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7794 lock_ReleaseWrite(&scp->rw);
7795 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
7797 fidp->flags = fidflags;
7799 /* remember if the file was newly created */
7801 fidp->flags |= SMB_FID_CREATED;
7803 /* save parent dir and pathname for delete or change notification */
7804 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7805 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
7806 fidp->flags |= SMB_FID_NTOPEN;
7807 fidp->NTopen_dscp = dscp;
7809 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
7811 fidp->NTopen_wholepathp = realPathp;
7812 lock_ReleaseMutex(&fidp->mx);
7814 /* we don't need this any longer */
7816 cm_ReleaseSCache(dscp);
7820 cm_Open(scp, 0, userp);
7822 /* set inp->fid so that later read calls in same msg can find fid */
7823 inp->fid = fidp->fid;
7827 lock_ObtainRead(&scp->rw);
7828 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7829 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7830 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7831 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7832 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7833 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7834 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7835 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7836 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7838 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7839 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7840 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
7841 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
7842 smb_SetSMBParmByte(outp, parmSlot,
7843 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7844 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7845 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7846 smb_SetSMBDataLength(outp, 0);
7848 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
7849 LargeIntegerGreaterThanZero(scp->length) &&
7850 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
7853 lock_ReleaseRead(&scp->rw);
7856 cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
7857 scp->length.LowPart, scp->length.HighPart,
7861 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %S", fidp->fid,
7862 osi_LogSaveClientString(smb_logp, realPathp));
7864 cm_ReleaseUser(userp);
7865 smb_ReleaseFID(fidp);
7867 /* Can't free realPathp if we get here since
7868 fidp->NTopen_wholepathp is pointing there */
7870 /* leave scp held since we put it in fidp->scp */
7875 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
7876 * Instead, ultimately, would like to use a subroutine for common code.
7879 /* NT_TRANSACT_CREATE (SMB_COM_NT_TRANSACT) */
7880 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7882 clientchar_t *pathp, *realPathp;
7886 cm_scache_t *dscp; /* parent dir */
7887 cm_scache_t *scp; /* file to create or open */
7888 cm_scache_t *targetScp; /* if scp is a symlink */
7890 clientchar_t *lastNamep;
7891 unsigned long nameLength;
7893 unsigned int requestOpLock;
7894 unsigned int requestBatchOpLock;
7895 unsigned int mustBeDir;
7896 unsigned int extendedRespRequired;
7898 unsigned int desiredAccess;
7899 unsigned int allocSize;
7900 unsigned int shareAccess;
7901 unsigned int extAttributes;
7902 unsigned int createDisp;
7905 unsigned int impLevel;
7906 unsigned int secFlags;
7907 unsigned int createOptions;
7908 int initialModeBits;
7909 unsigned short baseFid;
7910 smb_fid_t *baseFidp;
7912 cm_scache_t *baseDirp;
7913 unsigned short openAction;
7917 clientchar_t *tidPathp;
7919 int parmOffset, dataOffset;
7926 cm_lock_data_t *ldp = NULL;
7927 int checkDoneRequired = 0;
7934 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7935 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7936 parmp = inp->data + parmOffset;
7937 lparmp = (ULONG *) parmp;
7940 requestOpLock = flags & REQUEST_OPLOCK;
7941 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7942 mustBeDir = flags & OPEN_DIRECTORY;
7943 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7946 * Why all of a sudden 32-bit FID?
7947 * We will reject all bits higher than 16.
7949 if (lparmp[1] & 0xFFFF0000)
7950 return CM_ERROR_INVAL;
7951 baseFid = (unsigned short)lparmp[1];
7952 desiredAccess = lparmp[2];
7953 allocSize = lparmp[3];
7954 extAttributes = lparmp[5];
7955 shareAccess = lparmp[6];
7956 createDisp = lparmp[7];
7957 createOptions = lparmp[8];
7960 nameLength = lparmp[11]; /* spec says chars but appears to be bytes */
7961 impLevel = lparmp[12];
7962 secFlags = lparmp[13];
7964 /* mustBeDir is never set; createOptions directory bit seems to be
7967 if (createOptions & FILE_DIRECTORY_FILE)
7969 else if (createOptions & FILE_NON_DIRECTORY_FILE)
7975 * compute initial mode bits based on read-only flag in
7976 * extended attributes
7978 initialModeBits = 0666;
7979 if (extAttributes & SMB_ATTR_READONLY)
7980 initialModeBits &= ~0222;
7982 pathp = smb_ParseStringCb(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
7983 nameLength, NULL, SMB_STRF_ANSIPATH);
7984 /* Sometimes path is not nul-terminated, so we make a copy. */
7985 realPathp = malloc(nameLength+sizeof(clientchar_t));
7986 memcpy(realPathp, pathp, nameLength);
7987 realPathp[nameLength/sizeof(clientchar_t)] = 0;
7988 spacep = cm_GetSpace();
7989 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
7991 osi_Log1(smb_logp,"NTTranCreate %S",osi_LogSaveStringW(smb_logp,realPathp));
7992 osi_Log4(smb_logp,"... da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
7993 osi_Log4(smb_logp,"... co[%x],sdl[%x],eal[%x],as[%x],flags[%x]",createOptions,sdLen,eaLen,allocSize);
7994 osi_Log3(smb_logp,"... imp[%x],sec[%x],flags[%x]", impLevel, secFlags, flags);
7997 * Nothing here to handle SMB_IOCTL_FILENAME.
7998 * Will add it if necessary.
8001 if (!cm_IsValidClientString(realPathp)) {
8003 clientchar_t * hexp;
8005 hexp = cm_GetRawCharsAlloc(realPathp, -1);
8006 osi_Log1(smb_logp, "NTTranCreate rejecting invalid name. [%S]",
8007 osi_LogSaveClientString(smb_logp, hexp));
8011 osi_Log0(smb_logp, "NTTranCreate rejecting invalid name.");
8014 return CM_ERROR_BADNTFILENAME;
8017 userp = smb_GetUserFromVCP(vcp, inp);
8019 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
8021 return CM_ERROR_INVAL;
8026 baseDirp = cm_data.rootSCachep;
8027 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8028 if (code == CM_ERROR_TIDIPC) {
8029 /* Attempt to use a TID allocated for IPC. The client
8030 * is probably looking for DCE RPC end points which we
8031 * don't support OR it could be looking to make a DFS
8034 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
8037 cm_ReleaseUser(userp);
8038 return CM_ERROR_NOSUCHPATH;
8042 baseFidp = smb_FindFID(vcp, baseFid, 0);
8044 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
8046 cm_ReleaseUser(userp);
8047 return CM_ERROR_BADFD;
8050 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8052 cm_ReleaseUser(userp);
8053 smb_CloseFID(vcp, baseFidp, NULL, 0);
8054 smb_ReleaseFID(baseFidp);
8055 return CM_ERROR_NOSUCHPATH;
8058 baseDirp = baseFidp->scp;
8062 /* compute open mode */
8064 if (desiredAccess & DELETE)
8065 fidflags |= SMB_FID_OPENDELETE;
8066 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
8067 fidflags |= SMB_FID_OPENREAD_LISTDIR;
8068 if (desiredAccess & AFS_ACCESS_WRITE)
8069 fidflags |= SMB_FID_OPENWRITE;
8070 if (createOptions & FILE_DELETE_ON_CLOSE)
8071 fidflags |= SMB_FID_DELONCLOSE;
8072 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
8073 fidflags |= SMB_FID_SEQUENTIAL;
8074 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
8075 fidflags |= SMB_FID_RANDOM;
8076 if (createOptions & FILE_OPEN_REPARSE_POINT)
8077 osi_Log0(smb_logp, "NTTranCreate Open Reparse Point");
8078 if (smb_IsExecutableFileName(lastNamep))
8079 fidflags |= SMB_FID_EXECUTABLE;
8081 /* And the share mode */
8082 if (shareAccess & FILE_SHARE_READ)
8083 fidflags |= SMB_FID_SHARE_READ;
8084 if (shareAccess & FILE_SHARE_WRITE)
8085 fidflags |= SMB_FID_SHARE_WRITE;
8089 if ( createDisp == FILE_OPEN ||
8090 createDisp == FILE_OVERWRITE ||
8091 createDisp == FILE_OVERWRITE_IF) {
8092 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8093 userp, tidPathp, &req, &dscp);
8096 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8097 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8098 cm_ReleaseSCache(dscp);
8099 cm_ReleaseUser(userp);
8102 smb_ReleaseFID(baseFidp);
8103 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8104 return CM_ERROR_PATH_NOT_COVERED;
8106 return CM_ERROR_NOSUCHPATH;
8108 #endif /* DFS_SUPPORT */
8109 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
8111 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
8112 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
8113 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
8114 if (code == 0 && realDirFlag == 1) {
8115 cm_ReleaseSCache(scp);
8116 cm_ReleaseSCache(dscp);
8117 cm_ReleaseUser(userp);
8120 smb_ReleaseFID(baseFidp);
8121 return CM_ERROR_EXISTS;
8127 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8128 userp, tidPathp, &req, &scp);
8130 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
8131 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
8132 cm_ReleaseSCache(scp);
8133 cm_ReleaseUser(userp);
8136 smb_ReleaseFID(baseFidp);
8137 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8138 return CM_ERROR_PATH_NOT_COVERED;
8140 return CM_ERROR_NOSUCHPATH;
8142 #endif /* DFS_SUPPORT */
8148 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
8149 /* look up parent directory */
8151 code = cm_NameI(baseDirp, spacep->wdata,
8152 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8153 userp, tidPathp, &req, &dscp);
8155 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8156 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8157 cm_ReleaseSCache(dscp);
8158 cm_ReleaseUser(userp);
8161 smb_ReleaseFID(baseFidp);
8162 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8163 return CM_ERROR_PATH_NOT_COVERED;
8165 return CM_ERROR_NOSUCHPATH;
8167 #endif /* DFS_SUPPORT */
8171 cm_FreeSpace(spacep);
8174 smb_ReleaseFID(baseFidp);
8177 cm_ReleaseUser(userp);
8183 lastNamep = realPathp;
8187 if (!smb_IsLegalFilename(lastNamep))
8188 return CM_ERROR_BADNTFILENAME;
8191 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
8192 code = cm_Lookup(dscp, lastNamep,
8193 CM_FLAG_FOLLOW, userp, &req, &scp);
8195 code = cm_Lookup(dscp, lastNamep,
8196 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8199 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8200 cm_ReleaseSCache(dscp);
8201 cm_ReleaseUser(userp);
8208 smb_ReleaseFID(baseFidp);
8209 cm_FreeSpace(spacep);
8212 /* if we get here, if code is 0, the file exists and is represented by
8213 * scp. Otherwise, we have to create it. The dir may be represented
8214 * by dscp, or we may have found the file directly. If code is non-zero,
8218 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
8220 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8222 cm_ReleaseSCache(dscp);
8223 cm_ReleaseSCache(scp);
8224 cm_ReleaseUser(userp);
8228 checkDoneRequired = 1;
8230 if (createDisp == FILE_CREATE) {
8231 /* oops, file shouldn't be there */
8232 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8234 cm_ReleaseSCache(dscp);
8235 cm_ReleaseSCache(scp);
8236 cm_ReleaseUser(userp);
8238 return CM_ERROR_EXISTS;
8241 if (createDisp == FILE_OVERWRITE ||
8242 createDisp == FILE_OVERWRITE_IF) {
8243 setAttr.mask = CM_ATTRMASK_LENGTH;
8244 setAttr.length.LowPart = 0;
8245 setAttr.length.HighPart = 0;
8247 /* now watch for a symlink */
8249 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8251 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8253 /* we have a more accurate file to use (the
8254 * target of the symbolic link). Otherwise,
8255 * we'll just use the symlink anyway.
8257 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8259 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8260 cm_ReleaseSCache(scp);
8262 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
8264 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8266 cm_ReleaseSCache(dscp);
8268 cm_ReleaseSCache(scp);
8269 cm_ReleaseUser(userp);
8275 code = cm_SetAttr(scp, &setAttr, userp, &req);
8276 openAction = 3; /* truncated existing file */
8278 else openAction = 1; /* found existing file */
8280 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
8281 /* don't create if not found */
8283 cm_ReleaseSCache(dscp);
8284 cm_ReleaseUser(userp);
8286 return CM_ERROR_NOSUCHFILE;
8288 else if (realDirFlag == 0 || realDirFlag == -1) {
8289 osi_assertx(dscp != NULL, "null cm_scache_t");
8290 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %S",
8291 osi_LogSaveClientString(smb_logp, lastNamep));
8292 openAction = 2; /* created file */
8293 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8294 setAttr.clientModTime = time(NULL);
8295 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8299 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8300 smb_NotifyChange(FILE_ACTION_ADDED,
8301 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8302 dscp, lastNamep, NULL, TRUE);
8303 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
8304 /* Not an exclusive create, and someone else tried
8305 * creating it already, then we open it anyway. We
8306 * don't bother retrying after this, since if this next
8307 * fails, that means that the file was deleted after we
8308 * started this call.
8310 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8313 if (createDisp == FILE_OVERWRITE_IF) {
8314 setAttr.mask = CM_ATTRMASK_LENGTH;
8315 setAttr.length.LowPart = 0;
8316 setAttr.length.HighPart = 0;
8318 /* now watch for a symlink */
8320 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8322 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8324 /* we have a more accurate file to use (the
8325 * target of the symbolic link). Otherwise,
8326 * we'll just use the symlink anyway.
8328 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8330 cm_ReleaseSCache(scp);
8334 code = cm_SetAttr(scp, &setAttr, userp, &req);
8336 } /* lookup succeeded */
8339 /* create directory */
8340 osi_assertx(dscp != NULL, "null cm_scache_t");
8342 "smb_ReceiveNTTranCreate creating directory %S",
8343 osi_LogSaveClientString(smb_logp, lastNamep));
8344 openAction = 2; /* created directory */
8345 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8346 setAttr.clientModTime = time(NULL);
8347 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8348 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8349 smb_NotifyChange(FILE_ACTION_ADDED,
8350 FILE_NOTIFY_CHANGE_DIR_NAME,
8351 dscp, lastNamep, NULL, TRUE);
8353 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
8354 /* Not an exclusive create, and someone else tried
8355 * creating it already, then we open it anyway. We
8356 * don't bother retrying after this, since if this next
8357 * fails, that means that the file was deleted after we
8358 * started this call.
8360 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8366 /* something went wrong creating or truncating the file */
8367 if (checkDoneRequired)
8368 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8370 cm_ReleaseSCache(scp);
8371 cm_ReleaseUser(userp);
8376 /* make sure we have file vs. dir right */
8377 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
8378 /* now watch for a symlink */
8380 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8382 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8384 /* we have a more accurate file to use (the
8385 * target of the symbolic link). Otherwise,
8386 * we'll just use the symlink anyway.
8388 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8390 if (checkDoneRequired) {
8391 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8392 checkDoneRequired = 0;
8394 cm_ReleaseSCache(scp);
8399 if (scp->fileType != CM_SCACHETYPE_FILE) {
8400 if (checkDoneRequired)
8401 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8402 cm_ReleaseSCache(scp);
8403 cm_ReleaseUser(userp);
8405 return CM_ERROR_ISDIR;
8409 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8410 if (checkDoneRequired)
8411 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8412 cm_ReleaseSCache(scp);
8413 cm_ReleaseUser(userp);
8415 return CM_ERROR_NOTDIR;
8418 /* open the file itself */
8419 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8420 osi_assertx(fidp, "null smb_fid_t");
8422 /* save a reference to the user */
8424 fidp->userp = userp;
8426 /* If we are restricting sharing, we should do so with a suitable
8428 if (scp->fileType == CM_SCACHETYPE_FILE &&
8429 !(fidflags & SMB_FID_SHARE_WRITE)) {
8431 LARGE_INTEGER LOffset, LLength;
8434 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8435 LOffset.LowPart = SMB_FID_QLOCK_LOW;
8436 LLength.HighPart = 0;
8437 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8439 /* Similar to what we do in handling NTCreateX. We get a
8440 shared lock if we are only opening the file for reading. */
8441 if ((fidflags & SMB_FID_SHARE_READ) ||
8442 !(fidflags & SMB_FID_OPENWRITE)) {
8443 sLockType = LOCKING_ANDX_SHARED_LOCK;
8448 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8450 lock_ObtainWrite(&scp->rw);
8451 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8452 lock_ReleaseWrite(&scp->rw);
8455 if (checkDoneRequired)
8456 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8457 cm_ReleaseSCache(scp);
8458 cm_ReleaseUser(userp);
8459 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
8460 smb_CloseFID(vcp, fidp, NULL, 0);
8461 smb_ReleaseFID(fidp);
8463 return CM_ERROR_SHARING_VIOLATION;
8467 /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
8468 if (checkDoneRequired) {
8469 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8470 checkDoneRequired = 0;
8473 lock_ObtainMutex(&fidp->mx);
8474 /* save a pointer to the vnode */
8476 lock_ObtainWrite(&scp->rw);
8477 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8478 lock_ReleaseWrite(&scp->rw);
8479 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
8481 fidp->flags = fidflags;
8483 /* remember if the file was newly created */
8485 fidp->flags |= SMB_FID_CREATED;
8487 /* save parent dir and pathname for deletion or change notification */
8488 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8489 fidp->flags |= SMB_FID_NTOPEN;
8490 fidp->NTopen_dscp = dscp;
8491 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
8493 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
8495 fidp->NTopen_wholepathp = realPathp;
8496 lock_ReleaseMutex(&fidp->mx);
8498 /* we don't need this any longer */
8500 cm_ReleaseSCache(dscp);
8502 cm_Open(scp, 0, userp);
8504 /* set inp->fid so that later read calls in same msg can find fid */
8505 inp->fid = fidp->fid;
8507 /* check whether we are required to send an extended response */
8508 if (!extendedRespRequired) {
8510 parmOffset = 8*4 + 39;
8511 parmOffset += 1; /* pad to 4 */
8512 dataOffset = parmOffset + 70;
8516 /* Total Parameter Count */
8517 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8518 /* Total Data Count */
8519 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8520 /* Parameter Count */
8521 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8522 /* Parameter Offset */
8523 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8524 /* Parameter Displacement */
8525 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8527 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8529 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8530 /* Data Displacement */
8531 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8532 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8533 smb_SetSMBDataLength(outp, 70);
8535 lock_ObtainRead(&scp->rw);
8536 outData = smb_GetSMBData(outp, NULL);
8537 outData++; /* round to get to parmOffset */
8538 *outData = 0; outData++; /* oplock */
8539 *outData = 0; outData++; /* reserved */
8540 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8541 *((ULONG *)outData) = openAction; outData += 4;
8542 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8543 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8544 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8545 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8546 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8547 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8548 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8549 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8550 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8551 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8552 *((USHORT *)outData) = 0; outData += 2; /* dev state */
8553 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8554 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8555 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8556 outData += 2; /* is a dir? */
8559 parmOffset = 8*4 + 39;
8560 parmOffset += 1; /* pad to 4 */
8561 dataOffset = parmOffset + 104;
8565 /* Total Parameter Count */
8566 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8567 /* Total Data Count */
8568 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8569 /* Parameter Count */
8570 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8571 /* Parameter Offset */
8572 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8573 /* Parameter Displacement */
8574 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8576 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8578 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8579 /* Data Displacement */
8580 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8581 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8582 smb_SetSMBDataLength(outp, 105);
8584 lock_ObtainRead(&scp->rw);
8585 outData = smb_GetSMBData(outp, NULL);
8586 outData++; /* round to get to parmOffset */
8587 *outData = 0; outData++; /* oplock */
8588 *outData = 1; outData++; /* response type */
8589 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8590 *((ULONG *)outData) = openAction; outData += 4;
8591 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8592 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8593 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8594 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8595 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8596 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8597 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8598 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8599 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8600 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8601 *((USHORT *)outData) = 0; outData += 2; /* dev state */
8602 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8603 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8604 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8605 outData += 1; /* is a dir? */
8606 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
8607 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
8608 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
8611 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
8612 LargeIntegerGreaterThanZero(scp->length) &&
8613 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
8616 lock_ReleaseRead(&scp->rw);
8619 cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
8620 scp->length.LowPart, scp->length.HighPart,
8623 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
8625 cm_ReleaseUser(userp);
8626 smb_ReleaseFID(fidp);
8628 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
8629 /* leave scp held since we put it in fidp->scp */
8633 /* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
8634 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
8637 smb_packet_t *savedPacketp;
8639 USHORT fid, watchtree;
8643 filter = smb_GetSMBParm(inp, 19) |
8644 (smb_GetSMBParm(inp, 20) << 16);
8645 fid = smb_GetSMBParm(inp, 21);
8646 watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
8648 fidp = smb_FindFID(vcp, fid, 0);
8650 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
8651 return CM_ERROR_BADFD;
8654 lock_ObtainMutex(&fidp->mx);
8655 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8656 lock_ReleaseMutex(&fidp->mx);
8657 smb_CloseFID(vcp, fidp, NULL, 0);
8658 smb_ReleaseFID(fidp);
8659 return CM_ERROR_NOSUCHFILE;
8663 lock_ReleaseMutex(&fidp->mx);
8665 /* Create a copy of the Directory Watch Packet to use when sending the
8666 * notification if in the future a matching change is detected.
8668 savedPacketp = smb_CopyPacket(inp);
8669 if (vcp != savedPacketp->vcp) {
8671 if (savedPacketp->vcp)
8672 smb_ReleaseVC(savedPacketp->vcp);
8673 savedPacketp->vcp = vcp;
8676 /* Add the watch to the list of events to send notifications for */
8677 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8678 savedPacketp->nextp = smb_Directory_Watches;
8679 smb_Directory_Watches = savedPacketp;
8680 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8682 osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%S\"",
8683 fidp, scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp));
8684 osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
8685 filter, fid, watchtree);
8686 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8687 osi_Log0(smb_logp, " Notify Change File Name");
8688 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8689 osi_Log0(smb_logp, " Notify Change Directory Name");
8690 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8691 osi_Log0(smb_logp, " Notify Change Attributes");
8692 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8693 osi_Log0(smb_logp, " Notify Change Size");
8694 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8695 osi_Log0(smb_logp, " Notify Change Last Write");
8696 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8697 osi_Log0(smb_logp, " Notify Change Last Access");
8698 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8699 osi_Log0(smb_logp, " Notify Change Creation");
8700 if (filter & FILE_NOTIFY_CHANGE_EA)
8701 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8702 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8703 osi_Log0(smb_logp, " Notify Change Security");
8704 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8705 osi_Log0(smb_logp, " Notify Change Stream Name");
8706 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8707 osi_Log0(smb_logp, " Notify Change Stream Size");
8708 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8709 osi_Log0(smb_logp, " Notify Change Stream Write");
8711 lock_ObtainWrite(&scp->rw);
8713 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
8715 scp->flags |= CM_SCACHEFLAG_WATCHED;
8716 lock_ReleaseWrite(&scp->rw);
8717 cm_ReleaseSCache(scp);
8718 smb_ReleaseFID(fidp);
8720 outp->flags |= SMB_PACKETFLAG_NOSEND;
8724 unsigned char nullSecurityDesc[36] = {
8725 0x01, /* security descriptor revision */
8726 0x00, /* reserved, should be zero */
8727 0x00, 0x80, /* security descriptor control;
8728 * 0x8000 : self-relative format */
8729 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
8730 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
8731 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
8732 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
8733 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8734 /* "null SID" owner SID */
8735 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
8736 /* "null SID" group SID */
8739 /* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
8740 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8742 int parmOffset, parmCount, dataOffset, dataCount;
8750 ULONG securityInformation;
8752 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8753 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8754 parmp = inp->data + parmOffset;
8755 sparmp = (USHORT *) parmp;
8756 lparmp = (ULONG *) parmp;
8759 securityInformation = lparmp[1];
8761 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
8762 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
8770 parmOffset = 8*4 + 39;
8771 parmOffset += 1; /* pad to 4 */
8773 dataOffset = parmOffset + parmCount;
8777 /* Total Parameter Count */
8778 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8779 /* Total Data Count */
8780 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8781 /* Parameter Count */
8782 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8783 /* Parameter Offset */
8784 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8785 /* Parameter Displacement */
8786 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8788 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8790 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8791 /* Data Displacement */
8792 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8793 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8794 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
8796 outData = smb_GetSMBData(outp, NULL);
8797 outData++; /* round to get to parmOffset */
8798 *((ULONG *)outData) = 36; outData += 4; /* length */
8800 if (maxData >= 36) {
8801 memcpy(outData, nullSecurityDesc, 36);
8805 return CM_ERROR_BUFFERTOOSMALL;
8808 /* SMB_COM_NT_TRANSACT
8810 SMB_COM_NT_TRANSACT_SECONDARY should also be handled here.
8812 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8814 unsigned short function;
8816 function = smb_GetSMBParm(inp, 18);
8818 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
8820 /* We can handle long names */
8821 if (vcp->flags & SMB_VCFLAG_USENT)
8822 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
8825 case 1: /* NT_TRANSACT_CREATE */
8826 return smb_ReceiveNTTranCreate(vcp, inp, outp);
8827 case 2: /* NT_TRANSACT_IOCTL */
8828 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
8830 case 3: /* NT_TRANSACT_SET_SECURITY_DESC */
8831 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
8833 case 4: /* NT_TRANSACT_NOTIFY_CHANGE */
8834 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
8835 case 5: /* NT_TRANSACT_RENAME */
8836 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
8838 case 6: /* NT_TRANSACT_QUERY_SECURITY_DESC */
8839 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
8841 osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
8844 osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
8847 return CM_ERROR_INVAL;
8851 * smb_NotifyChange -- find relevant change notification messages and
8854 * If we don't know the file name (i.e. a callback break), filename is
8855 * NULL, and we return a zero-length list.
8857 * At present there is not a single call to smb_NotifyChange that
8858 * has the isDirectParent parameter set to FALSE.
8860 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
8861 cm_scache_t *dscp, clientchar_t *filename, clientchar_t *otherFilename,
8862 BOOL isDirectParent)
8864 smb_packet_t *watch, *lastWatch, *nextWatch;
8865 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen = 0;
8866 char *outData, *oldOutData;
8870 BOOL twoEntries = FALSE;
8871 ULONG otherNameLen, oldParmCount = 0;
8875 /* Get ready for rename within directory */
8876 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
8878 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
8881 osi_Log4(smb_logp,"in smb_NotifyChange for file [%S] dscp [%p] notification 0x%x parent %d",
8882 osi_LogSaveClientString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
8884 osi_Log0(smb_logp," FILE_ACTION_NONE");
8885 if (action == FILE_ACTION_ADDED)
8886 osi_Log0(smb_logp," FILE_ACTION_ADDED");
8887 if (action == FILE_ACTION_REMOVED)
8888 osi_Log0(smb_logp," FILE_ACTION_REMOVED");
8889 if (action == FILE_ACTION_MODIFIED)
8890 osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
8891 if (action == FILE_ACTION_RENAMED_OLD_NAME)
8892 osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
8893 if (action == FILE_ACTION_RENAMED_NEW_NAME)
8894 osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
8896 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8897 watch = smb_Directory_Watches;
8899 filter = smb_GetSMBParm(watch, 19)
8900 | (smb_GetSMBParm(watch, 20) << 16);
8901 fid = smb_GetSMBParm(watch, 21);
8902 wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
8904 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
8905 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
8908 * Strange hack - bug in NT Client and NT Server that we must emulate?
8910 if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
8911 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
8913 fidp = smb_FindFID(watch->vcp, fid, 0);
8915 osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
8917 watch = watch->nextp;
8921 if (fidp->scp != dscp ||
8922 fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
8923 (filter & notifyFilter) == 0 ||
8924 (!isDirectParent && !wtree))
8926 osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
8928 watch = watch->nextp;
8929 smb_ReleaseFID(fidp);
8934 "Sending Change Notification for fid %d filter 0x%x wtree %d file %S",
8935 fid, filter, wtree, osi_LogSaveClientString(smb_logp, filename));
8936 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8937 osi_Log0(smb_logp, " Notify Change File Name");
8938 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8939 osi_Log0(smb_logp, " Notify Change Directory Name");
8940 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8941 osi_Log0(smb_logp, " Notify Change Attributes");
8942 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8943 osi_Log0(smb_logp, " Notify Change Size");
8944 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8945 osi_Log0(smb_logp, " Notify Change Last Write");
8946 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8947 osi_Log0(smb_logp, " Notify Change Last Access");
8948 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8949 osi_Log0(smb_logp, " Notify Change Creation");
8950 if (filter & FILE_NOTIFY_CHANGE_EA)
8951 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8952 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8953 osi_Log0(smb_logp, " Notify Change Security");
8954 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8955 osi_Log0(smb_logp, " Notify Change Stream Name");
8956 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8957 osi_Log0(smb_logp, " Notify Change Stream Size");
8958 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8959 osi_Log0(smb_logp, " Notify Change Stream Write");
8961 /* A watch can only be notified once. Remove it from the list */
8962 nextWatch = watch->nextp;
8963 if (watch == smb_Directory_Watches)
8964 smb_Directory_Watches = nextWatch;
8966 lastWatch->nextp = nextWatch;
8968 /* Turn off WATCHED flag in dscp */
8969 lock_ObtainWrite(&dscp->rw);
8971 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8973 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
8974 lock_ReleaseWrite(&dscp->rw);
8976 /* Convert to response packet */
8977 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
8978 #ifdef SEND_CANONICAL_PATHNAMES
8979 ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
8981 ((smb_t *) watch)->wct = 0;
8984 if (filename == NULL) {
8987 nameLen = (ULONG)cm_ClientStrLen(filename);
8988 parmCount = 3*4 + nameLen*2;
8989 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8991 otherNameLen = (ULONG)cm_ClientStrLen(otherFilename);
8992 oldParmCount = parmCount;
8993 parmCount += 3*4 + otherNameLen*2;
8994 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8996 if (maxLen < parmCount)
8997 parmCount = 0; /* not enough room */
8999 parmOffset = 8*4 + 39;
9000 parmOffset += 1; /* pad to 4 */
9001 dataOffset = parmOffset + parmCount;
9005 /* Total Parameter Count */
9006 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
9007 /* Total Data Count */
9008 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9009 /* Parameter Count */
9010 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
9011 /* Parameter Offset */
9012 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
9013 /* Parameter Displacement */
9014 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9016 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9018 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
9019 /* Data Displacement */
9020 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9021 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
9022 smb_SetSMBDataLength(watch, parmCount + 1);
9024 if (parmCount != 0) {
9025 outData = smb_GetSMBData(watch, NULL);
9026 outData++; /* round to get to parmOffset */
9027 oldOutData = outData;
9028 *((DWORD *)outData) = oldParmCount; outData += 4;
9029 /* Next Entry Offset */
9030 *((DWORD *)outData) = action; outData += 4;
9032 *((DWORD *)outData) = nameLen*2; outData += 4;
9033 /* File Name Length */
9035 smb_UnparseString(watch, outData, filename, NULL, 0);
9039 outData = oldOutData + oldParmCount;
9040 *((DWORD *)outData) = 0; outData += 4;
9041 /* Next Entry Offset */
9042 *((DWORD *)outData) = otherAction; outData += 4;
9044 *((DWORD *)outData) = otherNameLen*2;
9045 outData += 4; /* File Name Length */
9046 smb_UnparseString(watch, outData, otherFilename, NULL, 0);
9051 * If filename is null, we don't know the cause of the
9052 * change notification. We return zero data (see above),
9053 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
9054 * (= 0x010C). We set the error code here by hand, without
9055 * modifying wct and bcc.
9057 if (filename == NULL) {
9058 ((smb_t *) watch)->rcls = 0x0C;
9059 ((smb_t *) watch)->reh = 0x01;
9060 ((smb_t *) watch)->errLow = 0;
9061 ((smb_t *) watch)->errHigh = 0;
9062 /* Set NT Status codes flag */
9063 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9066 smb_SendPacket(watch->vcp, watch);
9067 smb_FreePacket(watch);
9069 smb_ReleaseFID(fidp);
9072 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9075 /* SMB_COM_NT_CANCEL */
9076 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9078 unsigned char *replyWctp;
9079 smb_packet_t *watch, *lastWatch;
9080 USHORT fid, watchtree;
9084 osi_Log0(smb_logp, "SMB3 receive NT cancel");
9086 lock_ObtainMutex(&smb_Dir_Watch_Lock);
9087 watch = smb_Directory_Watches;
9089 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
9090 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
9091 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
9092 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
9093 if (watch == smb_Directory_Watches)
9094 smb_Directory_Watches = watch->nextp;
9096 lastWatch->nextp = watch->nextp;
9097 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9099 /* Turn off WATCHED flag in scp */
9100 fid = smb_GetSMBParm(watch, 21);
9101 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
9103 if (vcp != watch->vcp)
9104 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
9107 fidp = smb_FindFID(vcp, fid, 0);
9109 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %S",
9111 (fidp ? osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp) :_C("")));
9114 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
9116 lock_ObtainWrite(&scp->rw);
9118 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
9120 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
9121 lock_ReleaseWrite(&scp->rw);
9123 smb_ReleaseFID(fidp);
9125 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
9128 /* assume STATUS32; return 0xC0000120 (CANCELED) */
9129 replyWctp = watch->wctp;
9133 ((smb_t *)watch)->rcls = 0x20;
9134 ((smb_t *)watch)->reh = 0x1;
9135 ((smb_t *)watch)->errLow = 0;
9136 ((smb_t *)watch)->errHigh = 0xC0;
9137 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9138 smb_SendPacket(vcp, watch);
9139 smb_FreePacket(watch);
9143 watch = watch->nextp;
9145 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9151 * NT rename also does hard links.
9154 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
9155 #define RENAME_FLAG_HARD_LINK 0x103
9156 #define RENAME_FLAG_RENAME 0x104
9157 #define RENAME_FLAG_COPY 0x105
9159 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9161 clientchar_t *oldPathp, *newPathp;
9167 attrs = smb_GetSMBParm(inp, 0);
9168 rename_type = smb_GetSMBParm(inp, 1);
9170 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
9171 osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
9172 return CM_ERROR_NOACCESS;
9175 tp = smb_GetSMBData(inp, NULL);
9176 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
9178 return CM_ERROR_BADSMB;
9179 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
9181 return CM_ERROR_BADSMB;
9183 osi_Log3(smb_logp, "NTRename for [%S]->[%S] type [%s]",
9184 osi_LogSaveClientString(smb_logp, oldPathp),
9185 osi_LogSaveClientString(smb_logp, newPathp),
9186 ((rename_type==RENAME_FLAG_RENAME)?"rename":(rename_type==RENAME_FLAG_HARD_LINK)?"hardlink":"other"));
9188 if (rename_type == RENAME_FLAG_RENAME) {
9189 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
9190 } else if (rename_type == RENAME_FLAG_HARD_LINK) { /* RENAME_FLAG_HARD_LINK */
9191 code = smb_Link(vcp,inp,oldPathp,newPathp);
9193 code = CM_ERROR_BADOP;
9199 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock", LOCK_HIERARCHY_SMB_DIRWATCH);
9202 cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
9204 smb_username_t *unp;
9207 unp = smb_FindUserByName(usern, machine, flags);
9209 lock_ObtainMutex(&unp->mx);
9210 unp->userp = cm_NewUser();
9211 lock_ReleaseMutex(&unp->mx);
9212 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9214 osi_Log2(smb_logp,"smb_FindCMUserByName Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9218 smb_ReleaseUsername(unp);