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);
3158 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO)
3159 responseSize = sizeof(qpi.u.QPfileStreamInfo);
3161 osi_Log2(smb_logp, "Bad Tran2QPathInfo op 0x%x infolevel 0x%x",
3162 p->opcode, infoLevel);
3163 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3166 memset(&qpi, 0, sizeof(qpi));
3168 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3169 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %S", infoLevel,
3170 osi_LogSaveClientString(smb_logp, pathp));
3172 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3174 if (infoLevel > 0x100)
3175 outp->totalParms = 2;
3177 outp->totalParms = 0;
3179 /* now, if we're at infoLevel 6, we're only being asked to check
3180 * the syntax, so we just OK things now. In particular, we're *not*
3181 * being asked to verify anything about the state of any parent dirs.
3183 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
3184 smb_SendTran2Packet(vcp, outp, opx);
3185 smb_FreeTran2Packet(outp);
3189 userp = smb_GetTran2User(vcp, p);
3191 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
3192 smb_FreeTran2Packet(outp);
3193 return CM_ERROR_BADSMB;
3196 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3198 cm_ReleaseUser(userp);
3199 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
3200 smb_FreeTran2Packet(outp);
3205 * XXX Strange hack XXX
3207 * As of Patch 7 (13 January 98), we are having the following problem:
3208 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3209 * requests to look up "desktop.ini" in all the subdirectories.
3210 * This can cause zillions of timeouts looking up non-existent cells
3211 * and volumes, especially in the top-level directory.
3213 * We have not found any way to avoid this or work around it except
3214 * to explicitly ignore the requests for mount points that haven't
3215 * yet been evaluated and for directories that haven't yet been
3218 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3219 spacep = cm_GetSpace();
3220 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3221 #ifndef SPECIAL_FOLDERS
3222 /* Make sure that lastComp is not NULL */
3224 if (cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
3225 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3229 userp, tidPathp, &req, &dscp);
3232 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3233 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3235 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3236 code = CM_ERROR_PATH_NOT_COVERED;
3238 code = CM_ERROR_NOSUCHPATH;
3240 #endif /* DFS_SUPPORT */
3241 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3242 code = CM_ERROR_NOSUCHFILE;
3243 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3244 cm_buf_t *bp = buf_Find(dscp, &hzero);
3250 code = CM_ERROR_NOSUCHFILE;
3252 cm_ReleaseSCache(dscp);
3254 cm_FreeSpace(spacep);
3255 cm_ReleaseUser(userp);
3256 smb_SendTran2Error(vcp, p, opx, code);
3257 smb_FreeTran2Packet(outp);
3263 #endif /* SPECIAL_FOLDERS */
3265 cm_FreeSpace(spacep);
3268 /* now do namei and stat, and copy out the info */
3269 code = cm_NameI(cm_data.rootSCachep, pathp,
3270 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3273 cm_ReleaseUser(userp);
3274 smb_SendTran2Error(vcp, p, opx, code);
3275 smb_FreeTran2Packet(outp);
3280 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3281 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3282 cm_ReleaseSCache(scp);
3283 cm_ReleaseUser(userp);
3284 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3285 code = CM_ERROR_PATH_NOT_COVERED;
3287 code = CM_ERROR_NOSUCHPATH;
3288 smb_SendTran2Error(vcp, p, opx, code);
3289 smb_FreeTran2Packet(outp);
3292 #endif /* DFS_SUPPORT */
3294 lock_ObtainWrite(&scp->rw);
3296 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3297 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3301 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3303 lock_ConvertWToR(&scp->rw);
3308 /* now we have the status in the cache entry, and everything is locked.
3309 * Marshall the output data.
3311 /* for info level 108, figure out short name */
3312 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3313 code = cm_GetShortName(pathp, userp, &req,
3314 tidPathp, scp->fid.vnode, shortName,
3320 smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
3321 qpi.u.QPfileAltNameInfo.fileNameLength = len;
3322 responseSize = sizeof(unsigned long) + len;
3324 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3325 smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3326 qpi.u.QPfileNameInfo.fileNameLength = len;
3327 responseSize = sizeof(unsigned long) + 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) {
3380 lock_ReleaseRead(&scp->rw);
3382 fidp = smb_FindFIDByScache(vcp, scp);
3384 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3385 qpi.u.QPfileAllInfo.creationTime = ft;
3386 qpi.u.QPfileAllInfo.lastAccessTime = ft;
3387 qpi.u.QPfileAllInfo.lastWriteTime = ft;
3388 qpi.u.QPfileAllInfo.changeTime = ft;
3389 extAttributes = smb_ExtAttributes(scp);
3390 qpi.u.QPfileAllInfo.attributes = extAttributes;
3391 qpi.u.QPfileAllInfo.allocationSize = scp->length;
3392 qpi.u.QPfileAllInfo.endOfFile = scp->length;
3393 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3394 qpi.u.QPfileAllInfo.deletePending = 0;
3395 qpi.u.QPfileAllInfo.directory =
3396 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3397 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3398 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3399 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.vnode;
3400 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.unique;
3401 qpi.u.QPfileAllInfo.eaSize = 0;
3402 qpi.u.QPfileAllInfo.accessFlags = 0;
3404 lock_ObtainMutex(&fidp->mx);
3405 if (fidp->flags & SMB_FID_OPENDELETE)
3406 qpi.u.QPfileAllInfo.accessFlags |= DELETE;
3407 if (fidp->flags & SMB_FID_OPENREAD_LISTDIR)
3408 qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_READ|AFS_ACCESS_EXECUTE;
3409 if (fidp->flags & SMB_FID_OPENWRITE)
3410 qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_WRITE;
3411 if (fidp->flags & SMB_FID_DELONCLOSE)
3412 qpi.u.QPfileAllInfo.deletePending = 1;
3413 lock_ReleaseMutex(&fidp->mx);
3414 smb_ReleaseFID(fidp);
3416 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.cell;
3417 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.volume;
3418 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3419 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3420 qpi.u.QPfileAllInfo.mode = 0;
3421 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3423 smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3424 qpi.u.QPfileAllInfo.fileNameLength = len;
3425 responseSize -= (sizeof(qpi.u.QPfileAllInfo.fileName) - len);
3427 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO) {
3429 /* For now we have no streams */
3430 qpi.u.QPfileStreamInfo.nextEntryOffset = 0;
3431 qpi.u.QPfileStreamInfo.streamSize = scp->length;
3432 qpi.u.QPfileStreamInfo.streamAllocationSize = scp->length;
3433 smb_UnparseString(opx, qpi.u.QPfileStreamInfo.fileName, L"::$DATA", &len, SMB_STRF_IGNORENUL);
3434 qpi.u.QPfileStreamInfo.streamNameLength = len;
3435 responseSize -= (sizeof(qpi.u.QPfileStreamInfo.fileName) - len);
3437 outp->totalData = responseSize;
3439 /* send and free the packets */
3441 switch (scp_rw_held) {
3443 lock_ReleaseRead(&scp->rw);
3446 lock_ReleaseWrite(&scp->rw);
3450 cm_ReleaseSCache(scp);
3451 cm_ReleaseUser(userp);
3453 memcpy(outp->datap, &qpi, responseSize);
3454 smb_SendTran2Packet(vcp, outp, opx);
3456 smb_SendTran2Error(vcp, p, opx, code);
3458 smb_FreeTran2Packet(outp);
3463 /* TRANS2_SET_PATH_INFORMATION */
3464 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3467 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
3468 return CM_ERROR_BADOP;
3471 unsigned short infoLevel;
3472 clientchar_t * pathp;
3473 smb_tran2Packet_t *outp;
3474 smb_tran2QPathInfo_t *spi;
3476 cm_scache_t *scp, *dscp;
3479 clientchar_t *tidPathp;
3480 clientchar_t *lastComp;
3484 infoLevel = p->parmsp[0];
3485 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
3486 if (infoLevel != SMB_INFO_STANDARD &&
3487 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
3488 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
3489 osi_Log2(smb_logp, "Bad Tran2SetPathInfo op 0x%x infolevel 0x%x",
3490 p->opcode, infoLevel);
3491 smb_SendTran2Error(vcp, p, opx,
3492 infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3496 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3498 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
3499 osi_LogSaveClientString(smb_logp, pathp));
3501 userp = smb_GetTran2User(vcp, p);
3503 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3504 code = CM_ERROR_BADSMB;
3508 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3509 if (code == CM_ERROR_TIDIPC) {
3510 /* Attempt to use a TID allocated for IPC. The client
3511 * is probably looking for DCE RPC end points which we
3512 * don't support OR it could be looking to make a DFS
3515 osi_Log0(smb_logp, "Tran2Open received IPC TID");
3516 cm_ReleaseUser(userp);
3517 return CM_ERROR_NOSUCHPATH;
3521 * XXX Strange hack XXX
3523 * As of Patch 7 (13 January 98), we are having the following problem:
3524 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3525 * requests to look up "desktop.ini" in all the subdirectories.
3526 * This can cause zillions of timeouts looking up non-existent cells
3527 * and volumes, especially in the top-level directory.
3529 * We have not found any way to avoid this or work around it except
3530 * to explicitly ignore the requests for mount points that haven't
3531 * yet been evaluated and for directories that haven't yet been
3534 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3535 spacep = cm_GetSpace();
3536 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3537 #ifndef SPECIAL_FOLDERS
3538 /* Make sure that lastComp is not NULL */
3540 if (cm_ClientStrCmpI(lastComp, _C("\\desktop.ini")) == 0) {
3541 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3545 userp, tidPathp, &req, &dscp);
3548 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3549 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3551 if ( WANTS_DFS_PATHNAMES(p) || pnc )
3552 code = CM_ERROR_PATH_NOT_COVERED;
3554 code = CM_ERROR_NOSUCHPATH;
3556 #endif /* DFS_SUPPORT */
3557 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3558 code = CM_ERROR_NOSUCHFILE;
3559 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3560 cm_buf_t *bp = buf_Find(dscp, &hzero);
3566 code = CM_ERROR_NOSUCHFILE;
3568 cm_ReleaseSCache(dscp);
3570 cm_FreeSpace(spacep);
3571 cm_ReleaseUser(userp);
3572 smb_SendTran2Error(vcp, p, opx, code);
3578 #endif /* SPECIAL_FOLDERS */
3580 cm_FreeSpace(spacep);
3583 /* now do namei and stat, and copy out the info */
3584 code = cm_NameI(cm_data.rootSCachep, pathp,
3585 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3587 cm_ReleaseUser(userp);
3588 smb_SendTran2Error(vcp, p, opx, code);
3592 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3594 outp->totalParms = 2;
3595 outp->totalData = 0;
3597 spi = (smb_tran2QPathInfo_t *)p->datap;
3598 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3601 /* lock the vnode with a callback; we need the current status
3602 * to determine what the new status is, in some cases.
3604 lock_ObtainWrite(&scp->rw);
3605 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3606 CM_SCACHESYNC_GETSTATUS
3607 | CM_SCACHESYNC_NEEDCALLBACK);
3609 lock_ReleaseWrite(&scp->rw);
3612 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3614 /* prepare for setattr call */
3615 attr.mask = CM_ATTRMASK_LENGTH;
3616 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3617 attr.length.HighPart = 0;
3619 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3620 cm_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3621 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3624 if (spi->u.QPstandardInfo.attributes != 0) {
3625 if ((scp->unixModeBits & 0222)
3626 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3627 /* make a writable file read-only */
3628 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3629 attr.unixModeBits = scp->unixModeBits & ~0222;
3631 else if ((scp->unixModeBits & 0222) == 0
3632 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3633 /* make a read-only file writable */
3634 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3635 attr.unixModeBits = scp->unixModeBits | 0222;
3638 lock_ReleaseRead(&scp->rw);
3642 code = cm_SetAttr(scp, &attr, userp, &req);
3646 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3647 /* we don't support EAs */
3648 code = CM_ERROR_EAS_NOT_SUPPORTED;
3652 cm_ReleaseSCache(scp);
3653 cm_ReleaseUser(userp);
3655 smb_SendTran2Packet(vcp, outp, opx);
3657 smb_SendTran2Error(vcp, p, opx, code);
3658 smb_FreeTran2Packet(outp);
3664 /* TRANS2_QUERY_FILE_INFORMATION */
3665 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3667 smb_tran2Packet_t *outp;
3669 unsigned long attributes;
3670 unsigned short infoLevel;
3677 smb_tran2QFileInfo_t qfi;
3685 fidp = smb_FindFID(vcp, fid, 0);
3688 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3692 lock_ObtainMutex(&fidp->mx);
3693 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3694 lock_ReleaseMutex(&fidp->mx);
3695 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3696 smb_CloseFID(vcp, fidp, NULL, 0);
3697 smb_ReleaseFID(fidp);
3700 lock_ReleaseMutex(&fidp->mx);
3702 infoLevel = p->parmsp[1];
3703 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3704 responseSize = sizeof(qfi.u.QFbasicInfo);
3705 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3706 responseSize = sizeof(qfi.u.QFstandardInfo);
3707 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3708 responseSize = sizeof(qfi.u.QFeaInfo);
3709 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3710 responseSize = sizeof(qfi.u.QFfileNameInfo);
3711 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO)
3712 responseSize = sizeof(qfi.u.QFfileStreamInfo);
3714 osi_Log2(smb_logp, "Bad Tran2QFileInfo op 0x%x infolevel 0x%x",
3715 p->opcode, infoLevel);
3716 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3717 smb_ReleaseFID(fidp);
3720 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3721 memset(&qfi, 0, sizeof(qfi));
3723 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3725 if (infoLevel > 0x100)
3726 outp->totalParms = 2;
3728 outp->totalParms = 0;
3730 userp = smb_GetTran2User(vcp, p);
3732 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3733 code = CM_ERROR_BADSMB;
3737 lock_ObtainMutex(&fidp->mx);
3738 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3740 osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3742 lock_ReleaseMutex(&fidp->mx);
3743 lock_ObtainWrite(&scp->rw);
3744 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3745 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3749 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3751 lock_ConvertWToR(&scp->rw);
3754 /* now we have the status in the cache entry, and everything is locked.
3755 * Marshall the output data.
3757 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3758 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3759 qfi.u.QFbasicInfo.creationTime = ft;
3760 qfi.u.QFbasicInfo.lastAccessTime = ft;
3761 qfi.u.QFbasicInfo.lastWriteTime = ft;
3762 qfi.u.QFbasicInfo.lastChangeTime = ft;
3763 attributes = smb_ExtAttributes(scp);
3764 qfi.u.QFbasicInfo.attributes = attributes;
3766 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3767 qfi.u.QFstandardInfo.allocationSize = scp->length;
3768 qfi.u.QFstandardInfo.endOfFile = scp->length;
3769 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3770 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3771 qfi.u.QFstandardInfo.directory =
3772 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3773 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3774 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3776 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3777 qfi.u.QFeaInfo.eaSize = 0;
3779 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3783 lock_ReleaseRead(&scp->rw);
3784 lock_ObtainMutex(&fidp->mx);
3785 lock_ObtainRead(&scp->rw);
3786 if (fidp->NTopen_wholepathp)
3787 name = fidp->NTopen_wholepathp;
3789 name = _C("\\"); /* probably can't happen */
3790 lock_ReleaseMutex(&fidp->mx);
3792 smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, SMB_STRF_IGNORENUL);
3793 responseSize = len + 4; /* this is actually what we want to return */
3794 qfi.u.QFfileNameInfo.fileNameLength = len;
3796 else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO) {
3798 /* For now we have no streams */
3799 qfi.u.QFfileStreamInfo.nextEntryOffset = 0;
3800 qfi.u.QFfileStreamInfo.streamSize = scp->length;
3801 qfi.u.QFfileStreamInfo.streamAllocationSize = scp->length;
3802 smb_UnparseString(opx, qfi.u.QFfileStreamInfo.fileName, L"::$DATA", &len, SMB_STRF_IGNORENUL);
3803 qfi.u.QFfileStreamInfo.streamNameLength = len;
3804 responseSize -= (sizeof(qfi.u.QFfileStreamInfo.fileName) - len);
3806 outp->totalData = responseSize;
3808 /* send and free the packets */
3811 lock_ReleaseRead(&scp->rw);
3813 lock_ReleaseWrite(&scp->rw);
3814 cm_ReleaseSCache(scp);
3815 cm_ReleaseUser(userp);
3816 smb_ReleaseFID(fidp);
3818 memcpy(outp->datap, &qfi, responseSize);
3819 smb_SendTran2Packet(vcp, outp, opx);
3821 smb_SendTran2Error(vcp, p, opx, code);
3823 smb_FreeTran2Packet(outp);
3829 /* TRANS2_SET_FILE_INFORMATION */
3830 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3835 unsigned short infoLevel;
3836 smb_tran2Packet_t *outp;
3837 cm_user_t *userp = NULL;
3838 cm_scache_t *scp = NULL;
3844 fidp = smb_FindFID(vcp, fid, 0);
3847 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3851 infoLevel = p->parmsp[1];
3852 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3853 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3854 osi_Log2(smb_logp, "Bad Tran2SetFileInfo op 0x%x infolevel 0x%x",
3855 p->opcode, infoLevel);
3856 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3857 smb_ReleaseFID(fidp);
3861 lock_ObtainMutex(&fidp->mx);
3862 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3863 lock_ReleaseMutex(&fidp->mx);
3864 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3865 smb_CloseFID(vcp, fidp, NULL, 0);
3866 smb_ReleaseFID(fidp);
3870 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
3871 !(fidp->flags & SMB_FID_OPENDELETE)) {
3872 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3873 fidp, fidp->scp, fidp->flags);
3874 lock_ReleaseMutex(&fidp->mx);
3875 smb_ReleaseFID(fidp);
3876 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3879 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3880 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3881 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3882 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3883 fidp, fidp->scp, fidp->flags);
3884 lock_ReleaseMutex(&fidp->mx);
3885 smb_ReleaseFID(fidp);
3886 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3891 osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3893 lock_ReleaseMutex(&fidp->mx);
3895 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3897 outp->totalParms = 2;
3898 outp->totalData = 0;
3900 userp = smb_GetTran2User(vcp, p);
3902 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3903 code = CM_ERROR_BADSMB;
3907 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3909 unsigned int attribute;
3911 smb_tran2QFileInfo_t *sfi;
3913 sfi = (smb_tran2QFileInfo_t *)p->datap;
3915 /* lock the vnode with a callback; we need the current status
3916 * to determine what the new status is, in some cases.
3918 lock_ObtainWrite(&scp->rw);
3919 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3920 CM_SCACHESYNC_GETSTATUS
3921 | CM_SCACHESYNC_NEEDCALLBACK);
3923 lock_ReleaseWrite(&scp->rw);
3927 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3929 lock_ReleaseWrite(&scp->rw);
3930 lock_ObtainMutex(&fidp->mx);
3931 lock_ObtainRead(&scp->rw);
3933 /* prepare for setattr call */
3936 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3937 /* when called as result of move a b, lastMod is (-1, -1).
3938 * If the check for -1 is not present, timestamp
3939 * of the resulting file will be 1969 (-1)
3941 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3942 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3943 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3944 cm_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3945 fidp->flags |= SMB_FID_MTIMESETDONE;
3948 attribute = sfi->u.QFbasicInfo.attributes;
3949 if (attribute != 0) {
3950 if ((scp->unixModeBits & 0222)
3951 && (attribute & SMB_ATTR_READONLY) != 0) {
3952 /* make a writable file read-only */
3953 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3954 attr.unixModeBits = scp->unixModeBits & ~0222;
3956 else if ((scp->unixModeBits & 0222) == 0
3957 && (attribute & SMB_ATTR_READONLY) == 0) {
3958 /* make a read-only file writable */
3959 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3960 attr.unixModeBits = scp->unixModeBits | 0222;
3963 lock_ReleaseRead(&scp->rw);
3964 lock_ReleaseMutex(&fidp->mx);
3968 code = cm_SetAttr(scp, &attr, userp, &req);
3972 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3973 int delflag = *((char *)(p->datap));
3974 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
3975 delflag, fidp, scp);
3976 if (*((char *)(p->datap))) { /* File is Deleted */
3977 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3980 lock_ObtainMutex(&fidp->mx);
3981 fidp->flags |= SMB_FID_DELONCLOSE;
3982 lock_ReleaseMutex(&fidp->mx);
3984 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
3990 lock_ObtainMutex(&fidp->mx);
3991 fidp->flags &= ~SMB_FID_DELONCLOSE;
3992 lock_ReleaseMutex(&fidp->mx);
3995 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3996 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3997 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
4000 attr.mask = CM_ATTRMASK_LENGTH;
4001 attr.length.LowPart = size.LowPart;
4002 attr.length.HighPart = size.HighPart;
4003 code = cm_SetAttr(scp, &attr, userp, &req);
4007 cm_ReleaseSCache(scp);
4008 cm_ReleaseUser(userp);
4009 smb_ReleaseFID(fidp);
4011 smb_SendTran2Packet(vcp, outp, opx);
4013 smb_SendTran2Error(vcp, p, opx, code);
4014 smb_FreeTran2Packet(outp);
4021 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4023 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
4024 return CM_ERROR_BADOP;
4029 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4031 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
4032 return CM_ERROR_BADOP;
4035 /* TRANS2_FIND_NOTIFY_FIRST */
4037 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4039 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
4040 return CM_ERROR_BADOP;
4043 /* TRANS2_FIND_NOTIFY_NEXT */
4045 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4047 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
4048 return CM_ERROR_BADOP;
4051 /* TRANS2_CREATE_DIRECTORY */
4053 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4055 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
4056 return CM_ERROR_BADOP;
4059 /* TRANS2_SESSION_SETUP */
4061 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4063 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
4064 return CM_ERROR_BADOP;
4067 struct smb_v2_referral {
4069 USHORT ReferralFlags;
4072 USHORT DfsPathOffset;
4073 USHORT DfsAlternativePathOffset;
4074 USHORT NetworkAddressOffset;
4077 /* TRANS2_GET_DFS_REFERRAL */
4079 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
4081 /* This is a UNICODE only request (bit15 of Flags2) */
4082 /* The TID must be IPC$ */
4084 /* The documentation for the Flags response field is contradictory */
4086 /* Use Version 1 Referral Element Format */
4087 /* ServerType = 0; indicates the next server should be queried for the file */
4088 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
4089 /* Node = UnicodeString of UNC path of the next share name */
4092 int maxReferralLevel = 0;
4093 clientchar_t requestFileName[1024] = _C("");
4094 clientchar_t referralPath[1024] = _C("");
4095 smb_tran2Packet_t *outp = 0;
4096 cm_user_t *userp = 0;
4097 cm_scache_t *scp = 0;
4098 cm_scache_t *dscp = 0;
4100 CPINFO CodePageInfo;
4101 int i, nbnLen, reqLen, refLen;
4106 maxReferralLevel = p->parmsp[0];
4108 GetCPInfo(CP_ACP, &CodePageInfo);
4109 cm_Utf16ToClientString(&p->parmsp[1], -1, requestFileName, lengthof(requestFileName));
4111 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%S]",
4112 maxReferralLevel, osi_LogSaveClientString(smb_logp, requestFileName));
4114 nbnLen = (int)cm_ClientStrLen(cm_NetbiosNameC);
4115 reqLen = (int)cm_ClientStrLen(requestFileName);
4117 if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
4118 !cm_ClientStrCmpNI(cm_NetbiosNameC, &requestFileName[1], nbnLen) &&
4119 requestFileName[nbnLen+1] == '\\')
4123 if (!cm_ClientStrCmpNI(_C("all"), &requestFileName[nbnLen+2], 3) ||
4124 !cm_ClientStrCmpNI(_C("*."), &requestFileName[nbnLen+2], 2)) {
4126 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4129 userp = smb_GetTran2User(vcp, p);
4131 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
4132 code = CM_ERROR_BADSMB;
4137 * We have a requested path. Check to see if it is something
4140 * But be careful because the name that we might be searching
4141 * for might be a known name with the final character stripped
4144 code = cm_NameI(cm_data.rootSCachep, &requestFileName[nbnLen+2],
4145 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
4146 userp, NULL, &req, &scp);
4148 code == CM_ERROR_ALLDOWN ||
4149 code == CM_ERROR_ALLBUSY ||
4150 code == CM_ERROR_ALLOFFLINE ||
4151 code == CM_ERROR_NOSUCHCELL ||
4152 code == CM_ERROR_NOSUCHVOLUME ||
4153 code == CM_ERROR_NOACCESS) {
4156 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4158 } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
4159 clientchar_t temp[1024];
4160 clientchar_t pathName[1024];
4161 clientchar_t *lastComponent;
4163 * we have a msdfs link somewhere in the path
4164 * we should figure out where in the path the link is.
4167 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%S]", requestFileName);
4169 cm_ClientStrCpy(temp, lengthof(temp), &requestFileName[nbnLen+2]);
4173 cm_ReleaseSCache(dscp);
4177 cm_ReleaseSCache(scp);
4180 smb_StripLastComponent(pathName, &lastComponent, temp);
4182 code = cm_NameI(cm_data.rootSCachep, pathName,
4183 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4184 userp, NULL, &req, &dscp);
4186 code = cm_NameI(dscp, ++lastComponent,
4188 userp, NULL, &req, &scp);
4189 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK)
4192 } while (code == CM_ERROR_PATH_NOT_COVERED);
4194 /* scp should now be the DfsLink we are looking for */
4196 /* figure out how much of the input path was used */
4197 reqLen = (int)(nbnLen+2 + cm_ClientStrLen(pathName) + 1 + cm_ClientStrLen(lastComponent));
4199 cm_FsStringToClientString(&scp->mountPointStringp[strlen("msdfs:")], -1,
4200 referralPath, lengthof(referralPath));
4201 refLen = (int)cm_ClientStrLen(referralPath);
4205 clientchar_t shareName[MAX_PATH + 1];
4206 clientchar_t *p, *q;
4207 /* we may have a sharename that is a volume reference */
4209 for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
4215 if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
4216 code = cm_NameI(cm_data.rootSCachep, _C(""),
4217 CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
4218 userp, p, &req, &scp);
4223 cm_ClientStrCpy(referralPath, lengthof(referralPath),
4234 struct smb_v2_referral * v2ref;
4235 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (refLen + 8));
4237 sp = (USHORT *)outp->datap;
4239 sp[idx++] = reqLen; /* path consumed */
4240 sp[idx++] = 1; /* number of referrals */
4241 sp[idx++] = 0x03; /* flags */
4242 #ifdef DFS_VERSION_1
4243 sp[idx++] = 1; /* Version Number */
4244 sp[idx++] = refLen + 4; /* Referral Size */
4245 sp[idx++] = 1; /* Type = SMB Server */
4246 sp[idx++] = 0; /* Do not strip path consumed */
4247 for ( i=0;i<=refLen; i++ )
4248 sp[i+idx] = referralPath[i];
4249 #else /* DFS_VERSION_2 */
4250 sp[idx++] = 2; /* Version Number */
4251 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
4252 idx += (sizeof(struct smb_v2_referral) / 2);
4253 v2ref = (struct smb_v2_referral *) &sp[5];
4254 v2ref->ServerType = 1; /* SMB Server */
4255 v2ref->ReferralFlags = 0x03;
4256 v2ref->Proximity = 0; /* closest */
4257 v2ref->TimeToLive = 3600; /* seconds */
4258 v2ref->DfsPathOffset = idx * 2;
4259 v2ref->DfsAlternativePathOffset = idx * 2;
4260 v2ref->NetworkAddressOffset = 0;
4261 for ( i=0;i<=refLen; i++ )
4262 sp[i+idx] = referralPath[i];
4265 code = CM_ERROR_NOSUCHPATH;
4268 code = CM_ERROR_NOSUCHPATH;
4273 cm_ReleaseSCache(dscp);
4275 cm_ReleaseSCache(scp);
4277 cm_ReleaseUser(userp);
4279 smb_SendTran2Packet(vcp, outp, op);
4281 smb_SendTran2Error(vcp, p, op, code);
4283 smb_FreeTran2Packet(outp);
4286 #else /* DFS_SUPPORT */
4287 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
4288 return CM_ERROR_NOSUCHDEVICE;
4289 #endif /* DFS_SUPPORT */
4292 /* TRANS2_REPORT_DFS_INCONSISTENCY */
4294 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4296 /* This is a UNICODE only request (bit15 of Flags2) */
4298 /* There is nothing we can do about this operation. The client is going to
4299 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
4300 * Unfortunately, there is really nothing we can do about it other then log it
4301 * somewhere. Even then I don't think there is anything for us to do.
4302 * So let's return an error value.
4305 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
4306 return CM_ERROR_BADOP;
4310 smb_ApplyV3DirListPatches(cm_scache_t *dscp, smb_dirListPatch_t **dirPatchespp,
4311 clientchar_t * tidPathp, clientchar_t * relPathp,
4312 int infoLevel, cm_user_t *userp, cm_req_t *reqp)
4316 cm_scache_t *targetScp; /* target if scp is a symlink */
4319 unsigned short attr;
4320 unsigned long lattr;
4321 smb_dirListPatch_t *patchp;
4322 smb_dirListPatch_t *npatchp;
4324 afs_int32 mustFake = 0;
4325 clientchar_t path[AFSPATHMAX];
4327 code = cm_FindACLCache(dscp, userp, &rights);
4329 lock_ObtainWrite(&dscp->rw);
4330 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4331 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4333 cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4334 lock_ReleaseWrite(&dscp->rw);
4335 if (code == CM_ERROR_NOACCESS) {
4343 if (!mustFake) { /* Bulk Stat */
4345 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4347 memset(bsp, 0, sizeof(cm_bulkStat_t));
4349 for (patchp = *dirPatchespp, count=0;
4351 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4352 cm_scache_t *tscp = NULL;
4355 code = cm_GetSCache(&patchp->fid, &tscp, userp, reqp);
4357 if (lock_TryWrite(&tscp->rw)) {
4358 /* we have an entry that we can look at */
4359 #ifdef AFS_FREELANCE_CLIENT
4360 if (dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID && dscp->fid.volume == AFS_FAKE_ROOT_VOL_ID) {
4361 code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
4362 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4364 cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4366 lock_ReleaseWrite(&tscp->rw);
4367 cm_ReleaseSCache(tscp);
4370 #endif /* AFS_FREELANCE_CLIENT */
4371 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4372 /* we have a callback on it. Don't bother
4373 * fetching this stat entry, since we're happy
4374 * with the info we have.
4376 lock_ReleaseWrite(&tscp->rw);
4377 cm_ReleaseSCache(tscp);
4380 lock_ReleaseWrite(&tscp->rw);
4382 cm_ReleaseSCache(tscp);
4386 bsp->fids[i].Volume = patchp->fid.volume;
4387 bsp->fids[i].Vnode = patchp->fid.vnode;
4388 bsp->fids[i].Unique = patchp->fid.unique;
4390 if (bsp->counter == AFSCBMAX) {
4391 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4392 memset(bsp, 0, sizeof(cm_bulkStat_t));
4396 if (bsp->counter > 0)
4397 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4402 for( patchp = *dirPatchespp;
4404 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4405 cm_ClientStrPrintfN(path, lengthof(path),_C("%s\\%S"),
4406 relPathp ? relPathp : _C(""), patchp->dep->name);
4407 reqp->relPathp = path;
4408 reqp->tidPathp = tidPathp;
4410 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4411 reqp->relPathp = reqp->tidPathp = NULL;
4415 lock_ObtainWrite(&scp->rw);
4416 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4417 lock_ReleaseWrite(&scp->rw);
4419 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4420 errors in the client. */
4421 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4422 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4424 /* 1969-12-31 23:59:59 +00 */
4425 ft.dwHighDateTime = 0x19DB200;
4426 ft.dwLowDateTime = 0x5BB78980;
4428 /* copy to Creation Time */
4429 fa->creationTime = ft;
4430 fa->lastAccessTime = ft;
4431 fa->lastWriteTime = ft;
4432 fa->lastChangeTime = ft;
4434 switch (scp->fileType) {
4435 case CM_SCACHETYPE_DIRECTORY:
4436 case CM_SCACHETYPE_MOUNTPOINT:
4437 case CM_SCACHETYPE_INVALID:
4438 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4440 case CM_SCACHETYPE_SYMLINK:
4441 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4442 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4444 fa->extFileAttributes = SMB_ATTR_NORMAL;
4447 /* if we get here we either have a normal file
4448 * or we have a file for which we have never
4449 * received status info. In this case, we can
4450 * check the even/odd value of the entry's vnode.
4451 * odd means it is to be treated as a directory
4452 * and even means it is to be treated as a file.
4454 if (mustFake && (scp->fid.vnode & 0x1))
4455 fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4457 fa->extFileAttributes = SMB_ATTR_NORMAL;
4459 /* merge in hidden attribute */
4460 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4461 fa->extFileAttributes |= SMB_ATTR_HIDDEN;
4464 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4466 /* 1969-12-31 23:59:58 +00*/
4467 dosTime = 0xEBBFBF7D;
4469 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4470 fa->lastAccessDateTime = fa->creationDateTime;
4471 fa->lastWriteDateTime = fa->creationDateTime;
4473 /* set the attribute */
4474 switch (scp->fileType) {
4475 case CM_SCACHETYPE_DIRECTORY:
4476 case CM_SCACHETYPE_MOUNTPOINT:
4477 case CM_SCACHETYPE_INVALID:
4478 fa->attributes = SMB_ATTR_DIRECTORY;
4480 case CM_SCACHETYPE_SYMLINK:
4481 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4482 fa->attributes = SMB_ATTR_DIRECTORY;
4484 fa->attributes = SMB_ATTR_NORMAL;
4487 /* if we get here we either have a normal file
4488 * or we have a file for which we have never
4489 * received status info. In this case, we can
4490 * check the even/odd value of the entry's vnode.
4491 * even means it is to be treated as a directory
4492 * and odd means it is to be treated as a file.
4494 if (mustFake && (scp->fid.vnode & 0x1))
4495 fa->attributes = SMB_ATTR_DIRECTORY;
4497 fa->attributes = SMB_ATTR_NORMAL;
4500 /* merge in hidden (dot file) attribute */
4501 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4502 fa->attributes |= SMB_ATTR_HIDDEN;
4506 cm_ReleaseSCache(scp);
4510 /* now watch for a symlink */
4512 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
4513 lock_ReleaseWrite(&scp->rw);
4514 cm_ClientStrPrintfN(path, lengthof(path), _C("%s\\%S"),
4515 relPathp ? relPathp : _C(""), patchp->dep->name);
4516 reqp->relPathp = path;
4517 reqp->tidPathp = tidPathp;
4518 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
4519 reqp->relPathp = reqp->tidPathp = NULL;
4521 /* we have a more accurate file to use (the
4522 * target of the symbolic link). Otherwise,
4523 * we'll just use the symlink anyway.
4525 osi_Log2(smb_logp, "symlink vp %x to vp %x",
4527 cm_ReleaseSCache(scp);
4530 lock_ObtainWrite(&scp->rw);
4533 lock_ConvertWToR(&scp->rw);
4535 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4536 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4539 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4541 fa->creationTime = ft;
4542 fa->lastAccessTime = ft;
4543 fa->lastWriteTime = ft;
4544 fa->lastChangeTime = ft;
4546 /* Use length for both file length and alloc length */
4547 fa->endOfFile = scp->length;
4548 fa->allocationSize = scp->length;
4550 /* Copy attributes */
4551 lattr = smb_ExtAttributes(scp);
4552 if ((code == CM_ERROR_NOSUCHPATH &&
4553 (scp->fileType == CM_SCACHETYPE_SYMLINK &&
4554 cm_TargetPerceivedAsDirectory(scp->mountPointStringp))) ||
4555 code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4556 if (lattr == SMB_ATTR_NORMAL)
4557 lattr = SMB_ATTR_DIRECTORY;
4559 lattr |= SMB_ATTR_DIRECTORY;
4561 /* merge in hidden (dot file) attribute */
4562 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4563 if (lattr == SMB_ATTR_NORMAL)
4564 lattr = SMB_ATTR_HIDDEN;
4566 lattr |= SMB_ATTR_HIDDEN;
4569 fa->extFileAttributes = lattr;
4571 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4574 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4576 fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
4577 fa->lastAccessDateTime = fa->creationDateTime;
4578 fa->lastWriteDateTime = fa->creationDateTime;
4580 /* copy out file length and alloc length,
4581 * using the same for both
4583 fa->dataSize = scp->length.LowPart;
4584 fa->allocationSize = scp->length.LowPart;
4586 /* finally copy out attributes as short */
4587 attr = smb_Attributes(scp);
4588 /* merge in hidden (dot file) attribute */
4589 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4590 if (lattr == SMB_ATTR_NORMAL)
4591 lattr = SMB_ATTR_HIDDEN;
4593 lattr |= SMB_ATTR_HIDDEN;
4595 fa->attributes = attr;
4598 lock_ReleaseRead(&scp->rw);
4599 cm_ReleaseSCache(scp);
4602 /* now free the patches */
4603 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4604 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4608 /* and mark the list as empty */
4609 *dirPatchespp = NULL;
4615 /* smb_ReceiveTran2SearchDir implements both
4616 * Tran2_Find_First and Tran2_Find_Next
4618 #define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
4619 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
4620 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
4621 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
4622 #define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
4624 /* this is an optimized handler for T2SearchDir that handles the case
4625 where there are no wildcards in the search path. I.e. an
4626 application is using FindFirst(Ex) to get information about a
4627 single file or directory. It will attempt to do a single lookup.
4628 If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4629 the usual mechanism.
4631 This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4633 TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
4635 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4639 long code = 0, code2 = 0;
4640 clientchar_t *pathp = 0;
4642 smb_dirListPatch_t *dirListPatchesp;
4643 smb_dirListPatch_t *curPatchp;
4644 size_t orbytes; /* # of bytes in this output record */
4645 size_t ohbytes; /* # of bytes, except file name */
4646 size_t onbytes; /* # of bytes in name, incl. term. null */
4647 cm_scache_t *scp = NULL;
4648 cm_scache_t *targetscp = NULL;
4649 cm_user_t *userp = NULL;
4650 char *op; /* output data ptr */
4651 char *origOp; /* original value of op */
4652 cm_space_t *spacep; /* for pathname buffer */
4653 unsigned long maxReturnData; /* max # of return data */
4654 long maxReturnParms; /* max # of return parms */
4655 long bytesInBuffer; /* # data bytes in the output buffer */
4656 clientchar_t *maskp; /* mask part of path */
4660 smb_tran2Packet_t *outp; /* response packet */
4661 clientchar_t *tidPathp = 0;
4663 clientchar_t shortName[13]; /* 8.3 name if needed */
4665 clientchar_t *shortNameEnd;
4666 cm_dirEntry_t * dep = NULL;
4669 void * attrp = NULL;
4670 smb_tran2Find_t * fp;
4675 osi_assertx(p->opcode == 1, "invalid opcode");
4677 /* find first; obtain basic parameters from request */
4679 /* note that since we are going to failover to regular
4680 * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4681 * modify any of the input parameters here. */
4682 attribute = p->parmsp[0];
4683 maxCount = p->parmsp[1];
4684 infoLevel = p->parmsp[3];
4685 searchFlags = p->parmsp[2];
4686 pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4688 maskp = cm_ClientStrRChr(pathp, '\\');
4692 maskp++; /* skip over backslash */
4693 /* track if this is likely to match a lot of entries */
4695 osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%S], mask[%S]",
4696 osi_LogSaveClientString(smb_logp, pathp),
4697 osi_LogSaveClientString(smb_logp, maskp));
4699 switch ( infoLevel ) {
4700 case SMB_INFO_STANDARD:
4702 ohbytes = sizeof(fp->u.FstandardInfo);
4705 case SMB_INFO_QUERY_EA_SIZE:
4706 ohbytes = sizeof(fp->u.FeaSizeInfo);
4707 s = "InfoQueryEaSize";
4710 case SMB_INFO_QUERY_EAS_FROM_LIST:
4711 ohbytes = sizeof(fp->u.FeasFromListInfo);
4712 s = "InfoQueryEasFromList";
4715 case SMB_FIND_FILE_DIRECTORY_INFO:
4716 s = "FindFileDirectoryInfo";
4717 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4720 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4721 s = "FindFileFullDirectoryInfo";
4722 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4725 case SMB_FIND_FILE_NAMES_INFO:
4726 s = "FindFileNamesInfo";
4727 ohbytes = sizeof(fp->u.FfileNamesInfo);
4730 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4731 s = "FindFileBothDirectoryInfo";
4732 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4736 s = "unknownInfoLevel";
4740 osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
4743 "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4744 attribute, infoLevel, maxCount, searchFlags);
4747 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4748 return CM_ERROR_INVAL;
4751 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4752 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4754 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4757 dirListPatchesp = NULL;
4759 maxReturnData = p->maxReturnData;
4760 maxReturnParms = 10; /* return params for findfirst, which
4761 is the only one we handle.*/
4763 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4766 osi_Log2(smb_logp, "T2SDSingle search dir count %d [%S]",
4767 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4769 /* bail out if request looks bad */
4771 smb_FreeTran2Packet(outp);
4772 return CM_ERROR_BADSMB;
4775 userp = smb_GetTran2User(vcp, p);
4777 osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
4778 smb_FreeTran2Packet(outp);
4779 return CM_ERROR_BADSMB;
4782 /* try to get the vnode for the path name next */
4783 spacep = cm_GetSpace();
4784 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4785 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4787 cm_ReleaseUser(userp);
4788 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4789 smb_FreeTran2Packet(outp);
4793 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4794 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4795 userp, tidPathp, &req, &scp);
4796 cm_FreeSpace(spacep);
4799 cm_ReleaseUser(userp);
4800 smb_SendTran2Error(vcp, p, opx, code);
4801 smb_FreeTran2Packet(outp);
4805 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4806 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4807 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
4808 cm_ReleaseSCache(scp);
4809 cm_ReleaseUser(userp);
4810 if ( WANTS_DFS_PATHNAMES(p) || pnc )
4811 code = CM_ERROR_PATH_NOT_COVERED;
4813 code = CM_ERROR_NOSUCHPATH;
4814 smb_SendTran2Error(vcp, p, opx, code);
4815 smb_FreeTran2Packet(outp);
4818 #endif /* DFS_SUPPORT */
4819 osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
4821 /* now do a single case sensitive lookup for the file in question */
4822 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
4824 /* if a case sensitive match failed, we try a case insensitive one
4826 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
4827 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
4830 if (code == 0 && targetscp->fid.vnode == 0) {
4831 cm_ReleaseSCache(targetscp);
4832 code = CM_ERROR_NOSUCHFILE;
4836 /* if we can't find the directory entry, this block will
4837 return CM_ERROR_NOSUCHFILE, which we will pass on to
4838 smb_ReceiveTran2SearchDir(). */
4839 cm_ReleaseSCache(scp);
4840 cm_ReleaseUser(userp);
4841 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4842 smb_SendTran2Error(vcp, p, opx, code);
4845 smb_FreeTran2Packet(outp);
4849 /* now that we have the target in sight, we proceed with filling
4850 up the return data. */
4852 op = origOp = outp->datap;
4855 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4856 /* skip over resume key */
4860 fp = (smb_tran2Find_t *) op;
4862 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4863 && targetscp->fid.vnode != 0
4864 && !cm_Is8Dot3(maskp)) {
4867 dfid.vnode = htonl(targetscp->fid.vnode);
4868 dfid.unique = htonl(targetscp->fid.unique);
4870 cm_Gen8Dot3NameIntW(maskp, &dfid, shortName, &shortNameEnd);
4876 osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %S (%S)",
4877 htonl(targetscp->fid.vnode),
4878 htonl(targetscp->fid.unique),
4879 osi_LogSaveClientString(smb_logp, pathp),
4880 (NeedShortName)? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
4882 /* Eliminate entries that don't match requested attributes */
4883 if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
4884 smb_IsDotFile(maskp)) {
4886 code = CM_ERROR_NOSUCHFILE;
4887 osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
4892 if (!(attribute & SMB_ATTR_DIRECTORY) &&
4893 (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
4894 targetscp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4895 targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
4896 targetscp->fileType == CM_SCACHETYPE_INVALID)) {
4898 code = CM_ERROR_NOSUCHFILE;
4899 osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
4904 /* add header to name & term. null */
4906 smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
4907 orbytes = ohbytes + onbytes;
4909 /* now, we round up the record to a 4 byte alignment, and we make
4910 * sure that we have enough room here for even the aligned version
4911 * (so we don't have to worry about an * overflow when we pad
4912 * things out below). That's the reason for the alignment
4915 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4916 align = (4 - (orbytes & 3)) & 3;
4920 if (orbytes + align > maxReturnData) {
4922 /* even though this request is unlikely to succeed with a
4923 failover, we do it anyway. */
4924 code = CM_ERROR_NOSUCHFILE;
4925 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4930 /* this is one of the entries to use: it is not deleted and it
4931 * matches the star pattern we're looking for. Put out the name,
4932 * preceded by its length.
4934 /* First zero everything else */
4935 memset(origOp, 0, orbytes);
4938 smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
4940 switch (infoLevel) {
4941 case SMB_INFO_STANDARD:
4942 fp->u.FstandardInfo.fileNameLength = onbytes;
4943 attrp = &fp->u.FstandardInfo.fileAttrs;
4946 case SMB_INFO_QUERY_EA_SIZE:
4947 fp->u.FeaSizeInfo.fileNameLength = onbytes;
4948 attrp = &fp->u.FeaSizeInfo.fileAttrs;
4949 fp->u.FeaSizeInfo.eaSize = 0;
4952 case SMB_INFO_QUERY_EAS_FROM_LIST:
4953 fp->u.FeasFromListInfo.fileNameLength = onbytes;
4954 attrp = &fp->u.FeasFromListInfo.fileAttrs;
4955 fp->u.FeasFromListInfo.eaSize = 0;
4958 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4959 if (NeedShortName) {
4963 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
4964 fp->u.FfileBothDirectoryInfo.shortName,
4965 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
4967 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
4969 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
4970 fp->u.FfileBothDirectoryInfo.reserved = 0;
4972 strcpy(fp->u.FfileBothDirectoryInfo.shortName,
4974 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
4979 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4980 fp->u.FfileFullDirectoryInfo.eaSize = 0;
4983 case SMB_FIND_FILE_DIRECTORY_INFO:
4984 fp->u.FfileDirectoryInfo.nextEntryOffset = 0;
4985 fp->u.FfileDirectoryInfo.fileIndex = 0;
4986 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
4987 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
4990 case SMB_FIND_FILE_NAMES_INFO:
4991 fp->u.FfileNamesInfo.nextEntryOffset = 0;
4992 fp->u.FfileNamesInfo.fileIndex = 0;
4993 fp->u.FfileNamesInfo.fileNameLength = onbytes;
4997 /* we shouldn't hit this case */
4998 osi_assertx(FALSE, "Unknown query type");
5001 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5002 osi_assert(attrp != NULL);
5004 curPatchp = malloc(sizeof(*curPatchp));
5005 osi_QAdd((osi_queue_t **) &dirListPatchesp,
5007 curPatchp->dptr = attrp;
5009 if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
5010 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5012 curPatchp->flags = 0;
5015 cm_SetFid(&curPatchp->fid, targetscp->fid.cell, targetscp->fid.volume, targetscp->fid.vnode, targetscp->fid.unique);
5019 int namelen = cm_ClientStringToFsString(maskp, -1, NULL, 0);
5020 dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+namelen);
5021 cm_ClientStringToFsString(maskp, -1, dep->name, namelen);
5023 dep->fid.vnode = targetscp->fid.vnode;
5024 dep->fid.unique = targetscp->fid.unique;
5025 curPatchp->dep = dep;
5028 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
5029 /* put out resume key */
5030 *((u_long *)origOp) = 0;
5033 /* Adjust byte ptr and count */
5034 origOp += orbytes; /* skip entire record */
5035 bytesInBuffer += orbytes;
5037 /* and pad the record out */
5038 while (--align >= 0) {
5043 /* apply the patches */
5044 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->wdata, infoLevel, userp, &req);
5046 outp->parmsp[0] = 0;
5047 outp->parmsp[1] = 1; /* number of names returned */
5048 outp->parmsp[2] = 1; /* end of search */
5049 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5050 outp->parmsp[4] = 0;
5052 outp->totalParms = 10; /* in bytes */
5054 outp->totalData = bytesInBuffer;
5056 osi_Log0(smb_logp, "T2SDSingle done.");
5058 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5060 smb_SendTran2Error(vcp, p, opx, code);
5062 smb_SendTran2Packet(vcp, outp, opx);
5067 smb_FreeTran2Packet(outp);
5071 cm_ReleaseSCache(scp);
5072 cm_ReleaseSCache(targetscp);
5073 cm_ReleaseUser(userp);
5079 /* TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2 */
5080 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
5085 long code = 0, code2 = 0;
5086 clientchar_t *pathp;
5087 cm_dirEntry_t *dep = 0;
5089 smb_dirListPatch_t *dirListPatchesp = 0;
5090 smb_dirListPatch_t *curPatchp = 0;
5093 size_t orbytes; /* # of bytes in this output record */
5094 size_t ohbytes; /* # of bytes, except file name */
5095 size_t onbytes; /* # of bytes in name, incl. term. null */
5096 osi_hyper_t dirLength;
5097 osi_hyper_t bufferOffset;
5098 osi_hyper_t curOffset;
5100 smb_dirSearch_t *dsp;
5104 cm_pageHeader_t *pageHeaderp;
5105 cm_user_t *userp = NULL;
5108 long nextEntryCookie;
5109 int numDirChunks; /* # of 32 byte dir chunks in this entry */
5110 char *op; /* output data ptr */
5111 char *origOp; /* original value of op */
5112 cm_space_t *spacep; /* for pathname buffer */
5113 unsigned long maxReturnData; /* max # of return data */
5114 unsigned long maxReturnParms; /* max # of return parms */
5115 long bytesInBuffer; /* # data bytes in the output buffer */
5117 clientchar_t *maskp; /* mask part of path */
5121 smb_tran2Packet_t *outp; /* response packet */
5122 clientchar_t *tidPathp;
5124 clientchar_t shortName[13]; /* 8.3 name if needed */
5127 clientchar_t *shortNameEnd;
5133 smb_tran2Find_t * fp;
5138 if (p->opcode == 1) {
5139 /* find first; obtain basic parameters from request */
5140 attribute = p->parmsp[0];
5141 maxCount = p->parmsp[1];
5142 infoLevel = p->parmsp[3];
5143 searchFlags = p->parmsp[2];
5144 pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
5146 maskp = cm_ClientStrRChr(pathp, '\\');
5150 maskp++; /* skip over backslash */
5152 /* track if this is likely to match a lot of entries */
5153 starPattern = smb_V3IsStarMask(maskp);
5155 #ifndef NOFINDFIRSTOPTIMIZE
5157 /* if this is for a single directory or file, we let the
5158 optimized routine handle it. The only error it
5159 returns is CM_ERROR_NOSUCHFILE. The */
5160 code = smb_T2SearchDirSingle(vcp, p, opx);
5162 /* we only failover if we see a CM_ERROR_NOSUCHFILE */
5163 if (code != CM_ERROR_NOSUCHFILE) {
5165 /* unless we are using the BPlusTree */
5166 if (code == CM_ERROR_BPLUS_NOMATCH)
5167 code = CM_ERROR_NOSUCHFILE;
5168 #endif /* USE_BPLUS */
5172 #endif /* NOFINDFIRSTOPTIMIZE */
5175 dsp = smb_NewDirSearch(1);
5176 dsp->attribute = attribute;
5177 cm_ClientStrCpy(dsp->mask, lengthof(dsp->mask), maskp); /* and save mask */
5180 osi_assertx(p->opcode == 2, "invalid opcode");
5181 /* find next; obtain basic parameters from request or open dir file */
5182 dsp = smb_FindDirSearch(p->parmsp[0]);
5183 maxCount = p->parmsp[1];
5184 infoLevel = p->parmsp[2];
5185 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
5186 searchFlags = p->parmsp[5];
5188 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
5189 p->parmsp[0], nextCookie);
5190 return CM_ERROR_BADFD;
5192 attribute = dsp->attribute;
5195 starPattern = 1; /* assume, since required a Find Next */
5198 switch ( infoLevel ) {
5199 case SMB_INFO_STANDARD:
5201 ohbytes = sizeof(fp->u.FstandardInfo);
5204 case SMB_INFO_QUERY_EA_SIZE:
5205 ohbytes = sizeof(fp->u.FeaSizeInfo);
5206 s = "InfoQueryEaSize";
5209 case SMB_INFO_QUERY_EAS_FROM_LIST:
5210 ohbytes = sizeof(fp->u.FeasFromListInfo);
5211 s = "InfoQueryEasFromList";
5214 case SMB_FIND_FILE_DIRECTORY_INFO:
5215 s = "FindFileDirectoryInfo";
5216 ohbytes = sizeof(fp->u.FfileDirectoryInfo);
5219 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5220 s = "FindFileFullDirectoryInfo";
5221 ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
5224 case SMB_FIND_FILE_NAMES_INFO:
5225 s = "FindFileNamesInfo";
5226 ohbytes = sizeof(fp->u.FfileNamesInfo);
5229 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5230 s = "FindFileBothDirectoryInfo";
5231 ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
5235 s = "unknownInfoLevel";
5239 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
5242 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
5243 attribute, infoLevel, maxCount, searchFlags);
5245 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
5246 p->opcode, dsp->cookie, nextCookie);
5249 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
5250 smb_ReleaseDirSearch(dsp);
5251 return CM_ERROR_INVAL;
5254 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5255 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
5257 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5260 dirListPatchesp = NULL;
5262 maxReturnData = p->maxReturnData;
5263 if (p->opcode == 1) /* find first */
5264 maxReturnParms = 10; /* bytes */
5266 maxReturnParms = 8; /* bytes */
5268 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
5274 osi_Log2(smb_logp, "T2 receive search dir count %d [%S]",
5275 maxCount, osi_LogSaveClientString(smb_logp, pathp));
5277 /* bail out if request looks bad */
5278 if (p->opcode == 1 && !pathp) {
5279 smb_ReleaseDirSearch(dsp);
5280 smb_FreeTran2Packet(outp);
5281 return CM_ERROR_BADSMB;
5284 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
5285 dsp->cookie, nextCookie, attribute);
5287 userp = smb_GetTran2User(vcp, p);
5289 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
5290 smb_ReleaseDirSearch(dsp);
5291 smb_FreeTran2Packet(outp);
5292 return CM_ERROR_BADSMB;
5295 /* try to get the vnode for the path name next */
5296 lock_ObtainMutex(&dsp->mx);
5299 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5303 spacep = cm_GetSpace();
5304 smb_StripLastComponent(spacep->wdata, NULL, pathp);
5305 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
5307 cm_ReleaseUser(userp);
5308 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
5309 smb_FreeTran2Packet(outp);
5310 lock_ReleaseMutex(&dsp->mx);
5311 smb_DeleteDirSearch(dsp);
5312 smb_ReleaseDirSearch(dsp);
5316 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
5317 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
5319 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
5320 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5321 userp, tidPathp, &req, &scp);
5322 cm_FreeSpace(spacep);
5325 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
5326 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5327 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
5328 cm_ReleaseSCache(scp);
5329 cm_ReleaseUser(userp);
5330 if ( WANTS_DFS_PATHNAMES(p) || pnc )
5331 code = CM_ERROR_PATH_NOT_COVERED;
5333 code = CM_ERROR_NOSUCHPATH;
5334 smb_SendTran2Error(vcp, p, opx, code);
5335 smb_FreeTran2Packet(outp);
5336 lock_ReleaseMutex(&dsp->mx);
5337 smb_DeleteDirSearch(dsp);
5338 smb_ReleaseDirSearch(dsp);
5341 #endif /* DFS_SUPPORT */
5343 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5344 /* we need one hold for the entry we just stored into,
5345 * and one for our own processing. When we're done
5346 * with this function, we'll drop the one for our own
5347 * processing. We held it once from the namei call,
5348 * and so we do another hold now.
5351 dsp->flags |= SMB_DIRSEARCH_BULKST;
5354 lock_ReleaseMutex(&dsp->mx);
5356 cm_ReleaseUser(userp);
5357 smb_FreeTran2Packet(outp);
5358 smb_DeleteDirSearch(dsp);
5359 smb_ReleaseDirSearch(dsp);
5363 /* get the directory size */
5364 lock_ObtainWrite(&scp->rw);
5365 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5366 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5368 lock_ReleaseWrite(&scp->rw);
5369 cm_ReleaseSCache(scp);
5370 cm_ReleaseUser(userp);
5371 smb_FreeTran2Packet(outp);
5372 smb_DeleteDirSearch(dsp);
5373 smb_ReleaseDirSearch(dsp);
5377 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5380 dirLength = scp->length;
5382 bufferOffset.LowPart = bufferOffset.HighPart = 0;
5383 curOffset.HighPart = 0;
5384 curOffset.LowPart = nextCookie;
5385 origOp = outp->datap;
5392 normchar_t normName[MAX_PATH]; /* Normalized name */
5393 clientchar_t cfileName[MAX_PATH]; /* Non-normalized name */
5396 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5397 /* skip over resume key */
5400 fp = (smb_tran2Find_t *) op;
5402 /* make sure that curOffset.LowPart doesn't point to the first
5403 * 32 bytes in the 2nd through last dir page, and that it doesn't
5404 * point at the first 13 32-byte chunks in the first dir page,
5405 * since those are dir and page headers, and don't contain useful
5408 temp = curOffset.LowPart & (2048-1);
5409 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5410 /* we're in the first page */
5411 if (temp < 13*32) temp = 13*32;
5414 /* we're in a later dir page */
5415 if (temp < 32) temp = 32;
5418 /* make sure the low order 5 bits are zero */
5421 /* now put temp bits back ito curOffset.LowPart */
5422 curOffset.LowPart &= ~(2048-1);
5423 curOffset.LowPart |= temp;
5425 /* check if we've passed the dir's EOF */
5426 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
5427 osi_Log0(smb_logp, "T2 search dir passed eof");
5432 /* check if we've returned all the names that will fit in the
5433 * response packet; we check return count as well as the number
5434 * of bytes requested. We check the # of bytes after we find
5435 * the dir entry, since we'll need to check its size.
5437 if (returnedNames >= maxCount) {
5438 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
5439 returnedNames, maxCount);
5443 /* when we have obtained as many entries as can be processed in
5444 * a single Bulk Status call to the file server, apply the dir listing
5447 if (returnedNames > 0 && returnedNames % AFSCBMAX == 0) {
5448 lock_ReleaseWrite(&scp->rw);
5449 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5450 dsp->relPath, infoLevel, userp, &req);
5451 lock_ObtainWrite(&scp->rw);
5453 /* Then check to see if we have time left to process more entries */
5454 if (GetTickCount() - req.startTime > (RDRtimeout - 15) * 1000) {
5455 osi_Log0(smb_logp, "T2 search dir RDRtimeout exceeded");
5459 /* see if we can use the bufferp we have now; compute in which
5460 * page the current offset would be, and check whether that's
5461 * the offset of the buffer we have. If not, get the buffer.
5463 thyper.HighPart = curOffset.HighPart;
5464 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5465 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5468 buf_Release(bufferp);
5471 lock_ReleaseWrite(&scp->rw);
5472 code = buf_Get(scp, &thyper, &req, &bufferp);
5473 lock_ObtainWrite(&scp->rw);
5475 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
5479 bufferOffset = thyper;
5481 /* now get the data in the cache */
5483 code = cm_SyncOp(scp, bufferp, userp, &req,
5485 CM_SCACHESYNC_NEEDCALLBACK
5486 | CM_SCACHESYNC_READ);
5488 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5492 if (cm_HaveBuffer(scp, bufferp, 0)) {
5493 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5494 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5498 /* otherwise, load the buffer and try again */
5499 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5501 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5503 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5504 scp, bufferp, code);
5509 buf_Release(bufferp);
5513 } /* if (wrong buffer) ... */
5515 /* now we have the buffer containing the entry we're interested
5516 * in; copy it out if it represents a non-deleted entry.
5518 entryInDir = curOffset.LowPart & (2048-1);
5519 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5521 /* page header will help tell us which entries are free. Page
5522 * header can change more often than once per buffer, since
5523 * AFS 3 dir page size may be less than (but not more than)
5524 * a buffer package buffer.
5526 /* only look intra-buffer */
5527 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5528 temp &= ~(2048 - 1); /* turn off intra-page bits */
5529 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5531 /* now determine which entry we're looking at in the page.
5532 * If it is free (there's a free bitmap at the start of the
5533 * dir), we should skip these 32 bytes.
5535 slotInPage = (entryInDir & 0x7e0) >> 5;
5536 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5537 (1 << (slotInPage & 0x7)))) {
5538 /* this entry is free */
5539 numDirChunks = 1; /* only skip this guy */
5543 tp = bufferp->datap + entryInBuffer;
5544 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5546 /* while we're here, compute the next entry's location, too,
5547 * since we'll need it when writing out the cookie into the dir
5550 * XXXX Probably should do more sanity checking.
5552 numDirChunks = cm_NameEntries(dep->name, &onbytes);
5554 /* compute offset of cookie representing next entry */
5555 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5557 if (dep->fid.vnode == 0)
5558 goto nextEntry; /* This entry is not in use */
5560 if (cm_FsStringToClientString(dep->name, -1, cfileName, lengthof(cfileName)) == 0 ||
5561 cm_ClientStringToNormString(cfileName, -1, normName, lengthof(normName)) == 0) {
5563 osi_Log1(smb_logp, "Skipping entry [%s]. Can't convert or normalize FS String",
5564 osi_LogSaveString(smb_logp, dep->name));
5568 /* Need 8.3 name? */
5570 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
5571 !cm_Is8Dot3(cfileName)) {
5572 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5576 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %S (%S)",
5577 dep->fid.vnode, dep->fid.unique,
5578 osi_LogSaveClientString(smb_logp, cfileName),
5579 NeedShortName ? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
5581 /* When matching, we are using doing a case fold if we have a wildcard mask.
5582 * If we get a non-wildcard match, it's a lookup for a specific file.
5584 if (cm_MatchMask(normName, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5585 (NeedShortName && cm_MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))
5587 /* Eliminate entries that don't match requested attributes */
5588 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5589 smb_IsDotFile(cfileName)) {
5590 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5591 goto nextEntry; /* no hidden files */
5594 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5596 /* We have already done the cm_TryBulkStat above */
5597 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume,
5598 ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5599 fileType = cm_FindFileType(&fid);
5600 /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5601 * "has filetype %d", dep->name, fileType);
5603 if ( fileType == CM_SCACHETYPE_DIRECTORY ||
5604 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5605 fileType == CM_SCACHETYPE_DFSLINK ||
5606 fileType == CM_SCACHETYPE_INVALID)
5607 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5611 /* finally check if this name will fit */
5613 smb_UnparseString(opx, NULL, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5614 orbytes = ohbytes + onbytes;
5616 /* now, we round up the record to a 4 byte alignment,
5617 * and we make sure that we have enough room here for
5618 * even the aligned version (so we don't have to worry
5619 * about an overflow when we pad things out below).
5620 * That's the reason for the alignment arithmetic below.
5622 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5623 align = (4 - (orbytes & 3)) & 3;
5627 if (orbytes + bytesInBuffer + align > maxReturnData) {
5628 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5633 /* this is one of the entries to use: it is not deleted
5634 * and it matches the star pattern we're looking for.
5635 * Put out the name, preceded by its length.
5637 /* First zero everything else */
5638 memset(origOp, 0, orbytes);
5641 smb_UnparseString(opx, origOp + ohbytes, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5643 switch (infoLevel) {
5644 case SMB_INFO_STANDARD:
5645 fp->u.FstandardInfo.fileNameLength = onbytes;
5646 attrp = &fp->u.FstandardInfo.fileAttrs;
5649 case SMB_INFO_QUERY_EA_SIZE:
5650 fp->u.FeaSizeInfo.fileNameLength = onbytes;
5651 attrp = &fp->u.FeaSizeInfo.fileAttrs;
5652 fp->u.FeaSizeInfo.eaSize = 0;
5655 case SMB_INFO_QUERY_EAS_FROM_LIST:
5656 fp->u.FeasFromListInfo.fileNameLength = onbytes;
5657 attrp = &fp->u.FeasFromListInfo.fileAttrs;
5658 fp->u.FeasFromListInfo.eaSize = 0;
5661 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5662 if (NeedShortName) {
5666 nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
5667 fp->u.FfileBothDirectoryInfo.shortName,
5668 sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
5670 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
5672 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5673 fp->u.FfileBothDirectoryInfo.reserved = 0;
5675 cm_ClientStrCpy(fp->u.FfileBothDirectoryInfo.shortName,
5676 lengthof(fp->u.FfileBothDirectoryInfo.shortName),
5678 fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
5683 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5684 fp->u.FfileFullDirectoryInfo.eaSize = 0;
5687 case SMB_FIND_FILE_DIRECTORY_INFO:
5688 fp->u.FfileDirectoryInfo.nextEntryOffset = orbytes + align;
5689 fp->u.FfileDirectoryInfo.fileIndex = nextEntryCookie;
5690 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5691 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5694 case SMB_FIND_FILE_NAMES_INFO:
5695 fp->u.FfileNamesInfo.nextEntryOffset = orbytes + align;
5696 fp->u.FfileNamesInfo.fileIndex = nextEntryCookie;
5697 fp->u.FfileNamesInfo.fileNameLength = onbytes;
5702 /* we shouldn't hit this case */
5703 osi_assertx(FALSE, "Unknown query type");
5706 /* now, adjust the # of entries copied */
5709 /* now we emit the attribute. This is tricky, since
5710 * we need to really stat the file to find out what
5711 * type of entry we've got. Right now, we're copying
5712 * out data from a buffer, while holding the scp
5713 * locked, so it isn't really convenient to stat
5714 * something now. We'll put in a place holder
5715 * now, and make a second pass before returning this
5716 * to get the real attributes. So, we just skip the
5717 * data for now, and adjust it later. We allocate a
5718 * patch record to make it easy to find this point
5719 * later. The replay will happen at a time when it is
5720 * safe to unlock the directory.
5722 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5723 osi_assert(attrp != NULL);
5724 curPatchp = malloc(sizeof(*curPatchp));
5725 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5726 curPatchp->dptr = attrp;
5728 if (smb_hideDotFiles && smb_IsDotFile(cfileName)) {
5729 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5731 curPatchp->flags = 0;
5734 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5737 curPatchp->dep = dep;
5740 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5741 /* put out resume key */
5742 *((u_long *)origOp) = nextEntryCookie;
5744 /* Adjust byte ptr and count */
5745 origOp += orbytes; /* skip entire record */
5746 bytesInBuffer += orbytes;
5748 /* and pad the record out */
5749 while (align-- > 0) {
5753 } /* if we're including this name */
5754 else if (!starPattern &&
5756 cm_MatchMask(normName, maskp, CM_FLAG_CASEFOLD)) {
5757 /* We were looking for exact matches, but here's an inexact one*/
5762 /* and adjust curOffset to be where the new cookie is */
5763 thyper.HighPart = 0;
5764 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5765 curOffset = LargeIntegerAdd(thyper, curOffset);
5766 } /* while copying data for dir listing */
5768 /* If we didn't get a star pattern, we did an exact match during the first pass.
5769 * If there were no exact matches found, we fail over to inexact matches by
5770 * marking the query as a star pattern (matches all case permutations), and
5771 * re-running the query.
5773 if (returnedNames == 0 && !starPattern && foundInexact) {
5774 osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
5779 /* release the mutex */
5780 lock_ReleaseWrite(&scp->rw);
5782 buf_Release(bufferp);
5787 * Finally, process whatever entries we have left.
5789 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5790 dsp->relPath, infoLevel, userp, &req);
5792 /* now put out the final parameters */
5793 if (returnedNames == 0)
5795 if (p->opcode == 1) {
5797 outp->parmsp[0] = (unsigned short) dsp->cookie;
5798 outp->parmsp[1] = returnedNames;
5799 outp->parmsp[2] = eos;
5800 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5801 outp->parmsp[4] = 0;
5802 /* don't need last name to continue
5803 * search, cookie is enough. Normally,
5804 * this is the offset of the file name
5805 * of the last entry returned.
5807 outp->totalParms = 10; /* in bytes */
5811 outp->parmsp[0] = returnedNames;
5812 outp->parmsp[1] = eos;
5813 outp->parmsp[2] = 0; /* EAS error */
5814 outp->parmsp[3] = 0; /* last name, as above */
5815 outp->totalParms = 8; /* in bytes */
5818 /* return # of bytes in the buffer */
5819 outp->totalData = bytesInBuffer;
5821 /* Return error code if unsuccessful on first request */
5822 if (code == 0 && p->opcode == 1 && returnedNames == 0)
5823 code = CM_ERROR_NOSUCHFILE;
5825 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
5826 p->opcode, dsp->cookie, returnedNames, code);
5828 /* if we're supposed to close the search after this request, or if
5829 * we're supposed to close the search if we're done, and we're done,
5830 * or if something went wrong, close the search.
5832 if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
5833 (returnedNames == 0) ||
5834 ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
5836 smb_DeleteDirSearch(dsp);
5839 smb_SendTran2Error(vcp, p, opx, code);
5841 smb_SendTran2Packet(vcp, outp, opx);
5843 smb_FreeTran2Packet(outp);
5844 smb_ReleaseDirSearch(dsp);
5845 cm_ReleaseSCache(scp);
5846 cm_ReleaseUser(userp);
5850 /* SMB_COM_FIND_CLOSE2 */
5851 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5854 smb_dirSearch_t *dsp;
5856 dirHandle = smb_GetSMBParm(inp, 0);
5858 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
5860 dsp = smb_FindDirSearch(dirHandle);
5863 return CM_ERROR_BADFD;
5865 /* otherwise, we have an FD to destroy */
5866 smb_DeleteDirSearch(dsp);
5867 smb_ReleaseDirSearch(dsp);
5869 /* and return results */
5870 smb_SetSMBDataLength(outp, 0);
5876 /* SMB_COM_FIND_NOTIFY_CLOSE */
5877 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5879 smb_SetSMBDataLength(outp, 0);
5883 /* SMB_COM_OPEN_ANDX */
5884 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5886 clientchar_t *pathp;
5891 cm_scache_t *dscp; /* dir we're dealing with */
5892 cm_scache_t *scp; /* file we're creating */
5894 int initialModeBits;
5897 clientchar_t *lastNamep;
5898 unsigned long dosTime;
5904 int parmSlot; /* which parm we're dealing with */
5905 clientchar_t *tidPathp;
5908 BOOL is_rpc = FALSE;
5909 BOOL is_ipc = FALSE;
5915 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
5916 openFun = smb_GetSMBParm(inp, 8); /* open function */
5917 excl = ((openFun & 3) == 0);
5918 trunc = ((openFun & 3) == 2); /* truncate it */
5919 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
5920 openAction = 0; /* tracks what we did */
5922 attributes = smb_GetSMBParm(inp, 5);
5923 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
5925 /* compute initial mode bits based on read-only flag in attributes */
5926 initialModeBits = 0666;
5927 if (attributes & SMB_ATTR_READONLY)
5928 initialModeBits &= ~0222;
5930 pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
5933 return CM_ERROR_BADSMB;
5935 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5937 if (code == CM_ERROR_TIDIPC) {
5940 return CM_ERROR_NOSUCHPATH;
5944 spacep = inp->spacep;
5945 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5949 /* special case magic file name for receiving IOCTL requests
5950 * (since IOCTL calls themselves aren't getting through).
5952 (cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0 ||
5954 /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional) */
5955 (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
5957 unsigned short file_type = 0;
5958 unsigned short device_state = 0;
5960 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5962 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
5963 osi_Log1(smb_logp, "OpenAndX Setting up RPC on fid[%d]", fidp->fid);
5965 osi_Log1(smb_logp, "smb_SetupRPCFid failure code [%d]", code);
5966 smb_ReleaseFID(fidp);
5970 smb_SetupIoctlFid(fidp, spacep);
5971 osi_Log1(smb_logp, "OpenAndX Setting up IOCTL on fid[%d]", fidp->fid);
5974 /* set inp->fid so that later read calls in same msg can find fid */
5975 inp->fid = fidp->fid;
5977 /* copy out remainder of the parms */
5979 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5981 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
5982 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
5983 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5984 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
5985 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
5986 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5987 smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++;
5988 smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++;
5990 /* and the final "always present" stuff */
5991 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
5992 /* next write out the "unique" ID */
5993 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
5994 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
5995 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5996 smb_SetSMBDataLength(outp, 0);
5998 /* and clean up fid reference */
5999 smb_ReleaseFID(fidp);
6005 osi_Log0(smb_logp, "NTOpenX rejecting IPC TID");
6006 return CM_ERROR_BADFD;
6010 if (!cm_IsValidClientString(pathp)) {
6012 clientchar_t * hexp;
6014 hexp = cm_GetRawCharsAlloc(pathp, -1);
6015 osi_Log1(smb_logp, "NTOpenX rejecting invalid name. [%S]",
6016 osi_LogSaveClientString(smb_logp, hexp));
6020 osi_Log0(smb_logp, "NTOpenX rejecting invalid name");
6022 return CM_ERROR_BADNTFILENAME;
6025 #ifdef DEBUG_VERBOSE
6027 char *hexp, *asciip;
6028 asciip = (lastNamep ? lastNamep : pathp );
6029 hexp = osi_HexifyString(asciip);
6030 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
6034 userp = smb_GetUserFromVCP(vcp, inp);
6037 code = cm_NameI(cm_data.rootSCachep, pathp,
6038 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6039 userp, tidPathp, &req, &scp);
6042 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6043 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
6044 cm_ReleaseSCache(scp);
6045 cm_ReleaseUser(userp);
6046 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6047 return CM_ERROR_PATH_NOT_COVERED;
6049 return CM_ERROR_NOSUCHPATH;
6051 #endif /* DFS_SUPPORT */
6054 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
6055 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6056 userp, tidPathp, &req, &dscp);
6058 cm_ReleaseUser(userp);
6063 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6064 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
6066 cm_ReleaseSCache(dscp);
6067 cm_ReleaseUser(userp);
6068 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6069 return CM_ERROR_PATH_NOT_COVERED;
6071 return CM_ERROR_NOSUCHPATH;
6073 #endif /* DFS_SUPPORT */
6074 /* otherwise, scp points to the parent directory. Do a lookup,
6075 * and truncate the file if we find it, otherwise we create the
6082 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
6084 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
6085 cm_ReleaseSCache(dscp);
6086 cm_ReleaseUser(userp);
6091 /* if we get here, if code is 0, the file exists and is represented by
6092 * scp. Otherwise, we have to create it. The dir may be represented
6093 * by dscp, or we may have found the file directly. If code is non-zero,
6097 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
6099 if (dscp) cm_ReleaseSCache(dscp);
6100 cm_ReleaseSCache(scp);
6101 cm_ReleaseUser(userp);
6106 /* oops, file shouldn't be there */
6108 cm_ReleaseSCache(dscp);
6109 cm_ReleaseSCache(scp);
6110 cm_ReleaseUser(userp);
6111 return CM_ERROR_EXISTS;
6115 setAttr.mask = CM_ATTRMASK_LENGTH;
6116 setAttr.length.LowPart = 0;
6117 setAttr.length.HighPart = 0;
6118 code = cm_SetAttr(scp, &setAttr, userp, &req);
6119 openAction = 3; /* truncated existing file */
6121 else openAction = 1; /* found existing file */
6123 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
6124 /* don't create if not found */
6125 if (dscp) cm_ReleaseSCache(dscp);
6126 cm_ReleaseUser(userp);
6127 return CM_ERROR_NOSUCHFILE;
6130 osi_assertx(dscp != NULL, "null cm_scache_t");
6131 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %S",
6132 osi_LogSaveClientString(smb_logp, lastNamep));
6133 openAction = 2; /* created file */
6134 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6135 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6136 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6140 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6141 smb_NotifyChange(FILE_ACTION_ADDED,
6142 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6143 dscp, lastNamep, NULL, TRUE);
6144 } else if (!excl && code == CM_ERROR_EXISTS) {
6145 /* not an exclusive create, and someone else tried
6146 * creating it already, then we open it anyway. We
6147 * don't bother retrying after this, since if this next
6148 * fails, that means that the file was deleted after we
6149 * started this call.
6151 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6155 setAttr.mask = CM_ATTRMASK_LENGTH;
6156 setAttr.length.LowPart = 0;
6157 setAttr.length.HighPart = 0;
6158 code = cm_SetAttr(scp, &setAttr, userp, &req);
6160 } /* lookup succeeded */
6164 /* we don't need this any longer */
6166 cm_ReleaseSCache(dscp);
6169 /* something went wrong creating or truncating the file */
6171 cm_ReleaseSCache(scp);
6172 cm_ReleaseUser(userp);
6176 /* make sure we're about to open a file */
6177 if (scp->fileType != CM_SCACHETYPE_FILE) {
6178 cm_ReleaseSCache(scp);
6179 cm_ReleaseUser(userp);
6180 return CM_ERROR_ISDIR;
6183 /* now all we have to do is open the file itself */
6184 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6185 osi_assertx(fidp, "null smb_fid_t");
6188 lock_ObtainMutex(&fidp->mx);
6189 /* save a pointer to the vnode */
6191 lock_ObtainWrite(&scp->rw);
6192 scp->flags |= CM_SCACHEFLAG_SMB_FID;
6193 lock_ReleaseWrite(&scp->rw);
6194 osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
6196 fidp->userp = userp;
6198 /* compute open mode */
6200 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
6201 if (openMode == 1 || openMode == 2)
6202 fidp->flags |= SMB_FID_OPENWRITE;
6204 /* remember if the file was newly created */
6206 fidp->flags |= SMB_FID_CREATED;
6208 lock_ReleaseMutex(&fidp->mx);
6209 smb_ReleaseFID(fidp);
6211 cm_Open(scp, 0, userp);
6213 /* set inp->fid so that later read calls in same msg can find fid */
6214 inp->fid = fidp->fid;
6216 /* copy out remainder of the parms */
6218 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6219 lock_ObtainRead(&scp->rw);
6221 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
6222 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
6223 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
6224 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
6225 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
6226 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
6227 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
6228 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
6229 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
6231 /* and the final "always present" stuff */
6232 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
6233 /* next write out the "unique" ID */
6234 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
6235 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
6236 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6237 lock_ReleaseRead(&scp->rw);
6238 smb_SetSMBDataLength(outp, 0);
6240 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
6242 cm_ReleaseUser(userp);
6243 /* leave scp held since we put it in fidp->scp */
6247 static void smb_GetLockParams(unsigned char LockType,
6249 unsigned int * ppid,
6250 LARGE_INTEGER * pOffset,
6251 LARGE_INTEGER * pLength)
6253 if (LockType & LOCKING_ANDX_LARGE_FILES) {
6255 *ppid = *((USHORT *) *buf);
6256 pOffset->HighPart = *((LONG *)(*buf + 4));
6257 pOffset->LowPart = *((DWORD *)(*buf + 8));
6258 pLength->HighPart = *((LONG *)(*buf + 12));
6259 pLength->LowPart = *((DWORD *)(*buf + 16));
6263 /* Not Large Files */
6264 *ppid = *((USHORT *) *buf);
6265 pOffset->HighPart = 0;
6266 pOffset->LowPart = *((DWORD *)(*buf + 2));
6267 pLength->HighPart = 0;
6268 pLength->LowPart = *((DWORD *)(*buf + 6));
6273 /* SMB_COM_LOCKING_ANDX */
6274 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6281 unsigned char LockType;
6282 unsigned short NumberOfUnlocks, NumberOfLocks;
6286 LARGE_INTEGER LOffset, LLength;
6287 smb_waitingLockRequest_t *wlRequest = NULL;
6288 cm_file_lock_t *lockp;
6296 fid = smb_GetSMBParm(inp, 2);
6297 fid = smb_ChainFID(fid, inp);
6299 fidp = smb_FindFID(vcp, fid, 0);
6301 return CM_ERROR_BADFD;
6303 lock_ObtainMutex(&fidp->mx);
6304 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6305 lock_ReleaseMutex(&fidp->mx);
6306 smb_CloseFID(vcp, fidp, NULL, 0);
6307 smb_ReleaseFID(fidp);
6308 return CM_ERROR_NOSUCHFILE;
6311 if (fidp->flags & SMB_FID_IOCTL) {
6312 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
6313 lock_ReleaseMutex(&fidp->mx);
6314 smb_ReleaseFID(fidp);
6315 return CM_ERROR_BADFD;
6318 osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
6320 lock_ReleaseMutex(&fidp->mx);
6322 /* set inp->fid so that later read calls in same msg can find fid */
6325 userp = smb_GetUserFromVCP(vcp, inp);
6327 lock_ObtainWrite(&scp->rw);
6328 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6329 CM_SCACHESYNC_NEEDCALLBACK
6330 | CM_SCACHESYNC_GETSTATUS
6331 | CM_SCACHESYNC_LOCK);
6333 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
6337 LockType = smb_GetSMBParm(inp, 3) & 0xff;
6338 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
6339 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
6340 NumberOfLocks = smb_GetSMBParm(inp, 7);
6342 if (!(fidp->flags & SMB_FID_OPENWRITE) &&
6343 !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
6344 /* somebody wants exclusive locks on a file that they only
6345 opened for reading. We downgrade this to a shared lock. */
6346 osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
6347 LockType |= LOCKING_ANDX_SHARED_LOCK;
6350 if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
6351 /* AFS does not support atomic changes of lock types from read or write and vice-versa */
6352 osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]");
6353 code = CM_ERROR_BADOP;
6358 op = smb_GetSMBData(inp, NULL);
6360 if (LockType & LOCKING_ANDX_CANCEL_LOCK) {
6361 /* Cancel outstanding lock requests */
6362 smb_waitingLock_t * wl;
6364 for (i=0; i<NumberOfLocks; i++) {
6365 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6367 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6369 lock_ObtainWrite(&smb_globalLock);
6370 for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
6372 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
6373 if (cm_KeyEquals(&wl->key, &key, 0) && LargeIntegerEqualTo(wl->LOffset, LOffset) &&
6374 LargeIntegerEqualTo(wl->LLength, LLength)) {
6375 wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
6376 goto found_lock_request;
6381 lock_ReleaseWrite(&smb_globalLock);
6384 smb_SetSMBDataLength(outp, 0);
6389 for (i=0; i<NumberOfUnlocks; i++) {
6390 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6392 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6394 code = cm_Unlock(scp, LockType, LOffset, LLength, key, 0, userp, &req);
6402 for (i=0; i<NumberOfLocks; i++) {
6403 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6405 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6407 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
6408 userp, &req, &lockp);
6410 if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
6411 (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
6413 code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
6414 userp, &req, &lockp);
6417 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
6418 smb_waitingLock_t * wLock;
6420 /* Put on waiting list */
6421 if(wlRequest == NULL) {
6425 LARGE_INTEGER tOffset, tLength;
6427 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
6429 osi_assertx(wlRequest != NULL, "null wlRequest");
6431 wlRequest->vcp = vcp;
6433 wlRequest->scp = scp;
6434 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
6436 wlRequest->inp = smb_CopyPacket(inp);
6437 wlRequest->outp = smb_CopyPacket(outp);
6438 wlRequest->lockType = LockType;
6439 wlRequest->msTimeout = Timeout;
6440 wlRequest->start_t = osi_Time();
6441 wlRequest->locks = NULL;
6443 /* The waiting lock request needs to have enough
6444 information to undo all the locks in the request.
6445 We do the following to store info about locks that
6446 have already been granted. Sure, we can get most
6447 of the info from the packet, but the packet doesn't
6448 hold the result of cm_Lock call. In practice we
6449 only receive packets with one or two locks, so we
6450 are only wasting a few bytes here and there and
6451 only for a limited period of time until the waiting
6452 lock times out or is freed. */
6454 for(opt = op_locks, j=i; j > 0; j--) {
6455 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
6457 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6459 wLock = malloc(sizeof(smb_waitingLock_t));
6461 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6464 wLock->LOffset = tOffset;
6465 wLock->LLength = tLength;
6466 wLock->lockp = NULL;
6467 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
6468 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6473 wLock = malloc(sizeof(smb_waitingLock_t));
6475 osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6478 wLock->LOffset = LOffset;
6479 wLock->LLength = LLength;
6480 wLock->lockp = lockp;
6481 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
6482 osi_QAdd((osi_queue_t **) &wlRequest->locks,
6485 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
6493 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
6500 /* Since something went wrong with the lock number i, we now
6501 have to go ahead and release any locks acquired before the
6502 failure. All locks before lock number i (of which there
6503 are i of them) have either been successful or are waiting.
6504 Either case requires calling cm_Unlock(). */
6506 /* And purge the waiting lock */
6507 if(wlRequest != NULL) {
6508 smb_waitingLock_t * wl;
6509 smb_waitingLock_t * wlNext;
6512 for(wl = wlRequest->locks; wl; wl = wlNext) {
6514 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
6516 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, 0, userp, &req);
6519 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
6521 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
6524 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
6529 smb_ReleaseVC(wlRequest->vcp);
6530 cm_ReleaseSCache(wlRequest->scp);
6531 smb_FreePacket(wlRequest->inp);
6532 smb_FreePacket(wlRequest->outp);
6541 if (wlRequest != NULL) {
6543 lock_ObtainWrite(&smb_globalLock);
6544 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
6546 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
6547 lock_ReleaseWrite(&smb_globalLock);
6549 /* don't send reply immediately */
6550 outp->flags |= SMB_PACKETFLAG_NOSEND;
6553 smb_SetSMBDataLength(outp, 0);
6557 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
6560 lock_ReleaseWrite(&scp->rw);
6561 cm_ReleaseSCache(scp);
6562 cm_ReleaseUser(userp);
6563 smb_ReleaseFID(fidp);
6568 /* SMB_COM_QUERY_INFORMATION2 */
6569 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6575 afs_uint32 searchTime;
6582 fid = smb_GetSMBParm(inp, 0);
6583 fid = smb_ChainFID(fid, inp);
6585 fidp = smb_FindFID(vcp, fid, 0);
6587 return CM_ERROR_BADFD;
6589 lock_ObtainMutex(&fidp->mx);
6590 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6591 lock_ReleaseMutex(&fidp->mx);
6592 smb_CloseFID(vcp, fidp, NULL, 0);
6593 smb_ReleaseFID(fidp);
6594 return CM_ERROR_NOSUCHFILE;
6597 if (fidp->flags & SMB_FID_IOCTL) {
6598 lock_ReleaseMutex(&fidp->mx);
6599 smb_ReleaseFID(fidp);
6600 return CM_ERROR_BADFD;
6603 osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6605 lock_ReleaseMutex(&fidp->mx);
6607 userp = smb_GetUserFromVCP(vcp, inp);
6610 /* otherwise, stat the file */
6611 lock_ObtainWrite(&scp->rw);
6612 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6613 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6617 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6619 lock_ConvertWToR(&scp->rw);
6622 /* decode times. We need a search time, but the response to this
6623 * call provides the date first, not the time, as returned in the
6624 * searchTime variable. So we take the high-order bits first.
6626 cm_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
6627 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
6628 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
6629 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
6630 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
6631 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
6632 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
6634 /* now handle file size and allocation size */
6635 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
6636 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
6637 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
6638 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
6640 /* file attribute */
6641 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
6643 /* and finalize stuff */
6644 smb_SetSMBDataLength(outp, 0);
6649 lock_ReleaseRead(&scp->rw);
6651 lock_ReleaseWrite(&scp->rw);
6652 cm_ReleaseSCache(scp);
6653 cm_ReleaseUser(userp);
6654 smb_ReleaseFID(fidp);
6658 /* SMB_COM_SET_INFORMATION2 */
6659 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6665 afs_uint32 searchTime;
6673 fid = smb_GetSMBParm(inp, 0);
6674 fid = smb_ChainFID(fid, inp);
6676 fidp = smb_FindFID(vcp, fid, 0);
6678 return CM_ERROR_BADFD;
6680 lock_ObtainMutex(&fidp->mx);
6681 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6682 lock_ReleaseMutex(&fidp->mx);
6683 smb_CloseFID(vcp, fidp, NULL, 0);
6684 smb_ReleaseFID(fidp);
6685 return CM_ERROR_NOSUCHFILE;
6688 if (fidp->flags & SMB_FID_IOCTL) {
6689 lock_ReleaseMutex(&fidp->mx);
6690 smb_ReleaseFID(fidp);
6691 return CM_ERROR_BADFD;
6694 osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6696 lock_ReleaseMutex(&fidp->mx);
6698 userp = smb_GetUserFromVCP(vcp, inp);
6700 /* now prepare to call cm_setattr. This message only sets various times,
6701 * and AFS only implements mtime, and we'll set the mtime if that's
6702 * requested. The others we'll ignore.
6704 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
6706 if (searchTime != 0) {
6707 cm_UnixTimeFromSearchTime(&unixTime, searchTime);
6709 if ( unixTime != -1 ) {
6710 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
6711 attrs.clientModTime = unixTime;
6712 code = cm_SetAttr(scp, &attrs, userp, &req);
6714 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
6716 osi_Log1(smb_logp, "**cm_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
6722 cm_ReleaseSCache(scp);
6723 cm_ReleaseUser(userp);
6724 smb_ReleaseFID(fidp);
6728 /* SMB_COM_WRITE_ANDX */
6729 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6732 long count, written = 0, total_written = 0;
6736 smb_t *smbp = (smb_t*) inp;
6741 int inDataBlockCount;
6743 fd = smb_GetSMBParm(inp, 2);
6744 count = smb_GetSMBParm(inp, 10);
6746 offset.HighPart = 0;
6747 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6749 if (*inp->wctp == 14) {
6750 /* we have a request with 64-bit file offsets */
6751 #ifdef AFS_LARGEFILES
6752 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6754 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6756 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
6757 /* we shouldn't have received this op if we didn't specify
6758 largefile support */
6759 return CM_ERROR_BADOP;
6764 op = inp->data + smb_GetSMBParm(inp, 11);
6765 inDataBlockCount = count;
6767 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
6768 fd, offset.HighPart, offset.LowPart, count);
6770 fd = smb_ChainFID(fd, inp);
6771 fidp = smb_FindFID(vcp, fd, 0);
6773 return CM_ERROR_BADFD;
6775 lock_ObtainMutex(&fidp->mx);
6776 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6777 lock_ReleaseMutex(&fidp->mx);
6778 smb_CloseFID(vcp, fidp, NULL, 0);
6779 smb_ReleaseFID(fidp);
6780 return CM_ERROR_NOSUCHFILE;
6783 if (fidp->flags & SMB_FID_IOCTL) {
6784 lock_ReleaseMutex(&fidp->mx);
6785 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
6786 smb_ReleaseFID(fidp);
6790 if (fidp->flags & SMB_FID_RPC) {
6791 lock_ReleaseMutex(&fidp->mx);
6792 code = smb_RPCV3Write(fidp, vcp, inp, outp);
6793 smb_ReleaseFID(fidp);
6798 lock_ReleaseMutex(&fidp->mx);
6799 smb_ReleaseFID(fidp);
6800 return CM_ERROR_BADFDOP;
6805 lock_ReleaseMutex(&fidp->mx);
6807 userp = smb_GetUserFromVCP(vcp, inp);
6809 /* special case: 0 bytes transferred means there is no data
6810 transferred. A slight departure from SMB_COM_WRITE where this
6811 means that we are supposed to truncate the file at this
6816 LARGE_INTEGER LOffset;
6817 LARGE_INTEGER LLength;
6820 key = cm_GenerateKey(vcp->vcID, pid, fd);
6822 LOffset.HighPart = offset.HighPart;
6823 LOffset.LowPart = offset.LowPart;
6824 LLength.HighPart = 0;
6825 LLength.LowPart = count;
6827 lock_ObtainWrite(&scp->rw);
6828 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
6829 lock_ReleaseWrite(&scp->rw);
6836 * Work around bug in NT client
6838 * When copying a file, the NT client should first copy the data,
6839 * then copy the last write time. But sometimes the NT client does
6840 * these in the wrong order, so the data copies would inadvertently
6841 * cause the last write time to be overwritten. We try to detect this,
6842 * and don't set client mod time if we think that would go against the
6845 lock_ObtainMutex(&fidp->mx);
6846 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6847 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6848 scp->clientModTime = time(NULL);
6850 lock_ReleaseMutex(&fidp->mx);
6853 while ( code == 0 && count > 0 ) {
6854 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6855 if (code == 0 && written == 0)
6856 code = CM_ERROR_PARTIALWRITE;
6858 offset = LargeIntegerAdd(offset,
6859 ConvertLongToLargeInteger(written));
6861 total_written += written;
6865 /* slots 0 and 1 are reserved for request chaining and will be
6866 filled in when we return. */
6867 smb_SetSMBParm(outp, 2, total_written);
6868 smb_SetSMBParm(outp, 3, 0); /* reserved */
6869 smb_SetSMBParm(outp, 4, 0); /* reserved */
6870 smb_SetSMBParm(outp, 5, 0); /* reserved */
6871 smb_SetSMBDataLength(outp, 0);
6875 cm_ReleaseSCache(scp);
6876 cm_ReleaseUser(userp);
6877 smb_ReleaseFID(fidp);
6882 /* SMB_COM_READ_ANDX */
6883 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6887 long finalCount = 0;
6891 smb_t *smbp = (smb_t*) inp;
6898 fd = smb_GetSMBParm(inp, 2); /* File ID */
6899 count = smb_GetSMBParm(inp, 5); /* MaxCount */
6900 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6902 if (*inp->wctp == 12) {
6903 /* a request with 64-bit offsets */
6904 #ifdef AFS_LARGEFILES
6905 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
6907 if (LargeIntegerLessThanZero(offset)) {
6908 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
6909 offset.HighPart, offset.LowPart);
6910 return CM_ERROR_BADSMB;
6913 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
6914 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
6915 return CM_ERROR_BADSMB;
6917 offset.HighPart = 0;
6921 offset.HighPart = 0;
6924 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
6925 fd, offset.HighPart, offset.LowPart, count);
6927 fd = smb_ChainFID(fd, inp);
6928 fidp = smb_FindFID(vcp, fd, 0);
6930 return CM_ERROR_BADFD;
6933 lock_ObtainMutex(&fidp->mx);
6935 if (fidp->flags & SMB_FID_IOCTL) {
6936 lock_ReleaseMutex(&fidp->mx);
6938 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
6939 smb_ReleaseFID(fidp);
6943 if (fidp->flags & SMB_FID_RPC) {
6944 lock_ReleaseMutex(&fidp->mx);
6946 code = smb_RPCV3Read(fidp, vcp, inp, outp);
6947 smb_ReleaseFID(fidp);
6951 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6952 lock_ReleaseMutex(&fidp->mx);
6953 smb_CloseFID(vcp, fidp, NULL, 0);
6954 smb_ReleaseFID(fidp);
6955 return CM_ERROR_NOSUCHFILE;
6959 lock_ReleaseMutex(&fidp->mx);
6960 smb_ReleaseFID(fidp);
6961 return CM_ERROR_BADFDOP;
6967 lock_ReleaseMutex(&fidp->mx);
6970 key = cm_GenerateKey(vcp->vcID, pid, fd);
6972 LARGE_INTEGER LOffset, LLength;
6974 LOffset.HighPart = offset.HighPart;
6975 LOffset.LowPart = offset.LowPart;
6976 LLength.HighPart = 0;
6977 LLength.LowPart = count;
6979 lock_ObtainWrite(&scp->rw);
6980 code = cm_LockCheckRead(scp, LOffset, LLength, key);
6981 lock_ReleaseWrite(&scp->rw);
6983 cm_ReleaseSCache(scp);
6986 smb_ReleaseFID(fidp);
6990 /* set inp->fid so that later read calls in same msg can find fid */
6993 userp = smb_GetUserFromVCP(vcp, inp);
6995 /* 0 and 1 are reserved for request chaining, were setup by our caller,
6996 * and will be further filled in after we return.
6998 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
6999 smb_SetSMBParm(outp, 3, 0); /* resvd */
7000 smb_SetSMBParm(outp, 4, 0); /* resvd */
7001 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
7002 /* fill in #6 when we have all the parameters' space reserved */
7003 smb_SetSMBParm(outp, 7, 0); /* resv'd */
7004 smb_SetSMBParm(outp, 8, 0); /* resv'd */
7005 smb_SetSMBParm(outp, 9, 0); /* resv'd */
7006 smb_SetSMBParm(outp, 10, 0); /* resv'd */
7007 smb_SetSMBParm(outp, 11, 0); /* reserved */
7009 /* get op ptr after putting in the parms, since otherwise we don't
7010 * know where the data really is.
7012 op = smb_GetSMBData(outp, NULL);
7014 /* now fill in offset from start of SMB header to first data byte (to op) */
7015 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
7017 /* set the packet data length the count of the # of bytes */
7018 smb_SetSMBDataLength(outp, count);
7020 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7022 /* fix some things up */
7023 smb_SetSMBParm(outp, 5, finalCount);
7024 smb_SetSMBDataLength(outp, finalCount);
7026 cm_ReleaseUser(userp);
7027 smb_ReleaseFID(fidp);
7032 * Values for createDisp, copied from NTDDK.H
7034 #define FILE_SUPERSEDE 0 // (???)
7035 #define FILE_OPEN 1 // (open)
7036 #define FILE_CREATE 2 // (exclusive)
7037 #define FILE_OPEN_IF 3 // (non-exclusive)
7038 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
7039 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
7042 #define REQUEST_OPLOCK 2
7043 #define REQUEST_BATCH_OPLOCK 4
7044 #define OPEN_DIRECTORY 8
7045 #define EXTENDED_RESPONSE_REQUIRED 0x10
7047 /* CreateOptions field. */
7048 #define FILE_DIRECTORY_FILE 0x0001
7049 #define FILE_WRITE_THROUGH 0x0002
7050 #define FILE_SEQUENTIAL_ONLY 0x0004
7051 #define FILE_NON_DIRECTORY_FILE 0x0040
7052 #define FILE_NO_EA_KNOWLEDGE 0x0200
7053 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
7054 #define FILE_RANDOM_ACCESS 0x0800
7055 #define FILE_DELETE_ON_CLOSE 0x1000
7056 #define FILE_OPEN_BY_FILE_ID 0x2000
7057 #define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000
7058 #define FILE_NO_COMPRESSION 0x00008000
7059 #define FILE_RESERVE_OPFILTER 0x00100000
7060 #define FILE_OPEN_REPARSE_POINT 0x00200000
7061 #define FILE_OPEN_NO_RECALL 0x00400000
7062 #define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000
7064 /* SMB_COM_NT_CREATE_ANDX */
7065 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7067 clientchar_t *pathp, *realPathp;
7071 cm_scache_t *dscp; /* parent dir */
7072 cm_scache_t *scp; /* file to create or open */
7073 cm_scache_t *targetScp; /* if scp is a symlink */
7075 clientchar_t *lastNamep;
7076 clientchar_t *treeStartp;
7077 unsigned short nameLength;
7079 unsigned int requestOpLock;
7080 unsigned int requestBatchOpLock;
7081 unsigned int mustBeDir;
7082 unsigned int extendedRespRequired;
7083 unsigned int treeCreate;
7085 unsigned int desiredAccess;
7086 unsigned int extAttributes;
7087 unsigned int createDisp;
7088 unsigned int createOptions;
7089 unsigned int shareAccess;
7090 int initialModeBits;
7091 unsigned short baseFid;
7092 smb_fid_t *baseFidp;
7094 cm_scache_t *baseDirp;
7095 unsigned short openAction;
7100 clientchar_t *tidPathp;
7105 int checkDoneRequired = 0;
7106 cm_lock_data_t *ldp = NULL;
7107 BOOL is_rpc = FALSE;
7108 BOOL is_ipc = FALSE;
7112 /* This code is very long and has a lot of if-then-else clauses
7113 * scp and dscp get reused frequently and we need to ensure that
7114 * we don't lose a reference. Start by ensuring that they are NULL.
7121 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
7122 flags = smb_GetSMBOffsetParm(inp, 3, 1)
7123 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
7124 requestOpLock = flags & REQUEST_OPLOCK;
7125 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7126 mustBeDir = flags & OPEN_DIRECTORY;
7127 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7130 * Why all of a sudden 32-bit FID?
7131 * We will reject all bits higher than 16.
7133 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
7134 return CM_ERROR_INVAL;
7135 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
7136 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
7137 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
7138 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
7139 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
7140 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
7141 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
7142 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
7143 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
7144 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
7145 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
7147 /* mustBeDir is never set; createOptions directory bit seems to be
7150 if (createOptions & FILE_DIRECTORY_FILE)
7152 else if (createOptions & FILE_NON_DIRECTORY_FILE)
7158 * compute initial mode bits based on read-only flag in
7159 * extended attributes
7161 initialModeBits = 0666;
7162 if (extAttributes & SMB_ATTR_READONLY)
7163 initialModeBits &= ~0222;
7165 pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
7166 NULL, SMB_STRF_ANSIPATH);
7168 /* Sometimes path is not null-terminated, so we make a copy. */
7169 realPathp = malloc(nameLength+sizeof(clientchar_t));
7170 memcpy(realPathp, pathp, nameLength+sizeof(clientchar_t));
7171 realPathp[nameLength/sizeof(clientchar_t)] = 0;
7173 spacep = inp->spacep;
7174 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
7176 osi_Log1(smb_logp,"NTCreateX for [%S]",osi_LogSaveClientString(smb_logp,realPathp));
7177 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
7178 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%S]", shareAccess, flags, osi_LogSaveClientString(smb_logp,(lastNamep?lastNamep:_C("null"))));
7182 baseDirp = cm_data.rootSCachep;
7183 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7184 if (code == CM_ERROR_TIDIPC) {
7185 /* Attempt to use a TID allocated for IPC. The client
7186 * is probably looking for DCE RPC end points which we
7187 * don't support OR it could be looking to make a DFS
7190 osi_Log0(smb_logp, "NTCreateX received IPC TID");
7195 osi_Log1(smb_logp, "NTCreateX tidPathp=[%S]", (tidPathp==NULL)?_C("null"): osi_LogSaveClientString(smb_logp,tidPathp));
7199 ((is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)) ||
7201 /* special case magic file name for receiving IOCTL requests
7202 * (since IOCTL calls themselves aren't getting through).
7204 cm_ClientStrCmpIA(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0)) {
7206 unsigned short file_type = 0;
7207 unsigned short device_state = 0;
7209 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7212 code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
7213 osi_Log1(smb_logp, "NTCreateX Setting up RPC on fid[%d]", fidp->fid);
7215 osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
7216 smb_ReleaseFID(fidp);
7221 smb_SetupIoctlFid(fidp, spacep);
7222 osi_Log1(smb_logp, "NTCreateX Setting up IOCTL on fid[%d]", fidp->fid);
7225 /* set inp->fid so that later read calls in same msg can find fid */
7226 inp->fid = fidp->fid;
7230 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7231 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7232 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
7234 memset(&ft, 0, sizeof(ft));
7235 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7236 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7237 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7238 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7239 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
7240 sz.HighPart = 0x7fff; sz.LowPart = 0;
7241 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
7242 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
7243 smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++; /* filetype */
7244 smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++; /* dev state */
7245 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
7246 smb_SetSMBDataLength(outp, 0);
7248 /* clean up fid reference */
7249 smb_ReleaseFID(fidp);
7256 osi_Log0(smb_logp, "NTCreateX rejecting IPC TID");
7258 return CM_ERROR_BADFD;
7262 if (!cm_IsValidClientString(realPathp)) {
7264 clientchar_t * hexp;
7266 hexp = cm_GetRawCharsAlloc(realPathp, -1);
7267 osi_Log1(smb_logp, "NTCreateX rejecting invalid name. [%S]",
7268 osi_LogSaveClientString(smb_logp, hexp));
7272 osi_Log0(smb_logp, "NTCreateX rejecting invalid name");
7275 return CM_ERROR_BADNTFILENAME;
7278 userp = smb_GetUserFromVCP(vcp, inp);
7280 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
7282 return CM_ERROR_INVAL;
7285 if (baseFidp != 0) {
7286 baseFidp = smb_FindFID(vcp, baseFid, 0);
7288 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
7289 cm_ReleaseUser(userp);
7291 return CM_ERROR_INVAL;
7294 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7296 smb_CloseFID(vcp, baseFidp, NULL, 0);
7297 smb_ReleaseFID(baseFidp);
7298 cm_ReleaseUser(userp);
7299 return CM_ERROR_NOSUCHPATH;
7302 baseDirp = baseFidp->scp;
7306 /* compute open mode */
7308 if (desiredAccess & DELETE)
7309 fidflags |= SMB_FID_OPENDELETE;
7310 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
7311 fidflags |= SMB_FID_OPENREAD_LISTDIR;
7312 if (desiredAccess & AFS_ACCESS_WRITE)
7313 fidflags |= SMB_FID_OPENWRITE;
7314 if (createOptions & FILE_DELETE_ON_CLOSE)
7315 fidflags |= SMB_FID_DELONCLOSE;
7316 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7317 fidflags |= SMB_FID_SEQUENTIAL;
7318 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7319 fidflags |= SMB_FID_RANDOM;
7320 if (createOptions & FILE_OPEN_REPARSE_POINT)
7321 osi_Log0(smb_logp, "NTCreateX Open Reparse Point");
7322 if (smb_IsExecutableFileName(lastNamep))
7323 fidflags |= SMB_FID_EXECUTABLE;
7325 /* and the share mode */
7326 if (shareAccess & FILE_SHARE_READ)
7327 fidflags |= SMB_FID_SHARE_READ;
7328 if (shareAccess & FILE_SHARE_WRITE)
7329 fidflags |= SMB_FID_SHARE_WRITE;
7331 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
7334 /* For an exclusive create, we want to do a case sensitive match for the last component. */
7335 if ( createDisp == FILE_CREATE ||
7336 createDisp == FILE_OVERWRITE ||
7337 createDisp == FILE_OVERWRITE_IF) {
7338 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7339 userp, tidPathp, &req, &dscp);
7342 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7343 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7345 cm_ReleaseSCache(dscp);
7346 cm_ReleaseUser(userp);
7349 smb_ReleaseFID(baseFidp);
7350 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7351 return CM_ERROR_PATH_NOT_COVERED;
7353 return CM_ERROR_NOSUCHPATH;
7355 #endif /* DFS_SUPPORT */
7356 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7358 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7359 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7360 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7361 if (code == 0 && realDirFlag == 1) {
7362 cm_ReleaseSCache(scp);
7363 cm_ReleaseSCache(dscp);
7364 cm_ReleaseUser(userp);
7367 smb_ReleaseFID(baseFidp);
7368 return CM_ERROR_EXISTS;
7372 /* we have both scp and dscp */
7374 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7375 userp, tidPathp, &req, &scp);
7377 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7378 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7379 cm_ReleaseSCache(scp);
7380 cm_ReleaseUser(userp);
7383 smb_ReleaseFID(baseFidp);
7384 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7385 return CM_ERROR_PATH_NOT_COVERED;
7387 return CM_ERROR_NOSUCHPATH;
7389 #endif /* DFS_SUPPORT */
7390 /* we might have scp but not dscp */
7396 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7397 /* look up parent directory */
7398 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
7399 * the immediate parent. We have to work our way up realPathp until we hit something that we
7403 /* we might or might not have scp */
7409 code = cm_NameI(baseDirp, spacep->wdata,
7410 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7411 userp, tidPathp, &req, &dscp);
7414 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7415 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7418 cm_ReleaseSCache(scp);
7419 cm_ReleaseSCache(dscp);
7420 cm_ReleaseUser(userp);
7423 smb_ReleaseFID(baseFidp);
7424 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7425 return CM_ERROR_PATH_NOT_COVERED;
7427 return CM_ERROR_NOSUCHPATH;
7429 #endif /* DFS_SUPPORT */
7432 (tp = cm_ClientStrRChr(spacep->wdata, '\\')) &&
7433 (createDisp == FILE_CREATE) &&
7434 (realDirFlag == 1)) {
7437 treeStartp = realPathp + (tp - spacep->wdata);
7439 if (*tp && !smb_IsLegalFilename(tp)) {
7440 cm_ReleaseUser(userp);
7442 smb_ReleaseFID(baseFidp);
7445 cm_ReleaseSCache(scp);
7446 return CM_ERROR_BADNTFILENAME;
7450 } while (dscp == NULL && code == 0);
7454 /* we might have scp and we might have dscp */
7457 smb_ReleaseFID(baseFidp);
7460 osi_Log0(smb_logp,"NTCreateX parent not found");
7462 cm_ReleaseSCache(scp);
7464 cm_ReleaseSCache(dscp);
7465 cm_ReleaseUser(userp);
7470 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
7471 /* A file exists where we want a directory. */
7473 cm_ReleaseSCache(scp);
7474 cm_ReleaseSCache(dscp);
7475 cm_ReleaseUser(userp);
7477 return CM_ERROR_EXISTS;
7481 lastNamep = realPathp;
7485 if (!smb_IsLegalFilename(lastNamep)) {
7487 cm_ReleaseSCache(scp);
7489 cm_ReleaseSCache(dscp);
7490 cm_ReleaseUser(userp);
7492 return CM_ERROR_BADNTFILENAME;
7495 if (!foundscp && !treeCreate) {
7496 if ( createDisp == FILE_CREATE ||
7497 createDisp == FILE_OVERWRITE ||
7498 createDisp == FILE_OVERWRITE_IF)
7500 code = cm_Lookup(dscp, lastNamep,
7501 CM_FLAG_FOLLOW, userp, &req, &scp);
7503 code = cm_Lookup(dscp, lastNamep,
7504 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7507 if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
7509 cm_ReleaseSCache(dscp);
7510 cm_ReleaseUser(userp);
7515 /* we have scp and dscp */
7517 /* we have scp but not dscp */
7519 smb_ReleaseFID(baseFidp);
7522 /* if we get here, if code is 0, the file exists and is represented by
7523 * scp. Otherwise, we have to create it. The dir may be represented
7524 * by dscp, or we may have found the file directly. If code is non-zero,
7527 if (code == 0 && !treeCreate) {
7528 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7530 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7532 cm_ReleaseSCache(dscp);
7534 cm_ReleaseSCache(scp);
7535 cm_ReleaseUser(userp);
7539 checkDoneRequired = 1;
7541 if (createDisp == FILE_CREATE) {
7542 /* oops, file shouldn't be there */
7543 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7545 cm_ReleaseSCache(dscp);
7547 cm_ReleaseSCache(scp);
7548 cm_ReleaseUser(userp);
7550 return CM_ERROR_EXISTS;
7553 if ( createDisp == FILE_OVERWRITE ||
7554 createDisp == FILE_OVERWRITE_IF) {
7556 setAttr.mask = CM_ATTRMASK_LENGTH;
7557 setAttr.length.LowPart = 0;
7558 setAttr.length.HighPart = 0;
7559 /* now watch for a symlink */
7561 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7563 osi_assertx(dscp != NULL, "null cm_scache_t");
7564 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7566 /* we have a more accurate file to use (the
7567 * target of the symbolic link). Otherwise,
7568 * we'll just use the symlink anyway.
7570 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7572 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7573 cm_ReleaseSCache(scp);
7575 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7577 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7579 cm_ReleaseSCache(dscp);
7581 cm_ReleaseSCache(scp);
7582 cm_ReleaseUser(userp);
7588 code = cm_SetAttr(scp, &setAttr, userp, &req);
7589 openAction = 3; /* truncated existing file */
7592 openAction = 1; /* found existing file */
7594 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7595 /* don't create if not found */
7597 cm_ReleaseSCache(dscp);
7599 cm_ReleaseSCache(scp);
7600 cm_ReleaseUser(userp);
7602 return CM_ERROR_NOSUCHFILE;
7603 } else if (realDirFlag == 0 || realDirFlag == -1) {
7604 osi_assertx(dscp != NULL, "null cm_scache_t");
7605 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %S",
7606 osi_LogSaveClientString(smb_logp, lastNamep));
7607 openAction = 2; /* created file */
7608 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7609 setAttr.clientModTime = time(NULL);
7610 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
7613 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7614 smb_NotifyChange(FILE_ACTION_ADDED,
7615 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7616 dscp, lastNamep, NULL, TRUE);
7617 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7618 /* Not an exclusive create, and someone else tried
7619 * creating it already, then we open it anyway. We
7620 * don't bother retrying after this, since if this next
7621 * fails, that means that the file was deleted after we
7622 * started this call.
7624 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7627 if (createDisp == FILE_OVERWRITE_IF) {
7628 setAttr.mask = CM_ATTRMASK_LENGTH;
7629 setAttr.length.LowPart = 0;
7630 setAttr.length.HighPart = 0;
7632 /* now watch for a symlink */
7634 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7636 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7638 /* we have a more accurate file to use (the
7639 * target of the symbolic link). Otherwise,
7640 * we'll just use the symlink anyway.
7642 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7644 cm_ReleaseSCache(scp);
7648 code = cm_SetAttr(scp, &setAttr, userp, &req);
7650 } /* lookup succeeded */
7653 clientchar_t *tp, *pp;
7654 clientchar_t *cp; /* This component */
7655 int clen = 0; /* length of component */
7656 cm_scache_t *tscp1, *tscp2;
7659 /* create directory */
7661 treeStartp = lastNamep;
7662 osi_assertx(dscp != NULL, "null cm_scache_t");
7663 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%S]",
7664 osi_LogSaveClientString(smb_logp, treeStartp));
7665 openAction = 2; /* created directory */
7667 /* if the request is to create the root directory
7668 * it will appear as a directory name of the nul-string
7669 * and a code of CM_ERROR_NOSUCHFILE
7671 if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
7672 code = CM_ERROR_EXISTS;
7674 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7675 setAttr.clientModTime = time(NULL);
7680 cm_HoldSCache(tscp1);
7684 tp = cm_ClientStrChr(pp, '\\');
7686 cm_ClientStrCpy(cp, lengthof(spacep->wdata) - (cp - spacep->wdata), pp);
7687 clen = (int)cm_ClientStrLen(cp);
7688 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
7690 clen = (int)(tp - pp);
7691 cm_ClientStrCpyN(cp, lengthof(spacep->wdata) - (cp - spacep->wdata),
7699 continue; /* the supplied path can't have consecutive slashes either , but */
7701 /* cp is the next component to be created. */
7702 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req, NULL);
7703 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
7704 smb_NotifyChange(FILE_ACTION_ADDED,
7705 FILE_NOTIFY_CHANGE_DIR_NAME,
7706 tscp1, cp, NULL, TRUE);
7708 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7709 /* Not an exclusive create, and someone else tried
7710 * creating it already, then we open it anyway. We
7711 * don't bother retrying after this, since if this next
7712 * fails, that means that the file was deleted after we
7713 * started this call.
7715 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
7716 userp, &req, &tscp2);
7721 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
7722 cm_ReleaseSCache(tscp1);
7723 tscp1 = tscp2; /* Newly created directory will be next parent */
7724 /* the hold is transfered to tscp1 from tscp2 */
7729 cm_ReleaseSCache(dscp);
7732 cm_ReleaseSCache(scp);
7735 * if we get here and code == 0, then scp is the last directory created, and dscp is the
7741 /* something went wrong creating or truncating the file */
7742 if (checkDoneRequired)
7743 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7745 cm_ReleaseSCache(scp);
7747 cm_ReleaseSCache(dscp);
7748 cm_ReleaseUser(userp);
7753 /* make sure we have file vs. dir right (only applies for single component case) */
7754 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7755 /* now watch for a symlink */
7757 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7758 cm_scache_t * targetScp = 0;
7759 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7761 /* we have a more accurate file to use (the
7762 * target of the symbolic link). Otherwise,
7763 * we'll just use the symlink anyway.
7765 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
7766 if (checkDoneRequired) {
7767 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7768 checkDoneRequired = 0;
7770 cm_ReleaseSCache(scp);
7775 if (scp->fileType != CM_SCACHETYPE_FILE) {
7776 if (checkDoneRequired)
7777 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7779 cm_ReleaseSCache(dscp);
7780 cm_ReleaseSCache(scp);
7781 cm_ReleaseUser(userp);
7783 return CM_ERROR_ISDIR;
7787 /* (only applies to single component case) */
7788 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7789 if (checkDoneRequired)
7790 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7791 cm_ReleaseSCache(scp);
7793 cm_ReleaseSCache(dscp);
7794 cm_ReleaseUser(userp);
7796 return CM_ERROR_NOTDIR;
7799 /* open the file itself */
7800 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7801 osi_assertx(fidp, "null smb_fid_t");
7803 /* save a reference to the user */
7805 fidp->userp = userp;
7807 /* If we are restricting sharing, we should do so with a suitable
7809 if (scp->fileType == CM_SCACHETYPE_FILE &&
7810 !(fidflags & SMB_FID_SHARE_WRITE)) {
7812 LARGE_INTEGER LOffset, LLength;
7815 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7816 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7817 LLength.HighPart = 0;
7818 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7820 /* If we are not opening the file for writing, then we don't
7821 try to get an exclusive lock. No one else should be able to
7822 get an exclusive lock on the file anyway, although someone
7823 else can get a shared lock. */
7824 if ((fidflags & SMB_FID_SHARE_READ) ||
7825 !(fidflags & SMB_FID_OPENWRITE)) {
7826 sLockType = LOCKING_ANDX_SHARED_LOCK;
7831 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7833 lock_ObtainWrite(&scp->rw);
7834 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7835 lock_ReleaseWrite(&scp->rw);
7838 if (checkDoneRequired)
7839 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7840 cm_ReleaseSCache(scp);
7842 cm_ReleaseSCache(dscp);
7843 cm_ReleaseUser(userp);
7844 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7845 smb_CloseFID(vcp, fidp, NULL, 0);
7846 smb_ReleaseFID(fidp);
7852 /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
7853 if (checkDoneRequired) {
7854 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7855 checkDoneRequired = 0;
7858 lock_ObtainMutex(&fidp->mx);
7859 /* save a pointer to the vnode */
7860 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
7861 lock_ObtainWrite(&scp->rw);
7862 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7863 lock_ReleaseWrite(&scp->rw);
7864 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
7866 fidp->flags = fidflags;
7868 /* remember if the file was newly created */
7870 fidp->flags |= SMB_FID_CREATED;
7872 /* save parent dir and pathname for delete or change notification */
7873 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7874 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
7875 fidp->flags |= SMB_FID_NTOPEN;
7876 fidp->NTopen_dscp = dscp;
7878 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
7880 fidp->NTopen_wholepathp = realPathp;
7881 lock_ReleaseMutex(&fidp->mx);
7883 /* we don't need this any longer */
7885 cm_ReleaseSCache(dscp);
7889 cm_Open(scp, 0, userp);
7891 /* set inp->fid so that later read calls in same msg can find fid */
7892 inp->fid = fidp->fid;
7894 lock_ObtainRead(&scp->rw);
7896 /* check whether we are required to send an extended response */
7897 if (!extendedRespRequired) {
7900 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7901 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7902 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7903 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7904 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7905 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7906 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7907 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7908 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7910 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7911 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7912 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
7913 smb_SetSMBParm(outp, parmSlot, NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS);
7914 parmSlot++; /* dev state */
7915 smb_SetSMBParmByte(outp, parmSlot,
7916 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7917 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7918 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7919 smb_SetSMBDataLength(outp, 70);
7923 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7924 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7925 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7926 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7927 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7928 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7929 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7930 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7931 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7933 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7934 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7935 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
7936 smb_SetSMBParm(outp, parmSlot, NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS);
7937 parmSlot++; /* dev state */
7938 smb_SetSMBParmByte(outp, parmSlot,
7939 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7940 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7941 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7942 /* Setting the GUID results in a failure with cygwin */
7943 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7944 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7945 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7946 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7947 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7948 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7949 /* Maxmimal access rights */
7950 smb_SetSMBParmLong(outp, parmSlot, 0x001f01ff); parmSlot += 2;
7951 /* Guest access rights */
7952 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7953 smb_SetSMBDataLength(outp, 105);
7956 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
7957 LargeIntegerGreaterThanZero(scp->length) &&
7958 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
7961 lock_ReleaseRead(&scp->rw);
7964 cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
7965 scp->length.LowPart, scp->length.HighPart,
7969 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %S", fidp->fid,
7970 osi_LogSaveClientString(smb_logp, realPathp));
7972 cm_ReleaseUser(userp);
7973 smb_ReleaseFID(fidp);
7975 /* Can't free realPathp if we get here since
7976 fidp->NTopen_wholepathp is pointing there */
7978 /* leave scp held since we put it in fidp->scp */
7983 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
7984 * Instead, ultimately, would like to use a subroutine for common code.
7987 /* NT_TRANSACT_CREATE (SMB_COM_NT_TRANSACT) */
7988 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7990 clientchar_t *pathp, *realPathp;
7994 cm_scache_t *dscp; /* parent dir */
7995 cm_scache_t *scp; /* file to create or open */
7996 cm_scache_t *targetScp; /* if scp is a symlink */
7998 clientchar_t *lastNamep;
7999 unsigned long nameLength;
8001 unsigned int requestOpLock;
8002 unsigned int requestBatchOpLock;
8003 unsigned int mustBeDir;
8004 unsigned int extendedRespRequired;
8006 unsigned int desiredAccess;
8007 unsigned int allocSize;
8008 unsigned int shareAccess;
8009 unsigned int extAttributes;
8010 unsigned int createDisp;
8013 unsigned int impLevel;
8014 unsigned int secFlags;
8015 unsigned int createOptions;
8016 int initialModeBits;
8017 unsigned short baseFid;
8018 smb_fid_t *baseFidp;
8020 cm_scache_t *baseDirp;
8021 unsigned short openAction;
8025 clientchar_t *tidPathp;
8027 int parmOffset, dataOffset;
8034 cm_lock_data_t *ldp = NULL;
8035 int checkDoneRequired = 0;
8042 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8043 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8044 parmp = inp->data + parmOffset;
8045 lparmp = (ULONG *) parmp;
8048 requestOpLock = flags & REQUEST_OPLOCK;
8049 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
8050 mustBeDir = flags & OPEN_DIRECTORY;
8051 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
8054 * Why all of a sudden 32-bit FID?
8055 * We will reject all bits higher than 16.
8057 if (lparmp[1] & 0xFFFF0000)
8058 return CM_ERROR_INVAL;
8059 baseFid = (unsigned short)lparmp[1];
8060 desiredAccess = lparmp[2];
8061 allocSize = lparmp[3];
8062 extAttributes = lparmp[5];
8063 shareAccess = lparmp[6];
8064 createDisp = lparmp[7];
8065 createOptions = lparmp[8];
8068 nameLength = lparmp[11]; /* spec says chars but appears to be bytes */
8069 impLevel = lparmp[12];
8070 secFlags = lparmp[13];
8072 /* mustBeDir is never set; createOptions directory bit seems to be
8075 if (createOptions & FILE_DIRECTORY_FILE)
8077 else if (createOptions & FILE_NON_DIRECTORY_FILE)
8083 * compute initial mode bits based on read-only flag in
8084 * extended attributes
8086 initialModeBits = 0666;
8087 if (extAttributes & SMB_ATTR_READONLY)
8088 initialModeBits &= ~0222;
8090 pathp = smb_ParseStringCb(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
8091 nameLength, NULL, SMB_STRF_ANSIPATH);
8092 /* Sometimes path is not nul-terminated, so we make a copy. */
8093 realPathp = malloc(nameLength+sizeof(clientchar_t));
8094 memcpy(realPathp, pathp, nameLength);
8095 realPathp[nameLength/sizeof(clientchar_t)] = 0;
8096 spacep = cm_GetSpace();
8097 smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
8099 osi_Log1(smb_logp,"NTTranCreate %S",osi_LogSaveStringW(smb_logp,realPathp));
8100 osi_Log4(smb_logp,"... da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
8101 osi_Log4(smb_logp,"... co[%x],sdl[%x],eal[%x],as[%x],flags[%x]",createOptions,sdLen,eaLen,allocSize);
8102 osi_Log3(smb_logp,"... imp[%x],sec[%x],flags[%x]", impLevel, secFlags, flags);
8105 * Nothing here to handle SMB_IOCTL_FILENAME.
8106 * Will add it if necessary.
8109 if (!cm_IsValidClientString(realPathp)) {
8111 clientchar_t * hexp;
8113 hexp = cm_GetRawCharsAlloc(realPathp, -1);
8114 osi_Log1(smb_logp, "NTTranCreate rejecting invalid name. [%S]",
8115 osi_LogSaveClientString(smb_logp, hexp));
8119 osi_Log0(smb_logp, "NTTranCreate rejecting invalid name.");
8122 return CM_ERROR_BADNTFILENAME;
8125 userp = smb_GetUserFromVCP(vcp, inp);
8127 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
8129 return CM_ERROR_INVAL;
8134 baseDirp = cm_data.rootSCachep;
8135 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8136 if (code == CM_ERROR_TIDIPC) {
8137 /* Attempt to use a TID allocated for IPC. The client
8138 * is probably looking for DCE RPC end points which we
8139 * don't support OR it could be looking to make a DFS
8142 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
8145 cm_ReleaseUser(userp);
8146 return CM_ERROR_NOSUCHPATH;
8150 baseFidp = smb_FindFID(vcp, baseFid, 0);
8152 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
8154 cm_ReleaseUser(userp);
8155 return CM_ERROR_BADFD;
8158 if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8160 cm_ReleaseUser(userp);
8161 smb_CloseFID(vcp, baseFidp, NULL, 0);
8162 smb_ReleaseFID(baseFidp);
8163 return CM_ERROR_NOSUCHPATH;
8166 baseDirp = baseFidp->scp;
8170 /* compute open mode */
8172 if (desiredAccess & DELETE)
8173 fidflags |= SMB_FID_OPENDELETE;
8174 if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
8175 fidflags |= SMB_FID_OPENREAD_LISTDIR;
8176 if (desiredAccess & AFS_ACCESS_WRITE)
8177 fidflags |= SMB_FID_OPENWRITE;
8178 if (createOptions & FILE_DELETE_ON_CLOSE)
8179 fidflags |= SMB_FID_DELONCLOSE;
8180 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
8181 fidflags |= SMB_FID_SEQUENTIAL;
8182 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
8183 fidflags |= SMB_FID_RANDOM;
8184 if (createOptions & FILE_OPEN_REPARSE_POINT)
8185 osi_Log0(smb_logp, "NTTranCreate Open Reparse Point");
8186 if (smb_IsExecutableFileName(lastNamep))
8187 fidflags |= SMB_FID_EXECUTABLE;
8189 /* And the share mode */
8190 if (shareAccess & FILE_SHARE_READ)
8191 fidflags |= SMB_FID_SHARE_READ;
8192 if (shareAccess & FILE_SHARE_WRITE)
8193 fidflags |= SMB_FID_SHARE_WRITE;
8197 if ( createDisp == FILE_OPEN ||
8198 createDisp == FILE_OVERWRITE ||
8199 createDisp == FILE_OVERWRITE_IF) {
8200 code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8201 userp, tidPathp, &req, &dscp);
8204 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8205 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8206 cm_ReleaseSCache(dscp);
8207 cm_ReleaseUser(userp);
8210 smb_ReleaseFID(baseFidp);
8211 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8212 return CM_ERROR_PATH_NOT_COVERED;
8214 return CM_ERROR_NOSUCHPATH;
8216 #endif /* DFS_SUPPORT */
8217 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
8219 if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
8220 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
8221 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
8222 if (code == 0 && realDirFlag == 1) {
8223 cm_ReleaseSCache(scp);
8224 cm_ReleaseSCache(dscp);
8225 cm_ReleaseUser(userp);
8228 smb_ReleaseFID(baseFidp);
8229 return CM_ERROR_EXISTS;
8235 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8236 userp, tidPathp, &req, &scp);
8238 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
8239 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
8240 cm_ReleaseSCache(scp);
8241 cm_ReleaseUser(userp);
8244 smb_ReleaseFID(baseFidp);
8245 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8246 return CM_ERROR_PATH_NOT_COVERED;
8248 return CM_ERROR_NOSUCHPATH;
8250 #endif /* DFS_SUPPORT */
8256 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
8257 /* look up parent directory */
8259 code = cm_NameI(baseDirp, spacep->wdata,
8260 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8261 userp, tidPathp, &req, &dscp);
8263 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8264 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8265 cm_ReleaseSCache(dscp);
8266 cm_ReleaseUser(userp);
8269 smb_ReleaseFID(baseFidp);
8270 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8271 return CM_ERROR_PATH_NOT_COVERED;
8273 return CM_ERROR_NOSUCHPATH;
8275 #endif /* DFS_SUPPORT */
8279 cm_FreeSpace(spacep);
8282 smb_ReleaseFID(baseFidp);
8285 cm_ReleaseUser(userp);
8291 lastNamep = realPathp;
8295 if (!smb_IsLegalFilename(lastNamep))
8296 return CM_ERROR_BADNTFILENAME;
8299 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
8300 code = cm_Lookup(dscp, lastNamep,
8301 CM_FLAG_FOLLOW, userp, &req, &scp);
8303 code = cm_Lookup(dscp, lastNamep,
8304 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8307 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8308 cm_ReleaseSCache(dscp);
8309 cm_ReleaseUser(userp);
8316 smb_ReleaseFID(baseFidp);
8317 cm_FreeSpace(spacep);
8320 /* if we get here, if code is 0, the file exists and is represented by
8321 * scp. Otherwise, we have to create it. The dir may be represented
8322 * by dscp, or we may have found the file directly. If code is non-zero,
8326 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
8328 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8330 cm_ReleaseSCache(dscp);
8331 cm_ReleaseSCache(scp);
8332 cm_ReleaseUser(userp);
8336 checkDoneRequired = 1;
8338 if (createDisp == FILE_CREATE) {
8339 /* oops, file shouldn't be there */
8340 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8342 cm_ReleaseSCache(dscp);
8343 cm_ReleaseSCache(scp);
8344 cm_ReleaseUser(userp);
8346 return CM_ERROR_EXISTS;
8349 if (createDisp == FILE_OVERWRITE ||
8350 createDisp == FILE_OVERWRITE_IF) {
8351 setAttr.mask = CM_ATTRMASK_LENGTH;
8352 setAttr.length.LowPart = 0;
8353 setAttr.length.HighPart = 0;
8355 /* now watch for a symlink */
8357 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8359 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8361 /* we have a more accurate file to use (the
8362 * target of the symbolic link). Otherwise,
8363 * we'll just use the symlink anyway.
8365 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8367 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8368 cm_ReleaseSCache(scp);
8370 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
8372 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8374 cm_ReleaseSCache(dscp);
8376 cm_ReleaseSCache(scp);
8377 cm_ReleaseUser(userp);
8383 code = cm_SetAttr(scp, &setAttr, userp, &req);
8384 openAction = 3; /* truncated existing file */
8386 else openAction = 1; /* found existing file */
8388 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
8389 /* don't create if not found */
8391 cm_ReleaseSCache(dscp);
8392 cm_ReleaseUser(userp);
8394 return CM_ERROR_NOSUCHFILE;
8396 else if (realDirFlag == 0 || realDirFlag == -1) {
8397 osi_assertx(dscp != NULL, "null cm_scache_t");
8398 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %S",
8399 osi_LogSaveClientString(smb_logp, lastNamep));
8400 openAction = 2; /* created file */
8401 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8402 setAttr.clientModTime = time(NULL);
8403 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8407 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8408 smb_NotifyChange(FILE_ACTION_ADDED,
8409 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8410 dscp, lastNamep, NULL, TRUE);
8411 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
8412 /* Not an exclusive create, and someone else tried
8413 * creating it already, then we open it anyway. We
8414 * don't bother retrying after this, since if this next
8415 * fails, that means that the file was deleted after we
8416 * started this call.
8418 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8421 if (createDisp == FILE_OVERWRITE_IF) {
8422 setAttr.mask = CM_ATTRMASK_LENGTH;
8423 setAttr.length.LowPart = 0;
8424 setAttr.length.HighPart = 0;
8426 /* now watch for a symlink */
8428 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8430 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8432 /* we have a more accurate file to use (the
8433 * target of the symbolic link). Otherwise,
8434 * we'll just use the symlink anyway.
8436 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8438 cm_ReleaseSCache(scp);
8442 code = cm_SetAttr(scp, &setAttr, userp, &req);
8444 } /* lookup succeeded */
8447 /* create directory */
8448 osi_assertx(dscp != NULL, "null cm_scache_t");
8450 "smb_ReceiveNTTranCreate creating directory %S",
8451 osi_LogSaveClientString(smb_logp, lastNamep));
8452 openAction = 2; /* created directory */
8453 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8454 setAttr.clientModTime = time(NULL);
8455 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8456 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8457 smb_NotifyChange(FILE_ACTION_ADDED,
8458 FILE_NOTIFY_CHANGE_DIR_NAME,
8459 dscp, lastNamep, NULL, TRUE);
8461 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
8462 /* Not an exclusive create, and someone else tried
8463 * creating it already, then we open it anyway. We
8464 * don't bother retrying after this, since if this next
8465 * fails, that means that the file was deleted after we
8466 * started this call.
8468 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8474 /* something went wrong creating or truncating the file */
8475 if (checkDoneRequired)
8476 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8478 cm_ReleaseSCache(scp);
8479 cm_ReleaseUser(userp);
8484 /* make sure we have file vs. dir right */
8485 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
8486 /* now watch for a symlink */
8488 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8490 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8492 /* we have a more accurate file to use (the
8493 * target of the symbolic link). Otherwise,
8494 * we'll just use the symlink anyway.
8496 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8498 if (checkDoneRequired) {
8499 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8500 checkDoneRequired = 0;
8502 cm_ReleaseSCache(scp);
8507 if (scp->fileType != CM_SCACHETYPE_FILE) {
8508 if (checkDoneRequired)
8509 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8510 cm_ReleaseSCache(scp);
8511 cm_ReleaseUser(userp);
8513 return CM_ERROR_ISDIR;
8517 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8518 if (checkDoneRequired)
8519 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8520 cm_ReleaseSCache(scp);
8521 cm_ReleaseUser(userp);
8523 return CM_ERROR_NOTDIR;
8526 /* open the file itself */
8527 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8528 osi_assertx(fidp, "null smb_fid_t");
8530 /* save a reference to the user */
8532 fidp->userp = userp;
8534 /* If we are restricting sharing, we should do so with a suitable
8536 if (scp->fileType == CM_SCACHETYPE_FILE &&
8537 !(fidflags & SMB_FID_SHARE_WRITE)) {
8539 LARGE_INTEGER LOffset, LLength;
8542 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8543 LOffset.LowPart = SMB_FID_QLOCK_LOW;
8544 LLength.HighPart = 0;
8545 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8547 /* Similar to what we do in handling NTCreateX. We get a
8548 shared lock if we are only opening the file for reading. */
8549 if ((fidflags & SMB_FID_SHARE_READ) ||
8550 !(fidflags & SMB_FID_OPENWRITE)) {
8551 sLockType = LOCKING_ANDX_SHARED_LOCK;
8556 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8558 lock_ObtainWrite(&scp->rw);
8559 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8560 lock_ReleaseWrite(&scp->rw);
8563 if (checkDoneRequired)
8564 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8565 cm_ReleaseSCache(scp);
8566 cm_ReleaseUser(userp);
8567 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
8568 smb_CloseFID(vcp, fidp, NULL, 0);
8569 smb_ReleaseFID(fidp);
8571 return CM_ERROR_SHARING_VIOLATION;
8575 /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
8576 if (checkDoneRequired) {
8577 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8578 checkDoneRequired = 0;
8581 lock_ObtainMutex(&fidp->mx);
8582 /* save a pointer to the vnode */
8584 lock_ObtainWrite(&scp->rw);
8585 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8586 lock_ReleaseWrite(&scp->rw);
8587 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
8589 fidp->flags = fidflags;
8591 /* remember if the file was newly created */
8593 fidp->flags |= SMB_FID_CREATED;
8595 /* save parent dir and pathname for deletion or change notification */
8596 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8597 fidp->flags |= SMB_FID_NTOPEN;
8598 fidp->NTopen_dscp = dscp;
8599 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
8601 fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
8603 fidp->NTopen_wholepathp = realPathp;
8604 lock_ReleaseMutex(&fidp->mx);
8606 /* we don't need this any longer */
8608 cm_ReleaseSCache(dscp);
8610 cm_Open(scp, 0, userp);
8612 /* set inp->fid so that later read calls in same msg can find fid */
8613 inp->fid = fidp->fid;
8615 /* check whether we are required to send an extended response */
8616 if (!extendedRespRequired) {
8618 parmOffset = 8*4 + 39;
8619 parmOffset += 1; /* pad to 4 */
8620 dataOffset = parmOffset + 70;
8624 /* Total Parameter Count */
8625 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8626 /* Total Data Count */
8627 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8628 /* Parameter Count */
8629 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8630 /* Parameter Offset */
8631 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8632 /* Parameter Displacement */
8633 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8635 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8637 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8638 /* Data Displacement */
8639 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8640 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8641 smb_SetSMBDataLength(outp, 70);
8643 lock_ObtainRead(&scp->rw);
8644 outData = smb_GetSMBData(outp, NULL);
8645 outData++; /* round to get to parmOffset */
8646 *outData = 0; outData++; /* oplock */
8647 *outData = 0; outData++; /* reserved */
8648 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8649 *((ULONG *)outData) = openAction; outData += 4;
8650 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8651 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8652 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8653 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8654 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8655 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8656 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8657 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8658 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8659 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8660 *((USHORT *)outData) = NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS;
8661 outData += 2; /* dev state */
8662 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8663 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8664 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8665 outData += 2; /* is a dir? */
8668 parmOffset = 8*4 + 39;
8669 parmOffset += 1; /* pad to 4 */
8670 dataOffset = parmOffset + 104;
8674 /* Total Parameter Count */
8675 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8676 /* Total Data Count */
8677 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8678 /* Parameter Count */
8679 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8680 /* Parameter Offset */
8681 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8682 /* Parameter Displacement */
8683 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8685 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8687 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8688 /* Data Displacement */
8689 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8690 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8691 smb_SetSMBDataLength(outp, 105);
8693 lock_ObtainRead(&scp->rw);
8694 outData = smb_GetSMBData(outp, NULL);
8695 outData++; /* round to get to parmOffset */
8696 *outData = 0; outData++; /* oplock */
8697 *outData = 1; outData++; /* response type */
8698 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8699 *((ULONG *)outData) = openAction; outData += 4;
8700 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
8701 cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8702 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
8703 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
8704 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
8705 *((FILETIME *)outData) = ft; outData += 8; /* change time */
8706 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8707 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8708 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8709 *((USHORT *)outData) = 0; outData += 2; /* filetype */
8710 *((USHORT *)outData) = NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS;
8711 outData += 2; /* dev state */
8712 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8713 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8714 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8715 outData += 1; /* is a dir? */
8716 /* Setting the GUID results in failures with cygwin */
8717 memset(outData,0,24); outData += 24; /* GUID */
8718 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
8719 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
8722 if ((fidp->flags & SMB_FID_EXECUTABLE) &&
8723 LargeIntegerGreaterThanZero(scp->length) &&
8724 !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
8727 lock_ReleaseRead(&scp->rw);
8730 cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
8731 scp->length.LowPart, scp->length.HighPart,
8734 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
8736 cm_ReleaseUser(userp);
8737 smb_ReleaseFID(fidp);
8739 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
8740 /* leave scp held since we put it in fidp->scp */
8744 /* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
8745 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
8748 smb_packet_t *savedPacketp;
8750 USHORT fid, watchtree;
8754 filter = smb_GetSMBParm(inp, 19) |
8755 (smb_GetSMBParm(inp, 20) << 16);
8756 fid = smb_GetSMBParm(inp, 21);
8757 watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
8759 fidp = smb_FindFID(vcp, fid, 0);
8761 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
8762 return CM_ERROR_BADFD;
8765 lock_ObtainMutex(&fidp->mx);
8766 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8767 lock_ReleaseMutex(&fidp->mx);
8768 smb_CloseFID(vcp, fidp, NULL, 0);
8769 smb_ReleaseFID(fidp);
8770 return CM_ERROR_NOSUCHFILE;
8774 lock_ReleaseMutex(&fidp->mx);
8776 /* Create a copy of the Directory Watch Packet to use when sending the
8777 * notification if in the future a matching change is detected.
8779 savedPacketp = smb_CopyPacket(inp);
8780 if (vcp != savedPacketp->vcp) {
8782 if (savedPacketp->vcp)
8783 smb_ReleaseVC(savedPacketp->vcp);
8784 savedPacketp->vcp = vcp;
8787 /* Add the watch to the list of events to send notifications for */
8788 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8789 savedPacketp->nextp = smb_Directory_Watches;
8790 smb_Directory_Watches = savedPacketp;
8791 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8793 osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%S\"",
8794 fidp, scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp));
8795 osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
8796 filter, fid, watchtree);
8797 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8798 osi_Log0(smb_logp, " Notify Change File Name");
8799 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8800 osi_Log0(smb_logp, " Notify Change Directory Name");
8801 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8802 osi_Log0(smb_logp, " Notify Change Attributes");
8803 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8804 osi_Log0(smb_logp, " Notify Change Size");
8805 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8806 osi_Log0(smb_logp, " Notify Change Last Write");
8807 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8808 osi_Log0(smb_logp, " Notify Change Last Access");
8809 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8810 osi_Log0(smb_logp, " Notify Change Creation");
8811 if (filter & FILE_NOTIFY_CHANGE_EA)
8812 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8813 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8814 osi_Log0(smb_logp, " Notify Change Security");
8815 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8816 osi_Log0(smb_logp, " Notify Change Stream Name");
8817 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8818 osi_Log0(smb_logp, " Notify Change Stream Size");
8819 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8820 osi_Log0(smb_logp, " Notify Change Stream Write");
8822 lock_ObtainWrite(&scp->rw);
8824 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
8826 scp->flags |= CM_SCACHEFLAG_WATCHED;
8827 lock_ReleaseWrite(&scp->rw);
8828 cm_ReleaseSCache(scp);
8829 smb_ReleaseFID(fidp);
8831 outp->flags |= SMB_PACKETFLAG_NOSEND;
8835 unsigned char nullSecurityDesc[36] = {
8836 0x01, /* security descriptor revision */
8837 0x00, /* reserved, should be zero */
8838 0x00, 0x80, /* security descriptor control;
8839 * 0x8000 : self-relative format */
8840 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
8841 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
8842 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
8843 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
8844 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8845 /* "null SID" owner SID */
8846 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
8847 /* "null SID" group SID */
8850 /* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
8851 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8853 int parmOffset, parmCount, dataOffset, dataCount;
8861 ULONG securityInformation;
8863 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8864 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8865 parmp = inp->data + parmOffset;
8866 sparmp = (USHORT *) parmp;
8867 lparmp = (ULONG *) parmp;
8870 securityInformation = lparmp[1];
8872 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
8873 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
8881 parmOffset = 8*4 + 39;
8882 parmOffset += 1; /* pad to 4 */
8884 dataOffset = parmOffset + parmCount;
8888 /* Total Parameter Count */
8889 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8890 /* Total Data Count */
8891 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8892 /* Parameter Count */
8893 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8894 /* Parameter Offset */
8895 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8896 /* Parameter Displacement */
8897 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8899 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8901 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8902 /* Data Displacement */
8903 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8904 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8905 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
8907 outData = smb_GetSMBData(outp, NULL);
8908 outData++; /* round to get to parmOffset */
8909 *((ULONG *)outData) = 36; outData += 4; /* length */
8911 if (maxData >= 36) {
8912 memcpy(outData, nullSecurityDesc, 36);
8916 return CM_ERROR_BUFFERTOOSMALL;
8919 /* SMB_COM_NT_TRANSACT
8921 SMB_COM_NT_TRANSACT_SECONDARY should also be handled here.
8923 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8925 unsigned short function;
8927 function = smb_GetSMBParm(inp, 18);
8929 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
8931 /* We can handle long names */
8932 if (vcp->flags & SMB_VCFLAG_USENT)
8933 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
8936 case 1: /* NT_TRANSACT_CREATE */
8937 return smb_ReceiveNTTranCreate(vcp, inp, outp);
8938 case 2: /* NT_TRANSACT_IOCTL */
8939 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
8941 case 3: /* NT_TRANSACT_SET_SECURITY_DESC */
8942 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
8944 case 4: /* NT_TRANSACT_NOTIFY_CHANGE */
8945 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
8946 case 5: /* NT_TRANSACT_RENAME */
8947 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
8949 case 6: /* NT_TRANSACT_QUERY_SECURITY_DESC */
8950 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
8952 osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
8955 osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
8958 return CM_ERROR_BADOP;
8962 * smb_NotifyChange -- find relevant change notification messages and
8965 * If we don't know the file name (i.e. a callback break), filename is
8966 * NULL, and we return a zero-length list.
8968 * At present there is not a single call to smb_NotifyChange that
8969 * has the isDirectParent parameter set to FALSE.
8971 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
8972 cm_scache_t *dscp, clientchar_t *filename, clientchar_t *otherFilename,
8973 BOOL isDirectParent)
8975 smb_packet_t *watch, *lastWatch, *nextWatch;
8976 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen = 0;
8977 char *outData, *oldOutData;
8981 BOOL twoEntries = FALSE;
8982 ULONG otherNameLen, oldParmCount = 0;
8986 /* Get ready for rename within directory */
8987 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
8989 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
8992 osi_Log4(smb_logp,"in smb_NotifyChange for file [%S] dscp [%p] notification 0x%x parent %d",
8993 osi_LogSaveClientString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
8995 osi_Log0(smb_logp," FILE_ACTION_NONE");
8996 if (action == FILE_ACTION_ADDED)
8997 osi_Log0(smb_logp," FILE_ACTION_ADDED");
8998 if (action == FILE_ACTION_REMOVED)
8999 osi_Log0(smb_logp," FILE_ACTION_REMOVED");
9000 if (action == FILE_ACTION_MODIFIED)
9001 osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
9002 if (action == FILE_ACTION_RENAMED_OLD_NAME)
9003 osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
9004 if (action == FILE_ACTION_RENAMED_NEW_NAME)
9005 osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
9007 lock_ObtainMutex(&smb_Dir_Watch_Lock);
9008 watch = smb_Directory_Watches;
9010 filter = smb_GetSMBParm(watch, 19)
9011 | (smb_GetSMBParm(watch, 20) << 16);
9012 fid = smb_GetSMBParm(watch, 21);
9013 wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
9015 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
9016 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
9019 * Strange hack - bug in NT Client and NT Server that we must emulate?
9021 if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
9022 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
9024 fidp = smb_FindFID(watch->vcp, fid, 0);
9026 osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
9028 watch = watch->nextp;
9032 if (fidp->scp != dscp ||
9033 fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
9034 (filter & notifyFilter) == 0 ||
9035 (!isDirectParent && !wtree))
9037 osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
9039 watch = watch->nextp;
9040 smb_ReleaseFID(fidp);
9045 "Sending Change Notification for fid %d filter 0x%x wtree %d file %S",
9046 fid, filter, wtree, osi_LogSaveClientString(smb_logp, filename));
9047 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
9048 osi_Log0(smb_logp, " Notify Change File Name");
9049 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
9050 osi_Log0(smb_logp, " Notify Change Directory Name");
9051 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
9052 osi_Log0(smb_logp, " Notify Change Attributes");
9053 if (filter & FILE_NOTIFY_CHANGE_SIZE)
9054 osi_Log0(smb_logp, " Notify Change Size");
9055 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
9056 osi_Log0(smb_logp, " Notify Change Last Write");
9057 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
9058 osi_Log0(smb_logp, " Notify Change Last Access");
9059 if (filter & FILE_NOTIFY_CHANGE_CREATION)
9060 osi_Log0(smb_logp, " Notify Change Creation");
9061 if (filter & FILE_NOTIFY_CHANGE_EA)
9062 osi_Log0(smb_logp, " Notify Change Extended Attributes");
9063 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
9064 osi_Log0(smb_logp, " Notify Change Security");
9065 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
9066 osi_Log0(smb_logp, " Notify Change Stream Name");
9067 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
9068 osi_Log0(smb_logp, " Notify Change Stream Size");
9069 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
9070 osi_Log0(smb_logp, " Notify Change Stream Write");
9072 /* A watch can only be notified once. Remove it from the list */
9073 nextWatch = watch->nextp;
9074 if (watch == smb_Directory_Watches)
9075 smb_Directory_Watches = nextWatch;
9077 lastWatch->nextp = nextWatch;
9079 /* Turn off WATCHED flag in dscp */
9080 lock_ObtainWrite(&dscp->rw);
9082 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
9084 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
9085 lock_ReleaseWrite(&dscp->rw);
9087 /* Convert to response packet */
9088 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
9089 #ifdef SEND_CANONICAL_PATHNAMES
9090 ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
9092 ((smb_t *) watch)->wct = 0;
9095 if (filename == NULL) {
9098 nameLen = (ULONG)cm_ClientStrLen(filename);
9099 parmCount = 3*4 + nameLen*2;
9100 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
9102 otherNameLen = (ULONG)cm_ClientStrLen(otherFilename);
9103 oldParmCount = parmCount;
9104 parmCount += 3*4 + otherNameLen*2;
9105 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
9107 if (maxLen < parmCount)
9108 parmCount = 0; /* not enough room */
9110 parmOffset = 8*4 + 39;
9111 parmOffset += 1; /* pad to 4 */
9112 dataOffset = parmOffset + parmCount;
9116 /* Total Parameter Count */
9117 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
9118 /* Total Data Count */
9119 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9120 /* Parameter Count */
9121 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
9122 /* Parameter Offset */
9123 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
9124 /* Parameter Displacement */
9125 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9127 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9129 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
9130 /* Data Displacement */
9131 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9132 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
9133 smb_SetSMBDataLength(watch, parmCount + 1);
9135 if (parmCount != 0) {
9136 outData = smb_GetSMBData(watch, NULL);
9137 outData++; /* round to get to parmOffset */
9138 oldOutData = outData;
9139 *((DWORD *)outData) = oldParmCount; outData += 4;
9140 /* Next Entry Offset */
9141 *((DWORD *)outData) = action; outData += 4;
9143 *((DWORD *)outData) = nameLen*2; outData += 4;
9144 /* File Name Length */
9146 smb_UnparseString(watch, outData, filename, NULL, 0);
9150 outData = oldOutData + oldParmCount;
9151 *((DWORD *)outData) = 0; outData += 4;
9152 /* Next Entry Offset */
9153 *((DWORD *)outData) = otherAction; outData += 4;
9155 *((DWORD *)outData) = otherNameLen*2;
9156 outData += 4; /* File Name Length */
9157 smb_UnparseString(watch, outData, otherFilename, NULL, 0);
9162 * If filename is null, we don't know the cause of the
9163 * change notification. We return zero data (see above),
9164 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
9165 * (= 0x010C). We set the error code here by hand, without
9166 * modifying wct and bcc.
9168 if (filename == NULL) {
9169 ((smb_t *) watch)->rcls = 0x0C;
9170 ((smb_t *) watch)->reh = 0x01;
9171 ((smb_t *) watch)->errLow = 0;
9172 ((smb_t *) watch)->errHigh = 0;
9173 /* Set NT Status codes flag */
9174 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9177 smb_SendPacket(watch->vcp, watch);
9178 smb_FreePacket(watch);
9180 smb_ReleaseFID(fidp);
9183 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9186 /* SMB_COM_NT_CANCEL */
9187 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9189 unsigned char *replyWctp;
9190 smb_packet_t *watch, *lastWatch;
9191 USHORT fid, watchtree;
9195 osi_Log0(smb_logp, "SMB3 receive NT cancel");
9197 lock_ObtainMutex(&smb_Dir_Watch_Lock);
9198 watch = smb_Directory_Watches;
9200 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
9201 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
9202 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
9203 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
9204 if (watch == smb_Directory_Watches)
9205 smb_Directory_Watches = watch->nextp;
9207 lastWatch->nextp = watch->nextp;
9208 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9210 /* Turn off WATCHED flag in scp */
9211 fid = smb_GetSMBParm(watch, 21);
9212 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
9214 if (vcp != watch->vcp)
9215 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
9218 fidp = smb_FindFID(vcp, fid, 0);
9220 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %S",
9222 (fidp ? osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp) :_C("")));
9225 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
9227 lock_ObtainWrite(&scp->rw);
9229 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
9231 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
9232 lock_ReleaseWrite(&scp->rw);
9234 smb_ReleaseFID(fidp);
9236 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
9239 /* assume STATUS32; return 0xC0000120 (CANCELED) */
9240 replyWctp = watch->wctp;
9244 ((smb_t *)watch)->rcls = 0x20;
9245 ((smb_t *)watch)->reh = 0x1;
9246 ((smb_t *)watch)->errLow = 0;
9247 ((smb_t *)watch)->errHigh = 0xC0;
9248 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9249 smb_SendPacket(vcp, watch);
9250 smb_FreePacket(watch);
9254 watch = watch->nextp;
9256 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9262 * NT rename also does hard links.
9265 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
9266 #define RENAME_FLAG_HARD_LINK 0x103
9267 #define RENAME_FLAG_RENAME 0x104
9268 #define RENAME_FLAG_COPY 0x105
9270 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9272 clientchar_t *oldPathp, *newPathp;
9278 attrs = smb_GetSMBParm(inp, 0);
9279 rename_type = smb_GetSMBParm(inp, 1);
9281 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
9282 osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
9283 return CM_ERROR_NOACCESS;
9286 tp = smb_GetSMBData(inp, NULL);
9287 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
9289 return CM_ERROR_BADSMB;
9290 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
9292 return CM_ERROR_BADSMB;
9294 osi_Log3(smb_logp, "NTRename for [%S]->[%S] type [%s]",
9295 osi_LogSaveClientString(smb_logp, oldPathp),
9296 osi_LogSaveClientString(smb_logp, newPathp),
9297 ((rename_type==RENAME_FLAG_RENAME)?"rename":(rename_type==RENAME_FLAG_HARD_LINK)?"hardlink":"other"));
9299 if (rename_type == RENAME_FLAG_RENAME) {
9300 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
9301 } else if (rename_type == RENAME_FLAG_HARD_LINK) { /* RENAME_FLAG_HARD_LINK */
9302 code = smb_Link(vcp,inp,oldPathp,newPathp);
9304 code = CM_ERROR_BADOP;
9310 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock", LOCK_HIERARCHY_SMB_DIRWATCH);
9313 cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
9315 smb_username_t *unp;
9318 unp = smb_FindUserByName(usern, machine, flags);
9320 lock_ObtainMutex(&unp->mx);
9321 unp->userp = cm_NewUser();
9322 lock_ReleaseMutex(&unp->mx);
9323 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9325 osi_Log2(smb_logp,"smb_FindCMUserByName Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9329 smb_ReleaseUsername(unp);