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>
16 #define SECURITY_WIN32
28 #include <WINNT\afsreg.h>
32 extern osi_hyper_t hzero;
34 smb_packet_t *smb_Directory_Watches = NULL;
35 osi_mutex_t smb_Dir_Watch_Lock;
37 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
39 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
41 /* protected by the smb_globalLock */
42 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
44 /* retrieve a held reference to a user structure corresponding to an incoming
46 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
51 uidp = smb_FindUID(vcp, inp->uid, 0);
55 up = smb_GetUserFromUID(uidp);
63 * Return extended attributes.
64 * Right now, we aren't using any of the "new" bits, so this looks exactly
65 * like smb_Attributes() (see smb.c).
67 unsigned long smb_ExtAttributes(cm_scache_t *scp)
71 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
72 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
73 scp->fileType == CM_SCACHETYPE_INVALID)
75 attrs = SMB_ATTR_DIRECTORY;
76 #ifdef SPECIAL_FOLDERS
77 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
78 #endif /* SPECIAL_FOLDERS */
79 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
80 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
84 * We used to mark a file RO if it was in an RO volume, but that
85 * turns out to be impolitic in NT. See defect 10007.
88 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
89 attrs |= SMB_ATTR_READONLY; /* Read-only */
91 if ((scp->unixModeBits & 0222) == 0)
92 attrs |= SMB_ATTR_READONLY; /* Read-only */
96 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
101 int smb_V3IsStarMask(char *maskp)
105 while (tc = *maskp++)
106 if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
111 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
114 /* skip over null-terminated string */
115 *chainpp = inp + strlen(inp) + 1;
120 void OutputDebugF(char * format, ...) {
125 va_start( args, format );
126 len = _vscprintf( format, args ) // _vscprintf doesn't count
127 + 3; // terminating '\0' + '\n'
128 buffer = malloc( len * sizeof(char) );
129 vsprintf( buffer, format, args );
130 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buffer));
131 strcat(buffer, "\n");
132 OutputDebugString(buffer);
136 void OutputDebugHexDump(unsigned char * buffer, int len) {
139 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
141 OutputDebugF("Hexdump length [%d]",len);
143 for (i=0;i<len;i++) {
146 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
148 OutputDebugString(buf);
150 sprintf(buf,"%5x",i);
151 memset(buf+5,' ',80);
156 j = j*3 + 7 + ((j>7)?1:0);
159 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
162 j = j + 56 + ((j>7)?1:0) + pcts;
164 buf[j] = (k>32 && k<127)?k:'.';
171 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
173 OutputDebugString(buf);
177 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
179 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
180 SECURITY_STATUS status, istatus;
181 CredHandle creds = {0,0};
183 SecBufferDesc secOut;
191 OutputDebugF("Negotiating Extended Security");
193 status = AcquireCredentialsHandle( NULL,
194 SMB_EXT_SEC_PACKAGE_NAME,
203 if (status != SEC_E_OK) {
204 /* Really bad. We return an empty security blob */
205 OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
210 secOut.pBuffers = &secTok;
211 secOut.ulVersion = SECBUFFER_VERSION;
213 secTok.BufferType = SECBUFFER_TOKEN;
215 secTok.pvBuffer = NULL;
217 ctx.dwLower = ctx.dwUpper = 0;
219 status = AcceptSecurityContext( &creds,
222 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
223 SECURITY_NETWORK_DREP,
230 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
231 OutputDebugF("Completing token...");
232 istatus = CompleteAuthToken(&ctx, &secOut);
233 if ( istatus != SEC_E_OK )
234 OutputDebugF("Token completion failed: %x", istatus);
237 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
238 if (secTok.pvBuffer) {
239 *secBlobLength = secTok.cbBuffer;
240 *secBlob = malloc( secTok.cbBuffer );
241 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
244 if ( status != SEC_E_OK )
245 OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
248 /* Discard partial security context */
249 DeleteSecurityContext(&ctx);
251 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
253 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
254 FreeCredentialsHandle(&creds);
260 struct smb_ext_context {
267 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
268 SECURITY_STATUS status, istatus;
272 SecBufferDesc secBufIn;
274 SecBufferDesc secBufOut;
277 struct smb_ext_context * secCtx = NULL;
278 struct smb_ext_context * newSecCtx = NULL;
279 void * assembledBlob = NULL;
280 int assembledBlobLength = 0;
283 OutputDebugF("In smb_AuthenticateUserExt");
286 *secBlobOutLength = 0;
288 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
289 secCtx = vcp->secCtx;
290 lock_ObtainMutex(&vcp->mx);
291 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
293 lock_ReleaseMutex(&vcp->mx);
297 OutputDebugF("Received incoming token:");
298 OutputDebugHexDump(secBlobIn,secBlobInLength);
302 OutputDebugF("Continuing with existing context.");
303 creds = secCtx->creds;
306 if (secCtx->partialToken) {
307 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
308 assembledBlob = malloc(assembledBlobLength);
309 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
310 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
313 status = AcquireCredentialsHandle( NULL,
314 SMB_EXT_SEC_PACKAGE_NAME,
323 if (status != SEC_E_OK) {
324 OutputDebugF("Can't acquire Credentials handle [%lX]", status);
325 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
333 secBufIn.cBuffers = 1;
334 secBufIn.pBuffers = &secTokIn;
335 secBufIn.ulVersion = SECBUFFER_VERSION;
337 secTokIn.BufferType = SECBUFFER_TOKEN;
339 secTokIn.cbBuffer = assembledBlobLength;
340 secTokIn.pvBuffer = assembledBlob;
342 secTokIn.cbBuffer = secBlobInLength;
343 secTokIn.pvBuffer = secBlobIn;
346 secBufOut.cBuffers = 1;
347 secBufOut.pBuffers = &secTokOut;
348 secBufOut.ulVersion = SECBUFFER_VERSION;
350 secTokOut.BufferType = SECBUFFER_TOKEN;
351 secTokOut.cbBuffer = 0;
352 secTokOut.pvBuffer = NULL;
354 status = AcceptSecurityContext( &creds,
355 ((secCtx)?&ctx:NULL),
357 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
358 SECURITY_NETWORK_DREP,
365 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
366 OutputDebugF("Completing token...");
367 istatus = CompleteAuthToken(&ctx, &secBufOut);
368 if ( istatus != SEC_E_OK )
369 OutputDebugF("Token completion failed: %lX", istatus);
372 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
373 OutputDebugF("Continue needed");
375 newSecCtx = malloc(sizeof(*newSecCtx));
377 newSecCtx->creds = creds;
378 newSecCtx->ctx = ctx;
379 newSecCtx->partialToken = NULL;
380 newSecCtx->partialTokenLen = 0;
382 lock_ObtainMutex( &vcp->mx );
383 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
384 vcp->secCtx = newSecCtx;
385 lock_ReleaseMutex( &vcp->mx );
387 code = CM_ERROR_GSSCONTINUE;
390 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
391 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
392 secTokOut.pvBuffer) {
393 OutputDebugF("Need to send token back to client");
395 *secBlobOutLength = secTokOut.cbBuffer;
396 *secBlobOut = malloc(secTokOut.cbBuffer);
397 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
399 OutputDebugF("Outgoing token:");
400 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
401 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
402 OutputDebugF("Incomplete message");
404 newSecCtx = malloc(sizeof(*newSecCtx));
406 newSecCtx->creds = creds;
407 newSecCtx->ctx = ctx;
408 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
409 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
410 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
412 lock_ObtainMutex( &vcp->mx );
413 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
414 vcp->secCtx = newSecCtx;
415 lock_ReleaseMutex( &vcp->mx );
417 code = CM_ERROR_GSSCONTINUE;
420 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
422 SecPkgContext_Names names;
424 OutputDebugF("Authentication completed");
425 OutputDebugF("Returned flags : [%lX]", flags);
427 if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
428 OutputDebugF("Received name [%s]", names.sUserName);
429 strcpy(usern, names.sUserName);
430 strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
431 FreeContextBuffer(names.sUserName);
433 /* Force the user to retry if the context is invalid */
434 OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
435 code = CM_ERROR_BADPASSWORD;
439 case SEC_E_INVALID_TOKEN:
440 OutputDebugF("Returning bad password :: INVALID_TOKEN");
442 case SEC_E_INVALID_HANDLE:
443 OutputDebugF("Returning bad password :: INVALID_HANDLE");
445 case SEC_E_LOGON_DENIED:
446 OutputDebugF("Returning bad password :: LOGON_DENIED");
448 case SEC_E_UNKNOWN_CREDENTIALS:
449 OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
451 case SEC_E_NO_CREDENTIALS:
452 OutputDebugF("Returning bad password :: NO_CREDENTIALS");
454 case SEC_E_CONTEXT_EXPIRED:
455 OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
457 case SEC_E_INCOMPLETE_CREDENTIALS:
458 OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
460 case SEC_E_WRONG_PRINCIPAL:
461 OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
463 case SEC_E_TIME_SKEW:
464 OutputDebugF("Returning bad password :: TIME_SKEW");
467 OutputDebugF("Returning bad password :: Status == %lX", status);
469 code = CM_ERROR_BADPASSWORD;
473 if (secCtx->partialToken) free(secCtx->partialToken);
481 if (secTokOut.pvBuffer)
482 FreeContextBuffer(secTokOut.pvBuffer);
484 if (code != CM_ERROR_GSSCONTINUE) {
485 DeleteSecurityContext(&ctx);
486 FreeCredentialsHandle(&creds);
494 #define P_RESP_LEN 128
496 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
497 So put stuff in a struct. */
498 struct Lm20AuthBlob {
499 MSV1_0_LM20_LOGON lmlogon;
500 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
501 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
502 WCHAR accountNameW[P_LEN];
503 WCHAR primaryDomainW[P_LEN];
504 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
505 TOKEN_GROUPS tgroups;
506 TOKEN_SOURCE tsource;
509 long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
512 struct Lm20AuthBlob lmAuth;
513 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
514 QUOTA_LIMITS quotaLimits;
516 ULONG lmprofilepSize;
520 OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
521 OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
523 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
524 OutputDebugF("ciPwdLength or csPwdLength is too long");
525 return CM_ERROR_BADPASSWORD;
528 memset(&lmAuth,0,sizeof(lmAuth));
530 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
532 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
533 mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
534 lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
535 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
537 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
538 mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
539 lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
540 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
542 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
543 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
544 size = MAX_COMPUTERNAME_LENGTH + 1;
545 GetComputerNameW(lmAuth.workstationW, &size);
546 lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
548 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
550 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
551 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
552 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
553 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
555 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
556 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
557 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
558 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
560 lmAuth.lmlogon.ParameterControl = 0;
562 lmAuth.tgroups.GroupCount = 0;
563 lmAuth.tgroups.Groups[0].Sid = NULL;
564 lmAuth.tgroups.Groups[0].Attributes = 0;
566 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
567 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
568 strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
570 nts = LsaLogonUser( smb_lsaHandle,
585 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
586 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
589 OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
590 OutputDebugF("Extended status is 0x%lX", ntsEx);
592 if (nts == ERROR_SUCCESS) {
594 LsaFreeReturnBuffer(lmprofilep);
595 CloseHandle(lmToken);
599 if (nts == 0xC000015BL)
600 return CM_ERROR_BADLOGONTYPE;
601 else /* our catchall is a bad password though we could be more specific */
602 return CM_ERROR_BADPASSWORD;
606 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
607 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName)
612 /* check if we have sane input */
613 if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
616 /* we could get : [accountName][domainName]
622 atsign = strchr(accountName, '@');
624 if (atsign) /* [user@domain][] -> [user@domain][domain] */
629 /* if for some reason the client doesn't know what domain to use,
630 it will either return an empty string or a '?' */
631 if (!domain[0] || domain[0] == '?')
632 /* Empty domains and empty usernames are usually sent from tokenless contexts.
633 This way such logins will get an empty username (easy to check). I don't know
634 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
635 strcpy(usern,accountName);
637 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
638 strcpy(usern,domain);
641 strncat(usern,accountName,atsign - accountName);
643 strcat(usern,accountName);
651 /* When using SMB auth, all SMB sessions have to pass through here
652 * first to authenticate the user.
654 * Caveat: If not using SMB auth, the protocol does not require
655 * sending a session setup packet, which means that we can't rely on a
656 * UID in subsequent packets. Though in practice we get one anyway.
658 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
662 unsigned short newUid;
663 unsigned long caps = 0;
667 char usern[SMB_MAX_USERNAME_LENGTH];
668 char *secBlobOut = NULL;
669 int secBlobOutLength = 0;
671 /* Check for bad conns */
672 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
673 return CM_ERROR_REMOTECONN;
675 if (vcp->flags & SMB_VCFLAG_USENT) {
676 if (smb_authType == SMB_AUTH_EXTENDED) {
677 /* extended authentication */
681 OutputDebugF("NT Session Setup: Extended");
683 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
684 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
687 secBlobInLength = smb_GetSMBParm(inp, 7);
688 secBlobIn = smb_GetSMBData(inp, NULL);
690 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
692 if (code == CM_ERROR_GSSCONTINUE) {
693 smb_SetSMBParm(outp, 2, 0);
694 smb_SetSMBParm(outp, 3, secBlobOutLength);
695 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
696 tp = smb_GetSMBData(outp, NULL);
697 if (secBlobOutLength) {
698 memcpy(tp, secBlobOut, secBlobOutLength);
700 tp += secBlobOutLength;
702 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
703 tp += smb_ServerOSLength;
704 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
705 tp += smb_ServerLanManagerLength;
706 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
707 tp += smb_ServerDomainNameLength;
710 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
712 unsigned ciPwdLength, csPwdLength;
718 if (smb_authType == SMB_AUTH_NTLM)
719 OutputDebugF("NT Session Setup: NTLM");
721 OutputDebugF("NT Session Setup: None");
723 /* TODO: parse for extended auth as well */
724 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
725 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
727 tp = smb_GetSMBData(inp, &datalen);
729 OutputDebugF("Session packet data size [%d]",datalen);
736 accountName = smb_ParseString(tp, &tp);
737 primaryDomain = smb_ParseString(tp, NULL);
739 OutputDebugF("Account Name: %s",accountName);
740 OutputDebugF("Primary Domain: %s", primaryDomain);
741 OutputDebugF("Case Sensitive Password: %s", csPwd && csPwd[0] ? "yes" : "no");
742 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
744 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
745 /* shouldn't happen */
746 code = CM_ERROR_BADSMB;
747 goto after_read_packet;
750 /* capabilities are only valid for first session packet */
751 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
752 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
755 if (smb_authType == SMB_AUTH_NTLM) {
756 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
758 OutputDebugF("LM authentication failed [%d]", code);
760 OutputDebugF("LM authentication succeeded");
764 unsigned ciPwdLength;
769 switch ( smb_authType ) {
770 case SMB_AUTH_EXTENDED:
771 OutputDebugF("V3 Session Setup: Extended");
774 OutputDebugF("V3 Session Setup: NTLM");
777 OutputDebugF("V3 Session Setup: None");
779 ciPwdLength = smb_GetSMBParm(inp, 7);
780 tp = smb_GetSMBData(inp, NULL);
784 accountName = smb_ParseString(tp, &tp);
785 primaryDomain = smb_ParseString(tp, NULL);
787 OutputDebugF("Account Name: %s",accountName);
788 OutputDebugF("Primary Domain: %s", primaryDomain);
789 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
791 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
792 /* shouldn't happen */
793 code = CM_ERROR_BADSMB;
794 goto after_read_packet;
797 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
800 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
801 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
803 OutputDebugF("LM authentication failed [%d]", code);
805 OutputDebugF("LM authentication succeeded");
810 /* note down that we received a session setup X and set the capabilities flag */
811 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
812 lock_ObtainMutex(&vcp->mx);
813 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
814 /* for the moment we can only deal with NTSTATUS */
815 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
816 vcp->flags |= SMB_VCFLAG_STATUS32;
818 lock_ReleaseMutex(&vcp->mx);
821 /* code would be non-zero if there was an authentication failure.
822 Ideally we would like to invalidate the uid for this session or break
823 early to avoid accidently stealing someone else's tokens. */
829 OutputDebugF("Received username=[%s]", usern);
831 /* On Windows 2000, this function appears to be called more often than
832 it is expected to be called. This resulted in multiple smb_user_t
833 records existing all for the same user session which results in all
834 of the users tokens disappearing.
836 To avoid this problem, we look for an existing smb_user_t record
837 based on the users name, and use that one if we find it.
840 uidp = smb_FindUserByNameThisSession(vcp, usern);
841 if (uidp) { /* already there, so don't create a new one */
843 newUid = uidp->userID;
844 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
845 vcp->lana,vcp->lsn,newUid);
846 smb_ReleaseUID(uidp);
851 /* do a global search for the username/machine name pair */
852 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
853 lock_ObtainMutex(&unp->mx);
854 if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
855 /* clear the afslogon flag so that the tickets can now
856 * be freed when the refCount returns to zero.
858 unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
860 lock_ReleaseMutex(&unp->mx);
862 /* Create a new UID and cm_user_t structure */
865 userp = cm_NewUser();
866 cm_HoldUserVCRef(userp);
867 lock_ObtainMutex(&vcp->mx);
868 if (!vcp->uidCounter)
869 vcp->uidCounter++; /* handle unlikely wraparounds */
870 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
871 lock_ReleaseMutex(&vcp->mx);
873 /* Create a new smb_user_t structure and connect them up */
874 lock_ObtainMutex(&unp->mx);
876 lock_ReleaseMutex(&unp->mx);
878 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
880 lock_ObtainMutex(&uidp->mx);
882 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
883 lock_ReleaseMutex(&uidp->mx);
884 smb_ReleaseUID(uidp);
888 /* Return UID to the client */
889 ((smb_t *)outp)->uid = newUid;
890 /* Also to the next chained message */
891 ((smb_t *)inp)->uid = newUid;
893 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
894 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
896 smb_SetSMBParm(outp, 2, 0);
898 if (vcp->flags & SMB_VCFLAG_USENT) {
899 if (smb_authType == SMB_AUTH_EXTENDED) {
900 smb_SetSMBParm(outp, 3, secBlobOutLength);
901 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
902 tp = smb_GetSMBData(outp, NULL);
903 if (secBlobOutLength) {
904 memcpy(tp, secBlobOut, secBlobOutLength);
906 tp += secBlobOutLength;
908 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
909 tp += smb_ServerOSLength;
910 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
911 tp += smb_ServerLanManagerLength;
912 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
913 tp += smb_ServerDomainNameLength;
915 smb_SetSMBDataLength(outp, 0);
918 if (smb_authType == SMB_AUTH_EXTENDED) {
919 smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
920 tp = smb_GetSMBData(outp, NULL);
921 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
922 tp += smb_ServerOSLength;
923 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
924 tp += smb_ServerLanManagerLength;
925 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
926 tp += smb_ServerDomainNameLength;
928 smb_SetSMBDataLength(outp, 0);
935 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
939 /* find the tree and free it */
940 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
942 smb_username_t * unp;
944 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %s", uidp->userID,
945 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "));
947 lock_ObtainMutex(&uidp->mx);
948 uidp->flags |= SMB_USERFLAG_DELETE;
950 * it doesn't get deleted right away
951 * because the vcp points to it
954 lock_ReleaseMutex(&uidp->mx);
957 /* we can't do this. we get logoff messages prior to a session
958 * disconnect even though it doesn't mean the user is logging out.
959 * we need to create a new pioctl and EventLogoff handler to set
960 * SMB_USERNAMEFLAG_LOGOFF.
962 if (unp && smb_LogoffTokenTransfer) {
963 lock_ObtainMutex(&unp->mx);
964 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
965 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
966 lock_ReleaseMutex(&unp->mx);
970 smb_ReleaseUID(uidp);
973 osi_Log0(smb_logp, "SMB3 user logoffX");
975 smb_SetSMBDataLength(outp, 0);
979 #define SMB_SUPPORT_SEARCH_BITS 0x0001
980 #define SMB_SHARE_IS_IN_DFS 0x0002
982 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
985 smb_user_t *uidp = NULL;
986 unsigned short newTid;
994 cm_user_t *userp = NULL;
997 osi_Log0(smb_logp, "SMB3 receive tree connect");
999 /* parse input parameters */
1000 tp = smb_GetSMBData(inp, NULL);
1001 passwordp = smb_ParseString(tp, &tp);
1002 pathp = smb_ParseString(tp, &tp);
1003 if (smb_StoreAnsiFilenames)
1004 OemToChar(pathp,pathp);
1005 servicep = smb_ParseString(tp, &tp);
1007 tp = strrchr(pathp, '\\');
1009 return CM_ERROR_BADSMB;
1011 strcpy(shareName, tp+1);
1013 osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
1014 osi_LogSaveString(smb_logp, pathp),
1015 osi_LogSaveString(smb_logp, shareName));
1017 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
1019 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1022 return CM_ERROR_NOIPC;
1026 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1028 userp = smb_GetUserFromUID(uidp);
1030 lock_ObtainMutex(&vcp->mx);
1031 newTid = vcp->tidCounter++;
1032 lock_ReleaseMutex(&vcp->mx);
1034 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1037 if (!strcmp(shareName, "*."))
1038 strcpy(shareName, "all");
1039 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1042 smb_ReleaseUID(uidp);
1043 smb_ReleaseTID(tidp);
1044 return CM_ERROR_BADSHARENAME;
1047 if (vcp->flags & SMB_VCFLAG_USENT)
1049 int policy = smb_FindShareCSCPolicy(shareName);
1050 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1052 SMB_SHARE_IS_IN_DFS |
1057 smb_SetSMBParm(outp, 2, 0);
1061 smb_ReleaseUID(uidp);
1063 lock_ObtainMutex(&tidp->mx);
1064 tidp->userp = userp;
1065 tidp->pathname = sharePath;
1067 tidp->flags |= SMB_TIDFLAG_IPC;
1068 lock_ReleaseMutex(&tidp->mx);
1069 smb_ReleaseTID(tidp);
1071 ((smb_t *)outp)->tid = newTid;
1072 ((smb_t *)inp)->tid = newTid;
1073 tp = smb_GetSMBData(outp, NULL);
1075 /* XXX - why is this a drive letter? */
1083 smb_SetSMBDataLength(outp, 7);
1086 smb_SetSMBDataLength(outp, 4);
1089 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1093 /* must be called with global tran lock held */
1094 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1096 smb_tran2Packet_t *tp;
1099 smbp = (smb_t *) inp->data;
1100 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1101 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1107 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1108 int totalParms, int totalData)
1110 smb_tran2Packet_t *tp;
1113 smbp = (smb_t *) inp->data;
1114 tp = malloc(sizeof(*tp));
1115 memset(tp, 0, sizeof(*tp));
1118 tp->curData = tp->curParms = 0;
1119 tp->totalData = totalData;
1120 tp->totalParms = totalParms;
1121 tp->tid = smbp->tid;
1122 tp->mid = smbp->mid;
1123 tp->uid = smbp->uid;
1124 tp->pid = smbp->pid;
1125 tp->res[0] = smbp->res[0];
1126 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1127 if (totalParms != 0)
1128 tp->parmsp = malloc(totalParms);
1130 tp->datap = malloc(totalData);
1131 if (smbp->com == 0x25 || smbp->com == 0x26)
1134 tp->opcode = smb_GetSMBParm(inp, 14);
1137 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1141 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1142 smb_tran2Packet_t *inp, smb_packet_t *outp,
1143 int totalParms, int totalData)
1145 smb_tran2Packet_t *tp;
1146 unsigned short parmOffset;
1147 unsigned short dataOffset;
1148 unsigned short dataAlign;
1150 tp = malloc(sizeof(*tp));
1151 memset(tp, 0, sizeof(*tp));
1154 tp->curData = tp->curParms = 0;
1155 tp->totalData = totalData;
1156 tp->totalParms = totalParms;
1157 tp->oldTotalParms = totalParms;
1162 tp->res[0] = inp->res[0];
1163 tp->opcode = inp->opcode;
1167 * We calculate where the parameters and data will start.
1168 * This calculation must parallel the calculation in
1169 * smb_SendTran2Packet.
1172 parmOffset = 10*2 + 35;
1173 parmOffset++; /* round to even */
1174 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1176 dataOffset = parmOffset + totalParms;
1177 dataAlign = dataOffset & 2; /* quad-align */
1178 dataOffset += dataAlign;
1179 tp->datap = outp->data + dataOffset;
1184 /* free a tran2 packet */
1185 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1188 smb_ReleaseVC(t2p->vcp);
1191 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1200 /* called with a VC, an input packet to respond to, and an error code.
1201 * sends an error response.
1203 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1204 smb_packet_t *tp, long code)
1207 unsigned short errCode;
1208 unsigned char errClass;
1209 unsigned long NTStatus;
1211 if (vcp->flags & SMB_VCFLAG_STATUS32)
1212 smb_MapNTError(code, &NTStatus);
1214 smb_MapCoreError(code, vcp, &errCode, &errClass);
1216 smb_FormatResponsePacket(vcp, NULL, tp);
1217 smbp = (smb_t *) tp;
1219 /* We can handle long names */
1220 if (vcp->flags & SMB_VCFLAG_USENT)
1221 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1223 /* now copy important fields from the tran 2 packet */
1224 smbp->com = t2p->com;
1225 smbp->tid = t2p->tid;
1226 smbp->mid = t2p->mid;
1227 smbp->pid = t2p->pid;
1228 smbp->uid = t2p->uid;
1229 smbp->res[0] = t2p->res[0];
1230 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1231 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1232 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1233 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1234 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1235 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1238 smbp->rcls = errClass;
1239 smbp->errLow = (unsigned char) (errCode & 0xff);
1240 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1244 smb_SendPacket(vcp, tp);
1247 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1250 unsigned short parmOffset;
1251 unsigned short dataOffset;
1252 unsigned short totalLength;
1253 unsigned short dataAlign;
1256 smb_FormatResponsePacket(vcp, NULL, tp);
1257 smbp = (smb_t *) tp;
1259 /* We can handle long names */
1260 if (vcp->flags & SMB_VCFLAG_USENT)
1261 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1263 /* now copy important fields from the tran 2 packet */
1264 smbp->com = t2p->com;
1265 smbp->tid = t2p->tid;
1266 smbp->mid = t2p->mid;
1267 smbp->pid = t2p->pid;
1268 smbp->uid = t2p->uid;
1269 smbp->res[0] = t2p->res[0];
1271 totalLength = 1 + t2p->totalData + t2p->totalParms;
1273 /* now add the core parameters (tran2 info) to the packet */
1274 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1275 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1276 smb_SetSMBParm(tp, 2, 0); /* reserved */
1277 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1278 parmOffset = 10*2 + 35; /* parm offset in packet */
1279 parmOffset++; /* round to even */
1280 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1281 * hdr, bcc and wct */
1282 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1283 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1284 dataOffset = parmOffset + t2p->oldTotalParms;
1285 dataAlign = dataOffset & 2; /* quad-align */
1286 dataOffset += dataAlign;
1287 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1288 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1289 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1292 datap = smb_GetSMBData(tp, NULL);
1293 *datap++ = 0; /* we rounded to even */
1295 totalLength += dataAlign;
1296 smb_SetSMBDataLength(tp, totalLength);
1298 /* next, send the datagram */
1299 smb_SendPacket(vcp, tp);
1302 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1304 smb_tran2Packet_t *asp;
1317 /* We sometimes see 0 word count. What to do? */
1318 if (*inp->wctp == 0) {
1319 osi_Log0(smb_logp, "Transaction2 word count = 0");
1321 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1324 smb_SetSMBDataLength(outp, 0);
1325 smb_SendPacket(vcp, outp);
1329 totalParms = smb_GetSMBParm(inp, 0);
1330 totalData = smb_GetSMBParm(inp, 1);
1332 firstPacket = (inp->inCom == 0x25);
1334 /* find the packet we're reassembling */
1335 lock_ObtainWrite(&smb_globalLock);
1336 asp = smb_FindTran2Packet(vcp, inp);
1338 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1340 lock_ReleaseWrite(&smb_globalLock);
1342 /* now merge in this latest packet; start by looking up offsets */
1344 parmDisp = dataDisp = 0;
1345 parmOffset = smb_GetSMBParm(inp, 10);
1346 dataOffset = smb_GetSMBParm(inp, 12);
1347 parmCount = smb_GetSMBParm(inp, 9);
1348 dataCount = smb_GetSMBParm(inp, 11);
1349 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1350 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1352 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1353 totalData, dataCount, asp->maxReturnData);
1356 parmDisp = smb_GetSMBParm(inp, 4);
1357 parmOffset = smb_GetSMBParm(inp, 3);
1358 dataDisp = smb_GetSMBParm(inp, 7);
1359 dataOffset = smb_GetSMBParm(inp, 6);
1360 parmCount = smb_GetSMBParm(inp, 2);
1361 dataCount = smb_GetSMBParm(inp, 5);
1363 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1364 parmCount, dataCount);
1367 /* now copy the parms and data */
1368 if ( asp->totalParms > 0 && parmCount != 0 )
1370 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1372 if ( asp->totalData > 0 && dataCount != 0 ) {
1373 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1376 /* account for new bytes */
1377 asp->curData += dataCount;
1378 asp->curParms += parmCount;
1380 /* finally, if we're done, remove the packet from the queue and dispatch it */
1381 if (asp->totalParms > 0 &&
1382 asp->curParms > 0 &&
1383 asp->totalData <= asp->curData &&
1384 asp->totalParms <= asp->curParms) {
1385 /* we've received it all */
1386 lock_ObtainWrite(&smb_globalLock);
1387 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1388 lock_ReleaseWrite(&smb_globalLock);
1390 /* now dispatch it */
1391 rapOp = asp->parmsp[0];
1393 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1394 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1395 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1396 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
1399 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1400 code = CM_ERROR_BADOP;
1403 /* if an error is returned, we're supposed to send an error packet,
1404 * otherwise the dispatched function already did the data sending.
1405 * We give dispatched proc the responsibility since it knows how much
1406 * space to allocate.
1409 smb_SendTran2Error(vcp, asp, outp, code);
1412 /* free the input tran 2 packet */
1413 smb_FreeTran2Packet(asp);
1415 else if (firstPacket) {
1416 /* the first packet in a multi-packet request, we need to send an
1417 * ack to get more data.
1419 smb_SetSMBDataLength(outp, 0);
1420 smb_SendPacket(vcp, outp);
1426 /* ANSI versions. The unicode versions support arbitrary length
1427 share names, but we don't support unicode yet. */
1429 typedef struct smb_rap_share_info_0 {
1430 char shi0_netname[13];
1431 } smb_rap_share_info_0_t;
1433 typedef struct smb_rap_share_info_1 {
1434 char shi1_netname[13];
1437 DWORD shi1_remark; /* char *shi1_remark; data offset */
1438 } smb_rap_share_info_1_t;
1440 typedef struct smb_rap_share_info_2 {
1441 char shi2_netname[13];
1443 unsigned short shi2_type;
1444 DWORD shi2_remark; /* char *shi2_remark; data offset */
1445 unsigned short shi2_permissions;
1446 unsigned short shi2_max_uses;
1447 unsigned short shi2_current_uses;
1448 DWORD shi2_path; /* char *shi2_path; data offset */
1449 unsigned short shi2_passwd[9];
1450 unsigned short shi2_pad2;
1451 } smb_rap_share_info_2_t;
1453 #define SMB_RAP_MAX_SHARES 512
1455 typedef struct smb_rap_share_list {
1458 smb_rap_share_info_0_t * shares;
1459 } smb_rap_share_list_t;
1461 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1462 smb_rap_share_list_t * sp;
1467 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1468 return 0; /* skip over '.' and '..' */
1470 sp = (smb_rap_share_list_t *) vrockp;
1472 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1473 sp->shares[sp->cShare].shi0_netname[12] = 0;
1477 if (sp->cShare >= sp->maxShares)
1478 return CM_ERROR_STOPNOW;
1483 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1485 smb_tran2Packet_t *outp;
1486 unsigned short * tp;
1490 int outParmsTotal; /* total parameter bytes */
1491 int outDataTotal; /* total data bytes */
1494 DWORD allSubmount = 0;
1496 DWORD nRegShares = 0;
1497 DWORD nSharesRet = 0;
1499 HKEY hkSubmount = NULL;
1500 smb_rap_share_info_1_t * shares;
1503 char thisShare[256];
1507 smb_rap_share_list_t rootShares;
1512 tp = p->parmsp + 1; /* skip over function number (always 0) */
1513 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1514 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1518 if (infoLevel != 1) {
1519 return CM_ERROR_INVAL;
1522 /* first figure out how many shares there are */
1523 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1524 KEY_QUERY_VALUE, &hkParam);
1525 if (rv == ERROR_SUCCESS) {
1526 len = sizeof(allSubmount);
1527 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1528 (BYTE *) &allSubmount, &len);
1529 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1532 RegCloseKey (hkParam);
1535 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1536 0, KEY_QUERY_VALUE, &hkSubmount);
1537 if (rv == ERROR_SUCCESS) {
1538 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1539 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1540 if (rv != ERROR_SUCCESS)
1546 /* fetch the root shares */
1547 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1548 rootShares.cShare = 0;
1549 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1553 userp = smb_GetTran2User(vcp,p);
1555 thyper.HighPart = 0;
1558 cm_HoldSCache(cm_data.rootSCachep);
1559 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1560 cm_ReleaseSCache(cm_data.rootSCachep);
1562 cm_ReleaseUser(userp);
1564 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1566 #define REMARK_LEN 1
1567 outParmsTotal = 8; /* 4 dwords */
1568 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1569 if(outDataTotal > bufsize) {
1570 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1571 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1574 nSharesRet = nShares;
1577 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1579 /* now for the submounts */
1580 shares = (smb_rap_share_info_1_t *) outp->datap;
1581 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1583 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1586 strcpy( shares[cshare].shi1_netname, "all" );
1587 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1588 /* type and pad are zero already */
1594 for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
1595 len = sizeof(thisShare);
1596 rv = RegEnumValue(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
1597 if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1598 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1599 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1600 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1605 nShares--; /* uncount key */
1608 RegCloseKey(hkSubmount);
1611 nonrootShares = cshare;
1613 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1614 /* in case there are collisions with submounts, submounts have higher priority */
1615 for (j=0; j < nonrootShares; j++)
1616 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1619 if (j < nonrootShares) {
1620 nShares--; /* uncount */
1624 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1625 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1630 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1631 outp->parmsp[1] = 0;
1632 outp->parmsp[2] = cshare;
1633 outp->parmsp[3] = nShares;
1635 outp->totalData = (int)(cstrp - outp->datap);
1636 outp->totalParms = outParmsTotal;
1638 smb_SendTran2Packet(vcp, outp, op);
1639 smb_FreeTran2Packet(outp);
1641 free(rootShares.shares);
1646 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1648 smb_tran2Packet_t *outp;
1649 unsigned short * tp;
1651 BOOL shareFound = FALSE;
1652 unsigned short infoLevel;
1653 unsigned short bufsize;
1663 tp = p->parmsp + 1; /* skip over function number (always 1) */
1664 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1665 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1666 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1673 totalData = sizeof(smb_rap_share_info_0_t);
1674 else if(infoLevel == SMB_INFO_STANDARD)
1675 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1676 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1677 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1679 return CM_ERROR_INVAL;
1681 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1683 if(!stricmp(shareName,"all") || !strcmp(shareName,"*.")) {
1684 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1685 KEY_QUERY_VALUE, &hkParam);
1686 if (rv == ERROR_SUCCESS) {
1687 len = sizeof(allSubmount);
1688 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1689 (BYTE *) &allSubmount, &len);
1690 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1693 RegCloseKey (hkParam);
1700 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1701 KEY_QUERY_VALUE, &hkSubmount);
1702 if (rv == ERROR_SUCCESS) {
1703 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1704 if (rv == ERROR_SUCCESS) {
1707 RegCloseKey(hkSubmount);
1712 smb_FreeTran2Packet(outp);
1713 return CM_ERROR_BADSHARENAME;
1716 memset(outp->datap, 0, totalData);
1718 outp->parmsp[0] = 0;
1719 outp->parmsp[1] = 0;
1720 outp->parmsp[2] = totalData;
1722 if (infoLevel == 0) {
1723 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1724 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1725 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1726 } else if(infoLevel == SMB_INFO_STANDARD) {
1727 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1728 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1729 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1730 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1731 /* type and pad are already zero */
1732 } else { /* infoLevel==2 */
1733 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1734 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1735 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1736 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1737 info->shi2_permissions = ACCESS_ALL;
1738 info->shi2_max_uses = (unsigned short) -1;
1739 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
1742 outp->totalData = totalData;
1743 outp->totalParms = totalParam;
1745 smb_SendTran2Packet(vcp, outp, op);
1746 smb_FreeTran2Packet(outp);
1751 typedef struct smb_rap_wksta_info_10 {
1752 DWORD wki10_computername; /*char *wki10_computername;*/
1753 DWORD wki10_username; /* char *wki10_username; */
1754 DWORD wki10_langroup; /* char *wki10_langroup;*/
1755 unsigned char wki10_ver_major;
1756 unsigned char wki10_ver_minor;
1757 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1758 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1759 } smb_rap_wksta_info_10_t;
1762 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1764 smb_tran2Packet_t *outp;
1768 unsigned short * tp;
1771 smb_rap_wksta_info_10_t * info;
1775 tp = p->parmsp + 1; /* Skip over function number */
1776 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1777 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1781 if (infoLevel != 10) {
1782 return CM_ERROR_INVAL;
1788 totalData = sizeof(*info) + /* info */
1789 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1790 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1791 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1792 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1793 1; /* wki10_oth_domains (null)*/
1795 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1797 memset(outp->parmsp,0,totalParams);
1798 memset(outp->datap,0,totalData);
1800 info = (smb_rap_wksta_info_10_t *) outp->datap;
1801 cstrp = (char *) (info + 1);
1803 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1804 strcpy(cstrp, smb_localNamep);
1805 cstrp += strlen(cstrp) + 1;
1807 info->wki10_username = (DWORD) (cstrp - outp->datap);
1808 uidp = smb_FindUID(vcp, p->uid, 0);
1810 lock_ObtainMutex(&uidp->mx);
1811 if(uidp->unp && uidp->unp->name)
1812 strcpy(cstrp, uidp->unp->name);
1813 lock_ReleaseMutex(&uidp->mx);
1814 smb_ReleaseUID(uidp);
1816 cstrp += strlen(cstrp) + 1;
1818 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1819 strcpy(cstrp, "WORKGROUP");
1820 cstrp += strlen(cstrp) + 1;
1822 /* TODO: Not sure what values these should take, but these work */
1823 info->wki10_ver_major = 5;
1824 info->wki10_ver_minor = 1;
1826 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1827 strcpy(cstrp, smb_ServerDomainName);
1828 cstrp += strlen(cstrp) + 1;
1830 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1831 cstrp ++; /* no other domains */
1833 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1834 outp->parmsp[2] = outp->totalData;
1835 outp->totalParms = totalParams;
1837 smb_SendTran2Packet(vcp,outp,op);
1838 smb_FreeTran2Packet(outp);
1843 typedef struct smb_rap_server_info_0 {
1845 } smb_rap_server_info_0_t;
1847 typedef struct smb_rap_server_info_1 {
1849 char sv1_version_major;
1850 char sv1_version_minor;
1851 unsigned long sv1_type;
1852 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1853 } smb_rap_server_info_1_t;
1855 char smb_ServerComment[] = "OpenAFS Client";
1856 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1858 #define SMB_SV_TYPE_SERVER 0x00000002L
1859 #define SMB_SV_TYPE_NT 0x00001000L
1860 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1862 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1864 smb_tran2Packet_t *outp;
1868 unsigned short * tp;
1871 smb_rap_server_info_0_t * info0;
1872 smb_rap_server_info_1_t * info1;
1875 tp = p->parmsp + 1; /* Skip over function number */
1876 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1877 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1881 if (infoLevel != 0 && infoLevel != 1) {
1882 return CM_ERROR_INVAL;
1888 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1889 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1891 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1893 memset(outp->parmsp,0,totalParams);
1894 memset(outp->datap,0,totalData);
1896 if (infoLevel == 0) {
1897 info0 = (smb_rap_server_info_0_t *) outp->datap;
1898 cstrp = (char *) (info0 + 1);
1899 strcpy(info0->sv0_name, "AFS");
1900 } else { /* infoLevel == SMB_INFO_STANDARD */
1901 info1 = (smb_rap_server_info_1_t *) outp->datap;
1902 cstrp = (char *) (info1 + 1);
1903 strcpy(info1->sv1_name, "AFS");
1906 SMB_SV_TYPE_SERVER |
1908 SMB_SV_TYPE_SERVER_NT;
1910 info1->sv1_version_major = 5;
1911 info1->sv1_version_minor = 1;
1912 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1914 strcpy(cstrp, smb_ServerComment);
1916 cstrp += smb_ServerCommentLen;
1919 totalData = (DWORD)(cstrp - outp->datap);
1920 outp->totalData = min(bufsize,totalData); /* actual data size */
1921 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1922 outp->parmsp[2] = totalData;
1923 outp->totalParms = totalParams;
1925 smb_SendTran2Packet(vcp,outp,op);
1926 smb_FreeTran2Packet(outp);
1931 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1933 smb_tran2Packet_t *asp;
1945 /* We sometimes see 0 word count. What to do? */
1946 if (*inp->wctp == 0) {
1947 osi_Log0(smb_logp, "Transaction2 word count = 0");
1949 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1952 smb_SetSMBDataLength(outp, 0);
1953 smb_SendPacket(vcp, outp);
1957 totalParms = smb_GetSMBParm(inp, 0);
1958 totalData = smb_GetSMBParm(inp, 1);
1960 firstPacket = (inp->inCom == 0x32);
1962 /* find the packet we're reassembling */
1963 lock_ObtainWrite(&smb_globalLock);
1964 asp = smb_FindTran2Packet(vcp, inp);
1966 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1968 lock_ReleaseWrite(&smb_globalLock);
1970 /* now merge in this latest packet; start by looking up offsets */
1972 parmDisp = dataDisp = 0;
1973 parmOffset = smb_GetSMBParm(inp, 10);
1974 dataOffset = smb_GetSMBParm(inp, 12);
1975 parmCount = smb_GetSMBParm(inp, 9);
1976 dataCount = smb_GetSMBParm(inp, 11);
1977 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1978 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1980 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1981 totalData, dataCount, asp->maxReturnData);
1984 parmDisp = smb_GetSMBParm(inp, 4);
1985 parmOffset = smb_GetSMBParm(inp, 3);
1986 dataDisp = smb_GetSMBParm(inp, 7);
1987 dataOffset = smb_GetSMBParm(inp, 6);
1988 parmCount = smb_GetSMBParm(inp, 2);
1989 dataCount = smb_GetSMBParm(inp, 5);
1991 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1992 parmCount, dataCount);
1995 /* now copy the parms and data */
1996 if ( asp->totalParms > 0 && parmCount != 0 )
1998 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2000 if ( asp->totalData > 0 && dataCount != 0 ) {
2001 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2004 /* account for new bytes */
2005 asp->curData += dataCount;
2006 asp->curParms += parmCount;
2008 /* finally, if we're done, remove the packet from the queue and dispatch it */
2009 if (asp->totalParms > 0 &&
2010 asp->curParms > 0 &&
2011 asp->totalData <= asp->curData &&
2012 asp->totalParms <= asp->curParms) {
2013 /* we've received it all */
2014 lock_ObtainWrite(&smb_globalLock);
2015 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2016 lock_ReleaseWrite(&smb_globalLock);
2018 /* now dispatch it */
2019 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2020 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2021 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2024 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2025 code = CM_ERROR_BADOP;
2028 /* if an error is returned, we're supposed to send an error packet,
2029 * otherwise the dispatched function already did the data sending.
2030 * We give dispatched proc the responsibility since it knows how much
2031 * space to allocate.
2034 smb_SendTran2Error(vcp, asp, outp, code);
2037 /* free the input tran 2 packet */
2038 smb_FreeTran2Packet(asp);
2040 else if (firstPacket) {
2041 /* the first packet in a multi-packet request, we need to send an
2042 * ack to get more data.
2044 smb_SetSMBDataLength(outp, 0);
2045 smb_SendPacket(vcp, outp);
2051 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2054 smb_tran2Packet_t *outp;
2059 cm_scache_t *dscp; /* dir we're dealing with */
2060 cm_scache_t *scp; /* file we're creating */
2062 int initialModeBits;
2072 int parmSlot; /* which parm we're dealing with */
2073 long returnEALength;
2082 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2083 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2085 openFun = p->parmsp[6]; /* open function */
2086 excl = ((openFun & 3) == 0);
2087 trunc = ((openFun & 3) == 2); /* truncate it */
2088 openMode = (p->parmsp[1] & 0x7);
2089 openAction = 0; /* tracks what we did */
2091 attributes = p->parmsp[3];
2092 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2094 /* compute initial mode bits based on read-only flag in attributes */
2095 initialModeBits = 0666;
2096 if (attributes & SMB_ATTR_READONLY)
2097 initialModeBits &= ~0222;
2099 pathp = (char *) (&p->parmsp[14]);
2100 if (smb_StoreAnsiFilenames)
2101 OemToChar(pathp,pathp);
2103 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2105 spacep = cm_GetSpace();
2106 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2108 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2109 /* special case magic file name for receiving IOCTL requests
2110 * (since IOCTL calls themselves aren't getting through).
2112 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2113 smb_SetupIoctlFid(fidp, spacep);
2115 /* copy out remainder of the parms */
2117 outp->parmsp[parmSlot++] = fidp->fid;
2119 outp->parmsp[parmSlot++] = 0; /* attrs */
2120 outp->parmsp[parmSlot++] = 0; /* mod time */
2121 outp->parmsp[parmSlot++] = 0;
2122 outp->parmsp[parmSlot++] = 0; /* len */
2123 outp->parmsp[parmSlot++] = 0x7fff;
2124 outp->parmsp[parmSlot++] = openMode;
2125 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2126 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2128 /* and the final "always present" stuff */
2129 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2130 /* next write out the "unique" ID */
2131 outp->parmsp[parmSlot++] = 0x1234;
2132 outp->parmsp[parmSlot++] = 0x5678;
2133 outp->parmsp[parmSlot++] = 0;
2134 if (returnEALength) {
2135 outp->parmsp[parmSlot++] = 0;
2136 outp->parmsp[parmSlot++] = 0;
2139 outp->totalData = 0;
2140 outp->totalParms = parmSlot * 2;
2142 smb_SendTran2Packet(vcp, outp, op);
2144 smb_FreeTran2Packet(outp);
2146 /* and clean up fid reference */
2147 smb_ReleaseFID(fidp);
2151 #ifdef DEBUG_VERBOSE
2153 char *hexp, *asciip;
2154 asciip = (lastNamep ? lastNamep : pathp);
2155 hexp = osi_HexifyString( asciip );
2156 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2161 userp = smb_GetTran2User(vcp, p);
2162 /* In the off chance that userp is NULL, we log and abandon */
2164 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2165 smb_FreeTran2Packet(outp);
2166 return CM_ERROR_BADSMB;
2169 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2170 if (code == CM_ERROR_TIDIPC) {
2171 /* Attempt to use a TID allocated for IPC. The client
2172 * is probably looking for DCE RPC end points which we
2173 * don't support OR it could be looking to make a DFS
2176 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2178 cm_ReleaseUser(userp);
2179 smb_FreeTran2Packet(outp);
2180 return CM_ERROR_NOSUCHPATH;
2185 code = cm_NameI(cm_data.rootSCachep, pathp,
2186 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2187 userp, tidPathp, &req, &scp);
2189 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2190 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2191 userp, tidPathp, &req, &dscp);
2192 cm_FreeSpace(spacep);
2195 cm_ReleaseUser(userp);
2196 smb_FreeTran2Packet(outp);
2201 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2202 cm_ReleaseSCache(dscp);
2203 cm_ReleaseUser(userp);
2204 smb_FreeTran2Packet(outp);
2205 if ( WANTS_DFS_PATHNAMES(p) )
2206 return CM_ERROR_PATH_NOT_COVERED;
2208 return CM_ERROR_BADSHARENAME;
2210 #endif /* DFS_SUPPORT */
2212 /* otherwise, scp points to the parent directory. Do a lookup,
2213 * and truncate the file if we find it, otherwise we create the
2220 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2222 if (code && code != CM_ERROR_NOSUCHFILE) {
2223 cm_ReleaseSCache(dscp);
2224 cm_ReleaseUser(userp);
2225 smb_FreeTran2Packet(outp);
2230 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2231 cm_ReleaseSCache(scp);
2232 cm_ReleaseUser(userp);
2233 smb_FreeTran2Packet(outp);
2234 if ( WANTS_DFS_PATHNAMES(p) )
2235 return CM_ERROR_PATH_NOT_COVERED;
2237 return CM_ERROR_BADSHARENAME;
2239 #endif /* DFS_SUPPORT */
2241 /* macintosh is expensive to program for it */
2242 cm_FreeSpace(spacep);
2245 /* if we get here, if code is 0, the file exists and is represented by
2246 * scp. Otherwise, we have to create it.
2249 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2252 cm_ReleaseSCache(dscp);
2253 cm_ReleaseSCache(scp);
2254 cm_ReleaseUser(userp);
2255 smb_FreeTran2Packet(outp);
2260 /* oops, file shouldn't be there */
2262 cm_ReleaseSCache(dscp);
2263 cm_ReleaseSCache(scp);
2264 cm_ReleaseUser(userp);
2265 smb_FreeTran2Packet(outp);
2266 return CM_ERROR_EXISTS;
2270 setAttr.mask = CM_ATTRMASK_LENGTH;
2271 setAttr.length.LowPart = 0;
2272 setAttr.length.HighPart = 0;
2273 code = cm_SetAttr(scp, &setAttr, userp, &req);
2274 openAction = 3; /* truncated existing file */
2277 openAction = 1; /* found existing file */
2279 else if (!(openFun & 0x10)) {
2280 /* don't create if not found */
2282 cm_ReleaseSCache(dscp);
2283 osi_assert(scp == NULL);
2284 cm_ReleaseUser(userp);
2285 smb_FreeTran2Packet(outp);
2286 return CM_ERROR_NOSUCHFILE;
2289 osi_assert(dscp != NULL && scp == NULL);
2290 openAction = 2; /* created file */
2291 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2292 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2293 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2297 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2298 smb_NotifyChange(FILE_ACTION_ADDED,
2299 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2300 dscp, lastNamep, NULL, TRUE);
2301 } else if (!excl && code == CM_ERROR_EXISTS) {
2302 /* not an exclusive create, and someone else tried
2303 * creating it already, then we open it anyway. We
2304 * don't bother retrying after this, since if this next
2305 * fails, that means that the file was deleted after we
2306 * started this call.
2308 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2312 setAttr.mask = CM_ATTRMASK_LENGTH;
2313 setAttr.length.LowPart = 0;
2314 setAttr.length.HighPart = 0;
2315 code = cm_SetAttr(scp, &setAttr, userp,
2318 } /* lookup succeeded */
2322 /* we don't need this any longer */
2324 cm_ReleaseSCache(dscp);
2327 /* something went wrong creating or truncating the file */
2329 cm_ReleaseSCache(scp);
2330 cm_ReleaseUser(userp);
2331 smb_FreeTran2Packet(outp);
2335 /* make sure we're about to open a file */
2336 if (scp->fileType != CM_SCACHETYPE_FILE) {
2338 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2339 cm_scache_t * targetScp = 0;
2340 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2342 /* we have a more accurate file to use (the
2343 * target of the symbolic link). Otherwise,
2344 * we'll just use the symlink anyway.
2346 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2348 cm_ReleaseSCache(scp);
2352 if (scp->fileType != CM_SCACHETYPE_FILE) {
2353 cm_ReleaseSCache(scp);
2354 cm_ReleaseUser(userp);
2355 smb_FreeTran2Packet(outp);
2356 return CM_ERROR_ISDIR;
2360 /* now all we have to do is open the file itself */
2361 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2365 lock_ObtainMutex(&fidp->mx);
2366 /* save a pointer to the vnode */
2367 osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2369 lock_ObtainMutex(&scp->mx);
2370 scp->flags |= CM_SCACHEFLAG_SMB_FID;
2371 lock_ReleaseMutex(&scp->mx);
2374 fidp->userp = userp;
2376 /* compute open mode */
2378 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
2379 if (openMode == 1 || openMode == 2)
2380 fidp->flags |= SMB_FID_OPENWRITE;
2382 /* remember that the file was newly created */
2384 fidp->flags |= SMB_FID_CREATED;
2386 lock_ReleaseMutex(&fidp->mx);
2388 smb_ReleaseFID(fidp);
2390 cm_Open(scp, 0, userp);
2392 /* copy out remainder of the parms */
2394 outp->parmsp[parmSlot++] = fidp->fid;
2395 lock_ObtainMutex(&scp->mx);
2397 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2398 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2399 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2400 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2401 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2402 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2403 outp->parmsp[parmSlot++] = openMode;
2404 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2405 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2407 /* and the final "always present" stuff */
2408 outp->parmsp[parmSlot++] = openAction;
2409 /* next write out the "unique" ID */
2410 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2411 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2412 outp->parmsp[parmSlot++] = 0;
2413 if (returnEALength) {
2414 outp->parmsp[parmSlot++] = 0;
2415 outp->parmsp[parmSlot++] = 0;
2417 lock_ReleaseMutex(&scp->mx);
2418 outp->totalData = 0; /* total # of data bytes */
2419 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2421 smb_SendTran2Packet(vcp, outp, op);
2423 smb_FreeTran2Packet(outp);
2425 cm_ReleaseUser(userp);
2426 /* leave scp held since we put it in fidp->scp */
2430 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2433 unsigned short infolevel;
2435 infolevel = p->parmsp[0];
2437 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2439 return CM_ERROR_BAD_LEVEL;
2442 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2444 smb_tran2Packet_t *outp;
2445 smb_tran2QFSInfo_t qi;
2447 static char FSname[8] = {'A', 0, 'F', 0, 'S', 0, 0, 0};
2449 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2451 switch (p->parmsp[0]) {
2452 case SMB_INFO_ALLOCATION:
2453 responseSize = sizeof(qi.u.allocInfo);
2455 case SMB_INFO_VOLUME:
2456 responseSize = sizeof(qi.u.volumeInfo);
2458 case SMB_QUERY_FS_VOLUME_INFO:
2459 responseSize = sizeof(qi.u.FSvolumeInfo);
2461 case SMB_QUERY_FS_SIZE_INFO:
2462 responseSize = sizeof(qi.u.FSsizeInfo);
2464 case SMB_QUERY_FS_DEVICE_INFO:
2465 responseSize = sizeof(qi.u.FSdeviceInfo);
2467 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2468 responseSize = sizeof(qi.u.FSattributeInfo);
2470 case SMB_INFO_UNIX: /* CIFS Unix Info */
2471 case SMB_INFO_MACOS: /* Mac FS Info */
2473 return CM_ERROR_BADOP;
2476 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2477 switch (p->parmsp[0]) {
2478 case SMB_INFO_ALLOCATION:
2480 qi.u.allocInfo.FSID = 0;
2481 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2482 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2483 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2484 qi.u.allocInfo.bytesPerSector = 1024;
2487 case SMB_INFO_VOLUME:
2489 qi.u.volumeInfo.vsn = 1234;
2490 qi.u.volumeInfo.vnCount = 4;
2491 /* we're supposed to pad it out with zeroes to the end */
2492 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2493 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2496 case SMB_QUERY_FS_VOLUME_INFO:
2497 /* FS volume info */
2498 memset((char *)&qi.u.FSvolumeInfo.vct, 0, 4);
2499 qi.u.FSvolumeInfo.vsn = 1234;
2500 qi.u.FSvolumeInfo.vnCount = 8;
2501 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0\0", 8);
2504 case SMB_QUERY_FS_SIZE_INFO:
2506 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2507 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2508 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2509 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2510 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2511 qi.u.FSsizeInfo.bytesPerSector = 1024;
2514 case SMB_QUERY_FS_DEVICE_INFO:
2515 /* FS device info */
2516 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2517 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2520 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2521 /* FS attribute info */
2522 /* attributes, defined in WINNT.H:
2523 * FILE_CASE_SENSITIVE_SEARCH 0x1
2524 * FILE_CASE_PRESERVED_NAMES 0x2
2525 * FILE_VOLUME_QUOTAS 0x10
2526 * <no name defined> 0x4000
2527 * If bit 0x4000 is not set, Windows 95 thinks
2528 * we can't handle long (non-8.3) names,
2529 * despite our protestations to the contrary.
2531 qi.u.FSattributeInfo.attributes = 0x4003;
2532 qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
2533 qi.u.FSattributeInfo.FSnameLength = sizeof(FSname);
2534 memcpy(qi.u.FSattributeInfo.FSname, FSname, sizeof(FSname));
2538 /* copy out return data, and set corresponding sizes */
2539 outp->totalParms = 0;
2540 outp->totalData = responseSize;
2541 memcpy(outp->datap, &qi, responseSize);
2543 /* send and free the packets */
2544 smb_SendTran2Packet(vcp, outp, op);
2545 smb_FreeTran2Packet(outp);
2550 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2552 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2553 return CM_ERROR_BADOP;
2556 struct smb_ShortNameRock {
2560 size_t shortNameLen;
2563 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2566 struct smb_ShortNameRock *rockp;
2570 /* compare both names and vnodes, though probably just comparing vnodes
2571 * would be safe enough.
2573 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2575 if (ntohl(dep->fid.vnode) != rockp->vnode)
2577 /* This is the entry */
2578 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2579 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2580 return CM_ERROR_STOPNOW;
2583 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2584 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2586 struct smb_ShortNameRock rock;
2590 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2594 spacep = cm_GetSpace();
2595 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2597 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2599 cm_FreeSpace(spacep);
2604 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2605 cm_ReleaseSCache(dscp);
2606 cm_ReleaseUser(userp);
2607 return CM_ERROR_PATH_NOT_COVERED;
2609 #endif /* DFS_SUPPORT */
2611 if (!lastNamep) lastNamep = pathp;
2614 thyper.HighPart = 0;
2615 rock.shortName = shortName;
2617 rock.maskp = lastNamep;
2618 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2620 cm_ReleaseSCache(dscp);
2623 return CM_ERROR_NOSUCHFILE;
2624 if (code == CM_ERROR_STOPNOW) {
2625 *shortNameLenp = rock.shortNameLen;
2631 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2633 smb_tran2Packet_t *outp;
2636 unsigned short infoLevel;
2637 smb_tran2QPathInfo_t qpi;
2639 unsigned short attributes;
2640 unsigned long extAttributes;
2645 cm_scache_t *scp, *dscp;
2646 int scp_mx_held = 0;
2656 infoLevel = p->parmsp[0];
2657 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2659 else if (infoLevel == SMB_INFO_STANDARD)
2660 responseSize = sizeof(qpi.u.QPstandardInfo);
2661 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2662 responseSize = sizeof(qpi.u.QPeaSizeInfo);
2663 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2664 responseSize = sizeof(qpi.u.QPfileBasicInfo);
2665 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2666 responseSize = sizeof(qpi.u.QPfileStandardInfo);
2667 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2668 responseSize = sizeof(qpi.u.QPfileEaInfo);
2669 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2670 responseSize = sizeof(qpi.u.QPfileNameInfo);
2671 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
2672 responseSize = sizeof(qpi.u.QPfileAllInfo);
2673 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2674 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2676 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2677 p->opcode, infoLevel);
2678 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
2682 pathp = (char *)(&p->parmsp[3]);
2683 if (smb_StoreAnsiFilenames)
2684 OemToChar(pathp,pathp);
2685 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2686 osi_LogSaveString(smb_logp, pathp));
2688 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2690 if (infoLevel > 0x100)
2691 outp->totalParms = 2;
2693 outp->totalParms = 0;
2694 outp->totalData = responseSize;
2696 /* now, if we're at infoLevel 6, we're only being asked to check
2697 * the syntax, so we just OK things now. In particular, we're *not*
2698 * being asked to verify anything about the state of any parent dirs.
2700 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2701 smb_SendTran2Packet(vcp, outp, opx);
2702 smb_FreeTran2Packet(outp);
2706 userp = smb_GetTran2User(vcp, p);
2708 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2709 smb_FreeTran2Packet(outp);
2710 return CM_ERROR_BADSMB;
2713 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2715 cm_ReleaseUser(userp);
2716 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2717 smb_FreeTran2Packet(outp);
2722 * XXX Strange hack XXX
2724 * As of Patch 7 (13 January 98), we are having the following problem:
2725 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2726 * requests to look up "desktop.ini" in all the subdirectories.
2727 * This can cause zillions of timeouts looking up non-existent cells
2728 * and volumes, especially in the top-level directory.
2730 * We have not found any way to avoid this or work around it except
2731 * to explicitly ignore the requests for mount points that haven't
2732 * yet been evaluated and for directories that haven't yet been
2735 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2736 spacep = cm_GetSpace();
2737 smb_StripLastComponent(spacep->data, &lastComp, pathp);
2738 #ifndef SPECIAL_FOLDERS
2739 /* Make sure that lastComp is not NULL */
2741 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2742 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2746 userp, tidPathp, &req, &dscp);
2749 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2750 if ( WANTS_DFS_PATHNAMES(p) )
2751 code = CM_ERROR_PATH_NOT_COVERED;
2753 code = CM_ERROR_BADSHARENAME;
2755 #endif /* DFS_SUPPORT */
2756 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2757 code = CM_ERROR_NOSUCHFILE;
2758 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2759 cm_buf_t *bp = buf_Find(dscp, &hzero);
2763 code = CM_ERROR_NOSUCHFILE;
2765 cm_ReleaseSCache(dscp);
2767 cm_FreeSpace(spacep);
2768 cm_ReleaseUser(userp);
2769 smb_SendTran2Error(vcp, p, opx, code);
2770 smb_FreeTran2Packet(outp);
2776 #endif /* SPECIAL_FOLDERS */
2778 cm_FreeSpace(spacep);
2781 /* now do namei and stat, and copy out the info */
2782 code = cm_NameI(cm_data.rootSCachep, pathp,
2783 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2786 cm_ReleaseUser(userp);
2787 smb_SendTran2Error(vcp, p, opx, code);
2788 smb_FreeTran2Packet(outp);
2793 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2794 cm_ReleaseSCache(scp);
2795 cm_ReleaseUser(userp);
2796 if ( WANTS_DFS_PATHNAMES(p) )
2797 code = CM_ERROR_PATH_NOT_COVERED;
2799 code = CM_ERROR_BADSHARENAME;
2800 smb_SendTran2Error(vcp, p, opx, code);
2801 smb_FreeTran2Packet(outp);
2804 #endif /* DFS_SUPPORT */
2806 lock_ObtainMutex(&scp->mx);
2808 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2809 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2810 if (code) goto done;
2812 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2814 /* now we have the status in the cache entry, and everything is locked.
2815 * Marshall the output data.
2817 /* for info level 108, figure out short name */
2818 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
2819 code = cm_GetShortName(pathp, userp, &req,
2820 tidPathp, scp->fid.vnode, shortName,
2826 qpi.u.QPfileAltNameInfo.fileNameLength = (len + 1) * 2;
2827 mbstowcs((unsigned short *)qpi.u.QPfileAltNameInfo.fileName, shortName, len + 1);
2831 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2832 len = strlen(lastComp);
2833 qpi.u.QPfileNameInfo.fileNameLength = (len + 1) * 2;
2834 mbstowcs((unsigned short *)qpi.u.QPfileNameInfo.fileName, lastComp, len + 1);
2838 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2839 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2840 qpi.u.QPstandardInfo.creationDateTime = dosTime;
2841 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
2842 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
2843 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
2844 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
2845 attributes = smb_Attributes(scp);
2846 qpi.u.QPstandardInfo.attributes = attributes;
2847 qpi.u.QPstandardInfo.eaSize = 0;
2849 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2850 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2851 qpi.u.QPfileBasicInfo.creationTime = ft;
2852 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
2853 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
2854 qpi.u.QPfileBasicInfo.changeTime = ft;
2855 extAttributes = smb_ExtAttributes(scp);
2856 qpi.u.QPfileBasicInfo.attributes = extAttributes;
2857 qpi.u.QPfileBasicInfo.reserved = 0;
2859 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2860 smb_fid_t *fidp = smb_FindFIDByScache(vcp, scp);
2862 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
2863 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
2864 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
2865 qpi.u.QPfileStandardInfo.directory =
2866 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2867 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2868 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2869 qpi.u.QPfileStandardInfo.reserved = 0;
2872 lock_ReleaseMutex(&scp->mx);
2874 lock_ObtainMutex(&fidp->mx);
2875 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
2876 lock_ReleaseMutex(&fidp->mx);
2877 smb_ReleaseFID(fidp);
2879 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
2881 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2882 qpi.u.QPfileEaInfo.eaSize = 0;
2884 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
2885 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2886 qpi.u.QPfileAllInfo.creationTime = ft;
2887 qpi.u.QPfileAllInfo.lastAccessTime = ft;
2888 qpi.u.QPfileAllInfo.lastWriteTime = ft;
2889 qpi.u.QPfileAllInfo.changeTime = ft;
2890 extAttributes = smb_ExtAttributes(scp);
2891 qpi.u.QPfileAllInfo.attributes = extAttributes;
2892 qpi.u.QPfileAllInfo.allocationSize = scp->length;
2893 qpi.u.QPfileAllInfo.endOfFile = scp->length;
2894 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
2895 qpi.u.QPfileAllInfo.deletePending = 0;
2896 qpi.u.QPfileAllInfo.directory =
2897 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2898 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2899 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2900 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
2901 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
2902 qpi.u.QPfileAllInfo.eaSize = 0;
2903 qpi.u.QPfileAllInfo.accessFlags = 0;
2904 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
2905 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
2906 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
2907 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
2908 qpi.u.QPfileAllInfo.mode = 0;
2909 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
2910 len = strlen(lastComp);
2911 qpi.u.QPfileAllInfo.fileNameLength = (len + 1) * 2;
2912 mbstowcs((unsigned short *)qpi.u.QPfileAllInfo.fileName, lastComp, len + 1);
2915 /* send and free the packets */
2918 lock_ReleaseMutex(&scp->mx);
2919 cm_ReleaseSCache(scp);
2920 cm_ReleaseUser(userp);
2922 memcpy(outp->datap, &qpi, responseSize);
2923 smb_SendTran2Packet(vcp, outp, opx);
2925 smb_SendTran2Error(vcp, p, opx, code);
2927 smb_FreeTran2Packet(outp);
2932 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2935 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2936 return CM_ERROR_BADOP;
2940 unsigned short infoLevel;
2942 smb_tran2Packet_t *outp;
2943 smb_tran2QPathInfo_t *spi;
2945 cm_scache_t *scp, *dscp;
2953 infoLevel = p->parmsp[0];
2954 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
2955 if (infoLevel != SMB_INFO_STANDARD &&
2956 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
2957 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
2958 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2959 p->opcode, infoLevel);
2960 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
2964 pathp = (char *)(&p->parmsp[3]);
2965 if (smb_StoreAnsiFilenames)
2966 OemToChar(pathp,pathp);
2967 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %s", infoLevel,
2968 osi_LogSaveString(smb_logp, pathp));
2970 userp = smb_GetTran2User(vcp, p);
2972 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
2973 code = CM_ERROR_BADSMB;
2977 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2978 if (code == CM_ERROR_TIDIPC) {
2979 /* Attempt to use a TID allocated for IPC. The client
2980 * is probably looking for DCE RPC end points which we
2981 * don't support OR it could be looking to make a DFS
2984 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2985 cm_ReleaseUser(userp);
2986 return CM_ERROR_NOSUCHPATH;
2990 * XXX Strange hack XXX
2992 * As of Patch 7 (13 January 98), we are having the following problem:
2993 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2994 * requests to look up "desktop.ini" in all the subdirectories.
2995 * This can cause zillions of timeouts looking up non-existent cells
2996 * and volumes, especially in the top-level directory.
2998 * We have not found any way to avoid this or work around it except
2999 * to explicitly ignore the requests for mount points that haven't
3000 * yet been evaluated and for directories that haven't yet been
3003 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3004 spacep = cm_GetSpace();
3005 smb_StripLastComponent(spacep->data, &lastComp, pathp);
3006 #ifndef SPECIAL_FOLDERS
3007 /* Make sure that lastComp is not NULL */
3009 if (stricmp(lastComp, "\\desktop.ini") == 0) {
3010 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3014 userp, tidPathp, &req, &dscp);
3017 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3018 if ( WANTS_DFS_PATHNAMES(p) )
3019 code = CM_ERROR_PATH_NOT_COVERED;
3021 code = CM_ERROR_BADSHARENAME;
3023 #endif /* DFS_SUPPORT */
3024 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3025 code = CM_ERROR_NOSUCHFILE;
3026 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3027 cm_buf_t *bp = buf_Find(dscp, &hzero);
3031 code = CM_ERROR_NOSUCHFILE;
3033 cm_ReleaseSCache(dscp);
3035 cm_FreeSpace(spacep);
3036 cm_ReleaseUser(userp);
3037 smb_SendTran2Error(vcp, p, opx, code);
3043 #endif /* SPECIAL_FOLDERS */
3045 cm_FreeSpace(spacep);
3048 /* now do namei and stat, and copy out the info */
3049 code = cm_NameI(cm_data.rootSCachep, pathp,
3050 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3052 cm_ReleaseUser(userp);
3053 smb_SendTran2Error(vcp, p, opx, code);
3057 fidp = smb_FindFIDByScache(vcp, scp);
3059 cm_ReleaseSCache(scp);
3060 cm_ReleaseUser(userp);
3061 smb_SendTran2Error(vcp, p, opx, code);
3065 lock_ObtainMutex(&fidp->mx);
3066 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
3067 lock_ReleaseMutex(&fidp->mx);
3068 cm_ReleaseSCache(scp);
3069 smb_ReleaseFID(fidp);
3070 cm_ReleaseUser(userp);
3071 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3074 lock_ReleaseMutex(&fidp->mx);
3076 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3078 outp->totalParms = 2;
3079 outp->totalData = 0;
3081 spi = (smb_tran2QPathInfo_t *)p->datap;
3082 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3085 /* lock the vnode with a callback; we need the current status
3086 * to determine what the new status is, in some cases.
3088 lock_ObtainMutex(&scp->mx);
3089 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3090 CM_SCACHESYNC_GETSTATUS
3091 | CM_SCACHESYNC_NEEDCALLBACK);
3093 lock_ReleaseMutex(&scp->mx);
3096 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3098 lock_ReleaseMutex(&scp->mx);
3099 lock_ObtainMutex(&fidp->mx);
3100 lock_ObtainMutex(&scp->mx);
3102 /* prepare for setattr call */
3103 attr.mask = CM_ATTRMASK_LENGTH;
3104 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3105 attr.length.HighPart = 0;
3107 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3108 smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3109 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3110 fidp->flags |= SMB_FID_MTIMESETDONE;
3113 if (spi->u.QPstandardInfo.attributes != 0) {
3114 if ((scp->unixModeBits & 0222)
3115 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3116 /* make a writable file read-only */
3117 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3118 attr.unixModeBits = scp->unixModeBits & ~0222;
3120 else if ((scp->unixModeBits & 0222) == 0
3121 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3122 /* make a read-only file writable */
3123 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3124 attr.unixModeBits = scp->unixModeBits | 0222;
3127 lock_ReleaseMutex(&scp->mx);
3128 lock_ReleaseMutex(&fidp->mx);
3132 code = cm_SetAttr(scp, &attr, userp, &req);
3136 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3137 /* we don't support EAs */
3138 code = CM_ERROR_INVAL;
3142 cm_ReleaseSCache(scp);
3143 cm_ReleaseUser(userp);
3144 smb_ReleaseFID(fidp);
3146 smb_SendTran2Packet(vcp, outp, opx);
3148 smb_SendTran2Error(vcp, p, opx, code);
3149 smb_FreeTran2Packet(outp);
3155 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3157 smb_tran2Packet_t *outp;
3159 unsigned long attributes;
3160 unsigned short infoLevel;
3167 smb_tran2QFileInfo_t qfi;
3174 fidp = smb_FindFID(vcp, fid, 0);
3177 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3181 infoLevel = p->parmsp[1];
3182 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3183 responseSize = sizeof(qfi.u.QFbasicInfo);
3184 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3185 responseSize = sizeof(qfi.u.QFstandardInfo);
3186 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3187 responseSize = sizeof(qfi.u.QFeaInfo);
3188 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3189 responseSize = sizeof(qfi.u.QFfileNameInfo);
3191 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3192 p->opcode, infoLevel);
3193 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3194 smb_ReleaseFID(fidp);
3197 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3199 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3201 if (infoLevel > 0x100)
3202 outp->totalParms = 2;
3204 outp->totalParms = 0;
3205 outp->totalData = responseSize;
3207 userp = smb_GetTran2User(vcp, p);
3209 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3210 code = CM_ERROR_BADSMB;
3214 lock_ObtainMutex(&fidp->mx);
3215 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3217 osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3219 lock_ReleaseMutex(&fidp->mx);
3220 lock_ObtainMutex(&scp->mx);
3221 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3222 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3226 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3228 /* now we have the status in the cache entry, and everything is locked.
3229 * Marshall the output data.
3231 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3232 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3233 qfi.u.QFbasicInfo.creationTime = ft;
3234 qfi.u.QFbasicInfo.lastAccessTime = ft;
3235 qfi.u.QFbasicInfo.lastWriteTime = ft;
3236 qfi.u.QFbasicInfo.lastChangeTime = ft;
3237 attributes = smb_ExtAttributes(scp);
3238 qfi.u.QFbasicInfo.attributes = attributes;
3240 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3241 qfi.u.QFstandardInfo.allocationSize = scp->length;
3242 qfi.u.QFstandardInfo.endOfFile = scp->length;
3243 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3244 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3245 qfi.u.QFstandardInfo.directory =
3246 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3247 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3248 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3250 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3251 qfi.u.QFeaInfo.eaSize = 0;
3253 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3257 lock_ReleaseMutex(&scp->mx);
3258 lock_ObtainMutex(&fidp->mx);
3259 lock_ObtainMutex(&scp->mx);
3260 if (fidp->NTopen_wholepathp)
3261 name = fidp->NTopen_wholepathp;
3263 name = "\\"; /* probably can't happen */
3264 lock_ReleaseMutex(&fidp->mx);
3265 len = (unsigned long)strlen(name);
3266 outp->totalData = ((len+1)*2) + 4; /* this is actually what we want to return */
3267 qfi.u.QFfileNameInfo.fileNameLength = (len + 1) * 2;
3268 mbstowcs((unsigned short *)qfi.u.QFfileNameInfo.fileName, name, len + 1);
3271 /* send and free the packets */
3273 lock_ReleaseMutex(&scp->mx);
3274 cm_ReleaseSCache(scp);
3275 cm_ReleaseUser(userp);
3276 smb_ReleaseFID(fidp);
3278 memcpy(outp->datap, &qfi, responseSize);
3279 smb_SendTran2Packet(vcp, outp, opx);
3281 smb_SendTran2Error(vcp, p, opx, code);
3283 smb_FreeTran2Packet(outp);
3288 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3293 unsigned short infoLevel;
3294 smb_tran2Packet_t *outp;
3295 cm_user_t *userp = NULL;
3296 cm_scache_t *scp = NULL;
3302 fidp = smb_FindFID(vcp, fid, 0);
3305 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3309 infoLevel = p->parmsp[1];
3310 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3311 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3312 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3313 p->opcode, infoLevel);
3314 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3315 smb_ReleaseFID(fidp);
3319 lock_ObtainMutex(&fidp->mx);
3320 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
3321 !(fidp->flags & SMB_FID_OPENDELETE)) {
3322 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3323 fidp, fidp->scp, fidp->flags);
3324 lock_ReleaseMutex(&fidp->mx);
3325 smb_ReleaseFID(fidp);
3326 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3329 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3330 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3331 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3332 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
3333 fidp, fidp->scp, fidp->flags);
3334 lock_ReleaseMutex(&fidp->mx);
3335 smb_ReleaseFID(fidp);
3336 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3341 osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3343 lock_ReleaseMutex(&fidp->mx);
3345 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3347 outp->totalParms = 2;
3348 outp->totalData = 0;
3350 userp = smb_GetTran2User(vcp, p);
3352 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3353 code = CM_ERROR_BADSMB;
3357 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3359 unsigned int attribute;
3361 smb_tran2QFileInfo_t *sfi;
3363 sfi = (smb_tran2QFileInfo_t *)p->datap;
3365 /* lock the vnode with a callback; we need the current status
3366 * to determine what the new status is, in some cases.
3368 lock_ObtainMutex(&scp->mx);
3369 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3370 CM_SCACHESYNC_GETSTATUS
3371 | CM_SCACHESYNC_NEEDCALLBACK);
3373 lock_ReleaseMutex(&scp->mx);
3377 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3379 lock_ReleaseMutex(&scp->mx);
3380 lock_ObtainMutex(&fidp->mx);
3381 lock_ObtainMutex(&scp->mx);
3383 /* prepare for setattr call */
3386 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3387 /* when called as result of move a b, lastMod is (-1, -1).
3388 * If the check for -1 is not present, timestamp
3389 * of the resulting file will be 1969 (-1)
3391 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3392 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3393 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3394 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3395 fidp->flags |= SMB_FID_MTIMESETDONE;
3398 attribute = sfi->u.QFbasicInfo.attributes;
3399 if (attribute != 0) {
3400 if ((scp->unixModeBits & 0222)
3401 && (attribute & SMB_ATTR_READONLY) != 0) {
3402 /* make a writable file read-only */
3403 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3404 attr.unixModeBits = scp->unixModeBits & ~0222;
3406 else if ((scp->unixModeBits & 0222) == 0
3407 && (attribute & SMB_ATTR_READONLY) == 0) {
3408 /* make a read-only file writable */
3409 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3410 attr.unixModeBits = scp->unixModeBits | 0222;
3413 lock_ReleaseMutex(&scp->mx);
3414 lock_ReleaseMutex(&fidp->mx);
3418 code = cm_SetAttr(scp, &attr, userp, &req);
3422 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3423 int delflag = *((char *)(p->datap));
3424 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
3425 delflag, fidp, scp);
3426 if (*((char *)(p->datap))) { /* File is Deleted */
3427 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3430 lock_ObtainMutex(&fidp->mx);
3431 fidp->flags |= SMB_FID_DELONCLOSE;
3432 lock_ReleaseMutex(&fidp->mx);
3434 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
3440 lock_ObtainMutex(&fidp->mx);
3441 fidp->flags &= ~SMB_FID_DELONCLOSE;
3442 lock_ReleaseMutex(&fidp->mx);
3445 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3446 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3447 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3450 attr.mask = CM_ATTRMASK_LENGTH;
3451 attr.length.LowPart = size.LowPart;
3452 attr.length.HighPart = size.HighPart;
3453 code = cm_SetAttr(scp, &attr, userp, &req);
3457 cm_ReleaseSCache(scp);
3458 cm_ReleaseUser(userp);
3459 smb_ReleaseFID(fidp);
3461 smb_SendTran2Packet(vcp, outp, opx);
3463 smb_SendTran2Error(vcp, p, opx, code);
3464 smb_FreeTran2Packet(outp);
3470 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3472 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3473 return CM_ERROR_BADOP;
3477 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3479 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3480 return CM_ERROR_BADOP;
3484 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3486 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3487 return CM_ERROR_BADOP;
3491 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3493 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3494 return CM_ERROR_BADOP;
3498 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3500 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3501 return CM_ERROR_BADOP;
3505 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3507 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3508 return CM_ERROR_BADOP;
3511 struct smb_v2_referral {
3513 USHORT ReferralFlags;
3516 USHORT DfsPathOffset;
3517 USHORT DfsAlternativePathOffset;
3518 USHORT NetworkAddressOffset;
3522 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3524 /* This is a UNICODE only request (bit15 of Flags2) */
3525 /* The TID must be IPC$ */
3527 /* The documentation for the Flags response field is contradictory */
3529 /* Use Version 1 Referral Element Format */
3530 /* ServerType = 0; indicates the next server should be queried for the file */
3531 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3532 /* Node = UnicodeString of UNC path of the next share name */
3535 int maxReferralLevel = 0;
3536 char requestFileName[1024] = "";
3537 smb_tran2Packet_t *outp = 0;
3538 cm_user_t *userp = 0;
3540 CPINFO CodePageInfo;
3541 int i, nbnLen, reqLen;
3546 maxReferralLevel = p->parmsp[0];
3548 GetCPInfo(CP_ACP, &CodePageInfo);
3549 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
3550 requestFileName, 1024, NULL, NULL);
3552 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
3553 maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3555 nbnLen = strlen(cm_NetbiosName);
3556 reqLen = strlen(requestFileName);
3558 if (reqLen == nbnLen + 5 &&
3559 requestFileName[0] == '\\' &&
3560 !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3561 requestFileName[nbnLen+1] == '\\' &&
3562 (!_strnicmp("all",&requestFileName[nbnLen+2],3) ||
3563 !_strnicmp("*.",&requestFileName[nbnLen+2],2)))
3566 struct smb_v2_referral * v2ref;
3567 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
3569 sp = (USHORT *)outp->datap;
3571 sp[idx++] = reqLen; /* path consumed */
3572 sp[idx++] = 1; /* number of referrals */
3573 sp[idx++] = 0x03; /* flags */
3574 #ifdef DFS_VERSION_1
3575 sp[idx++] = 1; /* Version Number */
3576 sp[idx++] = reqLen + 4; /* Referral Size */
3577 sp[idx++] = 1; /* Type = SMB Server */
3578 sp[idx++] = 0; /* Do not strip path consumed */
3579 for ( i=0;i<=reqLen; i++ )
3580 sp[i+idx] = requestFileName[i];
3581 #else /* DFS_VERSION_2 */
3582 sp[idx++] = 2; /* Version Number */
3583 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3584 idx += (sizeof(struct smb_v2_referral) / 2);
3585 v2ref = (struct smb_v2_referral *) &sp[5];
3586 v2ref->ServerType = 1; /* SMB Server */
3587 v2ref->ReferralFlags = 0x03;
3588 v2ref->Proximity = 0; /* closest */
3589 v2ref->TimeToLive = 3600; /* seconds */
3590 v2ref->DfsPathOffset = idx * 2;
3591 v2ref->DfsAlternativePathOffset = idx * 2;
3592 v2ref->NetworkAddressOffset = 0;
3593 for ( i=0;i<=reqLen; i++ )
3594 sp[i+idx] = requestFileName[i];
3597 userp = smb_GetTran2User(vcp, p);
3599 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3600 code = CM_ERROR_BADSMB;
3605 code = CM_ERROR_NOSUCHPATH;
3610 cm_ReleaseUser(userp);
3612 smb_SendTran2Packet(vcp, outp, op);
3614 smb_SendTran2Error(vcp, p, op, code);
3616 smb_FreeTran2Packet(outp);
3619 #else /* DFS_SUPPORT */
3620 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3621 return CM_ERROR_BADOP;
3622 #endif /* DFS_SUPPORT */
3626 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3628 /* This is a UNICODE only request (bit15 of Flags2) */
3630 /* There is nothing we can do about this operation. The client is going to
3631 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3632 * Unfortunately, there is really nothing we can do about it other then log it
3633 * somewhere. Even then I don't think there is anything for us to do.
3634 * So let's return an error value.
3637 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3638 return CM_ERROR_BADOP;
3642 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3643 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3648 cm_scache_t *targetScp; /* target if scp is a symlink */
3653 unsigned short attr;
3654 unsigned long lattr;
3655 smb_dirListPatch_t *patchp;
3656 smb_dirListPatch_t *npatchp;
3658 afs_int32 mustFake = 0;
3660 code = cm_FindACLCache(dscp, userp, &rights);
3661 if (code == 0 && !(rights & PRSFS_READ))
3663 else if (code == -1) {
3664 lock_ObtainMutex(&dscp->mx);
3665 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
3666 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3667 lock_ReleaseMutex(&dscp->mx);
3668 if (code == CM_ERROR_NOACCESS) {
3676 for(patchp = *dirPatchespp; patchp; patchp =
3677 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3678 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3682 lock_ObtainMutex(&scp->mx);
3684 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3685 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3686 if (mustFake || code) {
3687 lock_ReleaseMutex(&scp->mx);
3689 dptr = patchp->dptr;
3691 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3692 errors in the client. */
3693 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3694 /* 1969-12-31 23:59:59 +00 */
3695 ft.dwHighDateTime = 0x19DB200;
3696 ft.dwLowDateTime = 0x5BB78980;
3698 /* copy to Creation Time */
3699 *((FILETIME *)dptr) = ft;
3702 /* copy to Last Access Time */
3703 *((FILETIME *)dptr) = ft;
3706 /* copy to Last Write Time */
3707 *((FILETIME *)dptr) = ft;
3710 /* copy to Change Time */
3711 *((FILETIME *)dptr) = ft;
3714 switch (scp->fileType) {
3715 case CM_SCACHETYPE_DIRECTORY:
3716 case CM_SCACHETYPE_MOUNTPOINT:
3717 case CM_SCACHETYPE_SYMLINK:
3718 case CM_SCACHETYPE_INVALID:
3719 *((u_long *)dptr) = SMB_ATTR_DIRECTORY;
3722 /* if we get here we either have a normal file
3723 * or we have a file for which we have never
3724 * received status info. In this case, we can
3725 * check the even/odd value of the entry's vnode.
3726 * even means it is to be treated as a directory
3727 * and odd means it is to be treated as a file.
3729 if (mustFake && (scp->fid.vnode & 0x1))
3730 *((u_long *)dptr) = SMB_ATTR_DIRECTORY;
3732 *((u_long *)dptr) = SMB_ATTR_NORMAL;
3735 /* merge in hidden attribute */
3736 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3737 *((u_long *)dptr) |= SMB_ATTR_HIDDEN;
3741 /* 1969-12-31 23:59:58 +00*/
3742 dosTime = 0xEBBFBF7D;
3744 /* and copy out date */
3745 shortTemp = (dosTime>>16) & 0xffff;
3746 *((u_short *)dptr) = shortTemp;
3749 /* copy out creation time */
3750 shortTemp = dosTime & 0xffff;
3751 *((u_short *)dptr) = shortTemp;
3754 /* and copy out date */
3755 shortTemp = (dosTime>>16) & 0xffff;
3756 *((u_short *)dptr) = shortTemp;
3759 /* copy out access time */
3760 shortTemp = dosTime & 0xffff;
3761 *((u_short *)dptr) = shortTemp;
3764 /* and copy out date */
3765 shortTemp = (dosTime>>16) & 0xffff;
3766 *((u_short *)dptr) = shortTemp;
3769 /* copy out mod time */
3770 shortTemp = dosTime & 0xffff;
3771 *((u_short *)dptr) = shortTemp;
3774 /* set the attribute */
3775 switch (scp->fileType) {
3776 case CM_SCACHETYPE_DIRECTORY:
3777 case CM_SCACHETYPE_MOUNTPOINT:
3778 case CM_SCACHETYPE_SYMLINK:
3779 case CM_SCACHETYPE_INVALID:
3780 attr = SMB_ATTR_DIRECTORY;
3782 attr = SMB_ATTR_NORMAL;
3784 /* merge in hidden (dot file) attribute */
3785 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3786 attr |= SMB_ATTR_HIDDEN;
3788 *dptr++ = attr & 0xff;
3789 *dptr++ = (attr >> 8) & 0xff;
3792 cm_ReleaseSCache(scp);
3796 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3798 /* now watch for a symlink */
3800 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3801 lock_ReleaseMutex(&scp->mx);
3802 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3804 /* we have a more accurate file to use (the
3805 * target of the symbolic link). Otherwise,
3806 * we'll just use the symlink anyway.
3808 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3810 cm_ReleaseSCache(scp);
3813 lock_ObtainMutex(&scp->mx);
3816 dptr = patchp->dptr;
3818 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3820 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3822 /* copy to Creation Time */
3823 *((FILETIME *)dptr) = ft;
3826 /* copy to Last Access Time */
3827 *((FILETIME *)dptr) = ft;
3830 /* copy to Last Write Time */
3831 *((FILETIME *)dptr) = ft;
3834 /* copy to Change Time */
3835 *((FILETIME *)dptr) = ft;
3838 /* Use length for both file length and alloc length */
3839 *((LARGE_INTEGER *)dptr) = scp->length;
3841 *((LARGE_INTEGER *)dptr) = scp->length;
3844 /* Copy attributes */
3845 lattr = smb_ExtAttributes(scp);
3846 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3847 if (lattr == SMB_ATTR_NORMAL)
3848 lattr = SMB_ATTR_DIRECTORY;
3850 lattr |= SMB_ATTR_DIRECTORY;
3852 /* merge in hidden (dot file) attribute */
3853 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3854 if (lattr == SMB_ATTR_NORMAL)
3855 lattr = SMB_ATTR_HIDDEN;
3857 lattr |= SMB_ATTR_HIDDEN;
3859 *((u_long *)dptr) = lattr;
3863 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3865 /* and copy out date */
3866 shortTemp = (dosTime>>16) & 0xffff;
3867 *((u_short *)dptr) = shortTemp;
3870 /* copy out creation time */
3871 shortTemp = dosTime & 0xffff;
3872 *((u_short *)dptr) = shortTemp;
3875 /* and copy out date */
3876 shortTemp = (dosTime>>16) & 0xffff;
3877 *((u_short *)dptr) = shortTemp;
3880 /* copy out access time */
3881 shortTemp = dosTime & 0xffff;
3882 *((u_short *)dptr) = shortTemp;
3885 /* and copy out date */
3886 shortTemp = (dosTime>>16) & 0xffff;
3887 *((u_short *)dptr) = shortTemp;
3890 /* copy out mod time */
3891 shortTemp = dosTime & 0xffff;
3892 *((u_short *)dptr) = shortTemp;
3895 /* copy out file length and alloc length,
3896 * using the same for both
3898 *((u_long *)dptr) = scp->length.LowPart;
3900 *((u_long *)dptr) = scp->length.LowPart;
3903 /* finally copy out attributes as short */
3904 attr = smb_Attributes(scp);
3905 /* merge in hidden (dot file) attribute */
3906 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3907 if (lattr == SMB_ATTR_NORMAL)
3908 lattr = SMB_ATTR_HIDDEN;
3910 lattr |= SMB_ATTR_HIDDEN;
3912 *dptr++ = attr & 0xff;
3913 *dptr++ = (attr >> 8) & 0xff;
3916 lock_ReleaseMutex(&scp->mx);
3917 cm_ReleaseSCache(scp);
3920 /* now free the patches */
3921 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3922 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3926 /* and mark the list as empty */
3927 *dirPatchespp = NULL;
3932 #ifndef USE_OLD_MATCHING
3933 // char table for case insensitive comparison
3934 char mapCaseTable[256];
3936 VOID initUpperCaseTable(VOID)
3939 for (i = 0; i < 256; ++i)
3940 mapCaseTable[i] = toupper(i);
3941 // make '"' match '.'
3942 mapCaseTable[(int)'"'] = toupper('.');
3943 // make '<' match '*'
3944 mapCaseTable[(int)'<'] = toupper('*');
3945 // make '>' match '?'
3946 mapCaseTable[(int)'>'] = toupper('?');
3949 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3951 // Note : this procedure works recursively calling itself.
3953 // PSZ pattern : string containing metacharacters.
3954 // PSZ name : file name to be compared with 'pattern'.
3956 // BOOL : TRUE/FALSE (match/mistmatch)
3959 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
3961 PSZ pename; // points to the last 'name' character
3963 pename = name + strlen(name) - 1;
3974 if (*pattern == '\0')
3976 for (p = pename; p >= name; --p) {
3977 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
3978 !casefold && (*p == *pattern)) &&
3979 szWildCardMatchFileName(pattern + 1, p + 1, casefold))
3984 if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
3985 (!casefold && *name != *pattern))
3992 /* if all we have left are wildcards, then we match */
3993 for (;*pattern; pattern++) {
3994 if (*pattern != '*' && *pattern != '?')
4000 /* do a case-folding search of the star name mask with the name in namep.
4001 * Return 1 if we match, otherwise 0.
4003 int smb_V3MatchMask(char *namep, char *maskp, int flags)
4006 int i, j, star, qmark, casefold, retval;
4008 /* make sure we only match 8.3 names, if requested */
4009 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
4012 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
4014 /* optimize the pattern:
4015 * if there is a mixture of '?' and '*',
4016 * for example the sequence "*?*?*?*"
4017 * must be turned into the form "*"
4019 newmask = (char *)malloc(strlen(maskp)+1);
4020 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
4021 switch ( maskp[i] ) {
4033 } else if ( qmark ) {
4037 newmask[j++] = maskp[i];
4044 } else if ( qmark ) {
4048 newmask[j++] = '\0';
4050 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
4056 #else /* USE_OLD_MATCHING */
4057 /* do a case-folding search of the star name mask with the name in namep.
4058 * Return 1 if we match, otherwise 0.
4060 int smb_V3MatchMask(char *namep, char *maskp, int flags)
4062 unsigned char tcp1, tcp2; /* Pattern characters */
4063 unsigned char tcn1; /* Name characters */
4064 int sawDot = 0, sawStar = 0, req8dot3 = 0;
4065 char *starNamep, *starMaskp;
4066 static char nullCharp[] = {0};
4067 int casefold = flags & CM_FLAG_CASEFOLD;
4069 /* make sure we only match 8.3 names, if requested */
4070 req8dot3 = (flags & CM_FLAG_8DOT3);
4071 if (req8dot3 && !cm_Is8Dot3(namep))
4076 /* Next pattern character */
4079 /* Next name character */
4083 /* 0 - end of pattern */
4089 else if (tcp1 == '.' || tcp1 == '"') {
4099 * first dot in pattern;
4100 * must match dot or end of name
4105 else if (tcn1 == '.') {
4114 else if (tcp1 == '?') {
4115 if (tcn1 == 0 || tcn1 == '.')
4120 else if (tcp1 == '>') {
4121 if (tcn1 != 0 && tcn1 != '.')
4125 else if (tcp1 == '*' || tcp1 == '<') {
4129 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
4130 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
4145 * pattern character after '*' is not null or
4146 * period. If it is '?' or '>', we are not
4147 * going to understand it. If it is '*' or
4148 * '<', we are going to skip over it. None of
4149 * these are likely, I hope.
4151 /* skip over '*' and '<' */
4152 while (tcp2 == '*' || tcp2 == '<')
4155 /* skip over characters that don't match tcp2 */
4156 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
4157 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
4158 (!casefold && tcn1 != tcp2)))
4162 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
4165 /* Remember where we are */
4175 /* tcp1 is not a wildcard */
4176 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
4177 (!casefold && tcn1 == tcp1)) {
4182 /* if trying to match a star pattern, go back */
4184 maskp = starMaskp - 2;
4185 namep = starNamep + 1;
4194 #endif /* USE_OLD_MATCHING */
4196 /* smb_ReceiveTran2SearchDir implements both
4197 * Tran2_Find_First and Tran2_Find_Next
4199 #define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
4200 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
4201 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
4202 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
4203 #define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
4205 /* this is an optimized handler for T2SearchDir that handles the case
4206 where there are no wildcards in the search path. I.e. an
4207 application is using FindFirst(Ex) to get information about a
4208 single file or directory. It will attempt to do a single lookup.
4209 If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4210 the usual mechanism.
4212 This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4214 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4218 long code = 0, code2 = 0;
4221 smb_dirListPatch_t *dirListPatchesp;
4222 smb_dirListPatch_t *curPatchp;
4223 long orbytes; /* # of bytes in this output record */
4224 long ohbytes; /* # of bytes, except file name */
4225 long onbytes; /* # of bytes in name, incl. term. null */
4226 cm_scache_t *scp = NULL;
4227 cm_scache_t *targetscp = NULL;
4228 cm_user_t *userp = NULL;
4229 char *op; /* output data ptr */
4230 char *origOp; /* original value of op */
4231 cm_space_t *spacep; /* for pathname buffer */
4232 long maxReturnData; /* max # of return data */
4233 long maxReturnParms; /* max # of return parms */
4234 long bytesInBuffer; /* # data bytes in the output buffer */
4235 char *maskp; /* mask part of path */
4239 smb_tran2Packet_t *outp; /* response packet */
4242 char shortName[13]; /* 8.3 name if needed */
4251 osi_assert(p->opcode == 1);
4253 /* find first; obtain basic parameters from request */
4255 /* note that since we are going to failover to regular
4256 * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4257 * modify any of the input parameters here. */
4258 attribute = p->parmsp[0];
4259 maxCount = p->parmsp[1];
4260 infoLevel = p->parmsp[3];
4261 searchFlags = p->parmsp[2];
4262 pathp = ((char *) p->parmsp) + 12; /* points to path */
4264 maskp = strrchr(pathp, '\\');
4268 maskp++; /* skip over backslash */
4269 /* track if this is likely to match a lot of entries */
4271 osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%s], mask[%s]",
4272 osi_LogSaveString(smb_logp, pathp),
4273 osi_LogSaveString(smb_logp, maskp));
4275 switch ( infoLevel ) {
4276 case SMB_INFO_STANDARD:
4279 case SMB_INFO_QUERY_EA_SIZE:
4280 s = "InfoQueryEaSize";
4282 case SMB_INFO_QUERY_EAS_FROM_LIST:
4283 s = "InfoQueryEasFromList";
4285 case SMB_FIND_FILE_DIRECTORY_INFO:
4286 s = "FindFileDirectoryInfo";
4288 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4289 s = "FindFileFullDirectoryInfo";
4291 case SMB_FIND_FILE_NAMES_INFO:
4292 s = "FindFileNamesInfo";
4294 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4295 s = "FindFileBothDirectoryInfo";
4298 s = "unknownInfoLevel";
4301 osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
4304 "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4305 attribute, infoLevel, maxCount, searchFlags);
4307 if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4308 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4309 return CM_ERROR_INVAL;
4312 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4313 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4315 dirListPatchesp = NULL;
4317 maxReturnData = p->maxReturnData;
4318 maxReturnParms = 10; /* return params for findfirst, which
4319 is the only one we handle.*/
4321 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4322 if (maxReturnData > 6000)
4323 maxReturnData = 6000;
4324 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4326 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4329 osi_Log2(smb_logp, "T2SDSingle search dir count %d [%s]",
4330 maxCount, osi_LogSaveString(smb_logp, pathp));
4332 /* bail out if request looks bad */
4334 smb_FreeTran2Packet(outp);
4335 return CM_ERROR_BADSMB;
4338 userp = smb_GetTran2User(vcp, p);
4340 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
4341 smb_FreeTran2Packet(outp);
4342 return CM_ERROR_BADSMB;
4345 /* try to get the vnode for the path name next */
4346 spacep = cm_GetSpace();
4347 smb_StripLastComponent(spacep->data, NULL, pathp);
4348 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4350 cm_ReleaseUser(userp);
4351 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4352 smb_FreeTran2Packet(outp);
4356 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4357 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4358 userp, tidPathp, &req, &scp);
4359 cm_FreeSpace(spacep);
4362 cm_ReleaseUser(userp);
4363 smb_SendTran2Error(vcp, p, opx, code);
4364 smb_FreeTran2Packet(outp);
4368 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4369 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4370 cm_ReleaseSCache(scp);
4371 cm_ReleaseUser(userp);
4372 if ( WANTS_DFS_PATHNAMES(p) )
4373 code = CM_ERROR_PATH_NOT_COVERED;
4375 code = CM_ERROR_BADSHARENAME;
4376 smb_SendTran2Error(vcp, p, opx, code);
4377 smb_FreeTran2Packet(outp);
4380 #endif /* DFS_SUPPORT */
4381 osi_Log1(smb_logp,"smb_ReceiveTran2SearchDir scp 0x%p", scp);
4382 lock_ObtainMutex(&scp->mx);
4383 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
4384 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4385 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4387 lock_ReleaseMutex(&scp->mx);
4389 /* now do a single case sensitive lookup for the file in question */
4390 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
4392 /* if a case sensitive match failed, we try a case insensitive one
4394 if (code == CM_ERROR_NOSUCHFILE) {
4395 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
4398 if (code == 0 && targetscp->fid.vnode == 0) {
4399 cm_ReleaseSCache(targetscp);
4400 code = CM_ERROR_NOSUCHFILE;
4404 /* if we can't find the directory entry, this block will
4405 return CM_ERROR_NOSUCHFILE, which we will pass on to
4406 smb_ReceiveTran2SearchDir(). */
4407 cm_ReleaseSCache(scp);
4408 cm_ReleaseUser(userp);
4409 if (code != CM_ERROR_NOSUCHFILE) {
4410 smb_SendTran2Error(vcp, p, opx, code);
4413 smb_FreeTran2Packet(outp);
4417 /* now that we have the target in sight, we proceed with filling
4418 up the return data. */
4420 op = origOp = outp->datap;
4423 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4424 /* skip over resume key */
4428 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4429 && targetscp->fid.vnode != 0
4430 && !cm_Is8Dot3(maskp)) {
4433 dfid.vnode = htonl(targetscp->fid.vnode);
4434 dfid.unique = htonl(targetscp->fid.unique);
4436 cm_Gen8Dot3NameInt(maskp, &dfid, shortName, &shortNameEnd);
4442 osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %s (%s)",
4443 htonl(targetscp->fid.vnode),
4444 htonl(targetscp->fid.unique),
4445 osi_LogSaveString(smb_logp, pathp),
4446 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4448 /* Eliminate entries that don't match requested attributes */
4449 if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
4450 smb_IsDotFile(maskp)) {
4452 code = CM_ERROR_NOSUCHFILE;
4453 osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
4458 if (!(attribute & SMB_ATTR_DIRECTORY) &&
4459 (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
4460 targetscp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4461 targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
4462 targetscp->fileType == CM_SCACHETYPE_INVALID)) {
4464 code = CM_ERROR_NOSUCHFILE;
4465 osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
4470 /* Check if the name will fit */
4471 if (infoLevel < 0x101)
4472 ohbytes = 23; /* pre-NT */
4473 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4474 ohbytes = 12; /* NT names only */
4476 ohbytes = 64; /* NT */
4478 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
4479 ohbytes += 26; /* Short name & length */
4481 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4482 ohbytes += 4; /* if resume key required */
4485 if (infoLevel != SMB_INFO_STANDARD
4486 && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
4487 && infoLevel != SMB_FIND_FILE_NAMES_INFO)
4488 ohbytes += 4; /* EASIZE */
4490 /* add header to name & term. null */
4491 onbytes = strlen(maskp);
4492 orbytes = ohbytes + onbytes + 1;
4494 /* now, we round up the record to a 4 byte alignment, and we make
4495 * sure that we have enough room here for even the aligned version
4496 * (so we don't have to worry about an * overflow when we pad
4497 * things out below). That's the reason for the alignment
4500 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4501 align = (4 - (orbytes & 3)) & 3;
4505 if (orbytes + align > maxReturnData) {
4507 /* even though this request is unlikely to succeed with a
4508 failover, we do it anyway. */
4509 code = CM_ERROR_NOSUCHFILE;
4510 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4515 /* this is one of the entries to use: it is not deleted and it
4516 * matches the star pattern we're looking for. Put out the name,
4517 * preceded by its length.
4519 /* First zero everything else */
4520 memset(origOp, 0, ohbytes);
4522 if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
4523 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4524 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4525 *((u_long *)(op + 8)) = onbytes;
4527 *((u_long *)(op + 60)) = onbytes;
4528 strcpy(origOp+ohbytes, maskp);
4529 if (smb_StoreAnsiFilenames)
4530 CharToOem(origOp+ohbytes, origOp+ohbytes);
4532 /* Short name if requested and needed */
4533 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4534 if (NeedShortName) {
4535 strcpy(op + 70, shortName);
4536 if (smb_StoreAnsiFilenames)
4537 CharToOem(op + 70, op + 70);
4538 *(op + 68) = (char)(shortNameEnd - shortName);
4542 /* NextEntryOffset and FileIndex */
4543 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4544 int entryOffset = orbytes + align;
4545 *((u_long *)op) = 0;
4546 *((u_long *)(op+4)) = 0;
4549 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4550 curPatchp = malloc(sizeof(*curPatchp));
4551 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4553 curPatchp->dptr = op;
4554 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4555 curPatchp->dptr += 8;
4557 if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
4558 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4560 curPatchp->flags = 0;
4563 curPatchp->fid.cell = targetscp->fid.cell;
4564 curPatchp->fid.volume = targetscp->fid.volume;
4565 curPatchp->fid.vnode = targetscp->fid.vnode;
4566 curPatchp->fid.unique = targetscp->fid.unique;
4569 curPatchp->dep = NULL;
4572 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4573 /* put out resume key */
4574 *((u_long *)origOp) = 0;
4577 /* Adjust byte ptr and count */
4578 origOp += orbytes; /* skip entire record */
4579 bytesInBuffer += orbytes;
4581 /* and pad the record out */
4582 while (--align >= 0) {
4587 /* apply the patches */
4588 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp, &req);
4590 outp->parmsp[0] = 0;
4591 outp->parmsp[1] = 1; /* number of names returned */
4592 outp->parmsp[2] = 1; /* end of search */
4593 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4594 outp->parmsp[4] = 0;
4596 outp->totalParms = 10; /* in bytes */
4598 outp->totalData = bytesInBuffer;
4600 osi_Log0(smb_logp, "T2SDSingle done.");
4602 if (code != CM_ERROR_NOSUCHFILE) {
4604 smb_SendTran2Error(vcp, p, opx, code);
4606 smb_SendTran2Packet(vcp, outp, opx);
4611 smb_FreeTran2Packet(outp);
4612 cm_ReleaseSCache(scp);
4613 cm_ReleaseSCache(targetscp);
4614 cm_ReleaseUser(userp);
4620 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4625 long code = 0, code2 = 0;
4629 smb_dirListPatch_t *dirListPatchesp;
4630 smb_dirListPatch_t *curPatchp;
4633 long orbytes; /* # of bytes in this output record */
4634 long ohbytes; /* # of bytes, except file name */
4635 long onbytes; /* # of bytes in name, incl. term. null */
4636 osi_hyper_t dirLength;
4637 osi_hyper_t bufferOffset;
4638 osi_hyper_t curOffset;
4640 smb_dirSearch_t *dsp;
4644 cm_pageHeader_t *pageHeaderp;
4645 cm_user_t *userp = NULL;
4648 long nextEntryCookie;
4649 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4650 char *op; /* output data ptr */
4651 char *origOp; /* original value of op */
4652 cm_space_t *spacep; /* for pathname buffer */
4653 long maxReturnData; /* max # of return data */
4654 long maxReturnParms; /* max # of return parms */
4655 long bytesInBuffer; /* # data bytes in the output buffer */
4657 char *maskp; /* mask part of path */
4661 smb_tran2Packet_t *outp; /* response packet */
4664 char shortName[13]; /* 8.3 name if needed */
4676 if (p->opcode == 1) {
4677 /* find first; obtain basic parameters from request */
4678 attribute = p->parmsp[0];
4679 maxCount = p->parmsp[1];
4680 infoLevel = p->parmsp[3];
4681 searchFlags = p->parmsp[2];
4682 pathp = ((char *) p->parmsp) + 12; /* points to path */
4683 if (smb_StoreAnsiFilenames)
4684 OemToChar(pathp,pathp);
4686 maskp = strrchr(pathp, '\\');
4690 maskp++; /* skip over backslash */
4692 /* track if this is likely to match a lot of entries */
4693 starPattern = smb_V3IsStarMask(maskp);
4695 #ifndef NOFINDFIRSTOPTIMIZE
4697 /* if this is for a single directory or file, we let the
4698 optimized routine handle it. The only error it
4699 returns is CM_ERROR_NOSUCHFILE. The */
4700 code = smb_T2SearchDirSingle(vcp, p, opx);
4702 /* we only failover if we see a CM_ERROR_NOSUCHFILE */
4703 if (code != CM_ERROR_NOSUCHFILE) {
4709 dsp = smb_NewDirSearch(1);
4710 dsp->attribute = attribute;
4711 strcpy(dsp->mask, maskp); /* and save mask */
4714 osi_assert(p->opcode == 2);
4715 /* find next; obtain basic parameters from request or open dir file */
4716 dsp = smb_FindDirSearch(p->parmsp[0]);
4717 maxCount = p->parmsp[1];
4718 infoLevel = p->parmsp[2];
4719 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4720 searchFlags = p->parmsp[5];
4722 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4723 p->parmsp[0], nextCookie);
4724 return CM_ERROR_BADFD;
4726 attribute = dsp->attribute;
4729 starPattern = 1; /* assume, since required a Find Next */
4732 switch ( infoLevel ) {
4733 case SMB_INFO_STANDARD:
4736 case SMB_INFO_QUERY_EA_SIZE:
4737 s = "InfoQueryEaSize";
4739 case SMB_INFO_QUERY_EAS_FROM_LIST:
4740 s = "InfoQueryEasFromList";
4742 case SMB_FIND_FILE_DIRECTORY_INFO:
4743 s = "FindFileDirectoryInfo";
4745 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4746 s = "FindFileFullDirectoryInfo";
4748 case SMB_FIND_FILE_NAMES_INFO:
4749 s = "FindFileNamesInfo";
4751 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4752 s = "FindFileBothDirectoryInfo";
4755 s = "unknownInfoLevel";
4758 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
4761 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4762 attribute, infoLevel, maxCount, searchFlags);
4764 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
4765 p->opcode, dsp->cookie, nextCookie);
4767 if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4768 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4769 smb_ReleaseDirSearch(dsp);
4770 return CM_ERROR_INVAL;
4773 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4774 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4776 dirListPatchesp = NULL;
4778 maxReturnData = p->maxReturnData;
4779 if (p->opcode == 1) /* find first */
4780 maxReturnParms = 10; /* bytes */
4782 maxReturnParms = 8; /* bytes */
4784 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4785 if (maxReturnData > 6000)
4786 maxReturnData = 6000;
4787 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4789 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4792 osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
4793 maxCount, osi_LogSaveString(smb_logp, pathp));
4795 /* bail out if request looks bad */
4796 if (p->opcode == 1 && !pathp) {
4797 smb_ReleaseDirSearch(dsp);
4798 smb_FreeTran2Packet(outp);
4799 return CM_ERROR_BADSMB;
4802 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
4803 dsp->cookie, nextCookie, attribute);
4805 userp = smb_GetTran2User(vcp, p);
4807 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
4808 smb_ReleaseDirSearch(dsp);
4809 smb_FreeTran2Packet(outp);
4810 return CM_ERROR_BADSMB;
4813 /* try to get the vnode for the path name next */
4814 lock_ObtainMutex(&dsp->mx);
4817 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4821 spacep = cm_GetSpace();
4822 smb_StripLastComponent(spacep->data, NULL, pathp);
4823 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4825 cm_ReleaseUser(userp);
4826 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4827 smb_FreeTran2Packet(outp);
4828 lock_ReleaseMutex(&dsp->mx);
4829 smb_DeleteDirSearch(dsp);
4830 smb_ReleaseDirSearch(dsp);
4833 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4834 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4835 userp, tidPathp, &req, &scp);
4836 cm_FreeSpace(spacep);
4839 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4840 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4841 cm_ReleaseSCache(scp);
4842 cm_ReleaseUser(userp);
4843 if ( WANTS_DFS_PATHNAMES(p) )
4844 code = CM_ERROR_PATH_NOT_COVERED;
4846 code = CM_ERROR_BADSHARENAME;
4847 smb_SendTran2Error(vcp, p, opx, code);
4848 smb_FreeTran2Packet(outp);
4849 lock_ReleaseMutex(&dsp->mx);
4850 smb_DeleteDirSearch(dsp);
4851 smb_ReleaseDirSearch(dsp);
4854 #endif /* DFS_SUPPORT */
4856 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4857 /* we need one hold for the entry we just stored into,
4858 * and one for our own processing. When we're done
4859 * with this function, we'll drop the one for our own
4860 * processing. We held it once from the namei call,
4861 * and so we do another hold now.
4864 lock_ObtainMutex(&scp->mx);
4865 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
4866 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4867 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4868 dsp->flags |= SMB_DIRSEARCH_BULKST;
4870 lock_ReleaseMutex(&scp->mx);
4873 lock_ReleaseMutex(&dsp->mx);
4875 cm_ReleaseUser(userp);
4876 smb_FreeTran2Packet(outp);
4877 smb_DeleteDirSearch(dsp);
4878 smb_ReleaseDirSearch(dsp);
4882 /* get the directory size */
4883 lock_ObtainMutex(&scp->mx);
4884 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4885 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4887 lock_ReleaseMutex(&scp->mx);
4888 cm_ReleaseSCache(scp);
4889 cm_ReleaseUser(userp);
4890 smb_FreeTran2Packet(outp);
4891 smb_DeleteDirSearch(dsp);
4892 smb_ReleaseDirSearch(dsp);
4896 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4899 dirLength = scp->length;
4901 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4902 curOffset.HighPart = 0;
4903 curOffset.LowPart = nextCookie;
4904 origOp = outp->datap;
4912 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4913 /* skip over resume key */
4916 /* make sure that curOffset.LowPart doesn't point to the first
4917 * 32 bytes in the 2nd through last dir page, and that it doesn't
4918 * point at the first 13 32-byte chunks in the first dir page,
4919 * since those are dir and page headers, and don't contain useful
4922 temp = curOffset.LowPart & (2048-1);
4923 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4924 /* we're in the first page */
4925 if (temp < 13*32) temp = 13*32;
4928 /* we're in a later dir page */
4929 if (temp < 32) temp = 32;
4932 /* make sure the low order 5 bits are zero */
4935 /* now put temp bits back ito curOffset.LowPart */
4936 curOffset.LowPart &= ~(2048-1);
4937 curOffset.LowPart |= temp;
4939 /* check if we've passed the dir's EOF */
4940 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4941 osi_Log0(smb_logp, "T2 search dir passed eof");
4946 /* check if we've returned all the names that will fit in the
4947 * response packet; we check return count as well as the number
4948 * of bytes requested. We check the # of bytes after we find
4949 * the dir entry, since we'll need to check its size.
4951 if (returnedNames >= maxCount) {
4952 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4953 returnedNames, maxCount);
4957 /* see if we can use the bufferp we have now; compute in which
4958 * page the current offset would be, and check whether that's
4959 * the offset of the buffer we have. If not, get the buffer.
4961 thyper.HighPart = curOffset.HighPart;
4962 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4963 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4966 buf_Release(bufferp);
4969 lock_ReleaseMutex(&scp->mx);
4970 lock_ObtainRead(&scp->bufCreateLock);
4971 code = buf_Get(scp, &thyper, &bufferp);
4972 lock_ReleaseRead(&scp->bufCreateLock);
4973 lock_ObtainMutex(&dsp->mx);
4975 /* now, if we're doing a star match, do bulk fetching
4976 * of all of the status info for files in the dir.
4979 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
4982 lock_ObtainMutex(&scp->mx);
4983 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4984 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
4985 /* Don't bulk stat if risking timeout */
4986 DWORD now = GetTickCount();
4987 if (now - req.startTime > RDRtimeout) {
4988 scp->bulkStatProgress = thyper;
4989 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4990 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4992 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4995 lock_ObtainMutex(&scp->mx);
4997 lock_ReleaseMutex(&dsp->mx);
4999 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
5003 bufferOffset = thyper;
5005 /* now get the data in the cache */
5007 code = cm_SyncOp(scp, bufferp, userp, &req,
5009 CM_SCACHESYNC_NEEDCALLBACK
5010 | CM_SCACHESYNC_READ);
5012 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5016 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5018 if (cm_HaveBuffer(scp, bufferp, 0)) {
5019 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5023 /* otherwise, load the buffer and try again */
5024 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5027 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5028 scp, bufferp, code);
5033 buf_Release(bufferp);
5037 } /* if (wrong buffer) ... */
5039 /* now we have the buffer containing the entry we're interested
5040 * in; copy it out if it represents a non-deleted entry.
5042 entryInDir = curOffset.LowPart & (2048-1);
5043 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5045 /* page header will help tell us which entries are free. Page
5046 * header can change more often than once per buffer, since
5047 * AFS 3 dir page size may be less than (but not more than)
5048 * a buffer package buffer.
5050 /* only look intra-buffer */
5051 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5052 temp &= ~(2048 - 1); /* turn off intra-page bits */
5053 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5055 /* now determine which entry we're looking at in the page.
5056 * If it is free (there's a free bitmap at the start of the
5057 * dir), we should skip these 32 bytes.
5059 slotInPage = (entryInDir & 0x7e0) >> 5;
5060 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5061 (1 << (slotInPage & 0x7)))) {
5062 /* this entry is free */
5063 numDirChunks = 1; /* only skip this guy */
5067 tp = bufferp->datap + entryInBuffer;
5068 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5070 /* while we're here, compute the next entry's location, too,
5071 * since we'll need it when writing out the cookie into the dir
5074 * XXXX Probably should do more sanity checking.
5076 numDirChunks = cm_NameEntries(dep->name, &onbytes);
5078 /* compute offset of cookie representing next entry */
5079 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5081 /* Need 8.3 name? */
5083 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
5084 && dep->fid.vnode != 0
5085 && !cm_Is8Dot3(dep->name)) {
5086 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5090 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %s (%s)",
5091 dep->fid.vnode, dep->fid.unique,
5092 osi_LogSaveString(smb_logp, dep->name),
5093 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
5095 /* When matching, we are using doing a case fold if we have a wildcard mask.
5096 * If we get a non-wildcard match, it's a lookup for a specific file.
5098 if (dep->fid.vnode != 0 &&
5099 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5101 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
5103 /* Eliminate entries that don't match requested attributes */
5104 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5105 smb_IsDotFile(dep->name)) {
5106 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5107 goto nextEntry; /* no hidden files */
5109 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5111 /* We have already done the cm_TryBulkStat above */
5112 fid.cell = scp->fid.cell;
5113 fid.volume = scp->fid.volume;
5114 fid.vnode = ntohl(dep->fid.vnode);
5115 fid.unique = ntohl(dep->fid.unique);
5116 fileType = cm_FindFileType(&fid);
5117 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5118 "has filetype %d", dep->name,
5120 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5121 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5122 fileType == CM_SCACHETYPE_DFSLINK ||
5123 fileType == CM_SCACHETYPE_INVALID)
5124 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5128 /* finally check if this name will fit */
5130 /* standard dir entry stuff */
5131 if (infoLevel < 0x101)
5132 ohbytes = 23; /* pre-NT */
5133 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
5134 ohbytes = 12; /* NT names only */
5136 ohbytes = 64; /* NT */
5138 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
5139 ohbytes += 26; /* Short name & length */
5141 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
5142 ohbytes += 4; /* if resume key required */
5145 if (infoLevel != SMB_INFO_STANDARD
5146 && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
5147 && infoLevel != SMB_FIND_FILE_NAMES_INFO)
5148 ohbytes += 4; /* EASIZE */
5150 /* add header to name & term. null */
5151 orbytes = onbytes + ohbytes + 1;
5153 /* now, we round up the record to a 4 byte alignment,
5154 * and we make sure that we have enough room here for
5155 * even the aligned version (so we don't have to worry
5156 * about an * overflow when we pad things out below).
5157 * That's the reason for the alignment arithmetic below.
5159 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5160 align = (4 - (orbytes & 3)) & 3;
5163 if (orbytes + bytesInBuffer + align > maxReturnData) {
5164 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5169 /* this is one of the entries to use: it is not deleted
5170 * and it matches the star pattern we're looking for.
5171 * Put out the name, preceded by its length.
5173 /* First zero everything else */
5174 memset(origOp, 0, ohbytes);
5176 if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
5177 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
5178 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
5179 *((u_long *)(op + 8)) = onbytes;
5181 *((u_long *)(op + 60)) = onbytes;
5182 strcpy(origOp+ohbytes, dep->name);
5183 if (smb_StoreAnsiFilenames)
5184 CharToOem(origOp+ohbytes, origOp+ohbytes);
5186 /* Short name if requested and needed */
5187 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
5188 if (NeedShortName) {
5189 strcpy(op + 70, shortName);
5190 if (smb_StoreAnsiFilenames)
5191 CharToOem(op + 70, op + 70);
5192 *(op + 68) = (char)(shortNameEnd - shortName);
5196 /* now, adjust the # of entries copied */
5199 /* NextEntryOffset and FileIndex */
5200 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
5201 int entryOffset = orbytes + align;
5202 *((u_long *)op) = entryOffset;
5203 *((u_long *)(op+4)) = nextEntryCookie;
5206 /* now we emit the attribute. This is tricky, since
5207 * we need to really stat the file to find out what
5208 * type of entry we've got. Right now, we're copying
5209 * out data from a buffer, while holding the scp
5210 * locked, so it isn't really convenient to stat
5211 * something now. We'll put in a place holder
5212 * now, and make a second pass before returning this
5213 * to get the real attributes. So, we just skip the
5214 * data for now, and adjust it later. We allocate a
5215 * patch record to make it easy to find this point
5216 * later. The replay will happen at a time when it is
5217 * safe to unlock the directory.
5219 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5220 curPatchp = malloc(sizeof(*curPatchp));
5221 osi_QAdd((osi_queue_t **) &dirListPatchesp,
5223 curPatchp->dptr = op;
5224 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5225 curPatchp->dptr += 8;
5227 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
5228 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5231 curPatchp->flags = 0;
5233 curPatchp->fid.cell = scp->fid.cell;
5234 curPatchp->fid.volume = scp->fid.volume;
5235 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
5236 curPatchp->fid.unique = ntohl(dep->fid.unique);
5239 curPatchp->dep = dep;
5242 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5243 /* put out resume key */
5244 *((u_long *)origOp) = nextEntryCookie;
5246 /* Adjust byte ptr and count */
5247 origOp += orbytes; /* skip entire record */
5248 bytesInBuffer += orbytes;
5250 /* and pad the record out */
5251 while (--align >= 0) {
5255 } /* if we're including this name */
5256 else if (!starPattern &&
5258 dep->fid.vnode != 0 &&
5259 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
5260 /* We were looking for exact matches, but here's an inexact one*/
5265 /* and adjust curOffset to be where the new cookie is */
5266 thyper.HighPart = 0;
5267 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5268 curOffset = LargeIntegerAdd(thyper, curOffset);
5269 } /* while copying data for dir listing */
5271 /* If we didn't get a star pattern, we did an exact match during the first pass.
5272 * If there were no exact matches found, we fail over to inexact matches by
5273 * marking the query as a star pattern (matches all case permutations), and
5274 * re-running the query.
5276 if (returnedNames == 0 && !starPattern && foundInexact) {
5277 osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
5282 /* release the mutex */
5283 lock_ReleaseMutex(&scp->mx);
5285 buf_Release(bufferp);
5289 /* apply and free last set of patches; if not doing a star match, this
5290 * will be empty, but better safe (and freeing everything) than sorry.
5292 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
5295 /* now put out the final parameters */
5296 if (returnedNames == 0)
5298 if (p->opcode == 1) {
5300 outp->parmsp[0] = (unsigned short) dsp->cookie;
5301 outp->parmsp[1] = returnedNames;
5302 outp->parmsp[2] = eos;
5303 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5304 outp->parmsp[4] = 0;
5305 /* don't need last name to continue
5306 * search, cookie is enough. Normally,
5307 * this is the offset of the file name
5308 * of the last entry returned.
5310 outp->totalParms = 10; /* in bytes */
5314 outp->parmsp[0] = returnedNames;
5315 outp->parmsp[1] = eos;
5316 outp->parmsp[2] = 0; /* EAS error */
5317 outp->parmsp[3] = 0; /* last name, as above */
5318 outp->totalParms = 8; /* in bytes */
5321 /* return # of bytes in the buffer */
5322 outp->totalData = bytesInBuffer;
5324 /* Return error code if unsuccessful on first request */
5325 if (code == 0 && p->opcode == 1 && returnedNames == 0)
5326 code = CM_ERROR_NOSUCHFILE;
5328 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
5329 p->opcode, dsp->cookie, returnedNames, code);
5331 /* if we're supposed to close the search after this request, or if
5332 * we're supposed to close the search if we're done, and we're done,
5333 * or if something went wrong, close the search.
5335 if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
5336 (returnedNames == 0) ||
5337 ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
5339 smb_DeleteDirSearch(dsp);
5342 smb_SendTran2Error(vcp, p, opx, code);
5344 smb_SendTran2Packet(vcp, outp, opx);
5346 smb_FreeTran2Packet(outp);
5347 smb_ReleaseDirSearch(dsp);
5348 cm_ReleaseSCache(scp);
5349 cm_ReleaseUser(userp);
5353 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5356 smb_dirSearch_t *dsp;
5358 dirHandle = smb_GetSMBParm(inp, 0);
5360 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
5362 dsp = smb_FindDirSearch(dirHandle);
5365 return CM_ERROR_BADFD;
5367 /* otherwise, we have an FD to destroy */
5368 smb_DeleteDirSearch(dsp);
5369 smb_ReleaseDirSearch(dsp);
5371 /* and return results */
5372 smb_SetSMBDataLength(outp, 0);
5377 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5379 smb_SetSMBDataLength(outp, 0);
5383 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5390 cm_scache_t *dscp; /* dir we're dealing with */
5391 cm_scache_t *scp; /* file we're creating */
5393 int initialModeBits;
5403 int parmSlot; /* which parm we're dealing with */
5412 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
5413 openFun = smb_GetSMBParm(inp, 8); /* open function */
5414 excl = ((openFun & 3) == 0);
5415 trunc = ((openFun & 3) == 2); /* truncate it */
5416 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
5417 openAction = 0; /* tracks what we did */
5419 attributes = smb_GetSMBParm(inp, 5);
5420 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
5422 /* compute initial mode bits based on read-only flag in attributes */
5423 initialModeBits = 0666;
5424 if (attributes & SMB_ATTR_READONLY)
5425 initialModeBits &= ~0222;
5427 pathp = smb_GetSMBData(inp, NULL);
5428 if (smb_StoreAnsiFilenames)
5429 OemToChar(pathp,pathp);
5431 spacep = inp->spacep;
5432 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5434 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5435 /* special case magic file name for receiving IOCTL requests
5436 * (since IOCTL calls themselves aren't getting through).
5439 osi_Log0(smb_logp, "IOCTL Open");
5442 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5443 smb_SetupIoctlFid(fidp, spacep);
5445 /* set inp->fid so that later read calls in same msg can find fid */
5446 inp->fid = fidp->fid;
5448 /* copy out remainder of the parms */
5450 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5452 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
5453 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
5454 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5455 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
5456 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
5457 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5458 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5459 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5461 /* and the final "always present" stuff */
5462 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
5463 /* next write out the "unique" ID */
5464 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
5465 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
5466 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5467 smb_SetSMBDataLength(outp, 0);
5469 /* and clean up fid reference */
5470 smb_ReleaseFID(fidp);
5474 #ifdef DEBUG_VERBOSE
5476 char *hexp, *asciip;
5477 asciip = (lastNamep ? lastNamep : pathp );
5478 hexp = osi_HexifyString(asciip);
5479 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
5483 userp = smb_GetUserFromVCP(vcp, inp);
5486 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5488 cm_ReleaseUser(userp);
5489 return CM_ERROR_NOSUCHPATH;
5491 code = cm_NameI(cm_data.rootSCachep, pathp,
5492 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5493 userp, tidPathp, &req, &scp);
5496 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5497 cm_ReleaseSCache(scp);
5498 cm_ReleaseUser(userp);
5499 if ( WANTS_DFS_PATHNAMES(inp) )
5500 return CM_ERROR_PATH_NOT_COVERED;
5502 return CM_ERROR_BADSHARENAME;
5504 #endif /* DFS_SUPPORT */
5507 code = cm_NameI(cm_data.rootSCachep, spacep->data,
5508 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5509 userp, tidPathp, &req, &dscp);
5511 cm_ReleaseUser(userp);
5516 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5517 cm_ReleaseSCache(dscp);
5518 cm_ReleaseUser(userp);
5519 if ( WANTS_DFS_PATHNAMES(inp) )
5520 return CM_ERROR_PATH_NOT_COVERED;
5522 return CM_ERROR_BADSHARENAME;
5524 #endif /* DFS_SUPPORT */
5525 /* otherwise, scp points to the parent directory. Do a lookup,
5526 * and truncate the file if we find it, otherwise we create the
5533 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
5535 if (code && code != CM_ERROR_NOSUCHFILE) {
5536 cm_ReleaseSCache(dscp);
5537 cm_ReleaseUser(userp);
5542 /* if we get here, if code is 0, the file exists and is represented by
5543 * scp. Otherwise, we have to create it. The dir may be represented
5544 * by dscp, or we may have found the file directly. If code is non-zero,
5548 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
5550 if (dscp) cm_ReleaseSCache(dscp);
5551 cm_ReleaseSCache(scp);
5552 cm_ReleaseUser(userp);
5557 /* oops, file shouldn't be there */
5559 cm_ReleaseSCache(dscp);
5560 cm_ReleaseSCache(scp);
5561 cm_ReleaseUser(userp);
5562 return CM_ERROR_EXISTS;
5566 setAttr.mask = CM_ATTRMASK_LENGTH;
5567 setAttr.length.LowPart = 0;
5568 setAttr.length.HighPart = 0;
5569 code = cm_SetAttr(scp, &setAttr, userp, &req);
5570 openAction = 3; /* truncated existing file */
5572 else openAction = 1; /* found existing file */
5574 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
5575 /* don't create if not found */
5576 if (dscp) cm_ReleaseSCache(dscp);
5577 cm_ReleaseUser(userp);
5578 return CM_ERROR_NOSUCHFILE;
5581 osi_assert(dscp != NULL);
5582 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
5583 osi_LogSaveString(smb_logp, lastNamep));
5584 openAction = 2; /* created file */
5585 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5586 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5587 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5591 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5592 smb_NotifyChange(FILE_ACTION_ADDED,
5593 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5594 dscp, lastNamep, NULL, TRUE);
5595 } else if (!excl && code == CM_ERROR_EXISTS) {
5596 /* not an exclusive create, and someone else tried
5597 * creating it already, then we open it anyway. We
5598 * don't bother retrying after this, since if this next
5599 * fails, that means that the file was deleted after we
5600 * started this call.
5602 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5606 setAttr.mask = CM_ATTRMASK_LENGTH;
5607 setAttr.length.LowPart = 0;
5608 setAttr.length.HighPart = 0;
5609 code = cm_SetAttr(scp, &setAttr, userp, &req);
5611 } /* lookup succeeded */
5615 /* we don't need this any longer */
5617 cm_ReleaseSCache(dscp);
5620 /* something went wrong creating or truncating the file */
5622 cm_ReleaseSCache(scp);
5623 cm_ReleaseUser(userp);
5627 /* make sure we're about to open a file */
5628 if (scp->fileType != CM_SCACHETYPE_FILE) {
5629 cm_ReleaseSCache(scp);
5630 cm_ReleaseUser(userp);
5631 return CM_ERROR_ISDIR;
5634 /* now all we have to do is open the file itself */
5635 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5639 lock_ObtainMutex(&fidp->mx);
5640 /* save a pointer to the vnode */
5642 lock_ObtainMutex(&scp->mx);
5643 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5644 lock_ReleaseMutex(&scp->mx);
5645 osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
5647 fidp->userp = userp;
5649 /* compute open mode */
5651 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5652 if (openMode == 1 || openMode == 2)
5653 fidp->flags |= SMB_FID_OPENWRITE;
5655 /* remember if the file was newly created */
5657 fidp->flags |= SMB_FID_CREATED;
5659 lock_ReleaseMutex(&fidp->mx);
5660 smb_ReleaseFID(fidp);
5662 cm_Open(scp, 0, userp);
5664 /* set inp->fid so that later read calls in same msg can find fid */
5665 inp->fid = fidp->fid;
5667 /* copy out remainder of the parms */
5669 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5670 lock_ObtainMutex(&scp->mx);
5672 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5673 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5674 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5675 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5676 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5677 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5678 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5679 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5680 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5682 /* and the final "always present" stuff */
5683 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5684 /* next write out the "unique" ID */
5685 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5686 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5687 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5688 lock_ReleaseMutex(&scp->mx);
5689 smb_SetSMBDataLength(outp, 0);
5691 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5693 cm_ReleaseUser(userp);
5694 /* leave scp held since we put it in fidp->scp */
5698 static void smb_GetLockParams(unsigned char LockType,
5700 unsigned int * ppid,
5701 LARGE_INTEGER * pOffset,
5702 LARGE_INTEGER * pLength)
5704 if (LockType & LOCKING_ANDX_LARGE_FILES) {
5706 *ppid = *((USHORT *) *buf);
5707 pOffset->HighPart = *((LONG *)(*buf + 4));
5708 pOffset->LowPart = *((DWORD *)(*buf + 8));
5709 pLength->HighPart = *((LONG *)(*buf + 12));
5710 pLength->LowPart = *((DWORD *)(*buf + 16));
5714 /* Not Large Files */
5715 *ppid = *((USHORT *) *buf);
5716 pOffset->HighPart = 0;
5717 pOffset->LowPart = *((DWORD *)(*buf + 2));
5718 pLength->HighPart = 0;
5719 pLength->LowPart = *((DWORD *)(*buf + 6));
5724 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5731 unsigned char LockType;
5732 unsigned short NumberOfUnlocks, NumberOfLocks;
5736 LARGE_INTEGER LOffset, LLength;
5737 smb_waitingLockRequest_t *wlRequest = NULL;
5738 cm_file_lock_t *lockp;
5746 fid = smb_GetSMBParm(inp, 2);
5747 fid = smb_ChainFID(fid, inp);
5749 fidp = smb_FindFID(vcp, fid, 0);
5751 return CM_ERROR_BADFD;
5753 lock_ObtainMutex(&fidp->mx);
5754 if (fidp->flags & SMB_FID_IOCTL) {
5755 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
5756 lock_ReleaseMutex(&fidp->mx);
5757 smb_ReleaseFID(fidp);
5758 return CM_ERROR_BADFD;
5761 osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
5763 lock_ReleaseMutex(&fidp->mx);
5765 /* set inp->fid so that later read calls in same msg can find fid */
5768 userp = smb_GetUserFromVCP(vcp, inp);
5771 lock_ObtainMutex(&scp->mx);
5772 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5773 CM_SCACHESYNC_NEEDCALLBACK
5774 | CM_SCACHESYNC_GETSTATUS
5775 | CM_SCACHESYNC_LOCK);
5777 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
5781 LockType = smb_GetSMBParm(inp, 3) & 0xff;
5782 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
5783 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
5784 NumberOfLocks = smb_GetSMBParm(inp, 7);
5786 if (!(fidp->flags & SMB_FID_OPENWRITE) &&
5787 !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
5788 /* somebody wants exclusive locks on a file that they only
5789 opened for reading. We downgrade this to a shared lock. */
5790 osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
5791 LockType |= LOCKING_ANDX_SHARED_LOCK;
5794 if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
5795 (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
5797 /* We don't support these requests. Apparently, we can safely
5798 not deal with them too. */
5799 osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
5800 ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
5801 "LOCKING_ANDX_CANCEL_LOCK":
5802 "LOCKING_ANDX_CHANGE_LOCKTYPE"));
5803 /* No need to call osi_LogSaveString since these are string
5806 code = CM_ERROR_BADOP;
5811 op = smb_GetSMBData(inp, NULL);
5813 for (i=0; i<NumberOfUnlocks; i++) {
5814 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5816 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5818 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
5826 for (i=0; i<NumberOfLocks; i++) {
5827 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5829 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5831 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
5832 userp, &req, &lockp);
5834 if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
5835 (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
5837 code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
5838 userp, &req, &lockp);
5841 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
5842 smb_waitingLock_t * wLock;
5844 /* Put on waiting list */
5845 if(wlRequest == NULL) {
5849 LARGE_INTEGER tOffset, tLength;
5851 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
5853 osi_assert(wlRequest != NULL);
5855 wlRequest->vcp = vcp;
5857 wlRequest->scp = scp;
5858 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
5860 wlRequest->inp = smb_CopyPacket(inp);
5861 wlRequest->outp = smb_CopyPacket(outp);
5862 wlRequest->lockType = LockType;
5863 wlRequest->timeRemaining = Timeout;
5864 wlRequest->locks = NULL;
5866 /* The waiting lock request needs to have enough
5867 information to undo all the locks in the request.
5868 We do the following to store info about locks that
5869 have already been granted. Sure, we can get most
5870 of the info from the packet, but the packet doesn't
5871 hold the result of cm_Lock call. In practice we
5872 only receive packets with one or two locks, so we
5873 are only wasting a few bytes here and there and
5874 only for a limited period of time until the waiting
5875 lock times out or is freed. */
5877 for(opt = op_locks, j=i; j > 0; j--) {
5878 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
5880 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5882 wLock = malloc(sizeof(smb_waitingLock_t));
5884 osi_assert(wLock != NULL);
5887 wLock->LOffset = tOffset;
5888 wLock->LLength = tLength;
5889 wLock->lockp = NULL;
5890 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
5891 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5896 wLock = malloc(sizeof(smb_waitingLock_t));
5898 osi_assert(wLock != NULL);
5901 wLock->LOffset = LOffset;
5902 wLock->LLength = LLength;
5903 wLock->lockp = lockp;
5904 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
5905 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5908 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
5916 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
5923 /* Since something went wrong with the lock number i, we now
5924 have to go ahead and release any locks acquired before the
5925 failure. All locks before lock number i (of which there
5926 are i of them) have either been successful or are waiting.
5927 Either case requires calling cm_Unlock(). */
5929 /* And purge the waiting lock */
5930 if(wlRequest != NULL) {
5931 smb_waitingLock_t * wl;
5932 smb_waitingLock_t * wlNext;
5935 for(wl = wlRequest->locks; wl; wl = wlNext) {
5937 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
5939 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
5942 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
5944 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
5947 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
5952 smb_ReleaseVC(wlRequest->vcp);
5953 cm_ReleaseSCache(wlRequest->scp);
5954 smb_FreePacket(wlRequest->inp);
5955 smb_FreePacket(wlRequest->outp);
5964 if (wlRequest != NULL) {
5966 lock_ObtainWrite(&smb_globalLock);
5967 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
5969 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
5970 lock_ReleaseWrite(&smb_globalLock);
5972 /* don't send reply immediately */
5973 outp->flags |= SMB_PACKETFLAG_NOSEND;
5976 smb_SetSMBDataLength(outp, 0);
5980 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5983 lock_ReleaseMutex(&scp->mx);
5984 cm_ReleaseSCache(scp);
5985 cm_ReleaseUser(userp);
5986 smb_ReleaseFID(fidp);
5991 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5997 afs_uint32 searchTime;
6003 fid = smb_GetSMBParm(inp, 0);
6004 fid = smb_ChainFID(fid, inp);
6006 fidp = smb_FindFID(vcp, fid, 0);
6008 return CM_ERROR_BADFD;
6010 lock_ObtainMutex(&fidp->mx);
6011 if (fidp->flags & SMB_FID_IOCTL) {
6012 lock_ReleaseMutex(&fidp->mx);
6013 smb_ReleaseFID(fidp);
6014 return CM_ERROR_BADFD;
6017 osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6019 lock_ReleaseMutex(&fidp->mx);
6021 userp = smb_GetUserFromVCP(vcp, inp);
6024 /* otherwise, stat the file */
6025 lock_ObtainMutex(&scp->mx);
6026 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6027 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6031 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6033 /* decode times. We need a search time, but the response to this
6034 * call provides the date first, not the time, as returned in the
6035 * searchTime variable. So we take the high-order bits first.
6037 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
6038 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
6039 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
6040 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
6041 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
6042 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
6043 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
6045 /* now handle file size and allocation size */
6046 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
6047 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
6048 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
6049 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
6051 /* file attribute */
6052 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
6054 /* and finalize stuff */
6055 smb_SetSMBDataLength(outp, 0);
6059 lock_ReleaseMutex(&scp->mx);
6060 cm_ReleaseSCache(scp);
6061 cm_ReleaseUser(userp);
6062 smb_ReleaseFID(fidp);
6066 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6072 afs_uint32 searchTime;
6080 fid = smb_GetSMBParm(inp, 0);
6081 fid = smb_ChainFID(fid, inp);
6083 fidp = smb_FindFID(vcp, fid, 0);
6085 return CM_ERROR_BADFD;
6087 lock_ObtainMutex(&fidp->mx);
6088 if (fidp->flags & SMB_FID_IOCTL) {
6089 lock_ReleaseMutex(&fidp->mx);
6090 smb_ReleaseFID(fidp);
6091 return CM_ERROR_BADFD;
6094 osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6096 lock_ReleaseMutex(&fidp->mx);
6098 userp = smb_GetUserFromVCP(vcp, inp);
6101 /* now prepare to call cm_setattr. This message only sets various times,
6102 * and AFS only implements mtime, and we'll set the mtime if that's
6103 * requested. The others we'll ignore.
6105 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
6107 if (searchTime != 0) {
6108 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
6110 if ( unixTime != -1 ) {
6111 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
6112 attrs.clientModTime = unixTime;
6113 code = cm_SetAttr(scp, &attrs, userp, &req);
6115 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
6117 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
6123 cm_ReleaseSCache(scp);
6124 cm_ReleaseUser(userp);
6125 smb_ReleaseFID(fidp);
6129 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6132 long count, written = 0, total_written = 0;
6139 int inDataBlockCount;
6141 fd = smb_GetSMBParm(inp, 2);
6142 count = smb_GetSMBParm(inp, 10);
6144 offset.HighPart = 0;
6145 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6147 if (*inp->wctp == 14) {
6148 /* we have a request with 64-bit file offsets */
6149 #ifdef AFS_LARGEFILES
6150 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6152 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6154 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
6155 /* we shouldn't have received this op if we didn't specify
6156 largefile support */
6157 return CM_ERROR_BADOP;
6162 op = inp->data + smb_GetSMBParm(inp, 11);
6163 inDataBlockCount = count;
6165 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
6166 fd, offset.HighPart, offset.LowPart, count);
6168 fd = smb_ChainFID(fd, inp);
6169 fidp = smb_FindFID(vcp, fd, 0);
6171 return CM_ERROR_BADFD;
6173 lock_ObtainMutex(&fidp->mx);
6174 if (fidp->flags & SMB_FID_IOCTL) {
6175 lock_ReleaseMutex(&fidp->mx);
6176 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
6177 smb_ReleaseFID(fidp);
6180 lock_ReleaseMutex(&fidp->mx);
6181 userp = smb_GetUserFromVCP(vcp, inp);
6183 /* special case: 0 bytes transferred means there is no data
6184 transferred. A slight departure from SMB_COM_WRITE where this
6185 means that we are supposed to truncate the file at this
6190 LARGE_INTEGER LOffset;
6191 LARGE_INTEGER LLength;
6194 pid = ((smb_t *) inp)->pid;
6195 key = cm_GenerateKey(vcp->vcID, pid, fd);
6197 LOffset.HighPart = offset.HighPart;
6198 LOffset.LowPart = offset.LowPart;
6199 LLength.HighPart = 0;
6200 LLength.LowPart = count;
6203 lock_ObtainMutex(&scp->mx);
6204 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
6205 lock_ReleaseMutex(&scp->mx);
6212 * Work around bug in NT client
6214 * When copying a file, the NT client should first copy the data,
6215 * then copy the last write time. But sometimes the NT client does
6216 * these in the wrong order, so the data copies would inadvertently
6217 * cause the last write time to be overwritten. We try to detect this,
6218 * and don't set client mod time if we think that would go against the
6221 lock_ObtainMutex(&fidp->mx);
6222 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6223 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6224 fidp->scp->clientModTime = time(NULL);
6226 lock_ReleaseMutex(&fidp->mx);
6229 while ( code == 0 && count > 0 ) {
6231 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6233 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6235 if (code == 0 && written == 0)
6236 code = CM_ERROR_PARTIALWRITE;
6238 offset = LargeIntegerAdd(offset,
6239 ConvertLongToLargeInteger(written));
6241 total_written += written;
6247 /* slots 0 and 1 are reserved for request chaining and will be
6248 filled in when we return. */
6249 smb_SetSMBParm(outp, 2, total_written);
6250 smb_SetSMBParm(outp, 3, 0); /* reserved */
6251 smb_SetSMBParm(outp, 4, 0); /* reserved */
6252 smb_SetSMBParm(outp, 5, 0); /* reserved */
6253 smb_SetSMBDataLength(outp, 0);
6256 cm_ReleaseUser(userp);
6257 smb_ReleaseFID(fidp);
6262 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6266 long finalCount = 0;
6275 fd = smb_GetSMBParm(inp, 2);
6276 count = smb_GetSMBParm(inp, 5);
6277 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6279 if (*inp->wctp == 12) {
6280 /* a request with 64-bit offsets */
6281 #ifdef AFS_LARGEFILES
6282 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
6284 if (LargeIntegerLessThanZero(offset)) {
6285 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
6286 offset.HighPart, offset.LowPart);
6287 return CM_ERROR_BADSMB;
6290 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
6291 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
6292 return CM_ERROR_BADSMB;
6294 offset.HighPart = 0;
6298 offset.HighPart = 0;
6301 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
6302 fd, offset.HighPart, offset.LowPart, count);
6304 fd = smb_ChainFID(fd, inp);
6305 fidp = smb_FindFID(vcp, fd, 0);
6307 return CM_ERROR_BADFD;
6310 pid = ((smb_t *) inp)->pid;
6311 key = cm_GenerateKey(vcp->vcID, pid, fd);
6313 LARGE_INTEGER LOffset, LLength;
6316 LOffset.HighPart = offset.HighPart;
6317 LOffset.LowPart = offset.LowPart;
6318 LLength.HighPart = 0;
6319 LLength.LowPart = count;
6322 lock_ObtainMutex(&scp->mx);
6323 code = cm_LockCheckRead(scp, LOffset, LLength, key);
6324 lock_ReleaseMutex(&scp->mx);
6328 smb_ReleaseFID(fidp);
6332 /* set inp->fid so that later read calls in same msg can find fid */
6335 lock_ObtainMutex(&fidp->mx);
6336 if (fidp->flags & SMB_FID_IOCTL) {
6337 lock_ReleaseMutex(&fidp->mx);
6338 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
6339 smb_ReleaseFID(fidp);
6342 lock_ReleaseMutex(&fidp->mx);
6344 userp = smb_GetUserFromVCP(vcp, inp);
6346 /* 0 and 1 are reserved for request chaining, were setup by our caller,
6347 * and will be further filled in after we return.
6349 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
6350 smb_SetSMBParm(outp, 3, 0); /* resvd */
6351 smb_SetSMBParm(outp, 4, 0); /* resvd */
6352 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
6353 /* fill in #6 when we have all the parameters' space reserved */
6354 smb_SetSMBParm(outp, 7, 0); /* resv'd */
6355 smb_SetSMBParm(outp, 8, 0); /* resv'd */
6356 smb_SetSMBParm(outp, 9, 0); /* resv'd */
6357 smb_SetSMBParm(outp, 10, 0); /* resv'd */
6358 smb_SetSMBParm(outp, 11, 0); /* reserved */
6360 /* get op ptr after putting in the parms, since otherwise we don't
6361 * know where the data really is.
6363 op = smb_GetSMBData(outp, NULL);
6365 /* now fill in offset from start of SMB header to first data byte (to op) */
6366 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
6368 /* set the packet data length the count of the # of bytes */
6369 smb_SetSMBDataLength(outp, count);
6372 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6374 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
6377 /* fix some things up */
6378 smb_SetSMBParm(outp, 5, finalCount);
6379 smb_SetSMBDataLength(outp, finalCount);
6381 cm_ReleaseUser(userp);
6382 smb_ReleaseFID(fidp);
6387 * Values for createDisp, copied from NTDDK.H
6389 #define FILE_SUPERSEDE 0 // (???)
6390 #define FILE_OPEN 1 // (open)
6391 #define FILE_CREATE 2 // (exclusive)
6392 #define FILE_OPEN_IF 3 // (non-exclusive)
6393 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
6394 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
6397 #define REQUEST_OPLOCK 2
6398 #define REQUEST_BATCH_OPLOCK 4
6399 #define OPEN_DIRECTORY 8
6400 #define EXTENDED_RESPONSE_REQUIRED 0x10
6402 /* CreateOptions field. */
6403 #define FILE_DIRECTORY_FILE 0x0001
6404 #define FILE_WRITE_THROUGH 0x0002
6405 #define FILE_SEQUENTIAL_ONLY 0x0004
6406 #define FILE_NON_DIRECTORY_FILE 0x0040
6407 #define FILE_NO_EA_KNOWLEDGE 0x0200
6408 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
6409 #define FILE_RANDOM_ACCESS 0x0800
6410 #define FILE_DELETE_ON_CLOSE 0x1000
6411 #define FILE_OPEN_BY_FILE_ID 0x2000
6413 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6415 char *pathp, *realPathp;
6419 cm_scache_t *dscp; /* parent dir */
6420 cm_scache_t *scp; /* file to create or open */
6421 cm_scache_t *targetScp; /* if scp is a symlink */
6425 unsigned short nameLength;
6427 unsigned int requestOpLock;
6428 unsigned int requestBatchOpLock;
6429 unsigned int mustBeDir;
6430 unsigned int extendedRespRequired;
6431 unsigned int treeCreate;
6433 unsigned int desiredAccess;
6434 unsigned int extAttributes;
6435 unsigned int createDisp;
6436 unsigned int createOptions;
6437 unsigned int shareAccess;
6438 int initialModeBits;
6439 unsigned short baseFid;
6440 smb_fid_t *baseFidp;
6442 cm_scache_t *baseDirp;
6443 unsigned short openAction;
6452 cm_lock_data_t *ldp = NULL;
6456 /* This code is very long and has a lot of if-then-else clauses
6457 * scp and dscp get reused frequently and we need to ensure that
6458 * we don't lose a reference. Start by ensuring that they are NULL.
6465 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
6466 flags = smb_GetSMBOffsetParm(inp, 3, 1)
6467 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
6468 requestOpLock = flags & REQUEST_OPLOCK;
6469 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6470 mustBeDir = flags & OPEN_DIRECTORY;
6471 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6474 * Why all of a sudden 32-bit FID?
6475 * We will reject all bits higher than 16.
6477 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
6478 return CM_ERROR_INVAL;
6479 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
6480 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
6481 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6482 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
6483 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
6484 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
6485 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
6486 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
6487 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
6488 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
6489 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
6491 /* mustBeDir is never set; createOptions directory bit seems to be
6494 if (createOptions & FILE_DIRECTORY_FILE)
6496 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6502 * compute initial mode bits based on read-only flag in
6503 * extended attributes
6505 initialModeBits = 0666;
6506 if (extAttributes & SMB_ATTR_READONLY)
6507 initialModeBits &= ~0222;
6509 pathp = smb_GetSMBData(inp, NULL);
6510 /* Sometimes path is not null-terminated, so we make a copy. */
6511 realPathp = malloc(nameLength+1);
6512 memcpy(realPathp, pathp, nameLength);
6513 realPathp[nameLength] = 0;
6514 if (smb_StoreAnsiFilenames)
6515 OemToChar(realPathp,realPathp);
6517 spacep = inp->spacep;
6518 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6520 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
6521 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
6522 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
6524 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
6525 /* special case magic file name for receiving IOCTL requests
6526 * (since IOCTL calls themselves aren't getting through).
6528 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6529 smb_SetupIoctlFid(fidp, spacep);
6530 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
6532 /* set inp->fid so that later read calls in same msg can find fid */
6533 inp->fid = fidp->fid;
6537 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6538 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6539 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
6541 memset(&ft, 0, sizeof(ft));
6542 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6543 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6544 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6545 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6546 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
6547 sz.HighPart = 0x7fff; sz.LowPart = 0;
6548 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
6549 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
6550 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6551 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6552 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
6553 smb_SetSMBDataLength(outp, 0);
6555 /* clean up fid reference */
6556 smb_ReleaseFID(fidp);
6561 #ifdef DEBUG_VERBOSE
6563 char *hexp, *asciip;
6564 asciip = (lastNamep? lastNamep : realPathp);
6565 hexp = osi_HexifyString( asciip );
6566 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
6571 userp = smb_GetUserFromVCP(vcp, inp);
6573 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
6575 return CM_ERROR_INVAL;
6580 baseDirp = cm_data.rootSCachep;
6581 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6582 if (code == CM_ERROR_TIDIPC) {
6583 /* Attempt to use a TID allocated for IPC. The client
6584 * is probably looking for DCE RPC end points which we
6585 * don't support OR it could be looking to make a DFS
6588 osi_Log0(smb_logp, "NTCreateX received IPC TID");
6591 cm_ReleaseUser(userp);
6592 return CM_ERROR_NOSUCHFILE;
6593 #endif /* DFS_SUPPORT */
6596 baseFidp = smb_FindFID(vcp, baseFid, 0);
6598 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
6600 cm_ReleaseUser(userp);
6601 return CM_ERROR_INVAL;
6603 baseDirp = baseFidp->scp;
6607 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
6609 /* compute open mode */
6611 if (desiredAccess & DELETE)
6612 fidflags |= SMB_FID_OPENDELETE;
6613 if (desiredAccess & AFS_ACCESS_READ)
6614 fidflags |= SMB_FID_OPENREAD_LISTDIR;
6615 if (desiredAccess & AFS_ACCESS_WRITE)
6616 fidflags |= SMB_FID_OPENWRITE;
6617 if (createOptions & FILE_DELETE_ON_CLOSE)
6618 fidflags |= SMB_FID_DELONCLOSE;
6619 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6620 fidflags |= SMB_FID_SEQUENTIAL;
6621 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6622 fidflags |= SMB_FID_RANDOM;
6624 /* and the share mode */
6625 if (shareAccess & FILE_SHARE_READ)
6626 fidflags |= SMB_FID_SHARE_READ;
6627 if (shareAccess & FILE_SHARE_WRITE)
6628 fidflags |= SMB_FID_SHARE_WRITE;
6630 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
6633 /* For an exclusive create, we want to do a case sensitive match for the last component. */
6634 if ( createDisp == FILE_CREATE ||
6635 createDisp == FILE_OVERWRITE ||
6636 createDisp == FILE_OVERWRITE_IF) {
6637 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6638 userp, tidPathp, &req, &dscp);
6641 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6642 cm_ReleaseSCache(dscp);
6643 cm_ReleaseUser(userp);
6646 smb_ReleaseFID(baseFidp);
6647 if ( WANTS_DFS_PATHNAMES(inp) )
6648 return CM_ERROR_PATH_NOT_COVERED;
6650 return CM_ERROR_BADSHARENAME;
6652 #endif /* DFS_SUPPORT */
6653 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6655 if (code == CM_ERROR_NOSUCHFILE) {
6656 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6657 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6658 if (code == 0 && realDirFlag == 1) {
6659 cm_ReleaseSCache(scp);
6660 cm_ReleaseSCache(dscp);
6661 cm_ReleaseUser(userp);
6664 smb_ReleaseFID(baseFidp);
6665 return CM_ERROR_EXISTS;
6669 /* we have both scp and dscp */
6671 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6672 userp, tidPathp, &req, &scp);
6674 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6675 cm_ReleaseSCache(scp);
6676 cm_ReleaseUser(userp);
6679 smb_ReleaseFID(baseFidp);
6680 if ( WANTS_DFS_PATHNAMES(inp) )
6681 return CM_ERROR_PATH_NOT_COVERED;
6683 return CM_ERROR_BADSHARENAME;
6685 #endif /* DFS_SUPPORT */
6686 /* we might have scp but not dscp */
6692 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6693 /* look up parent directory */
6694 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
6695 * the immediate parent. We have to work our way up realPathp until we hit something that we
6699 /* we might or might not have scp */
6705 code = cm_NameI(baseDirp, spacep->data,
6706 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6707 userp, tidPathp, &req, &dscp);
6710 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6712 cm_ReleaseSCache(scp);
6713 cm_ReleaseSCache(dscp);
6714 cm_ReleaseUser(userp);
6717 smb_ReleaseFID(baseFidp);
6718 if ( WANTS_DFS_PATHNAMES(inp) )
6719 return CM_ERROR_PATH_NOT_COVERED;
6721 return CM_ERROR_BADSHARENAME;
6723 #endif /* DFS_SUPPORT */
6726 (tp = strrchr(spacep->data,'\\')) &&
6727 (createDisp == FILE_CREATE) &&
6728 (realDirFlag == 1)) {
6731 treeStartp = realPathp + (tp - spacep->data);
6733 if (*tp && !smb_IsLegalFilename(tp)) {
6734 cm_ReleaseUser(userp);
6736 smb_ReleaseFID(baseFidp);
6739 cm_ReleaseSCache(scp);
6740 return CM_ERROR_BADNTFILENAME;
6744 } while (dscp == NULL && code == 0);
6748 /* we might have scp and we might have dscp */
6751 smb_ReleaseFID(baseFidp);
6754 osi_Log0(smb_logp,"NTCreateX parent not found");
6756 cm_ReleaseSCache(scp);
6758 cm_ReleaseSCache(dscp);
6759 cm_ReleaseUser(userp);
6764 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
6765 /* A file exists where we want a directory. */
6767 cm_ReleaseSCache(scp);
6768 cm_ReleaseSCache(dscp);
6769 cm_ReleaseUser(userp);
6771 return CM_ERROR_EXISTS;
6775 lastNamep = realPathp;
6779 if (!smb_IsLegalFilename(lastNamep)) {
6781 cm_ReleaseSCache(scp);
6783 cm_ReleaseSCache(dscp);
6784 cm_ReleaseUser(userp);
6786 return CM_ERROR_BADNTFILENAME;
6789 if (!foundscp && !treeCreate) {
6790 if ( createDisp == FILE_CREATE ||
6791 createDisp == FILE_OVERWRITE ||
6792 createDisp == FILE_OVERWRITE_IF)
6794 code = cm_Lookup(dscp, lastNamep,
6795 CM_FLAG_FOLLOW, userp, &req, &scp);
6797 code = cm_Lookup(dscp, lastNamep,
6798 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6801 if (code && code != CM_ERROR_NOSUCHFILE) {
6803 cm_ReleaseSCache(dscp);
6804 cm_ReleaseUser(userp);
6809 /* we have scp and dscp */
6811 /* we have scp but not dscp */
6813 smb_ReleaseFID(baseFidp);
6816 /* if we get here, if code is 0, the file exists and is represented by
6817 * scp. Otherwise, we have to create it. The dir may be represented
6818 * by dscp, or we may have found the file directly. If code is non-zero,
6821 if (code == 0 && !treeCreate) {
6822 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
6825 cm_ReleaseSCache(dscp);
6827 cm_ReleaseSCache(scp);
6828 cm_ReleaseUser(userp);
6833 if (createDisp == FILE_CREATE) {
6834 /* oops, file shouldn't be there */
6835 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6837 cm_ReleaseSCache(dscp);
6839 cm_ReleaseSCache(scp);
6840 cm_ReleaseUser(userp);
6842 return CM_ERROR_EXISTS;
6845 if ( createDisp == FILE_OVERWRITE ||
6846 createDisp == FILE_OVERWRITE_IF) {
6848 setAttr.mask = CM_ATTRMASK_LENGTH;
6849 setAttr.length.LowPart = 0;
6850 setAttr.length.HighPart = 0;
6851 /* now watch for a symlink */
6853 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6855 osi_assert(dscp != NULL);
6856 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6858 /* we have a more accurate file to use (the
6859 * target of the symbolic link). Otherwise,
6860 * we'll just use the symlink anyway.
6862 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6864 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6865 cm_ReleaseSCache(scp);
6867 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
6870 cm_ReleaseSCache(dscp);
6872 cm_ReleaseSCache(scp);
6873 cm_ReleaseUser(userp);
6879 code = cm_SetAttr(scp, &setAttr, userp, &req);
6880 openAction = 3; /* truncated existing file */
6883 openAction = 1; /* found existing file */
6885 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6886 /* don't create if not found */
6888 cm_ReleaseSCache(dscp);
6890 cm_ReleaseSCache(scp);
6891 cm_ReleaseUser(userp);
6893 return CM_ERROR_NOSUCHFILE;
6894 } else if (realDirFlag == 0 || realDirFlag == -1) {
6895 osi_assert(dscp != NULL);
6896 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
6897 osi_LogSaveString(smb_logp, lastNamep));
6898 openAction = 2; /* created file */
6899 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6900 setAttr.clientModTime = time(NULL);
6901 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
6904 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6905 smb_NotifyChange(FILE_ACTION_ADDED,
6906 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6907 dscp, lastNamep, NULL, TRUE);
6908 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6909 /* Not an exclusive create, and someone else tried
6910 * creating it already, then we open it anyway. We
6911 * don't bother retrying after this, since if this next
6912 * fails, that means that the file was deleted after we
6913 * started this call.
6915 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6918 if (createDisp == FILE_OVERWRITE_IF) {
6919 setAttr.mask = CM_ATTRMASK_LENGTH;
6920 setAttr.length.LowPart = 0;
6921 setAttr.length.HighPart = 0;
6923 /* now watch for a symlink */
6925 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6927 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6929 /* we have a more accurate file to use (the
6930 * target of the symbolic link). Otherwise,
6931 * we'll just use the symlink anyway.
6933 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6935 cm_ReleaseSCache(scp);
6939 code = cm_SetAttr(scp, &setAttr, userp, &req);
6941 } /* lookup succeeded */
6945 char *cp; /* This component */
6946 int clen = 0; /* length of component */
6947 cm_scache_t *tscp1, *tscp2;
6950 /* create directory */
6952 treeStartp = lastNamep;
6953 osi_assert(dscp != NULL);
6954 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
6955 osi_LogSaveString(smb_logp, treeStartp));
6956 openAction = 2; /* created directory */
6958 /* if the request is to create the root directory
6959 * it will appear as a directory name of the nul-string
6960 * and a code of CM_ERROR_NOSUCHFILE
6962 if ( !*treeStartp && code == CM_ERROR_NOSUCHFILE)
6963 code = CM_ERROR_EXISTS;
6965 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6966 setAttr.clientModTime = time(NULL);
6971 cm_HoldSCache(tscp1);
6975 tp = strchr(pp, '\\');
6978 clen = (int)strlen(cp);
6979 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
6981 clen = (int)(tp - pp);
6982 strncpy(cp,pp,clen);
6989 continue; /* the supplied path can't have consecutive slashes either , but */
6991 /* cp is the next component to be created. */
6992 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
6993 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
6994 smb_NotifyChange(FILE_ACTION_ADDED,
6995 FILE_NOTIFY_CHANGE_DIR_NAME,
6996 tscp1, cp, NULL, TRUE);
6998 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6999 /* Not an exclusive create, and someone else tried
7000 * creating it already, then we open it anyway. We
7001 * don't bother retrying after this, since if this next
7002 * fails, that means that the file was deleted after we
7003 * started this call.
7005 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
7006 userp, &req, &tscp2);
7011 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
7012 cm_ReleaseSCache(tscp1);
7013 tscp1 = tscp2; /* Newly created directory will be next parent */
7014 /* the hold is transfered to tscp1 from tscp2 */
7019 cm_ReleaseSCache(dscp);
7022 cm_ReleaseSCache(scp);
7025 * if we get here and code == 0, then scp is the last directory created, and dscp is the
7031 /* something went wrong creating or truncating the file */
7033 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7035 cm_ReleaseSCache(scp);
7037 cm_ReleaseSCache(dscp);
7038 cm_ReleaseUser(userp);
7043 /* make sure we have file vs. dir right (only applies for single component case) */
7044 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7045 /* now watch for a symlink */
7047 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7048 cm_scache_t * targetScp = 0;
7049 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7051 /* we have a more accurate file to use (the
7052 * target of the symbolic link). Otherwise,
7053 * we'll just use the symlink anyway.
7055 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
7057 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7058 cm_ReleaseSCache(scp);
7063 if (scp->fileType != CM_SCACHETYPE_FILE) {
7065 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7067 cm_ReleaseSCache(dscp);
7068 cm_ReleaseSCache(scp);
7069 cm_ReleaseUser(userp);
7071 return CM_ERROR_ISDIR;
7075 /* (only applies to single component case) */
7076 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7078 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7079 cm_ReleaseSCache(scp);
7081 cm_ReleaseSCache(dscp);
7082 cm_ReleaseUser(userp);
7084 return CM_ERROR_NOTDIR;
7087 /* open the file itself */
7088 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7091 /* save a reference to the user */
7093 fidp->userp = userp;
7095 /* If we are restricting sharing, we should do so with a suitable
7097 if (scp->fileType == CM_SCACHETYPE_FILE &&
7098 !(fidflags & SMB_FID_SHARE_WRITE)) {
7100 LARGE_INTEGER LOffset, LLength;
7103 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7104 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7105 LLength.HighPart = 0;
7106 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7108 /* If we are not opening the file for writing, then we don't
7109 try to get an exclusive lock. Noone else should be able to
7110 get an exclusive lock on the file anyway, although someone
7111 else can get a shared lock. */
7112 if ((fidflags & SMB_FID_SHARE_READ) ||
7113 !(fidflags & SMB_FID_OPENWRITE)) {
7114 sLockType = LOCKING_ANDX_SHARED_LOCK;
7119 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7121 lock_ObtainMutex(&scp->mx);
7122 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7123 lock_ReleaseMutex(&scp->mx);
7127 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7128 cm_ReleaseSCache(scp);
7130 cm_ReleaseSCache(dscp);
7131 cm_ReleaseUser(userp);
7132 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7133 smb_CloseFID(vcp, fidp, NULL, 0);
7134 smb_ReleaseFID(fidp);
7140 /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
7142 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7144 lock_ObtainMutex(&fidp->mx);
7145 /* save a pointer to the vnode */
7146 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
7147 lock_ObtainMutex(&scp->mx);
7148 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7149 lock_ReleaseMutex(&scp->mx);
7150 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
7152 fidp->flags = fidflags;
7154 /* remember if the file was newly created */
7156 fidp->flags |= SMB_FID_CREATED;
7158 /* save parent dir and pathname for delete or change notification */
7159 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7160 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
7161 fidp->flags |= SMB_FID_NTOPEN;
7162 fidp->NTopen_dscp = dscp;
7164 fidp->NTopen_pathp = strdup(lastNamep);
7166 fidp->NTopen_wholepathp = realPathp;
7167 lock_ReleaseMutex(&fidp->mx);
7169 /* we don't need this any longer */
7171 cm_ReleaseSCache(dscp);
7175 cm_Open(scp, 0, userp);
7177 /* set inp->fid so that later read calls in same msg can find fid */
7178 inp->fid = fidp->fid;
7182 lock_ObtainMutex(&scp->mx);
7183 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7184 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7185 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7186 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7187 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7188 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7189 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7190 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7191 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7193 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7194 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7195 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
7196 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
7197 smb_SetSMBParmByte(outp, parmSlot,
7198 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7199 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7200 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7201 lock_ReleaseMutex(&scp->mx);
7202 smb_SetSMBDataLength(outp, 0);
7204 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
7205 osi_LogSaveString(smb_logp, realPathp));
7207 cm_ReleaseUser(userp);
7208 smb_ReleaseFID(fidp);
7210 /* Can't free realPathp if we get here since
7211 fidp->NTopen_wholepathp is pointing there */
7213 /* leave scp held since we put it in fidp->scp */
7218 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
7219 * Instead, ultimately, would like to use a subroutine for common code.
7221 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7223 char *pathp, *realPathp;
7227 cm_scache_t *dscp; /* parent dir */
7228 cm_scache_t *scp; /* file to create or open */
7229 cm_scache_t *targetScp; /* if scp is a symlink */
7232 unsigned long nameLength;
7234 unsigned int requestOpLock;
7235 unsigned int requestBatchOpLock;
7236 unsigned int mustBeDir;
7237 unsigned int extendedRespRequired;
7239 unsigned int desiredAccess;
7240 #ifdef DEBUG_VERBOSE
7241 unsigned int allocSize;
7243 unsigned int shareAccess;
7244 unsigned int extAttributes;
7245 unsigned int createDisp;
7246 #ifdef DEBUG_VERBOSE
7249 unsigned int createOptions;
7250 int initialModeBits;
7251 unsigned short baseFid;
7252 smb_fid_t *baseFidp;
7254 cm_scache_t *baseDirp;
7255 unsigned short openAction;
7261 int parmOffset, dataOffset;
7267 cm_lock_data_t *ldp = NULL;
7274 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7275 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7276 parmp = inp->data + parmOffset;
7277 lparmp = (ULONG *) parmp;
7280 requestOpLock = flags & REQUEST_OPLOCK;
7281 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7282 mustBeDir = flags & OPEN_DIRECTORY;
7283 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7286 * Why all of a sudden 32-bit FID?
7287 * We will reject all bits higher than 16.
7289 if (lparmp[1] & 0xFFFF0000)
7290 return CM_ERROR_INVAL;
7291 baseFid = (unsigned short)lparmp[1];
7292 desiredAccess = lparmp[2];
7293 #ifdef DEBUG_VERBOSE
7294 allocSize = lparmp[3];
7295 #endif /* DEBUG_VERSOSE */
7296 extAttributes = lparmp[5];
7297 shareAccess = lparmp[6];
7298 createDisp = lparmp[7];
7299 createOptions = lparmp[8];
7300 #ifdef DEBUG_VERBOSE
7303 nameLength = lparmp[11];
7305 #ifdef DEBUG_VERBOSE
7306 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
7307 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
7308 osi_Log1(smb_logp,"... flags[%x]",flags);
7311 /* mustBeDir is never set; createOptions directory bit seems to be
7314 if (createOptions & FILE_DIRECTORY_FILE)
7316 else if (createOptions & FILE_NON_DIRECTORY_FILE)
7322 * compute initial mode bits based on read-only flag in
7323 * extended attributes
7325 initialModeBits = 0666;
7326 if (extAttributes & SMB_ATTR_READONLY)
7327 initialModeBits &= ~0222;
7329 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
7330 /* Sometimes path is not null-terminated, so we make a copy. */
7331 realPathp = malloc(nameLength+1);
7332 memcpy(realPathp, pathp, nameLength);
7333 realPathp[nameLength] = 0;
7334 if (smb_StoreAnsiFilenames)
7335 OemToChar(realPathp,realPathp);
7337 spacep = cm_GetSpace();
7338 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
7341 * Nothing here to handle SMB_IOCTL_FILENAME.
7342 * Will add it if necessary.
7345 #ifdef DEBUG_VERBOSE
7347 char *hexp, *asciip;
7348 asciip = (lastNamep? lastNamep : realPathp);
7349 hexp = osi_HexifyString( asciip );
7350 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
7355 userp = smb_GetUserFromVCP(vcp, inp);
7357 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
7359 return CM_ERROR_INVAL;
7364 baseDirp = cm_data.rootSCachep;
7365 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7366 if (code == CM_ERROR_TIDIPC) {
7367 /* Attempt to use a TID allocated for IPC. The client
7368 * is probably looking for DCE RPC end points which we
7369 * don't support OR it could be looking to make a DFS
7372 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
7375 cm_ReleaseUser(userp);
7376 return CM_ERROR_NOSUCHPATH;
7380 baseFidp = smb_FindFID(vcp, baseFid, 0);
7382 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
7384 cm_ReleaseUser(userp);
7385 return CM_ERROR_INVAL;
7387 baseDirp = baseFidp->scp;
7391 /* compute open mode */
7393 if (desiredAccess & DELETE)
7394 fidflags |= SMB_FID_OPENDELETE;
7395 if (desiredAccess & AFS_ACCESS_READ)
7396 fidflags |= SMB_FID_OPENREAD_LISTDIR;
7397 if (desiredAccess & AFS_ACCESS_WRITE)
7398 fidflags |= SMB_FID_OPENWRITE;
7399 if (createOptions & FILE_DELETE_ON_CLOSE)
7400 fidflags |= SMB_FID_DELONCLOSE;
7401 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7402 fidflags |= SMB_FID_SEQUENTIAL;
7403 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7404 fidflags |= SMB_FID_RANDOM;
7406 /* And the share mode */
7407 if (shareAccess & FILE_SHARE_READ)
7408 fidflags |= SMB_FID_SHARE_READ;
7409 if (shareAccess & FILE_SHARE_WRITE)
7410 fidflags |= SMB_FID_SHARE_WRITE;
7414 if ( createDisp == FILE_OPEN ||
7415 createDisp == FILE_OVERWRITE ||
7416 createDisp == FILE_OVERWRITE_IF) {
7417 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7418 userp, tidPathp, &req, &dscp);
7421 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7422 cm_ReleaseSCache(dscp);
7423 cm_ReleaseUser(userp);
7426 smb_ReleaseFID(baseFidp);
7427 if ( WANTS_DFS_PATHNAMES(inp) )
7428 return CM_ERROR_PATH_NOT_COVERED;
7430 return CM_ERROR_BADSHARENAME;
7432 #endif /* DFS_SUPPORT */
7433 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7435 if (code == CM_ERROR_NOSUCHFILE) {
7436 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7437 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7438 if (code == 0 && realDirFlag == 1) {
7439 cm_ReleaseSCache(scp);
7440 cm_ReleaseSCache(dscp);
7441 cm_ReleaseUser(userp);
7444 smb_ReleaseFID(baseFidp);
7445 return CM_ERROR_EXISTS;
7451 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7452 userp, tidPathp, &req, &scp);
7454 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7455 cm_ReleaseSCache(scp);
7456 cm_ReleaseUser(userp);
7459 smb_ReleaseFID(baseFidp);
7460 if ( WANTS_DFS_PATHNAMES(inp) )
7461 return CM_ERROR_PATH_NOT_COVERED;
7463 return CM_ERROR_BADSHARENAME;
7465 #endif /* DFS_SUPPORT */
7471 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7472 /* look up parent directory */
7474 code = cm_NameI(baseDirp, spacep->data,
7475 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7476 userp, tidPathp, &req, &dscp);
7478 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7479 cm_ReleaseSCache(dscp);
7480 cm_ReleaseUser(userp);
7483 smb_ReleaseFID(baseFidp);
7484 if ( WANTS_DFS_PATHNAMES(inp) )
7485 return CM_ERROR_PATH_NOT_COVERED;
7487 return CM_ERROR_BADSHARENAME;
7489 #endif /* DFS_SUPPORT */
7493 cm_FreeSpace(spacep);
7496 smb_ReleaseFID(baseFidp);
7499 cm_ReleaseUser(userp);
7505 lastNamep = realPathp;
7509 if (!smb_IsLegalFilename(lastNamep))
7510 return CM_ERROR_BADNTFILENAME;
7513 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
7514 code = cm_Lookup(dscp, lastNamep,
7515 CM_FLAG_FOLLOW, userp, &req, &scp);
7517 code = cm_Lookup(dscp, lastNamep,
7518 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7521 if (code && code != CM_ERROR_NOSUCHFILE) {
7522 cm_ReleaseSCache(dscp);
7523 cm_ReleaseUser(userp);
7530 smb_ReleaseFID(baseFidp);
7531 cm_FreeSpace(spacep);
7534 /* if we get here, if code is 0, the file exists and is represented by
7535 * scp. Otherwise, we have to create it. The dir may be represented
7536 * by dscp, or we may have found the file directly. If code is non-zero,
7540 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7543 cm_ReleaseSCache(dscp);
7544 cm_ReleaseSCache(scp);
7545 cm_ReleaseUser(userp);
7550 if (createDisp == FILE_CREATE) {
7551 /* oops, file shouldn't be there */
7552 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7554 cm_ReleaseSCache(dscp);
7555 cm_ReleaseSCache(scp);
7556 cm_ReleaseUser(userp);
7558 return CM_ERROR_EXISTS;
7561 if (createDisp == FILE_OVERWRITE ||
7562 createDisp == FILE_OVERWRITE_IF) {
7563 setAttr.mask = CM_ATTRMASK_LENGTH;
7564 setAttr.length.LowPart = 0;
7565 setAttr.length.HighPart = 0;
7567 /* now watch for a symlink */
7569 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7571 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7573 /* we have a more accurate file to use (the
7574 * target of the symbolic link). Otherwise,
7575 * we'll just use the symlink anyway.
7577 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7579 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7580 cm_ReleaseSCache(scp);
7582 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7585 cm_ReleaseSCache(dscp);
7587 cm_ReleaseSCache(scp);
7588 cm_ReleaseUser(userp);
7594 code = cm_SetAttr(scp, &setAttr, userp, &req);
7595 openAction = 3; /* truncated existing file */
7597 else openAction = 1; /* found existing file */
7599 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7600 /* don't create if not found */
7602 cm_ReleaseSCache(dscp);
7603 cm_ReleaseUser(userp);
7605 return CM_ERROR_NOSUCHFILE;
7607 else if (realDirFlag == 0 || realDirFlag == -1) {
7608 osi_assert(dscp != NULL);
7609 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
7610 osi_LogSaveString(smb_logp, lastNamep));
7611 openAction = 2; /* created file */
7612 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7613 setAttr.clientModTime = time(NULL);
7614 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7618 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7619 smb_NotifyChange(FILE_ACTION_ADDED,
7620 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7621 dscp, lastNamep, NULL, TRUE);
7622 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7623 /* Not an exclusive create, and someone else tried
7624 * creating it already, then we open it anyway. We
7625 * don't bother retrying after this, since if this next
7626 * fails, that means that the file was deleted after we
7627 * started this call.
7629 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7632 if (createDisp == FILE_OVERWRITE_IF) {
7633 setAttr.mask = CM_ATTRMASK_LENGTH;
7634 setAttr.length.LowPart = 0;
7635 setAttr.length.HighPart = 0;
7637 /* now watch for a symlink */
7639 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7641 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7643 /* we have a more accurate file to use (the
7644 * target of the symbolic link). Otherwise,
7645 * we'll just use the symlink anyway.
7647 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7649 cm_ReleaseSCache(scp);
7653 code = cm_SetAttr(scp, &setAttr, userp, &req);
7655 } /* lookup succeeded */
7658 /* create directory */
7659 osi_assert(dscp != NULL);
7661 "smb_ReceiveNTTranCreate creating directory %s",
7662 osi_LogSaveString(smb_logp, lastNamep));
7663 openAction = 2; /* created directory */
7664 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7665 setAttr.clientModTime = time(NULL);
7666 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
7667 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7668 smb_NotifyChange(FILE_ACTION_ADDED,
7669 FILE_NOTIFY_CHANGE_DIR_NAME,
7670 dscp, lastNamep, NULL, TRUE);
7672 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7673 /* Not an exclusive create, and someone else tried
7674 * creating it already, then we open it anyway. We
7675 * don't bother retrying after this, since if this next
7676 * fails, that means that the file was deleted after we
7677 * started this call.
7679 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7685 /* something went wrong creating or truncating the file */
7687 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7689 cm_ReleaseSCache(scp);
7690 cm_ReleaseUser(userp);
7695 /* make sure we have file vs. dir right */
7696 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7697 /* now watch for a symlink */
7699 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7701 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7703 /* we have a more accurate file to use (the
7704 * target of the symbolic link). Otherwise,
7705 * we'll just use the symlink anyway.
7707 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7710 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7711 cm_ReleaseSCache(scp);
7716 if (scp->fileType != CM_SCACHETYPE_FILE) {
7718 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7719 cm_ReleaseSCache(scp);
7720 cm_ReleaseUser(userp);
7722 return CM_ERROR_ISDIR;
7726 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7728 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7729 cm_ReleaseSCache(scp);
7730 cm_ReleaseUser(userp);
7732 return CM_ERROR_NOTDIR;
7735 /* open the file itself */
7736 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7739 /* save a reference to the user */
7741 fidp->userp = userp;
7743 /* If we are restricting sharing, we should do so with a suitable
7745 if (scp->fileType == CM_SCACHETYPE_FILE &&
7746 !(fidflags & SMB_FID_SHARE_WRITE)) {
7748 LARGE_INTEGER LOffset, LLength;
7751 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7752 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7753 LLength.HighPart = 0;
7754 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7756 /* Similar to what we do in handling NTCreateX. We get a
7757 shared lock if we are only opening the file for reading. */
7758 if ((fidflags & SMB_FID_SHARE_READ) ||
7759 !(fidflags & SMB_FID_OPENWRITE)) {
7760 sLockType = LOCKING_ANDX_SHARED_LOCK;
7765 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7767 lock_ObtainMutex(&scp->mx);
7768 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7769 lock_ReleaseMutex(&scp->mx);
7773 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7774 cm_ReleaseSCache(scp);
7775 cm_ReleaseUser(userp);
7776 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7777 smb_CloseFID(vcp, fidp, NULL, 0);
7778 smb_ReleaseFID(fidp);
7780 return CM_ERROR_SHARING_VIOLATION;
7784 /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
7786 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7788 lock_ObtainMutex(&fidp->mx);
7789 /* save a pointer to the vnode */
7791 lock_ObtainMutex(&scp->mx);
7792 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7793 lock_ReleaseMutex(&scp->mx);
7794 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
7796 fidp->flags = fidflags;
7798 /* remember if the file was newly created */
7800 fidp->flags |= SMB_FID_CREATED;
7802 /* save parent dir and pathname for deletion or change notification */
7803 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7804 fidp->flags |= SMB_FID_NTOPEN;
7805 fidp->NTopen_dscp = dscp;
7806 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
7808 fidp->NTopen_pathp = strdup(lastNamep);
7810 fidp->NTopen_wholepathp = realPathp;
7811 lock_ReleaseMutex(&fidp->mx);
7813 /* we don't need this any longer */
7815 cm_ReleaseSCache(dscp);
7817 cm_Open(scp, 0, userp);
7819 /* set inp->fid so that later read calls in same msg can find fid */
7820 inp->fid = fidp->fid;
7822 /* check whether we are required to send an extended response */
7823 if (!extendedRespRequired) {
7825 parmOffset = 8*4 + 39;
7826 parmOffset += 1; /* pad to 4 */
7827 dataOffset = parmOffset + 70;
7831 /* Total Parameter Count */
7832 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7833 /* Total Data Count */
7834 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7835 /* Parameter Count */
7836 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7837 /* Parameter Offset */
7838 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7839 /* Parameter Displacement */
7840 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7842 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7844 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7845 /* Data Displacement */
7846 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7847 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7848 smb_SetSMBDataLength(outp, 70);
7850 lock_ObtainMutex(&scp->mx);
7851 outData = smb_GetSMBData(outp, NULL);
7852 outData++; /* round to get to parmOffset */
7853 *outData = 0; outData++; /* oplock */
7854 *outData = 0; outData++; /* reserved */
7855 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7856 *((ULONG *)outData) = openAction; outData += 4;
7857 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
7858 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7859 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
7860 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
7861 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
7862 *((FILETIME *)outData) = ft; outData += 8; /* change time */
7863 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7864 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7865 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7866 *((USHORT *)outData) = 0; outData += 2; /* filetype */
7867 *((USHORT *)outData) = 0; outData += 2; /* dev state */
7868 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7869 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7870 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7871 outData += 2; /* is a dir? */
7872 lock_ReleaseMutex(&scp->mx);
7875 parmOffset = 8*4 + 39;
7876 parmOffset += 1; /* pad to 4 */
7877 dataOffset = parmOffset + 104;
7881 /* Total Parameter Count */
7882 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7883 /* Total Data Count */
7884 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7885 /* Parameter Count */
7886 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7887 /* Parameter Offset */
7888 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7889 /* Parameter Displacement */
7890 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7892 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7894 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7895 /* Data Displacement */
7896 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7897 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7898 smb_SetSMBDataLength(outp, 105);
7900 lock_ObtainMutex(&scp->mx);
7901 outData = smb_GetSMBData(outp, NULL);
7902 outData++; /* round to get to parmOffset */
7903 *outData = 0; outData++; /* oplock */
7904 *outData = 1; outData++; /* response type */
7905 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7906 *((ULONG *)outData) = openAction; outData += 4;
7907 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
7908 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7909 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
7910 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
7911 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
7912 *((FILETIME *)outData) = ft; outData += 8; /* change time */
7913 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7914 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7915 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7916 *((USHORT *)outData) = 0; outData += 2; /* filetype */
7917 *((USHORT *)outData) = 0; outData += 2; /* dev state */
7918 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7919 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7920 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7921 outData += 1; /* is a dir? */
7922 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
7923 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
7924 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
7925 lock_ReleaseMutex(&scp->mx);
7928 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
7930 cm_ReleaseUser(userp);
7931 smb_ReleaseFID(fidp);
7933 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
7934 /* leave scp held since we put it in fidp->scp */
7938 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
7941 smb_packet_t *savedPacketp;
7943 USHORT fid, watchtree;
7947 filter = smb_GetSMBParm(inp, 19) |
7948 (smb_GetSMBParm(inp, 20) << 16);
7949 fid = smb_GetSMBParm(inp, 21);
7950 watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
7952 fidp = smb_FindFID(vcp, fid, 0);
7954 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
7955 return CM_ERROR_BADFD;
7958 /* Create a copy of the Directory Watch Packet to use when sending the
7959 * notification if in the future a matching change is detected.
7961 savedPacketp = smb_CopyPacket(inp);
7963 if (savedPacketp->vcp)
7964 smb_ReleaseVC(savedPacketp->vcp);
7965 savedPacketp->vcp = vcp;
7967 /* Add the watch to the list of events to send notifications for */
7968 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7969 savedPacketp->nextp = smb_Directory_Watches;
7970 smb_Directory_Watches = savedPacketp;
7971 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7974 osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%s\"",
7975 fidp, scp, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
7976 osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
7977 filter, fid, watchtree);
7978 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
7979 osi_Log0(smb_logp, " Notify Change File Name");
7980 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
7981 osi_Log0(smb_logp, " Notify Change Directory Name");
7982 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
7983 osi_Log0(smb_logp, " Notify Change Attributes");
7984 if (filter & FILE_NOTIFY_CHANGE_SIZE)
7985 osi_Log0(smb_logp, " Notify Change Size");
7986 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
7987 osi_Log0(smb_logp, " Notify Change Last Write");
7988 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
7989 osi_Log0(smb_logp, " Notify Change Last Access");
7990 if (filter & FILE_NOTIFY_CHANGE_CREATION)
7991 osi_Log0(smb_logp, " Notify Change Creation");
7992 if (filter & FILE_NOTIFY_CHANGE_EA)
7993 osi_Log0(smb_logp, " Notify Change Extended Attributes");
7994 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
7995 osi_Log0(smb_logp, " Notify Change Security");
7996 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
7997 osi_Log0(smb_logp, " Notify Change Stream Name");
7998 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
7999 osi_Log0(smb_logp, " Notify Change Stream Size");
8000 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8001 osi_Log0(smb_logp, " Notify Change Stream Write");
8003 lock_ObtainMutex(&scp->mx);
8005 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
8007 scp->flags |= CM_SCACHEFLAG_WATCHED;
8008 lock_ReleaseMutex(&scp->mx);
8009 smb_ReleaseFID(fidp);
8011 outp->flags |= SMB_PACKETFLAG_NOSEND;
8015 unsigned char nullSecurityDesc[36] = {
8016 0x01, /* security descriptor revision */
8017 0x00, /* reserved, should be zero */
8018 0x00, 0x80, /* security descriptor control;
8019 * 0x8000 : self-relative format */
8020 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
8021 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
8022 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
8023 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
8024 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8025 /* "null SID" owner SID */
8026 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
8027 /* "null SID" group SID */
8030 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8032 int parmOffset, parmCount, dataOffset, dataCount;
8040 ULONG securityInformation;
8042 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8043 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8044 parmp = inp->data + parmOffset;
8045 sparmp = (USHORT *) parmp;
8046 lparmp = (ULONG *) parmp;
8049 securityInformation = lparmp[1];
8051 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
8052 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
8060 parmOffset = 8*4 + 39;
8061 parmOffset += 1; /* pad to 4 */
8063 dataOffset = parmOffset + parmCount;
8067 /* Total Parameter Count */
8068 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8069 /* Total Data Count */
8070 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8071 /* Parameter Count */
8072 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8073 /* Parameter Offset */
8074 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8075 /* Parameter Displacement */
8076 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8078 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8080 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8081 /* Data Displacement */
8082 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8083 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8084 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
8086 outData = smb_GetSMBData(outp, NULL);
8087 outData++; /* round to get to parmOffset */
8088 *((ULONG *)outData) = 36; outData += 4; /* length */
8090 if (maxData >= 36) {
8091 memcpy(outData, nullSecurityDesc, 36);
8095 return CM_ERROR_BUFFERTOOSMALL;
8098 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8100 unsigned short function;
8102 function = smb_GetSMBParm(inp, 18);
8104 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
8106 /* We can handle long names */
8107 if (vcp->flags & SMB_VCFLAG_USENT)
8108 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
8112 return smb_ReceiveNTTranCreate(vcp, inp, outp);
8114 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
8117 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
8120 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
8122 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
8125 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
8127 return CM_ERROR_INVAL;
8131 * smb_NotifyChange -- find relevant change notification messages and
8134 * If we don't know the file name (i.e. a callback break), filename is
8135 * NULL, and we return a zero-length list.
8137 * At present there is not a single call to smb_NotifyChange that
8138 * has the isDirectParent parameter set to FALSE.
8140 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
8141 cm_scache_t *dscp, char *filename, char *otherFilename,
8142 BOOL isDirectParent)
8144 smb_packet_t *watch, *lastWatch, *nextWatch;
8145 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
8146 char *outData, *oldOutData;
8150 BOOL twoEntries = FALSE;
8151 ULONG otherNameLen, oldParmCount = 0;
8155 /* Get ready for rename within directory */
8156 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
8158 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
8161 osi_Log4(smb_logp,"in smb_NotifyChange for file [%s] dscp [%p] notification 0x%x parent %d",
8162 osi_LogSaveString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
8164 osi_Log0(smb_logp," FILE_ACTION_NONE");
8165 if (action == FILE_ACTION_ADDED)
8166 osi_Log0(smb_logp," FILE_ACTION_ADDED");
8167 if (action == FILE_ACTION_REMOVED)
8168 osi_Log0(smb_logp," FILE_ACTION_REMOVED");
8169 if (action == FILE_ACTION_MODIFIED)
8170 osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
8171 if (action == FILE_ACTION_RENAMED_OLD_NAME)
8172 osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
8173 if (action == FILE_ACTION_RENAMED_NEW_NAME)
8174 osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
8176 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8177 watch = smb_Directory_Watches;
8179 filter = smb_GetSMBParm(watch, 19)
8180 | (smb_GetSMBParm(watch, 20) << 16);
8181 fid = smb_GetSMBParm(watch, 21);
8182 wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
8184 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
8185 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
8188 * Strange hack - bug in NT Client and NT Server that we must emulate?
8190 if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
8191 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
8193 fidp = smb_FindFID(watch->vcp, fid, 0);
8195 osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
8197 watch = watch->nextp;
8200 if (fidp->scp != dscp
8201 || (filter & notifyFilter) == 0
8202 || (!isDirectParent && !wtree)) {
8203 osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
8204 smb_ReleaseFID(fidp);
8206 watch = watch->nextp;
8209 smb_ReleaseFID(fidp);
8212 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
8213 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
8214 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8215 osi_Log0(smb_logp, " Notify Change File Name");
8216 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8217 osi_Log0(smb_logp, " Notify Change Directory Name");
8218 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8219 osi_Log0(smb_logp, " Notify Change Attributes");
8220 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8221 osi_Log0(smb_logp, " Notify Change Size");
8222 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8223 osi_Log0(smb_logp, " Notify Change Last Write");
8224 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8225 osi_Log0(smb_logp, " Notify Change Last Access");
8226 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8227 osi_Log0(smb_logp, " Notify Change Creation");
8228 if (filter & FILE_NOTIFY_CHANGE_EA)
8229 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8230 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8231 osi_Log0(smb_logp, " Notify Change Security");
8232 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8233 osi_Log0(smb_logp, " Notify Change Stream Name");
8234 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8235 osi_Log0(smb_logp, " Notify Change Stream Size");
8236 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8237 osi_Log0(smb_logp, " Notify Change Stream Write");
8239 /* A watch can only be notified once. Remove it from the list */
8240 nextWatch = watch->nextp;
8241 if (watch == smb_Directory_Watches)
8242 smb_Directory_Watches = nextWatch;
8244 lastWatch->nextp = nextWatch;
8246 /* Turn off WATCHED flag in dscp */
8247 lock_ObtainMutex(&dscp->mx);
8249 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8251 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
8252 lock_ReleaseMutex(&dscp->mx);
8254 /* Convert to response packet */
8255 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
8256 ((smb_t *) watch)->wct = 0;
8259 if (filename == NULL)
8262 nameLen = (ULONG)strlen(filename);
8263 parmCount = 3*4 + nameLen*2;
8264 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8266 otherNameLen = (ULONG)strlen(otherFilename);
8267 oldParmCount = parmCount;
8268 parmCount += 3*4 + otherNameLen*2;
8269 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8271 if (maxLen < parmCount)
8272 parmCount = 0; /* not enough room */
8274 parmOffset = 8*4 + 39;
8275 parmOffset += 1; /* pad to 4 */
8276 dataOffset = parmOffset + parmCount;
8280 /* Total Parameter Count */
8281 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8282 /* Total Data Count */
8283 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8284 /* Parameter Count */
8285 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8286 /* Parameter Offset */
8287 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
8288 /* Parameter Displacement */
8289 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8291 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8293 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
8294 /* Data Displacement */
8295 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8296 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
8297 smb_SetSMBDataLength(watch, parmCount + 1);
8299 if (parmCount != 0) {
8301 outData = smb_GetSMBData(watch, NULL);
8302 outData++; /* round to get to parmOffset */
8303 oldOutData = outData;
8304 *((DWORD *)outData) = oldParmCount; outData += 4;
8305 /* Next Entry Offset */
8306 *((DWORD *)outData) = action; outData += 4;
8308 *((DWORD *)outData) = nameLen*2; outData += 4;
8309 /* File Name Length */
8310 p = strdup(filename);
8311 if (smb_StoreAnsiFilenames)
8313 mbstowcs((WCHAR *)outData, p, nameLen);
8317 outData = oldOutData + oldParmCount;
8318 *((DWORD *)outData) = 0; outData += 4;
8319 /* Next Entry Offset */
8320 *((DWORD *)outData) = otherAction; outData += 4;
8322 *((DWORD *)outData) = otherNameLen*2;
8323 outData += 4; /* File Name Length */
8324 p = strdup(otherFilename);
8325 if (smb_StoreAnsiFilenames)
8327 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
8333 * If filename is null, we don't know the cause of the
8334 * change notification. We return zero data (see above),
8335 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
8336 * (= 0x010C). We set the error code here by hand, without
8337 * modifying wct and bcc.
8339 if (filename == NULL) {
8340 ((smb_t *) watch)->rcls = 0x0C;
8341 ((smb_t *) watch)->reh = 0x01;
8342 ((smb_t *) watch)->errLow = 0;
8343 ((smb_t *) watch)->errHigh = 0;
8344 /* Set NT Status codes flag */
8345 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8348 smb_SendPacket(watch->vcp, watch);
8349 smb_FreePacket(watch);
8352 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8355 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8357 unsigned char *replyWctp;
8358 smb_packet_t *watch, *lastWatch;
8359 USHORT fid, watchtree;
8363 osi_Log0(smb_logp, "SMB3 receive NT cancel");
8365 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8366 watch = smb_Directory_Watches;
8368 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
8369 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
8370 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
8371 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
8372 if (watch == smb_Directory_Watches)
8373 smb_Directory_Watches = watch->nextp;
8375 lastWatch->nextp = watch->nextp;
8376 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8378 /* Turn off WATCHED flag in scp */
8379 fid = smb_GetSMBParm(watch, 21);
8380 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
8382 if (vcp != watch->vcp)
8383 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
8386 fidp = smb_FindFID(vcp, fid, 0);
8388 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
8390 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
8393 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
8394 lock_ObtainMutex(&scp->mx);
8396 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8398 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
8399 lock_ReleaseMutex(&scp->mx);
8400 smb_ReleaseFID(fidp);
8402 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
8405 /* assume STATUS32; return 0xC0000120 (CANCELED) */
8406 replyWctp = watch->wctp;
8410 ((smb_t *)watch)->rcls = 0x20;
8411 ((smb_t *)watch)->reh = 0x1;
8412 ((smb_t *)watch)->errLow = 0;
8413 ((smb_t *)watch)->errHigh = 0xC0;
8414 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8415 smb_SendPacket(vcp, watch);
8416 smb_FreePacket(watch);
8420 watch = watch->nextp;
8422 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8428 * NT rename also does hard links.
8431 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
8432 #define RENAME_FLAG_HARD_LINK 0x103
8433 #define RENAME_FLAG_RENAME 0x104
8434 #define RENAME_FLAG_COPY 0x105
8436 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8438 char *oldPathp, *newPathp;
8444 attrs = smb_GetSMBParm(inp, 0);
8445 rename_type = smb_GetSMBParm(inp, 1);
8447 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
8448 osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
8449 return CM_ERROR_NOACCESS;
8452 tp = smb_GetSMBData(inp, NULL);
8453 oldPathp = smb_ParseASCIIBlock(tp, &tp);
8454 if (smb_StoreAnsiFilenames)
8455 OemToChar(oldPathp,oldPathp);
8456 newPathp = smb_ParseASCIIBlock(tp, &tp);
8457 if (smb_StoreAnsiFilenames)
8458 OemToChar(newPathp,newPathp);
8460 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
8461 osi_LogSaveString(smb_logp, oldPathp),
8462 osi_LogSaveString(smb_logp, newPathp),
8463 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
8465 if (rename_type == RENAME_FLAG_RENAME) {
8466 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
8467 } else { /* RENAME_FLAG_HARD_LINK */
8468 code = smb_Link(vcp,inp,oldPathp,newPathp);
8475 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
8478 cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
8480 smb_username_t *unp;
8483 unp = smb_FindUserByName(usern, machine, flags);
8485 lock_ObtainMutex(&unp->mx);
8486 unp->userp = cm_NewUser();
8487 lock_ReleaseMutex(&unp->mx);
8488 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
8490 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
8494 smb_ReleaseUsername(unp);