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 & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
119 attrs |= SMB_ATTR_READONLY; /* Read-only */
121 if ((scp->unixModeBits & 0222) == 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 */
2483 int initialModeBits;
2486 clientchar_t *lastNamep;
2493 int parmSlot; /* which parm we're dealing with */
2494 long returnEALength;
2495 clientchar_t *tidPathp;
2498 BOOL is_rpc = FALSE;
2499 BOOL is_ipc = FALSE;
2505 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2506 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2508 openFun = p->parmsp[6]; /* open function */
2509 excl = ((openFun & 3) == 0);
2510 trunc = ((openFun & 3) == 2); /* truncate it */
2511 openMode = (p->parmsp[1] & 0x7);
2512 openAction = 0; /* tracks what we did */
2514 attributes = p->parmsp[3];
2515 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2517 /* compute initial mode bits based on read-only flag in attributes */
2518 initialModeBits = 0666;
2519 if (attributes & SMB_ATTR_READONLY)
2520 initialModeBits &= ~0222;
2522 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
2525 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2527 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2528 if (code == CM_ERROR_TIDIPC) {
2530 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2533 spacep = cm_GetSpace();
2534 /* smb_StripLastComponent will strip "::$DATA" if present */
2535 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2539 /* special case magic file name for receiving IOCTL requests
2540 * (since IOCTL calls themselves aren't getting through).
2542 (cm_ClientStrCmpI(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
2544 /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional)*/
2545 (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
2547 unsigned short file_type = 0;
2548 unsigned short device_state = 0;
2550 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2553 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
2554 osi_Log2(smb_logp, "smb_ReceiveTran2Open Creating RPC Fid [%d] code [%d]",
2557 smb_ReleaseFID(fidp);
2558 smb_FreeTran2Packet(outp);
2559 osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
2563 smb_SetupIoctlFid(fidp, spacep);
2564 osi_Log1(smb_logp, "smb_ReceiveTran2Open Creating IOCTL Fid [%d]", fidp->fid);
2567 /* copy out remainder of the parms */
2569 outp->parmsp[parmSlot++] = fidp->fid;
2571 outp->parmsp[parmSlot++] = 0; /* attrs */
2572 outp->parmsp[parmSlot++] = 0; /* mod time */
2573 outp->parmsp[parmSlot++] = 0;
2574 outp->parmsp[parmSlot++] = 0; /* len */
2575 outp->parmsp[parmSlot++] = 0x7fff;
2576 outp->parmsp[parmSlot++] = openMode;
2577 outp->parmsp[parmSlot++] = file_type;
2578 outp->parmsp[parmSlot++] = device_state;
2580 /* and the final "always present" stuff */
2581 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2582 /* next write out the "unique" ID */
2583 outp->parmsp[parmSlot++] = 0x1234;
2584 outp->parmsp[parmSlot++] = 0x5678;
2585 outp->parmsp[parmSlot++] = 0;
2586 if (returnEALength) {
2587 outp->parmsp[parmSlot++] = 0;
2588 outp->parmsp[parmSlot++] = 0;
2591 outp->totalData = 0;
2592 outp->totalParms = parmSlot * 2;
2594 smb_SendTran2Packet(vcp, outp, op);
2596 smb_FreeTran2Packet(outp);
2598 /* and clean up fid reference */
2599 smb_ReleaseFID(fidp);
2605 osi_Log1(smb_logp, "Tran2Open rejecting IPC TID vcp %p", vcp);
2606 smb_FreeTran2Packet(outp);
2607 return CM_ERROR_BADFD;
2611 if (!cm_IsValidClientString(pathp)) {
2613 clientchar_t * hexp;
2615 hexp = cm_GetRawCharsAlloc(pathp, -1);
2616 osi_Log1(smb_logp, "Tran2Open rejecting invalid name. [%S]",
2617 osi_LogSaveClientString(smb_logp, hexp));
2621 osi_Log0(smb_logp, "Tran2Open rejecting invalid name");
2623 smb_FreeTran2Packet(outp);
2624 return CM_ERROR_BADNTFILENAME;
2627 #ifdef DEBUG_VERBOSE
2629 char *hexp, *asciip;
2630 asciip = (lastNamep ? lastNamep : pathp);
2631 hexp = osi_HexifyString( asciip );
2632 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2637 userp = smb_GetTran2User(vcp, p);
2638 /* In the off chance that userp is NULL, we log and abandon */
2640 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2641 smb_FreeTran2Packet(outp);
2642 return CM_ERROR_BADSMB;
2646 code = cm_NameI(cm_data.rootSCachep, pathp,
2647 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2648 userp, tidPathp, &req, &scp);
2650 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2651 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2652 userp, tidPathp, &req, &dscp);
2653 cm_FreeSpace(spacep);
2656 cm_ReleaseUser(userp);
2657 smb_FreeTran2Packet(outp);
2662 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2663 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2664 (clientchar_t*) spacep->data);
2665 cm_ReleaseSCache(dscp);
2666 cm_ReleaseUser(userp);
2667 smb_FreeTran2Packet(outp);
2668 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2669 return CM_ERROR_PATH_NOT_COVERED;
2671 return CM_ERROR_NOSUCHPATH;
2673 #endif /* DFS_SUPPORT */
2675 /* otherwise, scp points to the parent directory. Do a lookup,
2676 * and truncate the file if we find it, otherwise we create the
2683 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2685 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2686 cm_ReleaseSCache(dscp);
2687 cm_ReleaseUser(userp);
2688 smb_FreeTran2Packet(outp);
2692 /* macintosh is expensive to program for it */
2693 cm_FreeSpace(spacep);
2696 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2697 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2698 cm_ReleaseSCache(scp);
2699 cm_ReleaseUser(userp);
2700 smb_FreeTran2Packet(outp);
2701 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2702 return CM_ERROR_PATH_NOT_COVERED;
2704 return CM_ERROR_NOSUCHPATH;
2706 #endif /* DFS_SUPPORT */
2709 /* if we get here, if code is 0, the file exists and is represented by
2710 * scp. Otherwise, we have to create it.
2713 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2716 cm_ReleaseSCache(dscp);
2717 cm_ReleaseSCache(scp);
2718 cm_ReleaseUser(userp);
2719 smb_FreeTran2Packet(outp);
2724 /* oops, file shouldn't be there */
2726 cm_ReleaseSCache(dscp);
2727 cm_ReleaseSCache(scp);
2728 cm_ReleaseUser(userp);
2729 smb_FreeTran2Packet(outp);
2730 return CM_ERROR_EXISTS;
2734 setAttr.mask = CM_ATTRMASK_LENGTH;
2735 setAttr.length.LowPart = 0;
2736 setAttr.length.HighPart = 0;
2737 code = cm_SetAttr(scp, &setAttr, userp, &req);
2738 openAction = 3; /* truncated existing file */
2741 openAction = 1; /* found existing file */
2743 else if (!(openFun & 0x10)) {
2744 /* don't create if not found */
2746 cm_ReleaseSCache(dscp);
2747 osi_assertx(scp == NULL, "null cm_scache_t");
2748 cm_ReleaseUser(userp);
2749 smb_FreeTran2Packet(outp);
2750 return CM_ERROR_NOSUCHFILE;
2753 osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2754 openAction = 2; /* created file */
2755 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2756 cm_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2757 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2761 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2762 smb_NotifyChange(FILE_ACTION_ADDED,
2763 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2764 dscp, lastNamep, NULL, TRUE);
2765 } else if (!excl && code == CM_ERROR_EXISTS) {
2766 /* not an exclusive create, and someone else tried
2767 * creating it already, then we open it anyway. We
2768 * don't bother retrying after this, since if this next
2769 * fails, that means that the file was deleted after we
2770 * started this call.
2772 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2776 setAttr.mask = CM_ATTRMASK_LENGTH;
2777 setAttr.length.LowPart = 0;
2778 setAttr.length.HighPart = 0;
2779 code = cm_SetAttr(scp, &setAttr, userp,
2782 } /* lookup succeeded */
2786 /* we don't need this any longer */
2788 cm_ReleaseSCache(dscp);
2791 /* something went wrong creating or truncating the file */
2793 cm_ReleaseSCache(scp);
2794 cm_ReleaseUser(userp);
2795 smb_FreeTran2Packet(outp);
2799 /* make sure we're about to open a file */
2800 if (scp->fileType != CM_SCACHETYPE_FILE) {
2802 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2803 cm_scache_t * targetScp = 0;
2804 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2806 /* we have a more accurate file to use (the
2807 * target of the symbolic link). Otherwise,
2808 * we'll just use the symlink anyway.
2810 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2812 cm_ReleaseSCache(scp);
2816 if (scp->fileType != CM_SCACHETYPE_FILE) {
2817 cm_ReleaseSCache(scp);
2818 cm_ReleaseUser(userp);
2819 smb_FreeTran2Packet(outp);
2820 return CM_ERROR_ISDIR;
2824 /* now all we have to do is open the file itself */
2825 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2826 osi_assertx(fidp, "null smb_fid_t");
2829 lock_ObtainMutex(&fidp->mx);
2830 /* save a pointer to the vnode */
2831 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2833 lock_ObtainWrite(&scp->rw);
2834 scp->flags |= CM_SCACHEFLAG_SMB_FID;
2835 lock_ReleaseWrite(&scp->rw);
2838 fidp->userp = userp;
2840 /* compute open mode */
2842 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
2843 if (openMode == 1 || openMode == 2)
2844 fidp->flags |= SMB_FID_OPENWRITE;
2846 /* remember that the file was newly created */
2848 fidp->flags |= SMB_FID_CREATED;
2850 lock_ReleaseMutex(&fidp->mx);
2852 smb_ReleaseFID(fidp);
2854 cm_Open(scp, 0, userp);
2856 /* copy out remainder of the parms */
2858 outp->parmsp[parmSlot++] = fidp->fid;
2859 lock_ObtainRead(&scp->rw);
2861 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2862 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2863 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2864 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2865 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2866 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2867 outp->parmsp[parmSlot++] = openMode;
2868 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2869 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2871 /* and the final "always present" stuff */
2872 outp->parmsp[parmSlot++] = openAction;
2873 /* next write out the "unique" ID */
2874 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2875 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2876 outp->parmsp[parmSlot++] = 0;
2877 if (returnEALength) {
2878 outp->parmsp[parmSlot++] = 0;
2879 outp->parmsp[parmSlot++] = 0;
2881 lock_ReleaseRead(&scp->rw);
2882 outp->totalData = 0; /* total # of data bytes */
2883 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2885 smb_SendTran2Packet(vcp, outp, op);
2887 smb_FreeTran2Packet(outp);
2889 cm_ReleaseUser(userp);
2890 /* leave scp held since we put it in fidp->scp */
2894 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2897 unsigned short infolevel;
2899 infolevel = p->parmsp[0];
2901 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2903 return CM_ERROR_BAD_LEVEL;
2906 /* TRANS2_QUERY_FS_INFORMATION */
2907 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2909 smb_tran2Packet_t *outp;
2910 smb_tran2QFSInfo_t qi;
2914 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2916 switch (p->parmsp[0]) {
2917 case SMB_INFO_ALLOCATION:
2919 responseSize = sizeof(qi.u.allocInfo);
2921 qi.u.allocInfo.FSID = 0;
2922 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2923 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2924 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2925 qi.u.allocInfo.bytesPerSector = 1024;
2928 case SMB_INFO_VOLUME:
2930 qi.u.volumeInfo.vsn = 1234; /* Volume serial number */
2931 qi.u.volumeInfo.vnCount = 3; /* Number of characters in label (AFS\0)*/
2933 /* we're supposed to pad it out with zeroes to the end */
2934 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2935 smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
2937 responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
2940 case SMB_QUERY_FS_VOLUME_INFO:
2941 /* FS volume info */
2942 responseSize = sizeof(qi.u.FSvolumeInfo);
2945 FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
2946 memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
2949 qi.u.FSvolumeInfo.vsn = 1234;
2950 qi.u.FSvolumeInfo.vnCount = 6; /* This is always in Unicode */
2951 memset(&qi.u.FSvolumeInfo.label, 0, sizeof(qi.u.FSvolumeInfo.label));
2952 memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
2955 case SMB_QUERY_FS_SIZE_INFO:
2957 responseSize = sizeof(qi.u.FSsizeInfo);
2959 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2960 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2961 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2962 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2963 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2964 qi.u.FSsizeInfo.bytesPerSector = 1024;
2967 case SMB_QUERY_FS_DEVICE_INFO:
2968 /* FS device info */
2969 responseSize = sizeof(qi.u.FSdeviceInfo);
2971 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2972 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2975 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2976 /* FS attribute info */
2978 /* attributes, defined in WINNT.H:
2979 * FILE_CASE_SENSITIVE_SEARCH 0x1
2980 * FILE_CASE_PRESERVED_NAMES 0x2
2981 * FILE_UNICODE_ON_DISK 0x4
2982 * FILE_VOLUME_QUOTAS 0x10
2983 * <no name defined> 0x4000
2984 * If bit 0x4000 is not set, Windows 95 thinks
2985 * we can't handle long (non-8.3) names,
2986 * despite our protestations to the contrary.
2988 qi.u.FSattributeInfo.attributes = 0x4003;
2989 /* The maxCompLength is supposed to be in bytes */
2991 qi.u.FSattributeInfo.attributes |= 0x04;
2993 qi.u.FSattributeInfo.maxCompLength = 255;
2994 smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
2995 qi.u.FSattributeInfo.FSnameLength = sz;
2998 sizeof(qi.u.FSattributeInfo.attributes) +
2999 sizeof(qi.u.FSattributeInfo.maxCompLength) +
3000 sizeof(qi.u.FSattributeInfo.FSnameLength) +
3005 case SMB_INFO_UNIX: /* CIFS Unix Info */
3006 case SMB_INFO_MACOS: /* Mac FS Info */
3008 return CM_ERROR_BADOP;
3011 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
3013 /* copy out return data, and set corresponding sizes */
3014 outp->totalParms = 0;
3015 outp->totalData = responseSize;
3016 memcpy(outp->datap, &qi, responseSize);
3018 /* send and free the packets */
3019 smb_SendTran2Packet(vcp, outp, op);
3020 smb_FreeTran2Packet(outp);
3025 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3027 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
3028 return CM_ERROR_BADOP;
3031 struct smb_ShortNameRock {
3032 clientchar_t *maskp;
3034 clientchar_t *shortName;
3035 size_t shortNameLen;
3038 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
3041 struct smb_ShortNameRock *rockp;
3042 normchar_t normName[MAX_PATH];
3043 clientchar_t *shortNameEnd;
3047 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t)) == 0) {
3048 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
3049 osi_LogSaveString(smb_logp, dep->name));
3053 /* compare both names and vnodes, though probably just comparing vnodes
3054 * would be safe enough.
3056 if (cm_NormStrCmpI(normName, rockp->maskp) != 0)
3058 if (ntohl(dep->fid.vnode) != rockp->vnode)
3061 /* This is the entry */
3062 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
3063 rockp->shortNameLen = shortNameEnd - rockp->shortName;
3065 return CM_ERROR_STOPNOW;
3068 long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
3069 clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
3071 struct smb_ShortNameRock rock;
3072 clientchar_t *lastNamep;
3075 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
3079 spacep = cm_GetSpace();
3080 /* smb_StripLastComponent will strip "::$DATA" if present */
3081 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
3083 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3084 caseFold, userp, tidPathp,
3086 cm_FreeSpace(spacep);
3091 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3092 cm_ReleaseSCache(dscp);
3093 cm_ReleaseUser(userp);
3097 return CM_ERROR_PATH_NOT_COVERED;
3099 #endif /* DFS_SUPPORT */
3101 if (!lastNamep) lastNamep = pathp;
3104 thyper.HighPart = 0;
3105 rock.shortName = shortName;
3107 rock.maskp = lastNamep;
3108 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
3110 cm_ReleaseSCache(dscp);
3113 return CM_ERROR_NOSUCHFILE;
3114 if (code == CM_ERROR_STOPNOW) {
3115 *shortNameLenp = rock.shortNameLen;
3121 /* TRANS2_QUERY_PATH_INFORMATION */
3122 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3124 smb_tran2Packet_t *outp;
3127 unsigned short infoLevel;
3128 smb_tran2QPathInfo_t qpi;
3130 unsigned short attributes;
3131 unsigned long extAttributes;
3132 clientchar_t shortName[13];
3136 cm_scache_t *scp, *dscp;
3137 int scp_rw_held = 0;
3140 clientchar_t *pathp;
3141 clientchar_t *tidPathp;
3142 clientchar_t *lastComp;
3147 infoLevel = p->parmsp[0];
3148 if (infoLevel == SMB_INFO_IS_NAME_VALID)
3150 else if (infoLevel == SMB_INFO_STANDARD)
3151 responseSize = sizeof(qpi.u.QPstandardInfo);
3152 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
3153 responseSize = sizeof(qpi.u.QPeaSizeInfo);
3154 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3155 responseSize = sizeof(qpi.u.QPfileBasicInfo);
3156 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3157 responseSize = sizeof(qpi.u.QPfileStandardInfo);
3158 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3159 responseSize = sizeof(qpi.u.QPfileEaInfo);
3160 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3161 responseSize = sizeof(qpi.u.QPfileNameInfo);
3162 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
3163 responseSize = sizeof(qpi.u.QPfileAllInfo);
3164 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
3165 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
3166 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO)
3167 responseSize = sizeof(qpi.u.QPfileStreamInfo);
3169 osi_Log2(smb_logp, "Bad Tran2QPathInfo op 0x%x infolevel 0x%x",
3170 p->opcode, infoLevel);
3171 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3174 memset(&qpi, 0, sizeof(qpi));
3176 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3177 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path \"%S\"", infoLevel,
3178 osi_LogSaveClientString(smb_logp, pathp));
3180 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3182 if (infoLevel > 0x100)
3183 outp->totalParms = 2;
3185 outp->totalParms = 0;
3187 /* now, if we're at infoLevel 6, we're only being asked to check
3188 * the syntax, so we just OK things now. In particular, we're *not*
3189 * being asked to verify anything about the state of any parent dirs.
3191 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
3192 smb_SendTran2Packet(vcp, outp, opx);
3193 smb_FreeTran2Packet(outp);
3197 userp = smb_GetTran2User(vcp, p);
3199 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
3200 smb_FreeTran2Packet(outp);
3201 return CM_ERROR_BADSMB;
3204 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3206 osi_Log1(smb_logp, "ReceiveTran2QPathInfo tid path lookup failure 0x%x", code);
3207 cm_ReleaseUser(userp);
3208 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
3209 smb_FreeTran2Packet(outp);
3213 osi_Log1(smb_logp, "T2 QPathInfo tidPathp \"%S\"",
3214 osi_LogSaveClientString(smb_logp, tidPathp));
3217 * XXX Strange hack XXX
3219 * As of Patch 7 (13 January 98), we are having the following problem:
3220 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3221 * requests to look up "desktop.ini" in all the subdirectories.
3222 * This can cause zillions of timeouts looking up non-existent cells
3223 * and volumes, especially in the top-level directory.
3225 * We have not found any way to avoid this or work around it except
3226 * to explicitly ignore the requests for mount points that haven't
3227 * yet been evaluated and for directories that haven't yet been
3230 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3231 spacep = cm_GetSpace();
3232 /* smb_StripLastComponent will strip "::$DATA" if present */
3233 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3234 #ifndef SPECIAL_FOLDERS
3235 /* Make sure that lastComp is not NULL */
3237 if (cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
3238 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3242 userp, tidPathp, &req, &dscp);
3245 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3246 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3248 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3249 code = CM_ERROR_PATH_NOT_COVERED;
3251 code = CM_ERROR_NOSUCHPATH;
3253 #endif /* DFS_SUPPORT */
3254 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3255 code = CM_ERROR_NOSUCHFILE;
3256 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3257 cm_buf_t *bp = buf_Find(dscp, &hzero);
3263 code = CM_ERROR_NOSUCHFILE;
3265 cm_ReleaseSCache(dscp);
3267 cm_FreeSpace(spacep);
3268 cm_ReleaseUser(userp);
3269 smb_SendTran2Error(vcp, p, opx, code);
3270 smb_FreeTran2Packet(outp);
3276 #endif /* SPECIAL_FOLDERS */
3278 cm_FreeSpace(spacep);
3281 /* now do namei and stat, and copy out the info */
3282 code = cm_NameI(cm_data.rootSCachep, pathp,
3283 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3286 cm_ReleaseUser(userp);
3287 smb_SendTran2Error(vcp, p, opx, code);
3288 smb_FreeTran2Packet(outp);
3293 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3294 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3295 cm_ReleaseSCache(scp);
3296 cm_ReleaseUser(userp);
3297 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3298 code = CM_ERROR_PATH_NOT_COVERED;
3300 code = CM_ERROR_NOSUCHPATH;
3301 smb_SendTran2Error(vcp, p, opx, code);
3302 smb_FreeTran2Packet(outp);
3305 #endif /* DFS_SUPPORT */
3307 lock_ObtainWrite(&scp->rw);
3309 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3310 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3314 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3316 lock_ConvertWToR(&scp->rw);
3321 /* now we have the status in the cache entry, and everything is locked.
3322 * Marshall the output data.
3324 /* for info level 108, figure out short name */
3325 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3326 code = cm_GetShortName(pathp, userp, &req,
3327 tidPathp, scp->fid.vnode, shortName,
3333 smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
3334 qpi.u.QPfileAltNameInfo.fileNameLength = len;
3335 responseSize = sizeof(unsigned long) + len;
3337 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3338 smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3339 qpi.u.QPfileNameInfo.fileNameLength = len;
3340 responseSize = sizeof(unsigned long) + len;
3342 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3343 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3344 qpi.u.QPstandardInfo.creationDateTime = dosTime;
3345 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3346 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3347 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3348 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3349 attributes = smb_Attributes(scp);
3350 qpi.u.QPstandardInfo.attributes = attributes;
3351 qpi.u.QPstandardInfo.eaSize = 0;
3353 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3354 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3355 qpi.u.QPfileBasicInfo.creationTime = ft;
3356 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3357 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3358 qpi.u.QPfileBasicInfo.changeTime = ft;
3359 extAttributes = smb_ExtAttributes(scp);
3360 qpi.u.QPfileBasicInfo.attributes = extAttributes;
3361 qpi.u.QPfileBasicInfo.reserved = 0;
3363 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3366 lock_ReleaseRead(&scp->rw);
3368 fidp = smb_FindFIDByScache(vcp, scp);
3370 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3371 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3372 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3373 qpi.u.QPfileStandardInfo.directory =
3374 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3375 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3376 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3377 qpi.u.QPfileStandardInfo.reserved = 0;
3380 lock_ObtainMutex(&fidp->mx);
3381 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3382 lock_ReleaseMutex(&fidp->mx);
3383 smb_ReleaseFID(fidp);
3385 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3387 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3388 qpi.u.QPfileEaInfo.eaSize = 0;
3390 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3393 lock_ReleaseRead(&scp->rw);
3395 fidp = smb_FindFIDByScache(vcp, scp);
3397 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3398 qpi.u.QPfileAllInfo.creationTime = ft;
3399 qpi.u.QPfileAllInfo.lastAccessTime = ft;
3400 qpi.u.QPfileAllInfo.lastWriteTime = ft;
3401 qpi.u.QPfileAllInfo.changeTime = ft;
3402 extAttributes = smb_ExtAttributes(scp);
3403 qpi.u.QPfileAllInfo.attributes = extAttributes;
3404 qpi.u.QPfileAllInfo.allocationSize = scp->length;
3405 qpi.u.QPfileAllInfo.endOfFile = scp->length;
3406 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3407 qpi.u.QPfileAllInfo.deletePending = 0;
3408 qpi.u.QPfileAllInfo.directory =
3409 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3410 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3411 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3412 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.vnode;
3413 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.unique;
3414 qpi.u.QPfileAllInfo.eaSize = 0;
3415 qpi.u.QPfileAllInfo.accessFlags = 0;
3417 lock_ObtainMutex(&fidp->mx);
3418 if (fidp->flags & SMB_FID_OPENDELETE)
3419 qpi.u.QPfileAllInfo.accessFlags |= DELETE;
3420 if (fidp->flags & SMB_FID_OPENREAD_LISTDIR)
3421 qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_READ|AFS_ACCESS_EXECUTE;
3422 if (fidp->flags & SMB_FID_OPENWRITE)
3423 qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_WRITE;
3424 if (fidp->flags & SMB_FID_DELONCLOSE)
3425 qpi.u.QPfileAllInfo.deletePending = 1;
3426 lock_ReleaseMutex(&fidp->mx);
3427 smb_ReleaseFID(fidp);
3429 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.cell;
3430 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.volume;
3431 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3432 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3433 qpi.u.QPfileAllInfo.mode = 0;
3434 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3436 smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3437 qpi.u.QPfileAllInfo.fileNameLength = len;
3438 responseSize -= (sizeof(qpi.u.QPfileAllInfo.fileName) - len);
3440 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO) {
3442 /* For now we have no streams */
3443 qpi.u.QPfileStreamInfo.nextEntryOffset = 0;
3444 if (scp->fileType == CM_SCACHETYPE_FILE) {
3445 qpi.u.QPfileStreamInfo.streamSize = scp->length;
3446 qpi.u.QPfileStreamInfo.streamAllocationSize = scp->length;
3447 smb_UnparseString(opx, qpi.u.QPfileStreamInfo.fileName, L"::$DATA", &len, SMB_STRF_IGNORENUL);
3448 qpi.u.QPfileStreamInfo.streamNameLength = len;
3449 responseSize -= (sizeof(qpi.u.QPfileStreamInfo.fileName) - len);
3451 qpi.u.QPfileStreamInfo.streamSize.QuadPart = 0;
3452 qpi.u.QPfileStreamInfo.streamAllocationSize.QuadPart = 0;
3453 smb_UnparseString(opx, qpi.u.QPfileStreamInfo.fileName, L"", &len, SMB_STRF_IGNORENUL);
3454 qpi.u.QPfileStreamInfo.streamNameLength = 0;
3458 outp->totalData = responseSize;
3460 /* send and free the packets */
3462 switch (scp_rw_held) {
3464 lock_ReleaseRead(&scp->rw);
3467 lock_ReleaseWrite(&scp->rw);
3471 cm_ReleaseSCache(scp);
3472 cm_ReleaseUser(userp);
3474 memcpy(outp->datap, &qpi, responseSize);
3475 smb_SendTran2Packet(vcp, outp, opx);
3477 smb_SendTran2Error(vcp, p, opx, code);
3479 smb_FreeTran2Packet(outp);
3484 /* TRANS2_SET_PATH_INFORMATION */
3485 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3488 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
3489 return CM_ERROR_BADOP;
3492 unsigned short infoLevel;
3493 clientchar_t * pathp;
3494 smb_tran2Packet_t *outp;
3495 smb_tran2QPathInfo_t *spi;
3497 cm_scache_t *scp, *dscp;
3500 clientchar_t *tidPathp;
3501 clientchar_t *lastComp;
3505 infoLevel = p->parmsp[0];
3506 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
3507 if (infoLevel != SMB_INFO_STANDARD &&
3508 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
3509 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
3510 osi_Log2(smb_logp, "Bad Tran2SetPathInfo op 0x%x infolevel 0x%x",
3511 p->opcode, infoLevel);
3512 smb_SendTran2Error(vcp, p, opx,
3513 infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3517 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3519 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
3520 osi_LogSaveClientString(smb_logp, pathp));
3522 userp = smb_GetTran2User(vcp, p);
3524 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3525 code = CM_ERROR_BADSMB;
3529 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3530 if (code == CM_ERROR_TIDIPC) {
3531 /* Attempt to use a TID allocated for IPC. The client
3532 * is probably looking for DCE RPC end points which we
3533 * don't support OR it could be looking to make a DFS
3536 osi_Log0(smb_logp, "Tran2Open received IPC TID");
3537 cm_ReleaseUser(userp);
3538 return CM_ERROR_NOSUCHPATH;
3542 * XXX Strange hack XXX
3544 * As of Patch 7 (13 January 98), we are having the following problem:
3545 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3546 * requests to look up "desktop.ini" in all the subdirectories.
3547 * This can cause zillions of timeouts looking up non-existent cells
3548 * and volumes, especially in the top-level directory.
3550 * We have not found any way to avoid this or work around it except
3551 * to explicitly ignore the requests for mount points that haven't
3552 * yet been evaluated and for directories that haven't yet been
3555 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3556 spacep = cm_GetSpace();
3557 /* smb_StripLastComponent will strip "::$DATA" if present */
3558 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3559 #ifndef SPECIAL_FOLDERS
3560 /* Make sure that lastComp is not NULL */
3562 if (cm_ClientStrCmpI(lastComp, _C("\\desktop.ini")) == 0) {
3563 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3567 userp, tidPathp, &req, &dscp);
3570 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3571 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3573 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3574 code = CM_ERROR_PATH_NOT_COVERED;
3576 code = CM_ERROR_NOSUCHPATH;
3578 #endif /* DFS_SUPPORT */
3579 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3580 code = CM_ERROR_NOSUCHFILE;
3581 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3582 cm_buf_t *bp = buf_Find(dscp, &hzero);
3588 code = CM_ERROR_NOSUCHFILE;
3590 cm_ReleaseSCache(dscp);
3592 cm_FreeSpace(spacep);
3593 cm_ReleaseUser(userp);
3594 smb_SendTran2Error(vcp, p, opx, code);
3600 #endif /* SPECIAL_FOLDERS */
3602 cm_FreeSpace(spacep);
3605 /* now do namei and stat, and copy out the info */
3606 code = cm_NameI(cm_data.rootSCachep, pathp,
3607 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3609 cm_ReleaseUser(userp);
3610 smb_SendTran2Error(vcp, p, opx, code);
3614 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3616 outp->totalParms = 2;
3617 outp->totalData = 0;
3619 spi = (smb_tran2QPathInfo_t *)p->datap;
3620 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3623 /* lock the vnode with a callback; we need the current status
3624 * to determine what the new status is, in some cases.
3626 lock_ObtainWrite(&scp->rw);
3627 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3628 CM_SCACHESYNC_GETSTATUS
3629 | CM_SCACHESYNC_NEEDCALLBACK);
3631 lock_ReleaseWrite(&scp->rw);
3634 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3636 /* prepare for setattr call */
3637 attr.mask = CM_ATTRMASK_LENGTH;
3638 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3639 attr.length.HighPart = 0;
3641 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3642 cm_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3643 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3646 if (spi->u.QPstandardInfo.attributes != 0) {
3647 if ((scp->unixModeBits & 0222)
3648 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3649 /* make a writable file read-only */
3650 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3651 attr.unixModeBits = scp->unixModeBits & ~0222;
3653 else if ((scp->unixModeBits & 0222) == 0
3654 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3655 /* make a read-only file writable */
3656 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3657 attr.unixModeBits = scp->unixModeBits | 0222;
3660 lock_ReleaseRead(&scp->rw);
3664 code = cm_SetAttr(scp, &attr, userp, &req);
3668 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3669 /* we don't support EAs */
3670 code = CM_ERROR_EAS_NOT_SUPPORTED;
3674 cm_ReleaseSCache(scp);
3675 cm_ReleaseUser(userp);
3677 smb_SendTran2Packet(vcp, outp, opx);
3679 smb_SendTran2Error(vcp, p, opx, code);
3680 smb_FreeTran2Packet(outp);
3686 /* TRANS2_QUERY_FILE_INFORMATION */
3687 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3689 smb_tran2Packet_t *outp;
3691 unsigned long attributes;
3692 unsigned short infoLevel;
3699 smb_tran2QFileInfo_t qfi;
3707 fidp = smb_FindFID(vcp, fid, 0);
3710 osi_Log2(smb_logp, "Tran2QFileInfo Unknown SMB Fid vcp 0x%p fid %d",
3712 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3716 lock_ObtainMutex(&fidp->mx);
3717 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3718 lock_ReleaseMutex(&fidp->mx);
3719 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3720 smb_CloseFID(vcp, fidp, NULL, 0);
3721 smb_ReleaseFID(fidp);
3724 lock_ReleaseMutex(&fidp->mx);
3726 infoLevel = p->parmsp[1];
3727 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3728 responseSize = sizeof(qfi.u.QFbasicInfo);
3729 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3730 responseSize = sizeof(qfi.u.QFstandardInfo);
3731 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3732 responseSize = sizeof(qfi.u.QFeaInfo);
3733 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3734 responseSize = sizeof(qfi.u.QFfileNameInfo);
3735 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO)
3736 responseSize = sizeof(qfi.u.QFfileStreamInfo);
3738 osi_Log2(smb_logp, "Bad Tran2QFileInfo op 0x%x infolevel 0x%x",
3739 p->opcode, infoLevel);
3740 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3741 smb_ReleaseFID(fidp);
3744 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3745 memset(&qfi, 0, sizeof(qfi));
3747 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3749 if (infoLevel > 0x100)
3750 outp->totalParms = 2;
3752 outp->totalParms = 0;
3754 userp = smb_GetTran2User(vcp, p);
3756 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3757 code = CM_ERROR_BADSMB;
3761 lock_ObtainMutex(&fidp->mx);
3762 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3764 osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3766 lock_ReleaseMutex(&fidp->mx);
3767 lock_ObtainWrite(&scp->rw);
3768 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3769 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3773 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3775 lock_ConvertWToR(&scp->rw);
3778 /* now we have the status in the cache entry, and everything is locked.
3779 * Marshall the output data.
3781 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3782 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3783 qfi.u.QFbasicInfo.creationTime = ft;
3784 qfi.u.QFbasicInfo.lastAccessTime = ft;
3785 qfi.u.QFbasicInfo.lastWriteTime = ft;
3786 qfi.u.QFbasicInfo.lastChangeTime = ft;
3787 attributes = smb_ExtAttributes(scp);
3788 qfi.u.QFbasicInfo.attributes = attributes;
3790 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3791 qfi.u.QFstandardInfo.allocationSize = scp->length;
3792 qfi.u.QFstandardInfo.endOfFile = scp->length;
3793 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3794 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3795 qfi.u.QFstandardInfo.directory =
3796 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3797 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3798 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3800 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3801 qfi.u.QFeaInfo.eaSize = 0;
3803 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3807 lock_ReleaseRead(&scp->rw);
3808 lock_ObtainMutex(&fidp->mx);
3809 lock_ObtainRead(&scp->rw);
3810 if (fidp->NTopen_wholepathp)
3811 name = fidp->NTopen_wholepathp;
3813 name = _C("\\"); /* probably can't happen */
3814 lock_ReleaseMutex(&fidp->mx);
3816 smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, SMB_STRF_IGNORENUL);
3817 responseSize = len + 4; /* this is actually what we want to return */
3818 qfi.u.QFfileNameInfo.fileNameLength = len;
3820 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO) {
3823 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3824 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3825 scp->fileType == CM_SCACHETYPE_INVALID) {
3826 /* Do not return the alternate streams for directories */
3829 /* For now we have no alternate streams */
3830 qfi.u.QFfileStreamInfo.nextEntryOffset = 0;
3831 qfi.u.QFfileStreamInfo.streamSize = scp->length;
3832 qfi.u.QFfileStreamInfo.streamAllocationSize = scp->length;
3833 smb_UnparseString(opx, qfi.u.QFfileStreamInfo.fileName, L"::$DATA", &len, SMB_STRF_IGNORENUL);
3834 qfi.u.QFfileStreamInfo.streamNameLength = len;
3835 responseSize -= (sizeof(qfi.u.QFfileStreamInfo.fileName) - len);
3838 outp->totalData = responseSize;
3840 /* send and free the packets */
3843 lock_ReleaseRead(&scp->rw);
3845 lock_ReleaseWrite(&scp->rw);
3846 cm_ReleaseSCache(scp);
3847 cm_ReleaseUser(userp);
3848 smb_ReleaseFID(fidp);
3850 memcpy(outp->datap, &qfi, responseSize);
3851 smb_SendTran2Packet(vcp, outp, opx);
3853 smb_SendTran2Error(vcp, p, opx, code);
3855 smb_FreeTran2Packet(outp);
3861 /* TRANS2_SET_FILE_INFORMATION */
3862 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3867 unsigned short infoLevel;
3868 smb_tran2Packet_t *outp;
3869 cm_user_t *userp = NULL;
3870 cm_scache_t *scp = NULL;
3876 fidp = smb_FindFID(vcp, fid, 0);
3879 osi_Log2(smb_logp, "Tran2SetFileInfo Unknown SMB Fid vcp 0x%p fid %d",
3881 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3885 infoLevel = p->parmsp[1];
3886 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3887 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3888 osi_Log2(smb_logp, "Bad Tran2SetFileInfo op 0x%x infolevel 0x%x",
3889 p->opcode, infoLevel);
3890 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3891 smb_ReleaseFID(fidp);
3895 lock_ObtainMutex(&fidp->mx);
3896 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3897 lock_ReleaseMutex(&fidp->mx);
3898 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3899 smb_CloseFID(vcp, fidp, NULL, 0);
3900 smb_ReleaseFID(fidp);
3904 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
3905 !(fidp->flags & SMB_FID_OPENDELETE)) {
3906 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3907 fidp, fidp->scp, fidp->flags);
3908 lock_ReleaseMutex(&fidp->mx);
3909 smb_ReleaseFID(fidp);
3910 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3913 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3914 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3915 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3916 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3917 fidp, fidp->scp, fidp->flags);
3918 lock_ReleaseMutex(&fidp->mx);
3919 smb_ReleaseFID(fidp);
3920 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3925 osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3927 lock_ReleaseMutex(&fidp->mx);
3929 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3931 outp->totalParms = 2;
3932 outp->totalData = 0;
3934 userp = smb_GetTran2User(vcp, p);
3936 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3937 code = CM_ERROR_BADSMB;
3941 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3943 unsigned int attribute;
3945 smb_tran2QFileInfo_t *sfi;
3947 sfi = (smb_tran2QFileInfo_t *)p->datap;
3949 /* lock the vnode with a callback; we need the current status
3950 * to determine what the new status is, in some cases.
3952 lock_ObtainWrite(&scp->rw);
3953 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3954 CM_SCACHESYNC_GETSTATUS
3955 | CM_SCACHESYNC_NEEDCALLBACK);
3957 lock_ReleaseWrite(&scp->rw);
3961 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3963 lock_ReleaseWrite(&scp->rw);
3964 lock_ObtainMutex(&fidp->mx);
3965 lock_ObtainRead(&scp->rw);
3967 /* prepare for setattr call */
3970 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3971 /* when called as result of move a b, lastMod is (-1, -1).
3972 * If the check for -1 is not present, timestamp
3973 * of the resulting file will be 1969 (-1)
3975 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3976 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3977 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3978 cm_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3979 fidp->flags |= SMB_FID_MTIMESETDONE;
3982 attribute = sfi->u.QFbasicInfo.attributes;
3983 if (attribute != 0) {
3984 if ((scp->unixModeBits & 0222)
3985 && (attribute & SMB_ATTR_READONLY) != 0) {
3986 /* make a writable file read-only */
3987 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3988 attr.unixModeBits = scp->unixModeBits & ~0222;
3990 else if ((scp->unixModeBits & 0222) == 0
3991 && (attribute & SMB_ATTR_READONLY) == 0) {
3992 /* make a read-only file writable */
3993 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3994 attr.unixModeBits = scp->unixModeBits | 0222;
3997 lock_ReleaseRead(&scp->rw);
3998 lock_ReleaseMutex(&fidp->mx);
4002 code = cm_SetAttr(scp, &attr, userp, &req);
4006 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
4007 int delflag = *((char *)(p->datap));
4008 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
4009 delflag, fidp, scp);
4010 if (*((char *)(p->datap))) { /* File is Deleted */
4011 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
4014 lock_ObtainMutex(&fidp->mx);
4015 fidp->flags |= SMB_FID_DELONCLOSE;
4016 lock_ReleaseMutex(&fidp->mx);
4018 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
4024 lock_ObtainMutex(&fidp->mx);
4025 fidp->flags &= ~SMB_FID_DELONCLOSE;
4026 lock_ReleaseMutex(&fidp->mx);
4029 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
4030 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
4031 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
4034 attr.mask = CM_ATTRMASK_LENGTH;
4035 attr.length.LowPart = size.LowPart;
4036 attr.length.HighPart = size.HighPart;
4037 code = cm_SetAttr(scp, &attr, userp, &req);
4041 cm_ReleaseSCache(scp);
4042 cm_ReleaseUser(userp);
4043 smb_ReleaseFID(fidp);
4045 smb_SendTran2Packet(vcp, outp, opx);
4047 smb_SendTran2Error(vcp, p, opx, code);
4048 smb_FreeTran2Packet(outp);
4055 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4057 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
4058 return CM_ERROR_BADOP;
4063 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4065 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
4066 return CM_ERROR_BADOP;
4069 /* TRANS2_FIND_NOTIFY_FIRST */
4071 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4073 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
4074 return CM_ERROR_BADOP;
4077 /* TRANS2_FIND_NOTIFY_NEXT */
4079 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4081 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
4082 return CM_ERROR_BADOP;
4085 /* TRANS2_CREATE_DIRECTORY */
4087 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4089 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
4090 return CM_ERROR_BADOP;
4093 /* TRANS2_SESSION_SETUP */
4095 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4097 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
4098 return CM_ERROR_BADOP;
4101 struct smb_v2_referral {
4103 USHORT ReferralFlags;
4106 USHORT DfsPathOffset;
4107 USHORT DfsAlternativePathOffset;
4108 USHORT NetworkAddressOffset;
4111 /* TRANS2_GET_DFS_REFERRAL */
4113 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
4115 /* This is a UNICODE only request (bit15 of Flags2) */
4116 /* The TID must be IPC$ */
4118 /* The documentation for the Flags response field is contradictory */
4120 /* Use Version 1 Referral Element Format */
4121 /* ServerType = 0; indicates the next server should be queried for the file */
4122 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
4123 /* Node = UnicodeString of UNC path of the next share name */
4126 int maxReferralLevel = 0;
4127 clientchar_t requestFileName[1024] = _C("");
4128 clientchar_t referralPath[1024] = _C("");
4129 smb_tran2Packet_t *outp = 0;
4130 cm_user_t *userp = 0;
4131 cm_scache_t *scp = 0;
4132 cm_scache_t *dscp = 0;
4134 CPINFO CodePageInfo;
4135 int i, nbnLen, reqLen, refLen;
4140 maxReferralLevel = p->parmsp[0];
4142 GetCPInfo(CP_ACP, &CodePageInfo);
4143 cm_Utf16ToClientString(&p->parmsp[1], -1, requestFileName, lengthof(requestFileName));
4145 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%S]",
4146 maxReferralLevel, osi_LogSaveClientString(smb_logp, requestFileName));
4148 nbnLen = (int)cm_ClientStrLen(cm_NetbiosNameC);
4149 reqLen = (int)cm_ClientStrLen(requestFileName);
4151 if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
4152 !cm_ClientStrCmpNI(cm_NetbiosNameC, &requestFileName[1], nbnLen) &&
4153 requestFileName[nbnLen+1] == '\\')
4157 if (!cm_ClientStrCmpNI(_C("all"), &requestFileName[nbnLen+2], 3) ||
4158 !cm_ClientStrCmpNI(_C("*."), &requestFileName[nbnLen+2], 2)) {
4160 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4163 userp = smb_GetTran2User(vcp, p);
4165 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
4166 code = CM_ERROR_BADSMB;
4171 * We have a requested path. Check to see if it is something
4174 * But be careful because the name that we might be searching
4175 * for might be a known name with the final character stripped
4178 code = cm_NameI(cm_data.rootSCachep, &requestFileName[nbnLen+2],
4179 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
4180 userp, NULL, &req, &scp);
4182 code == CM_ERROR_ALLDOWN ||
4183 code == CM_ERROR_ALLBUSY ||
4184 code == CM_ERROR_ALLOFFLINE ||
4185 code == CM_ERROR_NOSUCHCELL ||
4186 code == CM_ERROR_NOSUCHVOLUME ||
4187 code == CM_ERROR_NOACCESS) {
4190 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4192 } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
4193 clientchar_t temp[1024];
4194 clientchar_t pathName[1024];
4195 clientchar_t *lastComponent;
4197 * we have a msdfs link somewhere in the path
4198 * we should figure out where in the path the link is.
4201 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%S]", requestFileName);
4203 cm_ClientStrCpy(temp, lengthof(temp), &requestFileName[nbnLen+2]);
4207 cm_ReleaseSCache(dscp);
4211 cm_ReleaseSCache(scp);
4214 /* smb_StripLastComponent will strip "::$DATA" if present */
4215 smb_StripLastComponent(pathName, &lastComponent, temp);
4217 code = cm_NameI(cm_data.rootSCachep, pathName,
4218 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4219 userp, NULL, &req, &dscp);
4221 code = cm_NameI(dscp, ++lastComponent,
4223 userp, NULL, &req, &scp);
4224 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK)
4227 } while (code == CM_ERROR_PATH_NOT_COVERED);
4229 /* scp should now be the DfsLink we are looking for */
4231 /* figure out how much of the input path was used */
4232 reqLen = (int)(nbnLen+2 + cm_ClientStrLen(pathName) + 1 + cm_ClientStrLen(lastComponent));
4234 cm_FsStringToClientString(&scp->mountPointStringp[strlen("msdfs:")], -1,
4235 referralPath, lengthof(referralPath));
4236 refLen = (int)cm_ClientStrLen(referralPath);
4240 clientchar_t shareName[MAX_PATH + 1];
4241 clientchar_t *p, *q;
4242 /* we may have a sharename that is a volume reference */
4244 for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
4250 if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
4251 code = cm_NameI(cm_data.rootSCachep, _C(""),
4252 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
4253 userp, p, &req, &scp);
4258 cm_ClientStrCpy(referralPath, lengthof(referralPath),
4269 struct smb_v2_referral * v2ref;
4270 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (refLen + 8));
4272 sp = (USHORT *)outp->datap;
4274 sp[idx++] = reqLen; /* path consumed */
4275 sp[idx++] = 1; /* number of referrals */
4276 sp[idx++] = 0x03; /* flags */
4277 #ifdef DFS_VERSION_1
4278 sp[idx++] = 1; /* Version Number */
4279 sp[idx++] = refLen + 4; /* Referral Size */
4280 sp[idx++] = 1; /* Type = SMB Server */
4281 sp[idx++] = 0; /* Do not strip path consumed */
4282 for ( i=0;i<=refLen; i++ )
4283 sp[i+idx] = referralPath[i];
4284 #else /* DFS_VERSION_2 */
4285 sp[idx++] = 2; /* Version Number */
4286 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
4287 idx += (sizeof(struct smb_v2_referral) / 2);
4288 v2ref = (struct smb_v2_referral *) &sp[5];
4289 v2ref->ServerType = 1; /* SMB Server */
4290 v2ref->ReferralFlags = 0x03;
4291 v2ref->Proximity = 0; /* closest */
4292 v2ref->TimeToLive = 3600; /* seconds */
4293 v2ref->DfsPathOffset = idx * 2;
4294 v2ref->DfsAlternativePathOffset = idx * 2;
4295 v2ref->NetworkAddressOffset = 0;
4296 for ( i=0;i<=refLen; i++ )
4297 sp[i+idx] = referralPath[i];
4300 code = CM_ERROR_NOSUCHPATH;
4303 code = CM_ERROR_NOSUCHPATH;
4308 cm_ReleaseSCache(dscp);
4310 cm_ReleaseSCache(scp);
4312 cm_ReleaseUser(userp);
4314 smb_SendTran2Packet(vcp, outp, op);
4316 smb_SendTran2Error(vcp, p, op, code);
4318 smb_FreeTran2Packet(outp);
4321 #else /* DFS_SUPPORT */
4322 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
4323 return CM_ERROR_NOSUCHDEVICE;
4324 #endif /* DFS_SUPPORT */
4327 /* TRANS2_REPORT_DFS_INCONSISTENCY */
4329 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4331 /* This is a UNICODE only request (bit15 of Flags2) */
4333 /* There is nothing we can do about this operation. The client is going to
4334 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
4335 * Unfortunately, there is really nothing we can do about it other then log it
4336 * somewhere. Even then I don't think there is anything for us to do.
4337 * So let's return an error value.
4340 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
4341 return CM_ERROR_BADOP;
4345 smb_ApplyV3DirListPatches(cm_scache_t *dscp, smb_dirListPatch_t **dirPatchespp,
4346 clientchar_t * tidPathp, clientchar_t * relPathp,
4347 int infoLevel, cm_user_t *userp, cm_req_t *reqp)
4351 cm_scache_t *targetScp; /* target if scp is a symlink */
4354 unsigned short attr;
4355 unsigned long lattr;
4356 smb_dirListPatch_t *patchp;
4357 smb_dirListPatch_t *npatchp;
4359 afs_int32 mustFake = 0;
4360 clientchar_t path[AFSPATHMAX];
4362 code = cm_FindACLCache(dscp, userp, &rights);
4364 lock_ObtainWrite(&dscp->rw);
4365 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4366 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4368 cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4369 lock_ReleaseWrite(&dscp->rw);
4370 if (code == CM_ERROR_NOACCESS) {
4378 if (!mustFake) { /* Bulk Stat */
4380 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4382 memset(bsp, 0, sizeof(cm_bulkStat_t));
4384 for (patchp = *dirPatchespp, count=0;
4386 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4387 cm_scache_t *tscp = NULL;
4390 code = cm_GetSCache(&patchp->fid, &tscp, userp, reqp);
4392 if (lock_TryWrite(&tscp->rw)) {
4393 /* we have an entry that we can look at */
4394 #ifdef AFS_FREELANCE_CLIENT
4395 if (dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID && dscp->fid.volume == AFS_FAKE_ROOT_VOL_ID) {
4396 code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
4397 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4399 cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4401 lock_ReleaseWrite(&tscp->rw);
4402 cm_ReleaseSCache(tscp);
4405 #endif /* AFS_FREELANCE_CLIENT */
4406 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4407 /* we have a callback on it. Don't bother
4408 * fetching this stat entry, since we're happy
4409 * with the info we have.
4411 lock_ReleaseWrite(&tscp->rw);
4412 cm_ReleaseSCache(tscp);
4415 lock_ReleaseWrite(&tscp->rw);
4417 cm_ReleaseSCache(tscp);
4421 bsp->fids[i].Volume = patchp->fid.volume;
4422 bsp->fids[i].Vnode = patchp->fid.vnode;
4423 bsp->fids[i].Unique = patchp->fid.unique;
4425 if (bsp->counter == AFSCBMAX) {
4426 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4427 memset(bsp, 0, sizeof(cm_bulkStat_t));
4431 if (bsp->counter > 0)
4432 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4437 for( patchp = *dirPatchespp;
4439 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4440 cm_ClientStrPrintfN(path, lengthof(path),_C("%s\\%S"),
4441 relPathp ? relPathp : _C(""), patchp->dep->name);
4442 reqp->relPathp = path;
4443 reqp->tidPathp = tidPathp;
4445 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4446 reqp->relPathp = reqp->tidPathp = NULL;
4450 lock_ObtainWrite(&scp->rw);
4451 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4452 lock_ReleaseWrite(&scp->rw);
4454 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4455 errors in the client. */
4456 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4457 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4459 /* 1969-12-31 23:59:59 +00 */
4460 ft.dwHighDateTime = 0x19DB200;
4461 ft.dwLowDateTime = 0x5BB78980;
4463 /* copy to Creation Time */
4464 fa->creationTime = ft;
4465 fa->lastAccessTime = ft;
4466 fa->lastWriteTime = ft;
4467 fa->lastChangeTime = ft;
4469 switch (scp->fileType) {
4470 case CM_SCACHETYPE_DIRECTORY:
4471 case CM_SCACHETYPE_MOUNTPOINT:
4472 case CM_SCACHETYPE_INVALID:
4473 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4475 case CM_SCACHETYPE_SYMLINK:
4476 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4477 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4479 fa->extFileAttributes = SMB_ATTR_NORMAL;
4482 /* if we get here we either have a normal file
4483 * or we have a file for which we have never
4484 * received status info. In this case, we can
4485 * check the even/odd value of the entry's vnode.
4486 * odd means it is to be treated as a directory
4487 * and even means it is to be treated as a file.
4489 if (mustFake && (scp->fid.vnode & 0x1))
4490 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4492 fa->extFileAttributes = SMB_ATTR_NORMAL;
4494 /* merge in hidden attribute */
4495 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4496 fa->extFileAttributes |= SMB_ATTR_HIDDEN;
4499 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4501 /* 1969-12-31 23:59:58 +00*/
4502 dosTime = 0xEBBFBF7D;
4504 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4505 fa->lastAccessDateTime = fa->creationDateTime;
4506 fa->lastWriteDateTime = fa->creationDateTime;
4508 /* set the attribute */
4509 switch (scp->fileType) {
4510 case CM_SCACHETYPE_DIRECTORY:
4511 case CM_SCACHETYPE_MOUNTPOINT:
4512 case CM_SCACHETYPE_INVALID:
4513 fa->attributes = SMB_ATTR_DIRECTORY;
4515 case CM_SCACHETYPE_SYMLINK:
4516 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4517 fa->attributes = SMB_ATTR_DIRECTORY;
4519 fa->attributes = SMB_ATTR_NORMAL;
4522 /* if we get here we either have a normal file
4523 * or we have a file for which we have never
4524 * received status info. In this case, we can
4525 * check the even/odd value of the entry's vnode.
4526 * even means it is to be treated as a directory
4527 * and odd means it is to be treated as a file.
4529 if (mustFake && (scp->fid.vnode & 0x1))
4530 fa->attributes = SMB_ATTR_DIRECTORY;
4532 fa->attributes = SMB_ATTR_NORMAL;
4535 /* merge in hidden (dot file) attribute */
4536 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4537 fa->attributes |= SMB_ATTR_HIDDEN;
4541 cm_ReleaseSCache(scp);
4545 /* now watch for a symlink */
4547 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
4548 lock_ReleaseWrite(&scp->rw);
4549 cm_ClientStrPrintfN(path, lengthof(path), _C("%s\\%S"),
4550 relPathp ? relPathp : _C(""), patchp->dep->name);
4551 reqp->relPathp = path;
4552 reqp->tidPathp = tidPathp;
4553 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
4554 reqp->relPathp = reqp->tidPathp = NULL;
4556 /* we have a more accurate file to use (the
4557 * target of the symbolic link). Otherwise,
4558 * we'll just use the symlink anyway.
4560 osi_Log2(smb_logp, "symlink vp %x to vp %x",
4562 cm_ReleaseSCache(scp);
4565 lock_ObtainWrite(&scp->rw);
4568 lock_ConvertWToR(&scp->rw);
4570 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4571 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4574 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4576 fa->creationTime = ft;
4577 fa->lastAccessTime = ft;
4578 fa->lastWriteTime = ft;
4579 fa->lastChangeTime = ft;
4581 /* Use length for both file length and alloc length */
4582 fa->endOfFile = scp->length;
4583 fa->allocationSize = scp->length;
4585 /* Copy attributes */
4586 lattr = smb_ExtAttributes(scp);
4587 if ((code == CM_ERROR_NOSUCHPATH &&
4588 (scp->fileType == CM_SCACHETYPE_SYMLINK &&
4589 cm_TargetPerceivedAsDirectory(scp->mountPointStringp))) ||
4590 code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4591 if (lattr == SMB_ATTR_NORMAL)
4592 lattr = SMB_ATTR_DIRECTORY;
4594 lattr |= SMB_ATTR_DIRECTORY;
4596 /* merge in hidden (dot file) attribute */
4597 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4598 if (lattr == SMB_ATTR_NORMAL)
4599 lattr = SMB_ATTR_HIDDEN;
4601 lattr |= SMB_ATTR_HIDDEN;
4604 fa->extFileAttributes = lattr;
4606 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4609 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4611 fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
4612 fa->lastAccessDateTime = fa->creationDateTime;
4613 fa->lastWriteDateTime = fa->creationDateTime;
4615 /* copy out file length and alloc length,
4616 * using the same for both
4618 fa->dataSize = scp->length.LowPart;
4619 fa->allocationSize = scp->length.LowPart;
4621 /* finally copy out attributes as short */
4622 attr = smb_Attributes(scp);
4623 /* merge in hidden (dot file) attribute */
4624 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4625 if (lattr == SMB_ATTR_NORMAL)
4626 lattr = SMB_ATTR_HIDDEN;
4628 lattr |= SMB_ATTR_HIDDEN;
4630 fa->attributes = attr;
4633 lock_ReleaseRead(&scp->rw);
4634 cm_ReleaseSCache(scp);
4637 /* now free the patches */
4638 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4639 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4643 /* and mark the list as empty */
4644 *dirPatchespp = NULL;
4650 /* smb_ReceiveTran2SearchDir implements both
4651 * Tran2_Find_First and Tran2_Find_Next
4653 #define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
4654 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
4655 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
4656 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
4657 #define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
4659 /* this is an optimized handler for T2SearchDir that handles the case
4660 where there are no wildcards in the search path. I.e. an
4661 application is using FindFirst(Ex) to get information about a
4662 single file or directory. It will attempt to do a single lookup.
4663 If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4664 the usual mechanism.
4666 This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4668 TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
4670 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4674 long code = 0, code2 = 0;
4675 clientchar_t *pathp = 0;
4677 smb_dirListPatch_t *dirListPatchesp;
4678 smb_dirListPatch_t *curPatchp;
4679 size_t orbytes; /* # of bytes in this output record */
4680 size_t ohbytes; /* # of bytes, except file name */
4681 size_t onbytes; /* # of bytes in name, incl. term. null */
4682 cm_scache_t *scp = NULL;
4683 cm_scache_t *targetscp = NULL;
4684 cm_user_t *userp = NULL;
4685 char *op; /* output data ptr */
4686 char *origOp; /* original value of op */
4687 cm_space_t *spacep; /* for pathname buffer */
4688 unsigned long maxReturnData; /* max # of return data */
4689 long maxReturnParms; /* max # of return parms */
4690 long bytesInBuffer; /* # data bytes in the output buffer */
4691 clientchar_t *maskp; /* mask part of path */
4695 smb_tran2Packet_t *outp; /* response packet */
4696 clientchar_t *tidPathp = 0;
4698 clientchar_t shortName[13]; /* 8.3 name if needed */
4700 clientchar_t *shortNameEnd;
4701 cm_dirEntry_t * dep = NULL;
4704 void * attrp = NULL;
4705 smb_tran2Find_t * fp;
4710 osi_assertx(p->opcode == 1, "invalid opcode");
4712 /* find first; obtain basic parameters from request */
4714 /* note that since we are going to failover to regular
4715 * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4716 * modify any of the input parameters here. */
4717 attribute = p->parmsp[0];
4718 maxCount = p->parmsp[1];
4719 infoLevel = p->parmsp[3];
4720 searchFlags = p->parmsp[2];
4721 pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4723 maskp = cm_ClientStrRChr(pathp, '\\');
4727 maskp++; /* skip over backslash */
4728 /* track if this is likely to match a lot of entries */
4730 osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%S], mask[%S]",
4731 osi_LogSaveClientString(smb_logp, pathp),
4732 osi_LogSaveClientString(smb_logp, maskp));
4734 switch ( infoLevel ) {
4735 case SMB_INFO_STANDARD:
4737 ohbytes = sizeof(fp->u.FstandardInfo);
4740 case SMB_INFO_QUERY_EA_SIZE:
4741 ohbytes = sizeof(fp->u.FeaSizeInfo);
4742 s = "InfoQueryEaSize";
4745 case SMB_INFO_QUERY_EAS_FROM_LIST:
4746 ohbytes = sizeof(fp->u.FeasFromListInfo);
4747 s = "InfoQueryEasFromList";
4750 case SMB_FIND_FILE_DIRECTORY_INFO:
4751 s = "FindFileDirectoryInfo";
4752 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4755 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4756 s = "FindFileFullDirectoryInfo";
4757 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4760 case SMB_FIND_FILE_NAMES_INFO:
4761 s = "FindFileNamesInfo";
4762 ohbytes = sizeof(fp->u.FfileNamesInfo);
4765 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4766 s = "FindFileBothDirectoryInfo";
4767 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4771 s = "unknownInfoLevel";
4775 osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
4778 "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4779 attribute, infoLevel, maxCount, searchFlags);
4782 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4783 return CM_ERROR_INVAL;
4786 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4787 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4789 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4792 dirListPatchesp = NULL;
4794 maxReturnData = p->maxReturnData;
4795 maxReturnParms = 10; /* return params for findfirst, which
4796 is the only one we handle.*/
4798 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4801 osi_Log2(smb_logp, "T2SDSingle search dir count %d [%S]",
4802 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4804 /* bail out if request looks bad */
4806 smb_FreeTran2Packet(outp);
4807 return CM_ERROR_BADSMB;
4810 userp = smb_GetTran2User(vcp, p);
4812 osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
4813 smb_FreeTran2Packet(outp);
4814 return CM_ERROR_BADSMB;
4817 /* try to get the vnode for the path name next */
4818 spacep = cm_GetSpace();
4819 /* smb_StripLastComponent will strip "::$DATA" if present */
4820 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4821 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4823 cm_ReleaseUser(userp);
4824 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4825 smb_FreeTran2Packet(outp);
4829 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4830 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4831 userp, tidPathp, &req, &scp);
4832 cm_FreeSpace(spacep);
4835 cm_ReleaseUser(userp);
4836 smb_SendTran2Error(vcp, p, opx, code);
4837 smb_FreeTran2Packet(outp);
4841 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4842 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4843 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
4844 cm_ReleaseSCache(scp);
4845 cm_ReleaseUser(userp);
4846 if ( WANTS_DFS_PATHNAMES(p) || pnc )
4847 code = CM_ERROR_PATH_NOT_COVERED;
4849 code = CM_ERROR_NOSUCHPATH;
4850 smb_SendTran2Error(vcp, p, opx, code);
4851 smb_FreeTran2Packet(outp);
4854 #endif /* DFS_SUPPORT */
4855 osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
4857 /* now do a single case sensitive lookup for the file in question */
4858 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
4860 /* if a case sensitive match failed, we try a case insensitive one
4862 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
4863 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
4866 if (code == 0 && targetscp->fid.vnode == 0) {
4867 cm_ReleaseSCache(targetscp);
4868 code = CM_ERROR_NOSUCHFILE;
4872 /* if we can't find the directory entry, this block will
4873 return CM_ERROR_NOSUCHFILE, which we will pass on to
4874 smb_ReceiveTran2SearchDir(). */
4875 cm_ReleaseSCache(scp);
4876 cm_ReleaseUser(userp);
4877 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4878 smb_SendTran2Error(vcp, p, opx, code);
4881 smb_FreeTran2Packet(outp);
4885 /* now that we have the target in sight, we proceed with filling
4886 up the return data. */
4888 op = origOp = outp->datap;
4891 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4892 /* skip over resume key */
4896 fp = (smb_tran2Find_t *) op;
4898 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4899 && targetscp->fid.vnode != 0
4900 && !cm_Is8Dot3(maskp)) {
4903 dfid.vnode = htonl(targetscp->fid.vnode);
4904 dfid.unique = htonl(targetscp->fid.unique);
4906 cm_Gen8Dot3NameIntW(maskp, &dfid, shortName, &shortNameEnd);
4912 osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %S (%S)",
4913 htonl(targetscp->fid.vnode),
4914 htonl(targetscp->fid.unique),
4915 osi_LogSaveClientString(smb_logp, pathp),
4916 (NeedShortName)? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
4918 /* Eliminate entries that don't match requested attributes */
4919 if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
4920 smb_IsDotFile(maskp)) {
4922 code = CM_ERROR_NOSUCHFILE;
4923 osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
4928 if (!(attribute & SMB_ATTR_DIRECTORY) &&
4929 (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
4930 targetscp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4931 targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
4932 targetscp->fileType == CM_SCACHETYPE_INVALID)) {
4934 code = CM_ERROR_NOSUCHFILE;
4935 osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
4940 /* add header to name & term. null */
4942 smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
4943 orbytes = ohbytes + onbytes;
4945 /* now, we round up the record to a 4 byte alignment, and we make
4946 * sure that we have enough room here for even the aligned version
4947 * (so we don't have to worry about an * overflow when we pad
4948 * things out below). That's the reason for the alignment
4951 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4952 align = (4 - (orbytes & 3)) & 3;
4956 if (orbytes + align > maxReturnData) {
4958 /* even though this request is unlikely to succeed with a
4959 failover, we do it anyway. */
4960 code = CM_ERROR_NOSUCHFILE;
4961 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4966 /* this is one of the entries to use: it is not deleted and it
4967 * matches the star pattern we're looking for. Put out the name,
4968 * preceded by its length.
4970 /* First zero everything else */
4971 memset(origOp, 0, orbytes);
4974 smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
4976 switch (infoLevel) {
4977 case SMB_INFO_STANDARD:
4978 fp->u.FstandardInfo.fileNameLength = onbytes;
4979 attrp = &fp->u.FstandardInfo.fileAttrs;
4982 case SMB_INFO_QUERY_EA_SIZE:
4983 fp->u.FeaSizeInfo.fileNameLength = onbytes;
4984 attrp = &fp->u.FeaSizeInfo.fileAttrs;
4985 fp->u.FeaSizeInfo.eaSize = 0;
4988 case SMB_INFO_QUERY_EAS_FROM_LIST:
4989 fp->u.FeasFromListInfo.fileNameLength = onbytes;
4990 attrp = &fp->u.FeasFromListInfo.fileAttrs;
4991 fp->u.FeasFromListInfo.eaSize = 0;
4994 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4995 if (NeedShortName) {
4999 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
5000 fp->u.FfileBothDirectoryInfo.shortName,
5001 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
5003 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
5005 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5006 fp->u.FfileBothDirectoryInfo.reserved = 0;
5008 strcpy(fp->u.FfileBothDirectoryInfo.shortName,
5010 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
5015 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5016 fp->u.FfileFullDirectoryInfo.eaSize = 0;
5019 case SMB_FIND_FILE_DIRECTORY_INFO:
5020 fp->u.FfileDirectoryInfo.nextEntryOffset = 0;
5021 fp->u.FfileDirectoryInfo.fileIndex = 0;
5022 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5023 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5026 case SMB_FIND_FILE_NAMES_INFO:
5027 fp->u.FfileNamesInfo.nextEntryOffset = 0;
5028 fp->u.FfileNamesInfo.fileIndex = 0;
5029 fp->u.FfileNamesInfo.fileNameLength = onbytes;
5033 /* we shouldn't hit this case */
5034 osi_assertx(FALSE, "Unknown query type");
5037 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5038 osi_assert(attrp != NULL);
5040 curPatchp = malloc(sizeof(*curPatchp));
5041 osi_QAdd((osi_queue_t **) &dirListPatchesp,
5043 curPatchp->dptr = attrp;
5045 if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
5046 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5048 curPatchp->flags = 0;
5051 cm_SetFid(&curPatchp->fid, targetscp->fid.cell, targetscp->fid.volume, targetscp->fid.vnode, targetscp->fid.unique);
5055 int namelen = cm_ClientStringToFsString(maskp, -1, NULL, 0);
5056 dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+namelen);
5057 cm_ClientStringToFsString(maskp, -1, dep->name, namelen);
5059 dep->fid.vnode = targetscp->fid.vnode;
5060 dep->fid.unique = targetscp->fid.unique;
5061 curPatchp->dep = dep;
5064 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
5065 /* put out resume key */
5066 *((u_long *)origOp) = 0;
5069 /* Adjust byte ptr and count */
5070 origOp += orbytes; /* skip entire record */
5071 bytesInBuffer += orbytes;
5073 /* and pad the record out */
5074 while (--align >= 0) {
5079 /* apply the patches */
5080 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->wdata, infoLevel, userp, &req);
5082 outp->parmsp[0] = 0;
5083 outp->parmsp[1] = 1; /* number of names returned */
5084 outp->parmsp[2] = 1; /* end of search */
5085 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5086 outp->parmsp[4] = 0;
5088 outp->totalParms = 10; /* in bytes */
5090 outp->totalData = bytesInBuffer;
5092 osi_Log0(smb_logp, "T2SDSingle done.");
5094 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5096 smb_SendTran2Error(vcp, p, opx, code);
5098 smb_SendTran2Packet(vcp, outp, opx);
5103 smb_FreeTran2Packet(outp);
5107 cm_ReleaseSCache(scp);
5108 cm_ReleaseSCache(targetscp);
5109 cm_ReleaseUser(userp);
5115 /* TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2 */
5116 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
5121 long code = 0, code2 = 0;
5122 clientchar_t *pathp;
5123 cm_dirEntry_t *dep = 0;
5125 smb_dirListPatch_t *dirListPatchesp = 0;
5126 smb_dirListPatch_t *curPatchp = 0;
5129 size_t orbytes; /* # of bytes in this output record */
5130 size_t ohbytes; /* # of bytes, except file name */
5131 size_t onbytes; /* # of bytes in name, incl. term. null */
5132 osi_hyper_t dirLength;
5133 osi_hyper_t bufferOffset;
5134 osi_hyper_t curOffset;
5136 smb_dirSearch_t *dsp;
5140 cm_pageHeader_t *pageHeaderp;
5141 cm_user_t *userp = NULL;
5144 long nextEntryCookie;
5145 int numDirChunks; /* # of 32 byte dir chunks in this entry */
5146 char *op; /* output data ptr */
5147 char *origOp; /* original value of op */
5148 cm_space_t *spacep; /* for pathname buffer */
5149 unsigned long maxReturnData; /* max # of return data */
5150 unsigned long maxReturnParms; /* max # of return parms */
5151 long bytesInBuffer; /* # data bytes in the output buffer */
5153 clientchar_t *maskp; /* mask part of path */
5157 smb_tran2Packet_t *outp; /* response packet */
5158 clientchar_t *tidPathp;
5160 clientchar_t shortName[13]; /* 8.3 name if needed */
5163 clientchar_t *shortNameEnd;
5169 smb_tran2Find_t * fp;
5174 if (p->opcode == 1) {
5175 /* find first; obtain basic parameters from request */
5176 attribute = p->parmsp[0];
5177 maxCount = p->parmsp[1];
5178 infoLevel = p->parmsp[3];
5179 searchFlags = p->parmsp[2];
5180 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
5182 maskp = cm_ClientStrRChr(pathp, '\\');
5186 maskp++; /* skip over backslash */
5188 /* track if this is likely to match a lot of entries */
5189 starPattern = smb_V3IsStarMask(maskp);
5191 #ifndef NOFINDFIRSTOPTIMIZE
5193 /* if this is for a single directory or file, we let the
5194 optimized routine handle it. The only error it
5195 returns is CM_ERROR_NOSUCHFILE. The */
5196 code = smb_T2SearchDirSingle(vcp, p, opx);
5198 /* we only failover if we see a CM_ERROR_NOSUCHFILE */
5199 if (code != CM_ERROR_NOSUCHFILE) {
5201 /* unless we are using the BPlusTree */
5202 if (code == CM_ERROR_BPLUS_NOMATCH)
5203 code = CM_ERROR_NOSUCHFILE;
5204 #endif /* USE_BPLUS */
5208 #endif /* NOFINDFIRSTOPTIMIZE */
5211 dsp = smb_NewDirSearch(1);
5212 dsp->attribute = attribute;
5213 cm_ClientStrCpy(dsp->mask, lengthof(dsp->mask), maskp); /* and save mask */
5216 osi_assertx(p->opcode == 2, "invalid opcode");
5217 /* find next; obtain basic parameters from request or open dir file */
5218 dsp = smb_FindDirSearch(p->parmsp[0]);
5219 maxCount = p->parmsp[1];
5220 infoLevel = p->parmsp[2];
5221 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
5222 searchFlags = p->parmsp[5];
5224 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
5225 p->parmsp[0], nextCookie);
5226 return CM_ERROR_BADFD;
5228 attribute = dsp->attribute;
5231 starPattern = 1; /* assume, since required a Find Next */
5234 switch ( infoLevel ) {
5235 case SMB_INFO_STANDARD:
5237 ohbytes = sizeof(fp->u.FstandardInfo);
5240 case SMB_INFO_QUERY_EA_SIZE:
5241 ohbytes = sizeof(fp->u.FeaSizeInfo);
5242 s = "InfoQueryEaSize";
5245 case SMB_INFO_QUERY_EAS_FROM_LIST:
5246 ohbytes = sizeof(fp->u.FeasFromListInfo);
5247 s = "InfoQueryEasFromList";
5250 case SMB_FIND_FILE_DIRECTORY_INFO:
5251 s = "FindFileDirectoryInfo";
5252 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
5255 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5256 s = "FindFileFullDirectoryInfo";
5257 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
5260 case SMB_FIND_FILE_NAMES_INFO:
5261 s = "FindFileNamesInfo";
5262 ohbytes = sizeof(fp->u.FfileNamesInfo);
5265 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5266 s = "FindFileBothDirectoryInfo";
5267 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
5271 s = "unknownInfoLevel";
5275 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
5278 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
5279 attribute, infoLevel, maxCount, searchFlags);
5281 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
5282 p->opcode, dsp->cookie, nextCookie);
5285 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
5286 smb_ReleaseDirSearch(dsp);
5287 return CM_ERROR_INVAL;
5290 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5291 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
5293 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5296 dirListPatchesp = NULL;
5298 maxReturnData = p->maxReturnData;
5299 if (p->opcode == 1) /* find first */
5300 maxReturnParms = 10; /* bytes */
5302 maxReturnParms = 8; /* bytes */
5304 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
5310 osi_Log2(smb_logp, "T2 receive search dir count %d [%S]",
5311 maxCount, osi_LogSaveClientString(smb_logp, pathp));
5313 /* bail out if request looks bad */
5314 if (p->opcode == 1 && !pathp) {
5315 smb_ReleaseDirSearch(dsp);
5316 smb_FreeTran2Packet(outp);
5317 return CM_ERROR_BADSMB;
5320 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
5321 dsp->cookie, nextCookie, attribute);
5323 userp = smb_GetTran2User(vcp, p);
5325 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
5326 smb_ReleaseDirSearch(dsp);
5327 smb_FreeTran2Packet(outp);
5328 return CM_ERROR_BADSMB;
5331 /* try to get the vnode for the path name next */
5332 lock_ObtainMutex(&dsp->mx);
5335 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5339 spacep = cm_GetSpace();
5340 /* smb_StripLastComponent will strip "::$DATA" if present */
5341 smb_StripLastComponent(spacep->wdata, NULL, pathp);
5342 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
5344 cm_ReleaseUser(userp);
5345 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
5346 smb_FreeTran2Packet(outp);
5347 lock_ReleaseMutex(&dsp->mx);
5348 smb_DeleteDirSearch(dsp);
5349 smb_ReleaseDirSearch(dsp);
5353 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
5354 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
5356 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
5357 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5358 userp, tidPathp, &req, &scp);
5359 cm_FreeSpace(spacep);
5362 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
5363 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5364 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
5365 cm_ReleaseSCache(scp);
5366 cm_ReleaseUser(userp);
5367 if ( WANTS_DFS_PATHNAMES(p) || pnc )
5368 code = CM_ERROR_PATH_NOT_COVERED;
5370 code = CM_ERROR_NOSUCHPATH;
5371 smb_SendTran2Error(vcp, p, opx, code);
5372 smb_FreeTran2Packet(outp);
5373 lock_ReleaseMutex(&dsp->mx);
5374 smb_DeleteDirSearch(dsp);
5375 smb_ReleaseDirSearch(dsp);
5378 #endif /* DFS_SUPPORT */
5380 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5381 /* we need one hold for the entry we just stored into,
5382 * and one for our own processing. When we're done
5383 * with this function, we'll drop the one for our own
5384 * processing. We held it once from the namei call,
5385 * and so we do another hold now.
5388 dsp->flags |= SMB_DIRSEARCH_BULKST;
5391 lock_ReleaseMutex(&dsp->mx);
5393 cm_ReleaseUser(userp);
5394 smb_FreeTran2Packet(outp);
5395 smb_DeleteDirSearch(dsp);
5396 smb_ReleaseDirSearch(dsp);
5400 /* get the directory size */
5401 lock_ObtainWrite(&scp->rw);
5402 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5403 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5405 lock_ReleaseWrite(&scp->rw);
5406 cm_ReleaseSCache(scp);
5407 cm_ReleaseUser(userp);
5408 smb_FreeTran2Packet(outp);
5409 smb_DeleteDirSearch(dsp);
5410 smb_ReleaseDirSearch(dsp);
5414 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5417 dirLength = scp->length;
5419 bufferOffset.LowPart = bufferOffset.HighPart = 0;
5420 curOffset.HighPart = 0;
5421 curOffset.LowPart = nextCookie;
5422 origOp = outp->datap;
5429 normchar_t normName[MAX_PATH]; /* Normalized name */
5430 clientchar_t cfileName[MAX_PATH]; /* Non-normalized name */
5433 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5434 /* skip over resume key */
5437 fp = (smb_tran2Find_t *) op;
5439 /* make sure that curOffset.LowPart doesn't point to the first
5440 * 32 bytes in the 2nd through last dir page, and that it doesn't
5441 * point at the first 13 32-byte chunks in the first dir page,
5442 * since those are dir and page headers, and don't contain useful
5445 temp = curOffset.LowPart & (2048-1);
5446 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5447 /* we're in the first page */
5448 if (temp < 13*32) temp = 13*32;
5451 /* we're in a later dir page */
5452 if (temp < 32) temp = 32;
5455 /* make sure the low order 5 bits are zero */
5458 /* now put temp bits back ito curOffset.LowPart */
5459 curOffset.LowPart &= ~(2048-1);
5460 curOffset.LowPart |= temp;
5462 /* check if we've passed the dir's EOF */
5463 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
5464 osi_Log0(smb_logp, "T2 search dir passed eof");
5469 /* check if we've returned all the names that will fit in the
5470 * response packet; we check return count as well as the number
5471 * of bytes requested. We check the # of bytes after we find
5472 * the dir entry, since we'll need to check its size.
5474 if (returnedNames >= maxCount) {
5475 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
5476 returnedNames, maxCount);
5480 /* when we have obtained as many entries as can be processed in
5481 * a single Bulk Status call to the file server, apply the dir listing
5484 if (returnedNames > 0 && returnedNames % AFSCBMAX == 0) {
5485 lock_ReleaseWrite(&scp->rw);
5486 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5487 dsp->relPath, infoLevel, userp, &req);
5488 lock_ObtainWrite(&scp->rw);
5490 /* Then check to see if we have time left to process more entries */
5491 if (GetTickCount() - req.startTime > (RDRtimeout - 15) * 1000) {
5492 osi_Log0(smb_logp, "T2 search dir RDRtimeout exceeded");
5496 /* see if we can use the bufferp we have now; compute in which
5497 * page the current offset would be, and check whether that's
5498 * the offset of the buffer we have. If not, get the buffer.
5500 thyper.HighPart = curOffset.HighPart;
5501 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5502 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5505 buf_Release(bufferp);
5508 lock_ReleaseWrite(&scp->rw);
5509 code = buf_Get(scp, &thyper, &req, &bufferp);
5510 lock_ObtainWrite(&scp->rw);
5512 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
5516 bufferOffset = thyper;
5518 /* now get the data in the cache */
5520 code = cm_SyncOp(scp, bufferp, userp, &req,
5522 CM_SCACHESYNC_NEEDCALLBACK
5523 | CM_SCACHESYNC_READ);
5525 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5529 if (cm_HaveBuffer(scp, bufferp, 0)) {
5530 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5531 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5535 /* otherwise, load the buffer and try again */
5536 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5538 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5540 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5541 scp, bufferp, code);
5546 buf_Release(bufferp);
5550 } /* if (wrong buffer) ... */
5552 /* now we have the buffer containing the entry we're interested
5553 * in; copy it out if it represents a non-deleted entry.
5555 entryInDir = curOffset.LowPart & (2048-1);
5556 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5558 /* page header will help tell us which entries are free. Page
5559 * header can change more often than once per buffer, since
5560 * AFS 3 dir page size may be less than (but not more than)
5561 * a buffer package buffer.
5563 /* only look intra-buffer */
5564 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5565 temp &= ~(2048 - 1); /* turn off intra-page bits */
5566 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5568 /* now determine which entry we're looking at in the page.
5569 * If it is free (there's a free bitmap at the start of the
5570 * dir), we should skip these 32 bytes.
5572 slotInPage = (entryInDir & 0x7e0) >> 5;
5573 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5574 (1 << (slotInPage & 0x7)))) {
5575 /* this entry is free */
5576 numDirChunks = 1; /* only skip this guy */
5580 tp = bufferp->datap + entryInBuffer;
5581 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5583 /* while we're here, compute the next entry's location, too,
5584 * since we'll need it when writing out the cookie into the dir
5587 * XXXX Probably should do more sanity checking.
5589 numDirChunks = cm_NameEntries(dep->name, &onbytes);
5591 /* compute offset of cookie representing next entry */
5592 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5594 if (dep->fid.vnode == 0)
5595 goto nextEntry; /* This entry is not in use */
5597 if (cm_FsStringToClientString(dep->name, -1, cfileName, lengthof(cfileName)) == 0 ||
5598 cm_ClientStringToNormString(cfileName, -1, normName, lengthof(normName)) == 0) {
5600 osi_Log1(smb_logp, "Skipping entry [%s]. Can't convert or normalize FS String",
5601 osi_LogSaveString(smb_logp, dep->name));
5605 /* Need 8.3 name? */
5607 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
5608 !cm_Is8Dot3(cfileName)) {
5609 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5613 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %S (%S)",
5614 dep->fid.vnode, dep->fid.unique,
5615 osi_LogSaveClientString(smb_logp, cfileName),
5616 NeedShortName ? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
5618 /* When matching, we are using doing a case fold if we have a wildcard mask.
5619 * If we get a non-wildcard match, it's a lookup for a specific file.
5621 if (cm_MatchMask(normName, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5622 (NeedShortName && cm_MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))
5624 /* Eliminate entries that don't match requested attributes */
5625 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5626 smb_IsDotFile(cfileName)) {
5627 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5628 goto nextEntry; /* no hidden files */
5631 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5633 /* We have already done the cm_TryBulkStat above */
5634 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume,
5635 ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5636 fileType = cm_FindFileType(&fid);
5637 /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5638 * "has filetype %d", dep->name, fileType);
5640 if ( fileType == CM_SCACHETYPE_DIRECTORY ||
5641 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5642 fileType == CM_SCACHETYPE_DFSLINK ||
5643 fileType == CM_SCACHETYPE_INVALID)
5644 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5648 /* finally check if this name will fit */
5650 smb_UnparseString(opx, NULL, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5651 orbytes = ohbytes + onbytes;
5653 /* now, we round up the record to a 4 byte alignment,
5654 * and we make sure that we have enough room here for
5655 * even the aligned version (so we don't have to worry
5656 * about an overflow when we pad things out below).
5657 * That's the reason for the alignment arithmetic below.
5659 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5660 align = (4 - (orbytes & 3)) & 3;
5664 if (orbytes + bytesInBuffer + align > maxReturnData) {
5665 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5670 /* this is one of the entries to use: it is not deleted
5671 * and it matches the star pattern we're looking for.
5672 * Put out the name, preceded by its length.
5674 /* First zero everything else */
5675 memset(origOp, 0, orbytes);
5678 smb_UnparseString(opx, origOp + ohbytes, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5680 switch (infoLevel) {
5681 case SMB_INFO_STANDARD:
5682 fp->u.FstandardInfo.fileNameLength = onbytes;
5683 attrp = &fp->u.FstandardInfo.fileAttrs;
5686 case SMB_INFO_QUERY_EA_SIZE:
5687 fp->u.FeaSizeInfo.fileNameLength = onbytes;
5688 attrp = &fp->u.FeaSizeInfo.fileAttrs;
5689 fp->u.FeaSizeInfo.eaSize = 0;
5692 case SMB_INFO_QUERY_EAS_FROM_LIST:
5693 fp->u.FeasFromListInfo.fileNameLength = onbytes;
5694 attrp = &fp->u.FeasFromListInfo.fileAttrs;
5695 fp->u.FeasFromListInfo.eaSize = 0;
5698 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5699 if (NeedShortName) {
5703 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
5704 fp->u.FfileBothDirectoryInfo.shortName,
5705 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
5707 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
5709 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5710 fp->u.FfileBothDirectoryInfo.reserved = 0;
5712 cm_ClientStrCpy(fp->u.FfileBothDirectoryInfo.shortName,
5713 lengthof(fp->u.FfileBothDirectoryInfo.shortName),
5715 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
5720 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5721 fp->u.FfileFullDirectoryInfo.eaSize = 0;
5724 case SMB_FIND_FILE_DIRECTORY_INFO:
5725 fp->u.FfileDirectoryInfo.nextEntryOffset = orbytes + align;
5726 fp->u.FfileDirectoryInfo.fileIndex = nextEntryCookie;
5727 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5728 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5731 case SMB_FIND_FILE_NAMES_INFO:
5732 fp->u.FfileNamesInfo.nextEntryOffset = orbytes + align;
5733 fp->u.FfileNamesInfo.fileIndex = nextEntryCookie;
5734 fp->u.FfileNamesInfo.fileNameLength = onbytes;
5739 /* we shouldn't hit this case */
5740 osi_assertx(FALSE, "Unknown query type");
5743 /* now, adjust the # of entries copied */
5746 /* now we emit the attribute. This is tricky, since
5747 * we need to really stat the file to find out what
5748 * type of entry we've got. Right now, we're copying
5749 * out data from a buffer, while holding the scp
5750 * locked, so it isn't really convenient to stat
5751 * something now. We'll put in a place holder
5752 * now, and make a second pass before returning this
5753 * to get the real attributes. So, we just skip the
5754 * data for now, and adjust it later. We allocate a
5755 * patch record to make it easy to find this point
5756 * later. The replay will happen at a time when it is
5757 * safe to unlock the directory.
5759 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5760 osi_assert(attrp != NULL);
5761 curPatchp = malloc(sizeof(*curPatchp));
5762 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5763 curPatchp->dptr = attrp;
5765 if (smb_hideDotFiles && smb_IsDotFile(cfileName)) {
5766 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5768 curPatchp->flags = 0;
5771 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5774 curPatchp->dep = dep;
5777 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5778 /* put out resume key */
5779 *((u_long *)origOp) = nextEntryCookie;
5781 /* Adjust byte ptr and count */
5782 origOp += orbytes; /* skip entire record */
5783 bytesInBuffer += orbytes;
5785 /* and pad the record out */
5786 while (align-- > 0) {
5790 } /* if we're including this name */
5791 else if (!starPattern &&
5793 cm_MatchMask(normName, maskp, CM_FLAG_CASEFOLD)) {
5794 /* We were looking for exact matches, but here's an inexact one*/
5799 /* and adjust curOffset to be where the new cookie is */
5800 thyper.HighPart = 0;
5801 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5802 curOffset = LargeIntegerAdd(thyper, curOffset);
5803 } /* while copying data for dir listing */
5805 /* If we didn't get a star pattern, we did an exact match during the first pass.
5806 * If there were no exact matches found, we fail over to inexact matches by
5807 * marking the query as a star pattern (matches all case permutations), and
5808 * re-running the query.
5810 if (returnedNames == 0 && !starPattern && foundInexact) {
5811 osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
5816 /* release the mutex */
5817 lock_ReleaseWrite(&scp->rw);
5819 buf_Release(bufferp);
5824 * Finally, process whatever entries we have left.
5826 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5827 dsp->relPath, infoLevel, userp, &req);
5829 /* now put out the final parameters */
5830 if (returnedNames == 0)
5832 if (p->opcode == 1) {
5834 outp->parmsp[0] = (unsigned short) dsp->cookie;
5835 outp->parmsp[1] = returnedNames;
5836 outp->parmsp[2] = eos;
5837 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5838 outp->parmsp[4] = 0;
5839 /* don't need last name to continue
5840 * search, cookie is enough. Normally,
5841 * this is the offset of the file name
5842 * of the last entry returned.
5844 outp->totalParms = 10; /* in bytes */
5848 outp->parmsp[0] = returnedNames;
5849 outp->parmsp[1] = eos;
5850 outp->parmsp[2] = 0; /* EAS error */
5851 outp->parmsp[3] = 0; /* last name, as above */
5852 outp->totalParms = 8; /* in bytes */
5855 /* return # of bytes in the buffer */
5856 outp->totalData = bytesInBuffer;
5858 /* Return error code if unsuccessful on first request */
5859 if (code == 0 && p->opcode == 1 && returnedNames == 0)
5860 code = CM_ERROR_NOSUCHFILE;
5862 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
5863 p->opcode, dsp->cookie, returnedNames, code);
5865 /* if we're supposed to close the search after this request, or if
5866 * we're supposed to close the search if we're done, and we're done,
5867 * or if something went wrong, close the search.
5869 if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
5870 (returnedNames == 0) ||
5871 ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
5873 smb_DeleteDirSearch(dsp);
5876 smb_SendTran2Error(vcp, p, opx, code);
5878 smb_SendTran2Packet(vcp, outp, opx);
5880 smb_FreeTran2Packet(outp);
5881 smb_ReleaseDirSearch(dsp);
5882 cm_ReleaseSCache(scp);
5883 cm_ReleaseUser(userp);
5887 /* SMB_COM_FIND_CLOSE2 */
5888 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5891 smb_dirSearch_t *dsp;
5893 dirHandle = smb_GetSMBParm(inp, 0);
5895 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
5897 dsp = smb_FindDirSearch(dirHandle);
5900 return CM_ERROR_BADFD;
5902 /* otherwise, we have an FD to destroy */
5903 smb_DeleteDirSearch(dsp);
5904 smb_ReleaseDirSearch(dsp);
5906 /* and return results */
5907 smb_SetSMBDataLength(outp, 0);
5913 /* SMB_COM_FIND_NOTIFY_CLOSE */
5914 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5916 smb_SetSMBDataLength(outp, 0);
5920 /* SMB_COM_OPEN_ANDX */
5921 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5923 clientchar_t *pathp;
5928 cm_scache_t *dscp; /* dir we're dealing with */
5929 cm_scache_t *scp; /* file we're creating */
5931 int initialModeBits;
5934 clientchar_t *lastNamep;
5935 unsigned long dosTime;
5941 int parmSlot; /* which parm we're dealing with */
5942 clientchar_t *tidPathp;
5945 BOOL is_rpc = FALSE;
5946 BOOL is_ipc = FALSE;
5952 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
5953 openFun = smb_GetSMBParm(inp, 8); /* open function */
5954 excl = ((openFun & 3) == 0);
5955 trunc = ((openFun & 3) == 2); /* truncate it */
5956 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
5957 openAction = 0; /* tracks what we did */
5959 attributes = smb_GetSMBParm(inp, 5);
5960 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
5962 /* compute initial mode bits based on read-only flag in attributes */
5963 initialModeBits = 0666;
5964 if (attributes & SMB_ATTR_READONLY)
5965 initialModeBits &= ~0222;
5967 pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
5970 return CM_ERROR_BADSMB;
5972 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5974 if (code == CM_ERROR_TIDIPC) {
5977 return CM_ERROR_NOSUCHPATH;
5981 spacep = inp->spacep;
5982 /* smb_StripLastComponent will strip "::$DATA" if present */
5983 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5987 /* special case magic file name for receiving IOCTL requests
5988 * (since IOCTL calls themselves aren't getting through).
5990 (cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
5992 /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional) */
5993 (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
5995 unsigned short file_type = 0;
5996 unsigned short device_state = 0;
5998 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6000 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
6001 osi_Log1(smb_logp, "OpenAndX Setting up RPC on fid[%d]", fidp->fid);
6003 osi_Log1(smb_logp, "smb_SetupRPCFid failure code [%d]", code);
6004 smb_ReleaseFID(fidp);
6008 smb_SetupIoctlFid(fidp, spacep);
6009 osi_Log1(smb_logp, "OpenAndX Setting up IOCTL on fid[%d]", fidp->fid);
6012 /* set inp->fid so that later read calls in same msg can find fid */
6013 inp->fid = fidp->fid;
6015 /* copy out remainder of the parms */
6017 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6019 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
6020 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
6021 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6022 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
6023 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
6024 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
6025 smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++;
6026 smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++;
6028 /* and the final "always present" stuff */
6029 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
6030 /* next write out the "unique" ID */
6031 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
6032 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
6033 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6034 smb_SetSMBDataLength(outp, 0);
6036 /* and clean up fid reference */
6037 smb_ReleaseFID(fidp);
6043 osi_Log0(smb_logp, "NTOpenX rejecting IPC TID");
6044 return CM_ERROR_BADFD;
6048 if (!cm_IsValidClientString(pathp)) {
6050 clientchar_t * hexp;
6052 hexp = cm_GetRawCharsAlloc(pathp, -1);
6053 osi_Log1(smb_logp, "NTOpenX rejecting invalid name. [%S]",
6054 osi_LogSaveClientString(smb_logp, hexp));
6058 osi_Log0(smb_logp, "NTOpenX rejecting invalid name");
6060 return CM_ERROR_BADNTFILENAME;
6063 #ifdef DEBUG_VERBOSE
6065 char *hexp, *asciip;
6066 asciip = (lastNamep ? lastNamep : pathp );
6067 hexp = osi_HexifyString(asciip);
6068 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
6072 userp = smb_GetUserFromVCP(vcp, inp);
6075 code = cm_NameI(cm_data.rootSCachep, pathp,
6076 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6077 userp, tidPathp, &req, &scp);
6080 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6081 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
6082 cm_ReleaseSCache(scp);
6083 cm_ReleaseUser(userp);
6084 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6085 return CM_ERROR_PATH_NOT_COVERED;
6087 return CM_ERROR_NOSUCHPATH;
6089 #endif /* DFS_SUPPORT */
6092 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
6093 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6094 userp, tidPathp, &req, &dscp);
6096 cm_ReleaseUser(userp);
6101 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6102 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
6104 cm_ReleaseSCache(dscp);
6105 cm_ReleaseUser(userp);
6106 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6107 return CM_ERROR_PATH_NOT_COVERED;
6109 return CM_ERROR_NOSUCHPATH;
6111 #endif /* DFS_SUPPORT */
6112 /* otherwise, scp points to the parent directory. Do a lookup,
6113 * and truncate the file if we find it, otherwise we create the
6120 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
6122 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
6123 cm_ReleaseSCache(dscp);
6124 cm_ReleaseUser(userp);
6129 /* if we get here, if code is 0, the file exists and is represented by
6130 * scp. Otherwise, we have to create it. The dir may be represented
6131 * by dscp, or we may have found the file directly. If code is non-zero,
6135 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
6137 if (dscp) cm_ReleaseSCache(dscp);
6138 cm_ReleaseSCache(scp);
6139 cm_ReleaseUser(userp);
6144 /* oops, file shouldn't be there */
6146 cm_ReleaseSCache(dscp);
6147 cm_ReleaseSCache(scp);
6148 cm_ReleaseUser(userp);
6149 return CM_ERROR_EXISTS;
6153 setAttr.mask = CM_ATTRMASK_LENGTH;
6154 setAttr.length.LowPart = 0;
6155 setAttr.length.HighPart = 0;
6156 code = cm_SetAttr(scp, &setAttr, userp, &req);
6157 openAction = 3; /* truncated existing file */
6159 else openAction = 1; /* found existing file */
6161 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
6162 /* don't create if not found */
6163 if (dscp) cm_ReleaseSCache(dscp);
6164 cm_ReleaseUser(userp);
6165 return CM_ERROR_NOSUCHFILE;
6168 osi_assertx(dscp != NULL, "null cm_scache_t");
6169 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %S",
6170 osi_LogSaveClientString(smb_logp, lastNamep));
6171 openAction = 2; /* created file */
6172 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6173 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6174 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6178 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6179 smb_NotifyChange(FILE_ACTION_ADDED,
6180 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6181 dscp, lastNamep, NULL, TRUE);
6182 } else if (!excl && code == CM_ERROR_EXISTS) {
6183 /* not an exclusive create, and someone else tried
6184 * creating it already, then we open it anyway. We
6185 * don't bother retrying after this, since if this next
6186 * fails, that means that the file was deleted after we
6187 * started this call.
6189 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6193 setAttr.mask = CM_ATTRMASK_LENGTH;
6194 setAttr.length.LowPart = 0;
6195 setAttr.length.HighPart = 0;
6196 code = cm_SetAttr(scp, &setAttr, userp, &req);
6198 } /* lookup succeeded */
6202 /* we don't need this any longer */
6204 cm_ReleaseSCache(dscp);
6207 /* something went wrong creating or truncating the file */
6209 cm_ReleaseSCache(scp);
6210 cm_ReleaseUser(userp);
6214 /* make sure we're about to open a file */
6215 if (scp->fileType != CM_SCACHETYPE_FILE) {
6216 cm_ReleaseSCache(scp);
6217 cm_ReleaseUser(userp);
6218 return CM_ERROR_ISDIR;
6221 /* now all we have to do is open the file itself */
6222 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6223 osi_assertx(fidp, "null smb_fid_t");
6226 lock_ObtainMutex(&fidp->mx);
6227 /* save a pointer to the vnode */
6229 lock_ObtainWrite(&scp->rw);
6230 scp->flags |= CM_SCACHEFLAG_SMB_FID;
6231 lock_ReleaseWrite(&scp->rw);
6232 osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
6234 fidp->userp = userp;
6236 /* compute open mode */
6238 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
6239 if (openMode == 1 || openMode == 2)
6240 fidp->flags |= SMB_FID_OPENWRITE;
6242 /* remember if the file was newly created */
6244 fidp->flags |= SMB_FID_CREATED;
6246 lock_ReleaseMutex(&fidp->mx);
6247 smb_ReleaseFID(fidp);
6249 cm_Open(scp, 0, userp);
6251 /* set inp->fid so that later read calls in same msg can find fid */
6252 inp->fid = fidp->fid;
6254 /* copy out remainder of the parms */
6256 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6257 lock_ObtainRead(&scp->rw);
6259 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
6260 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
6261 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
6262 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
6263 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
6264 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
6265 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
6266 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
6267 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
6269 /* and the final "always present" stuff */
6270 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
6271 /* next write out the "unique" ID */
6272 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
6273 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
6274 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6275 lock_ReleaseRead(&scp->rw);
6276 smb_SetSMBDataLength(outp, 0);
6278 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
6280 cm_ReleaseUser(userp);
6281 /* leave scp held since we put it in fidp->scp */
6285 static void smb_GetLockParams(unsigned char LockType,
6287 unsigned int * ppid,
6288 LARGE_INTEGER * pOffset,
6289 LARGE_INTEGER * pLength)
6291 if (LockType & LOCKING_ANDX_LARGE_FILES) {
6293 *ppid = *((USHORT *) *buf);
6294 pOffset->HighPart = *((LONG *)(*buf + 4));
6295 pOffset->LowPart = *((DWORD *)(*buf + 8));
6296 pLength->HighPart = *((LONG *)(*buf + 12));
6297 pLength->LowPart = *((DWORD *)(*buf + 16));
6301 /* Not Large Files */
6302 *ppid = *((USHORT *) *buf);
6303 pOffset->HighPart = 0;
6304 pOffset->LowPart = *((DWORD *)(*buf + 2));
6305 pLength->HighPart = 0;
6306 pLength->LowPart = *((DWORD *)(*buf + 6));
6311 /* SMB_COM_LOCKING_ANDX */
6312 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6319 unsigned char LockType;
6320 unsigned short NumberOfUnlocks, NumberOfLocks;
6324 LARGE_INTEGER LOffset, LLength;
6325 smb_waitingLockRequest_t *wlRequest = NULL;
6326 cm_file_lock_t *lockp;
6334 fid = smb_GetSMBParm(inp, 2);
6335 fid = smb_ChainFID(fid, inp);
6337 fidp = smb_FindFID(vcp, fid, 0);
6339 osi_Log2(smb_logp, "V3LockingX Unknown SMB Fid vcp 0x%p fid %d",
6341 return CM_ERROR_BADFD;
6343 lock_ObtainMutex(&fidp->mx);
6344 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6345 lock_ReleaseMutex(&fidp->mx);
6346 smb_CloseFID(vcp, fidp, NULL, 0);
6347 smb_ReleaseFID(fidp);
6348 return CM_ERROR_NOSUCHFILE;
6351 if (fidp->flags & SMB_FID_IOCTL) {
6352 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
6353 lock_ReleaseMutex(&fidp->mx);
6354 smb_ReleaseFID(fidp);
6355 return CM_ERROR_BADFD;
6358 osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
6360 lock_ReleaseMutex(&fidp->mx);
6362 /* set inp->fid so that later read calls in same msg can find fid */
6365 userp = smb_GetUserFromVCP(vcp, inp);
6367 lock_ObtainWrite(&scp->rw);
6368 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6369 CM_SCACHESYNC_NEEDCALLBACK
6370 | CM_SCACHESYNC_GETSTATUS
6371 | CM_SCACHESYNC_LOCK);
6373 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
6377 LockType = smb_GetSMBParm(inp, 3) & 0xff;
6378 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
6379 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
6380 NumberOfLocks = smb_GetSMBParm(inp, 7);
6382 if (!(fidp->flags & SMB_FID_OPENWRITE) &&
6383 !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
6384 /* somebody wants exclusive locks on a file that they only
6385 opened for reading. We downgrade this to a shared lock. */
6386 osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
6387 LockType |= LOCKING_ANDX_SHARED_LOCK;
6390 if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
6391 /* AFS does not support atomic changes of lock types from read or write and vice-versa */
6392 osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]");
6393 code = CM_ERROR_BADOP;
6398 op = smb_GetSMBData(inp, NULL);
6400 if (LockType & LOCKING_ANDX_CANCEL_LOCK) {
6401 /* Cancel outstanding lock requests */
6402 smb_waitingLock_t * wl;
6404 for (i=0; i<NumberOfLocks; i++) {
6405 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6407 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6409 lock_ObtainWrite(&smb_globalLock);
6410 for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
6412 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
6413 if (cm_KeyEquals(&wl->key, &key, 0) && LargeIntegerEqualTo(wl->LOffset, LOffset) &&
6414 LargeIntegerEqualTo(wl->LLength, LLength)) {
6415 wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
6416 goto found_lock_request;
6421 lock_ReleaseWrite(&smb_globalLock);
6424 smb_SetSMBDataLength(outp, 0);
6429 for (i=0; i<NumberOfUnlocks; i++) {
6430 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6432 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6434 code = cm_Unlock(scp, LockType, LOffset, LLength, key, 0, userp, &req);
6442 for (i=0; i<NumberOfLocks; i++) {
6443 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6445 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6447 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
6448 userp, &req, &lockp);
6450 if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
6451 (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
6453 code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
6454 userp, &req, &lockp);
6457 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
6458 smb_waitingLock_t * wLock;
6460 /* Put on waiting list */
6461 if(wlRequest == NULL) {
6465 LARGE_INTEGER tOffset, tLength;
6467 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
6469 osi_assertx(wlRequest != NULL, "null wlRequest");
6471 wlRequest->vcp = vcp;
6473 wlRequest->scp = scp;
6474 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
6476 wlRequest->inp = smb_CopyPacket(inp);
6477 wlRequest->outp = smb_CopyPacket(outp);
6478 wlRequest->lockType = LockType;
6479 wlRequest->msTimeout = Timeout;
6480 wlRequest->start_t = osi_Time();
6481 wlRequest->locks = NULL;
6483 /* The waiting lock request needs to have enough
6484 information to undo all the locks in the request.
6485 We do the following to store info about locks that
6486 have already been granted. Sure, we can get most
6487 of the info from the packet, but the packet doesn't
6488 hold the result of cm_Lock call. In practice we
6489 only receive packets with one or two locks, so we
6490 are only wasting a few bytes here and there and
6491 only for a limited period of time until the waiting
6492 lock times out or is freed. */
6494 for(opt = op_locks, j=i; j > 0; j--) {
6495 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
6497 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6499 wLock = malloc(sizeof(smb_waitingLock_t));
6501 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6504 wLock->LOffset = tOffset;
6505 wLock->LLength = tLength;
6506 wLock->lockp = NULL;
6507 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
6508 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6513 wLock = malloc(sizeof(smb_waitingLock_t));
6515 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6518 wLock->LOffset = LOffset;
6519 wLock->LLength = LLength;
6520 wLock->lockp = lockp;
6521 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
6522 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6525 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
6533 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
6540 /* Since something went wrong with the lock number i, we now
6541 have to go ahead and release any locks acquired before the
6542 failure. All locks before lock number i (of which there
6543 are i of them) have either been successful or are waiting.
6544 Either case requires calling cm_Unlock(). */
6546 /* And purge the waiting lock */
6547 if(wlRequest != NULL) {
6548 smb_waitingLock_t * wl;
6549 smb_waitingLock_t * wlNext;
6552 for(wl = wlRequest->locks; wl; wl = wlNext) {
6554 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
6556 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, 0, userp, &req);
6559 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
6561 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
6564 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
6569 smb_ReleaseVC(wlRequest->vcp);
6570 cm_ReleaseSCache(wlRequest->scp);
6571 smb_FreePacket(wlRequest->inp);
6572 smb_FreePacket(wlRequest->outp);
6581 if (wlRequest != NULL) {
6583 lock_ObtainWrite(&smb_globalLock);
6584 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
6586 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
6587 lock_ReleaseWrite(&smb_globalLock);
6589 /* don't send reply immediately */
6590 outp->flags |= SMB_PACKETFLAG_NOSEND;
6593 smb_SetSMBDataLength(outp, 0);
6597 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
6600 lock_ReleaseWrite(&scp->rw);
6601 cm_ReleaseSCache(scp);
6602 cm_ReleaseUser(userp);
6603 smb_ReleaseFID(fidp);
6608 /* SMB_COM_QUERY_INFORMATION2 */
6609 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6615 afs_uint32 searchTime;
6622 fid = smb_GetSMBParm(inp, 0);
6623 fid = smb_ChainFID(fid, inp);
6625 fidp = smb_FindFID(vcp, fid, 0);
6627 osi_Log2(smb_logp, "V3GetAttributes Unknown SMB Fid vcp 0x%p fid %d",
6629 return CM_ERROR_BADFD;
6631 lock_ObtainMutex(&fidp->mx);
6632 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6633 lock_ReleaseMutex(&fidp->mx);
6634 smb_CloseFID(vcp, fidp, NULL, 0);
6635 smb_ReleaseFID(fidp);
6636 return CM_ERROR_NOSUCHFILE;
6639 if (fidp->flags & SMB_FID_IOCTL) {
6640 lock_ReleaseMutex(&fidp->mx);
6641 smb_ReleaseFID(fidp);
6642 return CM_ERROR_BADFD;
6645 osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6647 lock_ReleaseMutex(&fidp->mx);
6649 userp = smb_GetUserFromVCP(vcp, inp);
6652 /* otherwise, stat the file */
6653 lock_ObtainWrite(&scp->rw);
6654 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6655 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6659 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6661 lock_ConvertWToR(&scp->rw);
6664 /* decode times. We need a search time, but the response to this
6665 * call provides the date first, not the time, as returned in the
6666 * searchTime variable. So we take the high-order bits first.
6668 cm_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
6669 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
6670 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
6671 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
6672 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
6673 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
6674 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
6676 /* now handle file size and allocation size */
6677 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
6678 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
6679 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
6680 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
6682 /* file attribute */
6683 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
6685 /* and finalize stuff */
6686 smb_SetSMBDataLength(outp, 0);
6691 lock_ReleaseRead(&scp->rw);
6693 lock_ReleaseWrite(&scp->rw);
6694 cm_ReleaseSCache(scp);
6695 cm_ReleaseUser(userp);
6696 smb_ReleaseFID(fidp);
6700 /* SMB_COM_SET_INFORMATION2 */
6701 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6707 afs_uint32 searchTime;
6715 fid = smb_GetSMBParm(inp, 0);
6716 fid = smb_ChainFID(fid, inp);
6718 fidp = smb_FindFID(vcp, fid, 0);
6720 osi_Log2(smb_logp, "V3SetAttributes Unknown SMB Fid vcp 0x%p fid %d",
6722 return CM_ERROR_BADFD;
6724 lock_ObtainMutex(&fidp->mx);
6725 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6726 lock_ReleaseMutex(&fidp->mx);
6727 smb_CloseFID(vcp, fidp, NULL, 0);
6728 smb_ReleaseFID(fidp);
6729 return CM_ERROR_NOSUCHFILE;
6732 if (fidp->flags & SMB_FID_IOCTL) {
6733 lock_ReleaseMutex(&fidp->mx);
6734 smb_ReleaseFID(fidp);
6735 return CM_ERROR_BADFD;
6738 osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6740 lock_ReleaseMutex(&fidp->mx);
6742 userp = smb_GetUserFromVCP(vcp, inp);
6744 /* now prepare to call cm_setattr. This message only sets various times,
6745 * and AFS only implements mtime, and we'll set the mtime if that's
6746 * requested. The others we'll ignore.
6748 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
6750 if (searchTime != 0) {
6751 cm_UnixTimeFromSearchTime(&unixTime, searchTime);
6753 if ( unixTime != -1 ) {
6754 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
6755 attrs.clientModTime = unixTime;
6756 code = cm_SetAttr(scp, &attrs, userp, &req);
6758 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
6760 osi_Log1(smb_logp, "**cm_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
6766 cm_ReleaseSCache(scp);
6767 cm_ReleaseUser(userp);
6768 smb_ReleaseFID(fidp);
6772 /* SMB_COM_WRITE_ANDX */
6773 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6776 long count, written = 0, total_written = 0;
6780 smb_t *smbp = (smb_t*) inp;
6785 int inDataBlockCount;
6787 fd = smb_GetSMBParm(inp, 2);
6788 count = smb_GetSMBParm(inp, 10);
6790 offset.HighPart = 0;
6791 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6793 if (*inp->wctp == 14) {
6794 /* we have a request with 64-bit file offsets */
6795 #ifdef AFS_LARGEFILES
6796 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6798 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6800 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
6801 /* we shouldn't have received this op if we didn't specify
6802 largefile support */
6803 return CM_ERROR_INVAL;
6808 op = inp->data + smb_GetSMBParm(inp, 11);
6809 inDataBlockCount = count;
6811 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
6812 fd, offset.HighPart, offset.LowPart, count);
6814 fd = smb_ChainFID(fd, inp);
6815 fidp = smb_FindFID(vcp, fd, 0);
6817 osi_Log2(smb_logp, "smb_ReceiveV3WriteX Unknown SMB Fid vcp 0x%p fid %d",
6819 return CM_ERROR_BADFD;
6821 lock_ObtainMutex(&fidp->mx);
6822 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6823 lock_ReleaseMutex(&fidp->mx);
6824 smb_CloseFID(vcp, fidp, NULL, 0);
6825 smb_ReleaseFID(fidp);
6826 return CM_ERROR_NOSUCHFILE;
6829 if (fidp->flags & SMB_FID_IOCTL) {
6830 lock_ReleaseMutex(&fidp->mx);
6831 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
6832 smb_ReleaseFID(fidp);
6836 if (fidp->flags & SMB_FID_RPC) {
6837 lock_ReleaseMutex(&fidp->mx);
6838 code = smb_RPCV3Write(fidp, vcp, inp, outp);
6839 smb_ReleaseFID(fidp);
6844 lock_ReleaseMutex(&fidp->mx);
6845 smb_ReleaseFID(fidp);
6846 return CM_ERROR_BADFDOP;
6851 lock_ReleaseMutex(&fidp->mx);
6853 userp = smb_GetUserFromVCP(vcp, inp);
6855 /* special case: 0 bytes transferred means there is no data
6856 transferred. A slight departure from SMB_COM_WRITE where this
6857 means that we are supposed to truncate the file at this
6862 LARGE_INTEGER LOffset;
6863 LARGE_INTEGER LLength;
6866 key = cm_GenerateKey(vcp->vcID, pid, fd);
6868 LOffset.HighPart = offset.HighPart;
6869 LOffset.LowPart = offset.LowPart;
6870 LLength.HighPart = 0;
6871 LLength.LowPart = count;
6873 lock_ObtainWrite(&scp->rw);
6874 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
6875 lock_ReleaseWrite(&scp->rw);
6882 * Work around bug in NT client
6884 * When copying a file, the NT client should first copy the data,
6885 * then copy the last write time. But sometimes the NT client does
6886 * these in the wrong order, so the data copies would inadvertently
6887 * cause the last write time to be overwritten. We try to detect this,
6888 * and don't set client mod time if we think that would go against the
6891 lock_ObtainMutex(&fidp->mx);
6892 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6893 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6894 scp->clientModTime = time(NULL);
6896 lock_ReleaseMutex(&fidp->mx);
6899 while ( code == 0 && count > 0 ) {
6900 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6901 if (code == 0 && written == 0)
6902 code = CM_ERROR_PARTIALWRITE;
6904 offset = LargeIntegerAdd(offset,
6905 ConvertLongToLargeInteger(written));
6907 total_written += written;
6911 /* slots 0 and 1 are reserved for request chaining and will be
6912 filled in when we return. */
6913 smb_SetSMBParm(outp, 2, total_written);
6914 smb_SetSMBParm(outp, 3, 0); /* reserved */
6915 smb_SetSMBParm(outp, 4, 0); /* reserved */
6916 smb_SetSMBParm(outp, 5, 0); /* reserved */
6917 smb_SetSMBDataLength(outp, 0);
6921 cm_ReleaseSCache(scp);
6922 cm_ReleaseUser(userp);
6923 smb_ReleaseFID(fidp);
6928 /* SMB_COM_READ_ANDX */
6929 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6933 long finalCount = 0;
6937 smb_t *smbp = (smb_t*) inp;
6944 fd = smb_GetSMBParm(inp, 2); /* File ID */
6945 count = smb_GetSMBParm(inp, 5); /* MaxCount */
6946 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6948 if (*inp->wctp == 12) {
6949 /* a request with 64-bit offsets */
6950 #ifdef AFS_LARGEFILES
6951 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
6953 if (LargeIntegerLessThanZero(offset)) {
6954 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
6955 offset.HighPart, offset.LowPart);
6956 return CM_ERROR_BADSMB;
6959 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
6960 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
6961 return CM_ERROR_BADSMB;
6963 offset.HighPart = 0;
6967 offset.HighPart = 0;
6970 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
6971 fd, offset.HighPart, offset.LowPart, count);
6973 fd = smb_ChainFID(fd, inp);
6974 fidp = smb_FindFID(vcp, fd, 0);
6976 osi_Log2(smb_logp, "smb_ReceiveV3Read Unknown SMB Fid vcp 0x%p fid %d",
6978 return CM_ERROR_BADFD;
6981 lock_ObtainMutex(&fidp->mx);
6983 if (fidp->flags & SMB_FID_IOCTL) {
6984 lock_ReleaseMutex(&fidp->mx);
6986 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
6987 smb_ReleaseFID(fidp);
6991 if (fidp->flags & SMB_FID_RPC) {
6992 lock_ReleaseMutex(&fidp->mx);
6994 code = smb_RPCV3Read(fidp, vcp, inp, outp);
6995 smb_ReleaseFID(fidp);
6999 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7000 lock_ReleaseMutex(&fidp->mx);
7001 smb_CloseFID(vcp, fidp, NULL, 0);
7002 smb_ReleaseFID(fidp);
7003 return CM_ERROR_NOSUCHFILE;
7007 lock_ReleaseMutex(&fidp->mx);
7008 smb_ReleaseFID(fidp);
7009 return CM_ERROR_BADFDOP;
7015 lock_ReleaseMutex(&fidp->mx);
7018 key = cm_GenerateKey(vcp->vcID, pid, fd);
7020 LARGE_INTEGER LOffset, LLength;
7022 LOffset.HighPart = offset.HighPart;
7023 LOffset.LowPart = offset.LowPart;
7024 LLength.HighPart = 0;
7025 LLength.LowPart = count;
7027 lock_ObtainWrite(&scp->rw);
7028 code = cm_LockCheckRead(scp, LOffset, LLength, key);
7029 lock_ReleaseWrite(&scp->rw);
7031 cm_ReleaseSCache(scp);
7034 smb_ReleaseFID(fidp);
7038 /* set inp->fid so that later read calls in same msg can find fid */
7041 userp = smb_GetUserFromVCP(vcp, inp);
7043 /* 0 and 1 are reserved for request chaining, were setup by our caller,
7044 * and will be further filled in after we return.
7046 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
7047 smb_SetSMBParm(outp, 3, 0); /* resvd */
7048 smb_SetSMBParm(outp, 4, 0); /* resvd */
7049 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
7050 /* fill in #6 when we have all the parameters' space reserved */
7051 smb_SetSMBParm(outp, 7, 0); /* resv'd */
7052 smb_SetSMBParm(outp, 8, 0); /* resv'd */
7053 smb_SetSMBParm(outp, 9, 0); /* resv'd */
7054 smb_SetSMBParm(outp, 10, 0); /* resv'd */
7055 smb_SetSMBParm(outp, 11, 0); /* reserved */
7057 /* get op ptr after putting in the parms, since otherwise we don't
7058 * know where the data really is.
7060 op = smb_GetSMBData(outp, NULL);
7062 /* now fill in offset from start of SMB header to first data byte (to op) */
7063 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
7065 /* set the packet data length the count of the # of bytes */
7066 smb_SetSMBDataLength(outp, count);
7068 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7070 /* fix some things up */
7071 smb_SetSMBParm(outp, 5, finalCount);
7072 smb_SetSMBDataLength(outp, finalCount);
7074 cm_ReleaseUser(userp);
7075 smb_ReleaseFID(fidp);
7080 * Values for createDisp, copied from NTDDK.H
7082 #define FILE_SUPERSEDE 0 // (???)
7083 #define FILE_OPEN 1 // (open)
7084 #define FILE_CREATE 2 // (exclusive)
7085 #define FILE_OPEN_IF 3 // (non-exclusive)
7086 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
7087 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
7090 #define REQUEST_OPLOCK 2
7091 #define REQUEST_BATCH_OPLOCK 4
7092 #define OPEN_DIRECTORY 8
7093 #define EXTENDED_RESPONSE_REQUIRED 0x10
7095 /* CreateOptions field. */
7096 #define FILE_DIRECTORY_FILE 0x0001
7097 #define FILE_WRITE_THROUGH 0x0002
7098 #define FILE_SEQUENTIAL_ONLY 0x0004
7099 #define FILE_NON_DIRECTORY_FILE 0x0040
7100 #define FILE_NO_EA_KNOWLEDGE 0x0200
7101 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
7102 #define FILE_RANDOM_ACCESS 0x0800
7103 #define FILE_DELETE_ON_CLOSE 0x1000
7104 #define FILE_OPEN_BY_FILE_ID 0x2000
7105 #define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000
7106 #define FILE_NO_COMPRESSION 0x00008000
7107 #define FILE_RESERVE_OPFILTER 0x00100000
7108 #define FILE_OPEN_REPARSE_POINT 0x00200000
7109 #define FILE_OPEN_NO_RECALL 0x00400000
7110 #define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000
7112 /* SMB_COM_NT_CREATE_ANDX */
7113 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7115 clientchar_t *pathp, *realPathp;
7119 cm_scache_t *dscp; /* parent dir */
7120 cm_scache_t *scp; /* file to create or open */
7121 cm_scache_t *targetScp; /* if scp is a symlink */
7123 clientchar_t *lastNamep;
7124 clientchar_t *treeStartp;
7125 unsigned short nameLength;
7127 unsigned int requestOpLock;
7128 unsigned int requestBatchOpLock;
7129 unsigned int mustBeDir;
7130 unsigned int extendedRespRequired;
7131 unsigned int treeCreate;
7133 unsigned int desiredAccess;
7134 unsigned int extAttributes;
7135 unsigned int createDisp;
7136 unsigned int createOptions;
7137 unsigned int shareAccess;
7138 int initialModeBits;
7139 unsigned short baseFid;
7140 smb_fid_t *baseFidp;
7142 cm_scache_t *baseDirp;
7143 unsigned short openAction;
7148 clientchar_t *tidPathp;
7153 int checkDoneRequired = 0;
7154 cm_lock_data_t *ldp = NULL;
7155 BOOL is_rpc = FALSE;
7156 BOOL is_ipc = FALSE;
7160 /* This code is very long and has a lot of if-then-else clauses
7161 * scp and dscp get reused frequently and we need to ensure that
7162 * we don't lose a reference. Start by ensuring that they are NULL.
7169 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
7170 flags = smb_GetSMBOffsetParm(inp, 3, 1)
7171 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
7172 requestOpLock = flags & REQUEST_OPLOCK;
7173 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7174 mustBeDir = flags & OPEN_DIRECTORY;
7175 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7178 * Why all of a sudden 32-bit FID?
7179 * We will reject all bits higher than 16.
7181 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
7182 return CM_ERROR_INVAL;
7183 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
7184 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
7185 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
7186 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
7187 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
7188 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
7189 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
7190 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
7191 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
7192 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
7193 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
7195 /* mustBeDir is never set; createOptions directory bit seems to be
7198 if (createOptions & FILE_DIRECTORY_FILE)
7200 else if (createOptions & FILE_NON_DIRECTORY_FILE)
7206 * compute initial mode bits based on read-only flag in
7207 * extended attributes
7209 initialModeBits = 0666;
7210 if (extAttributes & SMB_ATTR_READONLY)
7211 initialModeBits &= ~0222;
7213 pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
7214 NULL, SMB_STRF_ANSIPATH);
7216 /* Sometimes path is not null-terminated, so we make a copy. */
7217 realPathp = malloc(nameLength+sizeof(clientchar_t));
7218 memcpy(realPathp, pathp, nameLength+sizeof(clientchar_t));
7219 realPathp[nameLength/sizeof(clientchar_t)] = 0;
7221 spacep = inp->spacep;
7222 /* smb_StripLastComponent will strip "::$DATA" if present */
7223 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
7225 osi_Log1(smb_logp,"NTCreateX for [%S]",osi_LogSaveClientString(smb_logp,realPathp));
7226 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
7227 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%S]", shareAccess, flags, osi_LogSaveClientString(smb_logp,(lastNamep?lastNamep:_C("null"))));
7231 baseDirp = cm_data.rootSCachep;
7232 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7233 if (code == CM_ERROR_TIDIPC) {
7234 /* Attempt to use a TID allocated for IPC. The client
7235 * is probably looking for DCE RPC end points which we
7236 * don't support OR it could be looking to make a DFS
7239 osi_Log0(smb_logp, "NTCreateX received IPC TID");
7244 osi_Log1(smb_logp, "NTCreateX tidPathp=[%S]", (tidPathp==NULL)?_C("null"): osi_LogSaveClientString(smb_logp,tidPathp));
7248 ((is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)) ||
7250 /* special case magic file name for receiving IOCTL requests
7251 * (since IOCTL calls themselves aren't getting through).
7253 cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0)) {
7255 unsigned short file_type = 0;
7256 unsigned short device_state = 0;
7258 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7261 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
7262 osi_Log1(smb_logp, "NTCreateX Setting up RPC on fid[%d]", fidp->fid);
7264 osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
7265 smb_ReleaseFID(fidp);
7270 smb_SetupIoctlFid(fidp, spacep);
7271 osi_Log1(smb_logp, "NTCreateX Setting up IOCTL on fid[%d]", fidp->fid);
7274 /* set inp->fid so that later read calls in same msg can find fid */
7275 inp->fid = fidp->fid;
7279 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7280 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7281 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
7283 memset(&ft, 0, sizeof(ft));
7284 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7285 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7286 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7287 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7288 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
7289 sz.HighPart = 0x7fff; sz.LowPart = 0;
7290 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
7291 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
7292 smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++; /* filetype */
7293 smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++; /* dev state */
7294 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
7295 smb_SetSMBDataLength(outp, 0);
7297 /* clean up fid reference */
7298 smb_ReleaseFID(fidp);
7305 osi_Log0(smb_logp, "NTCreateX rejecting IPC TID");
7307 return CM_ERROR_BADFD;
7311 if (!cm_IsValidClientString(realPathp)) {
7313 clientchar_t * hexp;
7315 hexp = cm_GetRawCharsAlloc(realPathp, -1);
7316 osi_Log1(smb_logp, "NTCreateX rejecting invalid name. [%S]",
7317 osi_LogSaveClientString(smb_logp, hexp));
7321 osi_Log0(smb_logp, "NTCreateX rejecting invalid name");
7324 return CM_ERROR_BADNTFILENAME;
7327 userp = smb_GetUserFromVCP(vcp, inp);
7329 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
7331 return CM_ERROR_INVAL;
7334 if (baseFidp != 0) {
7335 baseFidp = smb_FindFID(vcp, baseFid, 0);
7337 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
7338 cm_ReleaseUser(userp);
7340 return CM_ERROR_INVAL;
7343 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7345 smb_CloseFID(vcp, baseFidp, NULL, 0);
7346 smb_ReleaseFID(baseFidp);
7347 cm_ReleaseUser(userp);
7348 return CM_ERROR_NOSUCHPATH;
7351 baseDirp = baseFidp->scp;
7355 /* compute open mode */
7357 if (desiredAccess & DELETE)
7358 fidflags |= SMB_FID_OPENDELETE;
7359 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
7360 fidflags |= SMB_FID_OPENREAD_LISTDIR;
7361 if (desiredAccess & AFS_ACCESS_WRITE)
7362 fidflags |= SMB_FID_OPENWRITE;
7363 if (createOptions & FILE_DELETE_ON_CLOSE)
7364 fidflags |= SMB_FID_DELONCLOSE;
7365 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7366 fidflags |= SMB_FID_SEQUENTIAL;
7367 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7368 fidflags |= SMB_FID_RANDOM;
7369 if (createOptions & FILE_OPEN_REPARSE_POINT)
7370 osi_Log0(smb_logp, "NTCreateX Open Reparse Point");
7371 if (smb_IsExecutableFileName(lastNamep))
7372 fidflags |= SMB_FID_EXECUTABLE;
7374 /* and the share mode */
7375 if (shareAccess & FILE_SHARE_READ)
7376 fidflags |= SMB_FID_SHARE_READ;
7377 if (shareAccess & FILE_SHARE_WRITE)
7378 fidflags |= SMB_FID_SHARE_WRITE;
7380 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
7383 /* For an exclusive create, we want to do a case sensitive match for the last component. */
7384 if ( createDisp == FILE_CREATE ||
7385 createDisp == FILE_OVERWRITE ||
7386 createDisp == FILE_OVERWRITE_IF) {
7387 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7388 userp, tidPathp, &req, &dscp);
7391 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7392 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7394 cm_ReleaseSCache(dscp);
7395 cm_ReleaseUser(userp);
7398 smb_ReleaseFID(baseFidp);
7399 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7400 return CM_ERROR_PATH_NOT_COVERED;
7402 return CM_ERROR_NOSUCHPATH;
7404 #endif /* DFS_SUPPORT */
7405 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7407 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7408 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7409 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7410 if (code == 0 && realDirFlag == 1) {
7411 cm_ReleaseSCache(scp);
7412 cm_ReleaseSCache(dscp);
7413 cm_ReleaseUser(userp);
7416 smb_ReleaseFID(baseFidp);
7417 return CM_ERROR_EXISTS;
7421 /* we have both scp and dscp */
7423 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7424 userp, tidPathp, &req, &scp);
7426 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7427 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7428 cm_ReleaseSCache(scp);
7429 cm_ReleaseUser(userp);
7432 smb_ReleaseFID(baseFidp);
7433 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7434 return CM_ERROR_PATH_NOT_COVERED;
7436 return CM_ERROR_NOSUCHPATH;
7438 #endif /* DFS_SUPPORT */
7439 /* we might have scp but not dscp */
7445 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7446 /* look up parent directory */
7447 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
7448 * the immediate parent. We have to work our way up realPathp until we hit something that we
7452 /* we might or might not have scp */
7458 code = cm_NameI(baseDirp, spacep->wdata,
7459 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7460 userp, tidPathp, &req, &dscp);
7463 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7464 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7467 cm_ReleaseSCache(scp);
7468 cm_ReleaseSCache(dscp);
7469 cm_ReleaseUser(userp);
7472 smb_ReleaseFID(baseFidp);
7473 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7474 return CM_ERROR_PATH_NOT_COVERED;
7476 return CM_ERROR_NOSUCHPATH;
7478 #endif /* DFS_SUPPORT */
7481 (tp = cm_ClientStrRChr(spacep->wdata, '\\')) &&
7482 (createDisp == FILE_CREATE) &&
7483 (realDirFlag == 1)) {
7486 treeStartp = realPathp + (tp - spacep->wdata);
7488 if (*tp && !smb_IsLegalFilename(tp)) {
7489 cm_ReleaseUser(userp);
7491 smb_ReleaseFID(baseFidp);
7494 cm_ReleaseSCache(scp);
7495 return CM_ERROR_BADNTFILENAME;
7499 } while (dscp == NULL && code == 0);
7503 /* we might have scp and we might have dscp */
7506 smb_ReleaseFID(baseFidp);
7509 osi_Log0(smb_logp,"NTCreateX parent not found");
7511 cm_ReleaseSCache(scp);
7513 cm_ReleaseSCache(dscp);
7514 cm_ReleaseUser(userp);
7519 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
7520 /* A file exists where we want a directory. */
7522 cm_ReleaseSCache(scp);
7523 cm_ReleaseSCache(dscp);
7524 cm_ReleaseUser(userp);
7526 return CM_ERROR_EXISTS;
7530 lastNamep = realPathp;
7534 if (!smb_IsLegalFilename(lastNamep)) {
7536 cm_ReleaseSCache(scp);
7538 cm_ReleaseSCache(dscp);
7539 cm_ReleaseUser(userp);
7541 return CM_ERROR_BADNTFILENAME;
7544 if (!foundscp && !treeCreate) {
7545 if ( createDisp == FILE_CREATE ||
7546 createDisp == FILE_OVERWRITE ||
7547 createDisp == FILE_OVERWRITE_IF)
7549 code = cm_Lookup(dscp, lastNamep,
7550 CM_FLAG_FOLLOW, userp, &req, &scp);
7552 code = cm_Lookup(dscp, lastNamep,
7553 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7556 if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
7558 cm_ReleaseSCache(dscp);
7559 cm_ReleaseUser(userp);
7564 /* we have scp and dscp */
7566 /* we have scp but not dscp */
7568 smb_ReleaseFID(baseFidp);
7571 /* if we get here, if code is 0, the file exists and is represented by
7572 * scp. Otherwise, we have to create it. The dir may be represented
7573 * by dscp, or we may have found the file directly. If code is non-zero,
7576 if (code == 0 && !treeCreate) {
7577 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7579 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7581 cm_ReleaseSCache(dscp);
7583 cm_ReleaseSCache(scp);
7584 cm_ReleaseUser(userp);
7588 checkDoneRequired = 1;
7590 if (createDisp == FILE_CREATE) {
7591 /* oops, file shouldn't be there */
7592 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7594 cm_ReleaseSCache(dscp);
7596 cm_ReleaseSCache(scp);
7597 cm_ReleaseUser(userp);
7599 return CM_ERROR_EXISTS;
7602 if ( createDisp == FILE_OVERWRITE ||
7603 createDisp == FILE_OVERWRITE_IF) {
7605 setAttr.mask = CM_ATTRMASK_LENGTH;
7606 setAttr.length.LowPart = 0;
7607 setAttr.length.HighPart = 0;
7608 /* now watch for a symlink */
7610 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7612 osi_assertx(dscp != NULL, "null cm_scache_t");
7613 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7615 /* we have a more accurate file to use (the
7616 * target of the symbolic link). Otherwise,
7617 * we'll just use the symlink anyway.
7619 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7621 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7622 cm_ReleaseSCache(scp);
7624 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7626 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7628 cm_ReleaseSCache(dscp);
7630 cm_ReleaseSCache(scp);
7631 cm_ReleaseUser(userp);
7637 code = cm_SetAttr(scp, &setAttr, userp, &req);
7638 openAction = 3; /* truncated existing file */
7641 openAction = 1; /* found existing file */
7643 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7644 /* don't create if not found */
7646 cm_ReleaseSCache(dscp);
7648 cm_ReleaseSCache(scp);
7649 cm_ReleaseUser(userp);
7651 return CM_ERROR_NOSUCHFILE;
7652 } else if (realDirFlag == 0 || realDirFlag == -1) {
7653 osi_assertx(dscp != NULL, "null cm_scache_t");
7654 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %S",
7655 osi_LogSaveClientString(smb_logp, lastNamep));
7656 openAction = 2; /* created file */
7657 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7658 setAttr.clientModTime = time(NULL);
7659 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
7662 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7663 smb_NotifyChange(FILE_ACTION_ADDED,
7664 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7665 dscp, lastNamep, NULL, TRUE);
7666 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7667 /* Not an exclusive create, and someone else tried
7668 * creating it already, then we open it anyway. We
7669 * don't bother retrying after this, since if this next
7670 * fails, that means that the file was deleted after we
7671 * started this call.
7673 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7676 if (createDisp == FILE_OVERWRITE_IF) {
7677 setAttr.mask = CM_ATTRMASK_LENGTH;
7678 setAttr.length.LowPart = 0;
7679 setAttr.length.HighPart = 0;
7681 /* now watch for a symlink */
7683 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7685 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7687 /* we have a more accurate file to use (the
7688 * target of the symbolic link). Otherwise,
7689 * we'll just use the symlink anyway.
7691 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7693 cm_ReleaseSCache(scp);
7697 code = cm_SetAttr(scp, &setAttr, userp, &req);
7699 } /* lookup succeeded */
7702 clientchar_t *tp, *pp;
7703 clientchar_t *cp; /* This component */
7704 int clen = 0; /* length of component */
7705 cm_scache_t *tscp1, *tscp2;
7708 /* create directory */
7710 treeStartp = lastNamep;
7711 osi_assertx(dscp != NULL, "null cm_scache_t");
7712 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%S]",
7713 osi_LogSaveClientString(smb_logp, treeStartp));
7714 openAction = 2; /* created directory */
7716 /* if the request is to create the root directory
7717 * it will appear as a directory name of the nul-string
7718 * and a code of CM_ERROR_NOSUCHFILE
7720 if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
7721 code = CM_ERROR_EXISTS;
7723 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7724 setAttr.clientModTime = time(NULL);
7729 cm_HoldSCache(tscp1);
7733 tp = cm_ClientStrChr(pp, '\\');
7735 cm_ClientStrCpy(cp, lengthof(spacep->wdata) - (cp - spacep->wdata), pp);
7736 clen = (int)cm_ClientStrLen(cp);
7737 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
7739 clen = (int)(tp - pp);
7740 cm_ClientStrCpyN(cp, lengthof(spacep->wdata) - (cp - spacep->wdata),
7748 continue; /* the supplied path can't have consecutive slashes either , but */
7750 /* cp is the next component to be created. */
7751 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req, NULL);
7752 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
7753 smb_NotifyChange(FILE_ACTION_ADDED,
7754 FILE_NOTIFY_CHANGE_DIR_NAME,
7755 tscp1, cp, NULL, TRUE);
7757 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7758 /* Not an exclusive create, and someone else tried
7759 * creating it already, then we open it anyway. We
7760 * don't bother retrying after this, since if this next
7761 * fails, that means that the file was deleted after we
7762 * started this call.
7764 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
7765 userp, &req, &tscp2);
7770 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
7771 cm_ReleaseSCache(tscp1);
7772 tscp1 = tscp2; /* Newly created directory will be next parent */
7773 /* the hold is transfered to tscp1 from tscp2 */
7778 cm_ReleaseSCache(dscp);
7781 cm_ReleaseSCache(scp);
7784 * if we get here and code == 0, then scp is the last directory created, and dscp is the
7790 /* something went wrong creating or truncating the file */
7791 if (checkDoneRequired)
7792 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7794 cm_ReleaseSCache(scp);
7796 cm_ReleaseSCache(dscp);
7797 cm_ReleaseUser(userp);
7802 /* make sure we have file vs. dir right (only applies for single component case) */
7803 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7804 /* now watch for a symlink */
7806 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7807 cm_scache_t * targetScp = 0;
7808 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7810 /* we have a more accurate file to use (the
7811 * target of the symbolic link). Otherwise,
7812 * we'll just use the symlink anyway.
7814 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
7815 if (checkDoneRequired) {
7816 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7817 checkDoneRequired = 0;
7819 cm_ReleaseSCache(scp);
7824 if (scp->fileType != CM_SCACHETYPE_FILE) {
7825 if (checkDoneRequired)
7826 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7828 cm_ReleaseSCache(dscp);
7829 cm_ReleaseSCache(scp);
7830 cm_ReleaseUser(userp);
7832 return CM_ERROR_ISDIR;
7836 /* (only applies to single component case) */
7837 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7838 if (checkDoneRequired)
7839 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7840 cm_ReleaseSCache(scp);
7842 cm_ReleaseSCache(dscp);
7843 cm_ReleaseUser(userp);
7845 return CM_ERROR_NOTDIR;
7848 /* open the file itself */
7849 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7850 osi_assertx(fidp, "null smb_fid_t");
7852 /* save a reference to the user */
7854 fidp->userp = userp;
7856 /* If we are restricting sharing, we should do so with a suitable
7858 if (scp->fileType == CM_SCACHETYPE_FILE &&
7859 !(fidflags & SMB_FID_SHARE_WRITE)) {
7861 LARGE_INTEGER LOffset, LLength;
7864 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7865 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7866 LLength.HighPart = 0;
7867 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7869 /* If we are not opening the file for writing, then we don't
7870 try to get an exclusive lock. No one else should be able to
7871 get an exclusive lock on the file anyway, although someone
7872 else can get a shared lock. */
7873 if ((fidflags & SMB_FID_SHARE_READ) ||
7874 !(fidflags & SMB_FID_OPENWRITE)) {
7875 sLockType = LOCKING_ANDX_SHARED_LOCK;
7880 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7882 lock_ObtainWrite(&scp->rw);
7883 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7884 lock_ReleaseWrite(&scp->rw);
7887 if (checkDoneRequired)
7888 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7889 cm_ReleaseSCache(scp);
7891 cm_ReleaseSCache(dscp);
7892 cm_ReleaseUser(userp);
7893 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7894 smb_CloseFID(vcp, fidp, NULL, 0);
7895 smb_ReleaseFID(fidp);
7901 /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
7902 if (checkDoneRequired) {
7903 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7904 checkDoneRequired = 0;
7907 lock_ObtainMutex(&fidp->mx);
7908 /* save a pointer to the vnode */
7909 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
7910 lock_ObtainWrite(&scp->rw);
7911 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7912 lock_ReleaseWrite(&scp->rw);
7913 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
7915 fidp->flags = fidflags;
7917 /* remember if the file was newly created */
7919 fidp->flags |= SMB_FID_CREATED;
7921 /* save parent dir and pathname for delete or change notification */
7922 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7923 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
7924 fidp->flags |= SMB_FID_NTOPEN;
7925 fidp->NTopen_dscp = dscp;
7927 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
7929 fidp->NTopen_wholepathp = realPathp;
7930 lock_ReleaseMutex(&fidp->mx);
7932 /* we don't need this any longer */
7934 cm_ReleaseSCache(dscp);
7938 cm_Open(scp, 0, userp);
7940 /* set inp->fid so that later read calls in same msg can find fid */
7941 inp->fid = fidp->fid;
7943 lock_ObtainRead(&scp->rw);
7946 * Always send the standard response. Sending the extended
7947 * response results in the Explorer Shell being unable to
7948 * access directories at random times.
7950 if (1 /*!extendedRespRequired */) {
7953 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7954 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7955 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7956 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7957 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7958 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7959 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7960 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7961 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7963 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7964 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7965 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
7966 smb_SetSMBParm(outp, parmSlot, NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS);
7967 parmSlot++; /* dev state */
7968 smb_SetSMBParmByte(outp, parmSlot,
7969 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7970 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7971 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7972 smb_SetSMBDataLength(outp, 0);
7976 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7977 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7978 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7979 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7980 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7981 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7982 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7983 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7984 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7986 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7987 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7988 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
7989 smb_SetSMBParm(outp, parmSlot, NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS);
7990 parmSlot++; /* dev state */
7991 smb_SetSMBParmByte(outp, parmSlot,
7992 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7993 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7994 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7995 /* Setting the GUID results in a failure with cygwin */
7996 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7997 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7998 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7999 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8000 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8001 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8002 /* Maxmimal access rights */
8003 smb_SetSMBParmLong(outp, parmSlot, 0x001f01ff); parmSlot += 2;
8004 /* Guest access rights */
8005 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8006 smb_SetSMBDataLength(outp, 0);
8009 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
8010 LargeIntegerGreaterThanZero(scp->length) &&
8011 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
8014 lock_ReleaseRead(&scp->rw);
8017 cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
8018 scp->length.LowPart, scp->length.HighPart,
8022 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %S", fidp->fid,
8023 osi_LogSaveClientString(smb_logp, realPathp));
8025 cm_ReleaseUser(userp);
8026 smb_ReleaseFID(fidp);
8028 /* Can't free realPathp if we get here since
8029 fidp->NTopen_wholepathp is pointing there */
8031 /* leave scp held since we put it in fidp->scp */
8036 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
8037 * Instead, ultimately, would like to use a subroutine for common code.
8040 /* NT_TRANSACT_CREATE (SMB_COM_NT_TRANSACT) */
8041 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8043 clientchar_t *pathp, *realPathp;
8047 cm_scache_t *dscp; /* parent dir */
8048 cm_scache_t *scp; /* file to create or open */
8049 cm_scache_t *targetScp; /* if scp is a symlink */
8051 clientchar_t *lastNamep;
8052 unsigned long nameLength;
8054 unsigned int requestOpLock;
8055 unsigned int requestBatchOpLock;
8056 unsigned int mustBeDir;
8057 unsigned int extendedRespRequired;
8059 unsigned int desiredAccess;
8060 unsigned int allocSize;
8061 unsigned int shareAccess;
8062 unsigned int extAttributes;
8063 unsigned int createDisp;
8066 unsigned int impLevel;
8067 unsigned int secFlags;
8068 unsigned int createOptions;
8069 int initialModeBits;
8070 unsigned short baseFid;
8071 smb_fid_t *baseFidp;
8073 cm_scache_t *baseDirp;
8074 unsigned short openAction;
8078 clientchar_t *tidPathp;
8080 int parmOffset, dataOffset;
8087 cm_lock_data_t *ldp = NULL;
8088 int checkDoneRequired = 0;
8095 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8096 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8097 parmp = inp->data + parmOffset;
8098 lparmp = (ULONG *) parmp;
8101 requestOpLock = flags & REQUEST_OPLOCK;
8102 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
8103 mustBeDir = flags & OPEN_DIRECTORY;
8104 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
8107 * Why all of a sudden 32-bit FID?
8108 * We will reject all bits higher than 16.
8110 if (lparmp[1] & 0xFFFF0000)
8111 return CM_ERROR_INVAL;
8112 baseFid = (unsigned short)lparmp[1];
8113 desiredAccess = lparmp[2];
8114 allocSize = lparmp[3];
8115 extAttributes = lparmp[5];
8116 shareAccess = lparmp[6];
8117 createDisp = lparmp[7];
8118 createOptions = lparmp[8];
8121 nameLength = lparmp[11]; /* spec says chars but appears to be bytes */
8122 impLevel = lparmp[12];
8123 secFlags = lparmp[13];
8125 /* mustBeDir is never set; createOptions directory bit seems to be
8128 if (createOptions & FILE_DIRECTORY_FILE)
8130 else if (createOptions & FILE_NON_DIRECTORY_FILE)
8136 * compute initial mode bits based on read-only flag in
8137 * extended attributes
8139 initialModeBits = 0666;
8140 if (extAttributes & SMB_ATTR_READONLY)
8141 initialModeBits &= ~0222;
8143 pathp = smb_ParseStringCb(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
8144 nameLength, NULL, SMB_STRF_ANSIPATH);
8145 /* Sometimes path is not nul-terminated, so we make a copy. */
8146 realPathp = malloc(nameLength+sizeof(clientchar_t));
8147 memcpy(realPathp, pathp, nameLength);
8148 realPathp[nameLength/sizeof(clientchar_t)] = 0;
8149 spacep = cm_GetSpace();
8150 /* smb_StripLastComponent will strip "::$DATA" if present */
8151 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
8153 osi_Log1(smb_logp,"NTTranCreate %S",osi_LogSaveStringW(smb_logp,realPathp));
8154 osi_Log4(smb_logp,"... da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
8155 osi_Log4(smb_logp,"... co[%x],sdl[%x],eal[%x],as[%x],flags[%x]",createOptions,sdLen,eaLen,allocSize);
8156 osi_Log3(smb_logp,"... imp[%x],sec[%x],flags[%x]", impLevel, secFlags, flags);
8159 * Nothing here to handle SMB_IOCTL_FILENAME.
8160 * Will add it if necessary.
8163 if (!cm_IsValidClientString(realPathp)) {
8165 clientchar_t * hexp;
8167 hexp = cm_GetRawCharsAlloc(realPathp, -1);
8168 osi_Log1(smb_logp, "NTTranCreate rejecting invalid name. [%S]",
8169 osi_LogSaveClientString(smb_logp, hexp));
8173 osi_Log0(smb_logp, "NTTranCreate rejecting invalid name.");
8176 return CM_ERROR_BADNTFILENAME;
8179 userp = smb_GetUserFromVCP(vcp, inp);
8181 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
8183 return CM_ERROR_INVAL;
8188 baseDirp = cm_data.rootSCachep;
8189 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8190 if (code == CM_ERROR_TIDIPC) {
8191 /* Attempt to use a TID allocated for IPC. The client
8192 * is probably looking for DCE RPC end points which we
8193 * don't support OR it could be looking to make a DFS
8196 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
8199 cm_ReleaseUser(userp);
8200 return CM_ERROR_NOSUCHPATH;
8204 baseFidp = smb_FindFID(vcp, baseFid, 0);
8206 osi_Log2(smb_logp, "NTTranCreate Unknown SMB Fid vcp 0x%p fid %d",
8209 cm_ReleaseUser(userp);
8210 return CM_ERROR_BADFD;
8213 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8215 cm_ReleaseUser(userp);
8216 smb_CloseFID(vcp, baseFidp, NULL, 0);
8217 smb_ReleaseFID(baseFidp);
8218 return CM_ERROR_NOSUCHPATH;
8221 baseDirp = baseFidp->scp;
8225 /* compute open mode */
8227 if (desiredAccess & DELETE)
8228 fidflags |= SMB_FID_OPENDELETE;
8229 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
8230 fidflags |= SMB_FID_OPENREAD_LISTDIR;
8231 if (desiredAccess & AFS_ACCESS_WRITE)
8232 fidflags |= SMB_FID_OPENWRITE;
8233 if (createOptions & FILE_DELETE_ON_CLOSE)
8234 fidflags |= SMB_FID_DELONCLOSE;
8235 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
8236 fidflags |= SMB_FID_SEQUENTIAL;
8237 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
8238 fidflags |= SMB_FID_RANDOM;
8239 if (createOptions & FILE_OPEN_REPARSE_POINT)
8240 osi_Log0(smb_logp, "NTTranCreate Open Reparse Point");
8241 if (smb_IsExecutableFileName(lastNamep))
8242 fidflags |= SMB_FID_EXECUTABLE;
8244 /* And the share mode */
8245 if (shareAccess & FILE_SHARE_READ)
8246 fidflags |= SMB_FID_SHARE_READ;
8247 if (shareAccess & FILE_SHARE_WRITE)
8248 fidflags |= SMB_FID_SHARE_WRITE;
8252 if ( createDisp == FILE_OPEN ||
8253 createDisp == FILE_OVERWRITE ||
8254 createDisp == FILE_OVERWRITE_IF) {
8255 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8256 userp, tidPathp, &req, &dscp);
8259 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8260 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8261 cm_ReleaseSCache(dscp);
8262 cm_ReleaseUser(userp);
8265 smb_ReleaseFID(baseFidp);
8266 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8267 return CM_ERROR_PATH_NOT_COVERED;
8269 return CM_ERROR_NOSUCHPATH;
8271 #endif /* DFS_SUPPORT */
8272 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
8274 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
8275 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
8276 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
8277 if (code == 0 && realDirFlag == 1) {
8278 cm_ReleaseSCache(scp);
8279 cm_ReleaseSCache(dscp);
8280 cm_ReleaseUser(userp);
8283 smb_ReleaseFID(baseFidp);
8284 return CM_ERROR_EXISTS;
8290 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8291 userp, tidPathp, &req, &scp);
8293 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
8294 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
8295 cm_ReleaseSCache(scp);
8296 cm_ReleaseUser(userp);
8299 smb_ReleaseFID(baseFidp);
8300 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8301 return CM_ERROR_PATH_NOT_COVERED;
8303 return CM_ERROR_NOSUCHPATH;
8305 #endif /* DFS_SUPPORT */
8311 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
8312 /* look up parent directory */
8314 code = cm_NameI(baseDirp, spacep->wdata,
8315 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8316 userp, tidPathp, &req, &dscp);
8318 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8319 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8320 cm_ReleaseSCache(dscp);
8321 cm_ReleaseUser(userp);
8324 smb_ReleaseFID(baseFidp);
8325 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8326 return CM_ERROR_PATH_NOT_COVERED;
8328 return CM_ERROR_NOSUCHPATH;
8330 #endif /* DFS_SUPPORT */
8334 cm_FreeSpace(spacep);
8337 smb_ReleaseFID(baseFidp);
8340 cm_ReleaseUser(userp);
8346 lastNamep = realPathp;
8350 if (!smb_IsLegalFilename(lastNamep))
8351 return CM_ERROR_BADNTFILENAME;
8354 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
8355 code = cm_Lookup(dscp, lastNamep,
8356 CM_FLAG_FOLLOW, userp, &req, &scp);
8358 code = cm_Lookup(dscp, lastNamep,
8359 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8362 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8363 cm_ReleaseSCache(dscp);
8364 cm_ReleaseUser(userp);
8371 smb_ReleaseFID(baseFidp);
8372 cm_FreeSpace(spacep);
8375 /* if we get here, if code is 0, the file exists and is represented by
8376 * scp. Otherwise, we have to create it. The dir may be represented
8377 * by dscp, or we may have found the file directly. If code is non-zero,
8381 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
8383 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8385 cm_ReleaseSCache(dscp);
8386 cm_ReleaseSCache(scp);
8387 cm_ReleaseUser(userp);
8391 checkDoneRequired = 1;
8393 if (createDisp == FILE_CREATE) {
8394 /* oops, file shouldn't be there */
8395 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8397 cm_ReleaseSCache(dscp);
8398 cm_ReleaseSCache(scp);
8399 cm_ReleaseUser(userp);
8401 return CM_ERROR_EXISTS;
8404 if (createDisp == FILE_OVERWRITE ||
8405 createDisp == FILE_OVERWRITE_IF) {
8406 setAttr.mask = CM_ATTRMASK_LENGTH;
8407 setAttr.length.LowPart = 0;
8408 setAttr.length.HighPart = 0;
8410 /* now watch for a symlink */
8412 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8414 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8416 /* we have a more accurate file to use (the
8417 * target of the symbolic link). Otherwise,
8418 * we'll just use the symlink anyway.
8420 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8422 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8423 cm_ReleaseSCache(scp);
8425 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
8427 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8429 cm_ReleaseSCache(dscp);
8431 cm_ReleaseSCache(scp);
8432 cm_ReleaseUser(userp);
8438 code = cm_SetAttr(scp, &setAttr, userp, &req);
8439 openAction = 3; /* truncated existing file */
8441 else openAction = 1; /* found existing file */
8443 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
8444 /* don't create if not found */
8446 cm_ReleaseSCache(dscp);
8447 cm_ReleaseUser(userp);
8449 return CM_ERROR_NOSUCHFILE;
8451 else if (realDirFlag == 0 || realDirFlag == -1) {
8452 osi_assertx(dscp != NULL, "null cm_scache_t");
8453 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %S",
8454 osi_LogSaveClientString(smb_logp, lastNamep));
8455 openAction = 2; /* created file */
8456 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8457 setAttr.clientModTime = time(NULL);
8458 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8462 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8463 smb_NotifyChange(FILE_ACTION_ADDED,
8464 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8465 dscp, lastNamep, NULL, TRUE);
8466 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
8467 /* Not an exclusive create, and someone else tried
8468 * creating it already, then we open it anyway. We
8469 * don't bother retrying after this, since if this next
8470 * fails, that means that the file was deleted after we
8471 * started this call.
8473 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8476 if (createDisp == FILE_OVERWRITE_IF) {
8477 setAttr.mask = CM_ATTRMASK_LENGTH;
8478 setAttr.length.LowPart = 0;
8479 setAttr.length.HighPart = 0;
8481 /* now watch for a symlink */
8483 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8485 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8487 /* we have a more accurate file to use (the
8488 * target of the symbolic link). Otherwise,
8489 * we'll just use the symlink anyway.
8491 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8493 cm_ReleaseSCache(scp);
8497 code = cm_SetAttr(scp, &setAttr, userp, &req);
8499 } /* lookup succeeded */
8502 /* create directory */
8503 osi_assertx(dscp != NULL, "null cm_scache_t");
8505 "smb_ReceiveNTTranCreate creating directory %S",
8506 osi_LogSaveClientString(smb_logp, lastNamep));
8507 openAction = 2; /* created directory */
8508 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8509 setAttr.clientModTime = time(NULL);
8510 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8511 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8512 smb_NotifyChange(FILE_ACTION_ADDED,
8513 FILE_NOTIFY_CHANGE_DIR_NAME,
8514 dscp, lastNamep, NULL, TRUE);
8516 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
8517 /* Not an exclusive create, and someone else tried
8518 * creating it already, then we open it anyway. We
8519 * don't bother retrying after this, since if this next
8520 * fails, that means that the file was deleted after we
8521 * started this call.
8523 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8529 /* something went wrong creating or truncating the file */
8530 if (checkDoneRequired)
8531 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8533 cm_ReleaseSCache(scp);
8534 cm_ReleaseUser(userp);
8539 /* make sure we have file vs. dir right */
8540 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
8541 /* now watch for a symlink */
8543 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8545 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8547 /* we have a more accurate file to use (the
8548 * target of the symbolic link). Otherwise,
8549 * we'll just use the symlink anyway.
8551 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8553 if (checkDoneRequired) {
8554 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8555 checkDoneRequired = 0;
8557 cm_ReleaseSCache(scp);
8562 if (scp->fileType != CM_SCACHETYPE_FILE) {
8563 if (checkDoneRequired)
8564 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8565 cm_ReleaseSCache(scp);
8566 cm_ReleaseUser(userp);
8568 return CM_ERROR_ISDIR;
8572 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8573 if (checkDoneRequired)
8574 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8575 cm_ReleaseSCache(scp);
8576 cm_ReleaseUser(userp);
8578 return CM_ERROR_NOTDIR;
8581 /* open the file itself */
8582 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8583 osi_assertx(fidp, "null smb_fid_t");
8585 /* save a reference to the user */
8587 fidp->userp = userp;
8589 /* If we are restricting sharing, we should do so with a suitable
8591 if (scp->fileType == CM_SCACHETYPE_FILE &&
8592 !(fidflags & SMB_FID_SHARE_WRITE)) {
8594 LARGE_INTEGER LOffset, LLength;
8597 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8598 LOffset.LowPart = SMB_FID_QLOCK_LOW;
8599 LLength.HighPart = 0;
8600 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8602 /* Similar to what we do in handling NTCreateX. We get a
8603 shared lock if we are only opening the file for reading. */
8604 if ((fidflags & SMB_FID_SHARE_READ) ||
8605 !(fidflags & SMB_FID_OPENWRITE)) {
8606 sLockType = LOCKING_ANDX_SHARED_LOCK;
8611 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8613 lock_ObtainWrite(&scp->rw);
8614 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8615 lock_ReleaseWrite(&scp->rw);
8618 if (checkDoneRequired)
8619 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8620 cm_ReleaseSCache(scp);
8621 cm_ReleaseUser(userp);
8622 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
8623 smb_CloseFID(vcp, fidp, NULL, 0);
8624 smb_ReleaseFID(fidp);
8626 return CM_ERROR_SHARING_VIOLATION;
8630 /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
8631 if (checkDoneRequired) {
8632 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8633 checkDoneRequired = 0;
8636 lock_ObtainMutex(&fidp->mx);
8637 /* save a pointer to the vnode */
8639 lock_ObtainWrite(&scp->rw);
8640 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8641 lock_ReleaseWrite(&scp->rw);
8642 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
8644 fidp->flags = fidflags;
8646 /* remember if the file was newly created */
8648 fidp->flags |= SMB_FID_CREATED;
8650 /* save parent dir and pathname for deletion or change notification */
8651 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8652 fidp->flags |= SMB_FID_NTOPEN;
8653 fidp->NTopen_dscp = dscp;
8654 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
8656 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
8658 fidp->NTopen_wholepathp = realPathp;
8659 lock_ReleaseMutex(&fidp->mx);
8661 /* we don't need this any longer */
8663 cm_ReleaseSCache(dscp);
8665 cm_Open(scp, 0, userp);
8667 /* set inp->fid so that later read calls in same msg can find fid */
8668 inp->fid = fidp->fid;
8670 /* check whether we are required to send an extended response */
8671 if (!extendedRespRequired) {
8673 parmOffset = 8*4 + 39;
8674 parmOffset += 1; /* pad to 4 */
8675 dataOffset = parmOffset + 70;
8679 /* Total Parameter Count */
8680 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8681 /* Total Data Count */
8682 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8683 /* Parameter Count */
8684 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8685 /* Parameter Offset */
8686 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8687 /* Parameter Displacement */
8688 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8690 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8692 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8693 /* Data Displacement */
8694 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8695 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8696 smb_SetSMBDataLength(outp, 70);
8698 lock_ObtainRead(&scp->rw);
8699 outData = smb_GetSMBData(outp, NULL);
8700 outData++; /* round to get to parmOffset */
8701 *outData = 0; outData++; /* oplock */
8702 *outData = 0; outData++; /* reserved */
8703 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8704 *((ULONG *)outData) = openAction; outData += 4;
8705 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8706 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8707 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8708 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8709 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8710 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8711 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8712 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8713 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8714 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8715 *((USHORT *)outData) = NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS;
8716 outData += 2; /* dev state */
8717 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8718 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8719 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8720 outData += 2; /* is a dir? */
8723 parmOffset = 8*4 + 39;
8724 parmOffset += 1; /* pad to 4 */
8725 dataOffset = parmOffset + 104;
8729 /* Total Parameter Count */
8730 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8731 /* Total Data Count */
8732 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8733 /* Parameter Count */
8734 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8735 /* Parameter Offset */
8736 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8737 /* Parameter Displacement */
8738 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8740 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8742 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8743 /* Data Displacement */
8744 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8745 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8746 smb_SetSMBDataLength(outp, 105);
8748 lock_ObtainRead(&scp->rw);
8749 outData = smb_GetSMBData(outp, NULL);
8750 outData++; /* round to get to parmOffset */
8751 *outData = 0; outData++; /* oplock */
8752 *outData = 1; outData++; /* response type */
8753 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8754 *((ULONG *)outData) = openAction; outData += 4;
8755 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8756 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8757 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8758 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8759 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8760 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8761 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8762 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8763 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8764 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8765 *((USHORT *)outData) = NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS;
8766 outData += 2; /* dev state */
8767 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8768 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8769 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8770 outData += 1; /* is a dir? */
8771 /* Setting the GUID results in failures with cygwin */
8772 memset(outData,0,24); outData += 24; /* GUID */
8773 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
8774 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
8777 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
8778 LargeIntegerGreaterThanZero(scp->length) &&
8779 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
8782 lock_ReleaseRead(&scp->rw);
8785 cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
8786 scp->length.LowPart, scp->length.HighPart,
8789 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
8791 cm_ReleaseUser(userp);
8792 smb_ReleaseFID(fidp);
8794 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
8795 /* leave scp held since we put it in fidp->scp */
8799 /* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
8800 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
8803 smb_packet_t *savedPacketp;
8805 USHORT fid, watchtree;
8809 filter = smb_GetSMBParm(inp, 19) |
8810 (smb_GetSMBParm(inp, 20) << 16);
8811 fid = smb_GetSMBParm(inp, 21);
8812 watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
8814 fidp = smb_FindFID(vcp, fid, 0);
8816 osi_Log2(smb_logp, "NotifyChange Unknown SMB Fid vcp 0x%p fid %d",
8818 return CM_ERROR_BADFD;
8821 lock_ObtainMutex(&fidp->mx);
8822 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8823 lock_ReleaseMutex(&fidp->mx);
8824 smb_CloseFID(vcp, fidp, NULL, 0);
8825 smb_ReleaseFID(fidp);
8826 return CM_ERROR_NOSUCHFILE;
8830 lock_ReleaseMutex(&fidp->mx);
8832 /* Create a copy of the Directory Watch Packet to use when sending the
8833 * notification if in the future a matching change is detected.
8835 savedPacketp = smb_CopyPacket(inp);
8836 if (vcp != savedPacketp->vcp) {
8838 if (savedPacketp->vcp)
8839 smb_ReleaseVC(savedPacketp->vcp);
8840 savedPacketp->vcp = vcp;
8843 /* Add the watch to the list of events to send notifications for */
8844 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8845 savedPacketp->nextp = smb_Directory_Watches;
8846 smb_Directory_Watches = savedPacketp;
8847 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8849 osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%S\"",
8850 fidp, scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp));
8851 osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
8852 filter, fid, watchtree);
8853 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8854 osi_Log0(smb_logp, " Notify Change File Name");
8855 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8856 osi_Log0(smb_logp, " Notify Change Directory Name");
8857 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8858 osi_Log0(smb_logp, " Notify Change Attributes");
8859 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8860 osi_Log0(smb_logp, " Notify Change Size");
8861 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8862 osi_Log0(smb_logp, " Notify Change Last Write");
8863 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8864 osi_Log0(smb_logp, " Notify Change Last Access");
8865 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8866 osi_Log0(smb_logp, " Notify Change Creation");
8867 if (filter & FILE_NOTIFY_CHANGE_EA)
8868 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8869 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8870 osi_Log0(smb_logp, " Notify Change Security");
8871 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8872 osi_Log0(smb_logp, " Notify Change Stream Name");
8873 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8874 osi_Log0(smb_logp, " Notify Change Stream Size");
8875 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8876 osi_Log0(smb_logp, " Notify Change Stream Write");
8878 lock_ObtainWrite(&scp->rw);
8880 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
8882 scp->flags |= CM_SCACHEFLAG_WATCHED;
8883 lock_ReleaseWrite(&scp->rw);
8884 cm_ReleaseSCache(scp);
8885 smb_ReleaseFID(fidp);
8887 outp->flags |= SMB_PACKETFLAG_NOSEND;
8891 unsigned char nullSecurityDesc[36] = {
8892 0x01, /* security descriptor revision */
8893 0x00, /* reserved, should be zero */
8894 0x00, 0x80, /* security descriptor control;
8895 * 0x8000 : self-relative format */
8896 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
8897 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
8898 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
8899 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
8900 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8901 /* "null SID" owner SID */
8902 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
8903 /* "null SID" group SID */
8906 /* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
8907 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8909 int parmOffset, parmCount, dataOffset, dataCount;
8917 ULONG securityInformation;
8919 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8920 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8921 parmp = inp->data + parmOffset;
8922 sparmp = (USHORT *) parmp;
8923 lparmp = (ULONG *) parmp;
8926 securityInformation = lparmp[1];
8928 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
8929 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
8937 parmOffset = 8*4 + 39;
8938 parmOffset += 1; /* pad to 4 */
8940 dataOffset = parmOffset + parmCount;
8944 /* Total Parameter Count */
8945 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8946 /* Total Data Count */
8947 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8948 /* Parameter Count */
8949 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8950 /* Parameter Offset */
8951 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8952 /* Parameter Displacement */
8953 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8955 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8957 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8958 /* Data Displacement */
8959 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8960 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8961 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
8963 outData = smb_GetSMBData(outp, NULL);
8964 outData++; /* round to get to parmOffset */
8965 *((ULONG *)outData) = 36; outData += 4; /* length */
8967 if (maxData >= 36) {
8968 memcpy(outData, nullSecurityDesc, 36);
8972 return CM_ERROR_BUFFERTOOSMALL;
8975 /* SMB_COM_NT_TRANSACT
8977 SMB_COM_NT_TRANSACT_SECONDARY should also be handled here.
8979 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8981 unsigned short function;
8983 function = smb_GetSMBParm(inp, 18);
8985 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
8987 /* We can handle long names */
8988 if (vcp->flags & SMB_VCFLAG_USENT)
8989 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
8992 case 1: /* NT_TRANSACT_CREATE */
8993 return smb_ReceiveNTTranCreate(vcp, inp, outp);
8994 case 2: /* NT_TRANSACT_IOCTL */
8995 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
8997 case 3: /* NT_TRANSACT_SET_SECURITY_DESC */
8998 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
9000 case 4: /* NT_TRANSACT_NOTIFY_CHANGE */
9001 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
9002 case 5: /* NT_TRANSACT_RENAME */
9003 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
9005 case 6: /* NT_TRANSACT_QUERY_SECURITY_DESC */
9006 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
9008 osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
9011 osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
9014 return CM_ERROR_BADOP;
9018 * smb_NotifyChange -- find relevant change notification messages and
9021 * If we don't know the file name (i.e. a callback break), filename is
9022 * NULL, and we return a zero-length list.
9024 * At present there is not a single call to smb_NotifyChange that
9025 * has the isDirectParent parameter set to FALSE.
9027 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
9028 cm_scache_t *dscp, clientchar_t *filename, clientchar_t *otherFilename,
9029 BOOL isDirectParent)
9031 smb_packet_t *watch, *lastWatch, *nextWatch;
9032 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen = 0;
9033 char *outData, *oldOutData;
9037 BOOL twoEntries = FALSE;
9038 ULONG otherNameLen, oldParmCount = 0;
9042 /* Get ready for rename within directory */
9043 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
9045 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
9048 osi_Log4(smb_logp,"in smb_NotifyChange for file [%S] dscp [%p] notification 0x%x parent %d",
9049 osi_LogSaveClientString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
9051 osi_Log0(smb_logp," FILE_ACTION_NONE");
9052 if (action == FILE_ACTION_ADDED)
9053 osi_Log0(smb_logp," FILE_ACTION_ADDED");
9054 if (action == FILE_ACTION_REMOVED)
9055 osi_Log0(smb_logp," FILE_ACTION_REMOVED");
9056 if (action == FILE_ACTION_MODIFIED)
9057 osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
9058 if (action == FILE_ACTION_RENAMED_OLD_NAME)
9059 osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
9060 if (action == FILE_ACTION_RENAMED_NEW_NAME)
9061 osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
9063 lock_ObtainMutex(&smb_Dir_Watch_Lock);
9064 watch = smb_Directory_Watches;
9066 filter = smb_GetSMBParm(watch, 19)
9067 | (smb_GetSMBParm(watch, 20) << 16);
9068 fid = smb_GetSMBParm(watch, 21);
9069 wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
9071 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
9072 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
9075 * Strange hack - bug in NT Client and NT Server that we must emulate?
9077 if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
9078 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
9080 fidp = smb_FindFID(watch->vcp, fid, 0);
9082 osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
9084 watch = watch->nextp;
9088 if (fidp->scp != dscp ||
9089 fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
9090 (filter & notifyFilter) == 0 ||
9091 (!isDirectParent && !wtree))
9093 osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
9095 watch = watch->nextp;
9096 smb_ReleaseFID(fidp);
9101 "Sending Change Notification for fid %d filter 0x%x wtree %d file %S",
9102 fid, filter, wtree, osi_LogSaveClientString(smb_logp, filename));
9103 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
9104 osi_Log0(smb_logp, " Notify Change File Name");
9105 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
9106 osi_Log0(smb_logp, " Notify Change Directory Name");
9107 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
9108 osi_Log0(smb_logp, " Notify Change Attributes");
9109 if (filter & FILE_NOTIFY_CHANGE_SIZE)
9110 osi_Log0(smb_logp, " Notify Change Size");
9111 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
9112 osi_Log0(smb_logp, " Notify Change Last Write");
9113 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
9114 osi_Log0(smb_logp, " Notify Change Last Access");
9115 if (filter & FILE_NOTIFY_CHANGE_CREATION)
9116 osi_Log0(smb_logp, " Notify Change Creation");
9117 if (filter & FILE_NOTIFY_CHANGE_EA)
9118 osi_Log0(smb_logp, " Notify Change Extended Attributes");
9119 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
9120 osi_Log0(smb_logp, " Notify Change Security");
9121 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
9122 osi_Log0(smb_logp, " Notify Change Stream Name");
9123 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
9124 osi_Log0(smb_logp, " Notify Change Stream Size");
9125 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
9126 osi_Log0(smb_logp, " Notify Change Stream Write");
9128 /* A watch can only be notified once. Remove it from the list */
9129 nextWatch = watch->nextp;
9130 if (watch == smb_Directory_Watches)
9131 smb_Directory_Watches = nextWatch;
9133 lastWatch->nextp = nextWatch;
9135 /* Turn off WATCHED flag in dscp */
9136 lock_ObtainWrite(&dscp->rw);
9138 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
9140 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
9141 lock_ReleaseWrite(&dscp->rw);
9143 /* Convert to response packet */
9144 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
9145 #ifdef SEND_CANONICAL_PATHNAMES
9146 ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
9148 ((smb_t *) watch)->wct = 0;
9151 if (filename == NULL) {
9154 nameLen = (ULONG)cm_ClientStrLen(filename);
9155 parmCount = 3*4 + nameLen*2;
9156 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
9158 otherNameLen = (ULONG)cm_ClientStrLen(otherFilename);
9159 oldParmCount = parmCount;
9160 parmCount += 3*4 + otherNameLen*2;
9161 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
9163 if (maxLen < parmCount)
9164 parmCount = 0; /* not enough room */
9166 parmOffset = 8*4 + 39;
9167 parmOffset += 1; /* pad to 4 */
9168 dataOffset = parmOffset + parmCount;
9172 /* Total Parameter Count */
9173 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
9174 /* Total Data Count */
9175 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9176 /* Parameter Count */
9177 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
9178 /* Parameter Offset */
9179 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
9180 /* Parameter Displacement */
9181 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9183 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9185 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
9186 /* Data Displacement */
9187 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9188 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
9189 smb_SetSMBDataLength(watch, parmCount + 1);
9191 if (parmCount != 0) {
9192 outData = smb_GetSMBData(watch, NULL);
9193 outData++; /* round to get to parmOffset */
9194 oldOutData = outData;
9195 *((DWORD *)outData) = oldParmCount; outData += 4;
9196 /* Next Entry Offset */
9197 *((DWORD *)outData) = action; outData += 4;
9199 *((DWORD *)outData) = nameLen*2; outData += 4;
9200 /* File Name Length */
9202 smb_UnparseString(watch, outData, filename, NULL, 0);
9206 outData = oldOutData + oldParmCount;
9207 *((DWORD *)outData) = 0; outData += 4;
9208 /* Next Entry Offset */
9209 *((DWORD *)outData) = otherAction; outData += 4;
9211 *((DWORD *)outData) = otherNameLen*2;
9212 outData += 4; /* File Name Length */
9213 smb_UnparseString(watch, outData, otherFilename, NULL, 0);
9218 * If filename is null, we don't know the cause of the
9219 * change notification. We return zero data (see above),
9220 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
9221 * (= 0x010C). We set the error code here by hand, without
9222 * modifying wct and bcc.
9224 if (filename == NULL) {
9225 ((smb_t *) watch)->rcls = 0x0C;
9226 ((smb_t *) watch)->reh = 0x01;
9227 ((smb_t *) watch)->errLow = 0;
9228 ((smb_t *) watch)->errHigh = 0;
9229 /* Set NT Status codes flag */
9230 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9233 smb_SendPacket(watch->vcp, watch);
9234 smb_FreePacket(watch);
9236 smb_ReleaseFID(fidp);
9239 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9242 /* SMB_COM_NT_CANCEL */
9243 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9245 unsigned char *replyWctp;
9246 smb_packet_t *watch, *lastWatch;
9247 USHORT fid, watchtree;
9251 osi_Log0(smb_logp, "SMB3 receive NT cancel");
9253 lock_ObtainMutex(&smb_Dir_Watch_Lock);
9254 watch = smb_Directory_Watches;
9256 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
9257 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
9258 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
9259 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
9260 if (watch == smb_Directory_Watches)
9261 smb_Directory_Watches = watch->nextp;
9263 lastWatch->nextp = watch->nextp;
9264 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9266 /* Turn off WATCHED flag in scp */
9267 fid = smb_GetSMBParm(watch, 21);
9268 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
9270 if (vcp != watch->vcp)
9271 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
9274 fidp = smb_FindFID(vcp, fid, 0);
9276 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %S",
9278 (fidp ? osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp) :_C("")));
9281 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
9283 lock_ObtainWrite(&scp->rw);
9285 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
9287 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
9288 lock_ReleaseWrite(&scp->rw);
9290 smb_ReleaseFID(fidp);
9292 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
9295 /* assume STATUS32; return 0xC0000120 (CANCELED) */
9296 replyWctp = watch->wctp;
9300 ((smb_t *)watch)->rcls = 0x20;
9301 ((smb_t *)watch)->reh = 0x1;
9302 ((smb_t *)watch)->errLow = 0;
9303 ((smb_t *)watch)->errHigh = 0xC0;
9304 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9305 smb_SendPacket(vcp, watch);
9306 smb_FreePacket(watch);
9310 watch = watch->nextp;
9312 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9318 * NT rename also does hard links.
9321 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
9322 #define RENAME_FLAG_HARD_LINK 0x103
9323 #define RENAME_FLAG_RENAME 0x104
9324 #define RENAME_FLAG_COPY 0x105
9326 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9328 clientchar_t *oldPathp, *newPathp;
9334 attrs = smb_GetSMBParm(inp, 0);
9335 rename_type = smb_GetSMBParm(inp, 1);
9337 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
9338 osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
9339 return CM_ERROR_NOACCESS;
9342 tp = smb_GetSMBData(inp, NULL);
9343 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
9345 return CM_ERROR_BADSMB;
9346 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
9348 return CM_ERROR_BADSMB;
9350 osi_Log3(smb_logp, "NTRename for [%S]->[%S] type [%s]",
9351 osi_LogSaveClientString(smb_logp, oldPathp),
9352 osi_LogSaveClientString(smb_logp, newPathp),
9353 ((rename_type==RENAME_FLAG_RENAME)?"rename":(rename_type==RENAME_FLAG_HARD_LINK)?"hardlink":"other"));
9355 if (rename_type == RENAME_FLAG_RENAME) {
9356 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
9357 } else if (rename_type == RENAME_FLAG_HARD_LINK) { /* RENAME_FLAG_HARD_LINK */
9358 code = smb_Link(vcp,inp,oldPathp,newPathp);
9360 code = CM_ERROR_BADOP;
9366 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock", LOCK_HIERARCHY_SMB_DIRWATCH);
9369 cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
9371 smb_username_t *unp;
9374 unp = smb_FindUserByName(usern, machine, flags);
9376 lock_ObtainMutex(&unp->mx);
9377 unp->userp = cm_NewUser();
9378 lock_ReleaseMutex(&unp->mx);
9379 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9381 osi_Log2(smb_logp,"smb_FindCMUserByName Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9385 smb_ReleaseUsername(unp);