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>
35 extern osi_hyper_t hzero;
37 smb_packet_t *smb_Directory_Watches = NULL;
38 osi_mutex_t smb_Dir_Watch_Lock;
40 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
42 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
44 /* protected by the smb_globalLock */
45 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
47 const clientchar_t **smb_ExecutableExtensions = NULL;
49 /* retrieve a held reference to a user structure corresponding to an incoming
51 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
56 uidp = smb_FindUID(vcp, inp->uid, 0);
60 up = smb_GetUserFromUID(uidp);
68 * Return boolean specifying if the path name is thought to be an
69 * executable file. For now .exe or .dll.
71 afs_uint32 smb_IsExecutableFileName(const clientchar_t *name)
75 if ( smb_ExecutableExtensions == NULL || name == NULL)
78 len = (int)cm_ClientStrLen(name);
80 for ( i=0; smb_ExecutableExtensions[i]; i++) {
81 j = len - (int)cm_ClientStrLen(smb_ExecutableExtensions[i]);
82 if (cm_ClientStrCmpI(smb_ExecutableExtensions[i], &name[j]) == 0)
90 * Return extended attributes.
91 * Right now, we aren't using any of the "new" bits, so this looks exactly
92 * like smb_Attributes() (see smb.c).
94 unsigned long smb_ExtAttributes(cm_scache_t *scp)
98 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
99 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
100 scp->fileType == CM_SCACHETYPE_INVALID)
102 attrs = SMB_ATTR_DIRECTORY;
103 #ifdef SPECIAL_FOLDERS
104 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
105 #endif /* SPECIAL_FOLDERS */
106 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
107 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
108 } else if (scp->fid.vnode & 0x1)
109 attrs = SMB_ATTR_DIRECTORY;
114 * We used to mark a file RO if it was in an RO volume, but that
115 * turns out to be impolitic in NT. See defect 10007.
118 if ((scp->unixModeBits & 0200) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
119 attrs |= SMB_ATTR_READONLY; /* Read-only */
121 if ((scp->unixModeBits & 0200) == 0)
122 attrs |= SMB_ATTR_READONLY; /* Read-only */
126 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
131 int smb_V3IsStarMask(clientchar_t *maskp)
135 while (tc = *maskp++)
136 if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
141 void OutputDebugF(clientchar_t * format, ...) {
143 clientchar_t vbuffer[1024];
145 va_start( args, format );
146 cm_ClientStrPrintfV(vbuffer, lengthof(vbuffer), format, args);
147 osi_Log1(smb_logp, "%S", osi_LogSaveClientString(smb_logp, vbuffer));
150 void OutputDebugHexDump(unsigned char * buffer, int len) {
153 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
155 OutputDebugF(_C("Hexdump length [%d]"),len);
157 for (i=0;i<len;i++) {
160 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
162 StringCchPrintfA(buf, lengthof(buf), "%5x", i);
163 memset(buf+5,' ',80);
168 j = j*3 + 7 + ((j>7)?1:0);
171 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
174 j = j + 56 + ((j>7)?1:0);
176 buf[j] = (k>32 && k<127)?k:'.';
179 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
183 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
185 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
186 SECURITY_STATUS status, istatus;
187 CredHandle creds = {0,0};
189 SecBufferDesc secOut;
197 OutputDebugF(_C("Negotiating Extended Security"));
199 status = AcquireCredentialsHandle( NULL,
200 SMB_EXT_SEC_PACKAGE_NAME,
209 if (status != SEC_E_OK) {
210 /* Really bad. We return an empty security blob */
211 OutputDebugF(_C("AcquireCredentialsHandle failed with %lX"), status);
216 secOut.pBuffers = &secTok;
217 secOut.ulVersion = SECBUFFER_VERSION;
219 secTok.BufferType = SECBUFFER_TOKEN;
221 secTok.pvBuffer = NULL;
223 ctx.dwLower = ctx.dwUpper = 0;
225 status = AcceptSecurityContext( &creds,
228 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
229 SECURITY_NETWORK_DREP,
236 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
237 OutputDebugF(_C("Completing token..."));
238 istatus = CompleteAuthToken(&ctx, &secOut);
239 if ( istatus != SEC_E_OK )
240 OutputDebugF(_C("Token completion failed: %x"), istatus);
243 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
244 if (secTok.pvBuffer) {
245 *secBlobLength = secTok.cbBuffer;
246 *secBlob = malloc( secTok.cbBuffer );
247 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
250 if ( status != SEC_E_OK )
251 OutputDebugF(_C("AcceptSecurityContext status != CONTINUE %lX"), status);
254 /* Discard partial security context */
255 DeleteSecurityContext(&ctx);
257 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
259 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
260 FreeCredentialsHandle(&creds);
266 struct smb_ext_context {
273 long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern,
274 char * secBlobIn, int secBlobInLength,
275 char ** secBlobOut, int * secBlobOutLength) {
276 SECURITY_STATUS status, istatus;
280 SecBufferDesc secBufIn;
282 SecBufferDesc secBufOut;
285 struct smb_ext_context * secCtx = NULL;
286 struct smb_ext_context * newSecCtx = NULL;
287 void * assembledBlob = NULL;
288 int assembledBlobLength = 0;
291 OutputDebugF(_C("In smb_AuthenticateUserExt"));
294 *secBlobOutLength = 0;
296 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
297 secCtx = vcp->secCtx;
298 lock_ObtainMutex(&vcp->mx);
299 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
301 lock_ReleaseMutex(&vcp->mx);
305 OutputDebugF(_C("Received incoming token:"));
306 OutputDebugHexDump(secBlobIn,secBlobInLength);
310 OutputDebugF(_C("Continuing with existing context."));
311 creds = secCtx->creds;
314 if (secCtx->partialToken) {
315 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
316 assembledBlob = malloc(assembledBlobLength);
317 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
318 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
321 status = AcquireCredentialsHandle( NULL,
322 SMB_EXT_SEC_PACKAGE_NAME,
331 if (status != SEC_E_OK) {
332 OutputDebugF(_C("Can't acquire Credentials handle [%lX]"), status);
333 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
341 secBufIn.cBuffers = 1;
342 secBufIn.pBuffers = &secTokIn;
343 secBufIn.ulVersion = SECBUFFER_VERSION;
345 secTokIn.BufferType = SECBUFFER_TOKEN;
347 secTokIn.cbBuffer = assembledBlobLength;
348 secTokIn.pvBuffer = assembledBlob;
350 secTokIn.cbBuffer = secBlobInLength;
351 secTokIn.pvBuffer = secBlobIn;
354 secBufOut.cBuffers = 1;
355 secBufOut.pBuffers = &secTokOut;
356 secBufOut.ulVersion = SECBUFFER_VERSION;
358 secTokOut.BufferType = SECBUFFER_TOKEN;
359 secTokOut.cbBuffer = 0;
360 secTokOut.pvBuffer = NULL;
362 status = AcceptSecurityContext( &creds,
363 ((secCtx)?&ctx:NULL),
365 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
366 SECURITY_NETWORK_DREP,
373 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
374 OutputDebugF(_C("Completing token..."));
375 istatus = CompleteAuthToken(&ctx, &secBufOut);
376 if ( istatus != SEC_E_OK )
377 OutputDebugF(_C("Token completion failed: %lX"), istatus);
380 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
381 OutputDebugF(_C("Continue needed"));
383 newSecCtx = malloc(sizeof(*newSecCtx));
385 newSecCtx->creds = creds;
386 newSecCtx->ctx = ctx;
387 newSecCtx->partialToken = NULL;
388 newSecCtx->partialTokenLen = 0;
390 lock_ObtainMutex( &vcp->mx );
391 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
392 vcp->secCtx = newSecCtx;
393 lock_ReleaseMutex( &vcp->mx );
395 code = CM_ERROR_GSSCONTINUE;
398 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
399 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
400 secTokOut.pvBuffer) {
401 OutputDebugF(_C("Need to send token back to client"));
403 *secBlobOutLength = secTokOut.cbBuffer;
404 *secBlobOut = malloc(secTokOut.cbBuffer);
405 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
407 OutputDebugF(_C("Outgoing token:"));
408 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
409 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
410 OutputDebugF(_C("Incomplete message"));
412 newSecCtx = malloc(sizeof(*newSecCtx));
414 newSecCtx->creds = creds;
415 newSecCtx->ctx = ctx;
416 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
417 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
418 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
420 lock_ObtainMutex( &vcp->mx );
421 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
422 vcp->secCtx = newSecCtx;
423 lock_ReleaseMutex( &vcp->mx );
425 code = CM_ERROR_GSSCONTINUE;
428 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
430 SecPkgContext_NamesW names;
432 OutputDebugF(_C("Authentication completed"));
433 OutputDebugF(_C("Returned flags : [%lX]"), flags);
435 if (!QueryContextAttributesW(&ctx, SECPKG_ATTR_NAMES, &names)) {
436 OutputDebugF(_C("Received name [%s]"), names.sUserName);
437 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, names.sUserName);
438 cm_ClientStrLwr(usern); /* in tandem with smb_GetNormalizedUsername */
439 FreeContextBuffer(names.sUserName);
441 /* Force the user to retry if the context is invalid */
442 OutputDebugF(_C("QueryContextAttributes Names failed [%x]"), GetLastError());
443 code = CM_ERROR_BADPASSWORD;
447 case SEC_E_INVALID_TOKEN:
448 OutputDebugF(_C("Returning bad password :: INVALID_TOKEN"));
450 case SEC_E_INVALID_HANDLE:
451 OutputDebugF(_C("Returning bad password :: INVALID_HANDLE"));
453 case SEC_E_LOGON_DENIED:
454 OutputDebugF(_C("Returning bad password :: LOGON_DENIED"));
456 case SEC_E_UNKNOWN_CREDENTIALS:
457 OutputDebugF(_C("Returning bad password :: UNKNOWN_CREDENTIALS"));
459 case SEC_E_NO_CREDENTIALS:
460 OutputDebugF(_C("Returning bad password :: NO_CREDENTIALS"));
462 case SEC_E_CONTEXT_EXPIRED:
463 OutputDebugF(_C("Returning bad password :: CONTEXT_EXPIRED"));
465 case SEC_E_INCOMPLETE_CREDENTIALS:
466 OutputDebugF(_C("Returning bad password :: INCOMPLETE_CREDENTIALS"));
468 case SEC_E_WRONG_PRINCIPAL:
469 OutputDebugF(_C("Returning bad password :: WRONG_PRINCIPAL"));
471 case SEC_E_TIME_SKEW:
472 OutputDebugF(_C("Returning bad password :: TIME_SKEW"));
475 OutputDebugF(_C("Returning bad password :: Status == %lX"), status);
477 code = CM_ERROR_BADPASSWORD;
481 if (secCtx->partialToken) free(secCtx->partialToken);
489 if (secTokOut.pvBuffer)
490 FreeContextBuffer(secTokOut.pvBuffer);
492 if (code != CM_ERROR_GSSCONTINUE) {
493 DeleteSecurityContext(&ctx);
494 FreeCredentialsHandle(&creds);
502 #define P_RESP_LEN 128
504 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
505 So put stuff in a struct. */
506 struct Lm20AuthBlob {
507 MSV1_0_LM20_LOGON lmlogon;
508 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
509 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
510 WCHAR accountNameW[P_LEN];
511 WCHAR primaryDomainW[P_LEN];
512 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
513 TOKEN_GROUPS tgroups;
514 TOKEN_SOURCE tsource;
517 long smb_AuthenticateUserLM(smb_vc_t *vcp, clientchar_t * accountName, clientchar_t * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
520 struct Lm20AuthBlob lmAuth;
521 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
522 QUOTA_LIMITS quotaLimits;
524 ULONG lmprofilepSize;
528 OutputDebugF(_C("In smb_AuthenticateUser for user [%s] domain [%s]"), accountName, primaryDomain);
529 OutputDebugF(_C("ciPwdLength is %d and csPwdLength is %d"), ciPwdLength, csPwdLength);
531 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
532 OutputDebugF(_C("ciPwdLength or csPwdLength is too long"));
533 return CM_ERROR_BADPASSWORD;
536 memset(&lmAuth,0,sizeof(lmAuth));
538 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
540 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
541 cm_ClientStringToUtf16(primaryDomain, -1, lmAuth.primaryDomainW, P_LEN);
542 lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
543 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
545 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
546 cm_ClientStringToUtf16(accountName, -1, lmAuth.accountNameW, P_LEN);
547 lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
548 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
550 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
551 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
552 size = MAX_COMPUTERNAME_LENGTH + 1;
553 GetComputerNameW(lmAuth.workstationW, &size);
554 lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
556 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
558 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
559 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
560 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
561 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
563 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
564 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
565 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
566 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
568 lmAuth.lmlogon.ParameterControl = 0;
570 lmAuth.tgroups.GroupCount = 0;
571 lmAuth.tgroups.Groups[0].Sid = NULL;
572 lmAuth.tgroups.Groups[0].Attributes = 0;
575 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
577 lmAuth.tsource.SourceIdentifier.HighPart = 0;
579 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
580 StringCchCopyA(lmAuth.tsource.SourceName, lengthof(lmAuth.tsource.SourceName),
581 "OpenAFS"); /* 8 char limit */
583 nts = LsaLogonUser( smb_lsaHandle,
598 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
599 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
602 OutputDebugF(_C("Return from LsaLogonUser is 0x%lX"), nts);
603 OutputDebugF(_C("Extended status is 0x%lX"), ntsEx);
605 if (nts == ERROR_SUCCESS) {
607 LsaFreeReturnBuffer(lmprofilep);
608 CloseHandle(lmToken);
612 if (nts == 0xC000015BL)
613 return CM_ERROR_BADLOGONTYPE;
614 else /* our catchall is a bad password though we could be more specific */
615 return CM_ERROR_BADPASSWORD;
619 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
620 long smb_GetNormalizedUsername(clientchar_t * usern, const clientchar_t * accountName, const clientchar_t * domainName)
622 clientchar_t * atsign;
623 const clientchar_t * domain;
625 /* check if we have sane input */
626 if ((cm_ClientStrLen(accountName) + cm_ClientStrLen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
629 /* we could get : [accountName][domainName]
635 atsign = cm_ClientStrChr(accountName, '@');
637 if (atsign) /* [user@domain][] -> [user@domain][domain] */
642 /* if for some reason the client doesn't know what domain to use,
643 it will either return an empty string or a '?' */
644 if (!domain[0] || domain[0] == '?')
645 /* Empty domains and empty usernames are usually sent from tokenless contexts.
646 This way such logins will get an empty username (easy to check). I don't know
647 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
648 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, accountName);
650 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
651 cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, domain);
652 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, _C("\\"));
654 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
656 cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
659 cm_ClientStrLwr(usern);
664 /* When using SMB auth, all SMB sessions have to pass through here
665 * first to authenticate the user.
667 * Caveat: If not using SMB auth, the protocol does not require
668 * sending a session setup packet, which means that we can't rely on a
669 * UID in subsequent packets. Though in practice we get one anyway.
671 /* SMB_COM_SESSION_SETUP_ANDX */
672 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
676 unsigned short newUid;
677 unsigned long caps = 0;
679 clientchar_t *s1 = _C(" ");
681 clientchar_t usern[SMB_MAX_USERNAME_LENGTH];
682 char *secBlobOut = NULL;
683 int secBlobOutLength = 0;
684 int maxBufferSize = 0;
688 /* Check for bad conns */
689 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
690 return CM_ERROR_REMOTECONN;
693 maxBufferSize = smb_GetSMBParm(inp, 2);
694 maxMpxCount = smb_GetSMBParm(inp, 3);
695 vcNumber = smb_GetSMBParm(inp, 4);
697 osi_Log3(smb_logp, "SESSION_SETUP_ANDX with MaxBufferSize=%d, MaxMpxCount=%d, VCNumber=%d",
698 maxBufferSize, maxMpxCount, vcNumber);
700 if (maxMpxCount > smb_maxMpxRequests) {
701 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_MPX_COUNT, maxMpxCount, smb_maxMpxRequests);
702 osi_Log2(smb_logp, "MaxMpxCount for client is too large (Client=%d, Server=%d)",
703 maxMpxCount, smb_maxMpxRequests);
706 if (maxBufferSize < SMB_PACKETSIZE) {
707 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_BUFFER_SIZE, maxBufferSize, SMB_PACKETSIZE);
708 osi_Log2(smb_logp, "MaxBufferSize for client is too small (Client=%d, Server=%d)",
709 maxBufferSize, SMB_PACKETSIZE);
713 osi_Log0(smb_logp, "Resetting all VCs");
714 smb_MarkAllVCsDead(vcp);
717 if (vcp->flags & SMB_VCFLAG_USENT) {
718 if (smb_authType == SMB_AUTH_EXTENDED) {
719 /* extended authentication */
723 OutputDebugF(_C("NT Session Setup: Extended"));
725 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
726 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
729 secBlobInLength = smb_GetSMBParm(inp, 7);
730 secBlobIn = smb_GetSMBData(inp, NULL);
732 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
734 if (code == CM_ERROR_GSSCONTINUE) {
737 smb_SetSMBParm(outp, 2, 0);
738 smb_SetSMBParm(outp, 3, secBlobOutLength);
740 tp = smb_GetSMBData(outp, NULL);
741 if (secBlobOutLength) {
742 memcpy(tp, secBlobOut, secBlobOutLength);
744 tp += secBlobOutLength;
745 cb_data += secBlobOutLength;
747 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
748 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
749 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
751 smb_SetSMBDataLength(outp, cb_data);
754 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
756 unsigned ciPwdLength, csPwdLength;
758 clientchar_t *accountName;
759 clientchar_t *primaryDomain;
762 if (smb_authType == SMB_AUTH_NTLM)
763 OutputDebugF(_C("NT Session Setup: NTLM"));
765 OutputDebugF(_C("NT Session Setup: None"));
767 /* TODO: parse for extended auth as well */
768 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
769 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
771 tp = smb_GetSMBData(inp, &datalen);
773 OutputDebugF(_C("Session packet data size [%d]"),datalen);
780 accountName = smb_ParseString(inp, tp, &tp, 0);
781 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
783 OutputDebugF(_C("Account Name: %s"),accountName);
784 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
785 OutputDebugF(_C("Case Sensitive Password: %s"),
786 csPwd && csPwd[0] ? _C("yes") : _C("no"));
787 OutputDebugF(_C("Case Insensitive Password: %s"),
788 ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
790 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
791 /* shouldn't happen */
792 code = CM_ERROR_BADSMB;
793 goto after_read_packet;
796 /* capabilities are only valid for first session packet */
797 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
798 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
801 if (smb_authType == SMB_AUTH_NTLM) {
802 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
804 OutputDebugF(_C("LM authentication failed [%d]"), code);
806 OutputDebugF(_C("LM authentication succeeded"));
810 unsigned ciPwdLength;
812 clientchar_t *accountName;
813 clientchar_t *primaryDomain;
815 switch ( smb_authType ) {
816 case SMB_AUTH_EXTENDED:
817 OutputDebugF(_C("V3 Session Setup: Extended"));
820 OutputDebugF(_C("V3 Session Setup: NTLM"));
823 OutputDebugF(_C("V3 Session Setup: None"));
825 ciPwdLength = smb_GetSMBParm(inp, 7);
826 tp = smb_GetSMBData(inp, NULL);
830 accountName = smb_ParseString(inp, tp, &tp, 0);
831 primaryDomain = smb_ParseString(inp, tp, NULL, 0);
833 OutputDebugF(_C("Account Name: %s"),accountName);
834 OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
835 OutputDebugF(_C("Case Insensitive Password: %s"), ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
837 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
838 /* shouldn't happen */
839 code = CM_ERROR_BADSMB;
840 goto after_read_packet;
843 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
846 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
847 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
849 OutputDebugF(_C("LM authentication failed [%d]"), code);
851 OutputDebugF(_C("LM authentication succeeded"));
856 /* note down that we received a session setup X and set the capabilities flag */
857 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
858 lock_ObtainMutex(&vcp->mx);
859 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
860 /* for the moment we can only deal with NTSTATUS */
861 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
862 vcp->flags |= SMB_VCFLAG_STATUS32;
866 if ((caps & NTNEGOTIATE_CAPABILITY_UNICODE) && smb_UseUnicode) {
867 vcp->flags |= SMB_VCFLAG_USEUNICODE;
870 lock_ReleaseMutex(&vcp->mx);
873 /* code would be non-zero if there was an authentication failure.
874 Ideally we would like to invalidate the uid for this session or break
875 early to avoid accidently stealing someone else's tokens. */
881 OutputDebugF(_C("Received username=[%s]"), usern);
883 /* On Windows 2000, this function appears to be called more often than
884 it is expected to be called. This resulted in multiple smb_user_t
885 records existing all for the same user session which results in all
886 of the users tokens disappearing.
888 To avoid this problem, we look for an existing smb_user_t record
889 based on the users name, and use that one if we find it.
892 uidp = smb_FindUserByNameThisSession(vcp, usern);
893 if (uidp) { /* already there, so don't create a new one */
895 newUid = uidp->userID;
896 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
897 vcp->lana,vcp->lsn,newUid);
898 smb_ReleaseUID(uidp);
903 /* do a global search for the username/machine name pair */
904 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
905 lock_ObtainMutex(&unp->mx);
906 if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
907 /* clear the afslogon flag so that the tickets can now
908 * be freed when the refCount returns to zero.
910 unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
912 lock_ReleaseMutex(&unp->mx);
914 /* Create a new UID and cm_user_t structure */
917 userp = cm_NewUser();
918 cm_HoldUserVCRef(userp);
919 lock_ObtainMutex(&vcp->mx);
920 if (!vcp->uidCounter)
921 vcp->uidCounter++; /* handle unlikely wraparounds */
922 newUid = (cm_ClientStrLen(usern)==0)?0:vcp->uidCounter++;
923 lock_ReleaseMutex(&vcp->mx);
925 /* Create a new smb_user_t structure and connect them up */
926 lock_ObtainMutex(&unp->mx);
928 lock_ReleaseMutex(&unp->mx);
930 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
932 lock_ObtainMutex(&uidp->mx);
934 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
935 lock_ReleaseMutex(&uidp->mx);
936 smb_ReleaseUID(uidp);
940 /* Return UID to the client */
941 ((smb_t *)outp)->uid = newUid;
942 /* Also to the next chained message */
943 ((smb_t *)inp)->uid = newUid;
945 osi_Log3(smb_logp, "SMB3 session setup name %S creating ID %d%S",
946 osi_LogSaveClientString(smb_logp, usern), newUid,
947 osi_LogSaveClientString(smb_logp, s1));
949 smb_SetSMBParm(outp, 2, 0);
951 if (vcp->flags & SMB_VCFLAG_USENT) {
952 if (smb_authType == SMB_AUTH_EXTENDED) {
955 smb_SetSMBParm(outp, 3, secBlobOutLength);
957 tp = smb_GetSMBData(outp, NULL);
958 if (secBlobOutLength) {
959 memcpy(tp, secBlobOut, secBlobOutLength);
961 tp += secBlobOutLength;
962 cb_data += secBlobOutLength;
965 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
966 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
967 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
969 smb_SetSMBDataLength(outp, cb_data);
971 smb_SetSMBDataLength(outp, 0);
974 if (smb_authType == SMB_AUTH_EXTENDED) {
977 tp = smb_GetSMBData(outp, NULL);
979 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
980 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
981 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
983 smb_SetSMBDataLength(outp, cb_data);
985 smb_SetSMBDataLength(outp, 0);
992 /* SMB_COM_LOGOFF_ANDX */
993 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
997 /* find the tree and free it */
998 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1000 smb_username_t * unp;
1002 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %S", uidp->userID,
1003 osi_LogSaveClientString(smb_logp, (uidp->unp) ? uidp->unp->name: _C(" ")));
1005 lock_ObtainMutex(&uidp->mx);
1006 uidp->flags |= SMB_USERFLAG_DELETE;
1008 * it doesn't get deleted right away
1009 * because the vcp points to it
1012 lock_ReleaseMutex(&uidp->mx);
1015 /* we can't do this. we get logoff messages prior to a session
1016 * disconnect even though it doesn't mean the user is logging out.
1017 * we need to create a new pioctl and EventLogoff handler to set
1018 * SMB_USERNAMEFLAG_LOGOFF.
1020 if (unp && smb_LogoffTokenTransfer) {
1021 lock_ObtainMutex(&unp->mx);
1022 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
1023 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
1024 lock_ReleaseMutex(&unp->mx);
1028 smb_ReleaseUID(uidp);
1031 osi_Log0(smb_logp, "SMB3 user logoffX");
1033 smb_SetSMBDataLength(outp, 0);
1037 #define SMB_SUPPORT_SEARCH_BITS 0x0001
1038 #define SMB_SHARE_IS_IN_DFS 0x0002
1040 /* SMB_COM_TREE_CONNECT_ANDX */
1041 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1044 smb_user_t *uidp = NULL;
1045 unsigned short newTid;
1046 clientchar_t shareName[AFSPATHMAX];
1047 clientchar_t *sharePath;
1050 clientchar_t *slashp;
1051 clientchar_t *pathp;
1052 clientchar_t *passwordp;
1053 clientchar_t *servicep;
1054 cm_user_t *userp = NULL;
1057 osi_Log0(smb_logp, "SMB3 receive tree connect");
1059 /* parse input parameters */
1060 tp = smb_GetSMBData(inp, NULL);
1061 passwordp = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1062 pathp = smb_ParseString(inp, tp, &tp, SMB_STRF_ANSIPATH);
1063 servicep = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1065 slashp = cm_ClientStrRChr(pathp, '\\');
1067 return CM_ERROR_BADSMB;
1069 cm_ClientStrCpy(shareName, lengthof(shareName), slashp+1);
1071 osi_Log3(smb_logp, "Tree connect pathp[%S] shareName[%S] service[%S]",
1072 osi_LogSaveClientString(smb_logp, pathp),
1073 osi_LogSaveClientString(smb_logp, shareName),
1074 osi_LogSaveClientString(smb_logp, servicep));
1076 if (cm_ClientStrCmp(servicep, _C("IPC")) == 0 ||
1077 cm_ClientStrCmp(shareName, _C("IPC$")) == 0) {
1079 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1082 return CM_ERROR_NOIPC;
1086 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1088 userp = smb_GetUserFromUID(uidp);
1090 lock_ObtainMutex(&vcp->mx);
1091 newTid = vcp->tidCounter++;
1092 lock_ReleaseMutex(&vcp->mx);
1094 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1097 if (!cm_ClientStrCmp(shareName, _C("*.")))
1098 cm_ClientStrCpy(shareName, lengthof(shareName), _C("all"));
1099 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1102 smb_ReleaseUID(uidp);
1103 smb_ReleaseTID(tidp, FALSE);
1104 return CM_ERROR_BADSHARENAME;
1107 if (vcp->flags & SMB_VCFLAG_USENT)
1109 int policy = smb_FindShareCSCPolicy(shareName);
1112 DWORD dwAdvertiseDFS = 0, dwSize = sizeof(DWORD);
1114 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1115 0, KEY_QUERY_VALUE, &parmKey);
1116 if (code == ERROR_SUCCESS) {
1117 code = RegQueryValueEx(parmKey, "AdvertiseDFS", NULL, NULL,
1118 (BYTE *)&dwAdvertiseDFS, &dwSize);
1119 if (code != ERROR_SUCCESS)
1121 RegCloseKey (parmKey);
1123 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1124 (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
1128 smb_SetSMBParm(outp, 2, 0);
1132 smb_ReleaseUID(uidp);
1134 lock_ObtainMutex(&tidp->mx);
1135 tidp->userp = userp;
1136 tidp->pathname = sharePath;
1138 tidp->flags |= SMB_TIDFLAG_IPC;
1139 lock_ReleaseMutex(&tidp->mx);
1140 smb_ReleaseTID(tidp, FALSE);
1142 ((smb_t *)outp)->tid = newTid;
1143 ((smb_t *)inp)->tid = newTid;
1144 tp = smb_GetSMBData(outp, NULL);
1148 tp = smb_UnparseString(outp, tp, _C("A:"), &cb_data, SMB_STRF_FORCEASCII);
1149 tp = smb_UnparseString(outp, tp, _C("AFS"), &cb_data, 0);
1150 smb_SetSMBDataLength(outp, cb_data);
1154 tp = smb_UnparseString(outp, tp, _C("IPC"), &cb_data, SMB_STRF_FORCEASCII);
1155 smb_SetSMBDataLength(outp, cb_data);
1158 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1162 /* must be called with global tran lock held */
1163 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1165 smb_tran2Packet_t *tp;
1168 smbp = (smb_t *) inp->data;
1169 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1170 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1176 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1177 int totalParms, int totalData)
1179 smb_tran2Packet_t *tp;
1182 smbp = (smb_t *) inp->data;
1183 tp = malloc(sizeof(*tp));
1184 memset(tp, 0, sizeof(*tp));
1187 tp->curData = tp->curParms = 0;
1188 tp->totalData = totalData;
1189 tp->totalParms = totalParms;
1190 tp->tid = smbp->tid;
1191 tp->mid = smbp->mid;
1192 tp->uid = smbp->uid;
1193 tp->pid = smbp->pid;
1194 tp->res[0] = smbp->res[0];
1195 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1196 if (totalParms != 0)
1197 tp->parmsp = malloc(totalParms);
1199 tp->datap = malloc(totalData);
1200 if (smbp->com == 0x25 || smbp->com == 0x26)
1203 tp->opcode = smb_GetSMBParm(inp, 14);
1206 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1208 if (WANTS_UNICODE(inp) && (vcp->flags & SMB_VCFLAG_USEUNICODE))
1209 tp->flags |= SMB_TRAN2PFLAG_USEUNICODE;
1214 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1215 smb_tran2Packet_t *inp, smb_packet_t *outp,
1216 int totalParms, int totalData)
1218 smb_tran2Packet_t *tp;
1219 unsigned short parmOffset;
1220 unsigned short dataOffset;
1221 unsigned short dataAlign;
1223 tp = malloc(sizeof(*tp));
1224 memset(tp, 0, sizeof(*tp));
1227 tp->curData = tp->curParms = 0;
1228 tp->totalData = totalData;
1229 tp->totalParms = totalParms;
1230 tp->oldTotalParms = totalParms;
1235 tp->res[0] = inp->res[0];
1236 tp->opcode = inp->opcode;
1240 * We calculate where the parameters and data will start.
1241 * This calculation must parallel the calculation in
1242 * smb_SendTran2Packet.
1245 parmOffset = 10*2 + 35;
1246 parmOffset++; /* round to even */
1247 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1249 dataOffset = parmOffset + totalParms;
1250 dataAlign = dataOffset & 2; /* quad-align */
1251 dataOffset += dataAlign;
1252 tp->datap = outp->data + dataOffset;
1257 /* free a tran2 packet */
1258 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1261 smb_ReleaseVC(t2p->vcp);
1264 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1274 while (t2p->stringsp) {
1278 t2p->stringsp = ns->nextp;
1284 clientchar_t *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
1285 char ** chainpp, int flags)
1290 if (!(p->flags & SMB_TRAN2PFLAG_USEUNICODE))
1291 flags |= SMB_STRF_FORCEASCII;
1294 cb = p->totalParms - (inp - (char *)p->parmsp);
1295 if (inp < (char *) p->parmsp ||
1296 inp >= ((char *) p->parmsp) + p->totalParms) {
1297 #ifdef DEBUG_UNICODE
1303 return smb_ParseStringBuf((unsigned char *) p->parmsp, &p->stringsp,
1304 inp, &cb, chainpp, flags);
1307 /* called with a VC, an input packet to respond to, and an error code.
1308 * sends an error response.
1310 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1311 smb_packet_t *tp, long code)
1314 unsigned short errCode;
1315 unsigned char errClass;
1316 unsigned long NTStatus;
1318 if (vcp->flags & SMB_VCFLAG_STATUS32)
1319 smb_MapNTError(code, &NTStatus);
1321 smb_MapCoreError(code, vcp, &errCode, &errClass);
1323 smb_FormatResponsePacket(vcp, NULL, tp);
1324 smbp = (smb_t *) tp;
1326 /* We can handle long names */
1327 if (vcp->flags & SMB_VCFLAG_USENT)
1328 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1330 /* now copy important fields from the tran 2 packet */
1331 smbp->com = t2p->com;
1332 smbp->tid = t2p->tid;
1333 smbp->mid = t2p->mid;
1334 smbp->pid = t2p->pid;
1335 smbp->uid = t2p->uid;
1336 smbp->res[0] = t2p->res[0];
1337 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1338 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1339 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1340 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1341 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1342 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1345 smbp->rcls = errClass;
1346 smbp->errLow = (unsigned char) (errCode & 0xff);
1347 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1351 smb_SendPacket(vcp, tp);
1354 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1357 unsigned short parmOffset;
1358 unsigned short dataOffset;
1359 unsigned short totalLength;
1360 unsigned short dataAlign;
1363 smb_FormatResponsePacket(vcp, NULL, tp);
1364 smbp = (smb_t *) tp;
1366 /* We can handle long names */
1367 if (vcp->flags & SMB_VCFLAG_USENT)
1368 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1370 /* now copy important fields from the tran 2 packet */
1371 smbp->com = t2p->com;
1372 smbp->tid = t2p->tid;
1373 smbp->mid = t2p->mid;
1374 smbp->pid = t2p->pid;
1375 smbp->uid = t2p->uid;
1376 smbp->res[0] = t2p->res[0];
1378 if (t2p->error_code) {
1379 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1380 unsigned long NTStatus;
1382 smb_MapNTError(t2p->error_code, &NTStatus);
1384 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1385 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1386 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1387 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1388 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1391 unsigned short errCode;
1392 unsigned char errClass;
1394 smb_MapCoreError(t2p->error_code, vcp, &errCode, &errClass);
1396 smbp->rcls = errClass;
1397 smbp->errLow = (unsigned char) (errCode & 0xff);
1398 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1402 totalLength = 1 + t2p->totalData + t2p->totalParms;
1404 /* now add the core parameters (tran2 info) to the packet */
1405 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1406 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1407 smb_SetSMBParm(tp, 2, 0); /* reserved */
1408 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1409 parmOffset = 10*2 + 35; /* parm offset in packet */
1410 parmOffset++; /* round to even */
1411 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1412 * hdr, bcc and wct */
1413 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1414 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1415 dataOffset = parmOffset + t2p->oldTotalParms;
1416 dataAlign = dataOffset & 2; /* quad-align */
1417 dataOffset += dataAlign;
1418 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1419 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1420 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1423 datap = smb_GetSMBData(tp, NULL);
1424 *datap++ = 0; /* we rounded to even */
1426 totalLength += dataAlign;
1427 smb_SetSMBDataLength(tp, totalLength);
1429 /* next, send the datagram */
1430 smb_SendPacket(vcp, tp);
1433 /* TRANS_SET_NMPIPE_STATE */
1434 long smb_nmpipeSetState(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1438 int pipeState = 0x0100; /* default */
1439 smb_tran2Packet_t *outp = NULL;
1442 if (p->totalParms > 0)
1443 pipeState = p->parmsp[0];
1445 osi_Log2(smb_logp, "smb_nmpipeSetState for fd[%d] with state[0x%x]", fd, pipeState);
1447 fidp = smb_FindFID(vcp, fd, 0);
1449 osi_Log2(smb_logp, "smb_nmpipeSetState Unknown SMB Fid vcp 0x%p fid %d",
1451 return CM_ERROR_BADFD;
1453 lock_ObtainMutex(&fidp->mx);
1454 if (pipeState & 0x8000)
1455 fidp->flags |= SMB_FID_BLOCKINGPIPE;
1456 if (pipeState & 0x0100)
1457 fidp->flags |= SMB_FID_MESSAGEMODEPIPE;
1458 lock_ReleaseMutex(&fidp->mx);
1460 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 0);
1461 smb_SendTran2Packet(vcp, outp, op);
1462 smb_FreeTran2Packet(outp);
1464 smb_ReleaseFID(fidp);
1469 long smb_nmpipeTransact(smb_vc_t * vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1479 osi_Log3(smb_logp, "smb_nmpipeTransact for fd[%d] %d bytes in, %d max bytes out",
1480 fd, p->totalData, p->maxReturnData);
1482 fidp = smb_FindFID(vcp, fd, 0);
1484 osi_Log2(smb_logp, "smb_nmpipeTransact Unknown SMB Fid vcp 0x%p fid %d",
1486 return CM_ERROR_BADFD;
1488 lock_ObtainMutex(&fidp->mx);
1489 if (fidp->flags & SMB_FID_RPC) {
1492 lock_ReleaseMutex(&fidp->mx);
1495 code = smb_RPCNmpipeTransact(fidp, vcp, p, op);
1496 smb_ReleaseFID(fidp);
1498 /* We only deal with RPC pipes */
1499 osi_Log2(smb_logp, "smb_nmpipeTransact Not a RPC vcp 0x%p fid %d",
1501 code = CM_ERROR_BADFD;
1508 /* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
1509 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1511 smb_tran2Packet_t *asp;
1524 /* We sometimes see 0 word count. What to do? */
1525 if (*inp->wctp == 0) {
1526 osi_Log0(smb_logp, "Transaction2 word count = 0");
1527 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1529 smb_SetSMBDataLength(outp, 0);
1530 smb_SendPacket(vcp, outp);
1534 totalParms = smb_GetSMBParm(inp, 0);
1535 totalData = smb_GetSMBParm(inp, 1);
1537 firstPacket = (inp->inCom == 0x25);
1539 /* find the packet we're reassembling */
1540 lock_ObtainWrite(&smb_globalLock);
1541 asp = smb_FindTran2Packet(vcp, inp);
1543 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1545 lock_ReleaseWrite(&smb_globalLock);
1547 /* now merge in this latest packet; start by looking up offsets */
1549 parmDisp = dataDisp = 0;
1550 parmOffset = smb_GetSMBParm(inp, 10);
1551 dataOffset = smb_GetSMBParm(inp, 12);
1552 parmCount = smb_GetSMBParm(inp, 9);
1553 dataCount = smb_GetSMBParm(inp, 11);
1554 asp->setupCount = smb_GetSMBParmByte(inp, 13);
1555 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1556 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1558 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1559 totalData, dataCount, asp->maxReturnData);
1561 if (asp->setupCount == 2) {
1562 clientchar_t * pname;
1564 asp->pipeCommand = smb_GetSMBParm(inp, 14);
1565 asp->pipeParam = smb_GetSMBParm(inp, 15);
1566 pname = smb_ParseString(inp, inp->wctp + 35, NULL, 0);
1568 asp->name = cm_ClientStrDup(pname);
1571 osi_Log2(smb_logp, " Named Pipe command id [%d] with name [%S]",
1572 asp->pipeCommand, osi_LogSaveClientString(smb_logp, asp->name));
1576 parmDisp = smb_GetSMBParm(inp, 4);
1577 parmOffset = smb_GetSMBParm(inp, 3);
1578 dataDisp = smb_GetSMBParm(inp, 7);
1579 dataOffset = smb_GetSMBParm(inp, 6);
1580 parmCount = smb_GetSMBParm(inp, 2);
1581 dataCount = smb_GetSMBParm(inp, 5);
1583 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1584 parmCount, dataCount);
1587 /* now copy the parms and data */
1588 if ( asp->totalParms > 0 && parmCount != 0 )
1590 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1592 if ( asp->totalData > 0 && dataCount != 0 ) {
1593 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1596 /* account for new bytes */
1597 asp->curData += dataCount;
1598 asp->curParms += parmCount;
1600 /* finally, if we're done, remove the packet from the queue and dispatch it */
1601 if (((asp->totalParms > 0 && asp->curParms > 0)
1602 || asp->setupCount == 2) &&
1603 asp->totalData <= asp->curData &&
1604 asp->totalParms <= asp->curParms) {
1606 /* we've received it all */
1607 lock_ObtainWrite(&smb_globalLock);
1608 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1609 lock_ReleaseWrite(&smb_globalLock);
1611 switch(asp->setupCount) {
1614 rapOp = asp->parmsp[0];
1616 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES &&
1617 smb_rapDispatchTable[rapOp].procp) {
1619 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",
1620 myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1622 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1624 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",
1625 code,vcp,vcp->lana,vcp->lsn);
1628 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]",
1629 rapOp, vcp, vcp->lana, vcp->lsn);
1631 code = CM_ERROR_BADOP;
1637 { /* Named pipe operation */
1638 osi_Log2(smb_logp, "Named Pipe: %s with name [%S]",
1639 myCrt_NmpipeDispatch(asp->pipeCommand),
1640 osi_LogSaveClientString(smb_logp, asp->name));
1642 code = CM_ERROR_BADOP;
1644 switch (asp->pipeCommand) {
1645 case SMB_TRANS_SET_NMPIPE_STATE:
1646 code = smb_nmpipeSetState(vcp, asp, outp);
1649 case SMB_TRANS_RAW_READ_NMPIPE:
1652 case SMB_TRANS_QUERY_NMPIPE_STATE:
1655 case SMB_TRANS_QUERY_NMPIPE_INFO:
1658 case SMB_TRANS_PEEK_NMPIPE:
1661 case SMB_TRANS_TRANSACT_NMPIPE:
1662 code = smb_nmpipeTransact(vcp, asp, outp);
1665 case SMB_TRANS_RAW_WRITE_NMPIPE:
1668 case SMB_TRANS_READ_NMPIPE:
1671 case SMB_TRANS_WRITE_NMPIPE:
1674 case SMB_TRANS_WAIT_NMPIPE:
1677 case SMB_TRANS_CALL_NMPIPE:
1684 code = CM_ERROR_BADOP;
1687 /* if an error is returned, we're supposed to send an error packet,
1688 * otherwise the dispatched function already did the data sending.
1689 * We give dispatched proc the responsibility since it knows how much
1690 * space to allocate.
1693 smb_SendTran2Error(vcp, asp, outp, code);
1696 /* free the input tran 2 packet */
1697 smb_FreeTran2Packet(asp);
1699 else if (firstPacket) {
1700 /* the first packet in a multi-packet request, we need to send an
1701 * ack to get more data.
1703 smb_SetSMBDataLength(outp, 0);
1704 smb_SendPacket(vcp, outp);
1710 /* ANSI versions. */
1712 #pragma pack(push, 1)
1714 typedef struct smb_rap_share_info_0 {
1715 BYTE shi0_netname[13];
1716 } smb_rap_share_info_0_t;
1718 typedef struct smb_rap_share_info_1 {
1719 BYTE shi1_netname[13];
1722 DWORD shi1_remark; /* char *shi1_remark; data offset */
1723 } smb_rap_share_info_1_t;
1725 typedef struct smb_rap_share_info_2 {
1726 BYTE shi2_netname[13];
1729 DWORD shi2_remark; /* char *shi2_remark; data offset */
1730 WORD shi2_permissions;
1732 WORD shi2_current_uses;
1733 DWORD shi2_path; /* char *shi2_path; data offset */
1734 WORD shi2_passwd[9];
1736 } smb_rap_share_info_2_t;
1738 #define SMB_RAP_MAX_SHARES 512
1740 typedef struct smb_rap_share_list {
1743 smb_rap_share_info_0_t * shares;
1744 } smb_rap_share_list_t;
1748 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1749 smb_rap_share_list_t * sp;
1751 if (dep->name[0] == '.' && (!dep->name[1] || (dep->name[1] == '.' && !dep->name[2])))
1752 return 0; /* skip over '.' and '..' */
1754 sp = (smb_rap_share_list_t *) vrockp;
1756 strncpy(sp->shares[sp->cShare].shi0_netname, dep->name, 12);
1757 sp->shares[sp->cShare].shi0_netname[12] = 0;
1761 if (sp->cShare >= sp->maxShares)
1762 return CM_ERROR_STOPNOW;
1767 /* RAP NetShareEnumRequest */
1768 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1770 smb_tran2Packet_t *outp;
1771 unsigned short * tp;
1775 int outParmsTotal; /* total parameter bytes */
1776 int outDataTotal; /* total data bytes */
1779 DWORD allSubmount = 0;
1781 DWORD nRegShares = 0;
1782 DWORD nSharesRet = 0;
1784 HKEY hkSubmount = NULL;
1785 smb_rap_share_info_1_t * shares;
1788 clientchar_t thisShare[AFSPATHMAX];
1792 smb_rap_share_list_t rootShares;
1797 tp = p->parmsp + 1; /* skip over function number (always 0) */
1800 clientchar_t * cdescp;
1802 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1803 if (cm_ClientStrCmp(cdescp, _C("WrLeh")))
1804 return CM_ERROR_INVAL;
1805 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1806 if (cm_ClientStrCmp(cdescp, _C("B13BWz")))
1807 return CM_ERROR_INVAL;
1813 if (infoLevel != 1) {
1814 return CM_ERROR_INVAL;
1817 /* We are supposed to use the same ASCII data structure even if
1818 Unicode is negotiated, which ultimately means that the share
1819 names that we return must be at most 13 characters in length,
1820 including the NULL terminator.
1822 The RAP specification states that shares with names longer than
1823 12 characters should not be included in the enumeration.
1824 However, since we support prefix cell references and since many
1825 cell names are going to exceed 12 characters, we lie and send
1826 the first 12 characters.
1829 /* first figure out how many shares there are */
1830 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1831 KEY_QUERY_VALUE, &hkParam);
1832 if (rv == ERROR_SUCCESS) {
1833 len = sizeof(allSubmount);
1834 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1835 (BYTE *) &allSubmount, &len);
1836 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1839 RegCloseKey (hkParam);
1842 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1843 0, KEY_QUERY_VALUE, &hkSubmount);
1844 if (rv == ERROR_SUCCESS) {
1845 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1846 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1847 if (rv != ERROR_SUCCESS)
1853 /* fetch the root shares */
1854 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1855 rootShares.cShare = 0;
1856 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1860 userp = smb_GetTran2User(vcp,p);
1862 thyper.HighPart = 0;
1865 cm_HoldSCache(cm_data.rootSCachep);
1866 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1867 cm_ReleaseSCache(cm_data.rootSCachep);
1869 cm_ReleaseUser(userp);
1871 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1873 #define REMARK_LEN 1
1874 outParmsTotal = 8; /* 4 dwords */
1875 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1876 if(outDataTotal > bufsize) {
1877 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1878 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1881 nSharesRet = nShares;
1884 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1886 /* now for the submounts */
1887 shares = (smb_rap_share_info_1_t *) outp->datap;
1888 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1890 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1893 StringCchCopyA(shares[cshare].shi1_netname,
1894 lengthof(shares[cshare].shi1_netname), "all" );
1895 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1896 /* type and pad are zero already */
1902 for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
1903 len = sizeof(thisShare);
1904 rv = RegEnumValueW(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
1905 if (rv == ERROR_SUCCESS &&
1906 cm_ClientStrLen(thisShare) &&
1907 (!allSubmount || cm_ClientStrCmpI(thisShare,_C("all")))) {
1908 cm_ClientStringToUtf8(thisShare, -1, shares[cshare].shi1_netname,
1909 lengthof( shares[cshare].shi1_netname ));
1910 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1911 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1916 nShares--; /* uncount key */
1919 RegCloseKey(hkSubmount);
1922 nonrootShares = cshare;
1924 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1925 /* in case there are collisions with submounts, submounts have
1927 for (j=0; j < nonrootShares; j++)
1928 if (!cm_stricmp_utf8(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1931 if (j < nonrootShares) {
1932 nShares--; /* uncount */
1936 StringCchCopyA(shares[cshare].shi1_netname, lengthof(shares[cshare].shi1_netname),
1937 rootShares.shares[i].shi0_netname);
1938 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1943 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1944 outp->parmsp[1] = 0;
1945 outp->parmsp[2] = cshare;
1946 outp->parmsp[3] = nShares;
1948 outp->totalData = (int)(cstrp - outp->datap);
1949 outp->totalParms = outParmsTotal;
1951 smb_SendTran2Packet(vcp, outp, op);
1952 smb_FreeTran2Packet(outp);
1954 free(rootShares.shares);
1959 /* RAP NetShareGetInfo */
1960 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1962 smb_tran2Packet_t *outp;
1963 unsigned short * tp;
1964 clientchar_t * shareName;
1965 BOOL shareFound = FALSE;
1966 unsigned short infoLevel;
1967 unsigned short bufsize;
1976 cm_scache_t *scp = NULL;
1982 tp = p->parmsp + 1; /* skip over function number (always 1) */
1985 clientchar_t * cdescp;
1987 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1988 if (cm_ClientStrCmp(cdescp, _C("zWrLh")))
1990 return CM_ERROR_INVAL;
1992 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1993 if (cm_ClientStrCmp(cdescp, _C("B13")) &&
1994 cm_ClientStrCmp(cdescp, _C("B13BWz")) &&
1995 cm_ClientStrCmp(cdescp, _C("B13BWzWWWzB9B")))
1997 return CM_ERROR_INVAL;
1999 shareName = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2007 totalData = sizeof(smb_rap_share_info_0_t);
2008 else if(infoLevel == SMB_INFO_STANDARD)
2009 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
2010 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
2011 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
2013 return CM_ERROR_INVAL;
2015 if(!cm_ClientStrCmpI(shareName, _C("all")) || !cm_ClientStrCmp(shareName,_C("*."))) {
2016 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
2017 KEY_QUERY_VALUE, &hkParam);
2018 if (rv == ERROR_SUCCESS) {
2019 len = sizeof(allSubmount);
2020 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
2021 (BYTE *) &allSubmount, &len);
2022 if (rv != ERROR_SUCCESS || allSubmount != 0) {
2025 RegCloseKey (hkParam);
2032 userp = smb_GetTran2User(vcp, p);
2034 osi_Log1(smb_logp,"ReceiveRAPNetShareGetInfo unable to resolve user [%d]", p->uid);
2035 return CM_ERROR_BADSMB;
2037 code = cm_NameI(cm_data.rootSCachep, shareName,
2038 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
2039 userp, NULL, &req, &scp);
2041 cm_ReleaseSCache(scp);
2044 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
2045 KEY_QUERY_VALUE, &hkSubmount);
2046 if (rv == ERROR_SUCCESS) {
2047 rv = RegQueryValueExW(hkSubmount, shareName, NULL, NULL, NULL, NULL);
2048 if (rv == ERROR_SUCCESS) {
2051 RegCloseKey(hkSubmount);
2057 return CM_ERROR_BADSHARENAME;
2059 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
2060 memset(outp->datap, 0, totalData);
2062 outp->parmsp[0] = 0;
2063 outp->parmsp[1] = 0;
2064 outp->parmsp[2] = totalData;
2066 if (infoLevel == 0) {
2067 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
2068 cm_ClientStringToUtf8(shareName, -1, info->shi0_netname,
2069 lengthof(info->shi0_netname));
2070 } else if(infoLevel == SMB_INFO_STANDARD) {
2071 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
2072 cm_ClientStringToUtf8(shareName, -1, info->shi1_netname, lengthof(info->shi1_netname));
2073 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
2074 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
2075 /* type and pad are already zero */
2076 } else { /* infoLevel==2 */
2077 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
2078 cm_ClientStringToUtf8(shareName, -1, info->shi2_netname, lengthof(info->shi2_netname));
2079 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
2080 info->shi2_permissions = ACCESS_ALL;
2081 info->shi2_max_uses = (unsigned short) -1;
2082 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
2085 outp->totalData = totalData;
2086 outp->totalParms = totalParam;
2088 smb_SendTran2Packet(vcp, outp, op);
2089 smb_FreeTran2Packet(outp);
2094 #pragma pack(push, 1)
2096 typedef struct smb_rap_wksta_info_10 {
2097 DWORD wki10_computername; /*char *wki10_computername;*/
2098 DWORD wki10_username; /* char *wki10_username; */
2099 DWORD wki10_langroup; /* char *wki10_langroup;*/
2100 BYTE wki10_ver_major;
2101 BYTE wki10_ver_minor;
2102 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
2103 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
2104 } smb_rap_wksta_info_10_t;
2108 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2110 smb_tran2Packet_t *outp;
2114 unsigned short * tp;
2117 smb_rap_wksta_info_10_t * info;
2121 tp = p->parmsp + 1; /* Skip over function number */
2124 clientchar_t * cdescp;
2126 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2127 SMB_STRF_FORCEASCII);
2128 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2129 return CM_ERROR_INVAL;
2131 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2132 SMB_STRF_FORCEASCII);
2133 if (cm_ClientStrCmp(cdescp, _C("zzzBBzz")))
2134 return CM_ERROR_INVAL;
2140 if (infoLevel != 10) {
2141 return CM_ERROR_INVAL;
2147 totalData = sizeof(*info) + /* info */
2148 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
2149 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
2150 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
2151 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
2152 1; /* wki10_oth_domains (null)*/
2154 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2156 memset(outp->parmsp,0,totalParams);
2157 memset(outp->datap,0,totalData);
2159 info = (smb_rap_wksta_info_10_t *) outp->datap;
2160 cstrp = (char *) (info + 1);
2162 info->wki10_computername = (DWORD) (cstrp - outp->datap);
2163 StringCbCopyA(cstrp, totalData, smb_localNamep);
2164 cstrp += strlen(cstrp) + 1;
2166 info->wki10_username = (DWORD) (cstrp - outp->datap);
2167 uidp = smb_FindUID(vcp, p->uid, 0);
2169 lock_ObtainMutex(&uidp->mx);
2170 if(uidp->unp && uidp->unp->name)
2171 cm_ClientStringToUtf8(uidp->unp->name, -1,
2172 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2173 lock_ReleaseMutex(&uidp->mx);
2174 smb_ReleaseUID(uidp);
2176 cstrp += strlen(cstrp) + 1;
2178 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
2179 StringCbCopyA(cstrp, totalData - (cstrp - outp->datap)*sizeof(char), "WORKGROUP");
2180 cstrp += strlen(cstrp) + 1;
2182 /* TODO: Not sure what values these should take, but these work */
2183 info->wki10_ver_major = 5;
2184 info->wki10_ver_minor = 1;
2186 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
2187 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
2188 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2189 cstrp += strlen(cstrp) + 1;
2191 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
2192 cstrp ++; /* no other domains */
2194 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
2195 outp->parmsp[2] = outp->totalData;
2196 outp->totalParms = totalParams;
2198 smb_SendTran2Packet(vcp,outp,op);
2199 smb_FreeTran2Packet(outp);
2204 #pragma pack(push, 1)
2206 typedef struct smb_rap_server_info_0 {
2208 } smb_rap_server_info_0_t;
2210 typedef struct smb_rap_server_info_1 {
2212 BYTE sv1_version_major;
2213 BYTE sv1_version_minor;
2215 DWORD sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
2216 } smb_rap_server_info_1_t;
2220 char smb_ServerComment[] = "OpenAFS Client";
2221 int smb_ServerCommentLen = sizeof(smb_ServerComment);
2223 #define SMB_SV_TYPE_SERVER 0x00000002L
2224 #define SMB_SV_TYPE_NT 0x00001000L
2225 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
2227 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2229 smb_tran2Packet_t *outp;
2233 unsigned short * tp;
2236 smb_rap_server_info_0_t * info0;
2237 smb_rap_server_info_1_t * info1;
2240 tp = p->parmsp + 1; /* Skip over function number */
2243 clientchar_t * cdescp;
2245 cdescp = smb_ParseStringT2Parm(p, (unsigned char *) tp, (char **) &tp,
2246 SMB_STRF_FORCEASCII);
2247 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2248 return CM_ERROR_INVAL;
2249 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2250 SMB_STRF_FORCEASCII);
2251 if (cm_ClientStrCmp(cdescp, _C("B16")) ||
2252 cm_ClientStrCmp(cdescp, _C("B16BBDz")))
2253 return CM_ERROR_INVAL;
2259 if (infoLevel != 0 && infoLevel != 1) {
2260 return CM_ERROR_INVAL;
2266 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
2267 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
2269 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2271 memset(outp->parmsp,0,totalParams);
2272 memset(outp->datap,0,totalData);
2274 if (infoLevel == 0) {
2275 info0 = (smb_rap_server_info_0_t *) outp->datap;
2276 cstrp = (char *) (info0 + 1);
2277 StringCchCopyA(info0->sv0_name, lengthof(info0->sv0_name), "AFS");
2278 } else { /* infoLevel == SMB_INFO_STANDARD */
2279 info1 = (smb_rap_server_info_1_t *) outp->datap;
2280 cstrp = (char *) (info1 + 1);
2281 StringCchCopyA(info1->sv1_name, lengthof(info1->sv1_name), "AFS");
2284 SMB_SV_TYPE_SERVER |
2286 SMB_SV_TYPE_SERVER_NT;
2288 info1->sv1_version_major = 5;
2289 info1->sv1_version_minor = 1;
2290 info1->sv1_comment_or_master_browser = (DWORD) (cstrp - outp->datap);
2292 StringCbCopyA(cstrp, smb_ServerCommentLen, smb_ServerComment);
2294 cstrp += smb_ServerCommentLen / sizeof(char);
2297 totalData = (DWORD)(cstrp - outp->datap);
2298 outp->totalData = min(bufsize,totalData); /* actual data size */
2299 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
2300 outp->parmsp[2] = totalData;
2301 outp->totalParms = totalParams;
2303 smb_SendTran2Packet(vcp,outp,op);
2304 smb_FreeTran2Packet(outp);
2309 /* SMB_COM_TRANSACTION2 and SMB_COM_TRANSACTION2_SECONDARY */
2310 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2312 smb_tran2Packet_t *asp;
2323 DWORD oldTime, newTime;
2325 /* We sometimes see 0 word count. What to do? */
2326 if (*inp->wctp == 0) {
2327 osi_Log0(smb_logp, "Transaction2 word count = 0");
2328 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
2330 smb_SetSMBDataLength(outp, 0);
2331 smb_SendPacket(vcp, outp);
2335 totalParms = smb_GetSMBParm(inp, 0);
2336 totalData = smb_GetSMBParm(inp, 1);
2338 firstPacket = (inp->inCom == 0x32);
2340 /* find the packet we're reassembling */
2341 lock_ObtainWrite(&smb_globalLock);
2342 asp = smb_FindTran2Packet(vcp, inp);
2344 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
2346 lock_ReleaseWrite(&smb_globalLock);
2348 /* now merge in this latest packet; start by looking up offsets */
2350 parmDisp = dataDisp = 0;
2351 parmOffset = smb_GetSMBParm(inp, 10);
2352 dataOffset = smb_GetSMBParm(inp, 12);
2353 parmCount = smb_GetSMBParm(inp, 9);
2354 dataCount = smb_GetSMBParm(inp, 11);
2355 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2356 asp->maxReturnData = smb_GetSMBParm(inp, 3);
2358 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2359 totalData, dataCount, asp->maxReturnData);
2362 parmDisp = smb_GetSMBParm(inp, 4);
2363 parmOffset = smb_GetSMBParm(inp, 3);
2364 dataDisp = smb_GetSMBParm(inp, 7);
2365 dataOffset = smb_GetSMBParm(inp, 6);
2366 parmCount = smb_GetSMBParm(inp, 2);
2367 dataCount = smb_GetSMBParm(inp, 5);
2369 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2370 parmCount, dataCount);
2373 /* now copy the parms and data */
2374 if ( asp->totalParms > 0 && parmCount != 0 )
2376 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2378 if ( asp->totalData > 0 && dataCount != 0 ) {
2379 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2382 /* account for new bytes */
2383 asp->curData += dataCount;
2384 asp->curParms += parmCount;
2386 /* finally, if we're done, remove the packet from the queue and dispatch it */
2387 if (asp->totalParms > 0 &&
2388 asp->curParms > 0 &&
2389 asp->totalData <= asp->curData &&
2390 asp->totalParms <= asp->curParms) {
2391 /* we've received it all */
2392 lock_ObtainWrite(&smb_globalLock);
2393 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2394 lock_ReleaseWrite(&smb_globalLock);
2396 oldTime = GetTickCount();
2398 /* now dispatch it */
2399 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2400 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2401 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2404 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2405 code = CM_ERROR_BADOP;
2408 /* if an error is returned, we're supposed to send an error packet,
2409 * otherwise the dispatched function already did the data sending.
2410 * We give dispatched proc the responsibility since it knows how much
2411 * space to allocate.
2414 smb_SendTran2Error(vcp, asp, outp, code);
2417 newTime = GetTickCount();
2418 if (newTime - oldTime > 45000) {
2421 clientchar_t *treepath = NULL; /* do not free */
2422 clientchar_t *pathname = NULL;
2423 cm_fid_t afid = {0,0,0,0,0};
2425 uidp = smb_FindUID(vcp, asp->uid, 0);
2426 smb_LookupTIDPath(vcp, asp->tid, &treepath);
2427 fidp = smb_FindFID(vcp, inp->fid, 0);
2430 lock_ObtainMutex(&fidp->mx);
2431 if (fidp->NTopen_pathp)
2432 pathname = fidp->NTopen_pathp;
2434 afid = fidp->scp->fid;
2436 if (inp->stringsp->wdata)
2437 pathname = inp->stringsp->wdata;
2440 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)",
2441 myCrt_2Dispatch(asp->opcode), newTime - oldTime,
2442 asp->uid, uidp ? uidp->unp->name : NULL,
2443 asp->pid, asp->mid, asp->tid,
2446 afid.cell, afid.volume, afid.vnode, afid.unique);
2449 lock_ReleaseMutex(&fidp->mx);
2452 smb_ReleaseUID(uidp);
2454 smb_ReleaseFID(fidp);
2457 /* free the input tran 2 packet */
2458 smb_FreeTran2Packet(asp);
2460 else if (firstPacket) {
2461 /* the first packet in a multi-packet request, we need to send an
2462 * ack to get more data.
2464 smb_SetSMBDataLength(outp, 0);
2465 smb_SendPacket(vcp, outp);
2472 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2474 clientchar_t *pathp;
2475 smb_tran2Packet_t *outp;
2480 cm_scache_t *dscp; /* dir we're dealing with */
2481 cm_scache_t *scp; /* file we're creating */
2485 clientchar_t *lastNamep;
2492 int parmSlot; /* which parm we're dealing with */
2493 long returnEALength;
2494 clientchar_t *tidPathp;
2497 BOOL is_rpc = FALSE;
2498 BOOL is_ipc = FALSE;
2504 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2505 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2507 openFun = p->parmsp[6]; /* open function */
2508 excl = ((openFun & 3) == 0);
2509 trunc = ((openFun & 3) == 2); /* truncate it */
2510 openMode = (p->parmsp[1] & 0x7);
2511 openAction = 0; /* tracks what we did */
2513 attributes = p->parmsp[3];
2514 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2516 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
2519 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2521 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2522 if (code == CM_ERROR_TIDIPC) {
2524 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2527 spacep = cm_GetSpace();
2528 /* smb_StripLastComponent will strip "::$DATA" if present */
2529 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2533 /* special case magic file name for receiving IOCTL requests
2534 * (since IOCTL calls themselves aren't getting through).
2536 (cm_ClientStrCmpI(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
2538 /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional)*/
2539 (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
2541 unsigned short file_type = 0;
2542 unsigned short device_state = 0;
2544 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2547 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
2548 osi_Log2(smb_logp, "smb_ReceiveTran2Open Creating RPC Fid [%d] code [%d]",
2551 smb_ReleaseFID(fidp);
2552 smb_FreeTran2Packet(outp);
2553 osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
2557 smb_SetupIoctlFid(fidp, spacep);
2558 osi_Log1(smb_logp, "smb_ReceiveTran2Open Creating IOCTL Fid [%d]", fidp->fid);
2561 /* copy out remainder of the parms */
2563 outp->parmsp[parmSlot++] = fidp->fid;
2565 outp->parmsp[parmSlot++] = 0; /* attrs */
2566 outp->parmsp[parmSlot++] = 0; /* mod time */
2567 outp->parmsp[parmSlot++] = 0;
2568 outp->parmsp[parmSlot++] = 0; /* len */
2569 outp->parmsp[parmSlot++] = 0x7fff;
2570 outp->parmsp[parmSlot++] = openMode;
2571 outp->parmsp[parmSlot++] = file_type;
2572 outp->parmsp[parmSlot++] = device_state;
2574 /* and the final "always present" stuff */
2575 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2576 /* next write out the "unique" ID */
2577 outp->parmsp[parmSlot++] = 0x1234;
2578 outp->parmsp[parmSlot++] = 0x5678;
2579 outp->parmsp[parmSlot++] = 0;
2580 if (returnEALength) {
2581 outp->parmsp[parmSlot++] = 0;
2582 outp->parmsp[parmSlot++] = 0;
2585 outp->totalData = 0;
2586 outp->totalParms = parmSlot * 2;
2588 smb_SendTran2Packet(vcp, outp, op);
2590 smb_FreeTran2Packet(outp);
2592 /* and clean up fid reference */
2593 smb_ReleaseFID(fidp);
2599 osi_Log1(smb_logp, "Tran2Open rejecting IPC TID vcp %p", vcp);
2600 smb_FreeTran2Packet(outp);
2601 return CM_ERROR_BADFD;
2605 if (!cm_IsValidClientString(pathp)) {
2607 clientchar_t * hexp;
2609 hexp = cm_GetRawCharsAlloc(pathp, -1);
2610 osi_Log1(smb_logp, "Tran2Open rejecting invalid name. [%S]",
2611 osi_LogSaveClientString(smb_logp, hexp));
2615 osi_Log0(smb_logp, "Tran2Open rejecting invalid name");
2617 smb_FreeTran2Packet(outp);
2618 return CM_ERROR_BADNTFILENAME;
2621 #ifdef DEBUG_VERBOSE
2623 char *hexp, *asciip;
2624 asciip = (lastNamep ? lastNamep : pathp);
2625 hexp = osi_HexifyString( asciip );
2626 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2631 userp = smb_GetTran2User(vcp, p);
2632 /* In the off chance that userp is NULL, we log and abandon */
2634 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2635 smb_FreeTran2Packet(outp);
2636 return CM_ERROR_BADSMB;
2640 code = cm_NameI(cm_data.rootSCachep, pathp,
2641 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2642 userp, tidPathp, &req, &scp);
2644 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2645 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2646 userp, tidPathp, &req, &dscp);
2647 cm_FreeSpace(spacep);
2650 cm_ReleaseUser(userp);
2651 smb_FreeTran2Packet(outp);
2656 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2657 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2658 (clientchar_t*) spacep->data);
2659 cm_ReleaseSCache(dscp);
2660 cm_ReleaseUser(userp);
2661 smb_FreeTran2Packet(outp);
2662 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2663 return CM_ERROR_PATH_NOT_COVERED;
2665 return CM_ERROR_NOSUCHPATH;
2667 #endif /* DFS_SUPPORT */
2669 /* otherwise, scp points to the parent directory. Do a lookup,
2670 * and truncate the file if we find it, otherwise we create the
2677 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2679 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2680 cm_ReleaseSCache(dscp);
2681 cm_ReleaseUser(userp);
2682 smb_FreeTran2Packet(outp);
2686 /* macintosh is expensive to program for it */
2687 cm_FreeSpace(spacep);
2690 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2691 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2692 cm_ReleaseSCache(scp);
2693 cm_ReleaseUser(userp);
2694 smb_FreeTran2Packet(outp);
2695 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2696 return CM_ERROR_PATH_NOT_COVERED;
2698 return CM_ERROR_NOSUCHPATH;
2700 #endif /* DFS_SUPPORT */
2703 /* if we get here, if code is 0, the file exists and is represented by
2704 * scp. Otherwise, we have to create it.
2707 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2710 cm_ReleaseSCache(dscp);
2711 cm_ReleaseSCache(scp);
2712 cm_ReleaseUser(userp);
2713 smb_FreeTran2Packet(outp);
2718 /* oops, file shouldn't be there */
2720 cm_ReleaseSCache(dscp);
2721 cm_ReleaseSCache(scp);
2722 cm_ReleaseUser(userp);
2723 smb_FreeTran2Packet(outp);
2724 return CM_ERROR_EXISTS;
2728 setAttr.mask = CM_ATTRMASK_LENGTH;
2729 setAttr.length.LowPart = 0;
2730 setAttr.length.HighPart = 0;
2731 code = cm_SetAttr(scp, &setAttr, userp, &req);
2732 openAction = 3; /* truncated existing file */
2735 openAction = 1; /* found existing file */
2737 else if (!(openFun & 0x10)) {
2738 /* don't create if not found */
2740 cm_ReleaseSCache(dscp);
2741 osi_assertx(scp == NULL, "null cm_scache_t");
2742 cm_ReleaseUser(userp);
2743 smb_FreeTran2Packet(outp);
2744 return CM_ERROR_NOSUCHFILE;
2747 osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2748 openAction = 2; /* created file */
2749 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2750 cm_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2751 smb_SetInitialModeBitsForFile(attributes, &setAttr);
2753 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2757 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2758 smb_NotifyChange(FILE_ACTION_ADDED,
2759 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2760 dscp, lastNamep, NULL, TRUE);
2761 } else if (!excl && code == CM_ERROR_EXISTS) {
2762 /* not an exclusive create, and someone else tried
2763 * creating it already, then we open it anyway. We
2764 * don't bother retrying after this, since if this next
2765 * fails, that means that the file was deleted after we
2766 * started this call.
2768 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2772 setAttr.mask = CM_ATTRMASK_LENGTH;
2773 setAttr.length.LowPart = 0;
2774 setAttr.length.HighPart = 0;
2775 code = cm_SetAttr(scp, &setAttr, userp,
2778 } /* lookup succeeded */
2782 /* we don't need this any longer */
2784 cm_ReleaseSCache(dscp);
2787 /* something went wrong creating or truncating the file */
2789 cm_ReleaseSCache(scp);
2790 cm_ReleaseUser(userp);
2791 smb_FreeTran2Packet(outp);
2795 /* make sure we're about to open a file */
2796 if (scp->fileType != CM_SCACHETYPE_FILE) {
2798 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2799 cm_scache_t * targetScp = 0;
2800 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2802 /* we have a more accurate file to use (the
2803 * target of the symbolic link). Otherwise,
2804 * we'll just use the symlink anyway.
2806 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2808 cm_ReleaseSCache(scp);
2812 if (scp->fileType != CM_SCACHETYPE_FILE) {
2813 cm_ReleaseSCache(scp);
2814 cm_ReleaseUser(userp);
2815 smb_FreeTran2Packet(outp);
2816 return CM_ERROR_ISDIR;
2820 /* now all we have to do is open the file itself */
2821 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2822 osi_assertx(fidp, "null smb_fid_t");
2825 lock_ObtainMutex(&fidp->mx);
2826 /* save a pointer to the vnode */
2827 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2829 lock_ObtainWrite(&scp->rw);
2830 scp->flags |= CM_SCACHEFLAG_SMB_FID;
2831 lock_ReleaseWrite(&scp->rw);
2834 fidp->userp = userp;
2836 /* compute open mode */
2838 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
2839 if (openMode == 1 || openMode == 2)
2840 fidp->flags |= SMB_FID_OPENWRITE;
2842 /* remember that the file was newly created */
2844 fidp->flags |= SMB_FID_CREATED;
2846 lock_ReleaseMutex(&fidp->mx);
2848 smb_ReleaseFID(fidp);
2850 cm_Open(scp, 0, userp);
2852 /* copy out remainder of the parms */
2854 outp->parmsp[parmSlot++] = fidp->fid;
2855 lock_ObtainRead(&scp->rw);
2857 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2858 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2859 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2860 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2861 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2862 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2863 outp->parmsp[parmSlot++] = openMode;
2864 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2865 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2867 /* and the final "always present" stuff */
2868 outp->parmsp[parmSlot++] = openAction;
2869 /* next write out the "unique" ID */
2870 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2871 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2872 outp->parmsp[parmSlot++] = 0;
2873 if (returnEALength) {
2874 outp->parmsp[parmSlot++] = 0;
2875 outp->parmsp[parmSlot++] = 0;
2877 lock_ReleaseRead(&scp->rw);
2878 outp->totalData = 0; /* total # of data bytes */
2879 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2881 smb_SendTran2Packet(vcp, outp, op);
2883 smb_FreeTran2Packet(outp);
2885 cm_ReleaseUser(userp);
2886 /* leave scp held since we put it in fidp->scp */
2890 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2893 unsigned short infolevel;
2895 infolevel = p->parmsp[0];
2897 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2899 return CM_ERROR_BAD_LEVEL;
2902 /* TRANS2_QUERY_FS_INFORMATION */
2903 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2905 smb_tran2Packet_t *outp;
2906 smb_tran2QFSInfo_t qi;
2910 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2912 switch (p->parmsp[0]) {
2913 case SMB_INFO_ALLOCATION:
2915 responseSize = sizeof(qi.u.allocInfo);
2917 qi.u.allocInfo.FSID = 0;
2918 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2919 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2920 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2921 qi.u.allocInfo.bytesPerSector = 1024;
2924 case SMB_INFO_VOLUME:
2926 qi.u.volumeInfo.vsn = 1234; /* Volume serial number */
2927 qi.u.volumeInfo.vnCount = 3; /* Number of characters in label (AFS\0)*/
2929 /* we're supposed to pad it out with zeroes to the end */
2930 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2931 smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
2933 responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
2936 case SMB_QUERY_FS_VOLUME_INFO:
2937 /* FS volume info */
2938 responseSize = sizeof(qi.u.FSvolumeInfo);
2941 FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
2942 memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
2945 qi.u.FSvolumeInfo.vsn = 1234;
2946 qi.u.FSvolumeInfo.vnCount = 6; /* This is always in Unicode */
2947 memset(&qi.u.FSvolumeInfo.label, 0, sizeof(qi.u.FSvolumeInfo.label));
2948 memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
2951 case SMB_QUERY_FS_SIZE_INFO:
2953 responseSize = sizeof(qi.u.FSsizeInfo);
2955 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2956 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2957 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2958 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2959 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2960 qi.u.FSsizeInfo.bytesPerSector = 1024;
2963 case SMB_QUERY_FS_DEVICE_INFO:
2964 /* FS device info */
2965 responseSize = sizeof(qi.u.FSdeviceInfo);
2967 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2968 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2971 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2972 /* FS attribute info */
2974 /* attributes, defined in WINNT.H:
2975 * FILE_CASE_SENSITIVE_SEARCH 0x1
2976 * FILE_CASE_PRESERVED_NAMES 0x2
2977 * FILE_UNICODE_ON_DISK 0x4
2978 * FILE_VOLUME_QUOTAS 0x10
2979 * <no name defined> 0x4000
2980 * If bit 0x4000 is not set, Windows 95 thinks
2981 * we can't handle long (non-8.3) names,
2982 * despite our protestations to the contrary.
2984 qi.u.FSattributeInfo.attributes = 0x4003;
2985 /* The maxCompLength is supposed to be in bytes */
2987 qi.u.FSattributeInfo.attributes |= 0x04;
2989 qi.u.FSattributeInfo.maxCompLength = 255;
2990 smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
2991 qi.u.FSattributeInfo.FSnameLength = sz;
2994 sizeof(qi.u.FSattributeInfo.attributes) +
2995 sizeof(qi.u.FSattributeInfo.maxCompLength) +
2996 sizeof(qi.u.FSattributeInfo.FSnameLength) +
3001 case SMB_INFO_UNIX: /* CIFS Unix Info */
3002 case SMB_INFO_MACOS: /* Mac FS Info */
3004 return CM_ERROR_BADOP;
3007 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
3009 /* copy out return data, and set corresponding sizes */
3010 outp->totalParms = 0;
3011 outp->totalData = responseSize;
3012 memcpy(outp->datap, &qi, responseSize);
3014 /* send and free the packets */
3015 smb_SendTran2Packet(vcp, outp, op);
3016 smb_FreeTran2Packet(outp);
3021 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3023 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
3024 return CM_ERROR_BADOP;
3027 struct smb_ShortNameRock {
3028 clientchar_t *maskp;
3030 clientchar_t *shortName;
3031 size_t shortNameLen;
3034 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
3037 struct smb_ShortNameRock *rockp;
3038 normchar_t normName[MAX_PATH];
3039 clientchar_t *shortNameEnd;
3043 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t)) == 0) {
3044 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
3045 osi_LogSaveString(smb_logp, dep->name));
3049 /* compare both names and vnodes, though probably just comparing vnodes
3050 * would be safe enough.
3052 if (cm_NormStrCmpI(normName, rockp->maskp) != 0)
3054 if (ntohl(dep->fid.vnode) != rockp->vnode)
3057 /* This is the entry */
3058 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
3059 rockp->shortNameLen = shortNameEnd - rockp->shortName;
3061 return CM_ERROR_STOPNOW;
3064 long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
3065 clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
3067 struct smb_ShortNameRock rock;
3068 clientchar_t *lastNamep;
3071 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
3075 spacep = cm_GetSpace();
3076 /* smb_StripLastComponent will strip "::$DATA" if present */
3077 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
3079 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3080 caseFold, userp, tidPathp,
3082 cm_FreeSpace(spacep);
3087 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3088 cm_ReleaseSCache(dscp);
3089 cm_ReleaseUser(userp);
3093 return CM_ERROR_PATH_NOT_COVERED;
3095 #endif /* DFS_SUPPORT */
3097 if (!lastNamep) lastNamep = pathp;
3100 thyper.HighPart = 0;
3101 rock.shortName = shortName;
3103 rock.maskp = lastNamep;
3104 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
3106 cm_ReleaseSCache(dscp);
3109 return CM_ERROR_NOSUCHFILE;
3110 if (code == CM_ERROR_STOPNOW) {
3111 *shortNameLenp = rock.shortNameLen;
3117 /* TRANS2_QUERY_PATH_INFORMATION */
3118 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3120 smb_tran2Packet_t *outp;
3123 unsigned short infoLevel;
3124 smb_tran2QPathInfo_t qpi;
3126 unsigned short attributes;
3127 unsigned long extAttributes;
3128 clientchar_t shortName[13];
3132 cm_scache_t *scp, *dscp;
3133 int scp_rw_held = 0;
3136 clientchar_t *pathp;
3137 clientchar_t *tidPathp;
3138 clientchar_t *lastComp;
3143 infoLevel = p->parmsp[0];
3144 if (infoLevel == SMB_INFO_IS_NAME_VALID)
3146 else if (infoLevel == SMB_INFO_STANDARD)
3147 responseSize = sizeof(qpi.u.QPstandardInfo);
3148 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
3149 responseSize = sizeof(qpi.u.QPeaSizeInfo);
3150 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3151 responseSize = sizeof(qpi.u.QPfileBasicInfo);
3152 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3153 responseSize = sizeof(qpi.u.QPfileStandardInfo);
3154 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3155 responseSize = sizeof(qpi.u.QPfileEaInfo);
3156 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3157 responseSize = sizeof(qpi.u.QPfileNameInfo);
3158 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
3159 responseSize = sizeof(qpi.u.QPfileAllInfo);
3160 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
3161 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
3162 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO)
3163 responseSize = sizeof(qpi.u.QPfileStreamInfo);
3165 osi_Log2(smb_logp, "Bad Tran2QPathInfo op 0x%x infolevel 0x%x",
3166 p->opcode, infoLevel);
3167 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3170 memset(&qpi, 0, sizeof(qpi));
3172 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3173 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path \"%S\"", infoLevel,
3174 osi_LogSaveClientString(smb_logp, pathp));
3176 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3178 if (infoLevel > 0x100)
3179 outp->totalParms = 2;
3181 outp->totalParms = 0;
3183 /* now, if we're at infoLevel 6, we're only being asked to check
3184 * the syntax, so we just OK things now. In particular, we're *not*
3185 * being asked to verify anything about the state of any parent dirs.
3187 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
3188 smb_SendTran2Packet(vcp, outp, opx);
3189 smb_FreeTran2Packet(outp);
3193 userp = smb_GetTran2User(vcp, p);
3195 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
3196 smb_FreeTran2Packet(outp);
3197 return CM_ERROR_BADSMB;
3200 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3202 osi_Log1(smb_logp, "ReceiveTran2QPathInfo tid path lookup failure 0x%x", code);
3203 cm_ReleaseUser(userp);
3204 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
3205 smb_FreeTran2Packet(outp);
3209 osi_Log1(smb_logp, "T2 QPathInfo tidPathp \"%S\"",
3210 osi_LogSaveClientString(smb_logp, tidPathp));
3213 * XXX Strange hack XXX
3215 * As of Patch 7 (13 January 98), we are having the following problem:
3216 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3217 * requests to look up "desktop.ini" in all the subdirectories.
3218 * This can cause zillions of timeouts looking up non-existent cells
3219 * and volumes, especially in the top-level directory.
3221 * We have not found any way to avoid this or work around it except
3222 * to explicitly ignore the requests for mount points that haven't
3223 * yet been evaluated and for directories that haven't yet been
3226 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3227 spacep = cm_GetSpace();
3228 /* smb_StripLastComponent will strip "::$DATA" if present */
3229 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3230 #ifndef SPECIAL_FOLDERS
3231 /* Make sure that lastComp is not NULL */
3233 if (cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
3234 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3238 userp, tidPathp, &req, &dscp);
3241 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3242 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3244 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3245 code = CM_ERROR_PATH_NOT_COVERED;
3247 code = CM_ERROR_NOSUCHPATH;
3249 #endif /* DFS_SUPPORT */
3250 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3251 code = CM_ERROR_NOSUCHFILE;
3252 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3253 cm_buf_t *bp = buf_Find(dscp, &hzero);
3259 code = CM_ERROR_NOSUCHFILE;
3261 cm_ReleaseSCache(dscp);
3263 cm_FreeSpace(spacep);
3264 cm_ReleaseUser(userp);
3265 smb_SendTran2Error(vcp, p, opx, code);
3266 smb_FreeTran2Packet(outp);
3272 #endif /* SPECIAL_FOLDERS */
3274 cm_FreeSpace(spacep);
3277 /* now do namei and stat, and copy out the info */
3278 code = cm_NameI(cm_data.rootSCachep, pathp,
3279 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3282 cm_ReleaseUser(userp);
3283 smb_SendTran2Error(vcp, p, opx, code);
3284 smb_FreeTran2Packet(outp);
3289 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3290 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3291 cm_ReleaseSCache(scp);
3292 cm_ReleaseUser(userp);
3293 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3294 code = CM_ERROR_PATH_NOT_COVERED;
3296 code = CM_ERROR_NOSUCHPATH;
3297 smb_SendTran2Error(vcp, p, opx, code);
3298 smb_FreeTran2Packet(outp);
3301 #endif /* DFS_SUPPORT */
3303 lock_ObtainWrite(&scp->rw);
3305 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3306 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3310 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3312 lock_ConvertWToR(&scp->rw);
3317 /* now we have the status in the cache entry, and everything is locked.
3318 * Marshall the output data.
3320 /* for info level 108, figure out short name */
3321 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3322 code = cm_GetShortName(pathp, userp, &req,
3323 tidPathp, scp->fid.vnode, shortName,
3329 smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
3330 qpi.u.QPfileAltNameInfo.fileNameLength = len;
3331 responseSize = sizeof(unsigned long) + len;
3333 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3334 smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3335 qpi.u.QPfileNameInfo.fileNameLength = len;
3336 responseSize = sizeof(unsigned long) + len;
3338 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3339 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3340 qpi.u.QPstandardInfo.creationDateTime = dosTime;
3341 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3342 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3343 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3344 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3345 attributes = smb_Attributes(scp);
3346 qpi.u.QPstandardInfo.attributes = attributes;
3347 qpi.u.QPstandardInfo.eaSize = 0;
3349 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3350 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3351 qpi.u.QPfileBasicInfo.creationTime = ft;
3352 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3353 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3354 qpi.u.QPfileBasicInfo.changeTime = ft;
3355 extAttributes = smb_ExtAttributes(scp);
3356 qpi.u.QPfileBasicInfo.attributes = extAttributes;
3357 qpi.u.QPfileBasicInfo.reserved = 0;
3359 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3362 lock_ReleaseRead(&scp->rw);
3364 fidp = smb_FindFIDByScache(vcp, scp);
3366 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3367 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3368 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3369 qpi.u.QPfileStandardInfo.directory =
3370 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3371 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3372 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3373 qpi.u.QPfileStandardInfo.reserved = 0;
3376 lock_ObtainMutex(&fidp->mx);
3377 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3378 lock_ReleaseMutex(&fidp->mx);
3379 smb_ReleaseFID(fidp);
3381 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3383 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3384 qpi.u.QPfileEaInfo.eaSize = 0;
3386 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3389 lock_ReleaseRead(&scp->rw);
3391 fidp = smb_FindFIDByScache(vcp, scp);
3393 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3394 qpi.u.QPfileAllInfo.creationTime = ft;
3395 qpi.u.QPfileAllInfo.lastAccessTime = ft;
3396 qpi.u.QPfileAllInfo.lastWriteTime = ft;
3397 qpi.u.QPfileAllInfo.changeTime = ft;
3398 extAttributes = smb_ExtAttributes(scp);
3399 qpi.u.QPfileAllInfo.attributes = extAttributes;
3400 qpi.u.QPfileAllInfo.allocationSize = scp->length;
3401 qpi.u.QPfileAllInfo.endOfFile = scp->length;
3402 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3403 qpi.u.QPfileAllInfo.deletePending = 0;
3404 qpi.u.QPfileAllInfo.directory =
3405 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3406 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3407 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3408 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.vnode;
3409 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.unique;
3410 qpi.u.QPfileAllInfo.eaSize = 0;
3411 qpi.u.QPfileAllInfo.accessFlags = 0;
3413 lock_ObtainMutex(&fidp->mx);
3414 if (fidp->flags & SMB_FID_OPENDELETE)
3415 qpi.u.QPfileAllInfo.accessFlags |= DELETE;
3416 if (fidp->flags & SMB_FID_OPENREAD_LISTDIR)
3417 qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_READ|AFS_ACCESS_EXECUTE;
3418 if (fidp->flags & SMB_FID_OPENWRITE)
3419 qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_WRITE;
3420 if (fidp->flags & SMB_FID_DELONCLOSE)
3421 qpi.u.QPfileAllInfo.deletePending = 1;
3422 lock_ReleaseMutex(&fidp->mx);
3423 smb_ReleaseFID(fidp);
3425 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.cell;
3426 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.volume;
3427 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3428 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3429 qpi.u.QPfileAllInfo.mode = 0;
3430 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3432 smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3433 qpi.u.QPfileAllInfo.fileNameLength = len;
3434 responseSize -= (sizeof(qpi.u.QPfileAllInfo.fileName) - len);
3436 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO) {
3438 /* For now we have no streams */
3439 qpi.u.QPfileStreamInfo.nextEntryOffset = 0;
3440 if (scp->fileType == CM_SCACHETYPE_FILE) {
3441 qpi.u.QPfileStreamInfo.streamSize = scp->length;
3442 qpi.u.QPfileStreamInfo.streamAllocationSize = scp->length;
3443 smb_UnparseString(opx, qpi.u.QPfileStreamInfo.fileName, L"::$DATA", &len, SMB_STRF_IGNORENUL);
3444 qpi.u.QPfileStreamInfo.streamNameLength = len;
3445 responseSize -= (sizeof(qpi.u.QPfileStreamInfo.fileName) - len);
3447 qpi.u.QPfileStreamInfo.streamSize.QuadPart = 0;
3448 qpi.u.QPfileStreamInfo.streamAllocationSize.QuadPart = 0;
3449 smb_UnparseString(opx, qpi.u.QPfileStreamInfo.fileName, L"", &len, SMB_STRF_IGNORENUL);
3450 qpi.u.QPfileStreamInfo.streamNameLength = 0;
3454 outp->totalData = responseSize;
3456 /* send and free the packets */
3458 switch (scp_rw_held) {
3460 lock_ReleaseRead(&scp->rw);
3463 lock_ReleaseWrite(&scp->rw);
3467 cm_ReleaseSCache(scp);
3468 cm_ReleaseUser(userp);
3470 memcpy(outp->datap, &qpi, responseSize);
3471 smb_SendTran2Packet(vcp, outp, opx);
3473 smb_SendTran2Error(vcp, p, opx, code);
3475 smb_FreeTran2Packet(outp);
3480 /* TRANS2_SET_PATH_INFORMATION */
3481 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3484 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
3485 return CM_ERROR_BADOP;
3488 unsigned short infoLevel;
3489 clientchar_t * pathp;
3490 smb_tran2Packet_t *outp;
3491 smb_tran2QPathInfo_t *spi;
3493 cm_scache_t *scp, *dscp;
3496 clientchar_t *tidPathp;
3497 clientchar_t *lastComp;
3501 infoLevel = p->parmsp[0];
3502 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
3503 if (infoLevel != SMB_INFO_STANDARD &&
3504 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
3505 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
3506 osi_Log2(smb_logp, "Bad Tran2SetPathInfo op 0x%x infolevel 0x%x",
3507 p->opcode, infoLevel);
3508 smb_SendTran2Error(vcp, p, opx,
3509 infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3513 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3515 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
3516 osi_LogSaveClientString(smb_logp, pathp));
3518 userp = smb_GetTran2User(vcp, p);
3520 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3521 code = CM_ERROR_BADSMB;
3525 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3526 if (code == CM_ERROR_TIDIPC) {
3527 /* Attempt to use a TID allocated for IPC. The client
3528 * is probably looking for DCE RPC end points which we
3529 * don't support OR it could be looking to make a DFS
3532 osi_Log0(smb_logp, "Tran2Open received IPC TID");
3533 cm_ReleaseUser(userp);
3534 return CM_ERROR_NOSUCHPATH;
3538 * XXX Strange hack XXX
3540 * As of Patch 7 (13 January 98), we are having the following problem:
3541 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3542 * requests to look up "desktop.ini" in all the subdirectories.
3543 * This can cause zillions of timeouts looking up non-existent cells
3544 * and volumes, especially in the top-level directory.
3546 * We have not found any way to avoid this or work around it except
3547 * to explicitly ignore the requests for mount points that haven't
3548 * yet been evaluated and for directories that haven't yet been
3551 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3552 spacep = cm_GetSpace();
3553 /* smb_StripLastComponent will strip "::$DATA" if present */
3554 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3555 #ifndef SPECIAL_FOLDERS
3556 /* Make sure that lastComp is not NULL */
3558 if (cm_ClientStrCmpI(lastComp, _C("\\desktop.ini")) == 0) {
3559 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3563 userp, tidPathp, &req, &dscp);
3566 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3567 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3569 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3570 code = CM_ERROR_PATH_NOT_COVERED;
3572 code = CM_ERROR_NOSUCHPATH;
3574 #endif /* DFS_SUPPORT */
3575 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3576 code = CM_ERROR_NOSUCHFILE;
3577 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3578 cm_buf_t *bp = buf_Find(dscp, &hzero);
3584 code = CM_ERROR_NOSUCHFILE;
3586 cm_ReleaseSCache(dscp);
3588 cm_FreeSpace(spacep);
3589 cm_ReleaseUser(userp);
3590 smb_SendTran2Error(vcp, p, opx, code);
3596 #endif /* SPECIAL_FOLDERS */
3598 cm_FreeSpace(spacep);
3601 /* now do namei and stat, and copy out the info */
3602 code = cm_NameI(cm_data.rootSCachep, pathp,
3603 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3605 cm_ReleaseUser(userp);
3606 smb_SendTran2Error(vcp, p, opx, code);
3610 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3612 outp->totalParms = 2;
3613 outp->totalData = 0;
3615 spi = (smb_tran2QPathInfo_t *)p->datap;
3616 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3619 /* lock the vnode with a callback; we need the current status
3620 * to determine what the new status is, in some cases.
3622 lock_ObtainWrite(&scp->rw);
3623 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3624 CM_SCACHESYNC_GETSTATUS
3625 | CM_SCACHESYNC_NEEDCALLBACK);
3627 lock_ReleaseWrite(&scp->rw);
3630 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3632 /* prepare for setattr call */
3633 attr.mask = CM_ATTRMASK_LENGTH;
3634 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3635 attr.length.HighPart = 0;
3637 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3638 cm_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3639 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3642 if (spi->u.QPstandardInfo.attributes != 0) {
3643 if ((scp->unixModeBits & 0200)
3644 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3645 /* make a writable file read-only */
3646 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3647 attr.unixModeBits = scp->unixModeBits & ~0222;
3649 else if ((scp->unixModeBits & 0200) == 0
3650 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3651 /* make a read-only file writable */
3652 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3653 attr.unixModeBits = scp->unixModeBits | 0222;
3656 lock_ReleaseRead(&scp->rw);
3660 code = cm_SetAttr(scp, &attr, userp, &req);
3664 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3665 /* we don't support EAs */
3666 code = CM_ERROR_EAS_NOT_SUPPORTED;
3670 cm_ReleaseSCache(scp);
3671 cm_ReleaseUser(userp);
3673 smb_SendTran2Packet(vcp, outp, opx);
3675 smb_SendTran2Error(vcp, p, opx, code);
3676 smb_FreeTran2Packet(outp);
3682 /* TRANS2_QUERY_FILE_INFORMATION */
3683 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3685 smb_tran2Packet_t *outp;
3687 unsigned long attributes;
3688 unsigned short infoLevel;
3695 smb_tran2QFileInfo_t qfi;
3703 fidp = smb_FindFID(vcp, fid, 0);
3706 osi_Log2(smb_logp, "Tran2QFileInfo Unknown SMB Fid vcp 0x%p fid %d",
3708 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3712 lock_ObtainMutex(&fidp->mx);
3713 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3714 lock_ReleaseMutex(&fidp->mx);
3715 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3716 smb_CloseFID(vcp, fidp, NULL, 0);
3717 smb_ReleaseFID(fidp);
3720 lock_ReleaseMutex(&fidp->mx);
3722 infoLevel = p->parmsp[1];
3723 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3724 responseSize = sizeof(qfi.u.QFbasicInfo);
3725 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3726 responseSize = sizeof(qfi.u.QFstandardInfo);
3727 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3728 responseSize = sizeof(qfi.u.QFeaInfo);
3729 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3730 responseSize = sizeof(qfi.u.QFfileNameInfo);
3731 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO)
3732 responseSize = sizeof(qfi.u.QFfileStreamInfo);
3734 osi_Log2(smb_logp, "Bad Tran2QFileInfo op 0x%x infolevel 0x%x",
3735 p->opcode, infoLevel);
3736 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3737 smb_ReleaseFID(fidp);
3740 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3741 memset(&qfi, 0, sizeof(qfi));
3743 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3745 if (infoLevel > 0x100)
3746 outp->totalParms = 2;
3748 outp->totalParms = 0;
3750 userp = smb_GetTran2User(vcp, p);
3752 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3753 code = CM_ERROR_BADSMB;
3757 lock_ObtainMutex(&fidp->mx);
3758 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3760 osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3762 lock_ReleaseMutex(&fidp->mx);
3763 lock_ObtainWrite(&scp->rw);
3764 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3765 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3769 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3771 lock_ConvertWToR(&scp->rw);
3774 /* now we have the status in the cache entry, and everything is locked.
3775 * Marshall the output data.
3777 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3778 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3779 qfi.u.QFbasicInfo.creationTime = ft;
3780 qfi.u.QFbasicInfo.lastAccessTime = ft;
3781 qfi.u.QFbasicInfo.lastWriteTime = ft;
3782 qfi.u.QFbasicInfo.lastChangeTime = ft;
3783 attributes = smb_ExtAttributes(scp);
3784 qfi.u.QFbasicInfo.attributes = attributes;
3786 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3787 qfi.u.QFstandardInfo.allocationSize = scp->length;
3788 qfi.u.QFstandardInfo.endOfFile = scp->length;
3789 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3790 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3791 qfi.u.QFstandardInfo.directory =
3792 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3793 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3794 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3796 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3797 qfi.u.QFeaInfo.eaSize = 0;
3799 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3803 lock_ReleaseRead(&scp->rw);
3804 lock_ObtainMutex(&fidp->mx);
3805 lock_ObtainRead(&scp->rw);
3806 if (fidp->NTopen_wholepathp)
3807 name = fidp->NTopen_wholepathp;
3809 name = _C("\\"); /* probably can't happen */
3810 lock_ReleaseMutex(&fidp->mx);
3812 smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, SMB_STRF_IGNORENUL);
3813 responseSize = len + 4; /* this is actually what we want to return */
3814 qfi.u.QFfileNameInfo.fileNameLength = len;
3816 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO) {
3819 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3820 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3821 scp->fileType == CM_SCACHETYPE_INVALID) {
3822 /* Do not return the alternate streams for directories */
3825 /* For now we have no alternate streams */
3826 qfi.u.QFfileStreamInfo.nextEntryOffset = 0;
3827 qfi.u.QFfileStreamInfo.streamSize = scp->length;
3828 qfi.u.QFfileStreamInfo.streamAllocationSize = scp->length;
3829 smb_UnparseString(opx, qfi.u.QFfileStreamInfo.fileName, L"::$DATA", &len, SMB_STRF_IGNORENUL);
3830 qfi.u.QFfileStreamInfo.streamNameLength = len;
3831 responseSize -= (sizeof(qfi.u.QFfileStreamInfo.fileName) - len);
3834 outp->totalData = responseSize;
3836 /* send and free the packets */
3839 lock_ReleaseRead(&scp->rw);
3841 lock_ReleaseWrite(&scp->rw);
3842 cm_ReleaseSCache(scp);
3843 cm_ReleaseUser(userp);
3844 smb_ReleaseFID(fidp);
3846 memcpy(outp->datap, &qfi, responseSize);
3847 smb_SendTran2Packet(vcp, outp, opx);
3849 smb_SendTran2Error(vcp, p, opx, code);
3851 smb_FreeTran2Packet(outp);
3857 /* TRANS2_SET_FILE_INFORMATION */
3858 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3863 unsigned short infoLevel;
3864 smb_tran2Packet_t *outp;
3865 cm_user_t *userp = NULL;
3866 cm_scache_t *scp = NULL;
3872 fidp = smb_FindFID(vcp, fid, 0);
3875 osi_Log2(smb_logp, "Tran2SetFileInfo Unknown SMB Fid vcp 0x%p fid %d",
3877 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3881 infoLevel = p->parmsp[1];
3882 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3883 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3884 osi_Log2(smb_logp, "Bad Tran2SetFileInfo op 0x%x infolevel 0x%x",
3885 p->opcode, infoLevel);
3886 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3887 smb_ReleaseFID(fidp);
3891 lock_ObtainMutex(&fidp->mx);
3892 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3893 lock_ReleaseMutex(&fidp->mx);
3894 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3895 smb_CloseFID(vcp, fidp, NULL, 0);
3896 smb_ReleaseFID(fidp);
3900 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
3901 !(fidp->flags & SMB_FID_OPENDELETE)) {
3902 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3903 fidp, fidp->scp, fidp->flags);
3904 lock_ReleaseMutex(&fidp->mx);
3905 smb_ReleaseFID(fidp);
3906 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3909 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3910 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3911 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3912 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3913 fidp, fidp->scp, fidp->flags);
3914 lock_ReleaseMutex(&fidp->mx);
3915 smb_ReleaseFID(fidp);
3916 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3921 osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3923 lock_ReleaseMutex(&fidp->mx);
3925 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3927 outp->totalParms = 2;
3928 outp->totalData = 0;
3930 userp = smb_GetTran2User(vcp, p);
3932 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3933 code = CM_ERROR_BADSMB;
3937 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3939 unsigned int attribute;
3941 smb_tran2QFileInfo_t *sfi;
3943 sfi = (smb_tran2QFileInfo_t *)p->datap;
3945 /* lock the vnode with a callback; we need the current status
3946 * to determine what the new status is, in some cases.
3948 lock_ObtainWrite(&scp->rw);
3949 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3950 CM_SCACHESYNC_GETSTATUS
3951 | CM_SCACHESYNC_NEEDCALLBACK);
3953 lock_ReleaseWrite(&scp->rw);
3957 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3959 lock_ReleaseWrite(&scp->rw);
3960 lock_ObtainMutex(&fidp->mx);
3961 lock_ObtainRead(&scp->rw);
3963 /* prepare for setattr call */
3966 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3967 /* when called as result of move a b, lastMod is (-1, -1).
3968 * If the check for -1 is not present, timestamp
3969 * of the resulting file will be 1969 (-1)
3971 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3972 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3973 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3974 cm_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3975 fidp->flags |= SMB_FID_MTIMESETDONE;
3978 attribute = sfi->u.QFbasicInfo.attributes;
3979 if (attribute != 0) {
3980 if ((scp->unixModeBits & 0200)
3981 && (attribute & SMB_ATTR_READONLY) != 0) {
3982 /* make a writable file read-only */
3983 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3984 attr.unixModeBits = scp->unixModeBits & ~0222;
3986 else if ((scp->unixModeBits & 0200) == 0
3987 && (attribute & SMB_ATTR_READONLY) == 0) {
3988 /* make a read-only file writable */
3989 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3990 attr.unixModeBits = scp->unixModeBits | 0222;
3993 lock_ReleaseRead(&scp->rw);
3994 lock_ReleaseMutex(&fidp->mx);
3998 code = cm_SetAttr(scp, &attr, userp, &req);
4002 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
4003 int delflag = *((char *)(p->datap));
4004 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
4005 delflag, fidp, scp);
4006 if (*((char *)(p->datap))) { /* File is Deleted */
4007 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
4010 lock_ObtainMutex(&fidp->mx);
4011 fidp->flags |= SMB_FID_DELONCLOSE;
4012 lock_ReleaseMutex(&fidp->mx);
4014 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
4020 lock_ObtainMutex(&fidp->mx);
4021 fidp->flags &= ~SMB_FID_DELONCLOSE;
4022 lock_ReleaseMutex(&fidp->mx);
4025 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
4026 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
4027 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
4030 attr.mask = CM_ATTRMASK_LENGTH;
4031 attr.length.LowPart = size.LowPart;
4032 attr.length.HighPart = size.HighPart;
4033 code = cm_SetAttr(scp, &attr, userp, &req);
4037 cm_ReleaseSCache(scp);
4038 cm_ReleaseUser(userp);
4039 smb_ReleaseFID(fidp);
4041 smb_SendTran2Packet(vcp, outp, opx);
4043 smb_SendTran2Error(vcp, p, opx, code);
4044 smb_FreeTran2Packet(outp);
4051 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4053 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
4054 return CM_ERROR_BADOP;
4059 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4061 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
4062 return CM_ERROR_BADOP;
4065 /* TRANS2_FIND_NOTIFY_FIRST */
4067 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4069 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
4070 return CM_ERROR_BADOP;
4073 /* TRANS2_FIND_NOTIFY_NEXT */
4075 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4077 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
4078 return CM_ERROR_BADOP;
4081 /* TRANS2_CREATE_DIRECTORY */
4083 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4085 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
4086 return CM_ERROR_BADOP;
4089 /* TRANS2_SESSION_SETUP */
4091 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4093 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
4094 return CM_ERROR_BADOP;
4097 struct smb_v2_referral {
4099 USHORT ReferralFlags;
4102 USHORT DfsPathOffset;
4103 USHORT DfsAlternativePathOffset;
4104 USHORT NetworkAddressOffset;
4107 /* TRANS2_GET_DFS_REFERRAL */
4109 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
4111 /* This is a UNICODE only request (bit15 of Flags2) */
4112 /* The TID must be IPC$ */
4114 /* The documentation for the Flags response field is contradictory */
4116 /* Use Version 1 Referral Element Format */
4117 /* ServerType = 0; indicates the next server should be queried for the file */
4118 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
4119 /* Node = UnicodeString of UNC path of the next share name */
4122 int maxReferralLevel = 0;
4123 clientchar_t requestFileName[1024] = _C("");
4124 clientchar_t referralPath[1024] = _C("");
4125 smb_tran2Packet_t *outp = 0;
4126 cm_user_t *userp = 0;
4127 cm_scache_t *scp = 0;
4128 cm_scache_t *dscp = 0;
4130 CPINFO CodePageInfo;
4131 int i, nbnLen, reqLen, refLen;
4136 maxReferralLevel = p->parmsp[0];
4138 GetCPInfo(CP_ACP, &CodePageInfo);
4139 cm_Utf16ToClientString(&p->parmsp[1], -1, requestFileName, lengthof(requestFileName));
4141 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%S]",
4142 maxReferralLevel, osi_LogSaveClientString(smb_logp, requestFileName));
4144 nbnLen = (int)cm_ClientStrLen(cm_NetbiosNameC);
4145 reqLen = (int)cm_ClientStrLen(requestFileName);
4147 if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
4148 !cm_ClientStrCmpNI(cm_NetbiosNameC, &requestFileName[1], nbnLen) &&
4149 requestFileName[nbnLen+1] == '\\')
4153 if (!cm_ClientStrCmpNI(_C("all"), &requestFileName[nbnLen+2], 3) ||
4154 !cm_ClientStrCmpNI(_C("*."), &requestFileName[nbnLen+2], 2)) {
4156 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4159 userp = smb_GetTran2User(vcp, p);
4161 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
4162 code = CM_ERROR_BADSMB;
4167 * We have a requested path. Check to see if it is something
4170 * But be careful because the name that we might be searching
4171 * for might be a known name with the final character stripped
4174 code = cm_NameI(cm_data.rootSCachep, &requestFileName[nbnLen+2],
4175 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
4176 userp, NULL, &req, &scp);
4178 code == CM_ERROR_ALLDOWN ||
4179 code == CM_ERROR_ALLBUSY ||
4180 code == CM_ERROR_ALLOFFLINE ||
4181 code == CM_ERROR_NOSUCHCELL ||
4182 code == CM_ERROR_NOSUCHVOLUME ||
4183 code == CM_ERROR_NOACCESS) {
4186 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4188 } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
4189 clientchar_t temp[1024];
4190 clientchar_t pathName[1024];
4191 clientchar_t *lastComponent;
4193 * we have a msdfs link somewhere in the path
4194 * we should figure out where in the path the link is.
4197 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%S]", requestFileName);
4199 cm_ClientStrCpy(temp, lengthof(temp), &requestFileName[nbnLen+2]);
4203 cm_ReleaseSCache(dscp);
4207 cm_ReleaseSCache(scp);
4210 /* smb_StripLastComponent will strip "::$DATA" if present */
4211 smb_StripLastComponent(pathName, &lastComponent, temp);
4213 code = cm_NameI(cm_data.rootSCachep, pathName,
4214 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4215 userp, NULL, &req, &dscp);
4217 code = cm_NameI(dscp, ++lastComponent,
4219 userp, NULL, &req, &scp);
4220 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK)
4223 } while (code == CM_ERROR_PATH_NOT_COVERED);
4225 /* scp should now be the DfsLink we are looking for */
4227 /* figure out how much of the input path was used */
4228 reqLen = (int)(nbnLen+2 + cm_ClientStrLen(pathName) + 1 + cm_ClientStrLen(lastComponent));
4230 cm_FsStringToClientString(&scp->mountPointStringp[strlen("msdfs:")], -1,
4231 referralPath, lengthof(referralPath));
4232 refLen = (int)cm_ClientStrLen(referralPath);
4236 clientchar_t shareName[MAX_PATH + 1];
4237 clientchar_t *p, *q;
4238 /* we may have a sharename that is a volume reference */
4240 for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
4246 if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
4247 code = cm_NameI(cm_data.rootSCachep, _C(""),
4248 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
4249 userp, p, &req, &scp);
4254 cm_ClientStrCpy(referralPath, lengthof(referralPath),
4265 struct smb_v2_referral * v2ref;
4266 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (refLen + 8));
4268 sp = (USHORT *)outp->datap;
4270 sp[idx++] = reqLen; /* path consumed */
4271 sp[idx++] = 1; /* number of referrals */
4272 sp[idx++] = 0x03; /* flags */
4273 #ifdef DFS_VERSION_1
4274 sp[idx++] = 1; /* Version Number */
4275 sp[idx++] = refLen + 4; /* Referral Size */
4276 sp[idx++] = 1; /* Type = SMB Server */
4277 sp[idx++] = 0; /* Do not strip path consumed */
4278 for ( i=0;i<=refLen; i++ )
4279 sp[i+idx] = referralPath[i];
4280 #else /* DFS_VERSION_2 */
4281 sp[idx++] = 2; /* Version Number */
4282 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
4283 idx += (sizeof(struct smb_v2_referral) / 2);
4284 v2ref = (struct smb_v2_referral *) &sp[5];
4285 v2ref->ServerType = 1; /* SMB Server */
4286 v2ref->ReferralFlags = 0x03;
4287 v2ref->Proximity = 0; /* closest */
4288 v2ref->TimeToLive = 3600; /* seconds */
4289 v2ref->DfsPathOffset = idx * 2;
4290 v2ref->DfsAlternativePathOffset = idx * 2;
4291 v2ref->NetworkAddressOffset = 0;
4292 for ( i=0;i<=refLen; i++ )
4293 sp[i+idx] = referralPath[i];
4296 code = CM_ERROR_NOSUCHPATH;
4299 code = CM_ERROR_NOSUCHPATH;
4304 cm_ReleaseSCache(dscp);
4306 cm_ReleaseSCache(scp);
4308 cm_ReleaseUser(userp);
4310 smb_SendTran2Packet(vcp, outp, op);
4312 smb_SendTran2Error(vcp, p, op, code);
4314 smb_FreeTran2Packet(outp);
4317 #else /* DFS_SUPPORT */
4318 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
4319 return CM_ERROR_NOSUCHDEVICE;
4320 #endif /* DFS_SUPPORT */
4323 /* TRANS2_REPORT_DFS_INCONSISTENCY */
4325 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4327 /* This is a UNICODE only request (bit15 of Flags2) */
4329 /* There is nothing we can do about this operation. The client is going to
4330 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
4331 * Unfortunately, there is really nothing we can do about it other then log it
4332 * somewhere. Even then I don't think there is anything for us to do.
4333 * So let's return an error value.
4336 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
4337 return CM_ERROR_BADOP;
4341 smb_ApplyV3DirListPatches(cm_scache_t *dscp, smb_dirListPatch_t **dirPatchespp,
4342 clientchar_t * tidPathp, clientchar_t * relPathp,
4343 int infoLevel, cm_user_t *userp, cm_req_t *reqp)
4347 cm_scache_t *targetScp; /* target if scp is a symlink */
4350 unsigned short attr;
4351 unsigned long lattr;
4352 smb_dirListPatch_t *patchp;
4353 smb_dirListPatch_t *npatchp;
4355 afs_int32 mustFake = 0;
4356 clientchar_t path[AFSPATHMAX];
4358 code = cm_FindACLCache(dscp, userp, &rights);
4360 lock_ObtainWrite(&dscp->rw);
4361 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4362 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4364 cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4365 lock_ReleaseWrite(&dscp->rw);
4366 if (code == CM_ERROR_NOACCESS) {
4374 if (!mustFake) { /* Bulk Stat */
4376 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4378 memset(bsp, 0, sizeof(cm_bulkStat_t));
4380 for (patchp = *dirPatchespp, count=0;
4382 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4383 cm_scache_t *tscp = NULL;
4386 code = cm_GetSCache(&patchp->fid, &tscp, userp, reqp);
4388 if (lock_TryWrite(&tscp->rw)) {
4389 /* we have an entry that we can look at */
4390 #ifdef AFS_FREELANCE_CLIENT
4391 if (dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID && dscp->fid.volume == AFS_FAKE_ROOT_VOL_ID) {
4392 code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
4393 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4395 cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4397 lock_ReleaseWrite(&tscp->rw);
4398 cm_ReleaseSCache(tscp);
4401 #endif /* AFS_FREELANCE_CLIENT */
4402 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4403 /* we have a callback on it. Don't bother
4404 * fetching this stat entry, since we're happy
4405 * with the info we have.
4407 lock_ReleaseWrite(&tscp->rw);
4408 cm_ReleaseSCache(tscp);
4411 lock_ReleaseWrite(&tscp->rw);
4413 cm_ReleaseSCache(tscp);
4417 bsp->fids[i].Volume = patchp->fid.volume;
4418 bsp->fids[i].Vnode = patchp->fid.vnode;
4419 bsp->fids[i].Unique = patchp->fid.unique;
4421 if (bsp->counter == AFSCBMAX) {
4422 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4423 memset(bsp, 0, sizeof(cm_bulkStat_t));
4427 if (bsp->counter > 0)
4428 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4433 for( patchp = *dirPatchespp;
4435 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4436 cm_ClientStrPrintfN(path, lengthof(path),_C("%s\\%S"),
4437 relPathp ? relPathp : _C(""), patchp->dep->name);
4438 reqp->relPathp = path;
4439 reqp->tidPathp = tidPathp;
4441 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4442 reqp->relPathp = reqp->tidPathp = NULL;
4446 lock_ObtainWrite(&scp->rw);
4447 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4448 lock_ReleaseWrite(&scp->rw);
4450 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4451 errors in the client. */
4452 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4453 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4455 /* 1969-12-31 23:59:59 +00 */
4456 ft.dwHighDateTime = 0x19DB200;
4457 ft.dwLowDateTime = 0x5BB78980;
4459 /* copy to Creation Time */
4460 fa->creationTime = ft;
4461 fa->lastAccessTime = ft;
4462 fa->lastWriteTime = ft;
4463 fa->lastChangeTime = ft;
4465 switch (scp->fileType) {
4466 case CM_SCACHETYPE_DIRECTORY:
4467 case CM_SCACHETYPE_MOUNTPOINT:
4468 case CM_SCACHETYPE_INVALID:
4469 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4471 case CM_SCACHETYPE_SYMLINK:
4472 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4473 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4475 fa->extFileAttributes = SMB_ATTR_NORMAL;
4478 /* if we get here we either have a normal file
4479 * or we have a file for which we have never
4480 * received status info. In this case, we can
4481 * check the even/odd value of the entry's vnode.
4482 * odd means it is to be treated as a directory
4483 * and even means it is to be treated as a file.
4485 if (mustFake && (scp->fid.vnode & 0x1))
4486 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4488 fa->extFileAttributes = SMB_ATTR_NORMAL;
4490 /* merge in hidden attribute */
4491 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4492 fa->extFileAttributes |= SMB_ATTR_HIDDEN;
4495 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4497 /* 1969-12-31 23:59:58 +00*/
4498 dosTime = 0xEBBFBF7D;
4500 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4501 fa->lastAccessDateTime = fa->creationDateTime;
4502 fa->lastWriteDateTime = fa->creationDateTime;
4504 /* set the attribute */
4505 switch (scp->fileType) {
4506 case CM_SCACHETYPE_DIRECTORY:
4507 case CM_SCACHETYPE_MOUNTPOINT:
4508 case CM_SCACHETYPE_INVALID:
4509 fa->attributes = SMB_ATTR_DIRECTORY;
4511 case CM_SCACHETYPE_SYMLINK:
4512 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4513 fa->attributes = SMB_ATTR_DIRECTORY;
4515 fa->attributes = SMB_ATTR_NORMAL;
4518 /* if we get here we either have a normal file
4519 * or we have a file for which we have never
4520 * received status info. In this case, we can
4521 * check the even/odd value of the entry's vnode.
4522 * even means it is to be treated as a directory
4523 * and odd means it is to be treated as a file.
4525 if (mustFake && (scp->fid.vnode & 0x1))
4526 fa->attributes = SMB_ATTR_DIRECTORY;
4528 fa->attributes = SMB_ATTR_NORMAL;
4531 /* merge in hidden (dot file) attribute */
4532 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4533 fa->attributes |= SMB_ATTR_HIDDEN;
4537 cm_ReleaseSCache(scp);
4541 /* now watch for a symlink */
4543 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
4544 lock_ReleaseWrite(&scp->rw);
4545 cm_ClientStrPrintfN(path, lengthof(path), _C("%s\\%S"),
4546 relPathp ? relPathp : _C(""), patchp->dep->name);
4547 reqp->relPathp = path;
4548 reqp->tidPathp = tidPathp;
4549 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
4550 reqp->relPathp = reqp->tidPathp = NULL;
4552 /* we have a more accurate file to use (the
4553 * target of the symbolic link). Otherwise,
4554 * we'll just use the symlink anyway.
4556 osi_Log2(smb_logp, "symlink vp %x to vp %x",
4558 cm_ReleaseSCache(scp);
4561 lock_ObtainWrite(&scp->rw);
4564 lock_ConvertWToR(&scp->rw);
4566 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4567 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4570 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4572 fa->creationTime = ft;
4573 fa->lastAccessTime = ft;
4574 fa->lastWriteTime = ft;
4575 fa->lastChangeTime = ft;
4577 /* Use length for both file length and alloc length */
4578 fa->endOfFile = scp->length;
4579 fa->allocationSize = scp->length;
4581 /* Copy attributes */
4582 lattr = smb_ExtAttributes(scp);
4583 if ((code == CM_ERROR_NOSUCHPATH &&
4584 (scp->fileType == CM_SCACHETYPE_SYMLINK &&
4585 cm_TargetPerceivedAsDirectory(scp->mountPointStringp))) ||
4586 code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4587 if (lattr == SMB_ATTR_NORMAL)
4588 lattr = SMB_ATTR_DIRECTORY;
4590 lattr |= SMB_ATTR_DIRECTORY;
4592 /* merge in hidden (dot file) attribute */
4593 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4594 if (lattr == SMB_ATTR_NORMAL)
4595 lattr = SMB_ATTR_HIDDEN;
4597 lattr |= SMB_ATTR_HIDDEN;
4600 fa->extFileAttributes = lattr;
4602 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4605 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4607 fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
4608 fa->lastAccessDateTime = fa->creationDateTime;
4609 fa->lastWriteDateTime = fa->creationDateTime;
4611 /* copy out file length and alloc length,
4612 * using the same for both
4614 fa->dataSize = scp->length.LowPart;
4615 fa->allocationSize = scp->length.LowPart;
4617 /* finally copy out attributes as short */
4618 attr = smb_Attributes(scp);
4619 /* merge in hidden (dot file) attribute */
4620 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4621 if (lattr == SMB_ATTR_NORMAL)
4622 lattr = SMB_ATTR_HIDDEN;
4624 lattr |= SMB_ATTR_HIDDEN;
4626 fa->attributes = attr;
4629 lock_ReleaseRead(&scp->rw);
4630 cm_ReleaseSCache(scp);
4633 /* now free the patches */
4634 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4635 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4639 /* and mark the list as empty */
4640 *dirPatchespp = NULL;
4646 /* smb_ReceiveTran2SearchDir implements both
4647 * Tran2_Find_First and Tran2_Find_Next
4649 #define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
4650 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
4651 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
4652 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
4653 #define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
4655 /* this is an optimized handler for T2SearchDir that handles the case
4656 where there are no wildcards in the search path. I.e. an
4657 application is using FindFirst(Ex) to get information about a
4658 single file or directory. It will attempt to do a single lookup.
4659 If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4660 the usual mechanism.
4662 This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4664 TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
4666 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4670 long code = 0, code2 = 0;
4671 clientchar_t *pathp = 0;
4673 smb_dirListPatch_t *dirListPatchesp;
4674 smb_dirListPatch_t *curPatchp;
4675 size_t orbytes; /* # of bytes in this output record */
4676 size_t ohbytes; /* # of bytes, except file name */
4677 size_t onbytes; /* # of bytes in name, incl. term. null */
4678 cm_scache_t *scp = NULL;
4679 cm_scache_t *targetscp = NULL;
4680 cm_user_t *userp = NULL;
4681 char *op; /* output data ptr */
4682 char *origOp; /* original value of op */
4683 cm_space_t *spacep; /* for pathname buffer */
4684 unsigned long maxReturnData; /* max # of return data */
4685 long maxReturnParms; /* max # of return parms */
4686 long bytesInBuffer; /* # data bytes in the output buffer */
4687 clientchar_t *maskp; /* mask part of path */
4691 smb_tran2Packet_t *outp; /* response packet */
4692 clientchar_t *tidPathp = 0;
4694 clientchar_t shortName[13]; /* 8.3 name if needed */
4696 clientchar_t *shortNameEnd;
4697 cm_dirEntry_t * dep = NULL;
4700 void * attrp = NULL;
4701 smb_tran2Find_t * fp;
4706 osi_assertx(p->opcode == 1, "invalid opcode");
4708 /* find first; obtain basic parameters from request */
4710 /* note that since we are going to failover to regular
4711 * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4712 * modify any of the input parameters here. */
4713 attribute = p->parmsp[0];
4714 maxCount = p->parmsp[1];
4715 infoLevel = p->parmsp[3];
4716 searchFlags = p->parmsp[2];
4717 pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4719 maskp = cm_ClientStrRChr(pathp, '\\');
4723 maskp++; /* skip over backslash */
4724 /* track if this is likely to match a lot of entries */
4726 osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%S], mask[%S]",
4727 osi_LogSaveClientString(smb_logp, pathp),
4728 osi_LogSaveClientString(smb_logp, maskp));
4730 switch ( infoLevel ) {
4731 case SMB_INFO_STANDARD:
4733 ohbytes = sizeof(fp->u.FstandardInfo);
4736 case SMB_INFO_QUERY_EA_SIZE:
4737 ohbytes = sizeof(fp->u.FeaSizeInfo);
4738 s = "InfoQueryEaSize";
4741 case SMB_INFO_QUERY_EAS_FROM_LIST:
4742 ohbytes = sizeof(fp->u.FeasFromListInfo);
4743 s = "InfoQueryEasFromList";
4746 case SMB_FIND_FILE_DIRECTORY_INFO:
4747 s = "FindFileDirectoryInfo";
4748 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4751 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4752 s = "FindFileFullDirectoryInfo";
4753 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4756 case SMB_FIND_FILE_NAMES_INFO:
4757 s = "FindFileNamesInfo";
4758 ohbytes = sizeof(fp->u.FfileNamesInfo);
4761 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4762 s = "FindFileBothDirectoryInfo";
4763 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4767 s = "unknownInfoLevel";
4771 osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
4774 "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4775 attribute, infoLevel, maxCount, searchFlags);
4778 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4779 return CM_ERROR_INVAL;
4782 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4783 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4785 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4788 dirListPatchesp = NULL;
4790 maxReturnData = p->maxReturnData;
4791 maxReturnParms = 10; /* return params for findfirst, which
4792 is the only one we handle.*/
4794 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4797 osi_Log2(smb_logp, "T2SDSingle search dir count %d [%S]",
4798 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4800 /* bail out if request looks bad */
4802 smb_FreeTran2Packet(outp);
4803 return CM_ERROR_BADSMB;
4806 userp = smb_GetTran2User(vcp, p);
4808 osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
4809 smb_FreeTran2Packet(outp);
4810 return CM_ERROR_BADSMB;
4813 /* try to get the vnode for the path name next */
4814 spacep = cm_GetSpace();
4815 /* smb_StripLastComponent will strip "::$DATA" if present */
4816 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4817 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4819 cm_ReleaseUser(userp);
4820 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4821 smb_FreeTran2Packet(outp);
4825 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4826 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4827 userp, tidPathp, &req, &scp);
4828 cm_FreeSpace(spacep);
4831 cm_ReleaseUser(userp);
4832 smb_SendTran2Error(vcp, p, opx, code);
4833 smb_FreeTran2Packet(outp);
4837 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4838 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4839 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
4840 cm_ReleaseSCache(scp);
4841 cm_ReleaseUser(userp);
4842 if ( WANTS_DFS_PATHNAMES(p) || pnc )
4843 code = CM_ERROR_PATH_NOT_COVERED;
4845 code = CM_ERROR_NOSUCHPATH;
4846 smb_SendTran2Error(vcp, p, opx, code);
4847 smb_FreeTran2Packet(outp);
4850 #endif /* DFS_SUPPORT */
4851 osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
4853 /* now do a single case sensitive lookup for the file in question */
4854 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
4856 /* if a case sensitive match failed, we try a case insensitive one
4858 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
4859 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
4862 if (code == 0 && targetscp->fid.vnode == 0) {
4863 cm_ReleaseSCache(targetscp);
4864 code = CM_ERROR_NOSUCHFILE;
4868 /* if we can't find the directory entry, this block will
4869 return CM_ERROR_NOSUCHFILE, which we will pass on to
4870 smb_ReceiveTran2SearchDir(). */
4871 cm_ReleaseSCache(scp);
4872 cm_ReleaseUser(userp);
4873 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4874 smb_SendTran2Error(vcp, p, opx, code);
4877 smb_FreeTran2Packet(outp);
4881 /* now that we have the target in sight, we proceed with filling
4882 up the return data. */
4884 op = origOp = outp->datap;
4887 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4888 /* skip over resume key */
4892 fp = (smb_tran2Find_t *) op;
4894 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4895 && targetscp->fid.vnode != 0
4896 && !cm_Is8Dot3(maskp)) {
4899 dfid.vnode = htonl(targetscp->fid.vnode);
4900 dfid.unique = htonl(targetscp->fid.unique);
4902 cm_Gen8Dot3NameIntW(maskp, &dfid, shortName, &shortNameEnd);
4908 osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %S (%S)",
4909 htonl(targetscp->fid.vnode),
4910 htonl(targetscp->fid.unique),
4911 osi_LogSaveClientString(smb_logp, pathp),
4912 (NeedShortName)? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
4914 /* Eliminate entries that don't match requested attributes */
4915 if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
4916 smb_IsDotFile(maskp)) {
4918 code = CM_ERROR_NOSUCHFILE;
4919 osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
4924 if (!(attribute & SMB_ATTR_DIRECTORY) &&
4925 (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
4926 targetscp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4927 targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
4928 targetscp->fileType == CM_SCACHETYPE_INVALID)) {
4930 code = CM_ERROR_NOSUCHFILE;
4931 osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
4936 /* add header to name & term. null */
4938 smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
4939 orbytes = ohbytes + onbytes;
4941 /* now, we round up the record to a 4 byte alignment, and we make
4942 * sure that we have enough room here for even the aligned version
4943 * (so we don't have to worry about an * overflow when we pad
4944 * things out below). That's the reason for the alignment
4947 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4948 align = (4 - (orbytes & 3)) & 3;
4952 if (orbytes + align > maxReturnData) {
4954 /* even though this request is unlikely to succeed with a
4955 failover, we do it anyway. */
4956 code = CM_ERROR_NOSUCHFILE;
4957 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4962 /* this is one of the entries to use: it is not deleted and it
4963 * matches the star pattern we're looking for. Put out the name,
4964 * preceded by its length.
4966 /* First zero everything else */
4967 memset(origOp, 0, orbytes);
4970 smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
4972 switch (infoLevel) {
4973 case SMB_INFO_STANDARD:
4974 fp->u.FstandardInfo.fileNameLength = onbytes;
4975 attrp = &fp->u.FstandardInfo.fileAttrs;
4978 case SMB_INFO_QUERY_EA_SIZE:
4979 fp->u.FeaSizeInfo.fileNameLength = onbytes;
4980 attrp = &fp->u.FeaSizeInfo.fileAttrs;
4981 fp->u.FeaSizeInfo.eaSize = 0;
4984 case SMB_INFO_QUERY_EAS_FROM_LIST:
4985 fp->u.FeasFromListInfo.fileNameLength = onbytes;
4986 attrp = &fp->u.FeasFromListInfo.fileAttrs;
4987 fp->u.FeasFromListInfo.eaSize = 0;
4990 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4991 if (NeedShortName) {
4995 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
4996 fp->u.FfileBothDirectoryInfo.shortName,
4997 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
4999 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
5001 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5002 fp->u.FfileBothDirectoryInfo.reserved = 0;
5004 strcpy(fp->u.FfileBothDirectoryInfo.shortName,
5006 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
5011 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5012 fp->u.FfileFullDirectoryInfo.eaSize = 0;
5015 case SMB_FIND_FILE_DIRECTORY_INFO:
5016 fp->u.FfileDirectoryInfo.nextEntryOffset = 0;
5017 fp->u.FfileDirectoryInfo.fileIndex = 0;
5018 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5019 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5022 case SMB_FIND_FILE_NAMES_INFO:
5023 fp->u.FfileNamesInfo.nextEntryOffset = 0;
5024 fp->u.FfileNamesInfo.fileIndex = 0;
5025 fp->u.FfileNamesInfo.fileNameLength = onbytes;
5029 /* we shouldn't hit this case */
5030 osi_assertx(FALSE, "Unknown query type");
5033 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5034 osi_assert(attrp != NULL);
5036 curPatchp = malloc(sizeof(*curPatchp));
5037 osi_QAdd((osi_queue_t **) &dirListPatchesp,
5039 curPatchp->dptr = attrp;
5041 if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
5042 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5044 curPatchp->flags = 0;
5047 cm_SetFid(&curPatchp->fid, targetscp->fid.cell, targetscp->fid.volume, targetscp->fid.vnode, targetscp->fid.unique);
5051 int namelen = cm_ClientStringToFsString(maskp, -1, NULL, 0);
5052 dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+namelen);
5053 cm_ClientStringToFsString(maskp, -1, dep->name, namelen);
5055 dep->fid.vnode = targetscp->fid.vnode;
5056 dep->fid.unique = targetscp->fid.unique;
5057 curPatchp->dep = dep;
5060 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
5061 /* put out resume key */
5062 *((u_long *)origOp) = 0;
5065 /* Adjust byte ptr and count */
5066 origOp += orbytes; /* skip entire record */
5067 bytesInBuffer += orbytes;
5069 /* and pad the record out */
5070 while (--align >= 0) {
5075 /* apply the patches */
5076 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->wdata, infoLevel, userp, &req);
5078 outp->parmsp[0] = 0;
5079 outp->parmsp[1] = 1; /* number of names returned */
5080 outp->parmsp[2] = 1; /* end of search */
5081 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5082 outp->parmsp[4] = 0;
5084 outp->totalParms = 10; /* in bytes */
5086 outp->totalData = bytesInBuffer;
5088 osi_Log0(smb_logp, "T2SDSingle done.");
5090 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5092 smb_SendTran2Error(vcp, p, opx, code);
5094 smb_SendTran2Packet(vcp, outp, opx);
5099 smb_FreeTran2Packet(outp);
5103 cm_ReleaseSCache(scp);
5104 cm_ReleaseSCache(targetscp);
5105 cm_ReleaseUser(userp);
5111 /* TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2 */
5112 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
5117 long code = 0, code2 = 0;
5118 clientchar_t *pathp;
5119 cm_dirEntry_t *dep = 0;
5121 smb_dirListPatch_t *dirListPatchesp = 0;
5122 smb_dirListPatch_t *curPatchp = 0;
5125 size_t orbytes; /* # of bytes in this output record */
5126 size_t ohbytes; /* # of bytes, except file name */
5127 size_t onbytes; /* # of bytes in name, incl. term. null */
5128 osi_hyper_t dirLength;
5129 osi_hyper_t bufferOffset;
5130 osi_hyper_t curOffset;
5132 smb_dirSearch_t *dsp;
5136 cm_pageHeader_t *pageHeaderp;
5137 cm_user_t *userp = NULL;
5140 long nextEntryCookie;
5141 int numDirChunks; /* # of 32 byte dir chunks in this entry */
5142 char *op; /* output data ptr */
5143 char *origOp; /* original value of op */
5144 cm_space_t *spacep; /* for pathname buffer */
5145 unsigned long maxReturnData; /* max # of return data */
5146 unsigned long maxReturnParms; /* max # of return parms */
5147 long bytesInBuffer; /* # data bytes in the output buffer */
5149 clientchar_t *maskp; /* mask part of path */
5153 smb_tran2Packet_t *outp; /* response packet */
5154 clientchar_t *tidPathp;
5156 clientchar_t shortName[13]; /* 8.3 name if needed */
5159 clientchar_t *shortNameEnd;
5165 smb_tran2Find_t * fp;
5170 if (p->opcode == 1) {
5171 /* find first; obtain basic parameters from request */
5172 attribute = p->parmsp[0];
5173 maxCount = p->parmsp[1];
5174 infoLevel = p->parmsp[3];
5175 searchFlags = p->parmsp[2];
5176 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
5178 maskp = cm_ClientStrRChr(pathp, '\\');
5182 maskp++; /* skip over backslash */
5184 /* track if this is likely to match a lot of entries */
5185 starPattern = smb_V3IsStarMask(maskp);
5187 #ifndef NOFINDFIRSTOPTIMIZE
5189 /* if this is for a single directory or file, we let the
5190 optimized routine handle it. The only error it
5191 returns is CM_ERROR_NOSUCHFILE. The */
5192 code = smb_T2SearchDirSingle(vcp, p, opx);
5194 /* we only failover if we see a CM_ERROR_NOSUCHFILE */
5195 if (code != CM_ERROR_NOSUCHFILE) {
5197 /* unless we are using the BPlusTree */
5198 if (code == CM_ERROR_BPLUS_NOMATCH)
5199 code = CM_ERROR_NOSUCHFILE;
5200 #endif /* USE_BPLUS */
5204 #endif /* NOFINDFIRSTOPTIMIZE */
5207 dsp = smb_NewDirSearch(1);
5208 dsp->attribute = attribute;
5209 cm_ClientStrCpy(dsp->mask, lengthof(dsp->mask), maskp); /* and save mask */
5212 osi_assertx(p->opcode == 2, "invalid opcode");
5213 /* find next; obtain basic parameters from request or open dir file */
5214 dsp = smb_FindDirSearch(p->parmsp[0]);
5215 maxCount = p->parmsp[1];
5216 infoLevel = p->parmsp[2];
5217 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
5218 searchFlags = p->parmsp[5];
5220 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
5221 p->parmsp[0], nextCookie);
5222 return CM_ERROR_BADFD;
5224 attribute = dsp->attribute;
5227 starPattern = 1; /* assume, since required a Find Next */
5230 switch ( infoLevel ) {
5231 case SMB_INFO_STANDARD:
5233 ohbytes = sizeof(fp->u.FstandardInfo);
5236 case SMB_INFO_QUERY_EA_SIZE:
5237 ohbytes = sizeof(fp->u.FeaSizeInfo);
5238 s = "InfoQueryEaSize";
5241 case SMB_INFO_QUERY_EAS_FROM_LIST:
5242 ohbytes = sizeof(fp->u.FeasFromListInfo);
5243 s = "InfoQueryEasFromList";
5246 case SMB_FIND_FILE_DIRECTORY_INFO:
5247 s = "FindFileDirectoryInfo";
5248 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
5251 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5252 s = "FindFileFullDirectoryInfo";
5253 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
5256 case SMB_FIND_FILE_NAMES_INFO:
5257 s = "FindFileNamesInfo";
5258 ohbytes = sizeof(fp->u.FfileNamesInfo);
5261 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5262 s = "FindFileBothDirectoryInfo";
5263 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
5267 s = "unknownInfoLevel";
5271 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
5274 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
5275 attribute, infoLevel, maxCount, searchFlags);
5277 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
5278 p->opcode, dsp->cookie, nextCookie);
5281 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
5282 smb_ReleaseDirSearch(dsp);
5283 return CM_ERROR_INVAL;
5286 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5287 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
5289 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5292 dirListPatchesp = NULL;
5294 maxReturnData = p->maxReturnData;
5295 if (p->opcode == 1) /* find first */
5296 maxReturnParms = 10; /* bytes */
5298 maxReturnParms = 8; /* bytes */
5300 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
5306 osi_Log2(smb_logp, "T2 receive search dir count %d [%S]",
5307 maxCount, osi_LogSaveClientString(smb_logp, pathp));
5309 /* bail out if request looks bad */
5310 if (p->opcode == 1 && !pathp) {
5311 smb_ReleaseDirSearch(dsp);
5312 smb_FreeTran2Packet(outp);
5313 return CM_ERROR_BADSMB;
5316 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
5317 dsp->cookie, nextCookie, attribute);
5319 userp = smb_GetTran2User(vcp, p);
5321 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
5322 smb_ReleaseDirSearch(dsp);
5323 smb_FreeTran2Packet(outp);
5324 return CM_ERROR_BADSMB;
5327 /* try to get the vnode for the path name next */
5328 lock_ObtainMutex(&dsp->mx);
5331 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5335 spacep = cm_GetSpace();
5336 /* smb_StripLastComponent will strip "::$DATA" if present */
5337 smb_StripLastComponent(spacep->wdata, NULL, pathp);
5338 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
5340 cm_ReleaseUser(userp);
5341 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
5342 smb_FreeTran2Packet(outp);
5343 lock_ReleaseMutex(&dsp->mx);
5344 smb_DeleteDirSearch(dsp);
5345 smb_ReleaseDirSearch(dsp);
5349 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
5350 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
5352 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
5353 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5354 userp, tidPathp, &req, &scp);
5355 cm_FreeSpace(spacep);
5358 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
5359 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5360 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
5361 cm_ReleaseSCache(scp);
5362 cm_ReleaseUser(userp);
5363 if ( WANTS_DFS_PATHNAMES(p) || pnc )
5364 code = CM_ERROR_PATH_NOT_COVERED;
5366 code = CM_ERROR_NOSUCHPATH;
5367 smb_SendTran2Error(vcp, p, opx, code);
5368 smb_FreeTran2Packet(outp);
5369 lock_ReleaseMutex(&dsp->mx);
5370 smb_DeleteDirSearch(dsp);
5371 smb_ReleaseDirSearch(dsp);
5374 #endif /* DFS_SUPPORT */
5376 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5377 /* we need one hold for the entry we just stored into,
5378 * and one for our own processing. When we're done
5379 * with this function, we'll drop the one for our own
5380 * processing. We held it once from the namei call,
5381 * and so we do another hold now.
5384 dsp->flags |= SMB_DIRSEARCH_BULKST;
5387 lock_ReleaseMutex(&dsp->mx);
5389 cm_ReleaseUser(userp);
5390 smb_FreeTran2Packet(outp);
5391 smb_DeleteDirSearch(dsp);
5392 smb_ReleaseDirSearch(dsp);
5396 /* get the directory size */
5397 lock_ObtainWrite(&scp->rw);
5398 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5399 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5401 lock_ReleaseWrite(&scp->rw);
5402 cm_ReleaseSCache(scp);
5403 cm_ReleaseUser(userp);
5404 smb_FreeTran2Packet(outp);
5405 smb_DeleteDirSearch(dsp);
5406 smb_ReleaseDirSearch(dsp);
5410 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5413 dirLength = scp->length;
5415 bufferOffset.LowPart = bufferOffset.HighPart = 0;
5416 curOffset.HighPart = 0;
5417 curOffset.LowPart = nextCookie;
5418 origOp = outp->datap;
5425 normchar_t normName[MAX_PATH]; /* Normalized name */
5426 clientchar_t cfileName[MAX_PATH]; /* Non-normalized name */
5429 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5430 /* skip over resume key */
5433 fp = (smb_tran2Find_t *) op;
5435 /* make sure that curOffset.LowPart doesn't point to the first
5436 * 32 bytes in the 2nd through last dir page, and that it doesn't
5437 * point at the first 13 32-byte chunks in the first dir page,
5438 * since those are dir and page headers, and don't contain useful
5441 temp = curOffset.LowPart & (2048-1);
5442 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5443 /* we're in the first page */
5444 if (temp < 13*32) temp = 13*32;
5447 /* we're in a later dir page */
5448 if (temp < 32) temp = 32;
5451 /* make sure the low order 5 bits are zero */
5454 /* now put temp bits back ito curOffset.LowPart */
5455 curOffset.LowPart &= ~(2048-1);
5456 curOffset.LowPart |= temp;
5458 /* check if we've passed the dir's EOF */
5459 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
5460 osi_Log0(smb_logp, "T2 search dir passed eof");
5465 /* check if we've returned all the names that will fit in the
5466 * response packet; we check return count as well as the number
5467 * of bytes requested. We check the # of bytes after we find
5468 * the dir entry, since we'll need to check its size.
5470 if (returnedNames >= maxCount) {
5471 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
5472 returnedNames, maxCount);
5476 /* when we have obtained as many entries as can be processed in
5477 * a single Bulk Status call to the file server, apply the dir listing
5480 if (returnedNames > 0 && returnedNames % AFSCBMAX == 0) {
5481 lock_ReleaseWrite(&scp->rw);
5482 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5483 dsp->relPath, infoLevel, userp, &req);
5484 lock_ObtainWrite(&scp->rw);
5486 /* Then check to see if we have time left to process more entries */
5487 if (GetTickCount() - req.startTime > (RDRtimeout - 15) * 1000) {
5488 osi_Log0(smb_logp, "T2 search dir RDRtimeout exceeded");
5492 /* see if we can use the bufferp we have now; compute in which
5493 * page the current offset would be, and check whether that's
5494 * the offset of the buffer we have. If not, get the buffer.
5496 thyper.HighPart = curOffset.HighPart;
5497 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5498 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5501 buf_Release(bufferp);
5504 lock_ReleaseWrite(&scp->rw);
5505 code = buf_Get(scp, &thyper, &req, &bufferp);
5506 lock_ObtainWrite(&scp->rw);
5508 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
5512 bufferOffset = thyper;
5514 /* now get the data in the cache */
5516 code = cm_SyncOp(scp, bufferp, userp, &req,
5518 CM_SCACHESYNC_NEEDCALLBACK
5519 | CM_SCACHESYNC_READ);
5521 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5525 if (cm_HaveBuffer(scp, bufferp, 0)) {
5526 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5527 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5531 /* otherwise, load the buffer and try again */
5532 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5534 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5536 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5537 scp, bufferp, code);
5542 buf_Release(bufferp);
5546 } /* if (wrong buffer) ... */
5548 /* now we have the buffer containing the entry we're interested
5549 * in; copy it out if it represents a non-deleted entry.
5551 entryInDir = curOffset.LowPart & (2048-1);
5552 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5554 /* page header will help tell us which entries are free. Page
5555 * header can change more often than once per buffer, since
5556 * AFS 3 dir page size may be less than (but not more than)
5557 * a buffer package buffer.
5559 /* only look intra-buffer */
5560 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5561 temp &= ~(2048 - 1); /* turn off intra-page bits */
5562 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5564 /* now determine which entry we're looking at in the page.
5565 * If it is free (there's a free bitmap at the start of the
5566 * dir), we should skip these 32 bytes.
5568 slotInPage = (entryInDir & 0x7e0) >> 5;
5569 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5570 (1 << (slotInPage & 0x7)))) {
5571 /* this entry is free */
5572 numDirChunks = 1; /* only skip this guy */
5576 tp = bufferp->datap + entryInBuffer;
5577 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5579 /* while we're here, compute the next entry's location, too,
5580 * since we'll need it when writing out the cookie into the dir
5583 * XXXX Probably should do more sanity checking.
5585 numDirChunks = cm_NameEntries(dep->name, &onbytes);
5587 /* compute offset of cookie representing next entry */
5588 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5590 if (dep->fid.vnode == 0)
5591 goto nextEntry; /* This entry is not in use */
5593 if (cm_FsStringToClientString(dep->name, -1, cfileName, lengthof(cfileName)) == 0 ||
5594 cm_ClientStringToNormString(cfileName, -1, normName, lengthof(normName)) == 0) {
5596 osi_Log1(smb_logp, "Skipping entry [%s]. Can't convert or normalize FS String",
5597 osi_LogSaveString(smb_logp, dep->name));
5601 /* Need 8.3 name? */
5603 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
5604 !cm_Is8Dot3(cfileName)) {
5605 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5609 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %S (%S)",
5610 dep->fid.vnode, dep->fid.unique,
5611 osi_LogSaveClientString(smb_logp, cfileName),
5612 NeedShortName ? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
5614 /* When matching, we are using doing a case fold if we have a wildcard mask.
5615 * If we get a non-wildcard match, it's a lookup for a specific file.
5617 if (cm_MatchMask(normName, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5618 (NeedShortName && cm_MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))
5620 /* Eliminate entries that don't match requested attributes */
5621 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5622 smb_IsDotFile(cfileName)) {
5623 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5624 goto nextEntry; /* no hidden files */
5627 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5629 /* We have already done the cm_TryBulkStat above */
5630 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume,
5631 ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5632 fileType = cm_FindFileType(&fid);
5633 /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5634 * "has filetype %d", dep->name, fileType);
5636 if ( fileType == CM_SCACHETYPE_DIRECTORY ||
5637 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5638 fileType == CM_SCACHETYPE_DFSLINK ||
5639 fileType == CM_SCACHETYPE_INVALID)
5640 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5644 /* finally check if this name will fit */
5646 smb_UnparseString(opx, NULL, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5647 orbytes = ohbytes + onbytes;
5649 /* now, we round up the record to a 4 byte alignment,
5650 * and we make sure that we have enough room here for
5651 * even the aligned version (so we don't have to worry
5652 * about an overflow when we pad things out below).
5653 * That's the reason for the alignment arithmetic below.
5655 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5656 align = (4 - (orbytes & 3)) & 3;
5660 if (orbytes + bytesInBuffer + align > maxReturnData) {
5661 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5666 /* this is one of the entries to use: it is not deleted
5667 * and it matches the star pattern we're looking for.
5668 * Put out the name, preceded by its length.
5670 /* First zero everything else */
5671 memset(origOp, 0, orbytes);
5674 smb_UnparseString(opx, origOp + ohbytes, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5676 switch (infoLevel) {
5677 case SMB_INFO_STANDARD:
5678 fp->u.FstandardInfo.fileNameLength = onbytes;
5679 attrp = &fp->u.FstandardInfo.fileAttrs;
5682 case SMB_INFO_QUERY_EA_SIZE:
5683 fp->u.FeaSizeInfo.fileNameLength = onbytes;
5684 attrp = &fp->u.FeaSizeInfo.fileAttrs;
5685 fp->u.FeaSizeInfo.eaSize = 0;
5688 case SMB_INFO_QUERY_EAS_FROM_LIST:
5689 fp->u.FeasFromListInfo.fileNameLength = onbytes;
5690 attrp = &fp->u.FeasFromListInfo.fileAttrs;
5691 fp->u.FeasFromListInfo.eaSize = 0;
5694 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5695 if (NeedShortName) {
5699 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
5700 fp->u.FfileBothDirectoryInfo.shortName,
5701 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
5703 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
5705 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5706 fp->u.FfileBothDirectoryInfo.reserved = 0;
5708 cm_ClientStrCpy(fp->u.FfileBothDirectoryInfo.shortName,
5709 lengthof(fp->u.FfileBothDirectoryInfo.shortName),
5711 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
5716 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5717 fp->u.FfileFullDirectoryInfo.eaSize = 0;
5720 case SMB_FIND_FILE_DIRECTORY_INFO:
5721 fp->u.FfileDirectoryInfo.nextEntryOffset = orbytes + align;
5722 fp->u.FfileDirectoryInfo.fileIndex = nextEntryCookie;
5723 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5724 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5727 case SMB_FIND_FILE_NAMES_INFO:
5728 fp->u.FfileNamesInfo.nextEntryOffset = orbytes + align;
5729 fp->u.FfileNamesInfo.fileIndex = nextEntryCookie;
5730 fp->u.FfileNamesInfo.fileNameLength = onbytes;
5735 /* we shouldn't hit this case */
5736 osi_assertx(FALSE, "Unknown query type");
5739 /* now, adjust the # of entries copied */
5742 /* now we emit the attribute. This is tricky, since
5743 * we need to really stat the file to find out what
5744 * type of entry we've got. Right now, we're copying
5745 * out data from a buffer, while holding the scp
5746 * locked, so it isn't really convenient to stat
5747 * something now. We'll put in a place holder
5748 * now, and make a second pass before returning this
5749 * to get the real attributes. So, we just skip the
5750 * data for now, and adjust it later. We allocate a
5751 * patch record to make it easy to find this point
5752 * later. The replay will happen at a time when it is
5753 * safe to unlock the directory.
5755 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5756 osi_assert(attrp != NULL);
5757 curPatchp = malloc(sizeof(*curPatchp));
5758 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5759 curPatchp->dptr = attrp;
5761 if (smb_hideDotFiles && smb_IsDotFile(cfileName)) {
5762 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5764 curPatchp->flags = 0;
5767 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5770 curPatchp->dep = dep;
5773 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5774 /* put out resume key */
5775 *((u_long *)origOp) = nextEntryCookie;
5777 /* Adjust byte ptr and count */
5778 origOp += orbytes; /* skip entire record */
5779 bytesInBuffer += orbytes;
5781 /* and pad the record out */
5782 while (align-- > 0) {
5786 } /* if we're including this name */
5787 else if (!starPattern &&
5789 cm_MatchMask(normName, maskp, CM_FLAG_CASEFOLD)) {
5790 /* We were looking for exact matches, but here's an inexact one*/
5795 /* and adjust curOffset to be where the new cookie is */
5796 thyper.HighPart = 0;
5797 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5798 curOffset = LargeIntegerAdd(thyper, curOffset);
5799 } /* while copying data for dir listing */
5801 /* If we didn't get a star pattern, we did an exact match during the first pass.
5802 * If there were no exact matches found, we fail over to inexact matches by
5803 * marking the query as a star pattern (matches all case permutations), and
5804 * re-running the query.
5806 if (returnedNames == 0 && !starPattern && foundInexact) {
5807 osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
5812 /* release the mutex */
5813 lock_ReleaseWrite(&scp->rw);
5815 buf_Release(bufferp);
5820 * Finally, process whatever entries we have left.
5822 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5823 dsp->relPath, infoLevel, userp, &req);
5825 /* now put out the final parameters */
5826 if (returnedNames == 0)
5828 if (p->opcode == 1) {
5830 outp->parmsp[0] = (unsigned short) dsp->cookie;
5831 outp->parmsp[1] = returnedNames;
5832 outp->parmsp[2] = eos;
5833 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5834 outp->parmsp[4] = 0;
5835 /* don't need last name to continue
5836 * search, cookie is enough. Normally,
5837 * this is the offset of the file name
5838 * of the last entry returned.
5840 outp->totalParms = 10; /* in bytes */
5844 outp->parmsp[0] = returnedNames;
5845 outp->parmsp[1] = eos;
5846 outp->parmsp[2] = 0; /* EAS error */
5847 outp->parmsp[3] = 0; /* last name, as above */
5848 outp->totalParms = 8; /* in bytes */
5851 /* return # of bytes in the buffer */
5852 outp->totalData = bytesInBuffer;
5854 /* Return error code if unsuccessful on first request */
5855 if (code == 0 && p->opcode == 1 && returnedNames == 0)
5856 code = CM_ERROR_NOSUCHFILE;
5858 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
5859 p->opcode, dsp->cookie, returnedNames, code);
5861 /* if we're supposed to close the search after this request, or if
5862 * we're supposed to close the search if we're done, and we're done,
5863 * or if something went wrong, close the search.
5865 if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
5866 (returnedNames == 0) ||
5867 ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
5869 smb_DeleteDirSearch(dsp);
5872 smb_SendTran2Error(vcp, p, opx, code);
5874 smb_SendTran2Packet(vcp, outp, opx);
5876 smb_FreeTran2Packet(outp);
5877 smb_ReleaseDirSearch(dsp);
5878 cm_ReleaseSCache(scp);
5879 cm_ReleaseUser(userp);
5883 /* SMB_COM_FIND_CLOSE2 */
5884 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5887 smb_dirSearch_t *dsp;
5889 dirHandle = smb_GetSMBParm(inp, 0);
5891 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
5893 dsp = smb_FindDirSearch(dirHandle);
5896 return CM_ERROR_BADFD;
5898 /* otherwise, we have an FD to destroy */
5899 smb_DeleteDirSearch(dsp);
5900 smb_ReleaseDirSearch(dsp);
5902 /* and return results */
5903 smb_SetSMBDataLength(outp, 0);
5909 /* SMB_COM_FIND_NOTIFY_CLOSE */
5910 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5912 smb_SetSMBDataLength(outp, 0);
5916 /* SMB_COM_OPEN_ANDX */
5917 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5919 clientchar_t *pathp;
5924 cm_scache_t *dscp; /* dir we're dealing with */
5925 cm_scache_t *scp; /* file we're creating */
5929 clientchar_t *lastNamep;
5930 unsigned long dosTime;
5936 int parmSlot; /* which parm we're dealing with */
5937 clientchar_t *tidPathp;
5940 BOOL is_rpc = FALSE;
5941 BOOL is_ipc = FALSE;
5947 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
5948 openFun = smb_GetSMBParm(inp, 8); /* open function */
5949 excl = ((openFun & 3) == 0);
5950 trunc = ((openFun & 3) == 2); /* truncate it */
5951 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
5952 openAction = 0; /* tracks what we did */
5954 attributes = smb_GetSMBParm(inp, 5);
5955 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
5957 pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
5960 return CM_ERROR_BADSMB;
5962 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5964 if (code == CM_ERROR_TIDIPC) {
5967 return CM_ERROR_NOSUCHPATH;
5971 spacep = inp->spacep;
5972 /* smb_StripLastComponent will strip "::$DATA" if present */
5973 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5977 /* special case magic file name for receiving IOCTL requests
5978 * (since IOCTL calls themselves aren't getting through).
5980 (cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
5982 /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional) */
5983 (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
5985 unsigned short file_type = 0;
5986 unsigned short device_state = 0;
5988 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5990 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
5991 osi_Log1(smb_logp, "OpenAndX Setting up RPC on fid[%d]", fidp->fid);
5993 osi_Log1(smb_logp, "smb_SetupRPCFid failure code [%d]", code);
5994 smb_ReleaseFID(fidp);
5998 smb_SetupIoctlFid(fidp, spacep);
5999 osi_Log1(smb_logp, "OpenAndX Setting up IOCTL on fid[%d]", fidp->fid);
6002 /* set inp->fid so that later read calls in same msg can find fid */
6003 inp->fid = fidp->fid;
6005 /* copy out remainder of the parms */
6007 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6009 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
6010 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
6011 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6012 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
6013 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
6014 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
6015 smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++;
6016 smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++;
6018 /* and the final "always present" stuff */
6019 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
6020 /* next write out the "unique" ID */
6021 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
6022 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
6023 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6024 smb_SetSMBDataLength(outp, 0);
6026 /* and clean up fid reference */
6027 smb_ReleaseFID(fidp);
6033 osi_Log0(smb_logp, "NTOpenX rejecting IPC TID");
6034 return CM_ERROR_BADFD;
6038 if (!cm_IsValidClientString(pathp)) {
6040 clientchar_t * hexp;
6042 hexp = cm_GetRawCharsAlloc(pathp, -1);
6043 osi_Log1(smb_logp, "NTOpenX rejecting invalid name. [%S]",
6044 osi_LogSaveClientString(smb_logp, hexp));
6048 osi_Log0(smb_logp, "NTOpenX rejecting invalid name");
6050 return CM_ERROR_BADNTFILENAME;
6053 #ifdef DEBUG_VERBOSE
6055 char *hexp, *asciip;
6056 asciip = (lastNamep ? lastNamep : pathp );
6057 hexp = osi_HexifyString(asciip);
6058 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
6062 userp = smb_GetUserFromVCP(vcp, inp);
6065 code = cm_NameI(cm_data.rootSCachep, pathp,
6066 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6067 userp, tidPathp, &req, &scp);
6070 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6071 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
6072 cm_ReleaseSCache(scp);
6073 cm_ReleaseUser(userp);
6074 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6075 return CM_ERROR_PATH_NOT_COVERED;
6077 return CM_ERROR_NOSUCHPATH;
6079 #endif /* DFS_SUPPORT */
6082 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
6083 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6084 userp, tidPathp, &req, &dscp);
6086 cm_ReleaseUser(userp);
6091 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6092 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
6094 cm_ReleaseSCache(dscp);
6095 cm_ReleaseUser(userp);
6096 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6097 return CM_ERROR_PATH_NOT_COVERED;
6099 return CM_ERROR_NOSUCHPATH;
6101 #endif /* DFS_SUPPORT */
6102 /* otherwise, scp points to the parent directory. Do a lookup,
6103 * and truncate the file if we find it, otherwise we create the
6110 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
6112 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
6113 cm_ReleaseSCache(dscp);
6114 cm_ReleaseUser(userp);
6119 /* if we get here, if code is 0, the file exists and is represented by
6120 * scp. Otherwise, we have to create it. The dir may be represented
6121 * by dscp, or we may have found the file directly. If code is non-zero,
6125 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
6127 if (dscp) cm_ReleaseSCache(dscp);
6128 cm_ReleaseSCache(scp);
6129 cm_ReleaseUser(userp);
6134 /* oops, file shouldn't be there */
6136 cm_ReleaseSCache(dscp);
6137 cm_ReleaseSCache(scp);
6138 cm_ReleaseUser(userp);
6139 return CM_ERROR_EXISTS;
6143 setAttr.mask = CM_ATTRMASK_LENGTH;
6144 setAttr.length.LowPart = 0;
6145 setAttr.length.HighPart = 0;
6146 code = cm_SetAttr(scp, &setAttr, userp, &req);
6147 openAction = 3; /* truncated existing file */
6149 else openAction = 1; /* found existing file */
6151 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
6152 /* don't create if not found */
6153 if (dscp) cm_ReleaseSCache(dscp);
6154 cm_ReleaseUser(userp);
6155 return CM_ERROR_NOSUCHFILE;
6158 osi_assertx(dscp != NULL, "null cm_scache_t");
6159 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %S",
6160 osi_LogSaveClientString(smb_logp, lastNamep));
6161 openAction = 2; /* created file */
6162 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6163 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6164 smb_SetInitialModeBitsForFile(attributes, &setAttr);
6166 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6170 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6171 smb_NotifyChange(FILE_ACTION_ADDED,
6172 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6173 dscp, lastNamep, NULL, TRUE);
6174 } else if (!excl && code == CM_ERROR_EXISTS) {
6175 /* not an exclusive create, and someone else tried
6176 * creating it already, then we open it anyway. We
6177 * don't bother retrying after this, since if this next
6178 * fails, that means that the file was deleted after we
6179 * started this call.
6181 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6185 setAttr.mask = CM_ATTRMASK_LENGTH;
6186 setAttr.length.LowPart = 0;
6187 setAttr.length.HighPart = 0;
6188 code = cm_SetAttr(scp, &setAttr, userp, &req);
6190 } /* lookup succeeded */
6194 /* we don't need this any longer */
6196 cm_ReleaseSCache(dscp);
6199 /* something went wrong creating or truncating the file */
6201 cm_ReleaseSCache(scp);
6202 cm_ReleaseUser(userp);
6206 /* make sure we're about to open a file */
6207 if (scp->fileType != CM_SCACHETYPE_FILE) {
6208 cm_ReleaseSCache(scp);
6209 cm_ReleaseUser(userp);
6210 return CM_ERROR_ISDIR;
6213 /* now all we have to do is open the file itself */
6214 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6215 osi_assertx(fidp, "null smb_fid_t");
6218 lock_ObtainMutex(&fidp->mx);
6219 /* save a pointer to the vnode */
6221 lock_ObtainWrite(&scp->rw);
6222 scp->flags |= CM_SCACHEFLAG_SMB_FID;
6223 lock_ReleaseWrite(&scp->rw);
6224 osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
6226 fidp->userp = userp;
6228 /* compute open mode */
6230 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
6231 if (openMode == 1 || openMode == 2)
6232 fidp->flags |= SMB_FID_OPENWRITE;
6234 /* remember if the file was newly created */
6236 fidp->flags |= SMB_FID_CREATED;
6238 lock_ReleaseMutex(&fidp->mx);
6239 smb_ReleaseFID(fidp);
6241 cm_Open(scp, 0, userp);
6243 /* set inp->fid so that later read calls in same msg can find fid */
6244 inp->fid = fidp->fid;
6246 /* copy out remainder of the parms */
6248 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6249 lock_ObtainRead(&scp->rw);
6251 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
6252 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
6253 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
6254 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
6255 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
6256 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
6257 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
6258 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
6259 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
6261 /* and the final "always present" stuff */
6262 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
6263 /* next write out the "unique" ID */
6264 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
6265 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
6266 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6267 lock_ReleaseRead(&scp->rw);
6268 smb_SetSMBDataLength(outp, 0);
6270 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
6272 cm_ReleaseUser(userp);
6273 /* leave scp held since we put it in fidp->scp */
6277 static void smb_GetLockParams(unsigned char LockType,
6279 unsigned int * ppid,
6280 LARGE_INTEGER * pOffset,
6281 LARGE_INTEGER * pLength)
6283 if (LockType & LOCKING_ANDX_LARGE_FILES) {
6285 *ppid = *((USHORT *) *buf);
6286 pOffset->HighPart = *((LONG *)(*buf + 4));
6287 pOffset->LowPart = *((DWORD *)(*buf + 8));
6288 pLength->HighPart = *((LONG *)(*buf + 12));
6289 pLength->LowPart = *((DWORD *)(*buf + 16));
6293 /* Not Large Files */
6294 *ppid = *((USHORT *) *buf);
6295 pOffset->HighPart = 0;
6296 pOffset->LowPart = *((DWORD *)(*buf + 2));
6297 pLength->HighPart = 0;
6298 pLength->LowPart = *((DWORD *)(*buf + 6));
6303 /* SMB_COM_LOCKING_ANDX */
6304 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6311 unsigned char LockType;
6312 unsigned short NumberOfUnlocks, NumberOfLocks;
6316 LARGE_INTEGER LOffset, LLength;
6317 smb_waitingLockRequest_t *wlRequest = NULL;
6318 cm_file_lock_t *lockp;
6326 fid = smb_GetSMBParm(inp, 2);
6327 fid = smb_ChainFID(fid, inp);
6329 fidp = smb_FindFID(vcp, fid, 0);
6331 osi_Log2(smb_logp, "V3LockingX Unknown SMB Fid vcp 0x%p fid %d",
6333 return CM_ERROR_BADFD;
6335 lock_ObtainMutex(&fidp->mx);
6336 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6337 lock_ReleaseMutex(&fidp->mx);
6338 smb_CloseFID(vcp, fidp, NULL, 0);
6339 smb_ReleaseFID(fidp);
6340 return CM_ERROR_NOSUCHFILE;
6343 if (fidp->flags & SMB_FID_IOCTL) {
6344 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
6345 lock_ReleaseMutex(&fidp->mx);
6346 smb_ReleaseFID(fidp);
6347 return CM_ERROR_BADFD;
6350 osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
6352 lock_ReleaseMutex(&fidp->mx);
6354 /* set inp->fid so that later read calls in same msg can find fid */
6357 userp = smb_GetUserFromVCP(vcp, inp);
6359 lock_ObtainWrite(&scp->rw);
6360 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6361 CM_SCACHESYNC_NEEDCALLBACK
6362 | CM_SCACHESYNC_GETSTATUS
6363 | CM_SCACHESYNC_LOCK);
6365 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
6369 LockType = smb_GetSMBParm(inp, 3) & 0xff;
6370 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
6371 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
6372 NumberOfLocks = smb_GetSMBParm(inp, 7);
6374 if (!(fidp->flags & SMB_FID_OPENWRITE) &&
6375 !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
6376 /* somebody wants exclusive locks on a file that they only
6377 opened for reading. We downgrade this to a shared lock. */
6378 osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
6379 LockType |= LOCKING_ANDX_SHARED_LOCK;
6382 if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
6383 /* AFS does not support atomic changes of lock types from read or write and vice-versa */
6384 osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]");
6385 code = CM_ERROR_BADOP;
6390 op = smb_GetSMBData(inp, NULL);
6392 if (LockType & LOCKING_ANDX_CANCEL_LOCK) {
6393 /* Cancel outstanding lock requests */
6394 smb_waitingLock_t * wl;
6396 for (i=0; i<NumberOfLocks; i++) {
6397 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6399 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6401 lock_ObtainWrite(&smb_globalLock);
6402 for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
6404 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
6405 if (cm_KeyEquals(&wl->key, &key, 0) && LargeIntegerEqualTo(wl->LOffset, LOffset) &&
6406 LargeIntegerEqualTo(wl->LLength, LLength)) {
6407 wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
6408 goto found_lock_request;
6413 lock_ReleaseWrite(&smb_globalLock);
6416 smb_SetSMBDataLength(outp, 0);
6421 for (i=0; i<NumberOfUnlocks; i++) {
6422 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6424 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6426 code = cm_Unlock(scp, LockType, LOffset, LLength, key, 0, userp, &req);
6434 for (i=0; i<NumberOfLocks; i++) {
6435 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6437 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6439 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
6440 userp, &req, &lockp);
6442 if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
6443 (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
6445 code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
6446 userp, &req, &lockp);
6449 if (code == CM_ERROR_LOCK_NOT_GRANTED && Timeout != 0) {
6450 smb_waitingLock_t * wLock;
6452 /* Put on waiting list */
6453 if(wlRequest == NULL) {
6457 LARGE_INTEGER tOffset, tLength;
6459 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
6461 osi_assertx(wlRequest != NULL, "null wlRequest");
6463 wlRequest->vcp = vcp;
6465 wlRequest->scp = scp;
6466 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
6468 wlRequest->inp = smb_CopyPacket(inp);
6469 wlRequest->outp = smb_CopyPacket(outp);
6470 wlRequest->lockType = LockType;
6471 wlRequest->msTimeout = Timeout;
6472 wlRequest->start_t = osi_Time();
6473 wlRequest->locks = NULL;
6475 /* The waiting lock request needs to have enough
6476 information to undo all the locks in the request.
6477 We do the following to store info about locks that
6478 have already been granted. Sure, we can get most
6479 of the info from the packet, but the packet doesn't
6480 hold the result of cm_Lock call. In practice we
6481 only receive packets with one or two locks, so we
6482 are only wasting a few bytes here and there and
6483 only for a limited period of time until the waiting
6484 lock times out or is freed. */
6486 for(opt = op_locks, j=i; j > 0; j--) {
6487 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
6489 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6491 wLock = malloc(sizeof(smb_waitingLock_t));
6493 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6496 wLock->LOffset = tOffset;
6497 wLock->LLength = tLength;
6498 wLock->lockp = NULL;
6499 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
6500 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6505 wLock = malloc(sizeof(smb_waitingLock_t));
6507 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6510 wLock->LOffset = LOffset;
6511 wLock->LLength = LLength;
6512 wLock->lockp = lockp;
6513 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
6514 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6517 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
6525 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
6532 /* Since something went wrong with the lock number i, we now
6533 have to go ahead and release any locks acquired before the
6534 failure. All locks before lock number i (of which there
6535 are i of them) have either been successful or are waiting.
6536 Either case requires calling cm_Unlock(). */
6538 /* And purge the waiting lock */
6539 if(wlRequest != NULL) {
6540 smb_waitingLock_t * wl;
6541 smb_waitingLock_t * wlNext;
6544 for(wl = wlRequest->locks; wl; wl = wlNext) {
6546 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
6548 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, 0, userp, &req);
6551 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
6553 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
6556 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
6561 smb_ReleaseVC(wlRequest->vcp);
6562 cm_ReleaseSCache(wlRequest->scp);
6563 smb_FreePacket(wlRequest->inp);
6564 smb_FreePacket(wlRequest->outp);
6573 if (wlRequest != NULL) {
6575 lock_ObtainWrite(&smb_globalLock);
6576 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
6578 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
6579 lock_ReleaseWrite(&smb_globalLock);
6581 /* don't send reply immediately */
6582 outp->flags |= SMB_PACKETFLAG_NOSEND;
6585 smb_SetSMBDataLength(outp, 0);
6589 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
6592 lock_ReleaseWrite(&scp->rw);
6593 cm_ReleaseSCache(scp);
6594 cm_ReleaseUser(userp);
6595 smb_ReleaseFID(fidp);
6600 /* SMB_COM_QUERY_INFORMATION2 */
6601 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6607 afs_uint32 searchTime;
6614 fid = smb_GetSMBParm(inp, 0);
6615 fid = smb_ChainFID(fid, inp);
6617 fidp = smb_FindFID(vcp, fid, 0);
6619 osi_Log2(smb_logp, "V3GetAttributes Unknown SMB Fid vcp 0x%p fid %d",
6621 return CM_ERROR_BADFD;
6623 lock_ObtainMutex(&fidp->mx);
6624 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6625 lock_ReleaseMutex(&fidp->mx);
6626 smb_CloseFID(vcp, fidp, NULL, 0);
6627 smb_ReleaseFID(fidp);
6628 return CM_ERROR_NOSUCHFILE;
6631 if (fidp->flags & SMB_FID_IOCTL) {
6632 lock_ReleaseMutex(&fidp->mx);
6633 smb_ReleaseFID(fidp);
6634 return CM_ERROR_BADFD;
6637 osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6639 lock_ReleaseMutex(&fidp->mx);
6641 userp = smb_GetUserFromVCP(vcp, inp);
6644 /* otherwise, stat the file */
6645 lock_ObtainWrite(&scp->rw);
6646 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6647 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6651 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6653 lock_ConvertWToR(&scp->rw);
6656 /* decode times. We need a search time, but the response to this
6657 * call provides the date first, not the time, as returned in the
6658 * searchTime variable. So we take the high-order bits first.
6660 cm_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
6661 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
6662 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
6663 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
6664 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
6665 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
6666 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
6668 /* now handle file size and allocation size */
6669 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
6670 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
6671 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
6672 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
6674 /* file attribute */
6675 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
6677 /* and finalize stuff */
6678 smb_SetSMBDataLength(outp, 0);
6683 lock_ReleaseRead(&scp->rw);
6685 lock_ReleaseWrite(&scp->rw);
6686 cm_ReleaseSCache(scp);
6687 cm_ReleaseUser(userp);
6688 smb_ReleaseFID(fidp);
6692 /* SMB_COM_SET_INFORMATION2 */
6693 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6699 afs_uint32 searchTime;
6707 fid = smb_GetSMBParm(inp, 0);
6708 fid = smb_ChainFID(fid, inp);
6710 fidp = smb_FindFID(vcp, fid, 0);
6712 osi_Log2(smb_logp, "V3SetAttributes Unknown SMB Fid vcp 0x%p fid %d",
6714 return CM_ERROR_BADFD;
6716 lock_ObtainMutex(&fidp->mx);
6717 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6718 lock_ReleaseMutex(&fidp->mx);
6719 smb_CloseFID(vcp, fidp, NULL, 0);
6720 smb_ReleaseFID(fidp);
6721 return CM_ERROR_NOSUCHFILE;
6724 if (fidp->flags & SMB_FID_IOCTL) {
6725 lock_ReleaseMutex(&fidp->mx);
6726 smb_ReleaseFID(fidp);
6727 return CM_ERROR_BADFD;
6730 osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6732 lock_ReleaseMutex(&fidp->mx);
6734 userp = smb_GetUserFromVCP(vcp, inp);
6736 /* now prepare to call cm_setattr. This message only sets various times,
6737 * and AFS only implements mtime, and we'll set the mtime if that's
6738 * requested. The others we'll ignore.
6740 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
6742 if (searchTime != 0) {
6743 cm_UnixTimeFromSearchTime(&unixTime, searchTime);
6745 if ( unixTime != -1 ) {
6746 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
6747 attrs.clientModTime = unixTime;
6748 code = cm_SetAttr(scp, &attrs, userp, &req);
6750 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
6752 osi_Log1(smb_logp, "**cm_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
6758 cm_ReleaseSCache(scp);
6759 cm_ReleaseUser(userp);
6760 smb_ReleaseFID(fidp);
6764 /* SMB_COM_WRITE_ANDX */
6765 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6768 long count, written = 0, total_written = 0;
6772 smb_t *smbp = (smb_t*) inp;
6777 int inDataBlockCount;
6779 fd = smb_GetSMBParm(inp, 2);
6780 count = smb_GetSMBParm(inp, 10);
6782 offset.HighPart = 0;
6783 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6785 if (*inp->wctp == 14) {
6786 /* we have a request with 64-bit file offsets */
6787 #ifdef AFS_LARGEFILES
6788 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6790 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6792 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
6793 /* we shouldn't have received this op if we didn't specify
6794 largefile support */
6795 return CM_ERROR_INVAL;
6800 op = inp->data + smb_GetSMBParm(inp, 11);
6801 inDataBlockCount = count;
6803 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
6804 fd, offset.HighPart, offset.LowPart, count);
6806 fd = smb_ChainFID(fd, inp);
6807 fidp = smb_FindFID(vcp, fd, 0);
6809 osi_Log2(smb_logp, "smb_ReceiveV3WriteX Unknown SMB Fid vcp 0x%p fid %d",
6811 return CM_ERROR_BADFD;
6813 lock_ObtainMutex(&fidp->mx);
6814 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6815 lock_ReleaseMutex(&fidp->mx);
6816 smb_CloseFID(vcp, fidp, NULL, 0);
6817 smb_ReleaseFID(fidp);
6818 return CM_ERROR_NOSUCHFILE;
6821 if (fidp->flags & SMB_FID_IOCTL) {
6822 lock_ReleaseMutex(&fidp->mx);
6823 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
6824 smb_ReleaseFID(fidp);
6828 if (fidp->flags & SMB_FID_RPC) {
6829 lock_ReleaseMutex(&fidp->mx);
6830 code = smb_RPCV3Write(fidp, vcp, inp, outp);
6831 smb_ReleaseFID(fidp);
6836 lock_ReleaseMutex(&fidp->mx);
6837 smb_ReleaseFID(fidp);
6838 return CM_ERROR_BADFDOP;
6843 lock_ReleaseMutex(&fidp->mx);
6845 userp = smb_GetUserFromVCP(vcp, inp);
6847 /* special case: 0 bytes transferred means there is no data
6848 transferred. A slight departure from SMB_COM_WRITE where this
6849 means that we are supposed to truncate the file at this
6854 LARGE_INTEGER LOffset;
6855 LARGE_INTEGER LLength;
6858 key = cm_GenerateKey(vcp->vcID, pid, fd);
6860 LOffset.HighPart = offset.HighPart;
6861 LOffset.LowPart = offset.LowPart;
6862 LLength.HighPart = 0;
6863 LLength.LowPart = count;
6865 lock_ObtainWrite(&scp->rw);
6866 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
6867 lock_ReleaseWrite(&scp->rw);
6874 * Work around bug in NT client
6876 * When copying a file, the NT client should first copy the data,
6877 * then copy the last write time. But sometimes the NT client does
6878 * these in the wrong order, so the data copies would inadvertently
6879 * cause the last write time to be overwritten. We try to detect this,
6880 * and don't set client mod time if we think that would go against the
6883 lock_ObtainMutex(&fidp->mx);
6884 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6885 lock_ObtainWrite(&fidp->scp->rw);
6886 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6887 scp->clientModTime = time(NULL);
6888 lock_ReleaseWrite(&fidp->scp->rw);
6890 lock_ReleaseMutex(&fidp->mx);
6893 while ( code == 0 && count > 0 ) {
6894 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6895 if (code == 0 && written == 0)
6896 code = CM_ERROR_PARTIALWRITE;
6898 offset = LargeIntegerAdd(offset,
6899 ConvertLongToLargeInteger(written));
6901 total_written += written;
6905 /* slots 0 and 1 are reserved for request chaining and will be
6906 filled in when we return. */
6907 smb_SetSMBParm(outp, 2, total_written);
6908 smb_SetSMBParm(outp, 3, 0); /* reserved */
6909 smb_SetSMBParm(outp, 4, 0); /* reserved */
6910 smb_SetSMBParm(outp, 5, 0); /* reserved */
6911 smb_SetSMBDataLength(outp, 0);
6915 cm_ReleaseSCache(scp);
6916 cm_ReleaseUser(userp);
6917 smb_ReleaseFID(fidp);
6922 /* SMB_COM_READ_ANDX */
6923 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6927 long finalCount = 0;
6931 smb_t *smbp = (smb_t*) inp;
6938 fd = smb_GetSMBParm(inp, 2); /* File ID */
6939 count = smb_GetSMBParm(inp, 5); /* MaxCount */
6940 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6942 if (*inp->wctp == 12) {
6943 /* a request with 64-bit offsets */
6944 #ifdef AFS_LARGEFILES
6945 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
6947 if (LargeIntegerLessThanZero(offset)) {
6948 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
6949 offset.HighPart, offset.LowPart);
6950 return CM_ERROR_BADSMB;
6953 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
6954 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
6955 return CM_ERROR_BADSMB;
6957 offset.HighPart = 0;
6961 offset.HighPart = 0;
6964 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
6965 fd, offset.HighPart, offset.LowPart, count);
6967 fd = smb_ChainFID(fd, inp);
6968 fidp = smb_FindFID(vcp, fd, 0);
6970 osi_Log2(smb_logp, "smb_ReceiveV3Read Unknown SMB Fid vcp 0x%p fid %d",
6972 return CM_ERROR_BADFD;
6975 lock_ObtainMutex(&fidp->mx);
6977 if (fidp->flags & SMB_FID_IOCTL) {
6978 lock_ReleaseMutex(&fidp->mx);
6980 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
6981 smb_ReleaseFID(fidp);
6985 if (fidp->flags & SMB_FID_RPC) {
6986 lock_ReleaseMutex(&fidp->mx);
6988 code = smb_RPCV3Read(fidp, vcp, inp, outp);
6989 smb_ReleaseFID(fidp);
6993 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6994 lock_ReleaseMutex(&fidp->mx);
6995 smb_CloseFID(vcp, fidp, NULL, 0);
6996 smb_ReleaseFID(fidp);
6997 return CM_ERROR_NOSUCHFILE;
7001 lock_ReleaseMutex(&fidp->mx);
7002 smb_ReleaseFID(fidp);
7003 return CM_ERROR_BADFDOP;
7009 lock_ReleaseMutex(&fidp->mx);
7012 key = cm_GenerateKey(vcp->vcID, pid, fd);
7014 LARGE_INTEGER LOffset, LLength;
7016 LOffset.HighPart = offset.HighPart;
7017 LOffset.LowPart = offset.LowPart;
7018 LLength.HighPart = 0;
7019 LLength.LowPart = count;
7021 lock_ObtainWrite(&scp->rw);
7022 code = cm_LockCheckRead(scp, LOffset, LLength, key);
7023 lock_ReleaseWrite(&scp->rw);
7025 cm_ReleaseSCache(scp);
7028 smb_ReleaseFID(fidp);
7032 /* set inp->fid so that later read calls in same msg can find fid */
7035 userp = smb_GetUserFromVCP(vcp, inp);
7037 /* 0 and 1 are reserved for request chaining, were setup by our caller,
7038 * and will be further filled in after we return.
7040 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
7041 smb_SetSMBParm(outp, 3, 0); /* resvd */
7042 smb_SetSMBParm(outp, 4, 0); /* resvd */
7043 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
7044 /* fill in #6 when we have all the parameters' space reserved */
7045 smb_SetSMBParm(outp, 7, 0); /* resv'd */
7046 smb_SetSMBParm(outp, 8, 0); /* resv'd */
7047 smb_SetSMBParm(outp, 9, 0); /* resv'd */
7048 smb_SetSMBParm(outp, 10, 0); /* resv'd */
7049 smb_SetSMBParm(outp, 11, 0); /* reserved */
7051 /* get op ptr after putting in the parms, since otherwise we don't
7052 * know where the data really is.
7054 op = smb_GetSMBData(outp, NULL);
7056 /* now fill in offset from start of SMB header to first data byte (to op) */
7057 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
7059 /* set the packet data length the count of the # of bytes */
7060 smb_SetSMBDataLength(outp, count);
7062 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7064 /* fix some things up */
7065 smb_SetSMBParm(outp, 5, finalCount);
7066 smb_SetSMBDataLength(outp, finalCount);
7068 cm_ReleaseUser(userp);
7069 smb_ReleaseFID(fidp);
7074 * Values for createDisp, copied from NTDDK.H
7076 #define FILE_SUPERSEDE 0 // (???)
7077 #define FILE_OPEN 1 // (open)
7078 #define FILE_CREATE 2 // (exclusive)
7079 #define FILE_OPEN_IF 3 // (non-exclusive)
7080 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
7081 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
7084 #define REQUEST_OPLOCK 2
7085 #define REQUEST_BATCH_OPLOCK 4
7086 #define OPEN_DIRECTORY 8
7087 #define EXTENDED_RESPONSE_REQUIRED 0x10
7089 /* CreateOptions field. */
7090 #define FILE_DIRECTORY_FILE 0x0001
7091 #define FILE_WRITE_THROUGH 0x0002
7092 #define FILE_SEQUENTIAL_ONLY 0x0004
7093 #define FILE_NON_DIRECTORY_FILE 0x0040
7094 #define FILE_NO_EA_KNOWLEDGE 0x0200
7095 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
7096 #define FILE_RANDOM_ACCESS 0x0800
7097 #define FILE_DELETE_ON_CLOSE 0x1000
7098 #define FILE_OPEN_BY_FILE_ID 0x2000
7099 #define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000
7100 #define FILE_NO_COMPRESSION 0x00008000
7101 #define FILE_RESERVE_OPFILTER 0x00100000
7102 #define FILE_OPEN_REPARSE_POINT 0x00200000
7103 #define FILE_OPEN_NO_RECALL 0x00400000
7104 #define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000
7106 /* SMB_COM_NT_CREATE_ANDX */
7107 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7109 clientchar_t *pathp, *realPathp;
7113 cm_scache_t *dscp; /* parent dir */
7114 cm_scache_t *scp; /* file to create or open */
7115 cm_scache_t *targetScp; /* if scp is a symlink */
7117 clientchar_t *lastNamep;
7118 clientchar_t *treeStartp;
7119 unsigned short nameLength;
7121 unsigned int requestOpLock;
7122 unsigned int requestBatchOpLock;
7123 unsigned int mustBeDir;
7124 unsigned int extendedRespRequired;
7125 unsigned int treeCreate;
7127 unsigned int desiredAccess;
7128 unsigned int extAttributes;
7129 unsigned int createDisp;
7130 unsigned int createOptions;
7131 unsigned int shareAccess;
7132 unsigned short baseFid;
7133 smb_fid_t *baseFidp;
7135 cm_scache_t *baseDirp;
7136 unsigned short openAction;
7141 clientchar_t *tidPathp;
7146 int checkDoneRequired = 0;
7147 cm_lock_data_t *ldp = NULL;
7148 BOOL is_rpc = FALSE;
7149 BOOL is_ipc = FALSE;
7153 /* This code is very long and has a lot of if-then-else clauses
7154 * scp and dscp get reused frequently and we need to ensure that
7155 * we don't lose a reference. Start by ensuring that they are NULL.
7162 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
7163 flags = smb_GetSMBOffsetParm(inp, 3, 1)
7164 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
7165 requestOpLock = flags & REQUEST_OPLOCK;
7166 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7167 mustBeDir = flags & OPEN_DIRECTORY;
7168 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7171 * Why all of a sudden 32-bit FID?
7172 * We will reject all bits higher than 16.
7174 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
7175 return CM_ERROR_INVAL;
7176 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
7177 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
7178 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
7179 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
7180 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
7181 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
7182 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
7183 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
7184 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
7185 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
7186 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
7188 /* mustBeDir is never set; createOptions directory bit seems to be
7191 if (createOptions & FILE_DIRECTORY_FILE)
7193 else if (createOptions & FILE_NON_DIRECTORY_FILE)
7198 pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
7199 NULL, SMB_STRF_ANSIPATH);
7201 /* Sometimes path is not null-terminated, so we make a copy. */
7202 realPathp = malloc(nameLength+sizeof(clientchar_t));
7203 memcpy(realPathp, pathp, nameLength+sizeof(clientchar_t));
7204 realPathp[nameLength/sizeof(clientchar_t)] = 0;
7206 spacep = inp->spacep;
7207 /* smb_StripLastComponent will strip "::$DATA" if present */
7208 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
7210 osi_Log1(smb_logp,"NTCreateX for [%S]",osi_LogSaveClientString(smb_logp,realPathp));
7211 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
7212 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%S]", shareAccess, flags, osi_LogSaveClientString(smb_logp,(lastNamep?lastNamep:_C("null"))));
7216 baseDirp = cm_data.rootSCachep;
7217 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7218 if (code == CM_ERROR_TIDIPC) {
7219 /* Attempt to use a TID allocated for IPC. The client
7220 * is probably looking for DCE RPC end points which we
7221 * don't support OR it could be looking to make a DFS
7224 osi_Log0(smb_logp, "NTCreateX received IPC TID");
7229 osi_Log1(smb_logp, "NTCreateX tidPathp=[%S]", (tidPathp==NULL)?_C("null"): osi_LogSaveClientString(smb_logp,tidPathp));
7233 ((is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)) ||
7235 /* special case magic file name for receiving IOCTL requests
7236 * (since IOCTL calls themselves aren't getting through).
7238 cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0)) {
7240 unsigned short file_type = 0;
7241 unsigned short device_state = 0;
7243 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7246 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
7247 osi_Log1(smb_logp, "NTCreateX Setting up RPC on fid[%d]", fidp->fid);
7249 osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
7250 smb_ReleaseFID(fidp);
7255 smb_SetupIoctlFid(fidp, spacep);
7256 osi_Log1(smb_logp, "NTCreateX Setting up IOCTL on fid[%d]", fidp->fid);
7259 /* set inp->fid so that later read calls in same msg can find fid */
7260 inp->fid = fidp->fid;
7264 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7265 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7266 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
7268 memset(&ft, 0, sizeof(ft));
7269 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7270 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7271 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7272 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7273 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
7274 sz.HighPart = 0x7fff; sz.LowPart = 0;
7275 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
7276 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
7277 smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++; /* filetype */
7278 smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++; /* dev state */
7279 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
7280 smb_SetSMBDataLength(outp, 0);
7282 /* clean up fid reference */
7283 smb_ReleaseFID(fidp);
7290 osi_Log0(smb_logp, "NTCreateX rejecting IPC TID");
7292 return CM_ERROR_BADFD;
7296 if (!cm_IsValidClientString(realPathp)) {
7298 clientchar_t * hexp;
7300 hexp = cm_GetRawCharsAlloc(realPathp, -1);
7301 osi_Log1(smb_logp, "NTCreateX rejecting invalid name. [%S]",
7302 osi_LogSaveClientString(smb_logp, hexp));
7306 osi_Log0(smb_logp, "NTCreateX rejecting invalid name");
7309 return CM_ERROR_BADNTFILENAME;
7312 userp = smb_GetUserFromVCP(vcp, inp);
7314 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
7316 return CM_ERROR_INVAL;
7319 if (baseFidp != 0) {
7320 baseFidp = smb_FindFID(vcp, baseFid, 0);
7322 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
7323 cm_ReleaseUser(userp);
7325 return CM_ERROR_INVAL;
7328 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7330 smb_CloseFID(vcp, baseFidp, NULL, 0);
7331 smb_ReleaseFID(baseFidp);
7332 cm_ReleaseUser(userp);
7333 return CM_ERROR_NOSUCHPATH;
7336 baseDirp = baseFidp->scp;
7340 /* compute open mode */
7342 if (desiredAccess & DELETE)
7343 fidflags |= SMB_FID_OPENDELETE;
7344 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
7345 fidflags |= SMB_FID_OPENREAD_LISTDIR;
7346 if (desiredAccess & AFS_ACCESS_WRITE)
7347 fidflags |= SMB_FID_OPENWRITE;
7348 if (createOptions & FILE_DELETE_ON_CLOSE)
7349 fidflags |= SMB_FID_DELONCLOSE;
7350 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7351 fidflags |= SMB_FID_SEQUENTIAL;
7352 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7353 fidflags |= SMB_FID_RANDOM;
7354 if (createOptions & FILE_OPEN_REPARSE_POINT)
7355 osi_Log0(smb_logp, "NTCreateX Open Reparse Point");
7356 if (smb_IsExecutableFileName(lastNamep))
7357 fidflags |= SMB_FID_EXECUTABLE;
7359 /* and the share mode */
7360 if (shareAccess & FILE_SHARE_READ)
7361 fidflags |= SMB_FID_SHARE_READ;
7362 if (shareAccess & FILE_SHARE_WRITE)
7363 fidflags |= SMB_FID_SHARE_WRITE;
7365 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
7368 /* For an exclusive create, we want to do a case sensitive match for the last component. */
7369 if ( createDisp == FILE_CREATE ||
7370 createDisp == FILE_OVERWRITE ||
7371 createDisp == FILE_OVERWRITE_IF) {
7372 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7373 userp, tidPathp, &req, &dscp);
7376 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7377 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7379 cm_ReleaseSCache(dscp);
7380 cm_ReleaseUser(userp);
7383 smb_ReleaseFID(baseFidp);
7384 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7385 return CM_ERROR_PATH_NOT_COVERED;
7387 return CM_ERROR_NOSUCHPATH;
7389 #endif /* DFS_SUPPORT */
7390 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7392 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7393 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7394 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7395 if (code == 0 && realDirFlag == 1) {
7396 cm_ReleaseSCache(scp);
7397 cm_ReleaseSCache(dscp);
7398 cm_ReleaseUser(userp);
7401 smb_ReleaseFID(baseFidp);
7402 return CM_ERROR_EXISTS;
7406 /* we have both scp and dscp */
7408 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7409 userp, tidPathp, &req, &scp);
7411 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7412 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7413 cm_ReleaseSCache(scp);
7414 cm_ReleaseUser(userp);
7417 smb_ReleaseFID(baseFidp);
7418 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7419 return CM_ERROR_PATH_NOT_COVERED;
7421 return CM_ERROR_NOSUCHPATH;
7423 #endif /* DFS_SUPPORT */
7424 /* we might have scp but not dscp */
7430 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7431 /* look up parent directory */
7432 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
7433 * the immediate parent. We have to work our way up realPathp until we hit something that we
7437 /* we might or might not have scp */
7443 code = cm_NameI(baseDirp, spacep->wdata,
7444 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7445 userp, tidPathp, &req, &dscp);
7448 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7449 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7452 cm_ReleaseSCache(scp);
7453 cm_ReleaseSCache(dscp);
7454 cm_ReleaseUser(userp);
7457 smb_ReleaseFID(baseFidp);
7458 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7459 return CM_ERROR_PATH_NOT_COVERED;
7461 return CM_ERROR_NOSUCHPATH;
7463 #endif /* DFS_SUPPORT */
7466 (tp = cm_ClientStrRChr(spacep->wdata, '\\')) &&
7467 (createDisp == FILE_CREATE) &&
7468 (realDirFlag == 1)) {
7471 treeStartp = realPathp + (tp - spacep->wdata);
7473 if (*tp && !smb_IsLegalFilename(tp)) {
7474 cm_ReleaseUser(userp);
7476 smb_ReleaseFID(baseFidp);
7479 cm_ReleaseSCache(scp);
7480 return CM_ERROR_BADNTFILENAME;
7484 } while (dscp == NULL && code == 0);
7488 /* we might have scp and we might have dscp */
7491 smb_ReleaseFID(baseFidp);
7494 osi_Log0(smb_logp,"NTCreateX parent not found");
7496 cm_ReleaseSCache(scp);
7498 cm_ReleaseSCache(dscp);
7499 cm_ReleaseUser(userp);
7504 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
7505 /* A file exists where we want a directory. */
7507 cm_ReleaseSCache(scp);
7508 cm_ReleaseSCache(dscp);
7509 cm_ReleaseUser(userp);
7511 return CM_ERROR_EXISTS;
7515 lastNamep = realPathp;
7519 if (!smb_IsLegalFilename(lastNamep)) {
7521 cm_ReleaseSCache(scp);
7523 cm_ReleaseSCache(dscp);
7524 cm_ReleaseUser(userp);
7526 return CM_ERROR_BADNTFILENAME;
7529 if (!foundscp && !treeCreate) {
7530 if ( createDisp == FILE_CREATE ||
7531 createDisp == FILE_OVERWRITE ||
7532 createDisp == FILE_OVERWRITE_IF)
7534 code = cm_Lookup(dscp, lastNamep,
7535 CM_FLAG_FOLLOW, userp, &req, &scp);
7537 code = cm_Lookup(dscp, lastNamep,
7538 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7541 if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
7543 cm_ReleaseSCache(dscp);
7544 cm_ReleaseUser(userp);
7549 /* we have scp and dscp */
7551 /* we have scp but not dscp */
7553 smb_ReleaseFID(baseFidp);
7556 /* if we get here, if code is 0, the file exists and is represented by
7557 * scp. Otherwise, we have to create it. The dir may be represented
7558 * by dscp, or we may have found the file directly. If code is non-zero,
7561 if (code == 0 && !treeCreate) {
7562 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7564 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7566 cm_ReleaseSCache(dscp);
7568 cm_ReleaseSCache(scp);
7569 cm_ReleaseUser(userp);
7573 checkDoneRequired = 1;
7575 if (createDisp == FILE_CREATE) {
7576 /* oops, file shouldn't be there */
7577 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7579 cm_ReleaseSCache(dscp);
7581 cm_ReleaseSCache(scp);
7582 cm_ReleaseUser(userp);
7584 return CM_ERROR_EXISTS;
7587 if ( createDisp == FILE_OVERWRITE ||
7588 createDisp == FILE_OVERWRITE_IF) {
7590 setAttr.mask = CM_ATTRMASK_LENGTH;
7591 setAttr.length.LowPart = 0;
7592 setAttr.length.HighPart = 0;
7593 /* now watch for a symlink */
7595 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7597 osi_assertx(dscp != NULL, "null cm_scache_t");
7598 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7600 /* we have a more accurate file to use (the
7601 * target of the symbolic link). Otherwise,
7602 * we'll just use the symlink anyway.
7604 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7606 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7607 cm_ReleaseSCache(scp);
7609 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7611 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7613 cm_ReleaseSCache(dscp);
7615 cm_ReleaseSCache(scp);
7616 cm_ReleaseUser(userp);
7622 code = cm_SetAttr(scp, &setAttr, userp, &req);
7623 openAction = 3; /* truncated existing file */
7626 openAction = 1; /* found existing file */
7628 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7629 /* don't create if not found */
7631 cm_ReleaseSCache(dscp);
7633 cm_ReleaseSCache(scp);
7634 cm_ReleaseUser(userp);
7636 return CM_ERROR_NOSUCHFILE;
7637 } else if (realDirFlag == 0 || realDirFlag == -1) {
7638 osi_assertx(dscp != NULL, "null cm_scache_t");
7639 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %S",
7640 osi_LogSaveClientString(smb_logp, lastNamep));
7641 openAction = 2; /* created file */
7642 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7643 setAttr.clientModTime = time(NULL);
7644 smb_SetInitialModeBitsForFile(extAttributes, &setAttr);
7646 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
7649 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7650 smb_NotifyChange(FILE_ACTION_ADDED,
7651 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7652 dscp, lastNamep, NULL, TRUE);
7653 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7654 /* Not an exclusive create, and someone else tried
7655 * creating it already, then we open it anyway. We
7656 * don't bother retrying after this, since if this next
7657 * fails, that means that the file was deleted after we
7658 * started this call.
7660 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7663 if (createDisp == FILE_OVERWRITE_IF) {
7664 setAttr.mask = CM_ATTRMASK_LENGTH;
7665 setAttr.length.LowPart = 0;
7666 setAttr.length.HighPart = 0;
7668 /* now watch for a symlink */
7670 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7672 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7674 /* we have a more accurate file to use (the
7675 * target of the symbolic link). Otherwise,
7676 * we'll just use the symlink anyway.
7678 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7680 cm_ReleaseSCache(scp);
7684 code = cm_SetAttr(scp, &setAttr, userp, &req);
7686 } /* lookup succeeded */
7689 clientchar_t *tp, *pp;
7690 clientchar_t *cp; /* This component */
7691 int clen = 0; /* length of component */
7692 cm_scache_t *tscp1, *tscp2;
7695 /* create directory */
7697 treeStartp = lastNamep;
7698 osi_assertx(dscp != NULL, "null cm_scache_t");
7699 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%S]",
7700 osi_LogSaveClientString(smb_logp, treeStartp));
7701 openAction = 2; /* created directory */
7703 /* if the request is to create the root directory
7704 * it will appear as a directory name of the nul-string
7705 * and a code of CM_ERROR_NOSUCHFILE
7707 if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
7708 code = CM_ERROR_EXISTS;
7710 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7711 setAttr.clientModTime = time(NULL);
7712 smb_SetInitialModeBitsForDir(extAttributes, &setAttr);
7717 cm_HoldSCache(tscp1);
7721 tp = cm_ClientStrChr(pp, '\\');
7723 cm_ClientStrCpy(cp, lengthof(spacep->wdata) - (cp - spacep->wdata), pp);
7724 clen = (int)cm_ClientStrLen(cp);
7725 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
7727 clen = (int)(tp - pp);
7728 cm_ClientStrCpyN(cp, lengthof(spacep->wdata) - (cp - spacep->wdata),
7736 continue; /* the supplied path can't have consecutive slashes either , but */
7738 /* cp is the next component to be created. */
7739 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req, NULL);
7740 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
7741 smb_NotifyChange(FILE_ACTION_ADDED,
7742 FILE_NOTIFY_CHANGE_DIR_NAME,
7743 tscp1, cp, NULL, TRUE);
7745 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7746 /* Not an exclusive create, and someone else tried
7747 * creating it already, then we open it anyway. We
7748 * don't bother retrying after this, since if this next
7749 * fails, that means that the file was deleted after we
7750 * started this call.
7752 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
7753 userp, &req, &tscp2);
7758 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
7759 cm_ReleaseSCache(tscp1);
7760 tscp1 = tscp2; /* Newly created directory will be next parent */
7761 /* the hold is transfered to tscp1 from tscp2 */
7766 cm_ReleaseSCache(dscp);
7769 cm_ReleaseSCache(scp);
7772 * if we get here and code == 0, then scp is the last directory created, and dscp is the
7778 /* something went wrong creating or truncating the file */
7779 if (checkDoneRequired)
7780 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7782 cm_ReleaseSCache(scp);
7784 cm_ReleaseSCache(dscp);
7785 cm_ReleaseUser(userp);
7790 /* make sure we have file vs. dir right (only applies for single component case) */
7791 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7792 /* now watch for a symlink */
7794 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7795 cm_scache_t * targetScp = 0;
7796 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7798 /* we have a more accurate file to use (the
7799 * target of the symbolic link). Otherwise,
7800 * we'll just use the symlink anyway.
7802 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
7803 if (checkDoneRequired) {
7804 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7805 checkDoneRequired = 0;
7807 cm_ReleaseSCache(scp);
7812 if (scp->fileType != CM_SCACHETYPE_FILE) {
7813 if (checkDoneRequired)
7814 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7816 cm_ReleaseSCache(dscp);
7817 cm_ReleaseSCache(scp);
7818 cm_ReleaseUser(userp);
7820 return CM_ERROR_ISDIR;
7824 /* (only applies to single component case) */
7825 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7826 if (checkDoneRequired)
7827 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7828 cm_ReleaseSCache(scp);
7830 cm_ReleaseSCache(dscp);
7831 cm_ReleaseUser(userp);
7833 return CM_ERROR_NOTDIR;
7836 /* open the file itself */
7837 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7838 osi_assertx(fidp, "null smb_fid_t");
7840 /* save a reference to the user */
7842 fidp->userp = userp;
7844 /* If we are restricting sharing, we should do so with a suitable
7846 if (scp->fileType == CM_SCACHETYPE_FILE &&
7847 !(fidflags & SMB_FID_SHARE_WRITE)) {
7849 LARGE_INTEGER LOffset, LLength;
7852 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7853 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7854 LLength.HighPart = 0;
7855 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7857 /* If we are not opening the file for writing, then we don't
7858 try to get an exclusive lock. No one else should be able to
7859 get an exclusive lock on the file anyway, although someone
7860 else can get a shared lock. */
7861 if ((fidflags & SMB_FID_SHARE_READ) ||
7862 !(fidflags & SMB_FID_OPENWRITE)) {
7863 sLockType = LOCKING_ANDX_SHARED_LOCK;
7868 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7870 lock_ObtainWrite(&scp->rw);
7871 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7872 lock_ReleaseWrite(&scp->rw);
7875 if (checkDoneRequired)
7876 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7877 cm_ReleaseSCache(scp);
7879 cm_ReleaseSCache(dscp);
7880 cm_ReleaseUser(userp);
7881 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7882 smb_CloseFID(vcp, fidp, NULL, 0);
7883 smb_ReleaseFID(fidp);
7885 return CM_ERROR_SHARING_VIOLATION;
7889 /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
7890 if (checkDoneRequired) {
7891 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7892 checkDoneRequired = 0;
7895 lock_ObtainMutex(&fidp->mx);
7896 /* save a pointer to the vnode */
7897 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
7898 lock_ObtainWrite(&scp->rw);
7899 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7900 lock_ReleaseWrite(&scp->rw);
7901 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
7903 fidp->flags = fidflags;
7905 /* remember if the file was newly created */
7907 fidp->flags |= SMB_FID_CREATED;
7909 /* save parent dir and pathname for delete or change notification */
7910 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7911 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
7912 fidp->flags |= SMB_FID_NTOPEN;
7913 fidp->NTopen_dscp = dscp;
7915 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
7917 fidp->NTopen_wholepathp = realPathp;
7918 lock_ReleaseMutex(&fidp->mx);
7920 /* we don't need this any longer */
7922 cm_ReleaseSCache(dscp);
7926 cm_Open(scp, 0, userp);
7928 /* set inp->fid so that later read calls in same msg can find fid */
7929 inp->fid = fidp->fid;
7931 lock_ObtainRead(&scp->rw);
7934 * Always send the standard response. Sending the extended
7935 * response results in the Explorer Shell being unable to
7936 * access directories at random times.
7938 if (1 /*!extendedRespRequired */) {
7941 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7942 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7943 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7944 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7945 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7946 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7947 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7948 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7949 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7951 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7952 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7953 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
7954 smb_SetSMBParm(outp, parmSlot, NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS);
7955 parmSlot++; /* dev state */
7956 smb_SetSMBParmByte(outp, parmSlot,
7957 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7958 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7959 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7960 smb_SetSMBDataLength(outp, 0);
7964 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7965 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7966 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7967 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7968 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7969 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7970 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7971 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7972 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7974 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7975 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7976 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
7977 smb_SetSMBParm(outp, parmSlot, NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS);
7978 parmSlot++; /* dev state */
7979 smb_SetSMBParmByte(outp, parmSlot,
7980 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7981 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7982 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7983 /* Setting the GUID results in a failure with cygwin */
7984 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7985 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7986 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7987 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7988 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7989 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7990 /* Maxmimal access rights */
7991 smb_SetSMBParmLong(outp, parmSlot, 0x001f01ff); parmSlot += 2;
7992 /* Guest access rights */
7993 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7994 smb_SetSMBDataLength(outp, 0);
7997 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
7998 LargeIntegerGreaterThanZero(scp->length) &&
7999 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
8002 lock_ReleaseRead(&scp->rw);
8005 cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
8006 scp->length.LowPart, scp->length.HighPart,
8010 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %S", fidp->fid,
8011 osi_LogSaveClientString(smb_logp, realPathp));
8013 cm_ReleaseUser(userp);
8014 smb_ReleaseFID(fidp);
8016 /* Can't free realPathp if we get here since
8017 fidp->NTopen_wholepathp is pointing there */
8019 /* leave scp held since we put it in fidp->scp */
8024 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
8025 * Instead, ultimately, would like to use a subroutine for common code.
8028 /* NT_TRANSACT_CREATE (SMB_COM_NT_TRANSACT) */
8029 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8031 clientchar_t *pathp, *realPathp;
8035 cm_scache_t *dscp; /* parent dir */
8036 cm_scache_t *scp; /* file to create or open */
8037 cm_scache_t *targetScp; /* if scp is a symlink */
8039 clientchar_t *lastNamep;
8040 unsigned long nameLength;
8042 unsigned int requestOpLock;
8043 unsigned int requestBatchOpLock;
8044 unsigned int mustBeDir;
8045 unsigned int extendedRespRequired;
8047 unsigned int desiredAccess;
8048 unsigned int allocSize;
8049 unsigned int shareAccess;
8050 unsigned int extAttributes;
8051 unsigned int createDisp;
8054 unsigned int impLevel;
8055 unsigned int secFlags;
8056 unsigned int createOptions;
8057 unsigned short baseFid;
8058 smb_fid_t *baseFidp;
8060 cm_scache_t *baseDirp;
8061 unsigned short openAction;
8065 clientchar_t *tidPathp;
8067 int parmOffset, dataOffset;
8074 cm_lock_data_t *ldp = NULL;
8075 int checkDoneRequired = 0;
8082 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8083 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8084 parmp = inp->data + parmOffset;
8085 lparmp = (ULONG *) parmp;
8088 requestOpLock = flags & REQUEST_OPLOCK;
8089 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
8090 mustBeDir = flags & OPEN_DIRECTORY;
8091 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
8094 * Why all of a sudden 32-bit FID?
8095 * We will reject all bits higher than 16.
8097 if (lparmp[1] & 0xFFFF0000)
8098 return CM_ERROR_INVAL;
8099 baseFid = (unsigned short)lparmp[1];
8100 desiredAccess = lparmp[2];
8101 allocSize = lparmp[3];
8102 extAttributes = lparmp[5];
8103 shareAccess = lparmp[6];
8104 createDisp = lparmp[7];
8105 createOptions = lparmp[8];
8108 nameLength = lparmp[11]; /* spec says chars but appears to be bytes */
8109 impLevel = lparmp[12];
8110 secFlags = lparmp[13];
8112 /* mustBeDir is never set; createOptions directory bit seems to be
8115 if (createOptions & FILE_DIRECTORY_FILE)
8117 else if (createOptions & FILE_NON_DIRECTORY_FILE)
8122 pathp = smb_ParseStringCb(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
8123 nameLength, NULL, SMB_STRF_ANSIPATH);
8124 /* Sometimes path is not nul-terminated, so we make a copy. */
8125 realPathp = malloc(nameLength+sizeof(clientchar_t));
8126 memcpy(realPathp, pathp, nameLength);
8127 realPathp[nameLength/sizeof(clientchar_t)] = 0;
8128 spacep = cm_GetSpace();
8129 /* smb_StripLastComponent will strip "::$DATA" if present */
8130 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
8132 osi_Log1(smb_logp,"NTTranCreate %S",osi_LogSaveStringW(smb_logp,realPathp));
8133 osi_Log4(smb_logp,"... da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
8134 osi_Log4(smb_logp,"... co[%x],sdl[%x],eal[%x],as[%x],flags[%x]",createOptions,sdLen,eaLen,allocSize);
8135 osi_Log3(smb_logp,"... imp[%x],sec[%x],flags[%x]", impLevel, secFlags, flags);
8138 * Nothing here to handle SMB_IOCTL_FILENAME.
8139 * Will add it if necessary.
8142 if (!cm_IsValidClientString(realPathp)) {
8144 clientchar_t * hexp;
8146 hexp = cm_GetRawCharsAlloc(realPathp, -1);
8147 osi_Log1(smb_logp, "NTTranCreate rejecting invalid name. [%S]",
8148 osi_LogSaveClientString(smb_logp, hexp));
8152 osi_Log0(smb_logp, "NTTranCreate rejecting invalid name.");
8155 return CM_ERROR_BADNTFILENAME;
8158 userp = smb_GetUserFromVCP(vcp, inp);
8160 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
8162 return CM_ERROR_INVAL;
8167 baseDirp = cm_data.rootSCachep;
8168 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8169 if (code == CM_ERROR_TIDIPC) {
8170 /* Attempt to use a TID allocated for IPC. The client
8171 * is probably looking for DCE RPC end points which we
8172 * don't support OR it could be looking to make a DFS
8175 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
8178 cm_ReleaseUser(userp);
8179 return CM_ERROR_NOSUCHPATH;
8183 baseFidp = smb_FindFID(vcp, baseFid, 0);
8185 osi_Log2(smb_logp, "NTTranCreate Unknown SMB Fid vcp 0x%p fid %d",
8188 cm_ReleaseUser(userp);
8189 return CM_ERROR_BADFD;
8192 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8194 cm_ReleaseUser(userp);
8195 smb_CloseFID(vcp, baseFidp, NULL, 0);
8196 smb_ReleaseFID(baseFidp);
8197 return CM_ERROR_NOSUCHPATH;
8200 baseDirp = baseFidp->scp;
8204 /* compute open mode */
8206 if (desiredAccess & DELETE)
8207 fidflags |= SMB_FID_OPENDELETE;
8208 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
8209 fidflags |= SMB_FID_OPENREAD_LISTDIR;
8210 if (desiredAccess & AFS_ACCESS_WRITE)
8211 fidflags |= SMB_FID_OPENWRITE;
8212 if (createOptions & FILE_DELETE_ON_CLOSE)
8213 fidflags |= SMB_FID_DELONCLOSE;
8214 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
8215 fidflags |= SMB_FID_SEQUENTIAL;
8216 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
8217 fidflags |= SMB_FID_RANDOM;
8218 if (createOptions & FILE_OPEN_REPARSE_POINT)
8219 osi_Log0(smb_logp, "NTTranCreate Open Reparse Point");
8220 if (smb_IsExecutableFileName(lastNamep))
8221 fidflags |= SMB_FID_EXECUTABLE;
8223 /* And the share mode */
8224 if (shareAccess & FILE_SHARE_READ)
8225 fidflags |= SMB_FID_SHARE_READ;
8226 if (shareAccess & FILE_SHARE_WRITE)
8227 fidflags |= SMB_FID_SHARE_WRITE;
8231 if ( createDisp == FILE_OPEN ||
8232 createDisp == FILE_OVERWRITE ||
8233 createDisp == FILE_OVERWRITE_IF) {
8234 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8235 userp, tidPathp, &req, &dscp);
8238 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8239 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8240 cm_ReleaseSCache(dscp);
8241 cm_ReleaseUser(userp);
8244 smb_ReleaseFID(baseFidp);
8245 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8246 return CM_ERROR_PATH_NOT_COVERED;
8248 return CM_ERROR_NOSUCHPATH;
8250 #endif /* DFS_SUPPORT */
8251 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
8253 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
8254 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
8255 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
8256 if (code == 0 && realDirFlag == 1) {
8257 cm_ReleaseSCache(scp);
8258 cm_ReleaseSCache(dscp);
8259 cm_ReleaseUser(userp);
8262 smb_ReleaseFID(baseFidp);
8263 return CM_ERROR_EXISTS;
8269 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8270 userp, tidPathp, &req, &scp);
8272 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
8273 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
8274 cm_ReleaseSCache(scp);
8275 cm_ReleaseUser(userp);
8278 smb_ReleaseFID(baseFidp);
8279 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8280 return CM_ERROR_PATH_NOT_COVERED;
8282 return CM_ERROR_NOSUCHPATH;
8284 #endif /* DFS_SUPPORT */
8290 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
8291 /* look up parent directory */
8293 code = cm_NameI(baseDirp, spacep->wdata,
8294 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8295 userp, tidPathp, &req, &dscp);
8297 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8298 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8299 cm_ReleaseSCache(dscp);
8300 cm_ReleaseUser(userp);
8303 smb_ReleaseFID(baseFidp);
8304 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8305 return CM_ERROR_PATH_NOT_COVERED;
8307 return CM_ERROR_NOSUCHPATH;
8309 #endif /* DFS_SUPPORT */
8313 cm_FreeSpace(spacep);
8316 smb_ReleaseFID(baseFidp);
8319 cm_ReleaseUser(userp);
8325 lastNamep = realPathp;
8329 if (!smb_IsLegalFilename(lastNamep))
8330 return CM_ERROR_BADNTFILENAME;
8333 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
8334 code = cm_Lookup(dscp, lastNamep,
8335 CM_FLAG_FOLLOW, userp, &req, &scp);
8337 code = cm_Lookup(dscp, lastNamep,
8338 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8341 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8342 cm_ReleaseSCache(dscp);
8343 cm_ReleaseUser(userp);
8350 smb_ReleaseFID(baseFidp);
8351 cm_FreeSpace(spacep);
8354 /* if we get here, if code is 0, the file exists and is represented by
8355 * scp. Otherwise, we have to create it. The dir may be represented
8356 * by dscp, or we may have found the file directly. If code is non-zero,
8360 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
8362 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8364 cm_ReleaseSCache(dscp);
8365 cm_ReleaseSCache(scp);
8366 cm_ReleaseUser(userp);
8370 checkDoneRequired = 1;
8372 if (createDisp == FILE_CREATE) {
8373 /* oops, file shouldn't be there */
8374 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8376 cm_ReleaseSCache(dscp);
8377 cm_ReleaseSCache(scp);
8378 cm_ReleaseUser(userp);
8380 return CM_ERROR_EXISTS;
8383 if (createDisp == FILE_OVERWRITE ||
8384 createDisp == FILE_OVERWRITE_IF) {
8385 setAttr.mask = CM_ATTRMASK_LENGTH;
8386 setAttr.length.LowPart = 0;
8387 setAttr.length.HighPart = 0;
8389 /* now watch for a symlink */
8391 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8393 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8395 /* we have a more accurate file to use (the
8396 * target of the symbolic link). Otherwise,
8397 * we'll just use the symlink anyway.
8399 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8401 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8402 cm_ReleaseSCache(scp);
8404 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
8406 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8408 cm_ReleaseSCache(dscp);
8410 cm_ReleaseSCache(scp);
8411 cm_ReleaseUser(userp);
8417 code = cm_SetAttr(scp, &setAttr, userp, &req);
8418 openAction = 3; /* truncated existing file */
8420 else openAction = 1; /* found existing file */
8422 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
8423 /* don't create if not found */
8425 cm_ReleaseSCache(dscp);
8426 cm_ReleaseUser(userp);
8428 return CM_ERROR_NOSUCHFILE;
8430 else if (realDirFlag == 0 || realDirFlag == -1) {
8431 osi_assertx(dscp != NULL, "null cm_scache_t");
8432 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %S",
8433 osi_LogSaveClientString(smb_logp, lastNamep));
8434 openAction = 2; /* created file */
8435 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8436 setAttr.clientModTime = time(NULL);
8437 smb_SetInitialModeBitsForFile(extAttributes, &setAttr);
8439 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8443 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8444 smb_NotifyChange(FILE_ACTION_ADDED,
8445 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8446 dscp, lastNamep, NULL, TRUE);
8447 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
8448 /* Not an exclusive create, and someone else tried
8449 * creating it already, then we open it anyway. We
8450 * don't bother retrying after this, since if this next
8451 * fails, that means that the file was deleted after we
8452 * started this call.
8454 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8457 if (createDisp == FILE_OVERWRITE_IF) {
8458 setAttr.mask = CM_ATTRMASK_LENGTH;
8459 setAttr.length.LowPart = 0;
8460 setAttr.length.HighPart = 0;
8462 /* now watch for a symlink */
8464 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8466 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8468 /* we have a more accurate file to use (the
8469 * target of the symbolic link). Otherwise,
8470 * we'll just use the symlink anyway.
8472 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8474 cm_ReleaseSCache(scp);
8478 code = cm_SetAttr(scp, &setAttr, userp, &req);
8480 } /* lookup succeeded */
8483 /* create directory */
8484 osi_assertx(dscp != NULL, "null cm_scache_t");
8486 "smb_ReceiveNTTranCreate creating directory %S",
8487 osi_LogSaveClientString(smb_logp, lastNamep));
8488 openAction = 2; /* created directory */
8489 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8490 setAttr.clientModTime = time(NULL);
8491 smb_SetInitialModeBitsForDir(extAttributes, &setAttr);
8493 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8494 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8495 smb_NotifyChange(FILE_ACTION_ADDED,
8496 FILE_NOTIFY_CHANGE_DIR_NAME,
8497 dscp, lastNamep, NULL, TRUE);
8499 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
8500 /* Not an exclusive create, and someone else tried
8501 * creating it already, then we open it anyway. We
8502 * don't bother retrying after this, since if this next
8503 * fails, that means that the file was deleted after we
8504 * started this call.
8506 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8512 /* something went wrong creating or truncating the file */
8513 if (checkDoneRequired)
8514 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8516 cm_ReleaseSCache(scp);
8517 cm_ReleaseUser(userp);
8522 /* make sure we have file vs. dir right */
8523 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
8524 /* now watch for a symlink */
8526 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8528 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8530 /* we have a more accurate file to use (the
8531 * target of the symbolic link). Otherwise,
8532 * we'll just use the symlink anyway.
8534 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8536 if (checkDoneRequired) {
8537 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8538 checkDoneRequired = 0;
8540 cm_ReleaseSCache(scp);
8545 if (scp->fileType != CM_SCACHETYPE_FILE) {
8546 if (checkDoneRequired)
8547 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8548 cm_ReleaseSCache(scp);
8549 cm_ReleaseUser(userp);
8551 return CM_ERROR_ISDIR;
8555 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8556 if (checkDoneRequired)
8557 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8558 cm_ReleaseSCache(scp);
8559 cm_ReleaseUser(userp);
8561 return CM_ERROR_NOTDIR;
8564 /* open the file itself */
8565 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8566 osi_assertx(fidp, "null smb_fid_t");
8568 /* save a reference to the user */
8570 fidp->userp = userp;
8572 /* If we are restricting sharing, we should do so with a suitable
8574 if (scp->fileType == CM_SCACHETYPE_FILE &&
8575 !(fidflags & SMB_FID_SHARE_WRITE)) {
8577 LARGE_INTEGER LOffset, LLength;
8580 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8581 LOffset.LowPart = SMB_FID_QLOCK_LOW;
8582 LLength.HighPart = 0;
8583 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8585 /* Similar to what we do in handling NTCreateX. We get a
8586 shared lock if we are only opening the file for reading. */
8587 if ((fidflags & SMB_FID_SHARE_READ) ||
8588 !(fidflags & SMB_FID_OPENWRITE)) {
8589 sLockType = LOCKING_ANDX_SHARED_LOCK;
8594 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8596 lock_ObtainWrite(&scp->rw);
8597 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8598 lock_ReleaseWrite(&scp->rw);
8601 if (checkDoneRequired)
8602 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8603 cm_ReleaseSCache(scp);
8604 cm_ReleaseUser(userp);
8605 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
8606 smb_CloseFID(vcp, fidp, NULL, 0);
8607 smb_ReleaseFID(fidp);
8609 return CM_ERROR_SHARING_VIOLATION;
8613 /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
8614 if (checkDoneRequired) {
8615 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8616 checkDoneRequired = 0;
8619 lock_ObtainMutex(&fidp->mx);
8620 /* save a pointer to the vnode */
8622 lock_ObtainWrite(&scp->rw);
8623 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8624 lock_ReleaseWrite(&scp->rw);
8625 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
8627 fidp->flags = fidflags;
8629 /* remember if the file was newly created */
8631 fidp->flags |= SMB_FID_CREATED;
8633 /* save parent dir and pathname for deletion or change notification */
8634 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8635 fidp->flags |= SMB_FID_NTOPEN;
8636 fidp->NTopen_dscp = dscp;
8637 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
8639 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
8641 fidp->NTopen_wholepathp = realPathp;
8642 lock_ReleaseMutex(&fidp->mx);
8644 /* we don't need this any longer */
8646 cm_ReleaseSCache(dscp);
8648 cm_Open(scp, 0, userp);
8650 /* set inp->fid so that later read calls in same msg can find fid */
8651 inp->fid = fidp->fid;
8653 /* check whether we are required to send an extended response */
8654 if (!extendedRespRequired) {
8656 parmOffset = 8*4 + 39;
8657 parmOffset += 1; /* pad to 4 */
8658 dataOffset = parmOffset + 70;
8662 /* Total Parameter Count */
8663 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8664 /* Total Data Count */
8665 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8666 /* Parameter Count */
8667 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8668 /* Parameter Offset */
8669 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8670 /* Parameter Displacement */
8671 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8673 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8675 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8676 /* Data Displacement */
8677 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8678 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8679 smb_SetSMBDataLength(outp, 70);
8681 lock_ObtainRead(&scp->rw);
8682 outData = smb_GetSMBData(outp, NULL);
8683 outData++; /* round to get to parmOffset */
8684 *outData = 0; outData++; /* oplock */
8685 *outData = 0; outData++; /* reserved */
8686 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8687 *((ULONG *)outData) = openAction; outData += 4;
8688 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8689 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8690 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8691 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8692 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8693 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8694 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8695 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8696 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8697 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8698 *((USHORT *)outData) = NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS;
8699 outData += 2; /* dev state */
8700 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8701 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8702 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8703 outData += 2; /* is a dir? */
8706 parmOffset = 8*4 + 39;
8707 parmOffset += 1; /* pad to 4 */
8708 dataOffset = parmOffset + 104;
8712 /* Total Parameter Count */
8713 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8714 /* Total Data Count */
8715 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8716 /* Parameter Count */
8717 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8718 /* Parameter Offset */
8719 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8720 /* Parameter Displacement */
8721 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8723 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8725 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8726 /* Data Displacement */
8727 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8728 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8729 smb_SetSMBDataLength(outp, 105);
8731 lock_ObtainRead(&scp->rw);
8732 outData = smb_GetSMBData(outp, NULL);
8733 outData++; /* round to get to parmOffset */
8734 *outData = 0; outData++; /* oplock */
8735 *outData = 1; outData++; /* response type */
8736 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8737 *((ULONG *)outData) = openAction; outData += 4;
8738 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8739 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8740 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8741 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8742 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8743 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8744 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8745 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8746 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8747 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8748 *((USHORT *)outData) = NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS;
8749 outData += 2; /* dev state */
8750 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8751 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8752 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8753 outData += 1; /* is a dir? */
8754 /* Setting the GUID results in failures with cygwin */
8755 memset(outData,0,24); outData += 24; /* GUID */
8756 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
8757 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
8760 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
8761 LargeIntegerGreaterThanZero(scp->length) &&
8762 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
8765 lock_ReleaseRead(&scp->rw);
8768 cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
8769 scp->length.LowPart, scp->length.HighPart,
8772 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
8774 cm_ReleaseUser(userp);
8775 smb_ReleaseFID(fidp);
8777 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
8778 /* leave scp held since we put it in fidp->scp */
8782 /* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
8783 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
8786 smb_packet_t *savedPacketp;
8788 USHORT fid, watchtree;
8792 filter = smb_GetSMBParm(inp, 19) |
8793 (smb_GetSMBParm(inp, 20) << 16);
8794 fid = smb_GetSMBParm(inp, 21);
8795 watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
8797 fidp = smb_FindFID(vcp, fid, 0);
8799 osi_Log2(smb_logp, "NotifyChange Unknown SMB Fid vcp 0x%p fid %d",
8801 return CM_ERROR_BADFD;
8804 lock_ObtainMutex(&fidp->mx);
8805 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8806 lock_ReleaseMutex(&fidp->mx);
8807 smb_CloseFID(vcp, fidp, NULL, 0);
8808 smb_ReleaseFID(fidp);
8809 return CM_ERROR_NOSUCHFILE;
8813 lock_ReleaseMutex(&fidp->mx);
8815 /* Create a copy of the Directory Watch Packet to use when sending the
8816 * notification if in the future a matching change is detected.
8818 savedPacketp = smb_CopyPacket(inp);
8819 if (vcp != savedPacketp->vcp) {
8821 if (savedPacketp->vcp)
8822 smb_ReleaseVC(savedPacketp->vcp);
8823 savedPacketp->vcp = vcp;
8826 /* Add the watch to the list of events to send notifications for */
8827 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8828 savedPacketp->nextp = smb_Directory_Watches;
8829 smb_Directory_Watches = savedPacketp;
8830 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8832 osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%S\"",
8833 fidp, scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp));
8834 osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
8835 filter, fid, watchtree);
8836 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8837 osi_Log0(smb_logp, " Notify Change File Name");
8838 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8839 osi_Log0(smb_logp, " Notify Change Directory Name");
8840 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8841 osi_Log0(smb_logp, " Notify Change Attributes");
8842 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8843 osi_Log0(smb_logp, " Notify Change Size");
8844 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8845 osi_Log0(smb_logp, " Notify Change Last Write");
8846 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8847 osi_Log0(smb_logp, " Notify Change Last Access");
8848 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8849 osi_Log0(smb_logp, " Notify Change Creation");
8850 if (filter & FILE_NOTIFY_CHANGE_EA)
8851 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8852 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8853 osi_Log0(smb_logp, " Notify Change Security");
8854 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8855 osi_Log0(smb_logp, " Notify Change Stream Name");
8856 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8857 osi_Log0(smb_logp, " Notify Change Stream Size");
8858 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8859 osi_Log0(smb_logp, " Notify Change Stream Write");
8861 lock_ObtainWrite(&scp->rw);
8863 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
8865 scp->flags |= CM_SCACHEFLAG_WATCHED;
8866 lock_ReleaseWrite(&scp->rw);
8867 cm_ReleaseSCache(scp);
8868 smb_ReleaseFID(fidp);
8870 outp->flags |= SMB_PACKETFLAG_NOSEND;
8874 unsigned char nullSecurityDesc[36] = {
8875 0x01, /* security descriptor revision */
8876 0x00, /* reserved, should be zero */
8877 0x00, 0x80, /* security descriptor control;
8878 * 0x8000 : self-relative format */
8879 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
8880 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
8881 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
8882 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
8883 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8884 /* "null SID" owner SID */
8885 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
8886 /* "null SID" group SID */
8889 /* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
8890 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8892 int parmOffset, parmCount, dataOffset, dataCount;
8900 ULONG securityInformation;
8902 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8903 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8904 parmp = inp->data + parmOffset;
8905 sparmp = (USHORT *) parmp;
8906 lparmp = (ULONG *) parmp;
8909 securityInformation = lparmp[1];
8911 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
8912 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
8920 parmOffset = 8*4 + 39;
8921 parmOffset += 1; /* pad to 4 */
8923 dataOffset = parmOffset + parmCount;
8927 /* Total Parameter Count */
8928 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8929 /* Total Data Count */
8930 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8931 /* Parameter Count */
8932 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8933 /* Parameter Offset */
8934 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8935 /* Parameter Displacement */
8936 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8938 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8940 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8941 /* Data Displacement */
8942 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8943 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8944 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
8946 outData = smb_GetSMBData(outp, NULL);
8947 outData++; /* round to get to parmOffset */
8948 *((ULONG *)outData) = 36; outData += 4; /* length */
8950 if (maxData >= 36) {
8951 memcpy(outData, nullSecurityDesc, 36);
8955 return CM_ERROR_BUFFERTOOSMALL;
8958 /* SMB_COM_NT_TRANSACT
8960 SMB_COM_NT_TRANSACT_SECONDARY should also be handled here.
8962 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8964 unsigned short function;
8966 function = smb_GetSMBParm(inp, 18);
8968 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
8970 /* We can handle long names */
8971 if (vcp->flags & SMB_VCFLAG_USENT)
8972 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
8975 case 1: /* NT_TRANSACT_CREATE */
8976 return smb_ReceiveNTTranCreate(vcp, inp, outp);
8977 case 2: /* NT_TRANSACT_IOCTL */
8978 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
8980 case 3: /* NT_TRANSACT_SET_SECURITY_DESC */
8981 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
8983 case 4: /* NT_TRANSACT_NOTIFY_CHANGE */
8984 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
8985 case 5: /* NT_TRANSACT_RENAME */
8986 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
8988 case 6: /* NT_TRANSACT_QUERY_SECURITY_DESC */
8989 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
8991 osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
8994 osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
8997 return CM_ERROR_BADOP;
9001 * smb_NotifyChange -- find relevant change notification messages and
9004 * If we don't know the file name (i.e. a callback break), filename is
9005 * NULL, and we return a zero-length list.
9007 * At present there is not a single call to smb_NotifyChange that
9008 * has the isDirectParent parameter set to FALSE.
9010 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
9011 cm_scache_t *dscp, clientchar_t *filename, clientchar_t *otherFilename,
9012 BOOL isDirectParent)
9014 smb_packet_t *watch, *lastWatch, *nextWatch;
9015 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen = 0;
9016 char *outData, *oldOutData;
9020 BOOL twoEntries = FALSE;
9021 ULONG otherNameLen, oldParmCount = 0;
9025 /* Get ready for rename within directory */
9026 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
9028 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
9031 osi_Log4(smb_logp,"in smb_NotifyChange for file [%S] dscp [%p] notification 0x%x parent %d",
9032 osi_LogSaveClientString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
9034 osi_Log0(smb_logp," FILE_ACTION_NONE");
9035 if (action == FILE_ACTION_ADDED)
9036 osi_Log0(smb_logp," FILE_ACTION_ADDED");
9037 if (action == FILE_ACTION_REMOVED)
9038 osi_Log0(smb_logp," FILE_ACTION_REMOVED");
9039 if (action == FILE_ACTION_MODIFIED)
9040 osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
9041 if (action == FILE_ACTION_RENAMED_OLD_NAME)
9042 osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
9043 if (action == FILE_ACTION_RENAMED_NEW_NAME)
9044 osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
9046 lock_ObtainMutex(&smb_Dir_Watch_Lock);
9047 watch = smb_Directory_Watches;
9049 filter = smb_GetSMBParm(watch, 19)
9050 | (smb_GetSMBParm(watch, 20) << 16);
9051 fid = smb_GetSMBParm(watch, 21);
9052 wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
9054 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
9055 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
9058 * Strange hack - bug in NT Client and NT Server that we must emulate?
9060 if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
9061 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
9063 fidp = smb_FindFID(watch->vcp, fid, 0);
9065 osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
9067 watch = watch->nextp;
9071 if (fidp->scp != dscp ||
9072 fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
9073 (filter & notifyFilter) == 0 ||
9074 (!isDirectParent && !wtree))
9076 osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
9078 watch = watch->nextp;
9079 smb_ReleaseFID(fidp);
9084 "Sending Change Notification for fid %d filter 0x%x wtree %d file %S",
9085 fid, filter, wtree, osi_LogSaveClientString(smb_logp, filename));
9086 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
9087 osi_Log0(smb_logp, " Notify Change File Name");
9088 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
9089 osi_Log0(smb_logp, " Notify Change Directory Name");
9090 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
9091 osi_Log0(smb_logp, " Notify Change Attributes");
9092 if (filter & FILE_NOTIFY_CHANGE_SIZE)
9093 osi_Log0(smb_logp, " Notify Change Size");
9094 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
9095 osi_Log0(smb_logp, " Notify Change Last Write");
9096 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
9097 osi_Log0(smb_logp, " Notify Change Last Access");
9098 if (filter & FILE_NOTIFY_CHANGE_CREATION)
9099 osi_Log0(smb_logp, " Notify Change Creation");
9100 if (filter & FILE_NOTIFY_CHANGE_EA)
9101 osi_Log0(smb_logp, " Notify Change Extended Attributes");
9102 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
9103 osi_Log0(smb_logp, " Notify Change Security");
9104 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
9105 osi_Log0(smb_logp, " Notify Change Stream Name");
9106 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
9107 osi_Log0(smb_logp, " Notify Change Stream Size");
9108 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
9109 osi_Log0(smb_logp, " Notify Change Stream Write");
9111 /* A watch can only be notified once. Remove it from the list */
9112 nextWatch = watch->nextp;
9113 if (watch == smb_Directory_Watches)
9114 smb_Directory_Watches = nextWatch;
9116 lastWatch->nextp = nextWatch;
9118 /* Turn off WATCHED flag in dscp */
9119 lock_ObtainWrite(&dscp->rw);
9121 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
9123 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
9124 lock_ReleaseWrite(&dscp->rw);
9126 /* Convert to response packet */
9127 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
9128 #ifdef SEND_CANONICAL_PATHNAMES
9129 ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
9131 ((smb_t *) watch)->wct = 0;
9134 if (filename == NULL) {
9137 nameLen = (ULONG)cm_ClientStrLen(filename);
9138 parmCount = 3*4 + nameLen*2;
9139 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
9141 otherNameLen = (ULONG)cm_ClientStrLen(otherFilename);
9142 oldParmCount = parmCount;
9143 parmCount += 3*4 + otherNameLen*2;
9144 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
9146 if (maxLen < parmCount)
9147 parmCount = 0; /* not enough room */
9149 parmOffset = 8*4 + 39;
9150 parmOffset += 1; /* pad to 4 */
9151 dataOffset = parmOffset + parmCount;
9155 /* Total Parameter Count */
9156 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
9157 /* Total Data Count */
9158 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9159 /* Parameter Count */
9160 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
9161 /* Parameter Offset */
9162 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
9163 /* Parameter Displacement */
9164 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9166 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9168 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
9169 /* Data Displacement */
9170 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9171 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
9172 smb_SetSMBDataLength(watch, parmCount + 1);
9174 if (parmCount != 0) {
9175 outData = smb_GetSMBData(watch, NULL);
9176 outData++; /* round to get to parmOffset */
9177 oldOutData = outData;
9178 *((DWORD *)outData) = oldParmCount; outData += 4;
9179 /* Next Entry Offset */
9180 *((DWORD *)outData) = action; outData += 4;
9182 *((DWORD *)outData) = nameLen*2; outData += 4;
9183 /* File Name Length */
9185 smb_UnparseString(watch, outData, filename, NULL, 0);
9189 outData = oldOutData + oldParmCount;
9190 *((DWORD *)outData) = 0; outData += 4;
9191 /* Next Entry Offset */
9192 *((DWORD *)outData) = otherAction; outData += 4;
9194 *((DWORD *)outData) = otherNameLen*2;
9195 outData += 4; /* File Name Length */
9196 smb_UnparseString(watch, outData, otherFilename, NULL, 0);
9201 * If filename is null, we don't know the cause of the
9202 * change notification. We return zero data (see above),
9203 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
9204 * (= 0x010C). We set the error code here by hand, without
9205 * modifying wct and bcc.
9207 if (filename == NULL) {
9208 ((smb_t *) watch)->rcls = 0x0C;
9209 ((smb_t *) watch)->reh = 0x01;
9210 ((smb_t *) watch)->errLow = 0;
9211 ((smb_t *) watch)->errHigh = 0;
9212 /* Set NT Status codes flag */
9213 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9216 smb_SendPacket(watch->vcp, watch);
9217 smb_FreePacket(watch);
9219 smb_ReleaseFID(fidp);
9222 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9225 /* SMB_COM_NT_CANCEL */
9226 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9228 unsigned char *replyWctp;
9229 smb_packet_t *watch, *lastWatch;
9230 USHORT fid, watchtree;
9234 osi_Log0(smb_logp, "SMB3 receive NT cancel");
9236 lock_ObtainMutex(&smb_Dir_Watch_Lock);
9237 watch = smb_Directory_Watches;
9239 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
9240 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
9241 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
9242 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
9243 if (watch == smb_Directory_Watches)
9244 smb_Directory_Watches = watch->nextp;
9246 lastWatch->nextp = watch->nextp;
9247 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9249 /* Turn off WATCHED flag in scp */
9250 fid = smb_GetSMBParm(watch, 21);
9251 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
9253 if (vcp != watch->vcp)
9254 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
9257 fidp = smb_FindFID(vcp, fid, 0);
9259 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %S",
9261 (fidp ? osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp) :_C("")));
9264 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
9266 lock_ObtainWrite(&scp->rw);
9268 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
9270 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
9271 lock_ReleaseWrite(&scp->rw);
9273 smb_ReleaseFID(fidp);
9275 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
9278 /* assume STATUS32; return 0xC0000120 (CANCELED) */
9279 replyWctp = watch->wctp;
9283 ((smb_t *)watch)->rcls = 0x20;
9284 ((smb_t *)watch)->reh = 0x1;
9285 ((smb_t *)watch)->errLow = 0;
9286 ((smb_t *)watch)->errHigh = 0xC0;
9287 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9288 smb_SendPacket(vcp, watch);
9289 smb_FreePacket(watch);
9293 watch = watch->nextp;
9295 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9301 * NT rename also does hard links.
9304 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
9305 #define RENAME_FLAG_HARD_LINK 0x103
9306 #define RENAME_FLAG_RENAME 0x104
9307 #define RENAME_FLAG_COPY 0x105
9309 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9311 clientchar_t *oldPathp, *newPathp;
9317 attrs = smb_GetSMBParm(inp, 0);
9318 rename_type = smb_GetSMBParm(inp, 1);
9320 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
9321 osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
9322 return CM_ERROR_NOACCESS;
9325 tp = smb_GetSMBData(inp, NULL);
9326 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
9328 return CM_ERROR_BADSMB;
9329 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
9331 return CM_ERROR_BADSMB;
9333 osi_Log3(smb_logp, "NTRename for [%S]->[%S] type [%s]",
9334 osi_LogSaveClientString(smb_logp, oldPathp),
9335 osi_LogSaveClientString(smb_logp, newPathp),
9336 ((rename_type==RENAME_FLAG_RENAME)?"rename":(rename_type==RENAME_FLAG_HARD_LINK)?"hardlink":"other"));
9338 if (rename_type == RENAME_FLAG_RENAME) {
9339 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
9340 } else if (rename_type == RENAME_FLAG_HARD_LINK) { /* RENAME_FLAG_HARD_LINK */
9341 code = smb_Link(vcp,inp,oldPathp,newPathp);
9343 code = CM_ERROR_BADOP;
9349 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock", LOCK_HIERARCHY_SMB_DIRWATCH);
9352 cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
9354 smb_username_t *unp;
9357 unp = smb_FindUserByName(usern, machine, flags);
9359 lock_ObtainMutex(&unp->mx);
9360 unp->userp = cm_NewUser();
9361 lock_ReleaseMutex(&unp->mx);
9362 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9364 osi_Log2(smb_logp,"smb_FindCMUserByName Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9368 smb_ReleaseUsername(unp);