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 return CM_ERROR_BADFD;
1451 lock_ObtainMutex(&fidp->mx);
1452 if (pipeState & 0x8000)
1453 fidp->flags |= SMB_FID_BLOCKINGPIPE;
1454 if (pipeState & 0x0100)
1455 fidp->flags |= SMB_FID_MESSAGEMODEPIPE;
1456 lock_ReleaseMutex(&fidp->mx);
1458 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 0);
1459 smb_SendTran2Packet(vcp, outp, op);
1460 smb_FreeTran2Packet(outp);
1462 smb_ReleaseFID(fidp);
1467 long smb_nmpipeTransact(smb_vc_t * vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1477 osi_Log3(smb_logp, "smb_nmpipeTransact for fd[%d] %d bytes in, %d max bytes out",
1478 fd, p->totalData, p->maxReturnData);
1480 fidp = smb_FindFID(vcp, fd, 0);
1482 return CM_ERROR_BADFD;
1484 lock_ObtainMutex(&fidp->mx);
1485 if (fidp->flags & SMB_FID_RPC) {
1488 lock_ReleaseMutex(&fidp->mx);
1491 code = smb_RPCNmpipeTransact(fidp, vcp, p, op);
1492 smb_ReleaseFID(fidp);
1494 /* We only deal with RPC pipes */
1495 code = CM_ERROR_BADFD;
1502 /* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
1503 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1505 smb_tran2Packet_t *asp;
1518 /* We sometimes see 0 word count. What to do? */
1519 if (*inp->wctp == 0) {
1520 osi_Log0(smb_logp, "Transaction2 word count = 0");
1521 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1523 smb_SetSMBDataLength(outp, 0);
1524 smb_SendPacket(vcp, outp);
1528 totalParms = smb_GetSMBParm(inp, 0);
1529 totalData = smb_GetSMBParm(inp, 1);
1531 firstPacket = (inp->inCom == 0x25);
1533 /* find the packet we're reassembling */
1534 lock_ObtainWrite(&smb_globalLock);
1535 asp = smb_FindTran2Packet(vcp, inp);
1537 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1539 lock_ReleaseWrite(&smb_globalLock);
1541 /* now merge in this latest packet; start by looking up offsets */
1543 parmDisp = dataDisp = 0;
1544 parmOffset = smb_GetSMBParm(inp, 10);
1545 dataOffset = smb_GetSMBParm(inp, 12);
1546 parmCount = smb_GetSMBParm(inp, 9);
1547 dataCount = smb_GetSMBParm(inp, 11);
1548 asp->setupCount = smb_GetSMBParmByte(inp, 13);
1549 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1550 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1552 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1553 totalData, dataCount, asp->maxReturnData);
1555 if (asp->setupCount == 2) {
1556 clientchar_t * pname;
1558 asp->pipeCommand = smb_GetSMBParm(inp, 14);
1559 asp->pipeParam = smb_GetSMBParm(inp, 15);
1560 pname = smb_ParseString(inp, inp->wctp + 35, NULL, 0);
1562 asp->name = cm_ClientStrDup(pname);
1565 osi_Log2(smb_logp, " Named Pipe command id [%d] with name [%S]",
1566 asp->pipeCommand, osi_LogSaveClientString(smb_logp, asp->name));
1570 parmDisp = smb_GetSMBParm(inp, 4);
1571 parmOffset = smb_GetSMBParm(inp, 3);
1572 dataDisp = smb_GetSMBParm(inp, 7);
1573 dataOffset = smb_GetSMBParm(inp, 6);
1574 parmCount = smb_GetSMBParm(inp, 2);
1575 dataCount = smb_GetSMBParm(inp, 5);
1577 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1578 parmCount, dataCount);
1581 /* now copy the parms and data */
1582 if ( asp->totalParms > 0 && parmCount != 0 )
1584 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1586 if ( asp->totalData > 0 && dataCount != 0 ) {
1587 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1590 /* account for new bytes */
1591 asp->curData += dataCount;
1592 asp->curParms += parmCount;
1594 /* finally, if we're done, remove the packet from the queue and dispatch it */
1595 if (((asp->totalParms > 0 && asp->curParms > 0)
1596 || asp->setupCount == 2) &&
1597 asp->totalData <= asp->curData &&
1598 asp->totalParms <= asp->curParms) {
1600 /* we've received it all */
1601 lock_ObtainWrite(&smb_globalLock);
1602 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1603 lock_ReleaseWrite(&smb_globalLock);
1605 switch(asp->setupCount) {
1608 rapOp = asp->parmsp[0];
1610 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES &&
1611 smb_rapDispatchTable[rapOp].procp) {
1613 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",
1614 myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1616 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1618 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",
1619 code,vcp,vcp->lana,vcp->lsn);
1622 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]",
1623 rapOp, vcp, vcp->lana, vcp->lsn);
1625 code = CM_ERROR_BADOP;
1631 { /* Named pipe operation */
1632 osi_Log2(smb_logp, "Named Pipe: %s with name [%S]",
1633 myCrt_NmpipeDispatch(asp->pipeCommand),
1634 osi_LogSaveClientString(smb_logp, asp->name));
1636 code = CM_ERROR_BADOP;
1638 switch (asp->pipeCommand) {
1639 case SMB_TRANS_SET_NMPIPE_STATE:
1640 code = smb_nmpipeSetState(vcp, asp, outp);
1643 case SMB_TRANS_RAW_READ_NMPIPE:
1646 case SMB_TRANS_QUERY_NMPIPE_STATE:
1649 case SMB_TRANS_QUERY_NMPIPE_INFO:
1652 case SMB_TRANS_PEEK_NMPIPE:
1655 case SMB_TRANS_TRANSACT_NMPIPE:
1656 code = smb_nmpipeTransact(vcp, asp, outp);
1659 case SMB_TRANS_RAW_WRITE_NMPIPE:
1662 case SMB_TRANS_READ_NMPIPE:
1665 case SMB_TRANS_WRITE_NMPIPE:
1668 case SMB_TRANS_WAIT_NMPIPE:
1671 case SMB_TRANS_CALL_NMPIPE:
1678 code = CM_ERROR_BADOP;
1681 /* if an error is returned, we're supposed to send an error packet,
1682 * otherwise the dispatched function already did the data sending.
1683 * We give dispatched proc the responsibility since it knows how much
1684 * space to allocate.
1687 smb_SendTran2Error(vcp, asp, outp, code);
1690 /* free the input tran 2 packet */
1691 smb_FreeTran2Packet(asp);
1693 else if (firstPacket) {
1694 /* the first packet in a multi-packet request, we need to send an
1695 * ack to get more data.
1697 smb_SetSMBDataLength(outp, 0);
1698 smb_SendPacket(vcp, outp);
1704 /* ANSI versions. */
1706 #pragma pack(push, 1)
1708 typedef struct smb_rap_share_info_0 {
1709 BYTE shi0_netname[13];
1710 } smb_rap_share_info_0_t;
1712 typedef struct smb_rap_share_info_1 {
1713 BYTE shi1_netname[13];
1716 DWORD shi1_remark; /* char *shi1_remark; data offset */
1717 } smb_rap_share_info_1_t;
1719 typedef struct smb_rap_share_info_2 {
1720 BYTE shi2_netname[13];
1723 DWORD shi2_remark; /* char *shi2_remark; data offset */
1724 WORD shi2_permissions;
1726 WORD shi2_current_uses;
1727 DWORD shi2_path; /* char *shi2_path; data offset */
1728 WORD shi2_passwd[9];
1730 } smb_rap_share_info_2_t;
1732 #define SMB_RAP_MAX_SHARES 512
1734 typedef struct smb_rap_share_list {
1737 smb_rap_share_info_0_t * shares;
1738 } smb_rap_share_list_t;
1742 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1743 smb_rap_share_list_t * sp;
1745 if (dep->name[0] == '.' && (!dep->name[1] || (dep->name[1] == '.' && !dep->name[2])))
1746 return 0; /* skip over '.' and '..' */
1748 sp = (smb_rap_share_list_t *) vrockp;
1750 strncpy(sp->shares[sp->cShare].shi0_netname, dep->name, 12);
1751 sp->shares[sp->cShare].shi0_netname[12] = 0;
1755 if (sp->cShare >= sp->maxShares)
1756 return CM_ERROR_STOPNOW;
1761 /* RAP NetShareEnumRequest */
1762 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1764 smb_tran2Packet_t *outp;
1765 unsigned short * tp;
1769 int outParmsTotal; /* total parameter bytes */
1770 int outDataTotal; /* total data bytes */
1773 DWORD allSubmount = 0;
1775 DWORD nRegShares = 0;
1776 DWORD nSharesRet = 0;
1778 HKEY hkSubmount = NULL;
1779 smb_rap_share_info_1_t * shares;
1782 clientchar_t thisShare[AFSPATHMAX];
1786 smb_rap_share_list_t rootShares;
1791 tp = p->parmsp + 1; /* skip over function number (always 0) */
1794 clientchar_t * cdescp;
1796 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1797 if (cm_ClientStrCmp(cdescp, _C("WrLeh")))
1798 return CM_ERROR_INVAL;
1799 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1800 if (cm_ClientStrCmp(cdescp, _C("B13BWz")))
1801 return CM_ERROR_INVAL;
1807 if (infoLevel != 1) {
1808 return CM_ERROR_INVAL;
1811 /* We are supposed to use the same ASCII data structure even if
1812 Unicode is negotiated, which ultimately means that the share
1813 names that we return must be at most 13 characters in length,
1814 including the NULL terminator.
1816 The RAP specification states that shares with names longer than
1817 12 characters should not be included in the enumeration.
1818 However, since we support prefix cell references and since many
1819 cell names are going to exceed 12 characters, we lie and send
1820 the first 12 characters.
1823 /* first figure out how many shares there are */
1824 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1825 KEY_QUERY_VALUE, &hkParam);
1826 if (rv == ERROR_SUCCESS) {
1827 len = sizeof(allSubmount);
1828 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1829 (BYTE *) &allSubmount, &len);
1830 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1833 RegCloseKey (hkParam);
1836 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1837 0, KEY_QUERY_VALUE, &hkSubmount);
1838 if (rv == ERROR_SUCCESS) {
1839 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1840 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1841 if (rv != ERROR_SUCCESS)
1847 /* fetch the root shares */
1848 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1849 rootShares.cShare = 0;
1850 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1854 userp = smb_GetTran2User(vcp,p);
1856 thyper.HighPart = 0;
1859 cm_HoldSCache(cm_data.rootSCachep);
1860 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1861 cm_ReleaseSCache(cm_data.rootSCachep);
1863 cm_ReleaseUser(userp);
1865 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1867 #define REMARK_LEN 1
1868 outParmsTotal = 8; /* 4 dwords */
1869 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1870 if(outDataTotal > bufsize) {
1871 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1872 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1875 nSharesRet = nShares;
1878 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1880 /* now for the submounts */
1881 shares = (smb_rap_share_info_1_t *) outp->datap;
1882 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1884 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1887 StringCchCopyA(shares[cshare].shi1_netname,
1888 lengthof(shares[cshare].shi1_netname), "all" );
1889 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1890 /* type and pad are zero already */
1896 for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
1897 len = sizeof(thisShare);
1898 rv = RegEnumValueW(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
1899 if (rv == ERROR_SUCCESS &&
1900 cm_ClientStrLen(thisShare) &&
1901 (!allSubmount || cm_ClientStrCmpI(thisShare,_C("all")))) {
1902 cm_ClientStringToUtf8(thisShare, -1, shares[cshare].shi1_netname,
1903 lengthof( shares[cshare].shi1_netname ));
1904 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1905 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1910 nShares--; /* uncount key */
1913 RegCloseKey(hkSubmount);
1916 nonrootShares = cshare;
1918 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1919 /* in case there are collisions with submounts, submounts have
1921 for (j=0; j < nonrootShares; j++)
1922 if (!cm_stricmp_utf8(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1925 if (j < nonrootShares) {
1926 nShares--; /* uncount */
1930 StringCchCopyA(shares[cshare].shi1_netname, lengthof(shares[cshare].shi1_netname),
1931 rootShares.shares[i].shi0_netname);
1932 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1937 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1938 outp->parmsp[1] = 0;
1939 outp->parmsp[2] = cshare;
1940 outp->parmsp[3] = nShares;
1942 outp->totalData = (int)(cstrp - outp->datap);
1943 outp->totalParms = outParmsTotal;
1945 smb_SendTran2Packet(vcp, outp, op);
1946 smb_FreeTran2Packet(outp);
1948 free(rootShares.shares);
1953 /* RAP NetShareGetInfo */
1954 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1956 smb_tran2Packet_t *outp;
1957 unsigned short * tp;
1958 clientchar_t * shareName;
1959 BOOL shareFound = FALSE;
1960 unsigned short infoLevel;
1961 unsigned short bufsize;
1970 cm_scache_t *scp = NULL;
1976 tp = p->parmsp + 1; /* skip over function number (always 1) */
1979 clientchar_t * cdescp;
1981 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1982 if (cm_ClientStrCmp(cdescp, _C("zWrLh")))
1984 return CM_ERROR_INVAL;
1986 cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1987 if (cm_ClientStrCmp(cdescp, _C("B13")) &&
1988 cm_ClientStrCmp(cdescp, _C("B13BWz")) &&
1989 cm_ClientStrCmp(cdescp, _C("B13BWzWWWzB9B")))
1991 return CM_ERROR_INVAL;
1993 shareName = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2001 totalData = sizeof(smb_rap_share_info_0_t);
2002 else if(infoLevel == SMB_INFO_STANDARD)
2003 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
2004 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
2005 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
2007 return CM_ERROR_INVAL;
2009 if(!cm_ClientStrCmpI(shareName, _C("all")) || !cm_ClientStrCmp(shareName,_C("*."))) {
2010 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
2011 KEY_QUERY_VALUE, &hkParam);
2012 if (rv == ERROR_SUCCESS) {
2013 len = sizeof(allSubmount);
2014 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
2015 (BYTE *) &allSubmount, &len);
2016 if (rv != ERROR_SUCCESS || allSubmount != 0) {
2019 RegCloseKey (hkParam);
2026 userp = smb_GetTran2User(vcp, p);
2028 osi_Log1(smb_logp,"ReceiveRAPNetShareGetInfo unable to resolve user [%d]", p->uid);
2029 return CM_ERROR_BADSMB;
2031 code = cm_NameI(cm_data.rootSCachep, shareName,
2032 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
2033 userp, NULL, &req, &scp);
2035 cm_ReleaseSCache(scp);
2038 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
2039 KEY_QUERY_VALUE, &hkSubmount);
2040 if (rv == ERROR_SUCCESS) {
2041 rv = RegQueryValueExW(hkSubmount, shareName, NULL, NULL, NULL, NULL);
2042 if (rv == ERROR_SUCCESS) {
2045 RegCloseKey(hkSubmount);
2051 return CM_ERROR_BADSHARENAME;
2053 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
2054 memset(outp->datap, 0, totalData);
2056 outp->parmsp[0] = 0;
2057 outp->parmsp[1] = 0;
2058 outp->parmsp[2] = totalData;
2060 if (infoLevel == 0) {
2061 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
2062 cm_ClientStringToUtf8(shareName, -1, info->shi0_netname,
2063 lengthof(info->shi0_netname));
2064 } else if(infoLevel == SMB_INFO_STANDARD) {
2065 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
2066 cm_ClientStringToUtf8(shareName, -1, info->shi1_netname, lengthof(info->shi1_netname));
2067 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
2068 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
2069 /* type and pad are already zero */
2070 } else { /* infoLevel==2 */
2071 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
2072 cm_ClientStringToUtf8(shareName, -1, info->shi2_netname, lengthof(info->shi2_netname));
2073 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
2074 info->shi2_permissions = ACCESS_ALL;
2075 info->shi2_max_uses = (unsigned short) -1;
2076 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
2079 outp->totalData = totalData;
2080 outp->totalParms = totalParam;
2082 smb_SendTran2Packet(vcp, outp, op);
2083 smb_FreeTran2Packet(outp);
2088 #pragma pack(push, 1)
2090 typedef struct smb_rap_wksta_info_10 {
2091 DWORD wki10_computername; /*char *wki10_computername;*/
2092 DWORD wki10_username; /* char *wki10_username; */
2093 DWORD wki10_langroup; /* char *wki10_langroup;*/
2094 BYTE wki10_ver_major;
2095 BYTE wki10_ver_minor;
2096 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
2097 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
2098 } smb_rap_wksta_info_10_t;
2102 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2104 smb_tran2Packet_t *outp;
2108 unsigned short * tp;
2111 smb_rap_wksta_info_10_t * info;
2115 tp = p->parmsp + 1; /* Skip over function number */
2118 clientchar_t * cdescp;
2120 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2121 SMB_STRF_FORCEASCII);
2122 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2123 return CM_ERROR_INVAL;
2125 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2126 SMB_STRF_FORCEASCII);
2127 if (cm_ClientStrCmp(cdescp, _C("zzzBBzz")))
2128 return CM_ERROR_INVAL;
2134 if (infoLevel != 10) {
2135 return CM_ERROR_INVAL;
2141 totalData = sizeof(*info) + /* info */
2142 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
2143 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
2144 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
2145 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
2146 1; /* wki10_oth_domains (null)*/
2148 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2150 memset(outp->parmsp,0,totalParams);
2151 memset(outp->datap,0,totalData);
2153 info = (smb_rap_wksta_info_10_t *) outp->datap;
2154 cstrp = (char *) (info + 1);
2156 info->wki10_computername = (DWORD) (cstrp - outp->datap);
2157 StringCbCopyA(cstrp, totalData, smb_localNamep);
2158 cstrp += strlen(cstrp) + 1;
2160 info->wki10_username = (DWORD) (cstrp - outp->datap);
2161 uidp = smb_FindUID(vcp, p->uid, 0);
2163 lock_ObtainMutex(&uidp->mx);
2164 if(uidp->unp && uidp->unp->name)
2165 cm_ClientStringToUtf8(uidp->unp->name, -1,
2166 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2167 lock_ReleaseMutex(&uidp->mx);
2168 smb_ReleaseUID(uidp);
2170 cstrp += strlen(cstrp) + 1;
2172 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
2173 StringCbCopyA(cstrp, totalData - (cstrp - outp->datap)*sizeof(char), "WORKGROUP");
2174 cstrp += strlen(cstrp) + 1;
2176 /* TODO: Not sure what values these should take, but these work */
2177 info->wki10_ver_major = 5;
2178 info->wki10_ver_minor = 1;
2180 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
2181 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
2182 cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2183 cstrp += strlen(cstrp) + 1;
2185 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
2186 cstrp ++; /* no other domains */
2188 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
2189 outp->parmsp[2] = outp->totalData;
2190 outp->totalParms = totalParams;
2192 smb_SendTran2Packet(vcp,outp,op);
2193 smb_FreeTran2Packet(outp);
2198 #pragma pack(push, 1)
2200 typedef struct smb_rap_server_info_0 {
2202 } smb_rap_server_info_0_t;
2204 typedef struct smb_rap_server_info_1 {
2206 BYTE sv1_version_major;
2207 BYTE sv1_version_minor;
2209 DWORD sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
2210 } smb_rap_server_info_1_t;
2214 char smb_ServerComment[] = "OpenAFS Client";
2215 int smb_ServerCommentLen = sizeof(smb_ServerComment);
2217 #define SMB_SV_TYPE_SERVER 0x00000002L
2218 #define SMB_SV_TYPE_NT 0x00001000L
2219 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
2221 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2223 smb_tran2Packet_t *outp;
2227 unsigned short * tp;
2230 smb_rap_server_info_0_t * info0;
2231 smb_rap_server_info_1_t * info1;
2234 tp = p->parmsp + 1; /* Skip over function number */
2237 clientchar_t * cdescp;
2239 cdescp = smb_ParseStringT2Parm(p, (unsigned char *) tp, (char **) &tp,
2240 SMB_STRF_FORCEASCII);
2241 if (cm_ClientStrCmp(cdescp, _C("WrLh")))
2242 return CM_ERROR_INVAL;
2243 cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2244 SMB_STRF_FORCEASCII);
2245 if (cm_ClientStrCmp(cdescp, _C("B16")) ||
2246 cm_ClientStrCmp(cdescp, _C("B16BBDz")))
2247 return CM_ERROR_INVAL;
2253 if (infoLevel != 0 && infoLevel != 1) {
2254 return CM_ERROR_INVAL;
2260 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
2261 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
2263 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2265 memset(outp->parmsp,0,totalParams);
2266 memset(outp->datap,0,totalData);
2268 if (infoLevel == 0) {
2269 info0 = (smb_rap_server_info_0_t *) outp->datap;
2270 cstrp = (char *) (info0 + 1);
2271 StringCchCopyA(info0->sv0_name, lengthof(info0->sv0_name), "AFS");
2272 } else { /* infoLevel == SMB_INFO_STANDARD */
2273 info1 = (smb_rap_server_info_1_t *) outp->datap;
2274 cstrp = (char *) (info1 + 1);
2275 StringCchCopyA(info1->sv1_name, lengthof(info1->sv1_name), "AFS");
2278 SMB_SV_TYPE_SERVER |
2280 SMB_SV_TYPE_SERVER_NT;
2282 info1->sv1_version_major = 5;
2283 info1->sv1_version_minor = 1;
2284 info1->sv1_comment_or_master_browser = (DWORD) (cstrp - outp->datap);
2286 StringCbCopyA(cstrp, smb_ServerCommentLen, smb_ServerComment);
2288 cstrp += smb_ServerCommentLen / sizeof(char);
2291 totalData = (DWORD)(cstrp - outp->datap);
2292 outp->totalData = min(bufsize,totalData); /* actual data size */
2293 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
2294 outp->parmsp[2] = totalData;
2295 outp->totalParms = totalParams;
2297 smb_SendTran2Packet(vcp,outp,op);
2298 smb_FreeTran2Packet(outp);
2303 /* SMB_COM_TRANSACTION2 and SMB_COM_TRANSACTION2_SECONDARY */
2304 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2306 smb_tran2Packet_t *asp;
2317 DWORD oldTime, newTime;
2319 /* We sometimes see 0 word count. What to do? */
2320 if (*inp->wctp == 0) {
2321 osi_Log0(smb_logp, "Transaction2 word count = 0");
2322 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
2324 smb_SetSMBDataLength(outp, 0);
2325 smb_SendPacket(vcp, outp);
2329 totalParms = smb_GetSMBParm(inp, 0);
2330 totalData = smb_GetSMBParm(inp, 1);
2332 firstPacket = (inp->inCom == 0x32);
2334 /* find the packet we're reassembling */
2335 lock_ObtainWrite(&smb_globalLock);
2336 asp = smb_FindTran2Packet(vcp, inp);
2338 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
2340 lock_ReleaseWrite(&smb_globalLock);
2342 /* now merge in this latest packet; start by looking up offsets */
2344 parmDisp = dataDisp = 0;
2345 parmOffset = smb_GetSMBParm(inp, 10);
2346 dataOffset = smb_GetSMBParm(inp, 12);
2347 parmCount = smb_GetSMBParm(inp, 9);
2348 dataCount = smb_GetSMBParm(inp, 11);
2349 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2350 asp->maxReturnData = smb_GetSMBParm(inp, 3);
2352 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2353 totalData, dataCount, asp->maxReturnData);
2356 parmDisp = smb_GetSMBParm(inp, 4);
2357 parmOffset = smb_GetSMBParm(inp, 3);
2358 dataDisp = smb_GetSMBParm(inp, 7);
2359 dataOffset = smb_GetSMBParm(inp, 6);
2360 parmCount = smb_GetSMBParm(inp, 2);
2361 dataCount = smb_GetSMBParm(inp, 5);
2363 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2364 parmCount, dataCount);
2367 /* now copy the parms and data */
2368 if ( asp->totalParms > 0 && parmCount != 0 )
2370 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2372 if ( asp->totalData > 0 && dataCount != 0 ) {
2373 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2376 /* account for new bytes */
2377 asp->curData += dataCount;
2378 asp->curParms += parmCount;
2380 /* finally, if we're done, remove the packet from the queue and dispatch it */
2381 if (asp->totalParms > 0 &&
2382 asp->curParms > 0 &&
2383 asp->totalData <= asp->curData &&
2384 asp->totalParms <= asp->curParms) {
2385 /* we've received it all */
2386 lock_ObtainWrite(&smb_globalLock);
2387 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2388 lock_ReleaseWrite(&smb_globalLock);
2390 oldTime = GetTickCount();
2392 /* now dispatch it */
2393 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2394 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2395 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2398 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2399 code = CM_ERROR_BADOP;
2402 /* if an error is returned, we're supposed to send an error packet,
2403 * otherwise the dispatched function already did the data sending.
2404 * We give dispatched proc the responsibility since it knows how much
2405 * space to allocate.
2408 smb_SendTran2Error(vcp, asp, outp, code);
2411 newTime = GetTickCount();
2412 if (newTime - oldTime > 45000) {
2415 clientchar_t *treepath = NULL; /* do not free */
2416 clientchar_t *pathname = NULL;
2417 cm_fid_t afid = {0,0,0,0,0};
2419 uidp = smb_FindUID(vcp, asp->uid, 0);
2420 smb_LookupTIDPath(vcp, asp->tid, &treepath);
2421 fidp = smb_FindFID(vcp, inp->fid, 0);
2424 lock_ObtainMutex(&fidp->mx);
2425 if (fidp->NTopen_pathp)
2426 pathname = fidp->NTopen_pathp;
2428 afid = fidp->scp->fid;
2430 if (inp->stringsp->wdata)
2431 pathname = inp->stringsp->wdata;
2434 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)",
2435 myCrt_2Dispatch(asp->opcode), newTime - oldTime,
2436 asp->uid, uidp ? uidp->unp->name : NULL,
2437 asp->pid, asp->mid, asp->tid,
2440 afid.cell, afid.volume, afid.vnode, afid.unique);
2443 lock_ReleaseMutex(&fidp->mx);
2446 smb_ReleaseUID(uidp);
2448 smb_ReleaseFID(fidp);
2451 /* free the input tran 2 packet */
2452 smb_FreeTran2Packet(asp);
2454 else if (firstPacket) {
2455 /* the first packet in a multi-packet request, we need to send an
2456 * ack to get more data.
2458 smb_SetSMBDataLength(outp, 0);
2459 smb_SendPacket(vcp, outp);
2466 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2468 clientchar_t *pathp;
2469 smb_tran2Packet_t *outp;
2474 cm_scache_t *dscp; /* dir we're dealing with */
2475 cm_scache_t *scp; /* file we're creating */
2477 int initialModeBits;
2480 clientchar_t *lastNamep;
2487 int parmSlot; /* which parm we're dealing with */
2488 long returnEALength;
2489 clientchar_t *tidPathp;
2492 BOOL is_rpc = FALSE;
2493 BOOL is_ipc = FALSE;
2499 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2500 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2502 openFun = p->parmsp[6]; /* open function */
2503 excl = ((openFun & 3) == 0);
2504 trunc = ((openFun & 3) == 2); /* truncate it */
2505 openMode = (p->parmsp[1] & 0x7);
2506 openAction = 0; /* tracks what we did */
2508 attributes = p->parmsp[3];
2509 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2511 /* compute initial mode bits based on read-only flag in attributes */
2512 initialModeBits = 0666;
2513 if (attributes & SMB_ATTR_READONLY)
2514 initialModeBits &= ~0222;
2516 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
2519 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2521 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2522 if (code == CM_ERROR_TIDIPC) {
2524 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2527 spacep = cm_GetSpace();
2528 /* smb_StripLastComponent will strip "::$DATA" if present */
2529 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2533 /* special case magic file name for receiving IOCTL requests
2534 * (since IOCTL calls themselves aren't getting through).
2536 (cm_ClientStrCmpI(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
2538 /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional)*/
2539 (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
2541 unsigned short file_type = 0;
2542 unsigned short device_state = 0;
2544 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2547 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
2548 osi_Log2(smb_logp, "smb_ReceiveTran2Open Creating RPC Fid [%d] code [%d]",
2551 smb_ReleaseFID(fidp);
2552 smb_FreeTran2Packet(outp);
2553 osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
2557 smb_SetupIoctlFid(fidp, spacep);
2558 osi_Log1(smb_logp, "smb_ReceiveTran2Open Creating IOCTL Fid [%d]", fidp->fid);
2561 /* copy out remainder of the parms */
2563 outp->parmsp[parmSlot++] = fidp->fid;
2565 outp->parmsp[parmSlot++] = 0; /* attrs */
2566 outp->parmsp[parmSlot++] = 0; /* mod time */
2567 outp->parmsp[parmSlot++] = 0;
2568 outp->parmsp[parmSlot++] = 0; /* len */
2569 outp->parmsp[parmSlot++] = 0x7fff;
2570 outp->parmsp[parmSlot++] = openMode;
2571 outp->parmsp[parmSlot++] = file_type;
2572 outp->parmsp[parmSlot++] = device_state;
2574 /* and the final "always present" stuff */
2575 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2576 /* next write out the "unique" ID */
2577 outp->parmsp[parmSlot++] = 0x1234;
2578 outp->parmsp[parmSlot++] = 0x5678;
2579 outp->parmsp[parmSlot++] = 0;
2580 if (returnEALength) {
2581 outp->parmsp[parmSlot++] = 0;
2582 outp->parmsp[parmSlot++] = 0;
2585 outp->totalData = 0;
2586 outp->totalParms = parmSlot * 2;
2588 smb_SendTran2Packet(vcp, outp, op);
2590 smb_FreeTran2Packet(outp);
2592 /* and clean up fid reference */
2593 smb_ReleaseFID(fidp);
2599 osi_Log0(smb_logp, "Tran2Open rejecting IPC TID");
2600 smb_FreeTran2Packet(outp);
2601 return CM_ERROR_BADFD;
2605 if (!cm_IsValidClientString(pathp)) {
2607 clientchar_t * hexp;
2609 hexp = cm_GetRawCharsAlloc(pathp, -1);
2610 osi_Log1(smb_logp, "Tran2Open rejecting invalid name. [%S]",
2611 osi_LogSaveClientString(smb_logp, hexp));
2615 osi_Log0(smb_logp, "Tran2Open rejecting invalid name");
2617 smb_FreeTran2Packet(outp);
2618 return CM_ERROR_BADNTFILENAME;
2621 #ifdef DEBUG_VERBOSE
2623 char *hexp, *asciip;
2624 asciip = (lastNamep ? lastNamep : pathp);
2625 hexp = osi_HexifyString( asciip );
2626 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2631 userp = smb_GetTran2User(vcp, p);
2632 /* In the off chance that userp is NULL, we log and abandon */
2634 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2635 smb_FreeTran2Packet(outp);
2636 return CM_ERROR_BADSMB;
2640 code = cm_NameI(cm_data.rootSCachep, pathp,
2641 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2642 userp, tidPathp, &req, &scp);
2644 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2645 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2646 userp, tidPathp, &req, &dscp);
2647 cm_FreeSpace(spacep);
2650 cm_ReleaseUser(userp);
2651 smb_FreeTran2Packet(outp);
2656 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2657 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2658 (clientchar_t*) spacep->data);
2659 cm_ReleaseSCache(dscp);
2660 cm_ReleaseUser(userp);
2661 smb_FreeTran2Packet(outp);
2662 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2663 return CM_ERROR_PATH_NOT_COVERED;
2665 return CM_ERROR_NOSUCHPATH;
2667 #endif /* DFS_SUPPORT */
2669 /* otherwise, scp points to the parent directory. Do a lookup,
2670 * and truncate the file if we find it, otherwise we create the
2677 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2679 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2680 cm_ReleaseSCache(dscp);
2681 cm_ReleaseUser(userp);
2682 smb_FreeTran2Packet(outp);
2686 /* macintosh is expensive to program for it */
2687 cm_FreeSpace(spacep);
2690 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2691 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2692 cm_ReleaseSCache(scp);
2693 cm_ReleaseUser(userp);
2694 smb_FreeTran2Packet(outp);
2695 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2696 return CM_ERROR_PATH_NOT_COVERED;
2698 return CM_ERROR_NOSUCHPATH;
2700 #endif /* DFS_SUPPORT */
2703 /* if we get here, if code is 0, the file exists and is represented by
2704 * scp. Otherwise, we have to create it.
2707 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2710 cm_ReleaseSCache(dscp);
2711 cm_ReleaseSCache(scp);
2712 cm_ReleaseUser(userp);
2713 smb_FreeTran2Packet(outp);
2718 /* oops, file shouldn't be there */
2720 cm_ReleaseSCache(dscp);
2721 cm_ReleaseSCache(scp);
2722 cm_ReleaseUser(userp);
2723 smb_FreeTran2Packet(outp);
2724 return CM_ERROR_EXISTS;
2728 setAttr.mask = CM_ATTRMASK_LENGTH;
2729 setAttr.length.LowPart = 0;
2730 setAttr.length.HighPart = 0;
2731 code = cm_SetAttr(scp, &setAttr, userp, &req);
2732 openAction = 3; /* truncated existing file */
2735 openAction = 1; /* found existing file */
2737 else if (!(openFun & 0x10)) {
2738 /* don't create if not found */
2740 cm_ReleaseSCache(dscp);
2741 osi_assertx(scp == NULL, "null cm_scache_t");
2742 cm_ReleaseUser(userp);
2743 smb_FreeTran2Packet(outp);
2744 return CM_ERROR_NOSUCHFILE;
2747 osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2748 openAction = 2; /* created file */
2749 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2750 cm_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2751 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2755 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2756 smb_NotifyChange(FILE_ACTION_ADDED,
2757 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2758 dscp, lastNamep, NULL, TRUE);
2759 } else if (!excl && code == CM_ERROR_EXISTS) {
2760 /* not an exclusive create, and someone else tried
2761 * creating it already, then we open it anyway. We
2762 * don't bother retrying after this, since if this next
2763 * fails, that means that the file was deleted after we
2764 * started this call.
2766 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2770 setAttr.mask = CM_ATTRMASK_LENGTH;
2771 setAttr.length.LowPart = 0;
2772 setAttr.length.HighPart = 0;
2773 code = cm_SetAttr(scp, &setAttr, userp,
2776 } /* lookup succeeded */
2780 /* we don't need this any longer */
2782 cm_ReleaseSCache(dscp);
2785 /* something went wrong creating or truncating the file */
2787 cm_ReleaseSCache(scp);
2788 cm_ReleaseUser(userp);
2789 smb_FreeTran2Packet(outp);
2793 /* make sure we're about to open a file */
2794 if (scp->fileType != CM_SCACHETYPE_FILE) {
2796 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2797 cm_scache_t * targetScp = 0;
2798 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2800 /* we have a more accurate file to use (the
2801 * target of the symbolic link). Otherwise,
2802 * we'll just use the symlink anyway.
2804 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2806 cm_ReleaseSCache(scp);
2810 if (scp->fileType != CM_SCACHETYPE_FILE) {
2811 cm_ReleaseSCache(scp);
2812 cm_ReleaseUser(userp);
2813 smb_FreeTran2Packet(outp);
2814 return CM_ERROR_ISDIR;
2818 /* now all we have to do is open the file itself */
2819 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2820 osi_assertx(fidp, "null smb_fid_t");
2823 lock_ObtainMutex(&fidp->mx);
2824 /* save a pointer to the vnode */
2825 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2827 lock_ObtainWrite(&scp->rw);
2828 scp->flags |= CM_SCACHEFLAG_SMB_FID;
2829 lock_ReleaseWrite(&scp->rw);
2832 fidp->userp = userp;
2834 /* compute open mode */
2836 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
2837 if (openMode == 1 || openMode == 2)
2838 fidp->flags |= SMB_FID_OPENWRITE;
2840 /* remember that the file was newly created */
2842 fidp->flags |= SMB_FID_CREATED;
2844 lock_ReleaseMutex(&fidp->mx);
2846 smb_ReleaseFID(fidp);
2848 cm_Open(scp, 0, userp);
2850 /* copy out remainder of the parms */
2852 outp->parmsp[parmSlot++] = fidp->fid;
2853 lock_ObtainRead(&scp->rw);
2855 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2856 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2857 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2858 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2859 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2860 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2861 outp->parmsp[parmSlot++] = openMode;
2862 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2863 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2865 /* and the final "always present" stuff */
2866 outp->parmsp[parmSlot++] = openAction;
2867 /* next write out the "unique" ID */
2868 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2869 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2870 outp->parmsp[parmSlot++] = 0;
2871 if (returnEALength) {
2872 outp->parmsp[parmSlot++] = 0;
2873 outp->parmsp[parmSlot++] = 0;
2875 lock_ReleaseRead(&scp->rw);
2876 outp->totalData = 0; /* total # of data bytes */
2877 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2879 smb_SendTran2Packet(vcp, outp, op);
2881 smb_FreeTran2Packet(outp);
2883 cm_ReleaseUser(userp);
2884 /* leave scp held since we put it in fidp->scp */
2888 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2891 unsigned short infolevel;
2893 infolevel = p->parmsp[0];
2895 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2897 return CM_ERROR_BAD_LEVEL;
2900 /* TRANS2_QUERY_FS_INFORMATION */
2901 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2903 smb_tran2Packet_t *outp;
2904 smb_tran2QFSInfo_t qi;
2908 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2910 switch (p->parmsp[0]) {
2911 case SMB_INFO_ALLOCATION:
2913 responseSize = sizeof(qi.u.allocInfo);
2915 qi.u.allocInfo.FSID = 0;
2916 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2917 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2918 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2919 qi.u.allocInfo.bytesPerSector = 1024;
2922 case SMB_INFO_VOLUME:
2924 qi.u.volumeInfo.vsn = 1234; /* Volume serial number */
2925 qi.u.volumeInfo.vnCount = 3; /* Number of characters in label (AFS\0)*/
2927 /* we're supposed to pad it out with zeroes to the end */
2928 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2929 smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
2931 responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
2934 case SMB_QUERY_FS_VOLUME_INFO:
2935 /* FS volume info */
2936 responseSize = sizeof(qi.u.FSvolumeInfo);
2939 FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
2940 memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
2943 qi.u.FSvolumeInfo.vsn = 1234;
2944 qi.u.FSvolumeInfo.vnCount = 6; /* This is always in Unicode */
2945 memset(&qi.u.FSvolumeInfo.label, 0, sizeof(qi.u.FSvolumeInfo.label));
2946 memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
2949 case SMB_QUERY_FS_SIZE_INFO:
2951 responseSize = sizeof(qi.u.FSsizeInfo);
2953 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2954 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2955 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2956 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2957 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2958 qi.u.FSsizeInfo.bytesPerSector = 1024;
2961 case SMB_QUERY_FS_DEVICE_INFO:
2962 /* FS device info */
2963 responseSize = sizeof(qi.u.FSdeviceInfo);
2965 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2966 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2969 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2970 /* FS attribute info */
2972 /* attributes, defined in WINNT.H:
2973 * FILE_CASE_SENSITIVE_SEARCH 0x1
2974 * FILE_CASE_PRESERVED_NAMES 0x2
2975 * FILE_UNICODE_ON_DISK 0x4
2976 * FILE_VOLUME_QUOTAS 0x10
2977 * <no name defined> 0x4000
2978 * If bit 0x4000 is not set, Windows 95 thinks
2979 * we can't handle long (non-8.3) names,
2980 * despite our protestations to the contrary.
2982 qi.u.FSattributeInfo.attributes = 0x4003;
2983 /* The maxCompLength is supposed to be in bytes */
2985 qi.u.FSattributeInfo.attributes |= 0x04;
2987 qi.u.FSattributeInfo.maxCompLength = 255;
2988 smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
2989 qi.u.FSattributeInfo.FSnameLength = sz;
2992 sizeof(qi.u.FSattributeInfo.attributes) +
2993 sizeof(qi.u.FSattributeInfo.maxCompLength) +
2994 sizeof(qi.u.FSattributeInfo.FSnameLength) +
2999 case SMB_INFO_UNIX: /* CIFS Unix Info */
3000 case SMB_INFO_MACOS: /* Mac FS Info */
3002 return CM_ERROR_BADOP;
3005 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
3007 /* copy out return data, and set corresponding sizes */
3008 outp->totalParms = 0;
3009 outp->totalData = responseSize;
3010 memcpy(outp->datap, &qi, responseSize);
3012 /* send and free the packets */
3013 smb_SendTran2Packet(vcp, outp, op);
3014 smb_FreeTran2Packet(outp);
3019 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3021 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
3022 return CM_ERROR_BADOP;
3025 struct smb_ShortNameRock {
3026 clientchar_t *maskp;
3028 clientchar_t *shortName;
3029 size_t shortNameLen;
3032 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
3035 struct smb_ShortNameRock *rockp;
3036 normchar_t normName[MAX_PATH];
3037 clientchar_t *shortNameEnd;
3041 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t)) == 0) {
3042 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
3043 osi_LogSaveString(smb_logp, dep->name));
3047 /* compare both names and vnodes, though probably just comparing vnodes
3048 * would be safe enough.
3050 if (cm_NormStrCmpI(normName, rockp->maskp) != 0)
3052 if (ntohl(dep->fid.vnode) != rockp->vnode)
3055 /* This is the entry */
3056 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
3057 rockp->shortNameLen = shortNameEnd - rockp->shortName;
3059 return CM_ERROR_STOPNOW;
3062 long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
3063 clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
3065 struct smb_ShortNameRock rock;
3066 clientchar_t *lastNamep;
3069 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
3073 spacep = cm_GetSpace();
3074 /* smb_StripLastComponent will strip "::$DATA" if present */
3075 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
3077 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3078 caseFold, userp, tidPathp,
3080 cm_FreeSpace(spacep);
3085 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3086 cm_ReleaseSCache(dscp);
3087 cm_ReleaseUser(userp);
3091 return CM_ERROR_PATH_NOT_COVERED;
3093 #endif /* DFS_SUPPORT */
3095 if (!lastNamep) lastNamep = pathp;
3098 thyper.HighPart = 0;
3099 rock.shortName = shortName;
3101 rock.maskp = lastNamep;
3102 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
3104 cm_ReleaseSCache(dscp);
3107 return CM_ERROR_NOSUCHFILE;
3108 if (code == CM_ERROR_STOPNOW) {
3109 *shortNameLenp = rock.shortNameLen;
3115 /* TRANS2_QUERY_PATH_INFORMATION */
3116 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3118 smb_tran2Packet_t *outp;
3121 unsigned short infoLevel;
3122 smb_tran2QPathInfo_t qpi;
3124 unsigned short attributes;
3125 unsigned long extAttributes;
3126 clientchar_t shortName[13];
3130 cm_scache_t *scp, *dscp;
3131 int scp_rw_held = 0;
3134 clientchar_t *pathp;
3135 clientchar_t *tidPathp;
3136 clientchar_t *lastComp;
3141 infoLevel = p->parmsp[0];
3142 if (infoLevel == SMB_INFO_IS_NAME_VALID)
3144 else if (infoLevel == SMB_INFO_STANDARD)
3145 responseSize = sizeof(qpi.u.QPstandardInfo);
3146 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
3147 responseSize = sizeof(qpi.u.QPeaSizeInfo);
3148 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3149 responseSize = sizeof(qpi.u.QPfileBasicInfo);
3150 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3151 responseSize = sizeof(qpi.u.QPfileStandardInfo);
3152 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3153 responseSize = sizeof(qpi.u.QPfileEaInfo);
3154 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3155 responseSize = sizeof(qpi.u.QPfileNameInfo);
3156 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
3157 responseSize = sizeof(qpi.u.QPfileAllInfo);
3158 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
3159 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
3160 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO)
3161 responseSize = sizeof(qpi.u.QPfileStreamInfo);
3163 osi_Log2(smb_logp, "Bad Tran2QPathInfo op 0x%x infolevel 0x%x",
3164 p->opcode, infoLevel);
3165 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3168 memset(&qpi, 0, sizeof(qpi));
3170 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3171 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path \"%S\"", infoLevel,
3172 osi_LogSaveClientString(smb_logp, pathp));
3174 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3176 if (infoLevel > 0x100)
3177 outp->totalParms = 2;
3179 outp->totalParms = 0;
3181 /* now, if we're at infoLevel 6, we're only being asked to check
3182 * the syntax, so we just OK things now. In particular, we're *not*
3183 * being asked to verify anything about the state of any parent dirs.
3185 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
3186 smb_SendTran2Packet(vcp, outp, opx);
3187 smb_FreeTran2Packet(outp);
3191 userp = smb_GetTran2User(vcp, p);
3193 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
3194 smb_FreeTran2Packet(outp);
3195 return CM_ERROR_BADSMB;
3198 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3200 osi_Log1(smb_logp, "ReceiveTran2QPathInfo tid path lookup failure 0x%x", code);
3201 cm_ReleaseUser(userp);
3202 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
3203 smb_FreeTran2Packet(outp);
3207 osi_Log1(smb_logp, "T2 QPathInfo tidPathp \"%S\"",
3208 osi_LogSaveClientString(smb_logp, tidPathp));
3211 * XXX Strange hack XXX
3213 * As of Patch 7 (13 January 98), we are having the following problem:
3214 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3215 * requests to look up "desktop.ini" in all the subdirectories.
3216 * This can cause zillions of timeouts looking up non-existent cells
3217 * and volumes, especially in the top-level directory.
3219 * We have not found any way to avoid this or work around it except
3220 * to explicitly ignore the requests for mount points that haven't
3221 * yet been evaluated and for directories that haven't yet been
3224 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3225 spacep = cm_GetSpace();
3226 /* smb_StripLastComponent will strip "::$DATA" if present */
3227 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3228 #ifndef SPECIAL_FOLDERS
3229 /* Make sure that lastComp is not NULL */
3231 if (cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
3232 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3236 userp, tidPathp, &req, &dscp);
3239 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3240 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3242 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3243 code = CM_ERROR_PATH_NOT_COVERED;
3245 code = CM_ERROR_NOSUCHPATH;
3247 #endif /* DFS_SUPPORT */
3248 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3249 code = CM_ERROR_NOSUCHFILE;
3250 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3251 cm_buf_t *bp = buf_Find(dscp, &hzero);
3257 code = CM_ERROR_NOSUCHFILE;
3259 cm_ReleaseSCache(dscp);
3261 cm_FreeSpace(spacep);
3262 cm_ReleaseUser(userp);
3263 smb_SendTran2Error(vcp, p, opx, code);
3264 smb_FreeTran2Packet(outp);
3270 #endif /* SPECIAL_FOLDERS */
3272 cm_FreeSpace(spacep);
3275 /* now do namei and stat, and copy out the info */
3276 code = cm_NameI(cm_data.rootSCachep, pathp,
3277 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3280 cm_ReleaseUser(userp);
3281 smb_SendTran2Error(vcp, p, opx, code);
3282 smb_FreeTran2Packet(outp);
3287 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3288 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3289 cm_ReleaseSCache(scp);
3290 cm_ReleaseUser(userp);
3291 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3292 code = CM_ERROR_PATH_NOT_COVERED;
3294 code = CM_ERROR_NOSUCHPATH;
3295 smb_SendTran2Error(vcp, p, opx, code);
3296 smb_FreeTran2Packet(outp);
3299 #endif /* DFS_SUPPORT */
3301 lock_ObtainWrite(&scp->rw);
3303 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3304 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3308 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3310 lock_ConvertWToR(&scp->rw);
3315 /* now we have the status in the cache entry, and everything is locked.
3316 * Marshall the output data.
3318 /* for info level 108, figure out short name */
3319 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3320 code = cm_GetShortName(pathp, userp, &req,
3321 tidPathp, scp->fid.vnode, shortName,
3327 smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
3328 qpi.u.QPfileAltNameInfo.fileNameLength = len;
3329 responseSize = sizeof(unsigned long) + len;
3331 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3332 smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3333 qpi.u.QPfileNameInfo.fileNameLength = len;
3334 responseSize = sizeof(unsigned long) + len;
3336 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3337 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3338 qpi.u.QPstandardInfo.creationDateTime = dosTime;
3339 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3340 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3341 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3342 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3343 attributes = smb_Attributes(scp);
3344 qpi.u.QPstandardInfo.attributes = attributes;
3345 qpi.u.QPstandardInfo.eaSize = 0;
3347 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3348 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3349 qpi.u.QPfileBasicInfo.creationTime = ft;
3350 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3351 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3352 qpi.u.QPfileBasicInfo.changeTime = ft;
3353 extAttributes = smb_ExtAttributes(scp);
3354 qpi.u.QPfileBasicInfo.attributes = extAttributes;
3355 qpi.u.QPfileBasicInfo.reserved = 0;
3357 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3360 lock_ReleaseRead(&scp->rw);
3362 fidp = smb_FindFIDByScache(vcp, scp);
3364 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3365 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3366 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3367 qpi.u.QPfileStandardInfo.directory =
3368 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3369 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3370 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3371 qpi.u.QPfileStandardInfo.reserved = 0;
3374 lock_ObtainMutex(&fidp->mx);
3375 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3376 lock_ReleaseMutex(&fidp->mx);
3377 smb_ReleaseFID(fidp);
3379 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3381 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3382 qpi.u.QPfileEaInfo.eaSize = 0;
3384 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3387 lock_ReleaseRead(&scp->rw);
3389 fidp = smb_FindFIDByScache(vcp, scp);
3391 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3392 qpi.u.QPfileAllInfo.creationTime = ft;
3393 qpi.u.QPfileAllInfo.lastAccessTime = ft;
3394 qpi.u.QPfileAllInfo.lastWriteTime = ft;
3395 qpi.u.QPfileAllInfo.changeTime = ft;
3396 extAttributes = smb_ExtAttributes(scp);
3397 qpi.u.QPfileAllInfo.attributes = extAttributes;
3398 qpi.u.QPfileAllInfo.allocationSize = scp->length;
3399 qpi.u.QPfileAllInfo.endOfFile = scp->length;
3400 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3401 qpi.u.QPfileAllInfo.deletePending = 0;
3402 qpi.u.QPfileAllInfo.directory =
3403 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3404 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3405 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3406 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.vnode;
3407 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.unique;
3408 qpi.u.QPfileAllInfo.eaSize = 0;
3409 qpi.u.QPfileAllInfo.accessFlags = 0;
3411 lock_ObtainMutex(&fidp->mx);
3412 if (fidp->flags & SMB_FID_OPENDELETE)
3413 qpi.u.QPfileAllInfo.accessFlags |= DELETE;
3414 if (fidp->flags & SMB_FID_OPENREAD_LISTDIR)
3415 qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_READ|AFS_ACCESS_EXECUTE;
3416 if (fidp->flags & SMB_FID_OPENWRITE)
3417 qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_WRITE;
3418 if (fidp->flags & SMB_FID_DELONCLOSE)
3419 qpi.u.QPfileAllInfo.deletePending = 1;
3420 lock_ReleaseMutex(&fidp->mx);
3421 smb_ReleaseFID(fidp);
3423 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.cell;
3424 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.volume;
3425 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3426 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3427 qpi.u.QPfileAllInfo.mode = 0;
3428 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3430 smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3431 qpi.u.QPfileAllInfo.fileNameLength = len;
3432 responseSize -= (sizeof(qpi.u.QPfileAllInfo.fileName) - len);
3434 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO) {
3436 /* For now we have no streams */
3437 qpi.u.QPfileStreamInfo.nextEntryOffset = 0;
3438 if (scp->fileType == CM_SCACHETYPE_FILE) {
3439 qpi.u.QPfileStreamInfo.streamSize = scp->length;
3440 qpi.u.QPfileStreamInfo.streamAllocationSize = scp->length;
3441 smb_UnparseString(opx, qpi.u.QPfileStreamInfo.fileName, L"::$DATA", &len, SMB_STRF_IGNORENUL);
3442 qpi.u.QPfileStreamInfo.streamNameLength = len;
3443 responseSize -= (sizeof(qpi.u.QPfileStreamInfo.fileName) - len);
3445 qpi.u.QPfileStreamInfo.streamSize.QuadPart = 0;
3446 qpi.u.QPfileStreamInfo.streamAllocationSize.QuadPart = 0;
3447 smb_UnparseString(opx, qpi.u.QPfileStreamInfo.fileName, L"", &len, SMB_STRF_IGNORENUL);
3448 qpi.u.QPfileStreamInfo.streamNameLength = 0;
3452 outp->totalData = responseSize;
3454 /* send and free the packets */
3456 switch (scp_rw_held) {
3458 lock_ReleaseRead(&scp->rw);
3461 lock_ReleaseWrite(&scp->rw);
3465 cm_ReleaseSCache(scp);
3466 cm_ReleaseUser(userp);
3468 memcpy(outp->datap, &qpi, responseSize);
3469 smb_SendTran2Packet(vcp, outp, opx);
3471 smb_SendTran2Error(vcp, p, opx, code);
3473 smb_FreeTran2Packet(outp);
3478 /* TRANS2_SET_PATH_INFORMATION */
3479 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3482 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
3483 return CM_ERROR_BADOP;
3486 unsigned short infoLevel;
3487 clientchar_t * pathp;
3488 smb_tran2Packet_t *outp;
3489 smb_tran2QPathInfo_t *spi;
3491 cm_scache_t *scp, *dscp;
3494 clientchar_t *tidPathp;
3495 clientchar_t *lastComp;
3499 infoLevel = p->parmsp[0];
3500 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
3501 if (infoLevel != SMB_INFO_STANDARD &&
3502 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
3503 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
3504 osi_Log2(smb_logp, "Bad Tran2SetPathInfo op 0x%x infolevel 0x%x",
3505 p->opcode, infoLevel);
3506 smb_SendTran2Error(vcp, p, opx,
3507 infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3511 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3513 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
3514 osi_LogSaveClientString(smb_logp, pathp));
3516 userp = smb_GetTran2User(vcp, p);
3518 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3519 code = CM_ERROR_BADSMB;
3523 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3524 if (code == CM_ERROR_TIDIPC) {
3525 /* Attempt to use a TID allocated for IPC. The client
3526 * is probably looking for DCE RPC end points which we
3527 * don't support OR it could be looking to make a DFS
3530 osi_Log0(smb_logp, "Tran2Open received IPC TID");
3531 cm_ReleaseUser(userp);
3532 return CM_ERROR_NOSUCHPATH;
3536 * XXX Strange hack XXX
3538 * As of Patch 7 (13 January 98), we are having the following problem:
3539 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3540 * requests to look up "desktop.ini" in all the subdirectories.
3541 * This can cause zillions of timeouts looking up non-existent cells
3542 * and volumes, especially in the top-level directory.
3544 * We have not found any way to avoid this or work around it except
3545 * to explicitly ignore the requests for mount points that haven't
3546 * yet been evaluated and for directories that haven't yet been
3549 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3550 spacep = cm_GetSpace();
3551 /* smb_StripLastComponent will strip "::$DATA" if present */
3552 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3553 #ifndef SPECIAL_FOLDERS
3554 /* Make sure that lastComp is not NULL */
3556 if (cm_ClientStrCmpI(lastComp, _C("\\desktop.ini")) == 0) {
3557 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3561 userp, tidPathp, &req, &dscp);
3564 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3565 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3567 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3568 code = CM_ERROR_PATH_NOT_COVERED;
3570 code = CM_ERROR_NOSUCHPATH;
3572 #endif /* DFS_SUPPORT */
3573 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3574 code = CM_ERROR_NOSUCHFILE;
3575 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3576 cm_buf_t *bp = buf_Find(dscp, &hzero);
3582 code = CM_ERROR_NOSUCHFILE;
3584 cm_ReleaseSCache(dscp);
3586 cm_FreeSpace(spacep);
3587 cm_ReleaseUser(userp);
3588 smb_SendTran2Error(vcp, p, opx, code);
3594 #endif /* SPECIAL_FOLDERS */
3596 cm_FreeSpace(spacep);
3599 /* now do namei and stat, and copy out the info */
3600 code = cm_NameI(cm_data.rootSCachep, pathp,
3601 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3603 cm_ReleaseUser(userp);
3604 smb_SendTran2Error(vcp, p, opx, code);
3608 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3610 outp->totalParms = 2;
3611 outp->totalData = 0;
3613 spi = (smb_tran2QPathInfo_t *)p->datap;
3614 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3617 /* lock the vnode with a callback; we need the current status
3618 * to determine what the new status is, in some cases.
3620 lock_ObtainWrite(&scp->rw);
3621 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3622 CM_SCACHESYNC_GETSTATUS
3623 | CM_SCACHESYNC_NEEDCALLBACK);
3625 lock_ReleaseWrite(&scp->rw);
3628 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3630 /* prepare for setattr call */
3631 attr.mask = CM_ATTRMASK_LENGTH;
3632 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3633 attr.length.HighPart = 0;
3635 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3636 cm_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3637 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3640 if (spi->u.QPstandardInfo.attributes != 0) {
3641 if ((scp->unixModeBits & 0222)
3642 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3643 /* make a writable file read-only */
3644 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3645 attr.unixModeBits = scp->unixModeBits & ~0222;
3647 else if ((scp->unixModeBits & 0222) == 0
3648 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3649 /* make a read-only file writable */
3650 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3651 attr.unixModeBits = scp->unixModeBits | 0222;
3654 lock_ReleaseRead(&scp->rw);
3658 code = cm_SetAttr(scp, &attr, userp, &req);
3662 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3663 /* we don't support EAs */
3664 code = CM_ERROR_EAS_NOT_SUPPORTED;
3668 cm_ReleaseSCache(scp);
3669 cm_ReleaseUser(userp);
3671 smb_SendTran2Packet(vcp, outp, opx);
3673 smb_SendTran2Error(vcp, p, opx, code);
3674 smb_FreeTran2Packet(outp);
3680 /* TRANS2_QUERY_FILE_INFORMATION */
3681 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3683 smb_tran2Packet_t *outp;
3685 unsigned long attributes;
3686 unsigned short infoLevel;
3693 smb_tran2QFileInfo_t qfi;
3701 fidp = smb_FindFID(vcp, fid, 0);
3704 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3708 lock_ObtainMutex(&fidp->mx);
3709 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3710 lock_ReleaseMutex(&fidp->mx);
3711 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3712 smb_CloseFID(vcp, fidp, NULL, 0);
3713 smb_ReleaseFID(fidp);
3716 lock_ReleaseMutex(&fidp->mx);
3718 infoLevel = p->parmsp[1];
3719 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3720 responseSize = sizeof(qfi.u.QFbasicInfo);
3721 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3722 responseSize = sizeof(qfi.u.QFstandardInfo);
3723 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3724 responseSize = sizeof(qfi.u.QFeaInfo);
3725 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3726 responseSize = sizeof(qfi.u.QFfileNameInfo);
3727 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO)
3728 responseSize = sizeof(qfi.u.QFfileStreamInfo);
3730 osi_Log2(smb_logp, "Bad Tran2QFileInfo op 0x%x infolevel 0x%x",
3731 p->opcode, infoLevel);
3732 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3733 smb_ReleaseFID(fidp);
3736 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3737 memset(&qfi, 0, sizeof(qfi));
3739 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3741 if (infoLevel > 0x100)
3742 outp->totalParms = 2;
3744 outp->totalParms = 0;
3746 userp = smb_GetTran2User(vcp, p);
3748 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3749 code = CM_ERROR_BADSMB;
3753 lock_ObtainMutex(&fidp->mx);
3754 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3756 osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3758 lock_ReleaseMutex(&fidp->mx);
3759 lock_ObtainWrite(&scp->rw);
3760 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3761 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3765 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3767 lock_ConvertWToR(&scp->rw);
3770 /* now we have the status in the cache entry, and everything is locked.
3771 * Marshall the output data.
3773 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3774 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3775 qfi.u.QFbasicInfo.creationTime = ft;
3776 qfi.u.QFbasicInfo.lastAccessTime = ft;
3777 qfi.u.QFbasicInfo.lastWriteTime = ft;
3778 qfi.u.QFbasicInfo.lastChangeTime = ft;
3779 attributes = smb_ExtAttributes(scp);
3780 qfi.u.QFbasicInfo.attributes = attributes;
3782 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3783 qfi.u.QFstandardInfo.allocationSize = scp->length;
3784 qfi.u.QFstandardInfo.endOfFile = scp->length;
3785 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3786 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3787 qfi.u.QFstandardInfo.directory =
3788 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3789 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3790 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3792 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3793 qfi.u.QFeaInfo.eaSize = 0;
3795 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3799 lock_ReleaseRead(&scp->rw);
3800 lock_ObtainMutex(&fidp->mx);
3801 lock_ObtainRead(&scp->rw);
3802 if (fidp->NTopen_wholepathp)
3803 name = fidp->NTopen_wholepathp;
3805 name = _C("\\"); /* probably can't happen */
3806 lock_ReleaseMutex(&fidp->mx);
3808 smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, SMB_STRF_IGNORENUL);
3809 responseSize = len + 4; /* this is actually what we want to return */
3810 qfi.u.QFfileNameInfo.fileNameLength = len;
3812 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO) {
3814 /* For now we have no streams */
3815 qfi.u.QFfileStreamInfo.nextEntryOffset = 0;
3816 qfi.u.QFfileStreamInfo.streamSize = scp->length;
3817 qfi.u.QFfileStreamInfo.streamAllocationSize = scp->length;
3818 smb_UnparseString(opx, qfi.u.QFfileStreamInfo.fileName, L"::$DATA", &len, SMB_STRF_IGNORENUL);
3819 qfi.u.QFfileStreamInfo.streamNameLength = len;
3820 responseSize -= (sizeof(qfi.u.QFfileStreamInfo.fileName) - len);
3822 outp->totalData = responseSize;
3824 /* send and free the packets */
3827 lock_ReleaseRead(&scp->rw);
3829 lock_ReleaseWrite(&scp->rw);
3830 cm_ReleaseSCache(scp);
3831 cm_ReleaseUser(userp);
3832 smb_ReleaseFID(fidp);
3834 memcpy(outp->datap, &qfi, responseSize);
3835 smb_SendTran2Packet(vcp, outp, opx);
3837 smb_SendTran2Error(vcp, p, opx, code);
3839 smb_FreeTran2Packet(outp);
3845 /* TRANS2_SET_FILE_INFORMATION */
3846 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3851 unsigned short infoLevel;
3852 smb_tran2Packet_t *outp;
3853 cm_user_t *userp = NULL;
3854 cm_scache_t *scp = NULL;
3860 fidp = smb_FindFID(vcp, fid, 0);
3863 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3867 infoLevel = p->parmsp[1];
3868 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3869 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3870 osi_Log2(smb_logp, "Bad Tran2SetFileInfo op 0x%x infolevel 0x%x",
3871 p->opcode, infoLevel);
3872 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3873 smb_ReleaseFID(fidp);
3877 lock_ObtainMutex(&fidp->mx);
3878 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3879 lock_ReleaseMutex(&fidp->mx);
3880 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3881 smb_CloseFID(vcp, fidp, NULL, 0);
3882 smb_ReleaseFID(fidp);
3886 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
3887 !(fidp->flags & SMB_FID_OPENDELETE)) {
3888 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3889 fidp, fidp->scp, fidp->flags);
3890 lock_ReleaseMutex(&fidp->mx);
3891 smb_ReleaseFID(fidp);
3892 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3895 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3896 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3897 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3898 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3899 fidp, fidp->scp, fidp->flags);
3900 lock_ReleaseMutex(&fidp->mx);
3901 smb_ReleaseFID(fidp);
3902 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3907 osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3909 lock_ReleaseMutex(&fidp->mx);
3911 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3913 outp->totalParms = 2;
3914 outp->totalData = 0;
3916 userp = smb_GetTran2User(vcp, p);
3918 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3919 code = CM_ERROR_BADSMB;
3923 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3925 unsigned int attribute;
3927 smb_tran2QFileInfo_t *sfi;
3929 sfi = (smb_tran2QFileInfo_t *)p->datap;
3931 /* lock the vnode with a callback; we need the current status
3932 * to determine what the new status is, in some cases.
3934 lock_ObtainWrite(&scp->rw);
3935 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3936 CM_SCACHESYNC_GETSTATUS
3937 | CM_SCACHESYNC_NEEDCALLBACK);
3939 lock_ReleaseWrite(&scp->rw);
3943 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3945 lock_ReleaseWrite(&scp->rw);
3946 lock_ObtainMutex(&fidp->mx);
3947 lock_ObtainRead(&scp->rw);
3949 /* prepare for setattr call */
3952 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3953 /* when called as result of move a b, lastMod is (-1, -1).
3954 * If the check for -1 is not present, timestamp
3955 * of the resulting file will be 1969 (-1)
3957 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3958 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3959 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3960 cm_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3961 fidp->flags |= SMB_FID_MTIMESETDONE;
3964 attribute = sfi->u.QFbasicInfo.attributes;
3965 if (attribute != 0) {
3966 if ((scp->unixModeBits & 0222)
3967 && (attribute & SMB_ATTR_READONLY) != 0) {
3968 /* make a writable file read-only */
3969 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3970 attr.unixModeBits = scp->unixModeBits & ~0222;
3972 else if ((scp->unixModeBits & 0222) == 0
3973 && (attribute & SMB_ATTR_READONLY) == 0) {
3974 /* make a read-only file writable */
3975 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3976 attr.unixModeBits = scp->unixModeBits | 0222;
3979 lock_ReleaseRead(&scp->rw);
3980 lock_ReleaseMutex(&fidp->mx);
3984 code = cm_SetAttr(scp, &attr, userp, &req);
3988 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3989 int delflag = *((char *)(p->datap));
3990 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
3991 delflag, fidp, scp);
3992 if (*((char *)(p->datap))) { /* File is Deleted */
3993 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3996 lock_ObtainMutex(&fidp->mx);
3997 fidp->flags |= SMB_FID_DELONCLOSE;
3998 lock_ReleaseMutex(&fidp->mx);
4000 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
4006 lock_ObtainMutex(&fidp->mx);
4007 fidp->flags &= ~SMB_FID_DELONCLOSE;
4008 lock_ReleaseMutex(&fidp->mx);
4011 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
4012 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
4013 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
4016 attr.mask = CM_ATTRMASK_LENGTH;
4017 attr.length.LowPart = size.LowPart;
4018 attr.length.HighPart = size.HighPart;
4019 code = cm_SetAttr(scp, &attr, userp, &req);
4023 cm_ReleaseSCache(scp);
4024 cm_ReleaseUser(userp);
4025 smb_ReleaseFID(fidp);
4027 smb_SendTran2Packet(vcp, outp, opx);
4029 smb_SendTran2Error(vcp, p, opx, code);
4030 smb_FreeTran2Packet(outp);
4037 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4039 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
4040 return CM_ERROR_BADOP;
4045 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4047 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
4048 return CM_ERROR_BADOP;
4051 /* TRANS2_FIND_NOTIFY_FIRST */
4053 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4055 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
4056 return CM_ERROR_BADOP;
4059 /* TRANS2_FIND_NOTIFY_NEXT */
4061 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4063 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
4064 return CM_ERROR_BADOP;
4067 /* TRANS2_CREATE_DIRECTORY */
4069 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4071 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
4072 return CM_ERROR_BADOP;
4075 /* TRANS2_SESSION_SETUP */
4077 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4079 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
4080 return CM_ERROR_BADOP;
4083 struct smb_v2_referral {
4085 USHORT ReferralFlags;
4088 USHORT DfsPathOffset;
4089 USHORT DfsAlternativePathOffset;
4090 USHORT NetworkAddressOffset;
4093 /* TRANS2_GET_DFS_REFERRAL */
4095 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
4097 /* This is a UNICODE only request (bit15 of Flags2) */
4098 /* The TID must be IPC$ */
4100 /* The documentation for the Flags response field is contradictory */
4102 /* Use Version 1 Referral Element Format */
4103 /* ServerType = 0; indicates the next server should be queried for the file */
4104 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
4105 /* Node = UnicodeString of UNC path of the next share name */
4108 int maxReferralLevel = 0;
4109 clientchar_t requestFileName[1024] = _C("");
4110 clientchar_t referralPath[1024] = _C("");
4111 smb_tran2Packet_t *outp = 0;
4112 cm_user_t *userp = 0;
4113 cm_scache_t *scp = 0;
4114 cm_scache_t *dscp = 0;
4116 CPINFO CodePageInfo;
4117 int i, nbnLen, reqLen, refLen;
4122 maxReferralLevel = p->parmsp[0];
4124 GetCPInfo(CP_ACP, &CodePageInfo);
4125 cm_Utf16ToClientString(&p->parmsp[1], -1, requestFileName, lengthof(requestFileName));
4127 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%S]",
4128 maxReferralLevel, osi_LogSaveClientString(smb_logp, requestFileName));
4130 nbnLen = (int)cm_ClientStrLen(cm_NetbiosNameC);
4131 reqLen = (int)cm_ClientStrLen(requestFileName);
4133 if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
4134 !cm_ClientStrCmpNI(cm_NetbiosNameC, &requestFileName[1], nbnLen) &&
4135 requestFileName[nbnLen+1] == '\\')
4139 if (!cm_ClientStrCmpNI(_C("all"), &requestFileName[nbnLen+2], 3) ||
4140 !cm_ClientStrCmpNI(_C("*."), &requestFileName[nbnLen+2], 2)) {
4142 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4145 userp = smb_GetTran2User(vcp, p);
4147 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
4148 code = CM_ERROR_BADSMB;
4153 * We have a requested path. Check to see if it is something
4156 * But be careful because the name that we might be searching
4157 * for might be a known name with the final character stripped
4160 code = cm_NameI(cm_data.rootSCachep, &requestFileName[nbnLen+2],
4161 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
4162 userp, NULL, &req, &scp);
4164 code == CM_ERROR_ALLDOWN ||
4165 code == CM_ERROR_ALLBUSY ||
4166 code == CM_ERROR_ALLOFFLINE ||
4167 code == CM_ERROR_NOSUCHCELL ||
4168 code == CM_ERROR_NOSUCHVOLUME ||
4169 code == CM_ERROR_NOACCESS) {
4172 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4174 } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
4175 clientchar_t temp[1024];
4176 clientchar_t pathName[1024];
4177 clientchar_t *lastComponent;
4179 * we have a msdfs link somewhere in the path
4180 * we should figure out where in the path the link is.
4183 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%S]", requestFileName);
4185 cm_ClientStrCpy(temp, lengthof(temp), &requestFileName[nbnLen+2]);
4189 cm_ReleaseSCache(dscp);
4193 cm_ReleaseSCache(scp);
4196 /* smb_StripLastComponent will strip "::$DATA" if present */
4197 smb_StripLastComponent(pathName, &lastComponent, temp);
4199 code = cm_NameI(cm_data.rootSCachep, pathName,
4200 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4201 userp, NULL, &req, &dscp);
4203 code = cm_NameI(dscp, ++lastComponent,
4205 userp, NULL, &req, &scp);
4206 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK)
4209 } while (code == CM_ERROR_PATH_NOT_COVERED);
4211 /* scp should now be the DfsLink we are looking for */
4213 /* figure out how much of the input path was used */
4214 reqLen = (int)(nbnLen+2 + cm_ClientStrLen(pathName) + 1 + cm_ClientStrLen(lastComponent));
4216 cm_FsStringToClientString(&scp->mountPointStringp[strlen("msdfs:")], -1,
4217 referralPath, lengthof(referralPath));
4218 refLen = (int)cm_ClientStrLen(referralPath);
4222 clientchar_t shareName[MAX_PATH + 1];
4223 clientchar_t *p, *q;
4224 /* we may have a sharename that is a volume reference */
4226 for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
4232 if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
4233 code = cm_NameI(cm_data.rootSCachep, _C(""),
4234 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
4235 userp, p, &req, &scp);
4240 cm_ClientStrCpy(referralPath, lengthof(referralPath),
4251 struct smb_v2_referral * v2ref;
4252 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (refLen + 8));
4254 sp = (USHORT *)outp->datap;
4256 sp[idx++] = reqLen; /* path consumed */
4257 sp[idx++] = 1; /* number of referrals */
4258 sp[idx++] = 0x03; /* flags */
4259 #ifdef DFS_VERSION_1
4260 sp[idx++] = 1; /* Version Number */
4261 sp[idx++] = refLen + 4; /* Referral Size */
4262 sp[idx++] = 1; /* Type = SMB Server */
4263 sp[idx++] = 0; /* Do not strip path consumed */
4264 for ( i=0;i<=refLen; i++ )
4265 sp[i+idx] = referralPath[i];
4266 #else /* DFS_VERSION_2 */
4267 sp[idx++] = 2; /* Version Number */
4268 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
4269 idx += (sizeof(struct smb_v2_referral) / 2);
4270 v2ref = (struct smb_v2_referral *) &sp[5];
4271 v2ref->ServerType = 1; /* SMB Server */
4272 v2ref->ReferralFlags = 0x03;
4273 v2ref->Proximity = 0; /* closest */
4274 v2ref->TimeToLive = 3600; /* seconds */
4275 v2ref->DfsPathOffset = idx * 2;
4276 v2ref->DfsAlternativePathOffset = idx * 2;
4277 v2ref->NetworkAddressOffset = 0;
4278 for ( i=0;i<=refLen; i++ )
4279 sp[i+idx] = referralPath[i];
4282 code = CM_ERROR_NOSUCHPATH;
4285 code = CM_ERROR_NOSUCHPATH;
4290 cm_ReleaseSCache(dscp);
4292 cm_ReleaseSCache(scp);
4294 cm_ReleaseUser(userp);
4296 smb_SendTran2Packet(vcp, outp, op);
4298 smb_SendTran2Error(vcp, p, op, code);
4300 smb_FreeTran2Packet(outp);
4303 #else /* DFS_SUPPORT */
4304 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
4305 return CM_ERROR_NOSUCHDEVICE;
4306 #endif /* DFS_SUPPORT */
4309 /* TRANS2_REPORT_DFS_INCONSISTENCY */
4311 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4313 /* This is a UNICODE only request (bit15 of Flags2) */
4315 /* There is nothing we can do about this operation. The client is going to
4316 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
4317 * Unfortunately, there is really nothing we can do about it other then log it
4318 * somewhere. Even then I don't think there is anything for us to do.
4319 * So let's return an error value.
4322 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
4323 return CM_ERROR_BADOP;
4327 smb_ApplyV3DirListPatches(cm_scache_t *dscp, smb_dirListPatch_t **dirPatchespp,
4328 clientchar_t * tidPathp, clientchar_t * relPathp,
4329 int infoLevel, cm_user_t *userp, cm_req_t *reqp)
4333 cm_scache_t *targetScp; /* target if scp is a symlink */
4336 unsigned short attr;
4337 unsigned long lattr;
4338 smb_dirListPatch_t *patchp;
4339 smb_dirListPatch_t *npatchp;
4341 afs_int32 mustFake = 0;
4342 clientchar_t path[AFSPATHMAX];
4344 code = cm_FindACLCache(dscp, userp, &rights);
4346 lock_ObtainWrite(&dscp->rw);
4347 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4348 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4350 cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4351 lock_ReleaseWrite(&dscp->rw);
4352 if (code == CM_ERROR_NOACCESS) {
4360 if (!mustFake) { /* Bulk Stat */
4362 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4364 memset(bsp, 0, sizeof(cm_bulkStat_t));
4366 for (patchp = *dirPatchespp, count=0;
4368 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4369 cm_scache_t *tscp = NULL;
4372 code = cm_GetSCache(&patchp->fid, &tscp, userp, reqp);
4374 if (lock_TryWrite(&tscp->rw)) {
4375 /* we have an entry that we can look at */
4376 #ifdef AFS_FREELANCE_CLIENT
4377 if (dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID && dscp->fid.volume == AFS_FAKE_ROOT_VOL_ID) {
4378 code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
4379 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4381 cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4383 lock_ReleaseWrite(&tscp->rw);
4384 cm_ReleaseSCache(tscp);
4387 #endif /* AFS_FREELANCE_CLIENT */
4388 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4389 /* we have a callback on it. Don't bother
4390 * fetching this stat entry, since we're happy
4391 * with the info we have.
4393 lock_ReleaseWrite(&tscp->rw);
4394 cm_ReleaseSCache(tscp);
4397 lock_ReleaseWrite(&tscp->rw);
4399 cm_ReleaseSCache(tscp);
4403 bsp->fids[i].Volume = patchp->fid.volume;
4404 bsp->fids[i].Vnode = patchp->fid.vnode;
4405 bsp->fids[i].Unique = patchp->fid.unique;
4407 if (bsp->counter == AFSCBMAX) {
4408 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4409 memset(bsp, 0, sizeof(cm_bulkStat_t));
4413 if (bsp->counter > 0)
4414 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4419 for( patchp = *dirPatchespp;
4421 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4422 cm_ClientStrPrintfN(path, lengthof(path),_C("%s\\%S"),
4423 relPathp ? relPathp : _C(""), patchp->dep->name);
4424 reqp->relPathp = path;
4425 reqp->tidPathp = tidPathp;
4427 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4428 reqp->relPathp = reqp->tidPathp = NULL;
4432 lock_ObtainWrite(&scp->rw);
4433 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4434 lock_ReleaseWrite(&scp->rw);
4436 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4437 errors in the client. */
4438 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4439 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4441 /* 1969-12-31 23:59:59 +00 */
4442 ft.dwHighDateTime = 0x19DB200;
4443 ft.dwLowDateTime = 0x5BB78980;
4445 /* copy to Creation Time */
4446 fa->creationTime = ft;
4447 fa->lastAccessTime = ft;
4448 fa->lastWriteTime = ft;
4449 fa->lastChangeTime = ft;
4451 switch (scp->fileType) {
4452 case CM_SCACHETYPE_DIRECTORY:
4453 case CM_SCACHETYPE_MOUNTPOINT:
4454 case CM_SCACHETYPE_INVALID:
4455 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4457 case CM_SCACHETYPE_SYMLINK:
4458 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4459 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4461 fa->extFileAttributes = SMB_ATTR_NORMAL;
4464 /* if we get here we either have a normal file
4465 * or we have a file for which we have never
4466 * received status info. In this case, we can
4467 * check the even/odd value of the entry's vnode.
4468 * odd means it is to be treated as a directory
4469 * and even means it is to be treated as a file.
4471 if (mustFake && (scp->fid.vnode & 0x1))
4472 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4474 fa->extFileAttributes = SMB_ATTR_NORMAL;
4476 /* merge in hidden attribute */
4477 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4478 fa->extFileAttributes |= SMB_ATTR_HIDDEN;
4481 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4483 /* 1969-12-31 23:59:58 +00*/
4484 dosTime = 0xEBBFBF7D;
4486 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4487 fa->lastAccessDateTime = fa->creationDateTime;
4488 fa->lastWriteDateTime = fa->creationDateTime;
4490 /* set the attribute */
4491 switch (scp->fileType) {
4492 case CM_SCACHETYPE_DIRECTORY:
4493 case CM_SCACHETYPE_MOUNTPOINT:
4494 case CM_SCACHETYPE_INVALID:
4495 fa->attributes = SMB_ATTR_DIRECTORY;
4497 case CM_SCACHETYPE_SYMLINK:
4498 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4499 fa->attributes = SMB_ATTR_DIRECTORY;
4501 fa->attributes = SMB_ATTR_NORMAL;
4504 /* if we get here we either have a normal file
4505 * or we have a file for which we have never
4506 * received status info. In this case, we can
4507 * check the even/odd value of the entry's vnode.
4508 * even means it is to be treated as a directory
4509 * and odd means it is to be treated as a file.
4511 if (mustFake && (scp->fid.vnode & 0x1))
4512 fa->attributes = SMB_ATTR_DIRECTORY;
4514 fa->attributes = SMB_ATTR_NORMAL;
4517 /* merge in hidden (dot file) attribute */
4518 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4519 fa->attributes |= SMB_ATTR_HIDDEN;
4523 cm_ReleaseSCache(scp);
4527 /* now watch for a symlink */
4529 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
4530 lock_ReleaseWrite(&scp->rw);
4531 cm_ClientStrPrintfN(path, lengthof(path), _C("%s\\%S"),
4532 relPathp ? relPathp : _C(""), patchp->dep->name);
4533 reqp->relPathp = path;
4534 reqp->tidPathp = tidPathp;
4535 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
4536 reqp->relPathp = reqp->tidPathp = NULL;
4538 /* we have a more accurate file to use (the
4539 * target of the symbolic link). Otherwise,
4540 * we'll just use the symlink anyway.
4542 osi_Log2(smb_logp, "symlink vp %x to vp %x",
4544 cm_ReleaseSCache(scp);
4547 lock_ObtainWrite(&scp->rw);
4550 lock_ConvertWToR(&scp->rw);
4552 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4553 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4556 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4558 fa->creationTime = ft;
4559 fa->lastAccessTime = ft;
4560 fa->lastWriteTime = ft;
4561 fa->lastChangeTime = ft;
4563 /* Use length for both file length and alloc length */
4564 fa->endOfFile = scp->length;
4565 fa->allocationSize = scp->length;
4567 /* Copy attributes */
4568 lattr = smb_ExtAttributes(scp);
4569 if ((code == CM_ERROR_NOSUCHPATH &&
4570 (scp->fileType == CM_SCACHETYPE_SYMLINK &&
4571 cm_TargetPerceivedAsDirectory(scp->mountPointStringp))) ||
4572 code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4573 if (lattr == SMB_ATTR_NORMAL)
4574 lattr = SMB_ATTR_DIRECTORY;
4576 lattr |= SMB_ATTR_DIRECTORY;
4578 /* merge in hidden (dot file) attribute */
4579 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4580 if (lattr == SMB_ATTR_NORMAL)
4581 lattr = SMB_ATTR_HIDDEN;
4583 lattr |= SMB_ATTR_HIDDEN;
4586 fa->extFileAttributes = lattr;
4588 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4591 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4593 fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
4594 fa->lastAccessDateTime = fa->creationDateTime;
4595 fa->lastWriteDateTime = fa->creationDateTime;
4597 /* copy out file length and alloc length,
4598 * using the same for both
4600 fa->dataSize = scp->length.LowPart;
4601 fa->allocationSize = scp->length.LowPart;
4603 /* finally copy out attributes as short */
4604 attr = smb_Attributes(scp);
4605 /* merge in hidden (dot file) attribute */
4606 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4607 if (lattr == SMB_ATTR_NORMAL)
4608 lattr = SMB_ATTR_HIDDEN;
4610 lattr |= SMB_ATTR_HIDDEN;
4612 fa->attributes = attr;
4615 lock_ReleaseRead(&scp->rw);
4616 cm_ReleaseSCache(scp);
4619 /* now free the patches */
4620 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4621 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4625 /* and mark the list as empty */
4626 *dirPatchespp = NULL;
4632 /* smb_ReceiveTran2SearchDir implements both
4633 * Tran2_Find_First and Tran2_Find_Next
4635 #define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
4636 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
4637 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
4638 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
4639 #define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
4641 /* this is an optimized handler for T2SearchDir that handles the case
4642 where there are no wildcards in the search path. I.e. an
4643 application is using FindFirst(Ex) to get information about a
4644 single file or directory. It will attempt to do a single lookup.
4645 If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4646 the usual mechanism.
4648 This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4650 TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
4652 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4656 long code = 0, code2 = 0;
4657 clientchar_t *pathp = 0;
4659 smb_dirListPatch_t *dirListPatchesp;
4660 smb_dirListPatch_t *curPatchp;
4661 size_t orbytes; /* # of bytes in this output record */
4662 size_t ohbytes; /* # of bytes, except file name */
4663 size_t onbytes; /* # of bytes in name, incl. term. null */
4664 cm_scache_t *scp = NULL;
4665 cm_scache_t *targetscp = NULL;
4666 cm_user_t *userp = NULL;
4667 char *op; /* output data ptr */
4668 char *origOp; /* original value of op */
4669 cm_space_t *spacep; /* for pathname buffer */
4670 unsigned long maxReturnData; /* max # of return data */
4671 long maxReturnParms; /* max # of return parms */
4672 long bytesInBuffer; /* # data bytes in the output buffer */
4673 clientchar_t *maskp; /* mask part of path */
4677 smb_tran2Packet_t *outp; /* response packet */
4678 clientchar_t *tidPathp = 0;
4680 clientchar_t shortName[13]; /* 8.3 name if needed */
4682 clientchar_t *shortNameEnd;
4683 cm_dirEntry_t * dep = NULL;
4686 void * attrp = NULL;
4687 smb_tran2Find_t * fp;
4692 osi_assertx(p->opcode == 1, "invalid opcode");
4694 /* find first; obtain basic parameters from request */
4696 /* note that since we are going to failover to regular
4697 * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4698 * modify any of the input parameters here. */
4699 attribute = p->parmsp[0];
4700 maxCount = p->parmsp[1];
4701 infoLevel = p->parmsp[3];
4702 searchFlags = p->parmsp[2];
4703 pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4705 maskp = cm_ClientStrRChr(pathp, '\\');
4709 maskp++; /* skip over backslash */
4710 /* track if this is likely to match a lot of entries */
4712 osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%S], mask[%S]",
4713 osi_LogSaveClientString(smb_logp, pathp),
4714 osi_LogSaveClientString(smb_logp, maskp));
4716 switch ( infoLevel ) {
4717 case SMB_INFO_STANDARD:
4719 ohbytes = sizeof(fp->u.FstandardInfo);
4722 case SMB_INFO_QUERY_EA_SIZE:
4723 ohbytes = sizeof(fp->u.FeaSizeInfo);
4724 s = "InfoQueryEaSize";
4727 case SMB_INFO_QUERY_EAS_FROM_LIST:
4728 ohbytes = sizeof(fp->u.FeasFromListInfo);
4729 s = "InfoQueryEasFromList";
4732 case SMB_FIND_FILE_DIRECTORY_INFO:
4733 s = "FindFileDirectoryInfo";
4734 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4737 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4738 s = "FindFileFullDirectoryInfo";
4739 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4742 case SMB_FIND_FILE_NAMES_INFO:
4743 s = "FindFileNamesInfo";
4744 ohbytes = sizeof(fp->u.FfileNamesInfo);
4747 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4748 s = "FindFileBothDirectoryInfo";
4749 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4753 s = "unknownInfoLevel";
4757 osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
4760 "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4761 attribute, infoLevel, maxCount, searchFlags);
4764 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4765 return CM_ERROR_INVAL;
4768 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4769 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4771 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4774 dirListPatchesp = NULL;
4776 maxReturnData = p->maxReturnData;
4777 maxReturnParms = 10; /* return params for findfirst, which
4778 is the only one we handle.*/
4780 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4783 osi_Log2(smb_logp, "T2SDSingle search dir count %d [%S]",
4784 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4786 /* bail out if request looks bad */
4788 smb_FreeTran2Packet(outp);
4789 return CM_ERROR_BADSMB;
4792 userp = smb_GetTran2User(vcp, p);
4794 osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
4795 smb_FreeTran2Packet(outp);
4796 return CM_ERROR_BADSMB;
4799 /* try to get the vnode for the path name next */
4800 spacep = cm_GetSpace();
4801 /* smb_StripLastComponent will strip "::$DATA" if present */
4802 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4803 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4805 cm_ReleaseUser(userp);
4806 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4807 smb_FreeTran2Packet(outp);
4811 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4812 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4813 userp, tidPathp, &req, &scp);
4814 cm_FreeSpace(spacep);
4817 cm_ReleaseUser(userp);
4818 smb_SendTran2Error(vcp, p, opx, code);
4819 smb_FreeTran2Packet(outp);
4823 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4824 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4825 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
4826 cm_ReleaseSCache(scp);
4827 cm_ReleaseUser(userp);
4828 if ( WANTS_DFS_PATHNAMES(p) || pnc )
4829 code = CM_ERROR_PATH_NOT_COVERED;
4831 code = CM_ERROR_NOSUCHPATH;
4832 smb_SendTran2Error(vcp, p, opx, code);
4833 smb_FreeTran2Packet(outp);
4836 #endif /* DFS_SUPPORT */
4837 osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
4839 /* now do a single case sensitive lookup for the file in question */
4840 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
4842 /* if a case sensitive match failed, we try a case insensitive one
4844 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
4845 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
4848 if (code == 0 && targetscp->fid.vnode == 0) {
4849 cm_ReleaseSCache(targetscp);
4850 code = CM_ERROR_NOSUCHFILE;
4854 /* if we can't find the directory entry, this block will
4855 return CM_ERROR_NOSUCHFILE, which we will pass on to
4856 smb_ReceiveTran2SearchDir(). */
4857 cm_ReleaseSCache(scp);
4858 cm_ReleaseUser(userp);
4859 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4860 smb_SendTran2Error(vcp, p, opx, code);
4863 smb_FreeTran2Packet(outp);
4867 /* now that we have the target in sight, we proceed with filling
4868 up the return data. */
4870 op = origOp = outp->datap;
4873 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4874 /* skip over resume key */
4878 fp = (smb_tran2Find_t *) op;
4880 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4881 && targetscp->fid.vnode != 0
4882 && !cm_Is8Dot3(maskp)) {
4885 dfid.vnode = htonl(targetscp->fid.vnode);
4886 dfid.unique = htonl(targetscp->fid.unique);
4888 cm_Gen8Dot3NameIntW(maskp, &dfid, shortName, &shortNameEnd);
4894 osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %S (%S)",
4895 htonl(targetscp->fid.vnode),
4896 htonl(targetscp->fid.unique),
4897 osi_LogSaveClientString(smb_logp, pathp),
4898 (NeedShortName)? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
4900 /* Eliminate entries that don't match requested attributes */
4901 if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
4902 smb_IsDotFile(maskp)) {
4904 code = CM_ERROR_NOSUCHFILE;
4905 osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
4910 if (!(attribute & SMB_ATTR_DIRECTORY) &&
4911 (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
4912 targetscp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4913 targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
4914 targetscp->fileType == CM_SCACHETYPE_INVALID)) {
4916 code = CM_ERROR_NOSUCHFILE;
4917 osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
4922 /* add header to name & term. null */
4924 smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
4925 orbytes = ohbytes + onbytes;
4927 /* now, we round up the record to a 4 byte alignment, and we make
4928 * sure that we have enough room here for even the aligned version
4929 * (so we don't have to worry about an * overflow when we pad
4930 * things out below). That's the reason for the alignment
4933 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4934 align = (4 - (orbytes & 3)) & 3;
4938 if (orbytes + align > maxReturnData) {
4940 /* even though this request is unlikely to succeed with a
4941 failover, we do it anyway. */
4942 code = CM_ERROR_NOSUCHFILE;
4943 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4948 /* this is one of the entries to use: it is not deleted and it
4949 * matches the star pattern we're looking for. Put out the name,
4950 * preceded by its length.
4952 /* First zero everything else */
4953 memset(origOp, 0, orbytes);
4956 smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
4958 switch (infoLevel) {
4959 case SMB_INFO_STANDARD:
4960 fp->u.FstandardInfo.fileNameLength = onbytes;
4961 attrp = &fp->u.FstandardInfo.fileAttrs;
4964 case SMB_INFO_QUERY_EA_SIZE:
4965 fp->u.FeaSizeInfo.fileNameLength = onbytes;
4966 attrp = &fp->u.FeaSizeInfo.fileAttrs;
4967 fp->u.FeaSizeInfo.eaSize = 0;
4970 case SMB_INFO_QUERY_EAS_FROM_LIST:
4971 fp->u.FeasFromListInfo.fileNameLength = onbytes;
4972 attrp = &fp->u.FeasFromListInfo.fileAttrs;
4973 fp->u.FeasFromListInfo.eaSize = 0;
4976 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4977 if (NeedShortName) {
4981 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
4982 fp->u.FfileBothDirectoryInfo.shortName,
4983 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
4985 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
4987 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
4988 fp->u.FfileBothDirectoryInfo.reserved = 0;
4990 strcpy(fp->u.FfileBothDirectoryInfo.shortName,
4992 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
4997 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4998 fp->u.FfileFullDirectoryInfo.eaSize = 0;
5001 case SMB_FIND_FILE_DIRECTORY_INFO:
5002 fp->u.FfileDirectoryInfo.nextEntryOffset = 0;
5003 fp->u.FfileDirectoryInfo.fileIndex = 0;
5004 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5005 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5008 case SMB_FIND_FILE_NAMES_INFO:
5009 fp->u.FfileNamesInfo.nextEntryOffset = 0;
5010 fp->u.FfileNamesInfo.fileIndex = 0;
5011 fp->u.FfileNamesInfo.fileNameLength = onbytes;
5015 /* we shouldn't hit this case */
5016 osi_assertx(FALSE, "Unknown query type");
5019 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5020 osi_assert(attrp != NULL);
5022 curPatchp = malloc(sizeof(*curPatchp));
5023 osi_QAdd((osi_queue_t **) &dirListPatchesp,
5025 curPatchp->dptr = attrp;
5027 if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
5028 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5030 curPatchp->flags = 0;
5033 cm_SetFid(&curPatchp->fid, targetscp->fid.cell, targetscp->fid.volume, targetscp->fid.vnode, targetscp->fid.unique);
5037 int namelen = cm_ClientStringToFsString(maskp, -1, NULL, 0);
5038 dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+namelen);
5039 cm_ClientStringToFsString(maskp, -1, dep->name, namelen);
5041 dep->fid.vnode = targetscp->fid.vnode;
5042 dep->fid.unique = targetscp->fid.unique;
5043 curPatchp->dep = dep;
5046 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
5047 /* put out resume key */
5048 *((u_long *)origOp) = 0;
5051 /* Adjust byte ptr and count */
5052 origOp += orbytes; /* skip entire record */
5053 bytesInBuffer += orbytes;
5055 /* and pad the record out */
5056 while (--align >= 0) {
5061 /* apply the patches */
5062 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->wdata, infoLevel, userp, &req);
5064 outp->parmsp[0] = 0;
5065 outp->parmsp[1] = 1; /* number of names returned */
5066 outp->parmsp[2] = 1; /* end of search */
5067 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5068 outp->parmsp[4] = 0;
5070 outp->totalParms = 10; /* in bytes */
5072 outp->totalData = bytesInBuffer;
5074 osi_Log0(smb_logp, "T2SDSingle done.");
5076 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5078 smb_SendTran2Error(vcp, p, opx, code);
5080 smb_SendTran2Packet(vcp, outp, opx);
5085 smb_FreeTran2Packet(outp);
5089 cm_ReleaseSCache(scp);
5090 cm_ReleaseSCache(targetscp);
5091 cm_ReleaseUser(userp);
5097 /* TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2 */
5098 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
5103 long code = 0, code2 = 0;
5104 clientchar_t *pathp;
5105 cm_dirEntry_t *dep = 0;
5107 smb_dirListPatch_t *dirListPatchesp = 0;
5108 smb_dirListPatch_t *curPatchp = 0;
5111 size_t orbytes; /* # of bytes in this output record */
5112 size_t ohbytes; /* # of bytes, except file name */
5113 size_t onbytes; /* # of bytes in name, incl. term. null */
5114 osi_hyper_t dirLength;
5115 osi_hyper_t bufferOffset;
5116 osi_hyper_t curOffset;
5118 smb_dirSearch_t *dsp;
5122 cm_pageHeader_t *pageHeaderp;
5123 cm_user_t *userp = NULL;
5126 long nextEntryCookie;
5127 int numDirChunks; /* # of 32 byte dir chunks in this entry */
5128 char *op; /* output data ptr */
5129 char *origOp; /* original value of op */
5130 cm_space_t *spacep; /* for pathname buffer */
5131 unsigned long maxReturnData; /* max # of return data */
5132 unsigned long maxReturnParms; /* max # of return parms */
5133 long bytesInBuffer; /* # data bytes in the output buffer */
5135 clientchar_t *maskp; /* mask part of path */
5139 smb_tran2Packet_t *outp; /* response packet */
5140 clientchar_t *tidPathp;
5142 clientchar_t shortName[13]; /* 8.3 name if needed */
5145 clientchar_t *shortNameEnd;
5151 smb_tran2Find_t * fp;
5156 if (p->opcode == 1) {
5157 /* find first; obtain basic parameters from request */
5158 attribute = p->parmsp[0];
5159 maxCount = p->parmsp[1];
5160 infoLevel = p->parmsp[3];
5161 searchFlags = p->parmsp[2];
5162 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
5164 maskp = cm_ClientStrRChr(pathp, '\\');
5168 maskp++; /* skip over backslash */
5170 /* track if this is likely to match a lot of entries */
5171 starPattern = smb_V3IsStarMask(maskp);
5173 #ifndef NOFINDFIRSTOPTIMIZE
5175 /* if this is for a single directory or file, we let the
5176 optimized routine handle it. The only error it
5177 returns is CM_ERROR_NOSUCHFILE. The */
5178 code = smb_T2SearchDirSingle(vcp, p, opx);
5180 /* we only failover if we see a CM_ERROR_NOSUCHFILE */
5181 if (code != CM_ERROR_NOSUCHFILE) {
5183 /* unless we are using the BPlusTree */
5184 if (code == CM_ERROR_BPLUS_NOMATCH)
5185 code = CM_ERROR_NOSUCHFILE;
5186 #endif /* USE_BPLUS */
5190 #endif /* NOFINDFIRSTOPTIMIZE */
5193 dsp = smb_NewDirSearch(1);
5194 dsp->attribute = attribute;
5195 cm_ClientStrCpy(dsp->mask, lengthof(dsp->mask), maskp); /* and save mask */
5198 osi_assertx(p->opcode == 2, "invalid opcode");
5199 /* find next; obtain basic parameters from request or open dir file */
5200 dsp = smb_FindDirSearch(p->parmsp[0]);
5201 maxCount = p->parmsp[1];
5202 infoLevel = p->parmsp[2];
5203 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
5204 searchFlags = p->parmsp[5];
5206 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
5207 p->parmsp[0], nextCookie);
5208 return CM_ERROR_BADFD;
5210 attribute = dsp->attribute;
5213 starPattern = 1; /* assume, since required a Find Next */
5216 switch ( infoLevel ) {
5217 case SMB_INFO_STANDARD:
5219 ohbytes = sizeof(fp->u.FstandardInfo);
5222 case SMB_INFO_QUERY_EA_SIZE:
5223 ohbytes = sizeof(fp->u.FeaSizeInfo);
5224 s = "InfoQueryEaSize";
5227 case SMB_INFO_QUERY_EAS_FROM_LIST:
5228 ohbytes = sizeof(fp->u.FeasFromListInfo);
5229 s = "InfoQueryEasFromList";
5232 case SMB_FIND_FILE_DIRECTORY_INFO:
5233 s = "FindFileDirectoryInfo";
5234 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
5237 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5238 s = "FindFileFullDirectoryInfo";
5239 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
5242 case SMB_FIND_FILE_NAMES_INFO:
5243 s = "FindFileNamesInfo";
5244 ohbytes = sizeof(fp->u.FfileNamesInfo);
5247 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5248 s = "FindFileBothDirectoryInfo";
5249 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
5253 s = "unknownInfoLevel";
5257 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
5260 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
5261 attribute, infoLevel, maxCount, searchFlags);
5263 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
5264 p->opcode, dsp->cookie, nextCookie);
5267 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
5268 smb_ReleaseDirSearch(dsp);
5269 return CM_ERROR_INVAL;
5272 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5273 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
5275 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5278 dirListPatchesp = NULL;
5280 maxReturnData = p->maxReturnData;
5281 if (p->opcode == 1) /* find first */
5282 maxReturnParms = 10; /* bytes */
5284 maxReturnParms = 8; /* bytes */
5286 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
5292 osi_Log2(smb_logp, "T2 receive search dir count %d [%S]",
5293 maxCount, osi_LogSaveClientString(smb_logp, pathp));
5295 /* bail out if request looks bad */
5296 if (p->opcode == 1 && !pathp) {
5297 smb_ReleaseDirSearch(dsp);
5298 smb_FreeTran2Packet(outp);
5299 return CM_ERROR_BADSMB;
5302 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
5303 dsp->cookie, nextCookie, attribute);
5305 userp = smb_GetTran2User(vcp, p);
5307 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
5308 smb_ReleaseDirSearch(dsp);
5309 smb_FreeTran2Packet(outp);
5310 return CM_ERROR_BADSMB;
5313 /* try to get the vnode for the path name next */
5314 lock_ObtainMutex(&dsp->mx);
5317 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5321 spacep = cm_GetSpace();
5322 /* smb_StripLastComponent will strip "::$DATA" if present */
5323 smb_StripLastComponent(spacep->wdata, NULL, pathp);
5324 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
5326 cm_ReleaseUser(userp);
5327 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
5328 smb_FreeTran2Packet(outp);
5329 lock_ReleaseMutex(&dsp->mx);
5330 smb_DeleteDirSearch(dsp);
5331 smb_ReleaseDirSearch(dsp);
5335 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
5336 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
5338 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
5339 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5340 userp, tidPathp, &req, &scp);
5341 cm_FreeSpace(spacep);
5344 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
5345 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5346 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
5347 cm_ReleaseSCache(scp);
5348 cm_ReleaseUser(userp);
5349 if ( WANTS_DFS_PATHNAMES(p) || pnc )
5350 code = CM_ERROR_PATH_NOT_COVERED;
5352 code = CM_ERROR_NOSUCHPATH;
5353 smb_SendTran2Error(vcp, p, opx, code);
5354 smb_FreeTran2Packet(outp);
5355 lock_ReleaseMutex(&dsp->mx);
5356 smb_DeleteDirSearch(dsp);
5357 smb_ReleaseDirSearch(dsp);
5360 #endif /* DFS_SUPPORT */
5362 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5363 /* we need one hold for the entry we just stored into,
5364 * and one for our own processing. When we're done
5365 * with this function, we'll drop the one for our own
5366 * processing. We held it once from the namei call,
5367 * and so we do another hold now.
5370 dsp->flags |= SMB_DIRSEARCH_BULKST;
5373 lock_ReleaseMutex(&dsp->mx);
5375 cm_ReleaseUser(userp);
5376 smb_FreeTran2Packet(outp);
5377 smb_DeleteDirSearch(dsp);
5378 smb_ReleaseDirSearch(dsp);
5382 /* get the directory size */
5383 lock_ObtainWrite(&scp->rw);
5384 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5385 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5387 lock_ReleaseWrite(&scp->rw);
5388 cm_ReleaseSCache(scp);
5389 cm_ReleaseUser(userp);
5390 smb_FreeTran2Packet(outp);
5391 smb_DeleteDirSearch(dsp);
5392 smb_ReleaseDirSearch(dsp);
5396 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5399 dirLength = scp->length;
5401 bufferOffset.LowPart = bufferOffset.HighPart = 0;
5402 curOffset.HighPart = 0;
5403 curOffset.LowPart = nextCookie;
5404 origOp = outp->datap;
5411 normchar_t normName[MAX_PATH]; /* Normalized name */
5412 clientchar_t cfileName[MAX_PATH]; /* Non-normalized name */
5415 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5416 /* skip over resume key */
5419 fp = (smb_tran2Find_t *) op;
5421 /* make sure that curOffset.LowPart doesn't point to the first
5422 * 32 bytes in the 2nd through last dir page, and that it doesn't
5423 * point at the first 13 32-byte chunks in the first dir page,
5424 * since those are dir and page headers, and don't contain useful
5427 temp = curOffset.LowPart & (2048-1);
5428 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5429 /* we're in the first page */
5430 if (temp < 13*32) temp = 13*32;
5433 /* we're in a later dir page */
5434 if (temp < 32) temp = 32;
5437 /* make sure the low order 5 bits are zero */
5440 /* now put temp bits back ito curOffset.LowPart */
5441 curOffset.LowPart &= ~(2048-1);
5442 curOffset.LowPart |= temp;
5444 /* check if we've passed the dir's EOF */
5445 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
5446 osi_Log0(smb_logp, "T2 search dir passed eof");
5451 /* check if we've returned all the names that will fit in the
5452 * response packet; we check return count as well as the number
5453 * of bytes requested. We check the # of bytes after we find
5454 * the dir entry, since we'll need to check its size.
5456 if (returnedNames >= maxCount) {
5457 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
5458 returnedNames, maxCount);
5462 /* when we have obtained as many entries as can be processed in
5463 * a single Bulk Status call to the file server, apply the dir listing
5466 if (returnedNames > 0 && returnedNames % AFSCBMAX == 0) {
5467 lock_ReleaseWrite(&scp->rw);
5468 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5469 dsp->relPath, infoLevel, userp, &req);
5470 lock_ObtainWrite(&scp->rw);
5472 /* Then check to see if we have time left to process more entries */
5473 if (GetTickCount() - req.startTime > (RDRtimeout - 15) * 1000) {
5474 osi_Log0(smb_logp, "T2 search dir RDRtimeout exceeded");
5478 /* see if we can use the bufferp we have now; compute in which
5479 * page the current offset would be, and check whether that's
5480 * the offset of the buffer we have. If not, get the buffer.
5482 thyper.HighPart = curOffset.HighPart;
5483 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5484 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5487 buf_Release(bufferp);
5490 lock_ReleaseWrite(&scp->rw);
5491 code = buf_Get(scp, &thyper, &req, &bufferp);
5492 lock_ObtainWrite(&scp->rw);
5494 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
5498 bufferOffset = thyper;
5500 /* now get the data in the cache */
5502 code = cm_SyncOp(scp, bufferp, userp, &req,
5504 CM_SCACHESYNC_NEEDCALLBACK
5505 | CM_SCACHESYNC_READ);
5507 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5511 if (cm_HaveBuffer(scp, bufferp, 0)) {
5512 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5513 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5517 /* otherwise, load the buffer and try again */
5518 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5520 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5522 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5523 scp, bufferp, code);
5528 buf_Release(bufferp);
5532 } /* if (wrong buffer) ... */
5534 /* now we have the buffer containing the entry we're interested
5535 * in; copy it out if it represents a non-deleted entry.
5537 entryInDir = curOffset.LowPart & (2048-1);
5538 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5540 /* page header will help tell us which entries are free. Page
5541 * header can change more often than once per buffer, since
5542 * AFS 3 dir page size may be less than (but not more than)
5543 * a buffer package buffer.
5545 /* only look intra-buffer */
5546 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5547 temp &= ~(2048 - 1); /* turn off intra-page bits */
5548 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5550 /* now determine which entry we're looking at in the page.
5551 * If it is free (there's a free bitmap at the start of the
5552 * dir), we should skip these 32 bytes.
5554 slotInPage = (entryInDir & 0x7e0) >> 5;
5555 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5556 (1 << (slotInPage & 0x7)))) {
5557 /* this entry is free */
5558 numDirChunks = 1; /* only skip this guy */
5562 tp = bufferp->datap + entryInBuffer;
5563 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5565 /* while we're here, compute the next entry's location, too,
5566 * since we'll need it when writing out the cookie into the dir
5569 * XXXX Probably should do more sanity checking.
5571 numDirChunks = cm_NameEntries(dep->name, &onbytes);
5573 /* compute offset of cookie representing next entry */
5574 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5576 if (dep->fid.vnode == 0)
5577 goto nextEntry; /* This entry is not in use */
5579 if (cm_FsStringToClientString(dep->name, -1, cfileName, lengthof(cfileName)) == 0 ||
5580 cm_ClientStringToNormString(cfileName, -1, normName, lengthof(normName)) == 0) {
5582 osi_Log1(smb_logp, "Skipping entry [%s]. Can't convert or normalize FS String",
5583 osi_LogSaveString(smb_logp, dep->name));
5587 /* Need 8.3 name? */
5589 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
5590 !cm_Is8Dot3(cfileName)) {
5591 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5595 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %S (%S)",
5596 dep->fid.vnode, dep->fid.unique,
5597 osi_LogSaveClientString(smb_logp, cfileName),
5598 NeedShortName ? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
5600 /* When matching, we are using doing a case fold if we have a wildcard mask.
5601 * If we get a non-wildcard match, it's a lookup for a specific file.
5603 if (cm_MatchMask(normName, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5604 (NeedShortName && cm_MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))
5606 /* Eliminate entries that don't match requested attributes */
5607 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5608 smb_IsDotFile(cfileName)) {
5609 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5610 goto nextEntry; /* no hidden files */
5613 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5615 /* We have already done the cm_TryBulkStat above */
5616 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume,
5617 ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5618 fileType = cm_FindFileType(&fid);
5619 /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5620 * "has filetype %d", dep->name, fileType);
5622 if ( fileType == CM_SCACHETYPE_DIRECTORY ||
5623 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5624 fileType == CM_SCACHETYPE_DFSLINK ||
5625 fileType == CM_SCACHETYPE_INVALID)
5626 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5630 /* finally check if this name will fit */
5632 smb_UnparseString(opx, NULL, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5633 orbytes = ohbytes + onbytes;
5635 /* now, we round up the record to a 4 byte alignment,
5636 * and we make sure that we have enough room here for
5637 * even the aligned version (so we don't have to worry
5638 * about an overflow when we pad things out below).
5639 * That's the reason for the alignment arithmetic below.
5641 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5642 align = (4 - (orbytes & 3)) & 3;
5646 if (orbytes + bytesInBuffer + align > maxReturnData) {
5647 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5652 /* this is one of the entries to use: it is not deleted
5653 * and it matches the star pattern we're looking for.
5654 * Put out the name, preceded by its length.
5656 /* First zero everything else */
5657 memset(origOp, 0, orbytes);
5660 smb_UnparseString(opx, origOp + ohbytes, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5662 switch (infoLevel) {
5663 case SMB_INFO_STANDARD:
5664 fp->u.FstandardInfo.fileNameLength = onbytes;
5665 attrp = &fp->u.FstandardInfo.fileAttrs;
5668 case SMB_INFO_QUERY_EA_SIZE:
5669 fp->u.FeaSizeInfo.fileNameLength = onbytes;
5670 attrp = &fp->u.FeaSizeInfo.fileAttrs;
5671 fp->u.FeaSizeInfo.eaSize = 0;
5674 case SMB_INFO_QUERY_EAS_FROM_LIST:
5675 fp->u.FeasFromListInfo.fileNameLength = onbytes;
5676 attrp = &fp->u.FeasFromListInfo.fileAttrs;
5677 fp->u.FeasFromListInfo.eaSize = 0;
5680 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5681 if (NeedShortName) {
5685 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
5686 fp->u.FfileBothDirectoryInfo.shortName,
5687 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
5689 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
5691 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5692 fp->u.FfileBothDirectoryInfo.reserved = 0;
5694 cm_ClientStrCpy(fp->u.FfileBothDirectoryInfo.shortName,
5695 lengthof(fp->u.FfileBothDirectoryInfo.shortName),
5697 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
5702 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5703 fp->u.FfileFullDirectoryInfo.eaSize = 0;
5706 case SMB_FIND_FILE_DIRECTORY_INFO:
5707 fp->u.FfileDirectoryInfo.nextEntryOffset = orbytes + align;
5708 fp->u.FfileDirectoryInfo.fileIndex = nextEntryCookie;
5709 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5710 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5713 case SMB_FIND_FILE_NAMES_INFO:
5714 fp->u.FfileNamesInfo.nextEntryOffset = orbytes + align;
5715 fp->u.FfileNamesInfo.fileIndex = nextEntryCookie;
5716 fp->u.FfileNamesInfo.fileNameLength = onbytes;
5721 /* we shouldn't hit this case */
5722 osi_assertx(FALSE, "Unknown query type");
5725 /* now, adjust the # of entries copied */
5728 /* now we emit the attribute. This is tricky, since
5729 * we need to really stat the file to find out what
5730 * type of entry we've got. Right now, we're copying
5731 * out data from a buffer, while holding the scp
5732 * locked, so it isn't really convenient to stat
5733 * something now. We'll put in a place holder
5734 * now, and make a second pass before returning this
5735 * to get the real attributes. So, we just skip the
5736 * data for now, and adjust it later. We allocate a
5737 * patch record to make it easy to find this point
5738 * later. The replay will happen at a time when it is
5739 * safe to unlock the directory.
5741 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5742 osi_assert(attrp != NULL);
5743 curPatchp = malloc(sizeof(*curPatchp));
5744 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5745 curPatchp->dptr = attrp;
5747 if (smb_hideDotFiles && smb_IsDotFile(cfileName)) {
5748 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5750 curPatchp->flags = 0;
5753 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5756 curPatchp->dep = dep;
5759 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5760 /* put out resume key */
5761 *((u_long *)origOp) = nextEntryCookie;
5763 /* Adjust byte ptr and count */
5764 origOp += orbytes; /* skip entire record */
5765 bytesInBuffer += orbytes;
5767 /* and pad the record out */
5768 while (align-- > 0) {
5772 } /* if we're including this name */
5773 else if (!starPattern &&
5775 cm_MatchMask(normName, maskp, CM_FLAG_CASEFOLD)) {
5776 /* We were looking for exact matches, but here's an inexact one*/
5781 /* and adjust curOffset to be where the new cookie is */
5782 thyper.HighPart = 0;
5783 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5784 curOffset = LargeIntegerAdd(thyper, curOffset);
5785 } /* while copying data for dir listing */
5787 /* If we didn't get a star pattern, we did an exact match during the first pass.
5788 * If there were no exact matches found, we fail over to inexact matches by
5789 * marking the query as a star pattern (matches all case permutations), and
5790 * re-running the query.
5792 if (returnedNames == 0 && !starPattern && foundInexact) {
5793 osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
5798 /* release the mutex */
5799 lock_ReleaseWrite(&scp->rw);
5801 buf_Release(bufferp);
5806 * Finally, process whatever entries we have left.
5808 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5809 dsp->relPath, infoLevel, userp, &req);
5811 /* now put out the final parameters */
5812 if (returnedNames == 0)
5814 if (p->opcode == 1) {
5816 outp->parmsp[0] = (unsigned short) dsp->cookie;
5817 outp->parmsp[1] = returnedNames;
5818 outp->parmsp[2] = eos;
5819 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5820 outp->parmsp[4] = 0;
5821 /* don't need last name to continue
5822 * search, cookie is enough. Normally,
5823 * this is the offset of the file name
5824 * of the last entry returned.
5826 outp->totalParms = 10; /* in bytes */
5830 outp->parmsp[0] = returnedNames;
5831 outp->parmsp[1] = eos;
5832 outp->parmsp[2] = 0; /* EAS error */
5833 outp->parmsp[3] = 0; /* last name, as above */
5834 outp->totalParms = 8; /* in bytes */
5837 /* return # of bytes in the buffer */
5838 outp->totalData = bytesInBuffer;
5840 /* Return error code if unsuccessful on first request */
5841 if (code == 0 && p->opcode == 1 && returnedNames == 0)
5842 code = CM_ERROR_NOSUCHFILE;
5844 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
5845 p->opcode, dsp->cookie, returnedNames, code);
5847 /* if we're supposed to close the search after this request, or if
5848 * we're supposed to close the search if we're done, and we're done,
5849 * or if something went wrong, close the search.
5851 if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
5852 (returnedNames == 0) ||
5853 ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
5855 smb_DeleteDirSearch(dsp);
5858 smb_SendTran2Error(vcp, p, opx, code);
5860 smb_SendTran2Packet(vcp, outp, opx);
5862 smb_FreeTran2Packet(outp);
5863 smb_ReleaseDirSearch(dsp);
5864 cm_ReleaseSCache(scp);
5865 cm_ReleaseUser(userp);
5869 /* SMB_COM_FIND_CLOSE2 */
5870 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5873 smb_dirSearch_t *dsp;
5875 dirHandle = smb_GetSMBParm(inp, 0);
5877 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
5879 dsp = smb_FindDirSearch(dirHandle);
5882 return CM_ERROR_BADFD;
5884 /* otherwise, we have an FD to destroy */
5885 smb_DeleteDirSearch(dsp);
5886 smb_ReleaseDirSearch(dsp);
5888 /* and return results */
5889 smb_SetSMBDataLength(outp, 0);
5895 /* SMB_COM_FIND_NOTIFY_CLOSE */
5896 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5898 smb_SetSMBDataLength(outp, 0);
5902 /* SMB_COM_OPEN_ANDX */
5903 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5905 clientchar_t *pathp;
5910 cm_scache_t *dscp; /* dir we're dealing with */
5911 cm_scache_t *scp; /* file we're creating */
5913 int initialModeBits;
5916 clientchar_t *lastNamep;
5917 unsigned long dosTime;
5923 int parmSlot; /* which parm we're dealing with */
5924 clientchar_t *tidPathp;
5927 BOOL is_rpc = FALSE;
5928 BOOL is_ipc = FALSE;
5934 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
5935 openFun = smb_GetSMBParm(inp, 8); /* open function */
5936 excl = ((openFun & 3) == 0);
5937 trunc = ((openFun & 3) == 2); /* truncate it */
5938 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
5939 openAction = 0; /* tracks what we did */
5941 attributes = smb_GetSMBParm(inp, 5);
5942 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
5944 /* compute initial mode bits based on read-only flag in attributes */
5945 initialModeBits = 0666;
5946 if (attributes & SMB_ATTR_READONLY)
5947 initialModeBits &= ~0222;
5949 pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
5952 return CM_ERROR_BADSMB;
5954 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5956 if (code == CM_ERROR_TIDIPC) {
5959 return CM_ERROR_NOSUCHPATH;
5963 spacep = inp->spacep;
5964 /* smb_StripLastComponent will strip "::$DATA" if present */
5965 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5969 /* special case magic file name for receiving IOCTL requests
5970 * (since IOCTL calls themselves aren't getting through).
5972 (cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
5974 /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional) */
5975 (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
5977 unsigned short file_type = 0;
5978 unsigned short device_state = 0;
5980 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5982 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
5983 osi_Log1(smb_logp, "OpenAndX Setting up RPC on fid[%d]", fidp->fid);
5985 osi_Log1(smb_logp, "smb_SetupRPCFid failure code [%d]", code);
5986 smb_ReleaseFID(fidp);
5990 smb_SetupIoctlFid(fidp, spacep);
5991 osi_Log1(smb_logp, "OpenAndX Setting up IOCTL on fid[%d]", fidp->fid);
5994 /* set inp->fid so that later read calls in same msg can find fid */
5995 inp->fid = fidp->fid;
5997 /* copy out remainder of the parms */
5999 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6001 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
6002 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
6003 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6004 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
6005 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
6006 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
6007 smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++;
6008 smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++;
6010 /* and the final "always present" stuff */
6011 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
6012 /* next write out the "unique" ID */
6013 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
6014 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
6015 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6016 smb_SetSMBDataLength(outp, 0);
6018 /* and clean up fid reference */
6019 smb_ReleaseFID(fidp);
6025 osi_Log0(smb_logp, "NTOpenX rejecting IPC TID");
6026 return CM_ERROR_BADFD;
6030 if (!cm_IsValidClientString(pathp)) {
6032 clientchar_t * hexp;
6034 hexp = cm_GetRawCharsAlloc(pathp, -1);
6035 osi_Log1(smb_logp, "NTOpenX rejecting invalid name. [%S]",
6036 osi_LogSaveClientString(smb_logp, hexp));
6040 osi_Log0(smb_logp, "NTOpenX rejecting invalid name");
6042 return CM_ERROR_BADNTFILENAME;
6045 #ifdef DEBUG_VERBOSE
6047 char *hexp, *asciip;
6048 asciip = (lastNamep ? lastNamep : pathp );
6049 hexp = osi_HexifyString(asciip);
6050 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
6054 userp = smb_GetUserFromVCP(vcp, inp);
6057 code = cm_NameI(cm_data.rootSCachep, pathp,
6058 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6059 userp, tidPathp, &req, &scp);
6062 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6063 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
6064 cm_ReleaseSCache(scp);
6065 cm_ReleaseUser(userp);
6066 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6067 return CM_ERROR_PATH_NOT_COVERED;
6069 return CM_ERROR_NOSUCHPATH;
6071 #endif /* DFS_SUPPORT */
6074 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
6075 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6076 userp, tidPathp, &req, &dscp);
6078 cm_ReleaseUser(userp);
6083 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6084 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
6086 cm_ReleaseSCache(dscp);
6087 cm_ReleaseUser(userp);
6088 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6089 return CM_ERROR_PATH_NOT_COVERED;
6091 return CM_ERROR_NOSUCHPATH;
6093 #endif /* DFS_SUPPORT */
6094 /* otherwise, scp points to the parent directory. Do a lookup,
6095 * and truncate the file if we find it, otherwise we create the
6102 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
6104 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
6105 cm_ReleaseSCache(dscp);
6106 cm_ReleaseUser(userp);
6111 /* if we get here, if code is 0, the file exists and is represented by
6112 * scp. Otherwise, we have to create it. The dir may be represented
6113 * by dscp, or we may have found the file directly. If code is non-zero,
6117 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
6119 if (dscp) cm_ReleaseSCache(dscp);
6120 cm_ReleaseSCache(scp);
6121 cm_ReleaseUser(userp);
6126 /* oops, file shouldn't be there */
6128 cm_ReleaseSCache(dscp);
6129 cm_ReleaseSCache(scp);
6130 cm_ReleaseUser(userp);
6131 return CM_ERROR_EXISTS;
6135 setAttr.mask = CM_ATTRMASK_LENGTH;
6136 setAttr.length.LowPart = 0;
6137 setAttr.length.HighPart = 0;
6138 code = cm_SetAttr(scp, &setAttr, userp, &req);
6139 openAction = 3; /* truncated existing file */
6141 else openAction = 1; /* found existing file */
6143 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
6144 /* don't create if not found */
6145 if (dscp) cm_ReleaseSCache(dscp);
6146 cm_ReleaseUser(userp);
6147 return CM_ERROR_NOSUCHFILE;
6150 osi_assertx(dscp != NULL, "null cm_scache_t");
6151 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %S",
6152 osi_LogSaveClientString(smb_logp, lastNamep));
6153 openAction = 2; /* created file */
6154 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6155 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6156 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6160 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6161 smb_NotifyChange(FILE_ACTION_ADDED,
6162 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6163 dscp, lastNamep, NULL, TRUE);
6164 } else if (!excl && code == CM_ERROR_EXISTS) {
6165 /* not an exclusive create, and someone else tried
6166 * creating it already, then we open it anyway. We
6167 * don't bother retrying after this, since if this next
6168 * fails, that means that the file was deleted after we
6169 * started this call.
6171 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6175 setAttr.mask = CM_ATTRMASK_LENGTH;
6176 setAttr.length.LowPart = 0;
6177 setAttr.length.HighPart = 0;
6178 code = cm_SetAttr(scp, &setAttr, userp, &req);
6180 } /* lookup succeeded */
6184 /* we don't need this any longer */
6186 cm_ReleaseSCache(dscp);
6189 /* something went wrong creating or truncating the file */
6191 cm_ReleaseSCache(scp);
6192 cm_ReleaseUser(userp);
6196 /* make sure we're about to open a file */
6197 if (scp->fileType != CM_SCACHETYPE_FILE) {
6198 cm_ReleaseSCache(scp);
6199 cm_ReleaseUser(userp);
6200 return CM_ERROR_ISDIR;
6203 /* now all we have to do is open the file itself */
6204 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6205 osi_assertx(fidp, "null smb_fid_t");
6208 lock_ObtainMutex(&fidp->mx);
6209 /* save a pointer to the vnode */
6211 lock_ObtainWrite(&scp->rw);
6212 scp->flags |= CM_SCACHEFLAG_SMB_FID;
6213 lock_ReleaseWrite(&scp->rw);
6214 osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
6216 fidp->userp = userp;
6218 /* compute open mode */
6220 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
6221 if (openMode == 1 || openMode == 2)
6222 fidp->flags |= SMB_FID_OPENWRITE;
6224 /* remember if the file was newly created */
6226 fidp->flags |= SMB_FID_CREATED;
6228 lock_ReleaseMutex(&fidp->mx);
6229 smb_ReleaseFID(fidp);
6231 cm_Open(scp, 0, userp);
6233 /* set inp->fid so that later read calls in same msg can find fid */
6234 inp->fid = fidp->fid;
6236 /* copy out remainder of the parms */
6238 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6239 lock_ObtainRead(&scp->rw);
6241 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
6242 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
6243 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
6244 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
6245 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
6246 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
6247 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
6248 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
6249 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
6251 /* and the final "always present" stuff */
6252 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
6253 /* next write out the "unique" ID */
6254 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
6255 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
6256 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6257 lock_ReleaseRead(&scp->rw);
6258 smb_SetSMBDataLength(outp, 0);
6260 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
6262 cm_ReleaseUser(userp);
6263 /* leave scp held since we put it in fidp->scp */
6267 static void smb_GetLockParams(unsigned char LockType,
6269 unsigned int * ppid,
6270 LARGE_INTEGER * pOffset,
6271 LARGE_INTEGER * pLength)
6273 if (LockType & LOCKING_ANDX_LARGE_FILES) {
6275 *ppid = *((USHORT *) *buf);
6276 pOffset->HighPart = *((LONG *)(*buf + 4));
6277 pOffset->LowPart = *((DWORD *)(*buf + 8));
6278 pLength->HighPart = *((LONG *)(*buf + 12));
6279 pLength->LowPart = *((DWORD *)(*buf + 16));
6283 /* Not Large Files */
6284 *ppid = *((USHORT *) *buf);
6285 pOffset->HighPart = 0;
6286 pOffset->LowPart = *((DWORD *)(*buf + 2));
6287 pLength->HighPart = 0;
6288 pLength->LowPart = *((DWORD *)(*buf + 6));
6293 /* SMB_COM_LOCKING_ANDX */
6294 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6301 unsigned char LockType;
6302 unsigned short NumberOfUnlocks, NumberOfLocks;
6306 LARGE_INTEGER LOffset, LLength;
6307 smb_waitingLockRequest_t *wlRequest = NULL;
6308 cm_file_lock_t *lockp;
6316 fid = smb_GetSMBParm(inp, 2);
6317 fid = smb_ChainFID(fid, inp);
6319 fidp = smb_FindFID(vcp, fid, 0);
6321 return CM_ERROR_BADFD;
6323 lock_ObtainMutex(&fidp->mx);
6324 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6325 lock_ReleaseMutex(&fidp->mx);
6326 smb_CloseFID(vcp, fidp, NULL, 0);
6327 smb_ReleaseFID(fidp);
6328 return CM_ERROR_NOSUCHFILE;
6331 if (fidp->flags & SMB_FID_IOCTL) {
6332 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
6333 lock_ReleaseMutex(&fidp->mx);
6334 smb_ReleaseFID(fidp);
6335 return CM_ERROR_BADFD;
6338 osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
6340 lock_ReleaseMutex(&fidp->mx);
6342 /* set inp->fid so that later read calls in same msg can find fid */
6345 userp = smb_GetUserFromVCP(vcp, inp);
6347 lock_ObtainWrite(&scp->rw);
6348 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6349 CM_SCACHESYNC_NEEDCALLBACK
6350 | CM_SCACHESYNC_GETSTATUS
6351 | CM_SCACHESYNC_LOCK);
6353 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
6357 LockType = smb_GetSMBParm(inp, 3) & 0xff;
6358 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
6359 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
6360 NumberOfLocks = smb_GetSMBParm(inp, 7);
6362 if (!(fidp->flags & SMB_FID_OPENWRITE) &&
6363 !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
6364 /* somebody wants exclusive locks on a file that they only
6365 opened for reading. We downgrade this to a shared lock. */
6366 osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
6367 LockType |= LOCKING_ANDX_SHARED_LOCK;
6370 if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
6371 /* AFS does not support atomic changes of lock types from read or write and vice-versa */
6372 osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]");
6373 code = CM_ERROR_BADOP;
6378 op = smb_GetSMBData(inp, NULL);
6380 if (LockType & LOCKING_ANDX_CANCEL_LOCK) {
6381 /* Cancel outstanding lock requests */
6382 smb_waitingLock_t * wl;
6384 for (i=0; i<NumberOfLocks; i++) {
6385 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6387 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6389 lock_ObtainWrite(&smb_globalLock);
6390 for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
6392 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
6393 if (cm_KeyEquals(&wl->key, &key, 0) && LargeIntegerEqualTo(wl->LOffset, LOffset) &&
6394 LargeIntegerEqualTo(wl->LLength, LLength)) {
6395 wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
6396 goto found_lock_request;
6401 lock_ReleaseWrite(&smb_globalLock);
6404 smb_SetSMBDataLength(outp, 0);
6409 for (i=0; i<NumberOfUnlocks; i++) {
6410 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6412 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6414 code = cm_Unlock(scp, LockType, LOffset, LLength, key, 0, userp, &req);
6422 for (i=0; i<NumberOfLocks; i++) {
6423 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6425 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6427 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
6428 userp, &req, &lockp);
6430 if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
6431 (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
6433 code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
6434 userp, &req, &lockp);
6437 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
6438 smb_waitingLock_t * wLock;
6440 /* Put on waiting list */
6441 if(wlRequest == NULL) {
6445 LARGE_INTEGER tOffset, tLength;
6447 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
6449 osi_assertx(wlRequest != NULL, "null wlRequest");
6451 wlRequest->vcp = vcp;
6453 wlRequest->scp = scp;
6454 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
6456 wlRequest->inp = smb_CopyPacket(inp);
6457 wlRequest->outp = smb_CopyPacket(outp);
6458 wlRequest->lockType = LockType;
6459 wlRequest->msTimeout = Timeout;
6460 wlRequest->start_t = osi_Time();
6461 wlRequest->locks = NULL;
6463 /* The waiting lock request needs to have enough
6464 information to undo all the locks in the request.
6465 We do the following to store info about locks that
6466 have already been granted. Sure, we can get most
6467 of the info from the packet, but the packet doesn't
6468 hold the result of cm_Lock call. In practice we
6469 only receive packets with one or two locks, so we
6470 are only wasting a few bytes here and there and
6471 only for a limited period of time until the waiting
6472 lock times out or is freed. */
6474 for(opt = op_locks, j=i; j > 0; j--) {
6475 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
6477 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6479 wLock = malloc(sizeof(smb_waitingLock_t));
6481 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6484 wLock->LOffset = tOffset;
6485 wLock->LLength = tLength;
6486 wLock->lockp = NULL;
6487 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
6488 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6493 wLock = malloc(sizeof(smb_waitingLock_t));
6495 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6498 wLock->LOffset = LOffset;
6499 wLock->LLength = LLength;
6500 wLock->lockp = lockp;
6501 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
6502 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6505 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
6513 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
6520 /* Since something went wrong with the lock number i, we now
6521 have to go ahead and release any locks acquired before the
6522 failure. All locks before lock number i (of which there
6523 are i of them) have either been successful or are waiting.
6524 Either case requires calling cm_Unlock(). */
6526 /* And purge the waiting lock */
6527 if(wlRequest != NULL) {
6528 smb_waitingLock_t * wl;
6529 smb_waitingLock_t * wlNext;
6532 for(wl = wlRequest->locks; wl; wl = wlNext) {
6534 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
6536 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, 0, userp, &req);
6539 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
6541 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
6544 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
6549 smb_ReleaseVC(wlRequest->vcp);
6550 cm_ReleaseSCache(wlRequest->scp);
6551 smb_FreePacket(wlRequest->inp);
6552 smb_FreePacket(wlRequest->outp);
6561 if (wlRequest != NULL) {
6563 lock_ObtainWrite(&smb_globalLock);
6564 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
6566 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
6567 lock_ReleaseWrite(&smb_globalLock);
6569 /* don't send reply immediately */
6570 outp->flags |= SMB_PACKETFLAG_NOSEND;
6573 smb_SetSMBDataLength(outp, 0);
6577 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
6580 lock_ReleaseWrite(&scp->rw);
6581 cm_ReleaseSCache(scp);
6582 cm_ReleaseUser(userp);
6583 smb_ReleaseFID(fidp);
6588 /* SMB_COM_QUERY_INFORMATION2 */
6589 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6595 afs_uint32 searchTime;
6602 fid = smb_GetSMBParm(inp, 0);
6603 fid = smb_ChainFID(fid, inp);
6605 fidp = smb_FindFID(vcp, fid, 0);
6607 return CM_ERROR_BADFD;
6609 lock_ObtainMutex(&fidp->mx);
6610 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6611 lock_ReleaseMutex(&fidp->mx);
6612 smb_CloseFID(vcp, fidp, NULL, 0);
6613 smb_ReleaseFID(fidp);
6614 return CM_ERROR_NOSUCHFILE;
6617 if (fidp->flags & SMB_FID_IOCTL) {
6618 lock_ReleaseMutex(&fidp->mx);
6619 smb_ReleaseFID(fidp);
6620 return CM_ERROR_BADFD;
6623 osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6625 lock_ReleaseMutex(&fidp->mx);
6627 userp = smb_GetUserFromVCP(vcp, inp);
6630 /* otherwise, stat the file */
6631 lock_ObtainWrite(&scp->rw);
6632 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6633 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6637 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6639 lock_ConvertWToR(&scp->rw);
6642 /* decode times. We need a search time, but the response to this
6643 * call provides the date first, not the time, as returned in the
6644 * searchTime variable. So we take the high-order bits first.
6646 cm_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
6647 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
6648 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
6649 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
6650 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
6651 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
6652 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
6654 /* now handle file size and allocation size */
6655 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
6656 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
6657 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
6658 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
6660 /* file attribute */
6661 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
6663 /* and finalize stuff */
6664 smb_SetSMBDataLength(outp, 0);
6669 lock_ReleaseRead(&scp->rw);
6671 lock_ReleaseWrite(&scp->rw);
6672 cm_ReleaseSCache(scp);
6673 cm_ReleaseUser(userp);
6674 smb_ReleaseFID(fidp);
6678 /* SMB_COM_SET_INFORMATION2 */
6679 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6685 afs_uint32 searchTime;
6693 fid = smb_GetSMBParm(inp, 0);
6694 fid = smb_ChainFID(fid, inp);
6696 fidp = smb_FindFID(vcp, fid, 0);
6698 return CM_ERROR_BADFD;
6700 lock_ObtainMutex(&fidp->mx);
6701 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6702 lock_ReleaseMutex(&fidp->mx);
6703 smb_CloseFID(vcp, fidp, NULL, 0);
6704 smb_ReleaseFID(fidp);
6705 return CM_ERROR_NOSUCHFILE;
6708 if (fidp->flags & SMB_FID_IOCTL) {
6709 lock_ReleaseMutex(&fidp->mx);
6710 smb_ReleaseFID(fidp);
6711 return CM_ERROR_BADFD;
6714 osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6716 lock_ReleaseMutex(&fidp->mx);
6718 userp = smb_GetUserFromVCP(vcp, inp);
6720 /* now prepare to call cm_setattr. This message only sets various times,
6721 * and AFS only implements mtime, and we'll set the mtime if that's
6722 * requested. The others we'll ignore.
6724 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
6726 if (searchTime != 0) {
6727 cm_UnixTimeFromSearchTime(&unixTime, searchTime);
6729 if ( unixTime != -1 ) {
6730 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
6731 attrs.clientModTime = unixTime;
6732 code = cm_SetAttr(scp, &attrs, userp, &req);
6734 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
6736 osi_Log1(smb_logp, "**cm_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
6742 cm_ReleaseSCache(scp);
6743 cm_ReleaseUser(userp);
6744 smb_ReleaseFID(fidp);
6748 /* SMB_COM_WRITE_ANDX */
6749 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6752 long count, written = 0, total_written = 0;
6756 smb_t *smbp = (smb_t*) inp;
6761 int inDataBlockCount;
6763 fd = smb_GetSMBParm(inp, 2);
6764 count = smb_GetSMBParm(inp, 10);
6766 offset.HighPart = 0;
6767 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6769 if (*inp->wctp == 14) {
6770 /* we have a request with 64-bit file offsets */
6771 #ifdef AFS_LARGEFILES
6772 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6774 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6776 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
6777 /* we shouldn't have received this op if we didn't specify
6778 largefile support */
6779 return CM_ERROR_INVAL;
6784 op = inp->data + smb_GetSMBParm(inp, 11);
6785 inDataBlockCount = count;
6787 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
6788 fd, offset.HighPart, offset.LowPart, count);
6790 fd = smb_ChainFID(fd, inp);
6791 fidp = smb_FindFID(vcp, fd, 0);
6793 return CM_ERROR_BADFD;
6795 lock_ObtainMutex(&fidp->mx);
6796 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6797 lock_ReleaseMutex(&fidp->mx);
6798 smb_CloseFID(vcp, fidp, NULL, 0);
6799 smb_ReleaseFID(fidp);
6800 return CM_ERROR_NOSUCHFILE;
6803 if (fidp->flags & SMB_FID_IOCTL) {
6804 lock_ReleaseMutex(&fidp->mx);
6805 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
6806 smb_ReleaseFID(fidp);
6810 if (fidp->flags & SMB_FID_RPC) {
6811 lock_ReleaseMutex(&fidp->mx);
6812 code = smb_RPCV3Write(fidp, vcp, inp, outp);
6813 smb_ReleaseFID(fidp);
6818 lock_ReleaseMutex(&fidp->mx);
6819 smb_ReleaseFID(fidp);
6820 return CM_ERROR_BADFDOP;
6825 lock_ReleaseMutex(&fidp->mx);
6827 userp = smb_GetUserFromVCP(vcp, inp);
6829 /* special case: 0 bytes transferred means there is no data
6830 transferred. A slight departure from SMB_COM_WRITE where this
6831 means that we are supposed to truncate the file at this
6836 LARGE_INTEGER LOffset;
6837 LARGE_INTEGER LLength;
6840 key = cm_GenerateKey(vcp->vcID, pid, fd);
6842 LOffset.HighPart = offset.HighPart;
6843 LOffset.LowPart = offset.LowPart;
6844 LLength.HighPart = 0;
6845 LLength.LowPart = count;
6847 lock_ObtainWrite(&scp->rw);
6848 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
6849 lock_ReleaseWrite(&scp->rw);
6856 * Work around bug in NT client
6858 * When copying a file, the NT client should first copy the data,
6859 * then copy the last write time. But sometimes the NT client does
6860 * these in the wrong order, so the data copies would inadvertently
6861 * cause the last write time to be overwritten. We try to detect this,
6862 * and don't set client mod time if we think that would go against the
6865 lock_ObtainMutex(&fidp->mx);
6866 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6867 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6868 scp->clientModTime = time(NULL);
6870 lock_ReleaseMutex(&fidp->mx);
6873 while ( code == 0 && count > 0 ) {
6874 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6875 if (code == 0 && written == 0)
6876 code = CM_ERROR_PARTIALWRITE;
6878 offset = LargeIntegerAdd(offset,
6879 ConvertLongToLargeInteger(written));
6881 total_written += written;
6885 /* slots 0 and 1 are reserved for request chaining and will be
6886 filled in when we return. */
6887 smb_SetSMBParm(outp, 2, total_written);
6888 smb_SetSMBParm(outp, 3, 0); /* reserved */
6889 smb_SetSMBParm(outp, 4, 0); /* reserved */
6890 smb_SetSMBParm(outp, 5, 0); /* reserved */
6891 smb_SetSMBDataLength(outp, 0);
6895 cm_ReleaseSCache(scp);
6896 cm_ReleaseUser(userp);
6897 smb_ReleaseFID(fidp);
6902 /* SMB_COM_READ_ANDX */
6903 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6907 long finalCount = 0;
6911 smb_t *smbp = (smb_t*) inp;
6918 fd = smb_GetSMBParm(inp, 2); /* File ID */
6919 count = smb_GetSMBParm(inp, 5); /* MaxCount */
6920 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6922 if (*inp->wctp == 12) {
6923 /* a request with 64-bit offsets */
6924 #ifdef AFS_LARGEFILES
6925 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
6927 if (LargeIntegerLessThanZero(offset)) {
6928 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
6929 offset.HighPart, offset.LowPart);
6930 return CM_ERROR_BADSMB;
6933 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
6934 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
6935 return CM_ERROR_BADSMB;
6937 offset.HighPart = 0;
6941 offset.HighPart = 0;
6944 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
6945 fd, offset.HighPart, offset.LowPart, count);
6947 fd = smb_ChainFID(fd, inp);
6948 fidp = smb_FindFID(vcp, fd, 0);
6950 return CM_ERROR_BADFD;
6953 lock_ObtainMutex(&fidp->mx);
6955 if (fidp->flags & SMB_FID_IOCTL) {
6956 lock_ReleaseMutex(&fidp->mx);
6958 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
6959 smb_ReleaseFID(fidp);
6963 if (fidp->flags & SMB_FID_RPC) {
6964 lock_ReleaseMutex(&fidp->mx);
6966 code = smb_RPCV3Read(fidp, vcp, inp, outp);
6967 smb_ReleaseFID(fidp);
6971 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6972 lock_ReleaseMutex(&fidp->mx);
6973 smb_CloseFID(vcp, fidp, NULL, 0);
6974 smb_ReleaseFID(fidp);
6975 return CM_ERROR_NOSUCHFILE;
6979 lock_ReleaseMutex(&fidp->mx);
6980 smb_ReleaseFID(fidp);
6981 return CM_ERROR_BADFDOP;
6987 lock_ReleaseMutex(&fidp->mx);
6990 key = cm_GenerateKey(vcp->vcID, pid, fd);
6992 LARGE_INTEGER LOffset, LLength;
6994 LOffset.HighPart = offset.HighPart;
6995 LOffset.LowPart = offset.LowPart;
6996 LLength.HighPart = 0;
6997 LLength.LowPart = count;
6999 lock_ObtainWrite(&scp->rw);
7000 code = cm_LockCheckRead(scp, LOffset, LLength, key);
7001 lock_ReleaseWrite(&scp->rw);
7003 cm_ReleaseSCache(scp);
7006 smb_ReleaseFID(fidp);
7010 /* set inp->fid so that later read calls in same msg can find fid */
7013 userp = smb_GetUserFromVCP(vcp, inp);
7015 /* 0 and 1 are reserved for request chaining, were setup by our caller,
7016 * and will be further filled in after we return.
7018 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
7019 smb_SetSMBParm(outp, 3, 0); /* resvd */
7020 smb_SetSMBParm(outp, 4, 0); /* resvd */
7021 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
7022 /* fill in #6 when we have all the parameters' space reserved */
7023 smb_SetSMBParm(outp, 7, 0); /* resv'd */
7024 smb_SetSMBParm(outp, 8, 0); /* resv'd */
7025 smb_SetSMBParm(outp, 9, 0); /* resv'd */
7026 smb_SetSMBParm(outp, 10, 0); /* resv'd */
7027 smb_SetSMBParm(outp, 11, 0); /* reserved */
7029 /* get op ptr after putting in the parms, since otherwise we don't
7030 * know where the data really is.
7032 op = smb_GetSMBData(outp, NULL);
7034 /* now fill in offset from start of SMB header to first data byte (to op) */
7035 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
7037 /* set the packet data length the count of the # of bytes */
7038 smb_SetSMBDataLength(outp, count);
7040 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7042 /* fix some things up */
7043 smb_SetSMBParm(outp, 5, finalCount);
7044 smb_SetSMBDataLength(outp, finalCount);
7046 cm_ReleaseUser(userp);
7047 smb_ReleaseFID(fidp);
7052 * Values for createDisp, copied from NTDDK.H
7054 #define FILE_SUPERSEDE 0 // (???)
7055 #define FILE_OPEN 1 // (open)
7056 #define FILE_CREATE 2 // (exclusive)
7057 #define FILE_OPEN_IF 3 // (non-exclusive)
7058 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
7059 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
7062 #define REQUEST_OPLOCK 2
7063 #define REQUEST_BATCH_OPLOCK 4
7064 #define OPEN_DIRECTORY 8
7065 #define EXTENDED_RESPONSE_REQUIRED 0x10
7067 /* CreateOptions field. */
7068 #define FILE_DIRECTORY_FILE 0x0001
7069 #define FILE_WRITE_THROUGH 0x0002
7070 #define FILE_SEQUENTIAL_ONLY 0x0004
7071 #define FILE_NON_DIRECTORY_FILE 0x0040
7072 #define FILE_NO_EA_KNOWLEDGE 0x0200
7073 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
7074 #define FILE_RANDOM_ACCESS 0x0800
7075 #define FILE_DELETE_ON_CLOSE 0x1000
7076 #define FILE_OPEN_BY_FILE_ID 0x2000
7077 #define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000
7078 #define FILE_NO_COMPRESSION 0x00008000
7079 #define FILE_RESERVE_OPFILTER 0x00100000
7080 #define FILE_OPEN_REPARSE_POINT 0x00200000
7081 #define FILE_OPEN_NO_RECALL 0x00400000
7082 #define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000
7084 /* SMB_COM_NT_CREATE_ANDX */
7085 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7087 clientchar_t *pathp, *realPathp;
7091 cm_scache_t *dscp; /* parent dir */
7092 cm_scache_t *scp; /* file to create or open */
7093 cm_scache_t *targetScp; /* if scp is a symlink */
7095 clientchar_t *lastNamep;
7096 clientchar_t *treeStartp;
7097 unsigned short nameLength;
7099 unsigned int requestOpLock;
7100 unsigned int requestBatchOpLock;
7101 unsigned int mustBeDir;
7102 unsigned int extendedRespRequired;
7103 unsigned int treeCreate;
7105 unsigned int desiredAccess;
7106 unsigned int extAttributes;
7107 unsigned int createDisp;
7108 unsigned int createOptions;
7109 unsigned int shareAccess;
7110 int initialModeBits;
7111 unsigned short baseFid;
7112 smb_fid_t *baseFidp;
7114 cm_scache_t *baseDirp;
7115 unsigned short openAction;
7120 clientchar_t *tidPathp;
7125 int checkDoneRequired = 0;
7126 cm_lock_data_t *ldp = NULL;
7127 BOOL is_rpc = FALSE;
7128 BOOL is_ipc = FALSE;
7132 /* This code is very long and has a lot of if-then-else clauses
7133 * scp and dscp get reused frequently and we need to ensure that
7134 * we don't lose a reference. Start by ensuring that they are NULL.
7141 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
7142 flags = smb_GetSMBOffsetParm(inp, 3, 1)
7143 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
7144 requestOpLock = flags & REQUEST_OPLOCK;
7145 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7146 mustBeDir = flags & OPEN_DIRECTORY;
7147 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7150 * Why all of a sudden 32-bit FID?
7151 * We will reject all bits higher than 16.
7153 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
7154 return CM_ERROR_INVAL;
7155 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
7156 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
7157 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
7158 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
7159 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
7160 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
7161 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
7162 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
7163 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
7164 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
7165 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
7167 /* mustBeDir is never set; createOptions directory bit seems to be
7170 if (createOptions & FILE_DIRECTORY_FILE)
7172 else if (createOptions & FILE_NON_DIRECTORY_FILE)
7178 * compute initial mode bits based on read-only flag in
7179 * extended attributes
7181 initialModeBits = 0666;
7182 if (extAttributes & SMB_ATTR_READONLY)
7183 initialModeBits &= ~0222;
7185 pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
7186 NULL, SMB_STRF_ANSIPATH);
7188 /* Sometimes path is not null-terminated, so we make a copy. */
7189 realPathp = malloc(nameLength+sizeof(clientchar_t));
7190 memcpy(realPathp, pathp, nameLength+sizeof(clientchar_t));
7191 realPathp[nameLength/sizeof(clientchar_t)] = 0;
7193 spacep = inp->spacep;
7194 /* smb_StripLastComponent will strip "::$DATA" if present */
7195 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
7197 osi_Log1(smb_logp,"NTCreateX for [%S]",osi_LogSaveClientString(smb_logp,realPathp));
7198 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
7199 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%S]", shareAccess, flags, osi_LogSaveClientString(smb_logp,(lastNamep?lastNamep:_C("null"))));
7203 baseDirp = cm_data.rootSCachep;
7204 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7205 if (code == CM_ERROR_TIDIPC) {
7206 /* Attempt to use a TID allocated for IPC. The client
7207 * is probably looking for DCE RPC end points which we
7208 * don't support OR it could be looking to make a DFS
7211 osi_Log0(smb_logp, "NTCreateX received IPC TID");
7216 osi_Log1(smb_logp, "NTCreateX tidPathp=[%S]", (tidPathp==NULL)?_C("null"): osi_LogSaveClientString(smb_logp,tidPathp));
7220 ((is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)) ||
7222 /* special case magic file name for receiving IOCTL requests
7223 * (since IOCTL calls themselves aren't getting through).
7225 cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0)) {
7227 unsigned short file_type = 0;
7228 unsigned short device_state = 0;
7230 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7233 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
7234 osi_Log1(smb_logp, "NTCreateX Setting up RPC on fid[%d]", fidp->fid);
7236 osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
7237 smb_ReleaseFID(fidp);
7242 smb_SetupIoctlFid(fidp, spacep);
7243 osi_Log1(smb_logp, "NTCreateX Setting up IOCTL on fid[%d]", fidp->fid);
7246 /* set inp->fid so that later read calls in same msg can find fid */
7247 inp->fid = fidp->fid;
7251 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7252 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7253 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
7255 memset(&ft, 0, sizeof(ft));
7256 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7257 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7258 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7259 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7260 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
7261 sz.HighPart = 0x7fff; sz.LowPart = 0;
7262 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
7263 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
7264 smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++; /* filetype */
7265 smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++; /* dev state */
7266 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
7267 smb_SetSMBDataLength(outp, 0);
7269 /* clean up fid reference */
7270 smb_ReleaseFID(fidp);
7277 osi_Log0(smb_logp, "NTCreateX rejecting IPC TID");
7279 return CM_ERROR_BADFD;
7283 if (!cm_IsValidClientString(realPathp)) {
7285 clientchar_t * hexp;
7287 hexp = cm_GetRawCharsAlloc(realPathp, -1);
7288 osi_Log1(smb_logp, "NTCreateX rejecting invalid name. [%S]",
7289 osi_LogSaveClientString(smb_logp, hexp));
7293 osi_Log0(smb_logp, "NTCreateX rejecting invalid name");
7296 return CM_ERROR_BADNTFILENAME;
7299 userp = smb_GetUserFromVCP(vcp, inp);
7301 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
7303 return CM_ERROR_INVAL;
7306 if (baseFidp != 0) {
7307 baseFidp = smb_FindFID(vcp, baseFid, 0);
7309 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
7310 cm_ReleaseUser(userp);
7312 return CM_ERROR_INVAL;
7315 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7317 smb_CloseFID(vcp, baseFidp, NULL, 0);
7318 smb_ReleaseFID(baseFidp);
7319 cm_ReleaseUser(userp);
7320 return CM_ERROR_NOSUCHPATH;
7323 baseDirp = baseFidp->scp;
7327 /* compute open mode */
7329 if (desiredAccess & DELETE)
7330 fidflags |= SMB_FID_OPENDELETE;
7331 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
7332 fidflags |= SMB_FID_OPENREAD_LISTDIR;
7333 if (desiredAccess & AFS_ACCESS_WRITE)
7334 fidflags |= SMB_FID_OPENWRITE;
7335 if (createOptions & FILE_DELETE_ON_CLOSE)
7336 fidflags |= SMB_FID_DELONCLOSE;
7337 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7338 fidflags |= SMB_FID_SEQUENTIAL;
7339 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7340 fidflags |= SMB_FID_RANDOM;
7341 if (createOptions & FILE_OPEN_REPARSE_POINT)
7342 osi_Log0(smb_logp, "NTCreateX Open Reparse Point");
7343 if (smb_IsExecutableFileName(lastNamep))
7344 fidflags |= SMB_FID_EXECUTABLE;
7346 /* and the share mode */
7347 if (shareAccess & FILE_SHARE_READ)
7348 fidflags |= SMB_FID_SHARE_READ;
7349 if (shareAccess & FILE_SHARE_WRITE)
7350 fidflags |= SMB_FID_SHARE_WRITE;
7352 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
7355 /* For an exclusive create, we want to do a case sensitive match for the last component. */
7356 if ( createDisp == FILE_CREATE ||
7357 createDisp == FILE_OVERWRITE ||
7358 createDisp == FILE_OVERWRITE_IF) {
7359 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7360 userp, tidPathp, &req, &dscp);
7363 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7364 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7366 cm_ReleaseSCache(dscp);
7367 cm_ReleaseUser(userp);
7370 smb_ReleaseFID(baseFidp);
7371 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7372 return CM_ERROR_PATH_NOT_COVERED;
7374 return CM_ERROR_NOSUCHPATH;
7376 #endif /* DFS_SUPPORT */
7377 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7379 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7380 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7381 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7382 if (code == 0 && realDirFlag == 1) {
7383 cm_ReleaseSCache(scp);
7384 cm_ReleaseSCache(dscp);
7385 cm_ReleaseUser(userp);
7388 smb_ReleaseFID(baseFidp);
7389 return CM_ERROR_EXISTS;
7393 /* we have both scp and dscp */
7395 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7396 userp, tidPathp, &req, &scp);
7398 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7399 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7400 cm_ReleaseSCache(scp);
7401 cm_ReleaseUser(userp);
7404 smb_ReleaseFID(baseFidp);
7405 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7406 return CM_ERROR_PATH_NOT_COVERED;
7408 return CM_ERROR_NOSUCHPATH;
7410 #endif /* DFS_SUPPORT */
7411 /* we might have scp but not dscp */
7417 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7418 /* look up parent directory */
7419 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
7420 * the immediate parent. We have to work our way up realPathp until we hit something that we
7424 /* we might or might not have scp */
7430 code = cm_NameI(baseDirp, spacep->wdata,
7431 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7432 userp, tidPathp, &req, &dscp);
7435 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7436 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7439 cm_ReleaseSCache(scp);
7440 cm_ReleaseSCache(dscp);
7441 cm_ReleaseUser(userp);
7444 smb_ReleaseFID(baseFidp);
7445 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7446 return CM_ERROR_PATH_NOT_COVERED;
7448 return CM_ERROR_NOSUCHPATH;
7450 #endif /* DFS_SUPPORT */
7453 (tp = cm_ClientStrRChr(spacep->wdata, '\\')) &&
7454 (createDisp == FILE_CREATE) &&
7455 (realDirFlag == 1)) {
7458 treeStartp = realPathp + (tp - spacep->wdata);
7460 if (*tp && !smb_IsLegalFilename(tp)) {
7461 cm_ReleaseUser(userp);
7463 smb_ReleaseFID(baseFidp);
7466 cm_ReleaseSCache(scp);
7467 return CM_ERROR_BADNTFILENAME;
7471 } while (dscp == NULL && code == 0);
7475 /* we might have scp and we might have dscp */
7478 smb_ReleaseFID(baseFidp);
7481 osi_Log0(smb_logp,"NTCreateX parent not found");
7483 cm_ReleaseSCache(scp);
7485 cm_ReleaseSCache(dscp);
7486 cm_ReleaseUser(userp);
7491 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
7492 /* A file exists where we want a directory. */
7494 cm_ReleaseSCache(scp);
7495 cm_ReleaseSCache(dscp);
7496 cm_ReleaseUser(userp);
7498 return CM_ERROR_EXISTS;
7502 lastNamep = realPathp;
7506 if (!smb_IsLegalFilename(lastNamep)) {
7508 cm_ReleaseSCache(scp);
7510 cm_ReleaseSCache(dscp);
7511 cm_ReleaseUser(userp);
7513 return CM_ERROR_BADNTFILENAME;
7516 if (!foundscp && !treeCreate) {
7517 if ( createDisp == FILE_CREATE ||
7518 createDisp == FILE_OVERWRITE ||
7519 createDisp == FILE_OVERWRITE_IF)
7521 code = cm_Lookup(dscp, lastNamep,
7522 CM_FLAG_FOLLOW, userp, &req, &scp);
7524 code = cm_Lookup(dscp, lastNamep,
7525 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7528 if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
7530 cm_ReleaseSCache(dscp);
7531 cm_ReleaseUser(userp);
7536 /* we have scp and dscp */
7538 /* we have scp but not dscp */
7540 smb_ReleaseFID(baseFidp);
7543 /* if we get here, if code is 0, the file exists and is represented by
7544 * scp. Otherwise, we have to create it. The dir may be represented
7545 * by dscp, or we may have found the file directly. If code is non-zero,
7548 if (code == 0 && !treeCreate) {
7549 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7551 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7553 cm_ReleaseSCache(dscp);
7555 cm_ReleaseSCache(scp);
7556 cm_ReleaseUser(userp);
7560 checkDoneRequired = 1;
7562 if (createDisp == FILE_CREATE) {
7563 /* oops, file shouldn't be there */
7564 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7566 cm_ReleaseSCache(dscp);
7568 cm_ReleaseSCache(scp);
7569 cm_ReleaseUser(userp);
7571 return CM_ERROR_EXISTS;
7574 if ( createDisp == FILE_OVERWRITE ||
7575 createDisp == FILE_OVERWRITE_IF) {
7577 setAttr.mask = CM_ATTRMASK_LENGTH;
7578 setAttr.length.LowPart = 0;
7579 setAttr.length.HighPart = 0;
7580 /* now watch for a symlink */
7582 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7584 osi_assertx(dscp != NULL, "null cm_scache_t");
7585 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7587 /* we have a more accurate file to use (the
7588 * target of the symbolic link). Otherwise,
7589 * we'll just use the symlink anyway.
7591 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7593 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7594 cm_ReleaseSCache(scp);
7596 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7598 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7600 cm_ReleaseSCache(dscp);
7602 cm_ReleaseSCache(scp);
7603 cm_ReleaseUser(userp);
7609 code = cm_SetAttr(scp, &setAttr, userp, &req);
7610 openAction = 3; /* truncated existing file */
7613 openAction = 1; /* found existing file */
7615 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7616 /* don't create if not found */
7618 cm_ReleaseSCache(dscp);
7620 cm_ReleaseSCache(scp);
7621 cm_ReleaseUser(userp);
7623 return CM_ERROR_NOSUCHFILE;
7624 } else if (realDirFlag == 0 || realDirFlag == -1) {
7625 osi_assertx(dscp != NULL, "null cm_scache_t");
7626 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %S",
7627 osi_LogSaveClientString(smb_logp, lastNamep));
7628 openAction = 2; /* created file */
7629 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7630 setAttr.clientModTime = time(NULL);
7631 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
7634 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7635 smb_NotifyChange(FILE_ACTION_ADDED,
7636 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7637 dscp, lastNamep, NULL, TRUE);
7638 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7639 /* Not an exclusive create, and someone else tried
7640 * creating it already, then we open it anyway. We
7641 * don't bother retrying after this, since if this next
7642 * fails, that means that the file was deleted after we
7643 * started this call.
7645 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7648 if (createDisp == FILE_OVERWRITE_IF) {
7649 setAttr.mask = CM_ATTRMASK_LENGTH;
7650 setAttr.length.LowPart = 0;
7651 setAttr.length.HighPart = 0;
7653 /* now watch for a symlink */
7655 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7657 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7659 /* we have a more accurate file to use (the
7660 * target of the symbolic link). Otherwise,
7661 * we'll just use the symlink anyway.
7663 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7665 cm_ReleaseSCache(scp);
7669 code = cm_SetAttr(scp, &setAttr, userp, &req);
7671 } /* lookup succeeded */
7674 clientchar_t *tp, *pp;
7675 clientchar_t *cp; /* This component */
7676 int clen = 0; /* length of component */
7677 cm_scache_t *tscp1, *tscp2;
7680 /* create directory */
7682 treeStartp = lastNamep;
7683 osi_assertx(dscp != NULL, "null cm_scache_t");
7684 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%S]",
7685 osi_LogSaveClientString(smb_logp, treeStartp));
7686 openAction = 2; /* created directory */
7688 /* if the request is to create the root directory
7689 * it will appear as a directory name of the nul-string
7690 * and a code of CM_ERROR_NOSUCHFILE
7692 if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
7693 code = CM_ERROR_EXISTS;
7695 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7696 setAttr.clientModTime = time(NULL);
7701 cm_HoldSCache(tscp1);
7705 tp = cm_ClientStrChr(pp, '\\');
7707 cm_ClientStrCpy(cp, lengthof(spacep->wdata) - (cp - spacep->wdata), pp);
7708 clen = (int)cm_ClientStrLen(cp);
7709 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
7711 clen = (int)(tp - pp);
7712 cm_ClientStrCpyN(cp, lengthof(spacep->wdata) - (cp - spacep->wdata),
7720 continue; /* the supplied path can't have consecutive slashes either , but */
7722 /* cp is the next component to be created. */
7723 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req, NULL);
7724 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
7725 smb_NotifyChange(FILE_ACTION_ADDED,
7726 FILE_NOTIFY_CHANGE_DIR_NAME,
7727 tscp1, cp, NULL, TRUE);
7729 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7730 /* Not an exclusive create, and someone else tried
7731 * creating it already, then we open it anyway. We
7732 * don't bother retrying after this, since if this next
7733 * fails, that means that the file was deleted after we
7734 * started this call.
7736 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
7737 userp, &req, &tscp2);
7742 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
7743 cm_ReleaseSCache(tscp1);
7744 tscp1 = tscp2; /* Newly created directory will be next parent */
7745 /* the hold is transfered to tscp1 from tscp2 */
7750 cm_ReleaseSCache(dscp);
7753 cm_ReleaseSCache(scp);
7756 * if we get here and code == 0, then scp is the last directory created, and dscp is the
7762 /* something went wrong creating or truncating the file */
7763 if (checkDoneRequired)
7764 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7766 cm_ReleaseSCache(scp);
7768 cm_ReleaseSCache(dscp);
7769 cm_ReleaseUser(userp);
7774 /* make sure we have file vs. dir right (only applies for single component case) */
7775 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7776 /* now watch for a symlink */
7778 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7779 cm_scache_t * targetScp = 0;
7780 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7782 /* we have a more accurate file to use (the
7783 * target of the symbolic link). Otherwise,
7784 * we'll just use the symlink anyway.
7786 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
7787 if (checkDoneRequired) {
7788 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7789 checkDoneRequired = 0;
7791 cm_ReleaseSCache(scp);
7796 if (scp->fileType != CM_SCACHETYPE_FILE) {
7797 if (checkDoneRequired)
7798 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7800 cm_ReleaseSCache(dscp);
7801 cm_ReleaseSCache(scp);
7802 cm_ReleaseUser(userp);
7804 return CM_ERROR_ISDIR;
7808 /* (only applies to single component case) */
7809 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7810 if (checkDoneRequired)
7811 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7812 cm_ReleaseSCache(scp);
7814 cm_ReleaseSCache(dscp);
7815 cm_ReleaseUser(userp);
7817 return CM_ERROR_NOTDIR;
7820 /* open the file itself */
7821 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7822 osi_assertx(fidp, "null smb_fid_t");
7824 /* save a reference to the user */
7826 fidp->userp = userp;
7828 /* If we are restricting sharing, we should do so with a suitable
7830 if (scp->fileType == CM_SCACHETYPE_FILE &&
7831 !(fidflags & SMB_FID_SHARE_WRITE)) {
7833 LARGE_INTEGER LOffset, LLength;
7836 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7837 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7838 LLength.HighPart = 0;
7839 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7841 /* If we are not opening the file for writing, then we don't
7842 try to get an exclusive lock. No one else should be able to
7843 get an exclusive lock on the file anyway, although someone
7844 else can get a shared lock. */
7845 if ((fidflags & SMB_FID_SHARE_READ) ||
7846 !(fidflags & SMB_FID_OPENWRITE)) {
7847 sLockType = LOCKING_ANDX_SHARED_LOCK;
7852 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7854 lock_ObtainWrite(&scp->rw);
7855 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7856 lock_ReleaseWrite(&scp->rw);
7859 if (checkDoneRequired)
7860 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7861 cm_ReleaseSCache(scp);
7863 cm_ReleaseSCache(dscp);
7864 cm_ReleaseUser(userp);
7865 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7866 smb_CloseFID(vcp, fidp, NULL, 0);
7867 smb_ReleaseFID(fidp);
7873 /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
7874 if (checkDoneRequired) {
7875 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7876 checkDoneRequired = 0;
7879 lock_ObtainMutex(&fidp->mx);
7880 /* save a pointer to the vnode */
7881 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
7882 lock_ObtainWrite(&scp->rw);
7883 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7884 lock_ReleaseWrite(&scp->rw);
7885 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
7887 fidp->flags = fidflags;
7889 /* remember if the file was newly created */
7891 fidp->flags |= SMB_FID_CREATED;
7893 /* save parent dir and pathname for delete or change notification */
7894 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7895 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
7896 fidp->flags |= SMB_FID_NTOPEN;
7897 fidp->NTopen_dscp = dscp;
7899 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
7901 fidp->NTopen_wholepathp = realPathp;
7902 lock_ReleaseMutex(&fidp->mx);
7904 /* we don't need this any longer */
7906 cm_ReleaseSCache(dscp);
7910 cm_Open(scp, 0, userp);
7912 /* set inp->fid so that later read calls in same msg can find fid */
7913 inp->fid = fidp->fid;
7915 lock_ObtainRead(&scp->rw);
7918 * Always send the standard response. Sending the extended
7919 * response results in the Explorer Shell being unable to
7920 * access directories at random times.
7922 if (1 /*!extendedRespRequired */) {
7925 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7926 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7927 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7928 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7929 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7930 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7931 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7932 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7933 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7935 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7936 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7937 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
7938 smb_SetSMBParm(outp, parmSlot, NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS);
7939 parmSlot++; /* dev state */
7940 smb_SetSMBParmByte(outp, parmSlot,
7941 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7942 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7943 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7944 smb_SetSMBDataLength(outp, 0);
7948 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7949 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7950 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7951 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7952 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7953 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7954 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7955 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7956 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7958 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7959 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7960 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
7961 smb_SetSMBParm(outp, parmSlot, NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS);
7962 parmSlot++; /* dev state */
7963 smb_SetSMBParmByte(outp, parmSlot,
7964 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7965 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7966 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7967 /* Setting the GUID results in a failure with cygwin */
7968 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7969 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7970 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7971 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7972 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7973 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7974 /* Maxmimal access rights */
7975 smb_SetSMBParmLong(outp, parmSlot, 0x001f01ff); parmSlot += 2;
7976 /* Guest access rights */
7977 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7978 smb_SetSMBDataLength(outp, 0);
7981 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
7982 LargeIntegerGreaterThanZero(scp->length) &&
7983 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
7986 lock_ReleaseRead(&scp->rw);
7989 cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
7990 scp->length.LowPart, scp->length.HighPart,
7994 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %S", fidp->fid,
7995 osi_LogSaveClientString(smb_logp, realPathp));
7997 cm_ReleaseUser(userp);
7998 smb_ReleaseFID(fidp);
8000 /* Can't free realPathp if we get here since
8001 fidp->NTopen_wholepathp is pointing there */
8003 /* leave scp held since we put it in fidp->scp */
8008 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
8009 * Instead, ultimately, would like to use a subroutine for common code.
8012 /* NT_TRANSACT_CREATE (SMB_COM_NT_TRANSACT) */
8013 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8015 clientchar_t *pathp, *realPathp;
8019 cm_scache_t *dscp; /* parent dir */
8020 cm_scache_t *scp; /* file to create or open */
8021 cm_scache_t *targetScp; /* if scp is a symlink */
8023 clientchar_t *lastNamep;
8024 unsigned long nameLength;
8026 unsigned int requestOpLock;
8027 unsigned int requestBatchOpLock;
8028 unsigned int mustBeDir;
8029 unsigned int extendedRespRequired;
8031 unsigned int desiredAccess;
8032 unsigned int allocSize;
8033 unsigned int shareAccess;
8034 unsigned int extAttributes;
8035 unsigned int createDisp;
8038 unsigned int impLevel;
8039 unsigned int secFlags;
8040 unsigned int createOptions;
8041 int initialModeBits;
8042 unsigned short baseFid;
8043 smb_fid_t *baseFidp;
8045 cm_scache_t *baseDirp;
8046 unsigned short openAction;
8050 clientchar_t *tidPathp;
8052 int parmOffset, dataOffset;
8059 cm_lock_data_t *ldp = NULL;
8060 int checkDoneRequired = 0;
8067 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8068 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8069 parmp = inp->data + parmOffset;
8070 lparmp = (ULONG *) parmp;
8073 requestOpLock = flags & REQUEST_OPLOCK;
8074 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
8075 mustBeDir = flags & OPEN_DIRECTORY;
8076 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
8079 * Why all of a sudden 32-bit FID?
8080 * We will reject all bits higher than 16.
8082 if (lparmp[1] & 0xFFFF0000)
8083 return CM_ERROR_INVAL;
8084 baseFid = (unsigned short)lparmp[1];
8085 desiredAccess = lparmp[2];
8086 allocSize = lparmp[3];
8087 extAttributes = lparmp[5];
8088 shareAccess = lparmp[6];
8089 createDisp = lparmp[7];
8090 createOptions = lparmp[8];
8093 nameLength = lparmp[11]; /* spec says chars but appears to be bytes */
8094 impLevel = lparmp[12];
8095 secFlags = lparmp[13];
8097 /* mustBeDir is never set; createOptions directory bit seems to be
8100 if (createOptions & FILE_DIRECTORY_FILE)
8102 else if (createOptions & FILE_NON_DIRECTORY_FILE)
8108 * compute initial mode bits based on read-only flag in
8109 * extended attributes
8111 initialModeBits = 0666;
8112 if (extAttributes & SMB_ATTR_READONLY)
8113 initialModeBits &= ~0222;
8115 pathp = smb_ParseStringCb(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
8116 nameLength, NULL, SMB_STRF_ANSIPATH);
8117 /* Sometimes path is not nul-terminated, so we make a copy. */
8118 realPathp = malloc(nameLength+sizeof(clientchar_t));
8119 memcpy(realPathp, pathp, nameLength);
8120 realPathp[nameLength/sizeof(clientchar_t)] = 0;
8121 spacep = cm_GetSpace();
8122 /* smb_StripLastComponent will strip "::$DATA" if present */
8123 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
8125 osi_Log1(smb_logp,"NTTranCreate %S",osi_LogSaveStringW(smb_logp,realPathp));
8126 osi_Log4(smb_logp,"... da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
8127 osi_Log4(smb_logp,"... co[%x],sdl[%x],eal[%x],as[%x],flags[%x]",createOptions,sdLen,eaLen,allocSize);
8128 osi_Log3(smb_logp,"... imp[%x],sec[%x],flags[%x]", impLevel, secFlags, flags);
8131 * Nothing here to handle SMB_IOCTL_FILENAME.
8132 * Will add it if necessary.
8135 if (!cm_IsValidClientString(realPathp)) {
8137 clientchar_t * hexp;
8139 hexp = cm_GetRawCharsAlloc(realPathp, -1);
8140 osi_Log1(smb_logp, "NTTranCreate rejecting invalid name. [%S]",
8141 osi_LogSaveClientString(smb_logp, hexp));
8145 osi_Log0(smb_logp, "NTTranCreate rejecting invalid name.");
8148 return CM_ERROR_BADNTFILENAME;
8151 userp = smb_GetUserFromVCP(vcp, inp);
8153 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
8155 return CM_ERROR_INVAL;
8160 baseDirp = cm_data.rootSCachep;
8161 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8162 if (code == CM_ERROR_TIDIPC) {
8163 /* Attempt to use a TID allocated for IPC. The client
8164 * is probably looking for DCE RPC end points which we
8165 * don't support OR it could be looking to make a DFS
8168 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
8171 cm_ReleaseUser(userp);
8172 return CM_ERROR_NOSUCHPATH;
8176 baseFidp = smb_FindFID(vcp, baseFid, 0);
8178 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
8180 cm_ReleaseUser(userp);
8181 return CM_ERROR_BADFD;
8184 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8186 cm_ReleaseUser(userp);
8187 smb_CloseFID(vcp, baseFidp, NULL, 0);
8188 smb_ReleaseFID(baseFidp);
8189 return CM_ERROR_NOSUCHPATH;
8192 baseDirp = baseFidp->scp;
8196 /* compute open mode */
8198 if (desiredAccess & DELETE)
8199 fidflags |= SMB_FID_OPENDELETE;
8200 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
8201 fidflags |= SMB_FID_OPENREAD_LISTDIR;
8202 if (desiredAccess & AFS_ACCESS_WRITE)
8203 fidflags |= SMB_FID_OPENWRITE;
8204 if (createOptions & FILE_DELETE_ON_CLOSE)
8205 fidflags |= SMB_FID_DELONCLOSE;
8206 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
8207 fidflags |= SMB_FID_SEQUENTIAL;
8208 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
8209 fidflags |= SMB_FID_RANDOM;
8210 if (createOptions & FILE_OPEN_REPARSE_POINT)
8211 osi_Log0(smb_logp, "NTTranCreate Open Reparse Point");
8212 if (smb_IsExecutableFileName(lastNamep))
8213 fidflags |= SMB_FID_EXECUTABLE;
8215 /* And the share mode */
8216 if (shareAccess & FILE_SHARE_READ)
8217 fidflags |= SMB_FID_SHARE_READ;
8218 if (shareAccess & FILE_SHARE_WRITE)
8219 fidflags |= SMB_FID_SHARE_WRITE;
8223 if ( createDisp == FILE_OPEN ||
8224 createDisp == FILE_OVERWRITE ||
8225 createDisp == FILE_OVERWRITE_IF) {
8226 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8227 userp, tidPathp, &req, &dscp);
8230 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8231 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8232 cm_ReleaseSCache(dscp);
8233 cm_ReleaseUser(userp);
8236 smb_ReleaseFID(baseFidp);
8237 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8238 return CM_ERROR_PATH_NOT_COVERED;
8240 return CM_ERROR_NOSUCHPATH;
8242 #endif /* DFS_SUPPORT */
8243 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
8245 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
8246 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
8247 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
8248 if (code == 0 && realDirFlag == 1) {
8249 cm_ReleaseSCache(scp);
8250 cm_ReleaseSCache(dscp);
8251 cm_ReleaseUser(userp);
8254 smb_ReleaseFID(baseFidp);
8255 return CM_ERROR_EXISTS;
8261 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8262 userp, tidPathp, &req, &scp);
8264 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
8265 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
8266 cm_ReleaseSCache(scp);
8267 cm_ReleaseUser(userp);
8270 smb_ReleaseFID(baseFidp);
8271 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8272 return CM_ERROR_PATH_NOT_COVERED;
8274 return CM_ERROR_NOSUCHPATH;
8276 #endif /* DFS_SUPPORT */
8282 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
8283 /* look up parent directory */
8285 code = cm_NameI(baseDirp, spacep->wdata,
8286 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8287 userp, tidPathp, &req, &dscp);
8289 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8290 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8291 cm_ReleaseSCache(dscp);
8292 cm_ReleaseUser(userp);
8295 smb_ReleaseFID(baseFidp);
8296 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8297 return CM_ERROR_PATH_NOT_COVERED;
8299 return CM_ERROR_NOSUCHPATH;
8301 #endif /* DFS_SUPPORT */
8305 cm_FreeSpace(spacep);
8308 smb_ReleaseFID(baseFidp);
8311 cm_ReleaseUser(userp);
8317 lastNamep = realPathp;
8321 if (!smb_IsLegalFilename(lastNamep))
8322 return CM_ERROR_BADNTFILENAME;
8325 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
8326 code = cm_Lookup(dscp, lastNamep,
8327 CM_FLAG_FOLLOW, userp, &req, &scp);
8329 code = cm_Lookup(dscp, lastNamep,
8330 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8333 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8334 cm_ReleaseSCache(dscp);
8335 cm_ReleaseUser(userp);
8342 smb_ReleaseFID(baseFidp);
8343 cm_FreeSpace(spacep);
8346 /* if we get here, if code is 0, the file exists and is represented by
8347 * scp. Otherwise, we have to create it. The dir may be represented
8348 * by dscp, or we may have found the file directly. If code is non-zero,
8352 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
8354 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8356 cm_ReleaseSCache(dscp);
8357 cm_ReleaseSCache(scp);
8358 cm_ReleaseUser(userp);
8362 checkDoneRequired = 1;
8364 if (createDisp == FILE_CREATE) {
8365 /* oops, file shouldn't be there */
8366 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8368 cm_ReleaseSCache(dscp);
8369 cm_ReleaseSCache(scp);
8370 cm_ReleaseUser(userp);
8372 return CM_ERROR_EXISTS;
8375 if (createDisp == FILE_OVERWRITE ||
8376 createDisp == FILE_OVERWRITE_IF) {
8377 setAttr.mask = CM_ATTRMASK_LENGTH;
8378 setAttr.length.LowPart = 0;
8379 setAttr.length.HighPart = 0;
8381 /* now watch for a symlink */
8383 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8385 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8387 /* we have a more accurate file to use (the
8388 * target of the symbolic link). Otherwise,
8389 * we'll just use the symlink anyway.
8391 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8393 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8394 cm_ReleaseSCache(scp);
8396 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
8398 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8400 cm_ReleaseSCache(dscp);
8402 cm_ReleaseSCache(scp);
8403 cm_ReleaseUser(userp);
8409 code = cm_SetAttr(scp, &setAttr, userp, &req);
8410 openAction = 3; /* truncated existing file */
8412 else openAction = 1; /* found existing file */
8414 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
8415 /* don't create if not found */
8417 cm_ReleaseSCache(dscp);
8418 cm_ReleaseUser(userp);
8420 return CM_ERROR_NOSUCHFILE;
8422 else if (realDirFlag == 0 || realDirFlag == -1) {
8423 osi_assertx(dscp != NULL, "null cm_scache_t");
8424 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %S",
8425 osi_LogSaveClientString(smb_logp, lastNamep));
8426 openAction = 2; /* created file */
8427 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8428 setAttr.clientModTime = time(NULL);
8429 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8433 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8434 smb_NotifyChange(FILE_ACTION_ADDED,
8435 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8436 dscp, lastNamep, NULL, TRUE);
8437 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
8438 /* Not an exclusive create, and someone else tried
8439 * creating it already, then we open it anyway. We
8440 * don't bother retrying after this, since if this next
8441 * fails, that means that the file was deleted after we
8442 * started this call.
8444 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8447 if (createDisp == FILE_OVERWRITE_IF) {
8448 setAttr.mask = CM_ATTRMASK_LENGTH;
8449 setAttr.length.LowPart = 0;
8450 setAttr.length.HighPart = 0;
8452 /* now watch for a symlink */
8454 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8456 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8458 /* we have a more accurate file to use (the
8459 * target of the symbolic link). Otherwise,
8460 * we'll just use the symlink anyway.
8462 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8464 cm_ReleaseSCache(scp);
8468 code = cm_SetAttr(scp, &setAttr, userp, &req);
8470 } /* lookup succeeded */
8473 /* create directory */
8474 osi_assertx(dscp != NULL, "null cm_scache_t");
8476 "smb_ReceiveNTTranCreate creating directory %S",
8477 osi_LogSaveClientString(smb_logp, lastNamep));
8478 openAction = 2; /* created directory */
8479 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8480 setAttr.clientModTime = time(NULL);
8481 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8482 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8483 smb_NotifyChange(FILE_ACTION_ADDED,
8484 FILE_NOTIFY_CHANGE_DIR_NAME,
8485 dscp, lastNamep, NULL, TRUE);
8487 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
8488 /* Not an exclusive create, and someone else tried
8489 * creating it already, then we open it anyway. We
8490 * don't bother retrying after this, since if this next
8491 * fails, that means that the file was deleted after we
8492 * started this call.
8494 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8500 /* something went wrong creating or truncating the file */
8501 if (checkDoneRequired)
8502 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8504 cm_ReleaseSCache(scp);
8505 cm_ReleaseUser(userp);
8510 /* make sure we have file vs. dir right */
8511 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
8512 /* now watch for a symlink */
8514 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8516 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8518 /* we have a more accurate file to use (the
8519 * target of the symbolic link). Otherwise,
8520 * we'll just use the symlink anyway.
8522 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8524 if (checkDoneRequired) {
8525 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8526 checkDoneRequired = 0;
8528 cm_ReleaseSCache(scp);
8533 if (scp->fileType != CM_SCACHETYPE_FILE) {
8534 if (checkDoneRequired)
8535 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8536 cm_ReleaseSCache(scp);
8537 cm_ReleaseUser(userp);
8539 return CM_ERROR_ISDIR;
8543 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8544 if (checkDoneRequired)
8545 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8546 cm_ReleaseSCache(scp);
8547 cm_ReleaseUser(userp);
8549 return CM_ERROR_NOTDIR;
8552 /* open the file itself */
8553 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8554 osi_assertx(fidp, "null smb_fid_t");
8556 /* save a reference to the user */
8558 fidp->userp = userp;
8560 /* If we are restricting sharing, we should do so with a suitable
8562 if (scp->fileType == CM_SCACHETYPE_FILE &&
8563 !(fidflags & SMB_FID_SHARE_WRITE)) {
8565 LARGE_INTEGER LOffset, LLength;
8568 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8569 LOffset.LowPart = SMB_FID_QLOCK_LOW;
8570 LLength.HighPart = 0;
8571 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8573 /* Similar to what we do in handling NTCreateX. We get a
8574 shared lock if we are only opening the file for reading. */
8575 if ((fidflags & SMB_FID_SHARE_READ) ||
8576 !(fidflags & SMB_FID_OPENWRITE)) {
8577 sLockType = LOCKING_ANDX_SHARED_LOCK;
8582 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8584 lock_ObtainWrite(&scp->rw);
8585 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8586 lock_ReleaseWrite(&scp->rw);
8589 if (checkDoneRequired)
8590 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8591 cm_ReleaseSCache(scp);
8592 cm_ReleaseUser(userp);
8593 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
8594 smb_CloseFID(vcp, fidp, NULL, 0);
8595 smb_ReleaseFID(fidp);
8597 return CM_ERROR_SHARING_VIOLATION;
8601 /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
8602 if (checkDoneRequired) {
8603 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8604 checkDoneRequired = 0;
8607 lock_ObtainMutex(&fidp->mx);
8608 /* save a pointer to the vnode */
8610 lock_ObtainWrite(&scp->rw);
8611 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8612 lock_ReleaseWrite(&scp->rw);
8613 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
8615 fidp->flags = fidflags;
8617 /* remember if the file was newly created */
8619 fidp->flags |= SMB_FID_CREATED;
8621 /* save parent dir and pathname for deletion or change notification */
8622 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8623 fidp->flags |= SMB_FID_NTOPEN;
8624 fidp->NTopen_dscp = dscp;
8625 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
8627 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
8629 fidp->NTopen_wholepathp = realPathp;
8630 lock_ReleaseMutex(&fidp->mx);
8632 /* we don't need this any longer */
8634 cm_ReleaseSCache(dscp);
8636 cm_Open(scp, 0, userp);
8638 /* set inp->fid so that later read calls in same msg can find fid */
8639 inp->fid = fidp->fid;
8641 /* check whether we are required to send an extended response */
8642 if (!extendedRespRequired) {
8644 parmOffset = 8*4 + 39;
8645 parmOffset += 1; /* pad to 4 */
8646 dataOffset = parmOffset + 70;
8650 /* Total Parameter Count */
8651 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8652 /* Total Data Count */
8653 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8654 /* Parameter Count */
8655 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8656 /* Parameter Offset */
8657 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8658 /* Parameter Displacement */
8659 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8661 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8663 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8664 /* Data Displacement */
8665 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8666 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8667 smb_SetSMBDataLength(outp, 70);
8669 lock_ObtainRead(&scp->rw);
8670 outData = smb_GetSMBData(outp, NULL);
8671 outData++; /* round to get to parmOffset */
8672 *outData = 0; outData++; /* oplock */
8673 *outData = 0; outData++; /* reserved */
8674 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8675 *((ULONG *)outData) = openAction; outData += 4;
8676 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8677 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8678 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8679 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8680 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8681 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8682 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8683 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8684 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8685 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8686 *((USHORT *)outData) = NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS;
8687 outData += 2; /* dev state */
8688 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8689 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8690 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8691 outData += 2; /* is a dir? */
8694 parmOffset = 8*4 + 39;
8695 parmOffset += 1; /* pad to 4 */
8696 dataOffset = parmOffset + 104;
8700 /* Total Parameter Count */
8701 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8702 /* Total Data Count */
8703 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8704 /* Parameter Count */
8705 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8706 /* Parameter Offset */
8707 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8708 /* Parameter Displacement */
8709 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8711 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8713 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8714 /* Data Displacement */
8715 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8716 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8717 smb_SetSMBDataLength(outp, 105);
8719 lock_ObtainRead(&scp->rw);
8720 outData = smb_GetSMBData(outp, NULL);
8721 outData++; /* round to get to parmOffset */
8722 *outData = 0; outData++; /* oplock */
8723 *outData = 1; outData++; /* response type */
8724 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8725 *((ULONG *)outData) = openAction; outData += 4;
8726 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8727 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8728 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8729 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8730 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8731 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8732 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8733 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8734 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8735 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8736 *((USHORT *)outData) = NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS;
8737 outData += 2; /* dev state */
8738 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8739 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8740 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8741 outData += 1; /* is a dir? */
8742 /* Setting the GUID results in failures with cygwin */
8743 memset(outData,0,24); outData += 24; /* GUID */
8744 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
8745 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
8748 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
8749 LargeIntegerGreaterThanZero(scp->length) &&
8750 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
8753 lock_ReleaseRead(&scp->rw);
8756 cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
8757 scp->length.LowPart, scp->length.HighPart,
8760 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
8762 cm_ReleaseUser(userp);
8763 smb_ReleaseFID(fidp);
8765 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
8766 /* leave scp held since we put it in fidp->scp */
8770 /* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
8771 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
8774 smb_packet_t *savedPacketp;
8776 USHORT fid, watchtree;
8780 filter = smb_GetSMBParm(inp, 19) |
8781 (smb_GetSMBParm(inp, 20) << 16);
8782 fid = smb_GetSMBParm(inp, 21);
8783 watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
8785 fidp = smb_FindFID(vcp, fid, 0);
8787 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
8788 return CM_ERROR_BADFD;
8791 lock_ObtainMutex(&fidp->mx);
8792 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8793 lock_ReleaseMutex(&fidp->mx);
8794 smb_CloseFID(vcp, fidp, NULL, 0);
8795 smb_ReleaseFID(fidp);
8796 return CM_ERROR_NOSUCHFILE;
8800 lock_ReleaseMutex(&fidp->mx);
8802 /* Create a copy of the Directory Watch Packet to use when sending the
8803 * notification if in the future a matching change is detected.
8805 savedPacketp = smb_CopyPacket(inp);
8806 if (vcp != savedPacketp->vcp) {
8808 if (savedPacketp->vcp)
8809 smb_ReleaseVC(savedPacketp->vcp);
8810 savedPacketp->vcp = vcp;
8813 /* Add the watch to the list of events to send notifications for */
8814 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8815 savedPacketp->nextp = smb_Directory_Watches;
8816 smb_Directory_Watches = savedPacketp;
8817 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8819 osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%S\"",
8820 fidp, scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp));
8821 osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
8822 filter, fid, watchtree);
8823 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8824 osi_Log0(smb_logp, " Notify Change File Name");
8825 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8826 osi_Log0(smb_logp, " Notify Change Directory Name");
8827 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8828 osi_Log0(smb_logp, " Notify Change Attributes");
8829 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8830 osi_Log0(smb_logp, " Notify Change Size");
8831 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8832 osi_Log0(smb_logp, " Notify Change Last Write");
8833 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8834 osi_Log0(smb_logp, " Notify Change Last Access");
8835 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8836 osi_Log0(smb_logp, " Notify Change Creation");
8837 if (filter & FILE_NOTIFY_CHANGE_EA)
8838 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8839 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8840 osi_Log0(smb_logp, " Notify Change Security");
8841 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8842 osi_Log0(smb_logp, " Notify Change Stream Name");
8843 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8844 osi_Log0(smb_logp, " Notify Change Stream Size");
8845 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8846 osi_Log0(smb_logp, " Notify Change Stream Write");
8848 lock_ObtainWrite(&scp->rw);
8850 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
8852 scp->flags |= CM_SCACHEFLAG_WATCHED;
8853 lock_ReleaseWrite(&scp->rw);
8854 cm_ReleaseSCache(scp);
8855 smb_ReleaseFID(fidp);
8857 outp->flags |= SMB_PACKETFLAG_NOSEND;
8861 unsigned char nullSecurityDesc[36] = {
8862 0x01, /* security descriptor revision */
8863 0x00, /* reserved, should be zero */
8864 0x00, 0x80, /* security descriptor control;
8865 * 0x8000 : self-relative format */
8866 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
8867 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
8868 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
8869 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
8870 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8871 /* "null SID" owner SID */
8872 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
8873 /* "null SID" group SID */
8876 /* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
8877 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8879 int parmOffset, parmCount, dataOffset, dataCount;
8887 ULONG securityInformation;
8889 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8890 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8891 parmp = inp->data + parmOffset;
8892 sparmp = (USHORT *) parmp;
8893 lparmp = (ULONG *) parmp;
8896 securityInformation = lparmp[1];
8898 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
8899 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
8907 parmOffset = 8*4 + 39;
8908 parmOffset += 1; /* pad to 4 */
8910 dataOffset = parmOffset + parmCount;
8914 /* Total Parameter Count */
8915 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8916 /* Total Data Count */
8917 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8918 /* Parameter Count */
8919 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8920 /* Parameter Offset */
8921 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8922 /* Parameter Displacement */
8923 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8925 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8927 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8928 /* Data Displacement */
8929 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8930 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8931 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
8933 outData = smb_GetSMBData(outp, NULL);
8934 outData++; /* round to get to parmOffset */
8935 *((ULONG *)outData) = 36; outData += 4; /* length */
8937 if (maxData >= 36) {
8938 memcpy(outData, nullSecurityDesc, 36);
8942 return CM_ERROR_BUFFERTOOSMALL;
8945 /* SMB_COM_NT_TRANSACT
8947 SMB_COM_NT_TRANSACT_SECONDARY should also be handled here.
8949 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8951 unsigned short function;
8953 function = smb_GetSMBParm(inp, 18);
8955 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
8957 /* We can handle long names */
8958 if (vcp->flags & SMB_VCFLAG_USENT)
8959 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
8962 case 1: /* NT_TRANSACT_CREATE */
8963 return smb_ReceiveNTTranCreate(vcp, inp, outp);
8964 case 2: /* NT_TRANSACT_IOCTL */
8965 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
8967 case 3: /* NT_TRANSACT_SET_SECURITY_DESC */
8968 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
8970 case 4: /* NT_TRANSACT_NOTIFY_CHANGE */
8971 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
8972 case 5: /* NT_TRANSACT_RENAME */
8973 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
8975 case 6: /* NT_TRANSACT_QUERY_SECURITY_DESC */
8976 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
8978 osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
8981 osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
8984 return CM_ERROR_BADOP;
8988 * smb_NotifyChange -- find relevant change notification messages and
8991 * If we don't know the file name (i.e. a callback break), filename is
8992 * NULL, and we return a zero-length list.
8994 * At present there is not a single call to smb_NotifyChange that
8995 * has the isDirectParent parameter set to FALSE.
8997 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
8998 cm_scache_t *dscp, clientchar_t *filename, clientchar_t *otherFilename,
8999 BOOL isDirectParent)
9001 smb_packet_t *watch, *lastWatch, *nextWatch;
9002 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen = 0;
9003 char *outData, *oldOutData;
9007 BOOL twoEntries = FALSE;
9008 ULONG otherNameLen, oldParmCount = 0;
9012 /* Get ready for rename within directory */
9013 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
9015 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
9018 osi_Log4(smb_logp,"in smb_NotifyChange for file [%S] dscp [%p] notification 0x%x parent %d",
9019 osi_LogSaveClientString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
9021 osi_Log0(smb_logp," FILE_ACTION_NONE");
9022 if (action == FILE_ACTION_ADDED)
9023 osi_Log0(smb_logp," FILE_ACTION_ADDED");
9024 if (action == FILE_ACTION_REMOVED)
9025 osi_Log0(smb_logp," FILE_ACTION_REMOVED");
9026 if (action == FILE_ACTION_MODIFIED)
9027 osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
9028 if (action == FILE_ACTION_RENAMED_OLD_NAME)
9029 osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
9030 if (action == FILE_ACTION_RENAMED_NEW_NAME)
9031 osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
9033 lock_ObtainMutex(&smb_Dir_Watch_Lock);
9034 watch = smb_Directory_Watches;
9036 filter = smb_GetSMBParm(watch, 19)
9037 | (smb_GetSMBParm(watch, 20) << 16);
9038 fid = smb_GetSMBParm(watch, 21);
9039 wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
9041 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
9042 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
9045 * Strange hack - bug in NT Client and NT Server that we must emulate?
9047 if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
9048 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
9050 fidp = smb_FindFID(watch->vcp, fid, 0);
9052 osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
9054 watch = watch->nextp;
9058 if (fidp->scp != dscp ||
9059 fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
9060 (filter & notifyFilter) == 0 ||
9061 (!isDirectParent && !wtree))
9063 osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
9065 watch = watch->nextp;
9066 smb_ReleaseFID(fidp);
9071 "Sending Change Notification for fid %d filter 0x%x wtree %d file %S",
9072 fid, filter, wtree, osi_LogSaveClientString(smb_logp, filename));
9073 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
9074 osi_Log0(smb_logp, " Notify Change File Name");
9075 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
9076 osi_Log0(smb_logp, " Notify Change Directory Name");
9077 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
9078 osi_Log0(smb_logp, " Notify Change Attributes");
9079 if (filter & FILE_NOTIFY_CHANGE_SIZE)
9080 osi_Log0(smb_logp, " Notify Change Size");
9081 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
9082 osi_Log0(smb_logp, " Notify Change Last Write");
9083 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
9084 osi_Log0(smb_logp, " Notify Change Last Access");
9085 if (filter & FILE_NOTIFY_CHANGE_CREATION)
9086 osi_Log0(smb_logp, " Notify Change Creation");
9087 if (filter & FILE_NOTIFY_CHANGE_EA)
9088 osi_Log0(smb_logp, " Notify Change Extended Attributes");
9089 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
9090 osi_Log0(smb_logp, " Notify Change Security");
9091 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
9092 osi_Log0(smb_logp, " Notify Change Stream Name");
9093 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
9094 osi_Log0(smb_logp, " Notify Change Stream Size");
9095 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
9096 osi_Log0(smb_logp, " Notify Change Stream Write");
9098 /* A watch can only be notified once. Remove it from the list */
9099 nextWatch = watch->nextp;
9100 if (watch == smb_Directory_Watches)
9101 smb_Directory_Watches = nextWatch;
9103 lastWatch->nextp = nextWatch;
9105 /* Turn off WATCHED flag in dscp */
9106 lock_ObtainWrite(&dscp->rw);
9108 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
9110 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
9111 lock_ReleaseWrite(&dscp->rw);
9113 /* Convert to response packet */
9114 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
9115 #ifdef SEND_CANONICAL_PATHNAMES
9116 ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
9118 ((smb_t *) watch)->wct = 0;
9121 if (filename == NULL) {
9124 nameLen = (ULONG)cm_ClientStrLen(filename);
9125 parmCount = 3*4 + nameLen*2;
9126 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
9128 otherNameLen = (ULONG)cm_ClientStrLen(otherFilename);
9129 oldParmCount = parmCount;
9130 parmCount += 3*4 + otherNameLen*2;
9131 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
9133 if (maxLen < parmCount)
9134 parmCount = 0; /* not enough room */
9136 parmOffset = 8*4 + 39;
9137 parmOffset += 1; /* pad to 4 */
9138 dataOffset = parmOffset + parmCount;
9142 /* Total Parameter Count */
9143 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
9144 /* Total Data Count */
9145 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9146 /* Parameter Count */
9147 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
9148 /* Parameter Offset */
9149 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
9150 /* Parameter Displacement */
9151 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9153 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9155 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
9156 /* Data Displacement */
9157 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9158 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
9159 smb_SetSMBDataLength(watch, parmCount + 1);
9161 if (parmCount != 0) {
9162 outData = smb_GetSMBData(watch, NULL);
9163 outData++; /* round to get to parmOffset */
9164 oldOutData = outData;
9165 *((DWORD *)outData) = oldParmCount; outData += 4;
9166 /* Next Entry Offset */
9167 *((DWORD *)outData) = action; outData += 4;
9169 *((DWORD *)outData) = nameLen*2; outData += 4;
9170 /* File Name Length */
9172 smb_UnparseString(watch, outData, filename, NULL, 0);
9176 outData = oldOutData + oldParmCount;
9177 *((DWORD *)outData) = 0; outData += 4;
9178 /* Next Entry Offset */
9179 *((DWORD *)outData) = otherAction; outData += 4;
9181 *((DWORD *)outData) = otherNameLen*2;
9182 outData += 4; /* File Name Length */
9183 smb_UnparseString(watch, outData, otherFilename, NULL, 0);
9188 * If filename is null, we don't know the cause of the
9189 * change notification. We return zero data (see above),
9190 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
9191 * (= 0x010C). We set the error code here by hand, without
9192 * modifying wct and bcc.
9194 if (filename == NULL) {
9195 ((smb_t *) watch)->rcls = 0x0C;
9196 ((smb_t *) watch)->reh = 0x01;
9197 ((smb_t *) watch)->errLow = 0;
9198 ((smb_t *) watch)->errHigh = 0;
9199 /* Set NT Status codes flag */
9200 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9203 smb_SendPacket(watch->vcp, watch);
9204 smb_FreePacket(watch);
9206 smb_ReleaseFID(fidp);
9209 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9212 /* SMB_COM_NT_CANCEL */
9213 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9215 unsigned char *replyWctp;
9216 smb_packet_t *watch, *lastWatch;
9217 USHORT fid, watchtree;
9221 osi_Log0(smb_logp, "SMB3 receive NT cancel");
9223 lock_ObtainMutex(&smb_Dir_Watch_Lock);
9224 watch = smb_Directory_Watches;
9226 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
9227 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
9228 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
9229 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
9230 if (watch == smb_Directory_Watches)
9231 smb_Directory_Watches = watch->nextp;
9233 lastWatch->nextp = watch->nextp;
9234 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9236 /* Turn off WATCHED flag in scp */
9237 fid = smb_GetSMBParm(watch, 21);
9238 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
9240 if (vcp != watch->vcp)
9241 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
9244 fidp = smb_FindFID(vcp, fid, 0);
9246 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %S",
9248 (fidp ? osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp) :_C("")));
9251 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
9253 lock_ObtainWrite(&scp->rw);
9255 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
9257 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
9258 lock_ReleaseWrite(&scp->rw);
9260 smb_ReleaseFID(fidp);
9262 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
9265 /* assume STATUS32; return 0xC0000120 (CANCELED) */
9266 replyWctp = watch->wctp;
9270 ((smb_t *)watch)->rcls = 0x20;
9271 ((smb_t *)watch)->reh = 0x1;
9272 ((smb_t *)watch)->errLow = 0;
9273 ((smb_t *)watch)->errHigh = 0xC0;
9274 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9275 smb_SendPacket(vcp, watch);
9276 smb_FreePacket(watch);
9280 watch = watch->nextp;
9282 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9288 * NT rename also does hard links.
9291 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
9292 #define RENAME_FLAG_HARD_LINK 0x103
9293 #define RENAME_FLAG_RENAME 0x104
9294 #define RENAME_FLAG_COPY 0x105
9296 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9298 clientchar_t *oldPathp, *newPathp;
9304 attrs = smb_GetSMBParm(inp, 0);
9305 rename_type = smb_GetSMBParm(inp, 1);
9307 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
9308 osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
9309 return CM_ERROR_NOACCESS;
9312 tp = smb_GetSMBData(inp, NULL);
9313 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
9315 return CM_ERROR_BADSMB;
9316 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
9318 return CM_ERROR_BADSMB;
9320 osi_Log3(smb_logp, "NTRename for [%S]->[%S] type [%s]",
9321 osi_LogSaveClientString(smb_logp, oldPathp),
9322 osi_LogSaveClientString(smb_logp, newPathp),
9323 ((rename_type==RENAME_FLAG_RENAME)?"rename":(rename_type==RENAME_FLAG_HARD_LINK)?"hardlink":"other"));
9325 if (rename_type == RENAME_FLAG_RENAME) {
9326 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
9327 } else if (rename_type == RENAME_FLAG_HARD_LINK) { /* RENAME_FLAG_HARD_LINK */
9328 code = smb_Link(vcp,inp,oldPathp,newPathp);
9330 code = CM_ERROR_BADOP;
9336 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock", LOCK_HIERARCHY_SMB_DIRWATCH);
9339 cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
9341 smb_username_t *unp;
9344 unp = smb_FindUserByName(usern, machine, flags);
9346 lock_ObtainMutex(&unp->mx);
9347 unp->userp = cm_NewUser();
9348 lock_ReleaseMutex(&unp->mx);
9349 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9351 osi_Log2(smb_logp,"smb_FindCMUserByName Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9355 smb_ReleaseUsername(unp);