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(spacep->wdata, &lastNamep, pathp);
2532 /* special case magic file name for receiving IOCTL requests
2533 * (since IOCTL calls themselves aren't getting through).
2535 (cm_ClientStrCmpI(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
2537 /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional)*/
2538 (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
2540 unsigned short file_type = 0;
2541 unsigned short device_state = 0;
2543 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2546 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
2547 osi_Log2(smb_logp, "smb_ReceiveTran2Open Creating RPC Fid [%d] code [%d]",
2550 smb_ReleaseFID(fidp);
2551 smb_FreeTran2Packet(outp);
2552 osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
2556 smb_SetupIoctlFid(fidp, spacep);
2557 osi_Log1(smb_logp, "smb_ReceiveTran2Open Creating IOCTL Fid [%d]", fidp->fid);
2560 /* copy out remainder of the parms */
2562 outp->parmsp[parmSlot++] = fidp->fid;
2564 outp->parmsp[parmSlot++] = 0; /* attrs */
2565 outp->parmsp[parmSlot++] = 0; /* mod time */
2566 outp->parmsp[parmSlot++] = 0;
2567 outp->parmsp[parmSlot++] = 0; /* len */
2568 outp->parmsp[parmSlot++] = 0x7fff;
2569 outp->parmsp[parmSlot++] = openMode;
2570 outp->parmsp[parmSlot++] = file_type;
2571 outp->parmsp[parmSlot++] = device_state;
2573 /* and the final "always present" stuff */
2574 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2575 /* next write out the "unique" ID */
2576 outp->parmsp[parmSlot++] = 0x1234;
2577 outp->parmsp[parmSlot++] = 0x5678;
2578 outp->parmsp[parmSlot++] = 0;
2579 if (returnEALength) {
2580 outp->parmsp[parmSlot++] = 0;
2581 outp->parmsp[parmSlot++] = 0;
2584 outp->totalData = 0;
2585 outp->totalParms = parmSlot * 2;
2587 smb_SendTran2Packet(vcp, outp, op);
2589 smb_FreeTran2Packet(outp);
2591 /* and clean up fid reference */
2592 smb_ReleaseFID(fidp);
2598 osi_Log0(smb_logp, "Tran2Open rejecting IPC TID");
2599 smb_FreeTran2Packet(outp);
2600 return CM_ERROR_BADFD;
2604 if (!cm_IsValidClientString(pathp)) {
2606 clientchar_t * hexp;
2608 hexp = cm_GetRawCharsAlloc(pathp, -1);
2609 osi_Log1(smb_logp, "Tran2Open rejecting invalid name. [%S]",
2610 osi_LogSaveClientString(smb_logp, hexp));
2614 osi_Log0(smb_logp, "Tran2Open rejecting invalid name");
2616 smb_FreeTran2Packet(outp);
2617 return CM_ERROR_BADNTFILENAME;
2620 #ifdef DEBUG_VERBOSE
2622 char *hexp, *asciip;
2623 asciip = (lastNamep ? lastNamep : pathp);
2624 hexp = osi_HexifyString( asciip );
2625 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2630 userp = smb_GetTran2User(vcp, p);
2631 /* In the off chance that userp is NULL, we log and abandon */
2633 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2634 smb_FreeTran2Packet(outp);
2635 return CM_ERROR_BADSMB;
2639 code = cm_NameI(cm_data.rootSCachep, pathp,
2640 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2641 userp, tidPathp, &req, &scp);
2643 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2644 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2645 userp, tidPathp, &req, &dscp);
2646 cm_FreeSpace(spacep);
2649 cm_ReleaseUser(userp);
2650 smb_FreeTran2Packet(outp);
2655 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2656 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2657 (clientchar_t*) spacep->data);
2658 cm_ReleaseSCache(dscp);
2659 cm_ReleaseUser(userp);
2660 smb_FreeTran2Packet(outp);
2661 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2662 return CM_ERROR_PATH_NOT_COVERED;
2664 return CM_ERROR_NOSUCHPATH;
2666 #endif /* DFS_SUPPORT */
2668 /* otherwise, scp points to the parent directory. Do a lookup,
2669 * and truncate the file if we find it, otherwise we create the
2676 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2678 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2679 cm_ReleaseSCache(dscp);
2680 cm_ReleaseUser(userp);
2681 smb_FreeTran2Packet(outp);
2686 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2687 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2688 cm_ReleaseSCache(scp);
2689 cm_ReleaseUser(userp);
2690 smb_FreeTran2Packet(outp);
2691 if ( WANTS_DFS_PATHNAMES(p) || pnc )
2692 return CM_ERROR_PATH_NOT_COVERED;
2694 return CM_ERROR_NOSUCHPATH;
2696 #endif /* DFS_SUPPORT */
2698 /* macintosh is expensive to program for it */
2699 cm_FreeSpace(spacep);
2702 /* if we get here, if code is 0, the file exists and is represented by
2703 * scp. Otherwise, we have to create it.
2706 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2709 cm_ReleaseSCache(dscp);
2710 cm_ReleaseSCache(scp);
2711 cm_ReleaseUser(userp);
2712 smb_FreeTran2Packet(outp);
2717 /* oops, file shouldn't be there */
2719 cm_ReleaseSCache(dscp);
2720 cm_ReleaseSCache(scp);
2721 cm_ReleaseUser(userp);
2722 smb_FreeTran2Packet(outp);
2723 return CM_ERROR_EXISTS;
2727 setAttr.mask = CM_ATTRMASK_LENGTH;
2728 setAttr.length.LowPart = 0;
2729 setAttr.length.HighPart = 0;
2730 code = cm_SetAttr(scp, &setAttr, userp, &req);
2731 openAction = 3; /* truncated existing file */
2734 openAction = 1; /* found existing file */
2736 else if (!(openFun & 0x10)) {
2737 /* don't create if not found */
2739 cm_ReleaseSCache(dscp);
2740 osi_assertx(scp == NULL, "null cm_scache_t");
2741 cm_ReleaseUser(userp);
2742 smb_FreeTran2Packet(outp);
2743 return CM_ERROR_NOSUCHFILE;
2746 osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2747 openAction = 2; /* created file */
2748 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2749 cm_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2750 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2754 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2755 smb_NotifyChange(FILE_ACTION_ADDED,
2756 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2757 dscp, lastNamep, NULL, TRUE);
2758 } else if (!excl && code == CM_ERROR_EXISTS) {
2759 /* not an exclusive create, and someone else tried
2760 * creating it already, then we open it anyway. We
2761 * don't bother retrying after this, since if this next
2762 * fails, that means that the file was deleted after we
2763 * started this call.
2765 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2769 setAttr.mask = CM_ATTRMASK_LENGTH;
2770 setAttr.length.LowPart = 0;
2771 setAttr.length.HighPart = 0;
2772 code = cm_SetAttr(scp, &setAttr, userp,
2775 } /* lookup succeeded */
2779 /* we don't need this any longer */
2781 cm_ReleaseSCache(dscp);
2784 /* something went wrong creating or truncating the file */
2786 cm_ReleaseSCache(scp);
2787 cm_ReleaseUser(userp);
2788 smb_FreeTran2Packet(outp);
2792 /* make sure we're about to open a file */
2793 if (scp->fileType != CM_SCACHETYPE_FILE) {
2795 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2796 cm_scache_t * targetScp = 0;
2797 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2799 /* we have a more accurate file to use (the
2800 * target of the symbolic link). Otherwise,
2801 * we'll just use the symlink anyway.
2803 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2805 cm_ReleaseSCache(scp);
2809 if (scp->fileType != CM_SCACHETYPE_FILE) {
2810 cm_ReleaseSCache(scp);
2811 cm_ReleaseUser(userp);
2812 smb_FreeTran2Packet(outp);
2813 return CM_ERROR_ISDIR;
2817 /* now all we have to do is open the file itself */
2818 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2819 osi_assertx(fidp, "null smb_fid_t");
2822 lock_ObtainMutex(&fidp->mx);
2823 /* save a pointer to the vnode */
2824 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2826 lock_ObtainWrite(&scp->rw);
2827 scp->flags |= CM_SCACHEFLAG_SMB_FID;
2828 lock_ReleaseWrite(&scp->rw);
2831 fidp->userp = userp;
2833 /* compute open mode */
2835 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
2836 if (openMode == 1 || openMode == 2)
2837 fidp->flags |= SMB_FID_OPENWRITE;
2839 /* remember that the file was newly created */
2841 fidp->flags |= SMB_FID_CREATED;
2843 lock_ReleaseMutex(&fidp->mx);
2845 smb_ReleaseFID(fidp);
2847 cm_Open(scp, 0, userp);
2849 /* copy out remainder of the parms */
2851 outp->parmsp[parmSlot++] = fidp->fid;
2852 lock_ObtainRead(&scp->rw);
2854 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2855 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2856 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2857 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2858 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2859 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2860 outp->parmsp[parmSlot++] = openMode;
2861 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2862 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2864 /* and the final "always present" stuff */
2865 outp->parmsp[parmSlot++] = openAction;
2866 /* next write out the "unique" ID */
2867 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2868 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2869 outp->parmsp[parmSlot++] = 0;
2870 if (returnEALength) {
2871 outp->parmsp[parmSlot++] = 0;
2872 outp->parmsp[parmSlot++] = 0;
2874 lock_ReleaseRead(&scp->rw);
2875 outp->totalData = 0; /* total # of data bytes */
2876 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2878 smb_SendTran2Packet(vcp, outp, op);
2880 smb_FreeTran2Packet(outp);
2882 cm_ReleaseUser(userp);
2883 /* leave scp held since we put it in fidp->scp */
2887 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2890 unsigned short infolevel;
2892 infolevel = p->parmsp[0];
2894 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2896 return CM_ERROR_BAD_LEVEL;
2899 /* TRANS2_QUERY_FS_INFORMATION */
2900 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2902 smb_tran2Packet_t *outp;
2903 smb_tran2QFSInfo_t qi;
2907 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2909 switch (p->parmsp[0]) {
2910 case SMB_INFO_ALLOCATION:
2912 responseSize = sizeof(qi.u.allocInfo);
2914 qi.u.allocInfo.FSID = 0;
2915 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2916 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2917 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2918 qi.u.allocInfo.bytesPerSector = 1024;
2921 case SMB_INFO_VOLUME:
2923 qi.u.volumeInfo.vsn = 1234; /* Volume serial number */
2924 qi.u.volumeInfo.vnCount = 3; /* Number of characters in label (AFS\0)*/
2926 /* we're supposed to pad it out with zeroes to the end */
2927 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2928 smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
2930 responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
2933 case SMB_QUERY_FS_VOLUME_INFO:
2934 /* FS volume info */
2935 responseSize = sizeof(qi.u.FSvolumeInfo);
2938 FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
2939 memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
2942 qi.u.FSvolumeInfo.vsn = 1234;
2943 qi.u.FSvolumeInfo.vnCount = 6; /* This is always in Unicode */
2944 memset(&qi.u.FSvolumeInfo.label, 0, sizeof(qi.u.FSvolumeInfo.label));
2945 memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
2948 case SMB_QUERY_FS_SIZE_INFO:
2950 responseSize = sizeof(qi.u.FSsizeInfo);
2952 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2953 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2954 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2955 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2956 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2957 qi.u.FSsizeInfo.bytesPerSector = 1024;
2960 case SMB_QUERY_FS_DEVICE_INFO:
2961 /* FS device info */
2962 responseSize = sizeof(qi.u.FSdeviceInfo);
2964 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2965 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2968 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2969 /* FS attribute info */
2971 /* attributes, defined in WINNT.H:
2972 * FILE_CASE_SENSITIVE_SEARCH 0x1
2973 * FILE_CASE_PRESERVED_NAMES 0x2
2974 * FILE_UNICODE_ON_DISK 0x4
2975 * FILE_VOLUME_QUOTAS 0x10
2976 * <no name defined> 0x4000
2977 * If bit 0x4000 is not set, Windows 95 thinks
2978 * we can't handle long (non-8.3) names,
2979 * despite our protestations to the contrary.
2981 qi.u.FSattributeInfo.attributes = 0x4003;
2982 /* The maxCompLength is supposed to be in bytes */
2984 qi.u.FSattributeInfo.attributes |= 0x04;
2986 qi.u.FSattributeInfo.maxCompLength = 255;
2987 smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
2988 qi.u.FSattributeInfo.FSnameLength = sz;
2991 sizeof(qi.u.FSattributeInfo.attributes) +
2992 sizeof(qi.u.FSattributeInfo.maxCompLength) +
2993 sizeof(qi.u.FSattributeInfo.FSnameLength) +
2998 case SMB_INFO_UNIX: /* CIFS Unix Info */
2999 case SMB_INFO_MACOS: /* Mac FS Info */
3001 return CM_ERROR_BADOP;
3004 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
3006 /* copy out return data, and set corresponding sizes */
3007 outp->totalParms = 0;
3008 outp->totalData = responseSize;
3009 memcpy(outp->datap, &qi, responseSize);
3011 /* send and free the packets */
3012 smb_SendTran2Packet(vcp, outp, op);
3013 smb_FreeTran2Packet(outp);
3018 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3020 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
3021 return CM_ERROR_BADOP;
3024 struct smb_ShortNameRock {
3025 clientchar_t *maskp;
3027 clientchar_t *shortName;
3028 size_t shortNameLen;
3031 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
3034 struct smb_ShortNameRock *rockp;
3035 normchar_t normName[MAX_PATH];
3036 clientchar_t *shortNameEnd;
3040 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t)) == 0) {
3041 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
3042 osi_LogSaveString(smb_logp, dep->name));
3046 /* compare both names and vnodes, though probably just comparing vnodes
3047 * would be safe enough.
3049 if (cm_NormStrCmpI(normName, rockp->maskp) != 0)
3051 if (ntohl(dep->fid.vnode) != rockp->vnode)
3054 /* This is the entry */
3055 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
3056 rockp->shortNameLen = shortNameEnd - rockp->shortName;
3058 return CM_ERROR_STOPNOW;
3061 long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
3062 clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
3064 struct smb_ShortNameRock rock;
3065 clientchar_t *lastNamep;
3068 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
3072 spacep = cm_GetSpace();
3073 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
3075 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3076 caseFold, userp, tidPathp,
3078 cm_FreeSpace(spacep);
3083 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3084 cm_ReleaseSCache(dscp);
3085 cm_ReleaseUser(userp);
3089 return CM_ERROR_PATH_NOT_COVERED;
3091 #endif /* DFS_SUPPORT */
3093 if (!lastNamep) lastNamep = pathp;
3096 thyper.HighPart = 0;
3097 rock.shortName = shortName;
3099 rock.maskp = lastNamep;
3100 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
3102 cm_ReleaseSCache(dscp);
3105 return CM_ERROR_NOSUCHFILE;
3106 if (code == CM_ERROR_STOPNOW) {
3107 *shortNameLenp = rock.shortNameLen;
3113 /* TRANS2_QUERY_PATH_INFORMATION */
3114 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3116 smb_tran2Packet_t *outp;
3119 unsigned short infoLevel;
3120 smb_tran2QPathInfo_t qpi;
3122 unsigned short attributes;
3123 unsigned long extAttributes;
3124 clientchar_t shortName[13];
3128 cm_scache_t *scp, *dscp;
3129 int scp_rw_held = 0;
3132 clientchar_t *pathp;
3133 clientchar_t *tidPathp;
3134 clientchar_t *lastComp;
3139 infoLevel = p->parmsp[0];
3140 if (infoLevel == SMB_INFO_IS_NAME_VALID)
3142 else if (infoLevel == SMB_INFO_STANDARD)
3143 responseSize = sizeof(qpi.u.QPstandardInfo);
3144 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
3145 responseSize = sizeof(qpi.u.QPeaSizeInfo);
3146 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3147 responseSize = sizeof(qpi.u.QPfileBasicInfo);
3148 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3149 responseSize = sizeof(qpi.u.QPfileStandardInfo);
3150 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3151 responseSize = sizeof(qpi.u.QPfileEaInfo);
3152 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3153 responseSize = sizeof(qpi.u.QPfileNameInfo);
3154 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
3155 responseSize = sizeof(qpi.u.QPfileAllInfo);
3156 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
3157 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
3159 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3160 p->opcode, infoLevel);
3161 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3165 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3166 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %S", infoLevel,
3167 osi_LogSaveClientString(smb_logp, pathp));
3169 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3171 if (infoLevel > 0x100)
3172 outp->totalParms = 2;
3174 outp->totalParms = 0;
3175 outp->totalData = responseSize;
3177 /* now, if we're at infoLevel 6, we're only being asked to check
3178 * the syntax, so we just OK things now. In particular, we're *not*
3179 * being asked to verify anything about the state of any parent dirs.
3181 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
3182 smb_SendTran2Packet(vcp, outp, opx);
3183 smb_FreeTran2Packet(outp);
3187 userp = smb_GetTran2User(vcp, p);
3189 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
3190 smb_FreeTran2Packet(outp);
3191 return CM_ERROR_BADSMB;
3194 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3196 cm_ReleaseUser(userp);
3197 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
3198 smb_FreeTran2Packet(outp);
3203 * XXX Strange hack XXX
3205 * As of Patch 7 (13 January 98), we are having the following problem:
3206 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3207 * requests to look up "desktop.ini" in all the subdirectories.
3208 * This can cause zillions of timeouts looking up non-existent cells
3209 * and volumes, especially in the top-level directory.
3211 * We have not found any way to avoid this or work around it except
3212 * to explicitly ignore the requests for mount points that haven't
3213 * yet been evaluated and for directories that haven't yet been
3216 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3217 spacep = cm_GetSpace();
3218 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3219 #ifndef SPECIAL_FOLDERS
3220 /* Make sure that lastComp is not NULL */
3222 if (cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
3223 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3227 userp, tidPathp, &req, &dscp);
3230 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3231 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3233 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3234 code = CM_ERROR_PATH_NOT_COVERED;
3236 code = CM_ERROR_NOSUCHPATH;
3238 #endif /* DFS_SUPPORT */
3239 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3240 code = CM_ERROR_NOSUCHFILE;
3241 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3242 cm_buf_t *bp = buf_Find(dscp, &hzero);
3248 code = CM_ERROR_NOSUCHFILE;
3250 cm_ReleaseSCache(dscp);
3252 cm_FreeSpace(spacep);
3253 cm_ReleaseUser(userp);
3254 smb_SendTran2Error(vcp, p, opx, code);
3255 smb_FreeTran2Packet(outp);
3261 #endif /* SPECIAL_FOLDERS */
3263 cm_FreeSpace(spacep);
3266 /* now do namei and stat, and copy out the info */
3267 code = cm_NameI(cm_data.rootSCachep, pathp,
3268 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3271 cm_ReleaseUser(userp);
3272 smb_SendTran2Error(vcp, p, opx, code);
3273 smb_FreeTran2Packet(outp);
3278 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3279 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3280 cm_ReleaseSCache(scp);
3281 cm_ReleaseUser(userp);
3282 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3283 code = CM_ERROR_PATH_NOT_COVERED;
3285 code = CM_ERROR_NOSUCHPATH;
3286 smb_SendTran2Error(vcp, p, opx, code);
3287 smb_FreeTran2Packet(outp);
3290 #endif /* DFS_SUPPORT */
3292 lock_ObtainWrite(&scp->rw);
3294 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3295 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3299 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3301 lock_ConvertWToR(&scp->rw);
3306 /* now we have the status in the cache entry, and everything is locked.
3307 * Marshall the output data.
3309 /* for info level 108, figure out short name */
3310 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3311 code = cm_GetShortName(pathp, userp, &req,
3312 tidPathp, scp->fid.vnode, shortName,
3318 smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
3319 qpi.u.QPfileAltNameInfo.fileNameLength = len;
3323 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3324 smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3325 qpi.u.QPfileNameInfo.fileNameLength = len;
3329 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3330 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3331 qpi.u.QPstandardInfo.creationDateTime = dosTime;
3332 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3333 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3334 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3335 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3336 attributes = smb_Attributes(scp);
3337 qpi.u.QPstandardInfo.attributes = attributes;
3338 qpi.u.QPstandardInfo.eaSize = 0;
3340 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3341 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3342 qpi.u.QPfileBasicInfo.creationTime = ft;
3343 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3344 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3345 qpi.u.QPfileBasicInfo.changeTime = ft;
3346 extAttributes = smb_ExtAttributes(scp);
3347 qpi.u.QPfileBasicInfo.attributes = extAttributes;
3348 qpi.u.QPfileBasicInfo.reserved = 0;
3350 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3353 lock_ReleaseRead(&scp->rw);
3355 fidp = smb_FindFIDByScache(vcp, scp);
3357 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3358 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3359 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3360 qpi.u.QPfileStandardInfo.directory =
3361 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3362 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3363 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3364 qpi.u.QPfileStandardInfo.reserved = 0;
3367 lock_ObtainMutex(&fidp->mx);
3368 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3369 lock_ReleaseMutex(&fidp->mx);
3370 smb_ReleaseFID(fidp);
3372 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3374 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3375 qpi.u.QPfileEaInfo.eaSize = 0;
3377 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3378 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3379 qpi.u.QPfileAllInfo.creationTime = ft;
3380 qpi.u.QPfileAllInfo.lastAccessTime = ft;
3381 qpi.u.QPfileAllInfo.lastWriteTime = ft;
3382 qpi.u.QPfileAllInfo.changeTime = ft;
3383 extAttributes = smb_ExtAttributes(scp);
3384 qpi.u.QPfileAllInfo.attributes = extAttributes;
3385 qpi.u.QPfileAllInfo.allocationSize = scp->length;
3386 qpi.u.QPfileAllInfo.endOfFile = scp->length;
3387 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3388 qpi.u.QPfileAllInfo.deletePending = 0;
3389 qpi.u.QPfileAllInfo.directory =
3390 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3391 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3392 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3393 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
3394 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
3395 qpi.u.QPfileAllInfo.eaSize = 0;
3396 qpi.u.QPfileAllInfo.accessFlags = 0;
3397 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
3398 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
3399 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3400 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3401 qpi.u.QPfileAllInfo.mode = 0;
3402 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3404 smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3405 qpi.u.QPfileAllInfo.fileNameLength = len;
3408 /* send and free the packets */
3410 switch (scp_rw_held) {
3412 lock_ReleaseRead(&scp->rw);
3415 lock_ReleaseWrite(&scp->rw);
3419 cm_ReleaseSCache(scp);
3420 cm_ReleaseUser(userp);
3422 memcpy(outp->datap, &qpi, responseSize);
3423 smb_SendTran2Packet(vcp, outp, opx);
3425 smb_SendTran2Error(vcp, p, opx, code);
3427 smb_FreeTran2Packet(outp);
3432 /* TRANS2_SET_PATH_INFORMATION */
3433 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3436 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
3437 return CM_ERROR_BADOP;
3440 unsigned short infoLevel;
3441 clientchar_t * pathp;
3442 smb_tran2Packet_t *outp;
3443 smb_tran2QPathInfo_t *spi;
3445 cm_scache_t *scp, *dscp;
3448 clientchar_t *tidPathp;
3449 clientchar_t *lastComp;
3453 infoLevel = p->parmsp[0];
3454 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
3455 if (infoLevel != SMB_INFO_STANDARD &&
3456 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
3457 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
3458 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3459 p->opcode, infoLevel);
3460 smb_SendTran2Error(vcp, p, opx,
3461 infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3465 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3467 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
3468 osi_LogSaveClientString(smb_logp, pathp));
3470 userp = smb_GetTran2User(vcp, p);
3472 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3473 code = CM_ERROR_BADSMB;
3477 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3478 if (code == CM_ERROR_TIDIPC) {
3479 /* Attempt to use a TID allocated for IPC. The client
3480 * is probably looking for DCE RPC end points which we
3481 * don't support OR it could be looking to make a DFS
3484 osi_Log0(smb_logp, "Tran2Open received IPC TID");
3485 cm_ReleaseUser(userp);
3486 return CM_ERROR_NOSUCHPATH;
3490 * XXX Strange hack XXX
3492 * As of Patch 7 (13 January 98), we are having the following problem:
3493 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3494 * requests to look up "desktop.ini" in all the subdirectories.
3495 * This can cause zillions of timeouts looking up non-existent cells
3496 * and volumes, especially in the top-level directory.
3498 * We have not found any way to avoid this or work around it except
3499 * to explicitly ignore the requests for mount points that haven't
3500 * yet been evaluated and for directories that haven't yet been
3503 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3504 spacep = cm_GetSpace();
3505 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3506 #ifndef SPECIAL_FOLDERS
3507 /* Make sure that lastComp is not NULL */
3509 if (cm_ClientStrCmpI(lastComp, _C("\\desktop.ini")) == 0) {
3510 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3514 userp, tidPathp, &req, &dscp);
3517 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3518 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3520 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3521 code = CM_ERROR_PATH_NOT_COVERED;
3523 code = CM_ERROR_NOSUCHPATH;
3525 #endif /* DFS_SUPPORT */
3526 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3527 code = CM_ERROR_NOSUCHFILE;
3528 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3529 cm_buf_t *bp = buf_Find(dscp, &hzero);
3535 code = CM_ERROR_NOSUCHFILE;
3537 cm_ReleaseSCache(dscp);
3539 cm_FreeSpace(spacep);
3540 cm_ReleaseUser(userp);
3541 smb_SendTran2Error(vcp, p, opx, code);
3547 #endif /* SPECIAL_FOLDERS */
3549 cm_FreeSpace(spacep);
3552 /* now do namei and stat, and copy out the info */
3553 code = cm_NameI(cm_data.rootSCachep, pathp,
3554 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3556 cm_ReleaseUser(userp);
3557 smb_SendTran2Error(vcp, p, opx, code);
3561 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3563 outp->totalParms = 2;
3564 outp->totalData = 0;
3566 spi = (smb_tran2QPathInfo_t *)p->datap;
3567 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3570 /* lock the vnode with a callback; we need the current status
3571 * to determine what the new status is, in some cases.
3573 lock_ObtainWrite(&scp->rw);
3574 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3575 CM_SCACHESYNC_GETSTATUS
3576 | CM_SCACHESYNC_NEEDCALLBACK);
3578 lock_ReleaseWrite(&scp->rw);
3581 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3583 /* prepare for setattr call */
3584 attr.mask = CM_ATTRMASK_LENGTH;
3585 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3586 attr.length.HighPart = 0;
3588 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3589 cm_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3590 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3593 if (spi->u.QPstandardInfo.attributes != 0) {
3594 if ((scp->unixModeBits & 0222)
3595 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3596 /* make a writable file read-only */
3597 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3598 attr.unixModeBits = scp->unixModeBits & ~0222;
3600 else if ((scp->unixModeBits & 0222) == 0
3601 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3602 /* make a read-only file writable */
3603 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3604 attr.unixModeBits = scp->unixModeBits | 0222;
3607 lock_ReleaseRead(&scp->rw);
3611 code = cm_SetAttr(scp, &attr, userp, &req);
3615 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3616 /* we don't support EAs */
3617 code = CM_ERROR_EAS_NOT_SUPPORTED;
3621 cm_ReleaseSCache(scp);
3622 cm_ReleaseUser(userp);
3624 smb_SendTran2Packet(vcp, outp, opx);
3626 smb_SendTran2Error(vcp, p, opx, code);
3627 smb_FreeTran2Packet(outp);
3633 /* TRANS2_QUERY_FILE_INFORMATION */
3634 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3636 smb_tran2Packet_t *outp;
3638 unsigned long attributes;
3639 unsigned short infoLevel;
3646 smb_tran2QFileInfo_t qfi;
3654 fidp = smb_FindFID(vcp, fid, 0);
3657 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3661 lock_ObtainMutex(&fidp->mx);
3662 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3663 lock_ReleaseMutex(&fidp->mx);
3664 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3665 smb_CloseFID(vcp, fidp, NULL, 0);
3666 smb_ReleaseFID(fidp);
3669 lock_ReleaseMutex(&fidp->mx);
3671 infoLevel = p->parmsp[1];
3672 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3673 responseSize = sizeof(qfi.u.QFbasicInfo);
3674 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3675 responseSize = sizeof(qfi.u.QFstandardInfo);
3676 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3677 responseSize = sizeof(qfi.u.QFeaInfo);
3678 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3679 responseSize = sizeof(qfi.u.QFfileNameInfo);
3681 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3682 p->opcode, infoLevel);
3683 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3684 smb_ReleaseFID(fidp);
3687 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3689 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3691 if (infoLevel > 0x100)
3692 outp->totalParms = 2;
3694 outp->totalParms = 0;
3695 outp->totalData = responseSize;
3697 userp = smb_GetTran2User(vcp, p);
3699 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3700 code = CM_ERROR_BADSMB;
3704 lock_ObtainMutex(&fidp->mx);
3705 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3707 osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3709 lock_ReleaseMutex(&fidp->mx);
3710 lock_ObtainWrite(&scp->rw);
3711 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3712 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3716 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3718 lock_ConvertWToR(&scp->rw);
3721 /* now we have the status in the cache entry, and everything is locked.
3722 * Marshall the output data.
3724 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3725 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3726 qfi.u.QFbasicInfo.creationTime = ft;
3727 qfi.u.QFbasicInfo.lastAccessTime = ft;
3728 qfi.u.QFbasicInfo.lastWriteTime = ft;
3729 qfi.u.QFbasicInfo.lastChangeTime = ft;
3730 attributes = smb_ExtAttributes(scp);
3731 qfi.u.QFbasicInfo.attributes = attributes;
3733 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3734 qfi.u.QFstandardInfo.allocationSize = scp->length;
3735 qfi.u.QFstandardInfo.endOfFile = scp->length;
3736 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3737 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3738 qfi.u.QFstandardInfo.directory =
3739 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3740 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3741 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3743 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3744 qfi.u.QFeaInfo.eaSize = 0;
3746 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3750 lock_ReleaseRead(&scp->rw);
3751 lock_ObtainMutex(&fidp->mx);
3752 lock_ObtainRead(&scp->rw);
3753 if (fidp->NTopen_wholepathp)
3754 name = fidp->NTopen_wholepathp;
3756 name = _C("\\"); /* probably can't happen */
3757 lock_ReleaseMutex(&fidp->mx);
3759 smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, SMB_STRF_IGNORENUL);
3760 outp->totalData = len + 4; /* this is actually what we want to return */
3761 qfi.u.QFfileNameInfo.fileNameLength = len;
3764 /* send and free the packets */
3767 lock_ReleaseRead(&scp->rw);
3769 lock_ReleaseWrite(&scp->rw);
3770 cm_ReleaseSCache(scp);
3771 cm_ReleaseUser(userp);
3772 smb_ReleaseFID(fidp);
3774 memcpy(outp->datap, &qfi, responseSize);
3775 smb_SendTran2Packet(vcp, outp, opx);
3777 smb_SendTran2Error(vcp, p, opx, code);
3779 smb_FreeTran2Packet(outp);
3785 /* TRANS2_SET_FILE_INFORMATION */
3786 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3791 unsigned short infoLevel;
3792 smb_tran2Packet_t *outp;
3793 cm_user_t *userp = NULL;
3794 cm_scache_t *scp = NULL;
3800 fidp = smb_FindFID(vcp, fid, 0);
3803 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3807 infoLevel = p->parmsp[1];
3808 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3809 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3810 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3811 p->opcode, infoLevel);
3812 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3813 smb_ReleaseFID(fidp);
3817 lock_ObtainMutex(&fidp->mx);
3818 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3819 lock_ReleaseMutex(&fidp->mx);
3820 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3821 smb_CloseFID(vcp, fidp, NULL, 0);
3822 smb_ReleaseFID(fidp);
3826 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
3827 !(fidp->flags & SMB_FID_OPENDELETE)) {
3828 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3829 fidp, fidp->scp, fidp->flags);
3830 lock_ReleaseMutex(&fidp->mx);
3831 smb_ReleaseFID(fidp);
3832 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3835 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3836 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3837 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3838 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3839 fidp, fidp->scp, fidp->flags);
3840 lock_ReleaseMutex(&fidp->mx);
3841 smb_ReleaseFID(fidp);
3842 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3847 osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3849 lock_ReleaseMutex(&fidp->mx);
3851 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3853 outp->totalParms = 2;
3854 outp->totalData = 0;
3856 userp = smb_GetTran2User(vcp, p);
3858 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3859 code = CM_ERROR_BADSMB;
3863 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3865 unsigned int attribute;
3867 smb_tran2QFileInfo_t *sfi;
3869 sfi = (smb_tran2QFileInfo_t *)p->datap;
3871 /* lock the vnode with a callback; we need the current status
3872 * to determine what the new status is, in some cases.
3874 lock_ObtainWrite(&scp->rw);
3875 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3876 CM_SCACHESYNC_GETSTATUS
3877 | CM_SCACHESYNC_NEEDCALLBACK);
3879 lock_ReleaseWrite(&scp->rw);
3883 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3885 lock_ReleaseWrite(&scp->rw);
3886 lock_ObtainMutex(&fidp->mx);
3887 lock_ObtainRead(&scp->rw);
3889 /* prepare for setattr call */
3892 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3893 /* when called as result of move a b, lastMod is (-1, -1).
3894 * If the check for -1 is not present, timestamp
3895 * of the resulting file will be 1969 (-1)
3897 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3898 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3899 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3900 cm_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3901 fidp->flags |= SMB_FID_MTIMESETDONE;
3904 attribute = sfi->u.QFbasicInfo.attributes;
3905 if (attribute != 0) {
3906 if ((scp->unixModeBits & 0222)
3907 && (attribute & SMB_ATTR_READONLY) != 0) {
3908 /* make a writable file read-only */
3909 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3910 attr.unixModeBits = scp->unixModeBits & ~0222;
3912 else if ((scp->unixModeBits & 0222) == 0
3913 && (attribute & SMB_ATTR_READONLY) == 0) {
3914 /* make a read-only file writable */
3915 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3916 attr.unixModeBits = scp->unixModeBits | 0222;
3919 lock_ReleaseRead(&scp->rw);
3920 lock_ReleaseMutex(&fidp->mx);
3924 code = cm_SetAttr(scp, &attr, userp, &req);
3928 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3929 int delflag = *((char *)(p->datap));
3930 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
3931 delflag, fidp, scp);
3932 if (*((char *)(p->datap))) { /* File is Deleted */
3933 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3936 lock_ObtainMutex(&fidp->mx);
3937 fidp->flags |= SMB_FID_DELONCLOSE;
3938 lock_ReleaseMutex(&fidp->mx);
3940 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
3946 lock_ObtainMutex(&fidp->mx);
3947 fidp->flags &= ~SMB_FID_DELONCLOSE;
3948 lock_ReleaseMutex(&fidp->mx);
3951 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3952 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3953 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3956 attr.mask = CM_ATTRMASK_LENGTH;
3957 attr.length.LowPart = size.LowPart;
3958 attr.length.HighPart = size.HighPart;
3959 code = cm_SetAttr(scp, &attr, userp, &req);
3963 cm_ReleaseSCache(scp);
3964 cm_ReleaseUser(userp);
3965 smb_ReleaseFID(fidp);
3967 smb_SendTran2Packet(vcp, outp, opx);
3969 smb_SendTran2Error(vcp, p, opx, code);
3970 smb_FreeTran2Packet(outp);
3977 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3979 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3980 return CM_ERROR_BADOP;
3985 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3987 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3988 return CM_ERROR_BADOP;
3991 /* TRANS2_FIND_NOTIFY_FIRST */
3993 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3995 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3996 return CM_ERROR_BADOP;
3999 /* TRANS2_FIND_NOTIFY_NEXT */
4001 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4003 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
4004 return CM_ERROR_BADOP;
4007 /* TRANS2_CREATE_DIRECTORY */
4009 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4011 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
4012 return CM_ERROR_BADOP;
4015 /* TRANS2_SESSION_SETUP */
4017 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4019 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
4020 return CM_ERROR_BADOP;
4023 struct smb_v2_referral {
4025 USHORT ReferralFlags;
4028 USHORT DfsPathOffset;
4029 USHORT DfsAlternativePathOffset;
4030 USHORT NetworkAddressOffset;
4033 /* TRANS2_GET_DFS_REFERRAL */
4035 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
4037 /* This is a UNICODE only request (bit15 of Flags2) */
4038 /* The TID must be IPC$ */
4040 /* The documentation for the Flags response field is contradictory */
4042 /* Use Version 1 Referral Element Format */
4043 /* ServerType = 0; indicates the next server should be queried for the file */
4044 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
4045 /* Node = UnicodeString of UNC path of the next share name */
4048 int maxReferralLevel = 0;
4049 clientchar_t requestFileName[1024] = _C("");
4050 clientchar_t referralPath[1024] = _C("");
4051 smb_tran2Packet_t *outp = 0;
4052 cm_user_t *userp = 0;
4053 cm_scache_t *scp = 0;
4054 cm_scache_t *dscp = 0;
4056 CPINFO CodePageInfo;
4057 int i, nbnLen, reqLen, refLen;
4062 maxReferralLevel = p->parmsp[0];
4064 GetCPInfo(CP_ACP, &CodePageInfo);
4065 cm_Utf16ToClientString(&p->parmsp[1], -1, requestFileName, lengthof(requestFileName));
4067 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%S]",
4068 maxReferralLevel, osi_LogSaveClientString(smb_logp, requestFileName));
4070 nbnLen = (int)cm_ClientStrLen(cm_NetbiosNameC);
4071 reqLen = (int)cm_ClientStrLen(requestFileName);
4073 if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
4074 !cm_ClientStrCmpNI(cm_NetbiosNameC, &requestFileName[1], nbnLen) &&
4075 requestFileName[nbnLen+1] == '\\')
4079 if (!cm_ClientStrCmpNI(_C("all"), &requestFileName[nbnLen+2], 3) ||
4080 !cm_ClientStrCmpNI(_C("*."), &requestFileName[nbnLen+2], 2)) {
4082 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4085 userp = smb_GetTran2User(vcp, p);
4087 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
4088 code = CM_ERROR_BADSMB;
4093 * We have a requested path. Check to see if it is something
4096 * But be careful because the name that we might be searching
4097 * for might be a known name with the final character stripped
4100 code = cm_NameI(cm_data.rootSCachep, &requestFileName[nbnLen+2],
4101 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
4102 userp, NULL, &req, &scp);
4104 code == CM_ERROR_ALLDOWN ||
4105 code == CM_ERROR_ALLBUSY ||
4106 code == CM_ERROR_ALLOFFLINE ||
4107 code == CM_ERROR_NOSUCHCELL ||
4108 code == CM_ERROR_NOSUCHVOLUME ||
4109 code == CM_ERROR_NOACCESS) {
4112 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4114 } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
4115 clientchar_t temp[1024];
4116 clientchar_t pathName[1024];
4117 clientchar_t *lastComponent;
4119 * we have a msdfs link somewhere in the path
4120 * we should figure out where in the path the link is.
4123 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%S]", requestFileName);
4125 cm_ClientStrCpy(temp, lengthof(temp), &requestFileName[nbnLen+2]);
4129 cm_ReleaseSCache(dscp);
4133 cm_ReleaseSCache(scp);
4136 smb_StripLastComponent(pathName, &lastComponent, temp);
4138 code = cm_NameI(cm_data.rootSCachep, pathName,
4139 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4140 userp, NULL, &req, &dscp);
4142 code = cm_NameI(dscp, ++lastComponent,
4144 userp, NULL, &req, &scp);
4145 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK)
4148 } while (code == CM_ERROR_PATH_NOT_COVERED);
4150 /* scp should now be the DfsLink we are looking for */
4152 /* figure out how much of the input path was used */
4153 reqLen = (int)(nbnLen+2 + cm_ClientStrLen(pathName) + 1 + cm_ClientStrLen(lastComponent));
4155 cm_FsStringToClientString(&scp->mountPointStringp[strlen("msdfs:")], -1,
4156 referralPath, lengthof(referralPath));
4157 refLen = (int)cm_ClientStrLen(referralPath);
4161 clientchar_t shareName[MAX_PATH + 1];
4162 clientchar_t *p, *q;
4163 /* we may have a sharename that is a volume reference */
4165 for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
4171 if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
4172 code = cm_NameI(cm_data.rootSCachep, _C(""),
4173 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
4174 userp, p, &req, &scp);
4179 cm_ClientStrCpy(referralPath, lengthof(referralPath),
4190 struct smb_v2_referral * v2ref;
4191 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (refLen + 8));
4193 sp = (USHORT *)outp->datap;
4195 sp[idx++] = reqLen; /* path consumed */
4196 sp[idx++] = 1; /* number of referrals */
4197 sp[idx++] = 0x03; /* flags */
4198 #ifdef DFS_VERSION_1
4199 sp[idx++] = 1; /* Version Number */
4200 sp[idx++] = refLen + 4; /* Referral Size */
4201 sp[idx++] = 1; /* Type = SMB Server */
4202 sp[idx++] = 0; /* Do not strip path consumed */
4203 for ( i=0;i<=refLen; i++ )
4204 sp[i+idx] = referralPath[i];
4205 #else /* DFS_VERSION_2 */
4206 sp[idx++] = 2; /* Version Number */
4207 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
4208 idx += (sizeof(struct smb_v2_referral) / 2);
4209 v2ref = (struct smb_v2_referral *) &sp[5];
4210 v2ref->ServerType = 1; /* SMB Server */
4211 v2ref->ReferralFlags = 0x03;
4212 v2ref->Proximity = 0; /* closest */
4213 v2ref->TimeToLive = 3600; /* seconds */
4214 v2ref->DfsPathOffset = idx * 2;
4215 v2ref->DfsAlternativePathOffset = idx * 2;
4216 v2ref->NetworkAddressOffset = 0;
4217 for ( i=0;i<=refLen; i++ )
4218 sp[i+idx] = referralPath[i];
4221 code = CM_ERROR_NOSUCHPATH;
4224 code = CM_ERROR_NOSUCHPATH;
4229 cm_ReleaseSCache(dscp);
4231 cm_ReleaseSCache(scp);
4233 cm_ReleaseUser(userp);
4235 smb_SendTran2Packet(vcp, outp, op);
4237 smb_SendTran2Error(vcp, p, op, code);
4239 smb_FreeTran2Packet(outp);
4242 #else /* DFS_SUPPORT */
4243 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
4244 return CM_ERROR_NOSUCHDEVICE;
4245 #endif /* DFS_SUPPORT */
4248 /* TRANS2_REPORT_DFS_INCONSISTENCY */
4250 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4252 /* This is a UNICODE only request (bit15 of Flags2) */
4254 /* There is nothing we can do about this operation. The client is going to
4255 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
4256 * Unfortunately, there is really nothing we can do about it other then log it
4257 * somewhere. Even then I don't think there is anything for us to do.
4258 * So let's return an error value.
4261 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
4262 return CM_ERROR_BADOP;
4266 smb_ApplyV3DirListPatches(cm_scache_t *dscp, smb_dirListPatch_t **dirPatchespp,
4267 clientchar_t * tidPathp, clientchar_t * relPathp,
4268 int infoLevel, cm_user_t *userp, cm_req_t *reqp)
4272 cm_scache_t *targetScp; /* target if scp is a symlink */
4275 unsigned short attr;
4276 unsigned long lattr;
4277 smb_dirListPatch_t *patchp;
4278 smb_dirListPatch_t *npatchp;
4280 afs_int32 mustFake = 0;
4281 clientchar_t path[AFSPATHMAX];
4283 code = cm_FindACLCache(dscp, userp, &rights);
4285 lock_ObtainWrite(&dscp->rw);
4286 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4287 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4289 cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4290 lock_ReleaseWrite(&dscp->rw);
4291 if (code == CM_ERROR_NOACCESS) {
4299 if (!mustFake) { /* Bulk Stat */
4301 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4303 memset(bsp, 0, sizeof(cm_bulkStat_t));
4305 for (patchp = *dirPatchespp, count=0;
4307 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4308 cm_scache_t *tscp = NULL;
4311 code = cm_GetSCache(&patchp->fid, &tscp, userp, reqp);
4313 if (lock_TryWrite(&tscp->rw)) {
4314 /* we have an entry that we can look at */
4315 #ifdef AFS_FREELANCE_CLIENT
4316 if (dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID && dscp->fid.volume == AFS_FAKE_ROOT_VOL_ID) {
4317 code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
4318 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4320 cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4322 lock_ReleaseWrite(&tscp->rw);
4323 cm_ReleaseSCache(tscp);
4326 #endif /* AFS_FREELANCE_CLIENT */
4327 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4328 /* we have a callback on it. Don't bother
4329 * fetching this stat entry, since we're happy
4330 * with the info we have.
4332 lock_ReleaseWrite(&tscp->rw);
4333 cm_ReleaseSCache(tscp);
4336 lock_ReleaseWrite(&tscp->rw);
4338 cm_ReleaseSCache(tscp);
4342 bsp->fids[i].Volume = patchp->fid.volume;
4343 bsp->fids[i].Vnode = patchp->fid.vnode;
4344 bsp->fids[i].Unique = patchp->fid.unique;
4346 if (bsp->counter == AFSCBMAX) {
4347 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4348 memset(bsp, 0, sizeof(cm_bulkStat_t));
4352 if (bsp->counter > 0)
4353 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4358 for( patchp = *dirPatchespp;
4360 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4361 cm_ClientStrPrintfN(path, lengthof(path),_C("%s\\%S"),
4362 relPathp ? relPathp : _C(""), patchp->dep->name);
4363 reqp->relPathp = path;
4364 reqp->tidPathp = tidPathp;
4366 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4367 reqp->relPathp = reqp->tidPathp = NULL;
4371 lock_ObtainWrite(&scp->rw);
4372 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4373 lock_ReleaseWrite(&scp->rw);
4375 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4376 errors in the client. */
4377 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4378 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4380 /* 1969-12-31 23:59:59 +00 */
4381 ft.dwHighDateTime = 0x19DB200;
4382 ft.dwLowDateTime = 0x5BB78980;
4384 /* copy to Creation Time */
4385 fa->creationTime = ft;
4386 fa->lastAccessTime = ft;
4387 fa->lastWriteTime = ft;
4388 fa->lastChangeTime = ft;
4390 switch (scp->fileType) {
4391 case CM_SCACHETYPE_DIRECTORY:
4392 case CM_SCACHETYPE_MOUNTPOINT:
4393 case CM_SCACHETYPE_INVALID:
4394 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4396 case CM_SCACHETYPE_SYMLINK:
4397 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4398 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4400 fa->extFileAttributes = SMB_ATTR_NORMAL;
4403 /* if we get here we either have a normal file
4404 * or we have a file for which we have never
4405 * received status info. In this case, we can
4406 * check the even/odd value of the entry's vnode.
4407 * odd means it is to be treated as a directory
4408 * and even means it is to be treated as a file.
4410 if (mustFake && (scp->fid.vnode & 0x1))
4411 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4413 fa->extFileAttributes = SMB_ATTR_NORMAL;
4415 /* merge in hidden attribute */
4416 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4417 fa->extFileAttributes |= SMB_ATTR_HIDDEN;
4420 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4422 /* 1969-12-31 23:59:58 +00*/
4423 dosTime = 0xEBBFBF7D;
4425 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4426 fa->lastAccessDateTime = fa->creationDateTime;
4427 fa->lastWriteDateTime = fa->creationDateTime;
4429 /* set the attribute */
4430 switch (scp->fileType) {
4431 case CM_SCACHETYPE_DIRECTORY:
4432 case CM_SCACHETYPE_MOUNTPOINT:
4433 case CM_SCACHETYPE_INVALID:
4434 fa->attributes = SMB_ATTR_DIRECTORY;
4436 case CM_SCACHETYPE_SYMLINK:
4437 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4438 fa->attributes = SMB_ATTR_DIRECTORY;
4440 fa->attributes = SMB_ATTR_NORMAL;
4443 /* if we get here we either have a normal file
4444 * or we have a file for which we have never
4445 * received status info. In this case, we can
4446 * check the even/odd value of the entry's vnode.
4447 * even means it is to be treated as a directory
4448 * and odd means it is to be treated as a file.
4450 if (mustFake && (scp->fid.vnode & 0x1))
4451 fa->attributes = SMB_ATTR_DIRECTORY;
4453 fa->attributes = SMB_ATTR_NORMAL;
4456 /* merge in hidden (dot file) attribute */
4457 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4458 fa->attributes |= SMB_ATTR_HIDDEN;
4462 cm_ReleaseSCache(scp);
4466 /* now watch for a symlink */
4468 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
4469 lock_ReleaseWrite(&scp->rw);
4470 cm_ClientStrPrintfN(path, lengthof(path), _C("%s\\%S"),
4471 relPathp ? relPathp : _C(""), patchp->dep->name);
4472 reqp->relPathp = path;
4473 reqp->tidPathp = tidPathp;
4474 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
4475 reqp->relPathp = reqp->tidPathp = NULL;
4477 /* we have a more accurate file to use (the
4478 * target of the symbolic link). Otherwise,
4479 * we'll just use the symlink anyway.
4481 osi_Log2(smb_logp, "symlink vp %x to vp %x",
4483 cm_ReleaseSCache(scp);
4486 lock_ObtainWrite(&scp->rw);
4489 lock_ConvertWToR(&scp->rw);
4491 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4492 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4495 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4497 fa->creationTime = ft;
4498 fa->lastAccessTime = ft;
4499 fa->lastWriteTime = ft;
4500 fa->lastChangeTime = ft;
4502 /* Use length for both file length and alloc length */
4503 fa->endOfFile = scp->length;
4504 fa->allocationSize = scp->length;
4506 /* Copy attributes */
4507 lattr = smb_ExtAttributes(scp);
4508 if ((code == CM_ERROR_NOSUCHPATH &&
4509 (scp->fileType == CM_SCACHETYPE_SYMLINK &&
4510 cm_TargetPerceivedAsDirectory(scp->mountPointStringp))) ||
4511 code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4512 if (lattr == SMB_ATTR_NORMAL)
4513 lattr = SMB_ATTR_DIRECTORY;
4515 lattr |= SMB_ATTR_DIRECTORY;
4517 /* merge in hidden (dot file) attribute */
4518 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4519 if (lattr == SMB_ATTR_NORMAL)
4520 lattr = SMB_ATTR_HIDDEN;
4522 lattr |= SMB_ATTR_HIDDEN;
4525 fa->extFileAttributes = lattr;
4527 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4530 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4532 fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
4533 fa->lastAccessDateTime = fa->creationDateTime;
4534 fa->lastWriteDateTime = fa->creationDateTime;
4536 /* copy out file length and alloc length,
4537 * using the same for both
4539 fa->dataSize = scp->length.LowPart;
4540 fa->allocationSize = scp->length.LowPart;
4542 /* finally copy out attributes as short */
4543 attr = smb_Attributes(scp);
4544 /* merge in hidden (dot file) attribute */
4545 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4546 if (lattr == SMB_ATTR_NORMAL)
4547 lattr = SMB_ATTR_HIDDEN;
4549 lattr |= SMB_ATTR_HIDDEN;
4551 fa->attributes = attr;
4554 lock_ReleaseRead(&scp->rw);
4555 cm_ReleaseSCache(scp);
4558 /* now free the patches */
4559 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4560 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4564 /* and mark the list as empty */
4565 *dirPatchespp = NULL;
4571 /* smb_ReceiveTran2SearchDir implements both
4572 * Tran2_Find_First and Tran2_Find_Next
4574 #define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
4575 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
4576 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
4577 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
4578 #define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
4580 /* this is an optimized handler for T2SearchDir that handles the case
4581 where there are no wildcards in the search path. I.e. an
4582 application is using FindFirst(Ex) to get information about a
4583 single file or directory. It will attempt to do a single lookup.
4584 If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4585 the usual mechanism.
4587 This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4589 TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
4591 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4595 long code = 0, code2 = 0;
4596 clientchar_t *pathp = 0;
4598 smb_dirListPatch_t *dirListPatchesp;
4599 smb_dirListPatch_t *curPatchp;
4600 size_t orbytes; /* # of bytes in this output record */
4601 size_t ohbytes; /* # of bytes, except file name */
4602 size_t onbytes; /* # of bytes in name, incl. term. null */
4603 cm_scache_t *scp = NULL;
4604 cm_scache_t *targetscp = NULL;
4605 cm_user_t *userp = NULL;
4606 char *op; /* output data ptr */
4607 char *origOp; /* original value of op */
4608 cm_space_t *spacep; /* for pathname buffer */
4609 unsigned long maxReturnData; /* max # of return data */
4610 long maxReturnParms; /* max # of return parms */
4611 long bytesInBuffer; /* # data bytes in the output buffer */
4612 clientchar_t *maskp; /* mask part of path */
4616 smb_tran2Packet_t *outp; /* response packet */
4617 clientchar_t *tidPathp = 0;
4619 clientchar_t shortName[13]; /* 8.3 name if needed */
4621 clientchar_t *shortNameEnd;
4622 cm_dirEntry_t * dep = NULL;
4625 void * attrp = NULL;
4626 smb_tran2Find_t * fp;
4631 osi_assertx(p->opcode == 1, "invalid opcode");
4633 /* find first; obtain basic parameters from request */
4635 /* note that since we are going to failover to regular
4636 * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4637 * modify any of the input parameters here. */
4638 attribute = p->parmsp[0];
4639 maxCount = p->parmsp[1];
4640 infoLevel = p->parmsp[3];
4641 searchFlags = p->parmsp[2];
4642 pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4644 maskp = cm_ClientStrRChr(pathp, '\\');
4648 maskp++; /* skip over backslash */
4649 /* track if this is likely to match a lot of entries */
4651 osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%S], mask[%S]",
4652 osi_LogSaveClientString(smb_logp, pathp),
4653 osi_LogSaveClientString(smb_logp, maskp));
4655 switch ( infoLevel ) {
4656 case SMB_INFO_STANDARD:
4658 ohbytes = sizeof(fp->u.FstandardInfo);
4661 case SMB_INFO_QUERY_EA_SIZE:
4662 ohbytes = sizeof(fp->u.FeaSizeInfo);
4663 s = "InfoQueryEaSize";
4666 case SMB_INFO_QUERY_EAS_FROM_LIST:
4667 ohbytes = sizeof(fp->u.FeasFromListInfo);
4668 s = "InfoQueryEasFromList";
4671 case SMB_FIND_FILE_DIRECTORY_INFO:
4672 s = "FindFileDirectoryInfo";
4673 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4676 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4677 s = "FindFileFullDirectoryInfo";
4678 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4681 case SMB_FIND_FILE_NAMES_INFO:
4682 s = "FindFileNamesInfo";
4683 ohbytes = sizeof(fp->u.FfileNamesInfo);
4686 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4687 s = "FindFileBothDirectoryInfo";
4688 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4692 s = "unknownInfoLevel";
4696 osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
4699 "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4700 attribute, infoLevel, maxCount, searchFlags);
4703 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4704 return CM_ERROR_INVAL;
4707 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4708 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4710 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4713 dirListPatchesp = NULL;
4715 maxReturnData = p->maxReturnData;
4716 maxReturnParms = 10; /* return params for findfirst, which
4717 is the only one we handle.*/
4719 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4722 osi_Log2(smb_logp, "T2SDSingle search dir count %d [%S]",
4723 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4725 /* bail out if request looks bad */
4727 smb_FreeTran2Packet(outp);
4728 return CM_ERROR_BADSMB;
4731 userp = smb_GetTran2User(vcp, p);
4733 osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
4734 smb_FreeTran2Packet(outp);
4735 return CM_ERROR_BADSMB;
4738 /* try to get the vnode for the path name next */
4739 spacep = cm_GetSpace();
4740 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4741 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4743 cm_ReleaseUser(userp);
4744 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4745 smb_FreeTran2Packet(outp);
4749 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4750 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4751 userp, tidPathp, &req, &scp);
4752 cm_FreeSpace(spacep);
4755 cm_ReleaseUser(userp);
4756 smb_SendTran2Error(vcp, p, opx, code);
4757 smb_FreeTran2Packet(outp);
4761 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4762 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4763 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
4764 cm_ReleaseSCache(scp);
4765 cm_ReleaseUser(userp);
4766 if ( WANTS_DFS_PATHNAMES(p) || pnc )
4767 code = CM_ERROR_PATH_NOT_COVERED;
4769 code = CM_ERROR_NOSUCHPATH;
4770 smb_SendTran2Error(vcp, p, opx, code);
4771 smb_FreeTran2Packet(outp);
4774 #endif /* DFS_SUPPORT */
4775 osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
4777 /* now do a single case sensitive lookup for the file in question */
4778 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
4780 /* if a case sensitive match failed, we try a case insensitive one
4782 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
4783 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
4786 if (code == 0 && targetscp->fid.vnode == 0) {
4787 cm_ReleaseSCache(targetscp);
4788 code = CM_ERROR_NOSUCHFILE;
4792 /* if we can't find the directory entry, this block will
4793 return CM_ERROR_NOSUCHFILE, which we will pass on to
4794 smb_ReceiveTran2SearchDir(). */
4795 cm_ReleaseSCache(scp);
4796 cm_ReleaseUser(userp);
4797 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4798 smb_SendTran2Error(vcp, p, opx, code);
4801 smb_FreeTran2Packet(outp);
4805 /* now that we have the target in sight, we proceed with filling
4806 up the return data. */
4808 op = origOp = outp->datap;
4811 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4812 /* skip over resume key */
4816 fp = (smb_tran2Find_t *) op;
4818 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4819 && targetscp->fid.vnode != 0
4820 && !cm_Is8Dot3(maskp)) {
4823 dfid.vnode = htonl(targetscp->fid.vnode);
4824 dfid.unique = htonl(targetscp->fid.unique);
4826 cm_Gen8Dot3NameIntW(maskp, &dfid, shortName, &shortNameEnd);
4832 osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %S (%S)",
4833 htonl(targetscp->fid.vnode),
4834 htonl(targetscp->fid.unique),
4835 osi_LogSaveClientString(smb_logp, pathp),
4836 (NeedShortName)? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
4838 /* Eliminate entries that don't match requested attributes */
4839 if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
4840 smb_IsDotFile(maskp)) {
4842 code = CM_ERROR_NOSUCHFILE;
4843 osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
4848 if (!(attribute & SMB_ATTR_DIRECTORY) &&
4849 (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
4850 targetscp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4851 targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
4852 targetscp->fileType == CM_SCACHETYPE_INVALID)) {
4854 code = CM_ERROR_NOSUCHFILE;
4855 osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
4860 /* add header to name & term. null */
4862 smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
4863 orbytes = ohbytes + onbytes;
4865 /* now, we round up the record to a 4 byte alignment, and we make
4866 * sure that we have enough room here for even the aligned version
4867 * (so we don't have to worry about an * overflow when we pad
4868 * things out below). That's the reason for the alignment
4871 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4872 align = (4 - (orbytes & 3)) & 3;
4876 if (orbytes + align > maxReturnData) {
4878 /* even though this request is unlikely to succeed with a
4879 failover, we do it anyway. */
4880 code = CM_ERROR_NOSUCHFILE;
4881 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4886 /* this is one of the entries to use: it is not deleted and it
4887 * matches the star pattern we're looking for. Put out the name,
4888 * preceded by its length.
4890 /* First zero everything else */
4891 memset(origOp, 0, orbytes);
4894 smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
4896 switch (infoLevel) {
4897 case SMB_INFO_STANDARD:
4898 fp->u.FstandardInfo.fileNameLength = onbytes;
4899 attrp = &fp->u.FstandardInfo.fileAttrs;
4902 case SMB_INFO_QUERY_EA_SIZE:
4903 fp->u.FeaSizeInfo.fileNameLength = onbytes;
4904 attrp = &fp->u.FeaSizeInfo.fileAttrs;
4905 fp->u.FeaSizeInfo.eaSize = 0;
4908 case SMB_INFO_QUERY_EAS_FROM_LIST:
4909 fp->u.FeasFromListInfo.fileNameLength = onbytes;
4910 attrp = &fp->u.FeasFromListInfo.fileAttrs;
4911 fp->u.FeasFromListInfo.eaSize = 0;
4914 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4915 if (NeedShortName) {
4919 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
4920 fp->u.FfileBothDirectoryInfo.shortName,
4921 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
4923 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
4925 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
4926 fp->u.FfileBothDirectoryInfo.reserved = 0;
4928 strcpy(fp->u.FfileBothDirectoryInfo.shortName,
4930 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
4935 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4936 fp->u.FfileFullDirectoryInfo.eaSize = 0;
4939 case SMB_FIND_FILE_DIRECTORY_INFO:
4940 fp->u.FfileDirectoryInfo.nextEntryOffset = 0;
4941 fp->u.FfileDirectoryInfo.fileIndex = 0;
4942 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
4943 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
4946 case SMB_FIND_FILE_NAMES_INFO:
4947 fp->u.FfileNamesInfo.nextEntryOffset = 0;
4948 fp->u.FfileNamesInfo.fileIndex = 0;
4949 fp->u.FfileNamesInfo.fileNameLength = onbytes;
4953 /* we shouldn't hit this case */
4954 osi_assertx(FALSE, "Unknown query type");
4957 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4958 osi_assert(attrp != NULL);
4960 curPatchp = malloc(sizeof(*curPatchp));
4961 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4963 curPatchp->dptr = attrp;
4965 if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
4966 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4968 curPatchp->flags = 0;
4971 cm_SetFid(&curPatchp->fid, targetscp->fid.cell, targetscp->fid.volume, targetscp->fid.vnode, targetscp->fid.unique);
4975 int namelen = cm_ClientStringToFsString(maskp, -1, NULL, 0);
4976 dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+namelen);
4977 cm_ClientStringToFsString(maskp, -1, dep->name, namelen);
4979 dep->fid.vnode = targetscp->fid.vnode;
4980 dep->fid.unique = targetscp->fid.unique;
4981 curPatchp->dep = dep;
4984 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4985 /* put out resume key */
4986 *((u_long *)origOp) = 0;
4989 /* Adjust byte ptr and count */
4990 origOp += orbytes; /* skip entire record */
4991 bytesInBuffer += orbytes;
4993 /* and pad the record out */
4994 while (--align >= 0) {
4999 /* apply the patches */
5000 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->wdata, infoLevel, userp, &req);
5002 outp->parmsp[0] = 0;
5003 outp->parmsp[1] = 1; /* number of names returned */
5004 outp->parmsp[2] = 1; /* end of search */
5005 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5006 outp->parmsp[4] = 0;
5008 outp->totalParms = 10; /* in bytes */
5010 outp->totalData = bytesInBuffer;
5012 osi_Log0(smb_logp, "T2SDSingle done.");
5014 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5016 smb_SendTran2Error(vcp, p, opx, code);
5018 smb_SendTran2Packet(vcp, outp, opx);
5023 smb_FreeTran2Packet(outp);
5027 cm_ReleaseSCache(scp);
5028 cm_ReleaseSCache(targetscp);
5029 cm_ReleaseUser(userp);
5035 /* TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2 */
5036 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
5041 long code = 0, code2 = 0;
5042 clientchar_t *pathp;
5043 cm_dirEntry_t *dep = 0;
5045 smb_dirListPatch_t *dirListPatchesp = 0;
5046 smb_dirListPatch_t *curPatchp = 0;
5049 size_t orbytes; /* # of bytes in this output record */
5050 size_t ohbytes; /* # of bytes, except file name */
5051 size_t onbytes; /* # of bytes in name, incl. term. null */
5052 osi_hyper_t dirLength;
5053 osi_hyper_t bufferOffset;
5054 osi_hyper_t curOffset;
5056 smb_dirSearch_t *dsp;
5060 cm_pageHeader_t *pageHeaderp;
5061 cm_user_t *userp = NULL;
5064 long nextEntryCookie;
5065 int numDirChunks; /* # of 32 byte dir chunks in this entry */
5066 char *op; /* output data ptr */
5067 char *origOp; /* original value of op */
5068 cm_space_t *spacep; /* for pathname buffer */
5069 unsigned long maxReturnData; /* max # of return data */
5070 unsigned long maxReturnParms; /* max # of return parms */
5071 long bytesInBuffer; /* # data bytes in the output buffer */
5073 clientchar_t *maskp; /* mask part of path */
5077 smb_tran2Packet_t *outp; /* response packet */
5078 clientchar_t *tidPathp;
5080 clientchar_t shortName[13]; /* 8.3 name if needed */
5083 clientchar_t *shortNameEnd;
5089 smb_tran2Find_t * fp;
5094 if (p->opcode == 1) {
5095 /* find first; obtain basic parameters from request */
5096 attribute = p->parmsp[0];
5097 maxCount = p->parmsp[1];
5098 infoLevel = p->parmsp[3];
5099 searchFlags = p->parmsp[2];
5100 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
5102 maskp = cm_ClientStrRChr(pathp, '\\');
5106 maskp++; /* skip over backslash */
5108 /* track if this is likely to match a lot of entries */
5109 starPattern = smb_V3IsStarMask(maskp);
5111 #ifndef NOFINDFIRSTOPTIMIZE
5113 /* if this is for a single directory or file, we let the
5114 optimized routine handle it. The only error it
5115 returns is CM_ERROR_NOSUCHFILE. The */
5116 code = smb_T2SearchDirSingle(vcp, p, opx);
5118 /* we only failover if we see a CM_ERROR_NOSUCHFILE */
5119 if (code != CM_ERROR_NOSUCHFILE) {
5121 /* unless we are using the BPlusTree */
5122 if (code == CM_ERROR_BPLUS_NOMATCH)
5123 code = CM_ERROR_NOSUCHFILE;
5124 #endif /* USE_BPLUS */
5128 #endif /* NOFINDFIRSTOPTIMIZE */
5131 dsp = smb_NewDirSearch(1);
5132 dsp->attribute = attribute;
5133 cm_ClientStrCpy(dsp->mask, lengthof(dsp->mask), maskp); /* and save mask */
5136 osi_assertx(p->opcode == 2, "invalid opcode");
5137 /* find next; obtain basic parameters from request or open dir file */
5138 dsp = smb_FindDirSearch(p->parmsp[0]);
5139 maxCount = p->parmsp[1];
5140 infoLevel = p->parmsp[2];
5141 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
5142 searchFlags = p->parmsp[5];
5144 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
5145 p->parmsp[0], nextCookie);
5146 return CM_ERROR_BADFD;
5148 attribute = dsp->attribute;
5151 starPattern = 1; /* assume, since required a Find Next */
5154 switch ( infoLevel ) {
5155 case SMB_INFO_STANDARD:
5157 ohbytes = sizeof(fp->u.FstandardInfo);
5160 case SMB_INFO_QUERY_EA_SIZE:
5161 ohbytes = sizeof(fp->u.FeaSizeInfo);
5162 s = "InfoQueryEaSize";
5165 case SMB_INFO_QUERY_EAS_FROM_LIST:
5166 ohbytes = sizeof(fp->u.FeasFromListInfo);
5167 s = "InfoQueryEasFromList";
5170 case SMB_FIND_FILE_DIRECTORY_INFO:
5171 s = "FindFileDirectoryInfo";
5172 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
5175 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5176 s = "FindFileFullDirectoryInfo";
5177 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
5180 case SMB_FIND_FILE_NAMES_INFO:
5181 s = "FindFileNamesInfo";
5182 ohbytes = sizeof(fp->u.FfileNamesInfo);
5185 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5186 s = "FindFileBothDirectoryInfo";
5187 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
5191 s = "unknownInfoLevel";
5195 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
5198 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
5199 attribute, infoLevel, maxCount, searchFlags);
5201 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
5202 p->opcode, dsp->cookie, nextCookie);
5205 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
5206 smb_ReleaseDirSearch(dsp);
5207 return CM_ERROR_INVAL;
5210 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5211 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
5213 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5216 dirListPatchesp = NULL;
5218 maxReturnData = p->maxReturnData;
5219 if (p->opcode == 1) /* find first */
5220 maxReturnParms = 10; /* bytes */
5222 maxReturnParms = 8; /* bytes */
5224 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
5230 osi_Log2(smb_logp, "T2 receive search dir count %d [%S]",
5231 maxCount, osi_LogSaveClientString(smb_logp, pathp));
5233 /* bail out if request looks bad */
5234 if (p->opcode == 1 && !pathp) {
5235 smb_ReleaseDirSearch(dsp);
5236 smb_FreeTran2Packet(outp);
5237 return CM_ERROR_BADSMB;
5240 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
5241 dsp->cookie, nextCookie, attribute);
5243 userp = smb_GetTran2User(vcp, p);
5245 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
5246 smb_ReleaseDirSearch(dsp);
5247 smb_FreeTran2Packet(outp);
5248 return CM_ERROR_BADSMB;
5251 /* try to get the vnode for the path name next */
5252 lock_ObtainMutex(&dsp->mx);
5255 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5259 spacep = cm_GetSpace();
5260 smb_StripLastComponent(spacep->wdata, NULL, pathp);
5261 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
5263 cm_ReleaseUser(userp);
5264 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
5265 smb_FreeTran2Packet(outp);
5266 lock_ReleaseMutex(&dsp->mx);
5267 smb_DeleteDirSearch(dsp);
5268 smb_ReleaseDirSearch(dsp);
5272 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
5273 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
5275 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
5276 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5277 userp, tidPathp, &req, &scp);
5278 cm_FreeSpace(spacep);
5281 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
5282 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5283 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
5284 cm_ReleaseSCache(scp);
5285 cm_ReleaseUser(userp);
5286 if ( WANTS_DFS_PATHNAMES(p) || pnc )
5287 code = CM_ERROR_PATH_NOT_COVERED;
5289 code = CM_ERROR_NOSUCHPATH;
5290 smb_SendTran2Error(vcp, p, opx, code);
5291 smb_FreeTran2Packet(outp);
5292 lock_ReleaseMutex(&dsp->mx);
5293 smb_DeleteDirSearch(dsp);
5294 smb_ReleaseDirSearch(dsp);
5297 #endif /* DFS_SUPPORT */
5299 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5300 /* we need one hold for the entry we just stored into,
5301 * and one for our own processing. When we're done
5302 * with this function, we'll drop the one for our own
5303 * processing. We held it once from the namei call,
5304 * and so we do another hold now.
5307 dsp->flags |= SMB_DIRSEARCH_BULKST;
5310 lock_ReleaseMutex(&dsp->mx);
5312 cm_ReleaseUser(userp);
5313 smb_FreeTran2Packet(outp);
5314 smb_DeleteDirSearch(dsp);
5315 smb_ReleaseDirSearch(dsp);
5319 /* get the directory size */
5320 lock_ObtainWrite(&scp->rw);
5321 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5322 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5324 lock_ReleaseWrite(&scp->rw);
5325 cm_ReleaseSCache(scp);
5326 cm_ReleaseUser(userp);
5327 smb_FreeTran2Packet(outp);
5328 smb_DeleteDirSearch(dsp);
5329 smb_ReleaseDirSearch(dsp);
5333 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5336 dirLength = scp->length;
5338 bufferOffset.LowPart = bufferOffset.HighPart = 0;
5339 curOffset.HighPart = 0;
5340 curOffset.LowPart = nextCookie;
5341 origOp = outp->datap;
5348 normchar_t normName[MAX_PATH]; /* Normalized name */
5349 clientchar_t cfileName[MAX_PATH]; /* Non-normalized name */
5352 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5353 /* skip over resume key */
5356 fp = (smb_tran2Find_t *) op;
5358 /* make sure that curOffset.LowPart doesn't point to the first
5359 * 32 bytes in the 2nd through last dir page, and that it doesn't
5360 * point at the first 13 32-byte chunks in the first dir page,
5361 * since those are dir and page headers, and don't contain useful
5364 temp = curOffset.LowPart & (2048-1);
5365 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5366 /* we're in the first page */
5367 if (temp < 13*32) temp = 13*32;
5370 /* we're in a later dir page */
5371 if (temp < 32) temp = 32;
5374 /* make sure the low order 5 bits are zero */
5377 /* now put temp bits back ito curOffset.LowPart */
5378 curOffset.LowPart &= ~(2048-1);
5379 curOffset.LowPart |= temp;
5381 /* check if we've passed the dir's EOF */
5382 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
5383 osi_Log0(smb_logp, "T2 search dir passed eof");
5388 /* check if we've returned all the names that will fit in the
5389 * response packet; we check return count as well as the number
5390 * of bytes requested. We check the # of bytes after we find
5391 * the dir entry, since we'll need to check its size.
5393 if (returnedNames >= maxCount) {
5394 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
5395 returnedNames, maxCount);
5399 /* when we have obtained as many entries as can be processed in
5400 * a single Bulk Status call to the file server, apply the dir listing
5403 if (returnedNames > 0 && returnedNames % AFSCBMAX == 0) {
5404 lock_ReleaseWrite(&scp->rw);
5405 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5406 dsp->relPath, infoLevel, userp, &req);
5407 lock_ObtainWrite(&scp->rw);
5409 /* Then check to see if we have time left to process more entries */
5410 if (GetTickCount() - req.startTime > (RDRtimeout - 15) * 1000) {
5411 osi_Log0(smb_logp, "T2 search dir RDRtimeout exceeded");
5415 /* see if we can use the bufferp we have now; compute in which
5416 * page the current offset would be, and check whether that's
5417 * the offset of the buffer we have. If not, get the buffer.
5419 thyper.HighPart = curOffset.HighPart;
5420 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5421 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5424 buf_Release(bufferp);
5427 lock_ReleaseWrite(&scp->rw);
5428 code = buf_Get(scp, &thyper, &req, &bufferp);
5429 lock_ObtainWrite(&scp->rw);
5431 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
5435 bufferOffset = thyper;
5437 /* now get the data in the cache */
5439 code = cm_SyncOp(scp, bufferp, userp, &req,
5441 CM_SCACHESYNC_NEEDCALLBACK
5442 | CM_SCACHESYNC_READ);
5444 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5448 if (cm_HaveBuffer(scp, bufferp, 0)) {
5449 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5450 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5454 /* otherwise, load the buffer and try again */
5455 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5457 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5459 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5460 scp, bufferp, code);
5465 buf_Release(bufferp);
5469 } /* if (wrong buffer) ... */
5471 /* now we have the buffer containing the entry we're interested
5472 * in; copy it out if it represents a non-deleted entry.
5474 entryInDir = curOffset.LowPart & (2048-1);
5475 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5477 /* page header will help tell us which entries are free. Page
5478 * header can change more often than once per buffer, since
5479 * AFS 3 dir page size may be less than (but not more than)
5480 * a buffer package buffer.
5482 /* only look intra-buffer */
5483 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5484 temp &= ~(2048 - 1); /* turn off intra-page bits */
5485 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5487 /* now determine which entry we're looking at in the page.
5488 * If it is free (there's a free bitmap at the start of the
5489 * dir), we should skip these 32 bytes.
5491 slotInPage = (entryInDir & 0x7e0) >> 5;
5492 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5493 (1 << (slotInPage & 0x7)))) {
5494 /* this entry is free */
5495 numDirChunks = 1; /* only skip this guy */
5499 tp = bufferp->datap + entryInBuffer;
5500 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5502 /* while we're here, compute the next entry's location, too,
5503 * since we'll need it when writing out the cookie into the dir
5506 * XXXX Probably should do more sanity checking.
5508 numDirChunks = cm_NameEntries(dep->name, &onbytes);
5510 /* compute offset of cookie representing next entry */
5511 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5513 if (dep->fid.vnode == 0)
5514 goto nextEntry; /* This entry is not in use */
5516 if (cm_FsStringToClientString(dep->name, -1, cfileName, lengthof(cfileName)) == 0 ||
5517 cm_ClientStringToNormString(cfileName, -1, normName, lengthof(normName)) == 0) {
5519 osi_Log1(smb_logp, "Skipping entry [%s]. Can't convert or normalize FS String",
5520 osi_LogSaveString(smb_logp, dep->name));
5524 /* Need 8.3 name? */
5526 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
5527 !cm_Is8Dot3(cfileName)) {
5528 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5532 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %S (%S)",
5533 dep->fid.vnode, dep->fid.unique,
5534 osi_LogSaveClientString(smb_logp, cfileName),
5535 NeedShortName ? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
5537 /* When matching, we are using doing a case fold if we have a wildcard mask.
5538 * If we get a non-wildcard match, it's a lookup for a specific file.
5540 if (cm_MatchMask(normName, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5541 (NeedShortName && cm_MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))
5543 /* Eliminate entries that don't match requested attributes */
5544 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5545 smb_IsDotFile(cfileName)) {
5546 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5547 goto nextEntry; /* no hidden files */
5550 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5552 /* We have already done the cm_TryBulkStat above */
5553 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume,
5554 ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5555 fileType = cm_FindFileType(&fid);
5556 /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5557 * "has filetype %d", dep->name, fileType);
5559 if ( fileType == CM_SCACHETYPE_DIRECTORY ||
5560 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5561 fileType == CM_SCACHETYPE_DFSLINK ||
5562 fileType == CM_SCACHETYPE_INVALID)
5563 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5567 /* finally check if this name will fit */
5569 smb_UnparseString(opx, NULL, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5570 orbytes = ohbytes + onbytes;
5572 /* now, we round up the record to a 4 byte alignment,
5573 * and we make sure that we have enough room here for
5574 * even the aligned version (so we don't have to worry
5575 * about an overflow when we pad things out below).
5576 * That's the reason for the alignment arithmetic below.
5578 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5579 align = (4 - (orbytes & 3)) & 3;
5583 if (orbytes + bytesInBuffer + align > maxReturnData) {
5584 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5589 /* this is one of the entries to use: it is not deleted
5590 * and it matches the star pattern we're looking for.
5591 * Put out the name, preceded by its length.
5593 /* First zero everything else */
5594 memset(origOp, 0, orbytes);
5597 smb_UnparseString(opx, origOp + ohbytes, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5599 switch (infoLevel) {
5600 case SMB_INFO_STANDARD:
5601 fp->u.FstandardInfo.fileNameLength = onbytes;
5602 attrp = &fp->u.FstandardInfo.fileAttrs;
5605 case SMB_INFO_QUERY_EA_SIZE:
5606 fp->u.FeaSizeInfo.fileNameLength = onbytes;
5607 attrp = &fp->u.FeaSizeInfo.fileAttrs;
5608 fp->u.FeaSizeInfo.eaSize = 0;
5611 case SMB_INFO_QUERY_EAS_FROM_LIST:
5612 fp->u.FeasFromListInfo.fileNameLength = onbytes;
5613 attrp = &fp->u.FeasFromListInfo.fileAttrs;
5614 fp->u.FeasFromListInfo.eaSize = 0;
5617 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5618 if (NeedShortName) {
5622 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
5623 fp->u.FfileBothDirectoryInfo.shortName,
5624 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
5626 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
5628 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5629 fp->u.FfileBothDirectoryInfo.reserved = 0;
5631 cm_ClientStrCpy(fp->u.FfileBothDirectoryInfo.shortName,
5632 lengthof(fp->u.FfileBothDirectoryInfo.shortName),
5634 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
5639 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5640 fp->u.FfileFullDirectoryInfo.eaSize = 0;
5643 case SMB_FIND_FILE_DIRECTORY_INFO:
5644 fp->u.FfileDirectoryInfo.nextEntryOffset = orbytes + align;
5645 fp->u.FfileDirectoryInfo.fileIndex = nextEntryCookie;
5646 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5647 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5650 case SMB_FIND_FILE_NAMES_INFO:
5651 fp->u.FfileNamesInfo.nextEntryOffset = orbytes + align;
5652 fp->u.FfileNamesInfo.fileIndex = nextEntryCookie;
5653 fp->u.FfileNamesInfo.fileNameLength = onbytes;
5658 /* we shouldn't hit this case */
5659 osi_assertx(FALSE, "Unknown query type");
5662 /* now, adjust the # of entries copied */
5665 /* now we emit the attribute. This is tricky, since
5666 * we need to really stat the file to find out what
5667 * type of entry we've got. Right now, we're copying
5668 * out data from a buffer, while holding the scp
5669 * locked, so it isn't really convenient to stat
5670 * something now. We'll put in a place holder
5671 * now, and make a second pass before returning this
5672 * to get the real attributes. So, we just skip the
5673 * data for now, and adjust it later. We allocate a
5674 * patch record to make it easy to find this point
5675 * later. The replay will happen at a time when it is
5676 * safe to unlock the directory.
5678 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5679 osi_assert(attrp != NULL);
5680 curPatchp = malloc(sizeof(*curPatchp));
5681 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5682 curPatchp->dptr = attrp;
5684 if (smb_hideDotFiles && smb_IsDotFile(cfileName)) {
5685 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5687 curPatchp->flags = 0;
5690 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5693 curPatchp->dep = dep;
5696 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5697 /* put out resume key */
5698 *((u_long *)origOp) = nextEntryCookie;
5700 /* Adjust byte ptr and count */
5701 origOp += orbytes; /* skip entire record */
5702 bytesInBuffer += orbytes;
5704 /* and pad the record out */
5705 while (align-- > 0) {
5709 } /* if we're including this name */
5710 else if (!starPattern &&
5712 cm_MatchMask(normName, maskp, CM_FLAG_CASEFOLD)) {
5713 /* We were looking for exact matches, but here's an inexact one*/
5718 /* and adjust curOffset to be where the new cookie is */
5719 thyper.HighPart = 0;
5720 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5721 curOffset = LargeIntegerAdd(thyper, curOffset);
5722 } /* while copying data for dir listing */
5724 /* If we didn't get a star pattern, we did an exact match during the first pass.
5725 * If there were no exact matches found, we fail over to inexact matches by
5726 * marking the query as a star pattern (matches all case permutations), and
5727 * re-running the query.
5729 if (returnedNames == 0 && !starPattern && foundInexact) {
5730 osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
5735 /* release the mutex */
5736 lock_ReleaseWrite(&scp->rw);
5738 buf_Release(bufferp);
5743 * Finally, process whatever entries we have left.
5745 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5746 dsp->relPath, infoLevel, userp, &req);
5748 /* now put out the final parameters */
5749 if (returnedNames == 0)
5751 if (p->opcode == 1) {
5753 outp->parmsp[0] = (unsigned short) dsp->cookie;
5754 outp->parmsp[1] = returnedNames;
5755 outp->parmsp[2] = eos;
5756 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5757 outp->parmsp[4] = 0;
5758 /* don't need last name to continue
5759 * search, cookie is enough. Normally,
5760 * this is the offset of the file name
5761 * of the last entry returned.
5763 outp->totalParms = 10; /* in bytes */
5767 outp->parmsp[0] = returnedNames;
5768 outp->parmsp[1] = eos;
5769 outp->parmsp[2] = 0; /* EAS error */
5770 outp->parmsp[3] = 0; /* last name, as above */
5771 outp->totalParms = 8; /* in bytes */
5774 /* return # of bytes in the buffer */
5775 outp->totalData = bytesInBuffer;
5777 /* Return error code if unsuccessful on first request */
5778 if (code == 0 && p->opcode == 1 && returnedNames == 0)
5779 code = CM_ERROR_NOSUCHFILE;
5781 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
5782 p->opcode, dsp->cookie, returnedNames, code);
5784 /* if we're supposed to close the search after this request, or if
5785 * we're supposed to close the search if we're done, and we're done,
5786 * or if something went wrong, close the search.
5788 if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
5789 (returnedNames == 0) ||
5790 ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
5792 smb_DeleteDirSearch(dsp);
5795 smb_SendTran2Error(vcp, p, opx, code);
5797 smb_SendTran2Packet(vcp, outp, opx);
5799 smb_FreeTran2Packet(outp);
5800 smb_ReleaseDirSearch(dsp);
5801 cm_ReleaseSCache(scp);
5802 cm_ReleaseUser(userp);
5806 /* SMB_COM_FIND_CLOSE2 */
5807 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5810 smb_dirSearch_t *dsp;
5812 dirHandle = smb_GetSMBParm(inp, 0);
5814 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
5816 dsp = smb_FindDirSearch(dirHandle);
5819 return CM_ERROR_BADFD;
5821 /* otherwise, we have an FD to destroy */
5822 smb_DeleteDirSearch(dsp);
5823 smb_ReleaseDirSearch(dsp);
5825 /* and return results */
5826 smb_SetSMBDataLength(outp, 0);
5832 /* SMB_COM_FIND_NOTIFY_CLOSE */
5833 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5835 smb_SetSMBDataLength(outp, 0);
5839 /* SMB_COM_OPEN_ANDX */
5840 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5842 clientchar_t *pathp;
5847 cm_scache_t *dscp; /* dir we're dealing with */
5848 cm_scache_t *scp; /* file we're creating */
5850 int initialModeBits;
5853 clientchar_t *lastNamep;
5854 unsigned long dosTime;
5860 int parmSlot; /* which parm we're dealing with */
5861 clientchar_t *tidPathp;
5864 BOOL is_rpc = FALSE;
5865 BOOL is_ipc = FALSE;
5871 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
5872 openFun = smb_GetSMBParm(inp, 8); /* open function */
5873 excl = ((openFun & 3) == 0);
5874 trunc = ((openFun & 3) == 2); /* truncate it */
5875 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
5876 openAction = 0; /* tracks what we did */
5878 attributes = smb_GetSMBParm(inp, 5);
5879 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
5881 /* compute initial mode bits based on read-only flag in attributes */
5882 initialModeBits = 0666;
5883 if (attributes & SMB_ATTR_READONLY)
5884 initialModeBits &= ~0222;
5886 pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
5889 return CM_ERROR_BADSMB;
5891 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5893 if (code == CM_ERROR_TIDIPC) {
5896 return CM_ERROR_NOSUCHPATH;
5900 spacep = inp->spacep;
5901 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5905 /* special case magic file name for receiving IOCTL requests
5906 * (since IOCTL calls themselves aren't getting through).
5908 (cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
5910 /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional) */
5911 (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
5913 unsigned short file_type = 0;
5914 unsigned short device_state = 0;
5916 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5918 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
5919 osi_Log1(smb_logp, "OpenAndX Setting up RPC on fid[%d]", fidp->fid);
5921 osi_Log1(smb_logp, "smb_SetupRPCFid failure code [%d]", code);
5922 smb_ReleaseFID(fidp);
5926 smb_SetupIoctlFid(fidp, spacep);
5927 osi_Log1(smb_logp, "OpenAndX Setting up IOCTL on fid[%d]", fidp->fid);
5930 /* set inp->fid so that later read calls in same msg can find fid */
5931 inp->fid = fidp->fid;
5933 /* copy out remainder of the parms */
5935 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5937 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
5938 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
5939 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5940 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
5941 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
5942 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5943 smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++;
5944 smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++;
5946 /* and the final "always present" stuff */
5947 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
5948 /* next write out the "unique" ID */
5949 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
5950 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
5951 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5952 smb_SetSMBDataLength(outp, 0);
5954 /* and clean up fid reference */
5955 smb_ReleaseFID(fidp);
5961 osi_Log0(smb_logp, "NTOpenX rejecting IPC TID");
5962 return CM_ERROR_BADFD;
5966 if (!cm_IsValidClientString(pathp)) {
5968 clientchar_t * hexp;
5970 hexp = cm_GetRawCharsAlloc(pathp, -1);
5971 osi_Log1(smb_logp, "NTOpenX rejecting invalid name. [%S]",
5972 osi_LogSaveClientString(smb_logp, hexp));
5976 osi_Log0(smb_logp, "NTOpenX rejecting invalid name");
5978 return CM_ERROR_BADNTFILENAME;
5981 #ifdef DEBUG_VERBOSE
5983 char *hexp, *asciip;
5984 asciip = (lastNamep ? lastNamep : pathp );
5985 hexp = osi_HexifyString(asciip);
5986 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
5990 userp = smb_GetUserFromVCP(vcp, inp);
5993 code = cm_NameI(cm_data.rootSCachep, pathp,
5994 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5995 userp, tidPathp, &req, &scp);
5998 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5999 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
6000 cm_ReleaseSCache(scp);
6001 cm_ReleaseUser(userp);
6002 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6003 return CM_ERROR_PATH_NOT_COVERED;
6005 return CM_ERROR_NOSUCHPATH;
6007 #endif /* DFS_SUPPORT */
6010 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
6011 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6012 userp, tidPathp, &req, &dscp);
6014 cm_ReleaseUser(userp);
6019 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6020 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
6022 cm_ReleaseSCache(dscp);
6023 cm_ReleaseUser(userp);
6024 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6025 return CM_ERROR_PATH_NOT_COVERED;
6027 return CM_ERROR_NOSUCHPATH;
6029 #endif /* DFS_SUPPORT */
6030 /* otherwise, scp points to the parent directory. Do a lookup,
6031 * and truncate the file if we find it, otherwise we create the
6038 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
6040 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
6041 cm_ReleaseSCache(dscp);
6042 cm_ReleaseUser(userp);
6047 /* if we get here, if code is 0, the file exists and is represented by
6048 * scp. Otherwise, we have to create it. The dir may be represented
6049 * by dscp, or we may have found the file directly. If code is non-zero,
6053 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
6055 if (dscp) cm_ReleaseSCache(dscp);
6056 cm_ReleaseSCache(scp);
6057 cm_ReleaseUser(userp);
6062 /* oops, file shouldn't be there */
6064 cm_ReleaseSCache(dscp);
6065 cm_ReleaseSCache(scp);
6066 cm_ReleaseUser(userp);
6067 return CM_ERROR_EXISTS;
6071 setAttr.mask = CM_ATTRMASK_LENGTH;
6072 setAttr.length.LowPart = 0;
6073 setAttr.length.HighPart = 0;
6074 code = cm_SetAttr(scp, &setAttr, userp, &req);
6075 openAction = 3; /* truncated existing file */
6077 else openAction = 1; /* found existing file */
6079 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
6080 /* don't create if not found */
6081 if (dscp) cm_ReleaseSCache(dscp);
6082 cm_ReleaseUser(userp);
6083 return CM_ERROR_NOSUCHFILE;
6086 osi_assertx(dscp != NULL, "null cm_scache_t");
6087 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %S",
6088 osi_LogSaveClientString(smb_logp, lastNamep));
6089 openAction = 2; /* created file */
6090 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6091 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6092 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6096 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6097 smb_NotifyChange(FILE_ACTION_ADDED,
6098 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6099 dscp, lastNamep, NULL, TRUE);
6100 } else if (!excl && code == CM_ERROR_EXISTS) {
6101 /* not an exclusive create, and someone else tried
6102 * creating it already, then we open it anyway. We
6103 * don't bother retrying after this, since if this next
6104 * fails, that means that the file was deleted after we
6105 * started this call.
6107 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6111 setAttr.mask = CM_ATTRMASK_LENGTH;
6112 setAttr.length.LowPart = 0;
6113 setAttr.length.HighPart = 0;
6114 code = cm_SetAttr(scp, &setAttr, userp, &req);
6116 } /* lookup succeeded */
6120 /* we don't need this any longer */
6122 cm_ReleaseSCache(dscp);
6125 /* something went wrong creating or truncating the file */
6127 cm_ReleaseSCache(scp);
6128 cm_ReleaseUser(userp);
6132 /* make sure we're about to open a file */
6133 if (scp->fileType != CM_SCACHETYPE_FILE) {
6134 cm_ReleaseSCache(scp);
6135 cm_ReleaseUser(userp);
6136 return CM_ERROR_ISDIR;
6139 /* now all we have to do is open the file itself */
6140 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6141 osi_assertx(fidp, "null smb_fid_t");
6144 lock_ObtainMutex(&fidp->mx);
6145 /* save a pointer to the vnode */
6147 lock_ObtainWrite(&scp->rw);
6148 scp->flags |= CM_SCACHEFLAG_SMB_FID;
6149 lock_ReleaseWrite(&scp->rw);
6150 osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
6152 fidp->userp = userp;
6154 /* compute open mode */
6156 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
6157 if (openMode == 1 || openMode == 2)
6158 fidp->flags |= SMB_FID_OPENWRITE;
6160 /* remember if the file was newly created */
6162 fidp->flags |= SMB_FID_CREATED;
6164 lock_ReleaseMutex(&fidp->mx);
6165 smb_ReleaseFID(fidp);
6167 cm_Open(scp, 0, userp);
6169 /* set inp->fid so that later read calls in same msg can find fid */
6170 inp->fid = fidp->fid;
6172 /* copy out remainder of the parms */
6174 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6175 lock_ObtainRead(&scp->rw);
6177 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
6178 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
6179 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
6180 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
6181 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
6182 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
6183 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
6184 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
6185 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
6187 /* and the final "always present" stuff */
6188 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
6189 /* next write out the "unique" ID */
6190 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
6191 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
6192 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6193 lock_ReleaseRead(&scp->rw);
6194 smb_SetSMBDataLength(outp, 0);
6196 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
6198 cm_ReleaseUser(userp);
6199 /* leave scp held since we put it in fidp->scp */
6203 static void smb_GetLockParams(unsigned char LockType,
6205 unsigned int * ppid,
6206 LARGE_INTEGER * pOffset,
6207 LARGE_INTEGER * pLength)
6209 if (LockType & LOCKING_ANDX_LARGE_FILES) {
6211 *ppid = *((USHORT *) *buf);
6212 pOffset->HighPart = *((LONG *)(*buf + 4));
6213 pOffset->LowPart = *((DWORD *)(*buf + 8));
6214 pLength->HighPart = *((LONG *)(*buf + 12));
6215 pLength->LowPart = *((DWORD *)(*buf + 16));
6219 /* Not Large Files */
6220 *ppid = *((USHORT *) *buf);
6221 pOffset->HighPart = 0;
6222 pOffset->LowPart = *((DWORD *)(*buf + 2));
6223 pLength->HighPart = 0;
6224 pLength->LowPart = *((DWORD *)(*buf + 6));
6229 /* SMB_COM_LOCKING_ANDX */
6230 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6237 unsigned char LockType;
6238 unsigned short NumberOfUnlocks, NumberOfLocks;
6242 LARGE_INTEGER LOffset, LLength;
6243 smb_waitingLockRequest_t *wlRequest = NULL;
6244 cm_file_lock_t *lockp;
6252 fid = smb_GetSMBParm(inp, 2);
6253 fid = smb_ChainFID(fid, inp);
6255 fidp = smb_FindFID(vcp, fid, 0);
6257 return CM_ERROR_BADFD;
6259 lock_ObtainMutex(&fidp->mx);
6260 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6261 lock_ReleaseMutex(&fidp->mx);
6262 smb_CloseFID(vcp, fidp, NULL, 0);
6263 smb_ReleaseFID(fidp);
6264 return CM_ERROR_NOSUCHFILE;
6267 if (fidp->flags & SMB_FID_IOCTL) {
6268 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
6269 lock_ReleaseMutex(&fidp->mx);
6270 smb_ReleaseFID(fidp);
6271 return CM_ERROR_BADFD;
6274 osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
6276 lock_ReleaseMutex(&fidp->mx);
6278 /* set inp->fid so that later read calls in same msg can find fid */
6281 userp = smb_GetUserFromVCP(vcp, inp);
6283 lock_ObtainWrite(&scp->rw);
6284 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6285 CM_SCACHESYNC_NEEDCALLBACK
6286 | CM_SCACHESYNC_GETSTATUS
6287 | CM_SCACHESYNC_LOCK);
6289 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
6293 LockType = smb_GetSMBParm(inp, 3) & 0xff;
6294 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
6295 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
6296 NumberOfLocks = smb_GetSMBParm(inp, 7);
6298 if (!(fidp->flags & SMB_FID_OPENWRITE) &&
6299 !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
6300 /* somebody wants exclusive locks on a file that they only
6301 opened for reading. We downgrade this to a shared lock. */
6302 osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
6303 LockType |= LOCKING_ANDX_SHARED_LOCK;
6306 if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
6307 /* AFS does not support atomic changes of lock types from read or write and vice-versa */
6308 osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]");
6309 code = CM_ERROR_BADOP;
6314 op = smb_GetSMBData(inp, NULL);
6316 if (LockType & LOCKING_ANDX_CANCEL_LOCK) {
6317 /* Cancel outstanding lock requests */
6318 smb_waitingLock_t * wl;
6320 for (i=0; i<NumberOfLocks; i++) {
6321 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6323 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6325 lock_ObtainWrite(&smb_globalLock);
6326 for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
6328 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
6329 if (cm_KeyEquals(&wl->key, &key, 0) && LargeIntegerEqualTo(wl->LOffset, LOffset) &&
6330 LargeIntegerEqualTo(wl->LLength, LLength)) {
6331 wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
6332 goto found_lock_request;
6337 lock_ReleaseWrite(&smb_globalLock);
6340 smb_SetSMBDataLength(outp, 0);
6345 for (i=0; i<NumberOfUnlocks; i++) {
6346 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6348 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6350 code = cm_Unlock(scp, LockType, LOffset, LLength, key, 0, userp, &req);
6358 for (i=0; i<NumberOfLocks; i++) {
6359 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6361 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6363 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
6364 userp, &req, &lockp);
6366 if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
6367 (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
6369 code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
6370 userp, &req, &lockp);
6373 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
6374 smb_waitingLock_t * wLock;
6376 /* Put on waiting list */
6377 if(wlRequest == NULL) {
6381 LARGE_INTEGER tOffset, tLength;
6383 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
6385 osi_assertx(wlRequest != NULL, "null wlRequest");
6387 wlRequest->vcp = vcp;
6389 wlRequest->scp = scp;
6390 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
6392 wlRequest->inp = smb_CopyPacket(inp);
6393 wlRequest->outp = smb_CopyPacket(outp);
6394 wlRequest->lockType = LockType;
6395 wlRequest->msTimeout = Timeout;
6396 wlRequest->start_t = osi_Time();
6397 wlRequest->locks = NULL;
6399 /* The waiting lock request needs to have enough
6400 information to undo all the locks in the request.
6401 We do the following to store info about locks that
6402 have already been granted. Sure, we can get most
6403 of the info from the packet, but the packet doesn't
6404 hold the result of cm_Lock call. In practice we
6405 only receive packets with one or two locks, so we
6406 are only wasting a few bytes here and there and
6407 only for a limited period of time until the waiting
6408 lock times out or is freed. */
6410 for(opt = op_locks, j=i; j > 0; j--) {
6411 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
6413 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6415 wLock = malloc(sizeof(smb_waitingLock_t));
6417 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6420 wLock->LOffset = tOffset;
6421 wLock->LLength = tLength;
6422 wLock->lockp = NULL;
6423 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
6424 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6429 wLock = malloc(sizeof(smb_waitingLock_t));
6431 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6434 wLock->LOffset = LOffset;
6435 wLock->LLength = LLength;
6436 wLock->lockp = lockp;
6437 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
6438 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6441 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
6449 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
6456 /* Since something went wrong with the lock number i, we now
6457 have to go ahead and release any locks acquired before the
6458 failure. All locks before lock number i (of which there
6459 are i of them) have either been successful or are waiting.
6460 Either case requires calling cm_Unlock(). */
6462 /* And purge the waiting lock */
6463 if(wlRequest != NULL) {
6464 smb_waitingLock_t * wl;
6465 smb_waitingLock_t * wlNext;
6468 for(wl = wlRequest->locks; wl; wl = wlNext) {
6470 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
6472 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, 0, userp, &req);
6475 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
6477 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
6480 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
6485 smb_ReleaseVC(wlRequest->vcp);
6486 cm_ReleaseSCache(wlRequest->scp);
6487 smb_FreePacket(wlRequest->inp);
6488 smb_FreePacket(wlRequest->outp);
6497 if (wlRequest != NULL) {
6499 lock_ObtainWrite(&smb_globalLock);
6500 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
6502 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
6503 lock_ReleaseWrite(&smb_globalLock);
6505 /* don't send reply immediately */
6506 outp->flags |= SMB_PACKETFLAG_NOSEND;
6509 smb_SetSMBDataLength(outp, 0);
6513 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
6516 lock_ReleaseWrite(&scp->rw);
6517 cm_ReleaseSCache(scp);
6518 cm_ReleaseUser(userp);
6519 smb_ReleaseFID(fidp);
6524 /* SMB_COM_QUERY_INFORMATION2 */
6525 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6531 afs_uint32 searchTime;
6538 fid = smb_GetSMBParm(inp, 0);
6539 fid = smb_ChainFID(fid, inp);
6541 fidp = smb_FindFID(vcp, fid, 0);
6543 return CM_ERROR_BADFD;
6545 lock_ObtainMutex(&fidp->mx);
6546 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6547 lock_ReleaseMutex(&fidp->mx);
6548 smb_CloseFID(vcp, fidp, NULL, 0);
6549 smb_ReleaseFID(fidp);
6550 return CM_ERROR_NOSUCHFILE;
6553 if (fidp->flags & SMB_FID_IOCTL) {
6554 lock_ReleaseMutex(&fidp->mx);
6555 smb_ReleaseFID(fidp);
6556 return CM_ERROR_BADFD;
6559 osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6561 lock_ReleaseMutex(&fidp->mx);
6563 userp = smb_GetUserFromVCP(vcp, inp);
6566 /* otherwise, stat the file */
6567 lock_ObtainWrite(&scp->rw);
6568 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6569 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6573 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6575 lock_ConvertWToR(&scp->rw);
6578 /* decode times. We need a search time, but the response to this
6579 * call provides the date first, not the time, as returned in the
6580 * searchTime variable. So we take the high-order bits first.
6582 cm_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
6583 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
6584 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
6585 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
6586 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
6587 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
6588 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
6590 /* now handle file size and allocation size */
6591 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
6592 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
6593 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
6594 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
6596 /* file attribute */
6597 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
6599 /* and finalize stuff */
6600 smb_SetSMBDataLength(outp, 0);
6605 lock_ReleaseRead(&scp->rw);
6607 lock_ReleaseWrite(&scp->rw);
6608 cm_ReleaseSCache(scp);
6609 cm_ReleaseUser(userp);
6610 smb_ReleaseFID(fidp);
6614 /* SMB_COM_SET_INFORMATION2 */
6615 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6621 afs_uint32 searchTime;
6629 fid = smb_GetSMBParm(inp, 0);
6630 fid = smb_ChainFID(fid, inp);
6632 fidp = smb_FindFID(vcp, fid, 0);
6634 return CM_ERROR_BADFD;
6636 lock_ObtainMutex(&fidp->mx);
6637 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6638 lock_ReleaseMutex(&fidp->mx);
6639 smb_CloseFID(vcp, fidp, NULL, 0);
6640 smb_ReleaseFID(fidp);
6641 return CM_ERROR_NOSUCHFILE;
6644 if (fidp->flags & SMB_FID_IOCTL) {
6645 lock_ReleaseMutex(&fidp->mx);
6646 smb_ReleaseFID(fidp);
6647 return CM_ERROR_BADFD;
6650 osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6652 lock_ReleaseMutex(&fidp->mx);
6654 userp = smb_GetUserFromVCP(vcp, inp);
6656 /* now prepare to call cm_setattr. This message only sets various times,
6657 * and AFS only implements mtime, and we'll set the mtime if that's
6658 * requested. The others we'll ignore.
6660 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
6662 if (searchTime != 0) {
6663 cm_UnixTimeFromSearchTime(&unixTime, searchTime);
6665 if ( unixTime != -1 ) {
6666 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
6667 attrs.clientModTime = unixTime;
6668 code = cm_SetAttr(scp, &attrs, userp, &req);
6670 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
6672 osi_Log1(smb_logp, "**cm_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
6678 cm_ReleaseSCache(scp);
6679 cm_ReleaseUser(userp);
6680 smb_ReleaseFID(fidp);
6684 /* SMB_COM_WRITE_ANDX */
6685 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6688 long count, written = 0, total_written = 0;
6692 smb_t *smbp = (smb_t*) inp;
6697 int inDataBlockCount;
6699 fd = smb_GetSMBParm(inp, 2);
6700 count = smb_GetSMBParm(inp, 10);
6702 offset.HighPart = 0;
6703 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6705 if (*inp->wctp == 14) {
6706 /* we have a request with 64-bit file offsets */
6707 #ifdef AFS_LARGEFILES
6708 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6710 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6712 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
6713 /* we shouldn't have received this op if we didn't specify
6714 largefile support */
6715 return CM_ERROR_BADOP;
6720 op = inp->data + smb_GetSMBParm(inp, 11);
6721 inDataBlockCount = count;
6723 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
6724 fd, offset.HighPart, offset.LowPart, count);
6726 fd = smb_ChainFID(fd, inp);
6727 fidp = smb_FindFID(vcp, fd, 0);
6729 return CM_ERROR_BADFD;
6731 lock_ObtainMutex(&fidp->mx);
6732 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6733 lock_ReleaseMutex(&fidp->mx);
6734 smb_CloseFID(vcp, fidp, NULL, 0);
6735 smb_ReleaseFID(fidp);
6736 return CM_ERROR_NOSUCHFILE;
6739 if (fidp->flags & SMB_FID_IOCTL) {
6740 lock_ReleaseMutex(&fidp->mx);
6741 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
6742 smb_ReleaseFID(fidp);
6746 if (fidp->flags & SMB_FID_RPC) {
6747 lock_ReleaseMutex(&fidp->mx);
6748 code = smb_RPCV3Write(fidp, vcp, inp, outp);
6749 smb_ReleaseFID(fidp);
6754 lock_ReleaseMutex(&fidp->mx);
6755 smb_ReleaseFID(fidp);
6756 return CM_ERROR_BADFDOP;
6761 lock_ReleaseMutex(&fidp->mx);
6763 userp = smb_GetUserFromVCP(vcp, inp);
6765 /* special case: 0 bytes transferred means there is no data
6766 transferred. A slight departure from SMB_COM_WRITE where this
6767 means that we are supposed to truncate the file at this
6772 LARGE_INTEGER LOffset;
6773 LARGE_INTEGER LLength;
6776 key = cm_GenerateKey(vcp->vcID, pid, fd);
6778 LOffset.HighPart = offset.HighPart;
6779 LOffset.LowPart = offset.LowPart;
6780 LLength.HighPart = 0;
6781 LLength.LowPart = count;
6783 lock_ObtainWrite(&scp->rw);
6784 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
6785 lock_ReleaseWrite(&scp->rw);
6792 * Work around bug in NT client
6794 * When copying a file, the NT client should first copy the data,
6795 * then copy the last write time. But sometimes the NT client does
6796 * these in the wrong order, so the data copies would inadvertently
6797 * cause the last write time to be overwritten. We try to detect this,
6798 * and don't set client mod time if we think that would go against the
6801 lock_ObtainMutex(&fidp->mx);
6802 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6803 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6804 scp->clientModTime = time(NULL);
6806 lock_ReleaseMutex(&fidp->mx);
6809 while ( code == 0 && count > 0 ) {
6810 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6811 if (code == 0 && written == 0)
6812 code = CM_ERROR_PARTIALWRITE;
6814 offset = LargeIntegerAdd(offset,
6815 ConvertLongToLargeInteger(written));
6817 total_written += written;
6821 /* slots 0 and 1 are reserved for request chaining and will be
6822 filled in when we return. */
6823 smb_SetSMBParm(outp, 2, total_written);
6824 smb_SetSMBParm(outp, 3, 0); /* reserved */
6825 smb_SetSMBParm(outp, 4, 0); /* reserved */
6826 smb_SetSMBParm(outp, 5, 0); /* reserved */
6827 smb_SetSMBDataLength(outp, 0);
6831 cm_ReleaseSCache(scp);
6832 cm_ReleaseUser(userp);
6833 smb_ReleaseFID(fidp);
6838 /* SMB_COM_READ_ANDX */
6839 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6843 long finalCount = 0;
6847 smb_t *smbp = (smb_t*) inp;
6854 fd = smb_GetSMBParm(inp, 2); /* File ID */
6855 count = smb_GetSMBParm(inp, 5); /* MaxCount */
6856 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6858 if (*inp->wctp == 12) {
6859 /* a request with 64-bit offsets */
6860 #ifdef AFS_LARGEFILES
6861 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
6863 if (LargeIntegerLessThanZero(offset)) {
6864 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
6865 offset.HighPart, offset.LowPart);
6866 return CM_ERROR_BADSMB;
6869 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
6870 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
6871 return CM_ERROR_BADSMB;
6873 offset.HighPart = 0;
6877 offset.HighPart = 0;
6880 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
6881 fd, offset.HighPart, offset.LowPart, count);
6883 fd = smb_ChainFID(fd, inp);
6884 fidp = smb_FindFID(vcp, fd, 0);
6886 return CM_ERROR_BADFD;
6889 lock_ObtainMutex(&fidp->mx);
6891 if (fidp->flags & SMB_FID_IOCTL) {
6892 lock_ReleaseMutex(&fidp->mx);
6894 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
6895 smb_ReleaseFID(fidp);
6899 if (fidp->flags & SMB_FID_RPC) {
6900 lock_ReleaseMutex(&fidp->mx);
6902 code = smb_RPCV3Read(fidp, vcp, inp, outp);
6903 smb_ReleaseFID(fidp);
6907 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6908 lock_ReleaseMutex(&fidp->mx);
6909 smb_CloseFID(vcp, fidp, NULL, 0);
6910 smb_ReleaseFID(fidp);
6911 return CM_ERROR_NOSUCHFILE;
6915 lock_ReleaseMutex(&fidp->mx);
6916 smb_ReleaseFID(fidp);
6917 return CM_ERROR_BADFDOP;
6923 lock_ReleaseMutex(&fidp->mx);
6926 key = cm_GenerateKey(vcp->vcID, pid, fd);
6928 LARGE_INTEGER LOffset, LLength;
6930 LOffset.HighPart = offset.HighPart;
6931 LOffset.LowPart = offset.LowPart;
6932 LLength.HighPart = 0;
6933 LLength.LowPart = count;
6935 lock_ObtainWrite(&scp->rw);
6936 code = cm_LockCheckRead(scp, LOffset, LLength, key);
6937 lock_ReleaseWrite(&scp->rw);
6939 cm_ReleaseSCache(scp);
6942 smb_ReleaseFID(fidp);
6946 /* set inp->fid so that later read calls in same msg can find fid */
6949 userp = smb_GetUserFromVCP(vcp, inp);
6951 /* 0 and 1 are reserved for request chaining, were setup by our caller,
6952 * and will be further filled in after we return.
6954 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
6955 smb_SetSMBParm(outp, 3, 0); /* resvd */
6956 smb_SetSMBParm(outp, 4, 0); /* resvd */
6957 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
6958 /* fill in #6 when we have all the parameters' space reserved */
6959 smb_SetSMBParm(outp, 7, 0); /* resv'd */
6960 smb_SetSMBParm(outp, 8, 0); /* resv'd */
6961 smb_SetSMBParm(outp, 9, 0); /* resv'd */
6962 smb_SetSMBParm(outp, 10, 0); /* resv'd */
6963 smb_SetSMBParm(outp, 11, 0); /* reserved */
6965 /* get op ptr after putting in the parms, since otherwise we don't
6966 * know where the data really is.
6968 op = smb_GetSMBData(outp, NULL);
6970 /* now fill in offset from start of SMB header to first data byte (to op) */
6971 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
6973 /* set the packet data length the count of the # of bytes */
6974 smb_SetSMBDataLength(outp, count);
6976 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6978 /* fix some things up */
6979 smb_SetSMBParm(outp, 5, finalCount);
6980 smb_SetSMBDataLength(outp, finalCount);
6982 cm_ReleaseUser(userp);
6983 smb_ReleaseFID(fidp);
6988 * Values for createDisp, copied from NTDDK.H
6990 #define FILE_SUPERSEDE 0 // (???)
6991 #define FILE_OPEN 1 // (open)
6992 #define FILE_CREATE 2 // (exclusive)
6993 #define FILE_OPEN_IF 3 // (non-exclusive)
6994 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
6995 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
6998 #define REQUEST_OPLOCK 2
6999 #define REQUEST_BATCH_OPLOCK 4
7000 #define OPEN_DIRECTORY 8
7001 #define EXTENDED_RESPONSE_REQUIRED 0x10
7003 /* CreateOptions field. */
7004 #define FILE_DIRECTORY_FILE 0x0001
7005 #define FILE_WRITE_THROUGH 0x0002
7006 #define FILE_SEQUENTIAL_ONLY 0x0004
7007 #define FILE_NON_DIRECTORY_FILE 0x0040
7008 #define FILE_NO_EA_KNOWLEDGE 0x0200
7009 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
7010 #define FILE_RANDOM_ACCESS 0x0800
7011 #define FILE_DELETE_ON_CLOSE 0x1000
7012 #define FILE_OPEN_BY_FILE_ID 0x2000
7013 #define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000
7014 #define FILE_NO_COMPRESSION 0x00008000
7015 #define FILE_RESERVE_OPFILTER 0x00100000
7016 #define FILE_OPEN_REPARSE_POINT 0x00200000
7017 #define FILE_OPEN_NO_RECALL 0x00400000
7018 #define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000
7020 /* SMB_COM_NT_CREATE_ANDX */
7021 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7023 clientchar_t *pathp, *realPathp;
7027 cm_scache_t *dscp; /* parent dir */
7028 cm_scache_t *scp; /* file to create or open */
7029 cm_scache_t *targetScp; /* if scp is a symlink */
7031 clientchar_t *lastNamep;
7032 clientchar_t *treeStartp;
7033 unsigned short nameLength;
7035 unsigned int requestOpLock;
7036 unsigned int requestBatchOpLock;
7037 unsigned int mustBeDir;
7038 unsigned int extendedRespRequired;
7039 unsigned int treeCreate;
7041 unsigned int desiredAccess;
7042 unsigned int extAttributes;
7043 unsigned int createDisp;
7044 unsigned int createOptions;
7045 unsigned int shareAccess;
7046 int initialModeBits;
7047 unsigned short baseFid;
7048 smb_fid_t *baseFidp;
7050 cm_scache_t *baseDirp;
7051 unsigned short openAction;
7056 clientchar_t *tidPathp;
7061 int checkDoneRequired = 0;
7062 cm_lock_data_t *ldp = NULL;
7063 BOOL is_rpc = FALSE;
7064 BOOL is_ipc = FALSE;
7068 /* This code is very long and has a lot of if-then-else clauses
7069 * scp and dscp get reused frequently and we need to ensure that
7070 * we don't lose a reference. Start by ensuring that they are NULL.
7077 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
7078 flags = smb_GetSMBOffsetParm(inp, 3, 1)
7079 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
7080 requestOpLock = flags & REQUEST_OPLOCK;
7081 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7082 mustBeDir = flags & OPEN_DIRECTORY;
7083 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7086 * Why all of a sudden 32-bit FID?
7087 * We will reject all bits higher than 16.
7089 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
7090 return CM_ERROR_INVAL;
7091 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
7092 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
7093 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
7094 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
7095 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
7096 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
7097 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
7098 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
7099 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
7100 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
7101 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
7103 /* mustBeDir is never set; createOptions directory bit seems to be
7106 if (createOptions & FILE_DIRECTORY_FILE)
7108 else if (createOptions & FILE_NON_DIRECTORY_FILE)
7114 * compute initial mode bits based on read-only flag in
7115 * extended attributes
7117 initialModeBits = 0666;
7118 if (extAttributes & SMB_ATTR_READONLY)
7119 initialModeBits &= ~0222;
7121 pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
7122 NULL, SMB_STRF_ANSIPATH);
7124 /* Sometimes path is not null-terminated, so we make a copy. */
7125 realPathp = malloc(nameLength+sizeof(clientchar_t));
7126 memcpy(realPathp, pathp, nameLength+sizeof(clientchar_t));
7127 realPathp[nameLength/sizeof(clientchar_t)] = 0;
7129 spacep = inp->spacep;
7130 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
7132 osi_Log1(smb_logp,"NTCreateX for [%S]",osi_LogSaveClientString(smb_logp,realPathp));
7133 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
7134 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%S]", shareAccess, flags, osi_LogSaveClientString(smb_logp,(lastNamep?lastNamep:_C("null"))));
7138 baseDirp = cm_data.rootSCachep;
7139 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7140 if (code == CM_ERROR_TIDIPC) {
7141 /* Attempt to use a TID allocated for IPC. The client
7142 * is probably looking for DCE RPC end points which we
7143 * don't support OR it could be looking to make a DFS
7146 osi_Log0(smb_logp, "NTCreateX received IPC TID");
7151 osi_Log1(smb_logp, "NTCreateX tidPathp=[%S]", (tidPathp==NULL)?_C("null"): osi_LogSaveClientString(smb_logp,tidPathp));
7155 ((is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)) ||
7157 /* special case magic file name for receiving IOCTL requests
7158 * (since IOCTL calls themselves aren't getting through).
7160 cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0)) {
7162 unsigned short file_type = 0;
7163 unsigned short device_state = 0;
7165 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7168 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
7169 osi_Log1(smb_logp, "NTCreateX Setting up RPC on fid[%d]", fidp->fid);
7171 osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
7172 smb_ReleaseFID(fidp);
7177 smb_SetupIoctlFid(fidp, spacep);
7178 osi_Log1(smb_logp, "NTCreateX Setting up IOCTL on fid[%d]", fidp->fid);
7181 /* set inp->fid so that later read calls in same msg can find fid */
7182 inp->fid = fidp->fid;
7186 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7187 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7188 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
7190 memset(&ft, 0, sizeof(ft));
7191 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7192 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7193 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7194 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7195 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
7196 sz.HighPart = 0x7fff; sz.LowPart = 0;
7197 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
7198 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
7199 smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++; /* filetype */
7200 smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++; /* dev state */
7201 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
7202 smb_SetSMBDataLength(outp, 0);
7204 /* clean up fid reference */
7205 smb_ReleaseFID(fidp);
7212 osi_Log0(smb_logp, "NTCreateX rejecting IPC TID");
7214 return CM_ERROR_BADFD;
7218 if (!cm_IsValidClientString(realPathp)) {
7220 clientchar_t * hexp;
7222 hexp = cm_GetRawCharsAlloc(realPathp, -1);
7223 osi_Log1(smb_logp, "NTCreateX rejecting invalid name. [%S]",
7224 osi_LogSaveClientString(smb_logp, hexp));
7228 osi_Log0(smb_logp, "NTCreateX rejecting invalid name");
7231 return CM_ERROR_BADNTFILENAME;
7234 userp = smb_GetUserFromVCP(vcp, inp);
7236 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
7238 return CM_ERROR_INVAL;
7241 if (baseFidp != 0) {
7242 baseFidp = smb_FindFID(vcp, baseFid, 0);
7244 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
7245 cm_ReleaseUser(userp);
7247 return CM_ERROR_INVAL;
7250 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7252 smb_CloseFID(vcp, baseFidp, NULL, 0);
7253 smb_ReleaseFID(baseFidp);
7254 cm_ReleaseUser(userp);
7255 return CM_ERROR_NOSUCHPATH;
7258 baseDirp = baseFidp->scp;
7262 /* compute open mode */
7264 if (desiredAccess & DELETE)
7265 fidflags |= SMB_FID_OPENDELETE;
7266 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
7267 fidflags |= SMB_FID_OPENREAD_LISTDIR;
7268 if (desiredAccess & AFS_ACCESS_WRITE)
7269 fidflags |= SMB_FID_OPENWRITE;
7270 if (createOptions & FILE_DELETE_ON_CLOSE)
7271 fidflags |= SMB_FID_DELONCLOSE;
7272 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7273 fidflags |= SMB_FID_SEQUENTIAL;
7274 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7275 fidflags |= SMB_FID_RANDOM;
7276 if (createOptions & FILE_OPEN_REPARSE_POINT)
7277 osi_Log0(smb_logp, "NTCreateX Open Reparse Point");
7278 if (smb_IsExecutableFileName(lastNamep))
7279 fidflags |= SMB_FID_EXECUTABLE;
7281 /* and the share mode */
7282 if (shareAccess & FILE_SHARE_READ)
7283 fidflags |= SMB_FID_SHARE_READ;
7284 if (shareAccess & FILE_SHARE_WRITE)
7285 fidflags |= SMB_FID_SHARE_WRITE;
7287 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
7290 /* For an exclusive create, we want to do a case sensitive match for the last component. */
7291 if ( createDisp == FILE_CREATE ||
7292 createDisp == FILE_OVERWRITE ||
7293 createDisp == FILE_OVERWRITE_IF) {
7294 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7295 userp, tidPathp, &req, &dscp);
7298 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7299 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7301 cm_ReleaseSCache(dscp);
7302 cm_ReleaseUser(userp);
7305 smb_ReleaseFID(baseFidp);
7306 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7307 return CM_ERROR_PATH_NOT_COVERED;
7309 return CM_ERROR_NOSUCHPATH;
7311 #endif /* DFS_SUPPORT */
7312 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7314 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7315 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7316 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7317 if (code == 0 && realDirFlag == 1) {
7318 cm_ReleaseSCache(scp);
7319 cm_ReleaseSCache(dscp);
7320 cm_ReleaseUser(userp);
7323 smb_ReleaseFID(baseFidp);
7324 return CM_ERROR_EXISTS;
7328 /* we have both scp and dscp */
7330 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7331 userp, tidPathp, &req, &scp);
7333 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7334 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7335 cm_ReleaseSCache(scp);
7336 cm_ReleaseUser(userp);
7339 smb_ReleaseFID(baseFidp);
7340 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7341 return CM_ERROR_PATH_NOT_COVERED;
7343 return CM_ERROR_NOSUCHPATH;
7345 #endif /* DFS_SUPPORT */
7346 /* we might have scp but not dscp */
7352 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7353 /* look up parent directory */
7354 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
7355 * the immediate parent. We have to work our way up realPathp until we hit something that we
7359 /* we might or might not have scp */
7365 code = cm_NameI(baseDirp, spacep->wdata,
7366 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7367 userp, tidPathp, &req, &dscp);
7370 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7371 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7374 cm_ReleaseSCache(scp);
7375 cm_ReleaseSCache(dscp);
7376 cm_ReleaseUser(userp);
7379 smb_ReleaseFID(baseFidp);
7380 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7381 return CM_ERROR_PATH_NOT_COVERED;
7383 return CM_ERROR_NOSUCHPATH;
7385 #endif /* DFS_SUPPORT */
7388 (tp = cm_ClientStrRChr(spacep->wdata, '\\')) &&
7389 (createDisp == FILE_CREATE) &&
7390 (realDirFlag == 1)) {
7393 treeStartp = realPathp + (tp - spacep->wdata);
7395 if (*tp && !smb_IsLegalFilename(tp)) {
7396 cm_ReleaseUser(userp);
7398 smb_ReleaseFID(baseFidp);
7401 cm_ReleaseSCache(scp);
7402 return CM_ERROR_BADNTFILENAME;
7406 } while (dscp == NULL && code == 0);
7410 /* we might have scp and we might have dscp */
7413 smb_ReleaseFID(baseFidp);
7416 osi_Log0(smb_logp,"NTCreateX parent not found");
7418 cm_ReleaseSCache(scp);
7420 cm_ReleaseSCache(dscp);
7421 cm_ReleaseUser(userp);
7426 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
7427 /* A file exists where we want a directory. */
7429 cm_ReleaseSCache(scp);
7430 cm_ReleaseSCache(dscp);
7431 cm_ReleaseUser(userp);
7433 return CM_ERROR_EXISTS;
7437 lastNamep = realPathp;
7441 if (!smb_IsLegalFilename(lastNamep)) {
7443 cm_ReleaseSCache(scp);
7445 cm_ReleaseSCache(dscp);
7446 cm_ReleaseUser(userp);
7448 return CM_ERROR_BADNTFILENAME;
7451 if (!foundscp && !treeCreate) {
7452 if ( createDisp == FILE_CREATE ||
7453 createDisp == FILE_OVERWRITE ||
7454 createDisp == FILE_OVERWRITE_IF)
7456 code = cm_Lookup(dscp, lastNamep,
7457 CM_FLAG_FOLLOW, userp, &req, &scp);
7459 code = cm_Lookup(dscp, lastNamep,
7460 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7463 if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
7465 cm_ReleaseSCache(dscp);
7466 cm_ReleaseUser(userp);
7471 /* we have scp and dscp */
7473 /* we have scp but not dscp */
7475 smb_ReleaseFID(baseFidp);
7478 /* if we get here, if code is 0, the file exists and is represented by
7479 * scp. Otherwise, we have to create it. The dir may be represented
7480 * by dscp, or we may have found the file directly. If code is non-zero,
7483 if (code == 0 && !treeCreate) {
7484 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7486 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7488 cm_ReleaseSCache(dscp);
7490 cm_ReleaseSCache(scp);
7491 cm_ReleaseUser(userp);
7495 checkDoneRequired = 1;
7497 if (createDisp == FILE_CREATE) {
7498 /* oops, file shouldn't be there */
7499 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7501 cm_ReleaseSCache(dscp);
7503 cm_ReleaseSCache(scp);
7504 cm_ReleaseUser(userp);
7506 return CM_ERROR_EXISTS;
7509 if ( createDisp == FILE_OVERWRITE ||
7510 createDisp == FILE_OVERWRITE_IF) {
7512 setAttr.mask = CM_ATTRMASK_LENGTH;
7513 setAttr.length.LowPart = 0;
7514 setAttr.length.HighPart = 0;
7515 /* now watch for a symlink */
7517 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7519 osi_assertx(dscp != NULL, "null cm_scache_t");
7520 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7522 /* we have a more accurate file to use (the
7523 * target of the symbolic link). Otherwise,
7524 * we'll just use the symlink anyway.
7526 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7528 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7529 cm_ReleaseSCache(scp);
7531 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7533 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7535 cm_ReleaseSCache(dscp);
7537 cm_ReleaseSCache(scp);
7538 cm_ReleaseUser(userp);
7544 code = cm_SetAttr(scp, &setAttr, userp, &req);
7545 openAction = 3; /* truncated existing file */
7548 openAction = 1; /* found existing file */
7550 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7551 /* don't create if not found */
7553 cm_ReleaseSCache(dscp);
7555 cm_ReleaseSCache(scp);
7556 cm_ReleaseUser(userp);
7558 return CM_ERROR_NOSUCHFILE;
7559 } else if (realDirFlag == 0 || realDirFlag == -1) {
7560 osi_assertx(dscp != NULL, "null cm_scache_t");
7561 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %S",
7562 osi_LogSaveClientString(smb_logp, lastNamep));
7563 openAction = 2; /* created file */
7564 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7565 setAttr.clientModTime = time(NULL);
7566 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
7569 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7570 smb_NotifyChange(FILE_ACTION_ADDED,
7571 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7572 dscp, lastNamep, NULL, TRUE);
7573 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7574 /* Not an exclusive create, and someone else tried
7575 * creating it already, then we open it anyway. We
7576 * don't bother retrying after this, since if this next
7577 * fails, that means that the file was deleted after we
7578 * started this call.
7580 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7583 if (createDisp == FILE_OVERWRITE_IF) {
7584 setAttr.mask = CM_ATTRMASK_LENGTH;
7585 setAttr.length.LowPart = 0;
7586 setAttr.length.HighPart = 0;
7588 /* now watch for a symlink */
7590 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7592 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7594 /* we have a more accurate file to use (the
7595 * target of the symbolic link). Otherwise,
7596 * we'll just use the symlink anyway.
7598 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7600 cm_ReleaseSCache(scp);
7604 code = cm_SetAttr(scp, &setAttr, userp, &req);
7606 } /* lookup succeeded */
7609 clientchar_t *tp, *pp;
7610 clientchar_t *cp; /* This component */
7611 int clen = 0; /* length of component */
7612 cm_scache_t *tscp1, *tscp2;
7615 /* create directory */
7617 treeStartp = lastNamep;
7618 osi_assertx(dscp != NULL, "null cm_scache_t");
7619 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%S]",
7620 osi_LogSaveClientString(smb_logp, treeStartp));
7621 openAction = 2; /* created directory */
7623 /* if the request is to create the root directory
7624 * it will appear as a directory name of the nul-string
7625 * and a code of CM_ERROR_NOSUCHFILE
7627 if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
7628 code = CM_ERROR_EXISTS;
7630 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7631 setAttr.clientModTime = time(NULL);
7636 cm_HoldSCache(tscp1);
7640 tp = cm_ClientStrChr(pp, '\\');
7642 cm_ClientStrCpy(cp, lengthof(spacep->wdata) - (cp - spacep->wdata), pp);
7643 clen = (int)cm_ClientStrLen(cp);
7644 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
7646 clen = (int)(tp - pp);
7647 cm_ClientStrCpyN(cp, lengthof(spacep->wdata) - (cp - spacep->wdata),
7655 continue; /* the supplied path can't have consecutive slashes either , but */
7657 /* cp is the next component to be created. */
7658 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req, NULL);
7659 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
7660 smb_NotifyChange(FILE_ACTION_ADDED,
7661 FILE_NOTIFY_CHANGE_DIR_NAME,
7662 tscp1, cp, NULL, TRUE);
7664 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7665 /* Not an exclusive create, and someone else tried
7666 * creating it already, then we open it anyway. We
7667 * don't bother retrying after this, since if this next
7668 * fails, that means that the file was deleted after we
7669 * started this call.
7671 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
7672 userp, &req, &tscp2);
7677 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
7678 cm_ReleaseSCache(tscp1);
7679 tscp1 = tscp2; /* Newly created directory will be next parent */
7680 /* the hold is transfered to tscp1 from tscp2 */
7685 cm_ReleaseSCache(dscp);
7688 cm_ReleaseSCache(scp);
7691 * if we get here and code == 0, then scp is the last directory created, and dscp is the
7697 /* something went wrong creating or truncating the file */
7698 if (checkDoneRequired)
7699 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7701 cm_ReleaseSCache(scp);
7703 cm_ReleaseSCache(dscp);
7704 cm_ReleaseUser(userp);
7709 /* make sure we have file vs. dir right (only applies for single component case) */
7710 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7711 /* now watch for a symlink */
7713 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7714 cm_scache_t * targetScp = 0;
7715 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7717 /* we have a more accurate file to use (the
7718 * target of the symbolic link). Otherwise,
7719 * we'll just use the symlink anyway.
7721 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
7722 if (checkDoneRequired) {
7723 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7724 checkDoneRequired = 0;
7726 cm_ReleaseSCache(scp);
7731 if (scp->fileType != CM_SCACHETYPE_FILE) {
7732 if (checkDoneRequired)
7733 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7735 cm_ReleaseSCache(dscp);
7736 cm_ReleaseSCache(scp);
7737 cm_ReleaseUser(userp);
7739 return CM_ERROR_ISDIR;
7743 /* (only applies to single component case) */
7744 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7745 if (checkDoneRequired)
7746 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7747 cm_ReleaseSCache(scp);
7749 cm_ReleaseSCache(dscp);
7750 cm_ReleaseUser(userp);
7752 return CM_ERROR_NOTDIR;
7755 /* open the file itself */
7756 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7757 osi_assertx(fidp, "null smb_fid_t");
7759 /* save a reference to the user */
7761 fidp->userp = userp;
7763 /* If we are restricting sharing, we should do so with a suitable
7765 if (scp->fileType == CM_SCACHETYPE_FILE &&
7766 !(fidflags & SMB_FID_SHARE_WRITE)) {
7768 LARGE_INTEGER LOffset, LLength;
7771 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7772 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7773 LLength.HighPart = 0;
7774 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7776 /* If we are not opening the file for writing, then we don't
7777 try to get an exclusive lock. No one else should be able to
7778 get an exclusive lock on the file anyway, although someone
7779 else can get a shared lock. */
7780 if ((fidflags & SMB_FID_SHARE_READ) ||
7781 !(fidflags & SMB_FID_OPENWRITE)) {
7782 sLockType = LOCKING_ANDX_SHARED_LOCK;
7787 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7789 lock_ObtainWrite(&scp->rw);
7790 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7791 lock_ReleaseWrite(&scp->rw);
7794 if (checkDoneRequired)
7795 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7796 cm_ReleaseSCache(scp);
7798 cm_ReleaseSCache(dscp);
7799 cm_ReleaseUser(userp);
7800 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7801 smb_CloseFID(vcp, fidp, NULL, 0);
7802 smb_ReleaseFID(fidp);
7808 /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
7809 if (checkDoneRequired) {
7810 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7811 checkDoneRequired = 0;
7814 lock_ObtainMutex(&fidp->mx);
7815 /* save a pointer to the vnode */
7816 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
7817 lock_ObtainWrite(&scp->rw);
7818 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7819 lock_ReleaseWrite(&scp->rw);
7820 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
7822 fidp->flags = fidflags;
7824 /* remember if the file was newly created */
7826 fidp->flags |= SMB_FID_CREATED;
7828 /* save parent dir and pathname for delete or change notification */
7829 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7830 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
7831 fidp->flags |= SMB_FID_NTOPEN;
7832 fidp->NTopen_dscp = dscp;
7834 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
7836 fidp->NTopen_wholepathp = realPathp;
7837 lock_ReleaseMutex(&fidp->mx);
7839 /* we don't need this any longer */
7841 cm_ReleaseSCache(dscp);
7845 cm_Open(scp, 0, userp);
7847 /* set inp->fid so that later read calls in same msg can find fid */
7848 inp->fid = fidp->fid;
7852 lock_ObtainRead(&scp->rw);
7853 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7854 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7855 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7856 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7857 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7858 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7859 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7860 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7861 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7863 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7864 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7865 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
7866 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
7867 smb_SetSMBParmByte(outp, parmSlot,
7868 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7869 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7870 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7871 smb_SetSMBDataLength(outp, 0);
7873 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
7874 LargeIntegerGreaterThanZero(scp->length) &&
7875 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
7878 lock_ReleaseRead(&scp->rw);
7881 cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
7882 scp->length.LowPart, scp->length.HighPart,
7886 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %S", fidp->fid,
7887 osi_LogSaveClientString(smb_logp, realPathp));
7889 cm_ReleaseUser(userp);
7890 smb_ReleaseFID(fidp);
7892 /* Can't free realPathp if we get here since
7893 fidp->NTopen_wholepathp is pointing there */
7895 /* leave scp held since we put it in fidp->scp */
7900 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
7901 * Instead, ultimately, would like to use a subroutine for common code.
7904 /* NT_TRANSACT_CREATE (SMB_COM_NT_TRANSACT) */
7905 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7907 clientchar_t *pathp, *realPathp;
7911 cm_scache_t *dscp; /* parent dir */
7912 cm_scache_t *scp; /* file to create or open */
7913 cm_scache_t *targetScp; /* if scp is a symlink */
7915 clientchar_t *lastNamep;
7916 unsigned long nameLength;
7918 unsigned int requestOpLock;
7919 unsigned int requestBatchOpLock;
7920 unsigned int mustBeDir;
7921 unsigned int extendedRespRequired;
7923 unsigned int desiredAccess;
7924 unsigned int allocSize;
7925 unsigned int shareAccess;
7926 unsigned int extAttributes;
7927 unsigned int createDisp;
7930 unsigned int impLevel;
7931 unsigned int secFlags;
7932 unsigned int createOptions;
7933 int initialModeBits;
7934 unsigned short baseFid;
7935 smb_fid_t *baseFidp;
7937 cm_scache_t *baseDirp;
7938 unsigned short openAction;
7942 clientchar_t *tidPathp;
7944 int parmOffset, dataOffset;
7951 cm_lock_data_t *ldp = NULL;
7952 int checkDoneRequired = 0;
7959 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7960 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7961 parmp = inp->data + parmOffset;
7962 lparmp = (ULONG *) parmp;
7965 requestOpLock = flags & REQUEST_OPLOCK;
7966 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7967 mustBeDir = flags & OPEN_DIRECTORY;
7968 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7971 * Why all of a sudden 32-bit FID?
7972 * We will reject all bits higher than 16.
7974 if (lparmp[1] & 0xFFFF0000)
7975 return CM_ERROR_INVAL;
7976 baseFid = (unsigned short)lparmp[1];
7977 desiredAccess = lparmp[2];
7978 allocSize = lparmp[3];
7979 extAttributes = lparmp[5];
7980 shareAccess = lparmp[6];
7981 createDisp = lparmp[7];
7982 createOptions = lparmp[8];
7985 nameLength = lparmp[11]; /* spec says chars but appears to be bytes */
7986 impLevel = lparmp[12];
7987 secFlags = lparmp[13];
7989 /* mustBeDir is never set; createOptions directory bit seems to be
7992 if (createOptions & FILE_DIRECTORY_FILE)
7994 else if (createOptions & FILE_NON_DIRECTORY_FILE)
8000 * compute initial mode bits based on read-only flag in
8001 * extended attributes
8003 initialModeBits = 0666;
8004 if (extAttributes & SMB_ATTR_READONLY)
8005 initialModeBits &= ~0222;
8007 pathp = smb_ParseStringCb(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
8008 nameLength, NULL, SMB_STRF_ANSIPATH);
8009 /* Sometimes path is not nul-terminated, so we make a copy. */
8010 realPathp = malloc(nameLength+sizeof(clientchar_t));
8011 memcpy(realPathp, pathp, nameLength);
8012 realPathp[nameLength/sizeof(clientchar_t)] = 0;
8013 spacep = cm_GetSpace();
8014 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
8016 osi_Log1(smb_logp,"NTTranCreate %S",osi_LogSaveStringW(smb_logp,realPathp));
8017 osi_Log4(smb_logp,"... da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
8018 osi_Log4(smb_logp,"... co[%x],sdl[%x],eal[%x],as[%x],flags[%x]",createOptions,sdLen,eaLen,allocSize);
8019 osi_Log3(smb_logp,"... imp[%x],sec[%x],flags[%x]", impLevel, secFlags, flags);
8022 * Nothing here to handle SMB_IOCTL_FILENAME.
8023 * Will add it if necessary.
8026 if (!cm_IsValidClientString(realPathp)) {
8028 clientchar_t * hexp;
8030 hexp = cm_GetRawCharsAlloc(realPathp, -1);
8031 osi_Log1(smb_logp, "NTTranCreate rejecting invalid name. [%S]",
8032 osi_LogSaveClientString(smb_logp, hexp));
8036 osi_Log0(smb_logp, "NTTranCreate rejecting invalid name.");
8039 return CM_ERROR_BADNTFILENAME;
8042 userp = smb_GetUserFromVCP(vcp, inp);
8044 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
8046 return CM_ERROR_INVAL;
8051 baseDirp = cm_data.rootSCachep;
8052 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8053 if (code == CM_ERROR_TIDIPC) {
8054 /* Attempt to use a TID allocated for IPC. The client
8055 * is probably looking for DCE RPC end points which we
8056 * don't support OR it could be looking to make a DFS
8059 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
8062 cm_ReleaseUser(userp);
8063 return CM_ERROR_NOSUCHPATH;
8067 baseFidp = smb_FindFID(vcp, baseFid, 0);
8069 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
8071 cm_ReleaseUser(userp);
8072 return CM_ERROR_BADFD;
8075 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8077 cm_ReleaseUser(userp);
8078 smb_CloseFID(vcp, baseFidp, NULL, 0);
8079 smb_ReleaseFID(baseFidp);
8080 return CM_ERROR_NOSUCHPATH;
8083 baseDirp = baseFidp->scp;
8087 /* compute open mode */
8089 if (desiredAccess & DELETE)
8090 fidflags |= SMB_FID_OPENDELETE;
8091 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
8092 fidflags |= SMB_FID_OPENREAD_LISTDIR;
8093 if (desiredAccess & AFS_ACCESS_WRITE)
8094 fidflags |= SMB_FID_OPENWRITE;
8095 if (createOptions & FILE_DELETE_ON_CLOSE)
8096 fidflags |= SMB_FID_DELONCLOSE;
8097 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
8098 fidflags |= SMB_FID_SEQUENTIAL;
8099 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
8100 fidflags |= SMB_FID_RANDOM;
8101 if (createOptions & FILE_OPEN_REPARSE_POINT)
8102 osi_Log0(smb_logp, "NTTranCreate Open Reparse Point");
8103 if (smb_IsExecutableFileName(lastNamep))
8104 fidflags |= SMB_FID_EXECUTABLE;
8106 /* And the share mode */
8107 if (shareAccess & FILE_SHARE_READ)
8108 fidflags |= SMB_FID_SHARE_READ;
8109 if (shareAccess & FILE_SHARE_WRITE)
8110 fidflags |= SMB_FID_SHARE_WRITE;
8114 if ( createDisp == FILE_OPEN ||
8115 createDisp == FILE_OVERWRITE ||
8116 createDisp == FILE_OVERWRITE_IF) {
8117 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8118 userp, tidPathp, &req, &dscp);
8121 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8122 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8123 cm_ReleaseSCache(dscp);
8124 cm_ReleaseUser(userp);
8127 smb_ReleaseFID(baseFidp);
8128 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8129 return CM_ERROR_PATH_NOT_COVERED;
8131 return CM_ERROR_NOSUCHPATH;
8133 #endif /* DFS_SUPPORT */
8134 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
8136 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
8137 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
8138 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
8139 if (code == 0 && realDirFlag == 1) {
8140 cm_ReleaseSCache(scp);
8141 cm_ReleaseSCache(dscp);
8142 cm_ReleaseUser(userp);
8145 smb_ReleaseFID(baseFidp);
8146 return CM_ERROR_EXISTS;
8152 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8153 userp, tidPathp, &req, &scp);
8155 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
8156 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
8157 cm_ReleaseSCache(scp);
8158 cm_ReleaseUser(userp);
8161 smb_ReleaseFID(baseFidp);
8162 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8163 return CM_ERROR_PATH_NOT_COVERED;
8165 return CM_ERROR_NOSUCHPATH;
8167 #endif /* DFS_SUPPORT */
8173 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
8174 /* look up parent directory */
8176 code = cm_NameI(baseDirp, spacep->wdata,
8177 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8178 userp, tidPathp, &req, &dscp);
8180 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8181 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8182 cm_ReleaseSCache(dscp);
8183 cm_ReleaseUser(userp);
8186 smb_ReleaseFID(baseFidp);
8187 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8188 return CM_ERROR_PATH_NOT_COVERED;
8190 return CM_ERROR_NOSUCHPATH;
8192 #endif /* DFS_SUPPORT */
8196 cm_FreeSpace(spacep);
8199 smb_ReleaseFID(baseFidp);
8202 cm_ReleaseUser(userp);
8208 lastNamep = realPathp;
8212 if (!smb_IsLegalFilename(lastNamep))
8213 return CM_ERROR_BADNTFILENAME;
8216 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
8217 code = cm_Lookup(dscp, lastNamep,
8218 CM_FLAG_FOLLOW, userp, &req, &scp);
8220 code = cm_Lookup(dscp, lastNamep,
8221 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8224 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8225 cm_ReleaseSCache(dscp);
8226 cm_ReleaseUser(userp);
8233 smb_ReleaseFID(baseFidp);
8234 cm_FreeSpace(spacep);
8237 /* if we get here, if code is 0, the file exists and is represented by
8238 * scp. Otherwise, we have to create it. The dir may be represented
8239 * by dscp, or we may have found the file directly. If code is non-zero,
8243 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
8245 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8247 cm_ReleaseSCache(dscp);
8248 cm_ReleaseSCache(scp);
8249 cm_ReleaseUser(userp);
8253 checkDoneRequired = 1;
8255 if (createDisp == FILE_CREATE) {
8256 /* oops, file shouldn't be there */
8257 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8259 cm_ReleaseSCache(dscp);
8260 cm_ReleaseSCache(scp);
8261 cm_ReleaseUser(userp);
8263 return CM_ERROR_EXISTS;
8266 if (createDisp == FILE_OVERWRITE ||
8267 createDisp == FILE_OVERWRITE_IF) {
8268 setAttr.mask = CM_ATTRMASK_LENGTH;
8269 setAttr.length.LowPart = 0;
8270 setAttr.length.HighPart = 0;
8272 /* now watch for a symlink */
8274 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8276 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8278 /* we have a more accurate file to use (the
8279 * target of the symbolic link). Otherwise,
8280 * we'll just use the symlink anyway.
8282 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8284 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8285 cm_ReleaseSCache(scp);
8287 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
8289 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8291 cm_ReleaseSCache(dscp);
8293 cm_ReleaseSCache(scp);
8294 cm_ReleaseUser(userp);
8300 code = cm_SetAttr(scp, &setAttr, userp, &req);
8301 openAction = 3; /* truncated existing file */
8303 else openAction = 1; /* found existing file */
8305 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
8306 /* don't create if not found */
8308 cm_ReleaseSCache(dscp);
8309 cm_ReleaseUser(userp);
8311 return CM_ERROR_NOSUCHFILE;
8313 else if (realDirFlag == 0 || realDirFlag == -1) {
8314 osi_assertx(dscp != NULL, "null cm_scache_t");
8315 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %S",
8316 osi_LogSaveClientString(smb_logp, lastNamep));
8317 openAction = 2; /* created file */
8318 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8319 setAttr.clientModTime = time(NULL);
8320 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8324 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8325 smb_NotifyChange(FILE_ACTION_ADDED,
8326 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8327 dscp, lastNamep, NULL, TRUE);
8328 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
8329 /* Not an exclusive create, and someone else tried
8330 * creating it already, then we open it anyway. We
8331 * don't bother retrying after this, since if this next
8332 * fails, that means that the file was deleted after we
8333 * started this call.
8335 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8338 if (createDisp == FILE_OVERWRITE_IF) {
8339 setAttr.mask = CM_ATTRMASK_LENGTH;
8340 setAttr.length.LowPart = 0;
8341 setAttr.length.HighPart = 0;
8343 /* now watch for a symlink */
8345 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8347 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8349 /* we have a more accurate file to use (the
8350 * target of the symbolic link). Otherwise,
8351 * we'll just use the symlink anyway.
8353 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8355 cm_ReleaseSCache(scp);
8359 code = cm_SetAttr(scp, &setAttr, userp, &req);
8361 } /* lookup succeeded */
8364 /* create directory */
8365 osi_assertx(dscp != NULL, "null cm_scache_t");
8367 "smb_ReceiveNTTranCreate creating directory %S",
8368 osi_LogSaveClientString(smb_logp, lastNamep));
8369 openAction = 2; /* created directory */
8370 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8371 setAttr.clientModTime = time(NULL);
8372 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8373 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8374 smb_NotifyChange(FILE_ACTION_ADDED,
8375 FILE_NOTIFY_CHANGE_DIR_NAME,
8376 dscp, lastNamep, NULL, TRUE);
8378 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
8379 /* Not an exclusive create, and someone else tried
8380 * creating it already, then we open it anyway. We
8381 * don't bother retrying after this, since if this next
8382 * fails, that means that the file was deleted after we
8383 * started this call.
8385 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8391 /* something went wrong creating or truncating the file */
8392 if (checkDoneRequired)
8393 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8395 cm_ReleaseSCache(scp);
8396 cm_ReleaseUser(userp);
8401 /* make sure we have file vs. dir right */
8402 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
8403 /* now watch for a symlink */
8405 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8407 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8409 /* we have a more accurate file to use (the
8410 * target of the symbolic link). Otherwise,
8411 * we'll just use the symlink anyway.
8413 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8415 if (checkDoneRequired) {
8416 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8417 checkDoneRequired = 0;
8419 cm_ReleaseSCache(scp);
8424 if (scp->fileType != CM_SCACHETYPE_FILE) {
8425 if (checkDoneRequired)
8426 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8427 cm_ReleaseSCache(scp);
8428 cm_ReleaseUser(userp);
8430 return CM_ERROR_ISDIR;
8434 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8435 if (checkDoneRequired)
8436 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8437 cm_ReleaseSCache(scp);
8438 cm_ReleaseUser(userp);
8440 return CM_ERROR_NOTDIR;
8443 /* open the file itself */
8444 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8445 osi_assertx(fidp, "null smb_fid_t");
8447 /* save a reference to the user */
8449 fidp->userp = userp;
8451 /* If we are restricting sharing, we should do so with a suitable
8453 if (scp->fileType == CM_SCACHETYPE_FILE &&
8454 !(fidflags & SMB_FID_SHARE_WRITE)) {
8456 LARGE_INTEGER LOffset, LLength;
8459 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8460 LOffset.LowPart = SMB_FID_QLOCK_LOW;
8461 LLength.HighPart = 0;
8462 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8464 /* Similar to what we do in handling NTCreateX. We get a
8465 shared lock if we are only opening the file for reading. */
8466 if ((fidflags & SMB_FID_SHARE_READ) ||
8467 !(fidflags & SMB_FID_OPENWRITE)) {
8468 sLockType = LOCKING_ANDX_SHARED_LOCK;
8473 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8475 lock_ObtainWrite(&scp->rw);
8476 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8477 lock_ReleaseWrite(&scp->rw);
8480 if (checkDoneRequired)
8481 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8482 cm_ReleaseSCache(scp);
8483 cm_ReleaseUser(userp);
8484 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
8485 smb_CloseFID(vcp, fidp, NULL, 0);
8486 smb_ReleaseFID(fidp);
8488 return CM_ERROR_SHARING_VIOLATION;
8492 /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
8493 if (checkDoneRequired) {
8494 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8495 checkDoneRequired = 0;
8498 lock_ObtainMutex(&fidp->mx);
8499 /* save a pointer to the vnode */
8501 lock_ObtainWrite(&scp->rw);
8502 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8503 lock_ReleaseWrite(&scp->rw);
8504 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
8506 fidp->flags = fidflags;
8508 /* remember if the file was newly created */
8510 fidp->flags |= SMB_FID_CREATED;
8512 /* save parent dir and pathname for deletion or change notification */
8513 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8514 fidp->flags |= SMB_FID_NTOPEN;
8515 fidp->NTopen_dscp = dscp;
8516 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
8518 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
8520 fidp->NTopen_wholepathp = realPathp;
8521 lock_ReleaseMutex(&fidp->mx);
8523 /* we don't need this any longer */
8525 cm_ReleaseSCache(dscp);
8527 cm_Open(scp, 0, userp);
8529 /* set inp->fid so that later read calls in same msg can find fid */
8530 inp->fid = fidp->fid;
8532 /* check whether we are required to send an extended response */
8533 if (!extendedRespRequired) {
8535 parmOffset = 8*4 + 39;
8536 parmOffset += 1; /* pad to 4 */
8537 dataOffset = parmOffset + 70;
8541 /* Total Parameter Count */
8542 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8543 /* Total Data Count */
8544 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8545 /* Parameter Count */
8546 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8547 /* Parameter Offset */
8548 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8549 /* Parameter Displacement */
8550 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8552 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8554 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8555 /* Data Displacement */
8556 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8557 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8558 smb_SetSMBDataLength(outp, 70);
8560 lock_ObtainRead(&scp->rw);
8561 outData = smb_GetSMBData(outp, NULL);
8562 outData++; /* round to get to parmOffset */
8563 *outData = 0; outData++; /* oplock */
8564 *outData = 0; outData++; /* reserved */
8565 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8566 *((ULONG *)outData) = openAction; outData += 4;
8567 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8568 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8569 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8570 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8571 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8572 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8573 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8574 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8575 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8576 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8577 *((USHORT *)outData) = 0; outData += 2; /* dev state */
8578 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8579 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8580 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8581 outData += 2; /* is a dir? */
8584 parmOffset = 8*4 + 39;
8585 parmOffset += 1; /* pad to 4 */
8586 dataOffset = parmOffset + 104;
8590 /* Total Parameter Count */
8591 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8592 /* Total Data Count */
8593 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8594 /* Parameter Count */
8595 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8596 /* Parameter Offset */
8597 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8598 /* Parameter Displacement */
8599 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8601 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8603 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8604 /* Data Displacement */
8605 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8606 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8607 smb_SetSMBDataLength(outp, 105);
8609 lock_ObtainRead(&scp->rw);
8610 outData = smb_GetSMBData(outp, NULL);
8611 outData++; /* round to get to parmOffset */
8612 *outData = 0; outData++; /* oplock */
8613 *outData = 1; outData++; /* response type */
8614 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8615 *((ULONG *)outData) = openAction; outData += 4;
8616 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8617 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8618 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8619 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8620 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8621 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8622 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8623 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8624 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8625 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8626 *((USHORT *)outData) = 0; outData += 2; /* dev state */
8627 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8628 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8629 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8630 outData += 1; /* is a dir? */
8631 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
8632 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
8633 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
8636 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
8637 LargeIntegerGreaterThanZero(scp->length) &&
8638 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
8641 lock_ReleaseRead(&scp->rw);
8644 cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
8645 scp->length.LowPart, scp->length.HighPart,
8648 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
8650 cm_ReleaseUser(userp);
8651 smb_ReleaseFID(fidp);
8653 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
8654 /* leave scp held since we put it in fidp->scp */
8658 /* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
8659 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
8662 smb_packet_t *savedPacketp;
8664 USHORT fid, watchtree;
8668 filter = smb_GetSMBParm(inp, 19) |
8669 (smb_GetSMBParm(inp, 20) << 16);
8670 fid = smb_GetSMBParm(inp, 21);
8671 watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
8673 fidp = smb_FindFID(vcp, fid, 0);
8675 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
8676 return CM_ERROR_BADFD;
8679 lock_ObtainMutex(&fidp->mx);
8680 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8681 lock_ReleaseMutex(&fidp->mx);
8682 smb_CloseFID(vcp, fidp, NULL, 0);
8683 smb_ReleaseFID(fidp);
8684 return CM_ERROR_NOSUCHFILE;
8688 lock_ReleaseMutex(&fidp->mx);
8690 /* Create a copy of the Directory Watch Packet to use when sending the
8691 * notification if in the future a matching change is detected.
8693 savedPacketp = smb_CopyPacket(inp);
8694 if (vcp != savedPacketp->vcp) {
8696 if (savedPacketp->vcp)
8697 smb_ReleaseVC(savedPacketp->vcp);
8698 savedPacketp->vcp = vcp;
8701 /* Add the watch to the list of events to send notifications for */
8702 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8703 savedPacketp->nextp = smb_Directory_Watches;
8704 smb_Directory_Watches = savedPacketp;
8705 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8707 osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%S\"",
8708 fidp, scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp));
8709 osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
8710 filter, fid, watchtree);
8711 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8712 osi_Log0(smb_logp, " Notify Change File Name");
8713 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8714 osi_Log0(smb_logp, " Notify Change Directory Name");
8715 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8716 osi_Log0(smb_logp, " Notify Change Attributes");
8717 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8718 osi_Log0(smb_logp, " Notify Change Size");
8719 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8720 osi_Log0(smb_logp, " Notify Change Last Write");
8721 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8722 osi_Log0(smb_logp, " Notify Change Last Access");
8723 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8724 osi_Log0(smb_logp, " Notify Change Creation");
8725 if (filter & FILE_NOTIFY_CHANGE_EA)
8726 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8727 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8728 osi_Log0(smb_logp, " Notify Change Security");
8729 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8730 osi_Log0(smb_logp, " Notify Change Stream Name");
8731 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8732 osi_Log0(smb_logp, " Notify Change Stream Size");
8733 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8734 osi_Log0(smb_logp, " Notify Change Stream Write");
8736 lock_ObtainWrite(&scp->rw);
8738 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
8740 scp->flags |= CM_SCACHEFLAG_WATCHED;
8741 lock_ReleaseWrite(&scp->rw);
8742 cm_ReleaseSCache(scp);
8743 smb_ReleaseFID(fidp);
8745 outp->flags |= SMB_PACKETFLAG_NOSEND;
8749 unsigned char nullSecurityDesc[36] = {
8750 0x01, /* security descriptor revision */
8751 0x00, /* reserved, should be zero */
8752 0x00, 0x80, /* security descriptor control;
8753 * 0x8000 : self-relative format */
8754 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
8755 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
8756 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
8757 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
8758 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8759 /* "null SID" owner SID */
8760 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
8761 /* "null SID" group SID */
8764 /* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
8765 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8767 int parmOffset, parmCount, dataOffset, dataCount;
8775 ULONG securityInformation;
8777 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8778 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8779 parmp = inp->data + parmOffset;
8780 sparmp = (USHORT *) parmp;
8781 lparmp = (ULONG *) parmp;
8784 securityInformation = lparmp[1];
8786 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
8787 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
8795 parmOffset = 8*4 + 39;
8796 parmOffset += 1; /* pad to 4 */
8798 dataOffset = parmOffset + parmCount;
8802 /* Total Parameter Count */
8803 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8804 /* Total Data Count */
8805 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8806 /* Parameter Count */
8807 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8808 /* Parameter Offset */
8809 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8810 /* Parameter Displacement */
8811 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8813 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8815 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8816 /* Data Displacement */
8817 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8818 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8819 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
8821 outData = smb_GetSMBData(outp, NULL);
8822 outData++; /* round to get to parmOffset */
8823 *((ULONG *)outData) = 36; outData += 4; /* length */
8825 if (maxData >= 36) {
8826 memcpy(outData, nullSecurityDesc, 36);
8830 return CM_ERROR_BUFFERTOOSMALL;
8833 /* SMB_COM_NT_TRANSACT
8835 SMB_COM_NT_TRANSACT_SECONDARY should also be handled here.
8837 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8839 unsigned short function;
8841 function = smb_GetSMBParm(inp, 18);
8843 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
8845 /* We can handle long names */
8846 if (vcp->flags & SMB_VCFLAG_USENT)
8847 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
8850 case 1: /* NT_TRANSACT_CREATE */
8851 return smb_ReceiveNTTranCreate(vcp, inp, outp);
8852 case 2: /* NT_TRANSACT_IOCTL */
8853 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
8855 case 3: /* NT_TRANSACT_SET_SECURITY_DESC */
8856 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
8858 case 4: /* NT_TRANSACT_NOTIFY_CHANGE */
8859 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
8860 case 5: /* NT_TRANSACT_RENAME */
8861 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
8863 case 6: /* NT_TRANSACT_QUERY_SECURITY_DESC */
8864 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
8866 osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
8869 osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
8872 return CM_ERROR_INVAL;
8876 * smb_NotifyChange -- find relevant change notification messages and
8879 * If we don't know the file name (i.e. a callback break), filename is
8880 * NULL, and we return a zero-length list.
8882 * At present there is not a single call to smb_NotifyChange that
8883 * has the isDirectParent parameter set to FALSE.
8885 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
8886 cm_scache_t *dscp, clientchar_t *filename, clientchar_t *otherFilename,
8887 BOOL isDirectParent)
8889 smb_packet_t *watch, *lastWatch, *nextWatch;
8890 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen = 0;
8891 char *outData, *oldOutData;
8895 BOOL twoEntries = FALSE;
8896 ULONG otherNameLen, oldParmCount = 0;
8900 /* Get ready for rename within directory */
8901 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
8903 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
8906 osi_Log4(smb_logp,"in smb_NotifyChange for file [%S] dscp [%p] notification 0x%x parent %d",
8907 osi_LogSaveClientString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
8909 osi_Log0(smb_logp," FILE_ACTION_NONE");
8910 if (action == FILE_ACTION_ADDED)
8911 osi_Log0(smb_logp," FILE_ACTION_ADDED");
8912 if (action == FILE_ACTION_REMOVED)
8913 osi_Log0(smb_logp," FILE_ACTION_REMOVED");
8914 if (action == FILE_ACTION_MODIFIED)
8915 osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
8916 if (action == FILE_ACTION_RENAMED_OLD_NAME)
8917 osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
8918 if (action == FILE_ACTION_RENAMED_NEW_NAME)
8919 osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
8921 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8922 watch = smb_Directory_Watches;
8924 filter = smb_GetSMBParm(watch, 19)
8925 | (smb_GetSMBParm(watch, 20) << 16);
8926 fid = smb_GetSMBParm(watch, 21);
8927 wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
8929 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
8930 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
8933 * Strange hack - bug in NT Client and NT Server that we must emulate?
8935 if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
8936 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
8938 fidp = smb_FindFID(watch->vcp, fid, 0);
8940 osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
8942 watch = watch->nextp;
8946 if (fidp->scp != dscp ||
8947 fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
8948 (filter & notifyFilter) == 0 ||
8949 (!isDirectParent && !wtree))
8951 osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
8953 watch = watch->nextp;
8954 smb_ReleaseFID(fidp);
8959 "Sending Change Notification for fid %d filter 0x%x wtree %d file %S",
8960 fid, filter, wtree, osi_LogSaveClientString(smb_logp, filename));
8961 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8962 osi_Log0(smb_logp, " Notify Change File Name");
8963 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8964 osi_Log0(smb_logp, " Notify Change Directory Name");
8965 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8966 osi_Log0(smb_logp, " Notify Change Attributes");
8967 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8968 osi_Log0(smb_logp, " Notify Change Size");
8969 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8970 osi_Log0(smb_logp, " Notify Change Last Write");
8971 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8972 osi_Log0(smb_logp, " Notify Change Last Access");
8973 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8974 osi_Log0(smb_logp, " Notify Change Creation");
8975 if (filter & FILE_NOTIFY_CHANGE_EA)
8976 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8977 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8978 osi_Log0(smb_logp, " Notify Change Security");
8979 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8980 osi_Log0(smb_logp, " Notify Change Stream Name");
8981 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8982 osi_Log0(smb_logp, " Notify Change Stream Size");
8983 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8984 osi_Log0(smb_logp, " Notify Change Stream Write");
8986 /* A watch can only be notified once. Remove it from the list */
8987 nextWatch = watch->nextp;
8988 if (watch == smb_Directory_Watches)
8989 smb_Directory_Watches = nextWatch;
8991 lastWatch->nextp = nextWatch;
8993 /* Turn off WATCHED flag in dscp */
8994 lock_ObtainWrite(&dscp->rw);
8996 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8998 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
8999 lock_ReleaseWrite(&dscp->rw);
9001 /* Convert to response packet */
9002 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
9003 #ifdef SEND_CANONICAL_PATHNAMES
9004 ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
9006 ((smb_t *) watch)->wct = 0;
9009 if (filename == NULL) {
9012 nameLen = (ULONG)cm_ClientStrLen(filename);
9013 parmCount = 3*4 + nameLen*2;
9014 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
9016 otherNameLen = (ULONG)cm_ClientStrLen(otherFilename);
9017 oldParmCount = parmCount;
9018 parmCount += 3*4 + otherNameLen*2;
9019 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
9021 if (maxLen < parmCount)
9022 parmCount = 0; /* not enough room */
9024 parmOffset = 8*4 + 39;
9025 parmOffset += 1; /* pad to 4 */
9026 dataOffset = parmOffset + parmCount;
9030 /* Total Parameter Count */
9031 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
9032 /* Total Data Count */
9033 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9034 /* Parameter Count */
9035 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
9036 /* Parameter Offset */
9037 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
9038 /* Parameter Displacement */
9039 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9041 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9043 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
9044 /* Data Displacement */
9045 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9046 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
9047 smb_SetSMBDataLength(watch, parmCount + 1);
9049 if (parmCount != 0) {
9050 outData = smb_GetSMBData(watch, NULL);
9051 outData++; /* round to get to parmOffset */
9052 oldOutData = outData;
9053 *((DWORD *)outData) = oldParmCount; outData += 4;
9054 /* Next Entry Offset */
9055 *((DWORD *)outData) = action; outData += 4;
9057 *((DWORD *)outData) = nameLen*2; outData += 4;
9058 /* File Name Length */
9060 smb_UnparseString(watch, outData, filename, NULL, 0);
9064 outData = oldOutData + oldParmCount;
9065 *((DWORD *)outData) = 0; outData += 4;
9066 /* Next Entry Offset */
9067 *((DWORD *)outData) = otherAction; outData += 4;
9069 *((DWORD *)outData) = otherNameLen*2;
9070 outData += 4; /* File Name Length */
9071 smb_UnparseString(watch, outData, otherFilename, NULL, 0);
9076 * If filename is null, we don't know the cause of the
9077 * change notification. We return zero data (see above),
9078 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
9079 * (= 0x010C). We set the error code here by hand, without
9080 * modifying wct and bcc.
9082 if (filename == NULL) {
9083 ((smb_t *) watch)->rcls = 0x0C;
9084 ((smb_t *) watch)->reh = 0x01;
9085 ((smb_t *) watch)->errLow = 0;
9086 ((smb_t *) watch)->errHigh = 0;
9087 /* Set NT Status codes flag */
9088 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9091 smb_SendPacket(watch->vcp, watch);
9092 smb_FreePacket(watch);
9094 smb_ReleaseFID(fidp);
9097 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9100 /* SMB_COM_NT_CANCEL */
9101 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9103 unsigned char *replyWctp;
9104 smb_packet_t *watch, *lastWatch;
9105 USHORT fid, watchtree;
9109 osi_Log0(smb_logp, "SMB3 receive NT cancel");
9111 lock_ObtainMutex(&smb_Dir_Watch_Lock);
9112 watch = smb_Directory_Watches;
9114 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
9115 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
9116 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
9117 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
9118 if (watch == smb_Directory_Watches)
9119 smb_Directory_Watches = watch->nextp;
9121 lastWatch->nextp = watch->nextp;
9122 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9124 /* Turn off WATCHED flag in scp */
9125 fid = smb_GetSMBParm(watch, 21);
9126 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
9128 if (vcp != watch->vcp)
9129 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
9132 fidp = smb_FindFID(vcp, fid, 0);
9134 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %S",
9136 (fidp ? osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp) :_C("")));
9139 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
9141 lock_ObtainWrite(&scp->rw);
9143 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
9145 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
9146 lock_ReleaseWrite(&scp->rw);
9148 smb_ReleaseFID(fidp);
9150 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
9153 /* assume STATUS32; return 0xC0000120 (CANCELED) */
9154 replyWctp = watch->wctp;
9158 ((smb_t *)watch)->rcls = 0x20;
9159 ((smb_t *)watch)->reh = 0x1;
9160 ((smb_t *)watch)->errLow = 0;
9161 ((smb_t *)watch)->errHigh = 0xC0;
9162 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9163 smb_SendPacket(vcp, watch);
9164 smb_FreePacket(watch);
9168 watch = watch->nextp;
9170 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9176 * NT rename also does hard links.
9179 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
9180 #define RENAME_FLAG_HARD_LINK 0x103
9181 #define RENAME_FLAG_RENAME 0x104
9182 #define RENAME_FLAG_COPY 0x105
9184 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9186 clientchar_t *oldPathp, *newPathp;
9192 attrs = smb_GetSMBParm(inp, 0);
9193 rename_type = smb_GetSMBParm(inp, 1);
9195 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
9196 osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
9197 return CM_ERROR_NOACCESS;
9200 tp = smb_GetSMBData(inp, NULL);
9201 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
9203 return CM_ERROR_BADSMB;
9204 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
9206 return CM_ERROR_BADSMB;
9208 osi_Log3(smb_logp, "NTRename for [%S]->[%S] type [%s]",
9209 osi_LogSaveClientString(smb_logp, oldPathp),
9210 osi_LogSaveClientString(smb_logp, newPathp),
9211 ((rename_type==RENAME_FLAG_RENAME)?"rename":(rename_type==RENAME_FLAG_HARD_LINK)?"hardlink":"other"));
9213 if (rename_type == RENAME_FLAG_RENAME) {
9214 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
9215 } else if (rename_type == RENAME_FLAG_HARD_LINK) { /* RENAME_FLAG_HARD_LINK */
9216 code = smb_Link(vcp,inp,oldPathp,newPathp);
9218 code = CM_ERROR_BADOP;
9224 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock", LOCK_HIERARCHY_SMB_DIRWATCH);
9227 cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
9229 smb_username_t *unp;
9232 unp = smb_FindUserByName(usern, machine, flags);
9234 lock_ObtainMutex(&unp->mx);
9235 unp->userp = cm_NewUser();
9236 lock_ReleaseMutex(&unp->mx);
9237 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9239 osi_Log2(smb_logp,"smb_FindCMUserByName Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9243 smb_ReleaseUsername(unp);