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;
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, 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, 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 for(patchp = *dirPatchespp; patchp; patchp =
3659 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3660 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3662 lock_ObtainMutex(&scp->mx);
3663 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3664 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3666 lock_ReleaseMutex(&scp->mx);
3667 cm_ReleaseSCache(scp);
3669 dptr = patchp->dptr;
3671 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3672 errors in the client. */
3673 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3674 /* 1969-12-31 23:59:59 +00 */
3675 ft.dwHighDateTime = 0x19DB200;
3676 ft.dwLowDateTime = 0x5BB78980;
3678 /* copy to Creation Time */
3679 *((FILETIME *)dptr) = ft;
3682 /* copy to Last Access Time */
3683 *((FILETIME *)dptr) = ft;
3686 /* copy to Last Write Time */
3687 *((FILETIME *)dptr) = ft;
3690 /* copy to Change Time */
3691 *((FILETIME *)dptr) = ft;
3694 /* merge in hidden attribute */
3695 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3696 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3700 /* 1969-12-31 23:59:58 +00*/
3701 dosTime = 0xEBBFBF7D;
3703 /* and copy out date */
3704 shortTemp = (dosTime>>16) & 0xffff;
3705 *((u_short *)dptr) = shortTemp;
3708 /* copy out creation time */
3709 shortTemp = dosTime & 0xffff;
3710 *((u_short *)dptr) = shortTemp;
3713 /* and copy out date */
3714 shortTemp = (dosTime>>16) & 0xffff;
3715 *((u_short *)dptr) = shortTemp;
3718 /* copy out access time */
3719 shortTemp = dosTime & 0xffff;
3720 *((u_short *)dptr) = shortTemp;
3723 /* and copy out date */
3724 shortTemp = (dosTime>>16) & 0xffff;
3725 *((u_short *)dptr) = shortTemp;
3728 /* copy out mod time */
3729 shortTemp = dosTime & 0xffff;
3730 *((u_short *)dptr) = shortTemp;
3733 /* merge in hidden (dot file) attribute */
3734 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3735 attr = SMB_ATTR_HIDDEN;
3736 *dptr++ = attr & 0xff;
3737 *dptr++ = (attr >> 8) & 0xff;
3743 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3745 /* now watch for a symlink */
3747 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3748 lock_ReleaseMutex(&scp->mx);
3749 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3751 /* we have a more accurate file to use (the
3752 * target of the symbolic link). Otherwise,
3753 * we'll just use the symlink anyway.
3755 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3757 cm_ReleaseSCache(scp);
3760 lock_ObtainMutex(&scp->mx);
3763 dptr = patchp->dptr;
3765 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3767 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3769 /* copy to Creation Time */
3770 *((FILETIME *)dptr) = ft;
3773 /* copy to Last Access Time */
3774 *((FILETIME *)dptr) = ft;
3777 /* copy to Last Write Time */
3778 *((FILETIME *)dptr) = ft;
3781 /* copy to Change Time */
3782 *((FILETIME *)dptr) = ft;
3785 /* Use length for both file length and alloc length */
3786 *((LARGE_INTEGER *)dptr) = scp->length;
3788 *((LARGE_INTEGER *)dptr) = scp->length;
3791 /* Copy attributes */
3792 lattr = smb_ExtAttributes(scp);
3793 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3794 if (lattr == SMB_ATTR_NORMAL)
3795 lattr = SMB_ATTR_DIRECTORY;
3797 lattr |= SMB_ATTR_DIRECTORY;
3799 /* merge in hidden (dot file) attribute */
3800 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3801 if (lattr == SMB_ATTR_NORMAL)
3802 lattr = SMB_ATTR_HIDDEN;
3804 lattr |= SMB_ATTR_HIDDEN;
3806 *((u_long *)dptr) = lattr;
3810 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3812 /* and copy out date */
3813 shortTemp = (dosTime>>16) & 0xffff;
3814 *((u_short *)dptr) = shortTemp;
3817 /* copy out creation time */
3818 shortTemp = dosTime & 0xffff;
3819 *((u_short *)dptr) = shortTemp;
3822 /* and copy out date */
3823 shortTemp = (dosTime>>16) & 0xffff;
3824 *((u_short *)dptr) = shortTemp;
3827 /* copy out access time */
3828 shortTemp = dosTime & 0xffff;
3829 *((u_short *)dptr) = shortTemp;
3832 /* and copy out date */
3833 shortTemp = (dosTime>>16) & 0xffff;
3834 *((u_short *)dptr) = shortTemp;
3837 /* copy out mod time */
3838 shortTemp = dosTime & 0xffff;
3839 *((u_short *)dptr) = shortTemp;
3842 /* copy out file length and alloc length,
3843 * using the same for both
3845 *((u_long *)dptr) = scp->length.LowPart;
3847 *((u_long *)dptr) = scp->length.LowPart;
3850 /* finally copy out attributes as short */
3851 attr = smb_Attributes(scp);
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 *dptr++ = attr & 0xff;
3860 *dptr++ = (attr >> 8) & 0xff;
3863 lock_ReleaseMutex(&scp->mx);
3864 cm_ReleaseSCache(scp);
3867 /* now free the patches */
3868 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3869 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3873 /* and mark the list as empty */
3874 *dirPatchespp = NULL;
3879 #ifndef USE_OLD_MATCHING
3880 // char table for case insensitive comparison
3881 char mapCaseTable[256];
3883 VOID initUpperCaseTable(VOID)
3886 for (i = 0; i < 256; ++i)
3887 mapCaseTable[i] = toupper(i);
3888 // make '"' match '.'
3889 mapCaseTable[(int)'"'] = toupper('.');
3890 // make '<' match '*'
3891 mapCaseTable[(int)'<'] = toupper('*');
3892 // make '>' match '?'
3893 mapCaseTable[(int)'>'] = toupper('?');
3896 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3898 // Note : this procedure works recursively calling itself.
3900 // PSZ pattern : string containing metacharacters.
3901 // PSZ name : file name to be compared with 'pattern'.
3903 // BOOL : TRUE/FALSE (match/mistmatch)
3906 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
3908 PSZ pename; // points to the last 'name' character
3910 pename = name + strlen(name) - 1;
3921 if (*pattern == '\0')
3923 for (p = pename; p >= name; --p) {
3924 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
3925 !casefold && (*p == *pattern)) &&
3926 szWildCardMatchFileName(pattern + 1, p + 1, casefold))
3931 if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
3932 (!casefold && *name != *pattern))
3939 /* if all we have left are wildcards, then we match */
3940 for (;*pattern; pattern++) {
3941 if (*pattern != '*' && *pattern != '?')
3947 /* do a case-folding search of the star name mask with the name in namep.
3948 * Return 1 if we match, otherwise 0.
3950 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3953 int i, j, star, qmark, casefold, retval;
3955 /* make sure we only match 8.3 names, if requested */
3956 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3959 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
3961 /* optimize the pattern:
3962 * if there is a mixture of '?' and '*',
3963 * for example the sequence "*?*?*?*"
3964 * must be turned into the form "*"
3966 newmask = (char *)malloc(strlen(maskp)+1);
3967 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3968 switch ( maskp[i] ) {
3980 } else if ( qmark ) {
3984 newmask[j++] = maskp[i];
3991 } else if ( qmark ) {
3995 newmask[j++] = '\0';
3997 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
4003 #else /* USE_OLD_MATCHING */
4004 /* do a case-folding search of the star name mask with the name in namep.
4005 * Return 1 if we match, otherwise 0.
4007 int smb_V3MatchMask(char *namep, char *maskp, int flags)
4009 unsigned char tcp1, tcp2; /* Pattern characters */
4010 unsigned char tcn1; /* Name characters */
4011 int sawDot = 0, sawStar = 0, req8dot3 = 0;
4012 char *starNamep, *starMaskp;
4013 static char nullCharp[] = {0};
4014 int casefold = flags & CM_FLAG_CASEFOLD;
4016 /* make sure we only match 8.3 names, if requested */
4017 req8dot3 = (flags & CM_FLAG_8DOT3);
4018 if (req8dot3 && !cm_Is8Dot3(namep))
4023 /* Next pattern character */
4026 /* Next name character */
4030 /* 0 - end of pattern */
4036 else if (tcp1 == '.' || tcp1 == '"') {
4046 * first dot in pattern;
4047 * must match dot or end of name
4052 else if (tcn1 == '.') {
4061 else if (tcp1 == '?') {
4062 if (tcn1 == 0 || tcn1 == '.')
4067 else if (tcp1 == '>') {
4068 if (tcn1 != 0 && tcn1 != '.')
4072 else if (tcp1 == '*' || tcp1 == '<') {
4076 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
4077 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
4092 * pattern character after '*' is not null or
4093 * period. If it is '?' or '>', we are not
4094 * going to understand it. If it is '*' or
4095 * '<', we are going to skip over it. None of
4096 * these are likely, I hope.
4098 /* skip over '*' and '<' */
4099 while (tcp2 == '*' || tcp2 == '<')
4102 /* skip over characters that don't match tcp2 */
4103 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
4104 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
4105 (!casefold && tcn1 != tcp2)))
4109 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
4112 /* Remember where we are */
4122 /* tcp1 is not a wildcard */
4123 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
4124 (!casefold && tcn1 == tcp1)) {
4129 /* if trying to match a star pattern, go back */
4131 maskp = starMaskp - 2;
4132 namep = starNamep + 1;
4141 #endif /* USE_OLD_MATCHING */
4143 /* smb_ReceiveTran2SearchDir implements both
4144 * Tran2_Find_First and Tran2_Find_Next
4146 #define TRAN2_FIND_FLAG_CLOSE_SEARCH 0x01
4147 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END 0x02
4148 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS 0x04
4149 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH 0x08
4150 #define TRAN2_FIND_FLAG_BACKUP_INTENT 0x10
4152 /* this is an optimized handler for T2SearchDir that handles the case
4153 where there are no wildcards in the search path. I.e. an
4154 application is using FindFirst(Ex) to get information about a
4155 single file or directory. It will attempt to do a single lookup.
4156 If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4157 the usual mechanism.
4159 This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4161 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4165 long code = 0, code2 = 0;
4168 smb_dirListPatch_t *dirListPatchesp;
4169 smb_dirListPatch_t *curPatchp;
4170 long orbytes; /* # of bytes in this output record */
4171 long ohbytes; /* # of bytes, except file name */
4172 long onbytes; /* # of bytes in name, incl. term. null */
4173 cm_scache_t *scp = NULL;
4174 cm_scache_t *targetscp = NULL;
4175 cm_user_t *userp = NULL;
4176 char *op; /* output data ptr */
4177 char *origOp; /* original value of op */
4178 cm_space_t *spacep; /* for pathname buffer */
4179 long maxReturnData; /* max # of return data */
4180 long maxReturnParms; /* max # of return parms */
4181 long bytesInBuffer; /* # data bytes in the output buffer */
4182 char *maskp; /* mask part of path */
4186 smb_tran2Packet_t *outp; /* response packet */
4189 char shortName[13]; /* 8.3 name if needed */
4198 osi_assert(p->opcode == 1);
4200 /* find first; obtain basic parameters from request */
4202 /* note that since we are going to failover to regular
4203 * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4204 * modify any of the input parameters here. */
4205 attribute = p->parmsp[0];
4206 maxCount = p->parmsp[1];
4207 infoLevel = p->parmsp[3];
4208 searchFlags = p->parmsp[2];
4209 pathp = ((char *) p->parmsp) + 12; /* points to path */
4211 maskp = strrchr(pathp, '\\');
4215 maskp++; /* skip over backslash */
4216 /* track if this is likely to match a lot of entries */
4218 osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%s], mask[%s]",
4219 osi_LogSaveString(smb_logp, pathp),
4220 osi_LogSaveString(smb_logp, maskp));
4222 switch ( infoLevel ) {
4223 case SMB_INFO_STANDARD:
4226 case SMB_INFO_QUERY_EA_SIZE:
4227 s = "InfoQueryEaSize";
4229 case SMB_INFO_QUERY_EAS_FROM_LIST:
4230 s = "InfoQueryEasFromList";
4232 case SMB_FIND_FILE_DIRECTORY_INFO:
4233 s = "FindFileDirectoryInfo";
4235 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4236 s = "FindFileFullDirectoryInfo";
4238 case SMB_FIND_FILE_NAMES_INFO:
4239 s = "FindFileNamesInfo";
4241 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4242 s = "FindFileBothDirectoryInfo";
4245 s = "unknownInfoLevel";
4248 osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
4251 "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4252 attribute, infoLevel, maxCount, searchFlags);
4254 if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4255 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4256 return CM_ERROR_INVAL;
4259 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4260 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4262 dirListPatchesp = NULL;
4264 maxReturnData = p->maxReturnData;
4265 maxReturnParms = 10; /* return params for findfirst, which
4266 is the only one we handle.*/
4268 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4269 if (maxReturnData > 6000)
4270 maxReturnData = 6000;
4271 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4273 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4276 osi_Log2(smb_logp, "T2SDSingle search dir count %d [%s]",
4277 maxCount, osi_LogSaveString(smb_logp, pathp));
4279 /* bail out if request looks bad */
4281 smb_FreeTran2Packet(outp);
4282 return CM_ERROR_BADSMB;
4285 userp = smb_GetTran2User(vcp, p);
4287 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
4288 smb_FreeTran2Packet(outp);
4289 return CM_ERROR_BADSMB;
4292 /* try to get the vnode for the path name next */
4293 spacep = cm_GetSpace();
4294 smb_StripLastComponent(spacep->data, NULL, pathp);
4295 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4297 cm_ReleaseUser(userp);
4298 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4299 smb_FreeTran2Packet(outp);
4303 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4304 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4305 userp, tidPathp, &req, &scp);
4306 cm_FreeSpace(spacep);
4309 cm_ReleaseUser(userp);
4310 smb_SendTran2Error(vcp, p, opx, code);
4311 smb_FreeTran2Packet(outp);
4315 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4316 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4317 cm_ReleaseSCache(scp);
4318 cm_ReleaseUser(userp);
4319 if ( WANTS_DFS_PATHNAMES(p) )
4320 code = CM_ERROR_PATH_NOT_COVERED;
4322 code = CM_ERROR_BADSHARENAME;
4323 smb_SendTran2Error(vcp, p, opx, code);
4324 smb_FreeTran2Packet(outp);
4327 #endif /* DFS_SUPPORT */
4328 osi_Log1(smb_logp,"smb_ReceiveTran2SearchDir scp 0x%p", scp);
4329 lock_ObtainMutex(&scp->mx);
4330 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
4331 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4332 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4334 lock_ReleaseMutex(&scp->mx);
4336 /* now do a single case sensitive lookup for the file in question */
4337 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
4339 /* if a case sensitive match failed, we try a case insensitive one
4341 if (code == CM_ERROR_NOSUCHFILE) {
4342 code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
4345 if (code == 0 && targetscp->fid.vnode == 0) {
4346 cm_ReleaseSCache(targetscp);
4347 code = CM_ERROR_NOSUCHFILE;
4351 /* if we can't find the directory entry, this block will
4352 return CM_ERROR_NOSUCHFILE, which we will pass on to
4353 smb_ReceiveTran2SearchDir(). */
4354 cm_ReleaseSCache(scp);
4355 cm_ReleaseUser(userp);
4356 if (code != CM_ERROR_NOSUCHFILE) {
4357 smb_SendTran2Error(vcp, p, opx, code);
4360 smb_FreeTran2Packet(outp);
4364 /* now that we have the target in sight, we proceed with filling
4365 up the return data. */
4367 op = origOp = outp->datap;
4370 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4371 /* skip over resume key */
4375 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4376 && targetscp->fid.vnode != 0
4377 && !cm_Is8Dot3(maskp)) {
4380 dfid.vnode = htonl(targetscp->fid.vnode);
4381 dfid.unique = htonl(targetscp->fid.unique);
4383 cm_Gen8Dot3NameInt(maskp, &dfid, shortName, &shortNameEnd);
4389 osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %s (%s)",
4390 htonl(targetscp->fid.vnode),
4391 htonl(targetscp->fid.unique),
4392 osi_LogSaveString(smb_logp, pathp),
4393 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4395 /* Eliminate entries that don't match requested attributes */
4396 if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
4397 smb_IsDotFile(maskp)) {
4399 code = CM_ERROR_NOSUCHFILE;
4400 osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
4405 if (!(attribute & SMB_ATTR_DIRECTORY) &&
4406 (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
4407 targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
4408 targetscp->fileType == CM_SCACHETYPE_INVALID)) {
4410 code = CM_ERROR_NOSUCHFILE;
4411 osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
4416 /* Check if the name will fit */
4417 if (infoLevel < 0x101)
4418 ohbytes = 23; /* pre-NT */
4419 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4420 ohbytes = 12; /* NT names only */
4422 ohbytes = 64; /* NT */
4424 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
4425 ohbytes += 26; /* Short name & length */
4427 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4428 ohbytes += 4; /* if resume key required */
4431 if (infoLevel != SMB_INFO_STANDARD
4432 && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
4433 && infoLevel != SMB_FIND_FILE_NAMES_INFO)
4434 ohbytes += 4; /* EASIZE */
4436 /* add header to name & term. null */
4437 onbytes = strlen(maskp);
4438 orbytes = ohbytes + onbytes + 1;
4440 /* now, we round up the record to a 4 byte alignment, and we make
4441 * sure that we have enough room here for even the aligned version
4442 * (so we don't have to worry about an * overflow when we pad
4443 * things out below). That's the reason for the alignment
4446 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4447 align = (4 - (orbytes & 3)) & 3;
4451 if (orbytes + align > maxReturnData) {
4453 /* even though this request is unlikely to succeed with a
4454 failover, we do it anyway. */
4455 code = CM_ERROR_NOSUCHFILE;
4456 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4461 /* this is one of the entries to use: it is not deleted and it
4462 * matches the star pattern we're looking for. Put out the name,
4463 * preceded by its length.
4465 /* First zero everything else */
4466 memset(origOp, 0, ohbytes);
4468 if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
4469 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4470 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4471 *((u_long *)(op + 8)) = onbytes;
4473 *((u_long *)(op + 60)) = onbytes;
4474 strcpy(origOp+ohbytes, maskp);
4475 if (smb_StoreAnsiFilenames)
4476 CharToOem(origOp+ohbytes, origOp+ohbytes);
4478 /* Short name if requested and needed */
4479 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4480 if (NeedShortName) {
4481 strcpy(op + 70, shortName);
4482 if (smb_StoreAnsiFilenames)
4483 CharToOem(op + 70, op + 70);
4484 *(op + 68) = (char)(shortNameEnd - shortName);
4488 /* NextEntryOffset and FileIndex */
4489 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4490 int entryOffset = orbytes + align;
4491 *((u_long *)op) = 0;
4492 *((u_long *)(op+4)) = 0;
4495 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4496 curPatchp = malloc(sizeof(*curPatchp));
4497 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4499 curPatchp->dptr = op;
4500 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4501 curPatchp->dptr += 8;
4503 if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
4504 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4506 curPatchp->flags = 0;
4509 curPatchp->fid.cell = targetscp->fid.cell;
4510 curPatchp->fid.volume = targetscp->fid.volume;
4511 curPatchp->fid.vnode = targetscp->fid.vnode;
4512 curPatchp->fid.unique = targetscp->fid.unique;
4515 curPatchp->dep = NULL;
4518 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4519 /* put out resume key */
4520 *((u_long *)origOp) = 0;
4523 /* Adjust byte ptr and count */
4524 origOp += orbytes; /* skip entire record */
4525 bytesInBuffer += orbytes;
4527 /* and pad the record out */
4528 while (--align >= 0) {
4533 /* apply the patches */
4534 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp, &req);
4536 outp->parmsp[0] = 0;
4537 outp->parmsp[1] = 1; /* number of names returned */
4538 outp->parmsp[2] = 1; /* end of search */
4539 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4540 outp->parmsp[4] = 0;
4542 outp->totalParms = 10; /* in bytes */
4544 outp->totalData = bytesInBuffer;
4546 osi_Log0(smb_logp, "T2SDSingle done.");
4548 if (code != CM_ERROR_NOSUCHFILE) {
4550 smb_SendTran2Error(vcp, p, opx, code);
4552 smb_SendTran2Packet(vcp, outp, opx);
4557 smb_FreeTran2Packet(outp);
4558 cm_ReleaseSCache(scp);
4559 cm_ReleaseSCache(targetscp);
4560 cm_ReleaseUser(userp);
4566 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4571 long code = 0, code2 = 0;
4575 smb_dirListPatch_t *dirListPatchesp;
4576 smb_dirListPatch_t *curPatchp;
4579 long orbytes; /* # of bytes in this output record */
4580 long ohbytes; /* # of bytes, except file name */
4581 long onbytes; /* # of bytes in name, incl. term. null */
4582 osi_hyper_t dirLength;
4583 osi_hyper_t bufferOffset;
4584 osi_hyper_t curOffset;
4586 smb_dirSearch_t *dsp;
4590 cm_pageHeader_t *pageHeaderp;
4591 cm_user_t *userp = NULL;
4594 long nextEntryCookie;
4595 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4596 char *op; /* output data ptr */
4597 char *origOp; /* original value of op */
4598 cm_space_t *spacep; /* for pathname buffer */
4599 long maxReturnData; /* max # of return data */
4600 long maxReturnParms; /* max # of return parms */
4601 long bytesInBuffer; /* # data bytes in the output buffer */
4603 char *maskp; /* mask part of path */
4607 smb_tran2Packet_t *outp; /* response packet */
4610 char shortName[13]; /* 8.3 name if needed */
4622 if (p->opcode == 1) {
4623 /* find first; obtain basic parameters from request */
4624 attribute = p->parmsp[0];
4625 maxCount = p->parmsp[1];
4626 infoLevel = p->parmsp[3];
4627 searchFlags = p->parmsp[2];
4628 pathp = ((char *) p->parmsp) + 12; /* points to path */
4629 if (smb_StoreAnsiFilenames)
4630 OemToChar(pathp,pathp);
4632 maskp = strrchr(pathp, '\\');
4636 maskp++; /* skip over backslash */
4638 /* track if this is likely to match a lot of entries */
4639 starPattern = smb_V3IsStarMask(maskp);
4641 #ifndef NOFINDFIRSTOPTIMIZE
4643 /* if this is for a single directory or file, we let the
4644 optimized routine handle it. The only error it
4645 returns is CM_ERROR_NOSUCHFILE. The */
4646 code = smb_T2SearchDirSingle(vcp, p, opx);
4648 /* we only failover if we see a CM_ERROR_NOSUCHFILE */
4649 if (code != CM_ERROR_NOSUCHFILE) {
4655 dsp = smb_NewDirSearch(1);
4656 dsp->attribute = attribute;
4657 strcpy(dsp->mask, maskp); /* and save mask */
4660 osi_assert(p->opcode == 2);
4661 /* find next; obtain basic parameters from request or open dir file */
4662 dsp = smb_FindDirSearch(p->parmsp[0]);
4663 maxCount = p->parmsp[1];
4664 infoLevel = p->parmsp[2];
4665 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4666 searchFlags = p->parmsp[5];
4668 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4669 p->parmsp[0], nextCookie);
4670 return CM_ERROR_BADFD;
4672 attribute = dsp->attribute;
4675 starPattern = 1; /* assume, since required a Find Next */
4678 switch ( infoLevel ) {
4679 case SMB_INFO_STANDARD:
4682 case SMB_INFO_QUERY_EA_SIZE:
4683 s = "InfoQueryEaSize";
4685 case SMB_INFO_QUERY_EAS_FROM_LIST:
4686 s = "InfoQueryEasFromList";
4688 case SMB_FIND_FILE_DIRECTORY_INFO:
4689 s = "FindFileDirectoryInfo";
4691 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4692 s = "FindFileFullDirectoryInfo";
4694 case SMB_FIND_FILE_NAMES_INFO:
4695 s = "FindFileNamesInfo";
4697 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4698 s = "FindFileBothDirectoryInfo";
4701 s = "unknownInfoLevel";
4704 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
4707 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4708 attribute, infoLevel, maxCount, searchFlags);
4710 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
4711 p->opcode, dsp->cookie, nextCookie);
4713 if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4714 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4715 smb_ReleaseDirSearch(dsp);
4716 return CM_ERROR_INVAL;
4719 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4720 searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS; /* no resume keys */
4722 dirListPatchesp = NULL;
4724 maxReturnData = p->maxReturnData;
4725 if (p->opcode == 1) /* find first */
4726 maxReturnParms = 10; /* bytes */
4728 maxReturnParms = 8; /* bytes */
4730 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4731 if (maxReturnData > 6000)
4732 maxReturnData = 6000;
4733 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4735 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4738 osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
4739 maxCount, osi_LogSaveString(smb_logp, pathp));
4741 /* bail out if request looks bad */
4742 if (p->opcode == 1 && !pathp) {
4743 smb_ReleaseDirSearch(dsp);
4744 smb_FreeTran2Packet(outp);
4745 return CM_ERROR_BADSMB;
4748 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
4749 dsp->cookie, nextCookie, attribute);
4751 userp = smb_GetTran2User(vcp, p);
4753 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
4754 smb_ReleaseDirSearch(dsp);
4755 smb_FreeTran2Packet(outp);
4756 return CM_ERROR_BADSMB;
4759 /* try to get the vnode for the path name next */
4760 lock_ObtainMutex(&dsp->mx);
4763 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4767 spacep = cm_GetSpace();
4768 smb_StripLastComponent(spacep->data, NULL, pathp);
4769 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4771 cm_ReleaseUser(userp);
4772 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4773 smb_FreeTran2Packet(outp);
4774 lock_ReleaseMutex(&dsp->mx);
4775 smb_DeleteDirSearch(dsp);
4776 smb_ReleaseDirSearch(dsp);
4779 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4780 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4781 userp, tidPathp, &req, &scp);
4782 cm_FreeSpace(spacep);
4785 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4786 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4787 cm_ReleaseSCache(scp);
4788 cm_ReleaseUser(userp);
4789 if ( WANTS_DFS_PATHNAMES(p) )
4790 code = CM_ERROR_PATH_NOT_COVERED;
4792 code = CM_ERROR_BADSHARENAME;
4793 smb_SendTran2Error(vcp, p, opx, code);
4794 smb_FreeTran2Packet(outp);
4795 lock_ReleaseMutex(&dsp->mx);
4796 smb_DeleteDirSearch(dsp);
4797 smb_ReleaseDirSearch(dsp);
4800 #endif /* DFS_SUPPORT */
4802 osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4803 /* we need one hold for the entry we just stored into,
4804 * and one for our own processing. When we're done
4805 * with this function, we'll drop the one for our own
4806 * processing. We held it once from the namei call,
4807 * and so we do another hold now.
4810 lock_ObtainMutex(&scp->mx);
4811 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
4812 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4813 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4814 dsp->flags |= SMB_DIRSEARCH_BULKST;
4816 lock_ReleaseMutex(&scp->mx);
4819 lock_ReleaseMutex(&dsp->mx);
4821 cm_ReleaseUser(userp);
4822 smb_FreeTran2Packet(outp);
4823 smb_DeleteDirSearch(dsp);
4824 smb_ReleaseDirSearch(dsp);
4828 /* get the directory size */
4829 lock_ObtainMutex(&scp->mx);
4830 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4831 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4833 lock_ReleaseMutex(&scp->mx);
4834 cm_ReleaseSCache(scp);
4835 cm_ReleaseUser(userp);
4836 smb_FreeTran2Packet(outp);
4837 smb_DeleteDirSearch(dsp);
4838 smb_ReleaseDirSearch(dsp);
4842 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4845 dirLength = scp->length;
4847 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4848 curOffset.HighPart = 0;
4849 curOffset.LowPart = nextCookie;
4850 origOp = outp->datap;
4858 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4859 /* skip over resume key */
4862 /* make sure that curOffset.LowPart doesn't point to the first
4863 * 32 bytes in the 2nd through last dir page, and that it doesn't
4864 * point at the first 13 32-byte chunks in the first dir page,
4865 * since those are dir and page headers, and don't contain useful
4868 temp = curOffset.LowPart & (2048-1);
4869 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4870 /* we're in the first page */
4871 if (temp < 13*32) temp = 13*32;
4874 /* we're in a later dir page */
4875 if (temp < 32) temp = 32;
4878 /* make sure the low order 5 bits are zero */
4881 /* now put temp bits back ito curOffset.LowPart */
4882 curOffset.LowPart &= ~(2048-1);
4883 curOffset.LowPart |= temp;
4885 /* check if we've passed the dir's EOF */
4886 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4887 osi_Log0(smb_logp, "T2 search dir passed eof");
4892 /* check if we've returned all the names that will fit in the
4893 * response packet; we check return count as well as the number
4894 * of bytes requested. We check the # of bytes after we find
4895 * the dir entry, since we'll need to check its size.
4897 if (returnedNames >= maxCount) {
4898 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4899 returnedNames, maxCount);
4903 /* see if we can use the bufferp we have now; compute in which
4904 * page the current offset would be, and check whether that's
4905 * the offset of the buffer we have. If not, get the buffer.
4907 thyper.HighPart = curOffset.HighPart;
4908 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4909 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4912 buf_Release(bufferp);
4915 lock_ReleaseMutex(&scp->mx);
4916 lock_ObtainRead(&scp->bufCreateLock);
4917 code = buf_Get(scp, &thyper, &bufferp);
4918 lock_ReleaseRead(&scp->bufCreateLock);
4919 lock_ObtainMutex(&dsp->mx);
4921 /* now, if we're doing a star match, do bulk fetching
4922 * of all of the status info for files in the dir.
4925 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
4928 lock_ObtainMutex(&scp->mx);
4929 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4930 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
4931 /* Don't bulk stat if risking timeout */
4932 DWORD now = GetTickCount();
4933 if (now - req.startTime > RDRtimeout) {
4934 scp->bulkStatProgress = thyper;
4935 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4936 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4938 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4941 lock_ObtainMutex(&scp->mx);
4943 lock_ReleaseMutex(&dsp->mx);
4945 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
4949 bufferOffset = thyper;
4951 /* now get the data in the cache */
4953 code = cm_SyncOp(scp, bufferp, userp, &req,
4955 CM_SCACHESYNC_NEEDCALLBACK
4956 | CM_SCACHESYNC_READ);
4958 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
4962 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4964 if (cm_HaveBuffer(scp, bufferp, 0)) {
4965 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4969 /* otherwise, load the buffer and try again */
4970 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4973 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4974 scp, bufferp, code);
4979 buf_Release(bufferp);
4983 } /* if (wrong buffer) ... */
4985 /* now we have the buffer containing the entry we're interested
4986 * in; copy it out if it represents a non-deleted entry.
4988 entryInDir = curOffset.LowPart & (2048-1);
4989 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4991 /* page header will help tell us which entries are free. Page
4992 * header can change more often than once per buffer, since
4993 * AFS 3 dir page size may be less than (but not more than)
4994 * a buffer package buffer.
4996 /* only look intra-buffer */
4997 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4998 temp &= ~(2048 - 1); /* turn off intra-page bits */
4999 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5001 /* now determine which entry we're looking at in the page.
5002 * If it is free (there's a free bitmap at the start of the
5003 * dir), we should skip these 32 bytes.
5005 slotInPage = (entryInDir & 0x7e0) >> 5;
5006 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5007 (1 << (slotInPage & 0x7)))) {
5008 /* this entry is free */
5009 numDirChunks = 1; /* only skip this guy */
5013 tp = bufferp->datap + entryInBuffer;
5014 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5016 /* while we're here, compute the next entry's location, too,
5017 * since we'll need it when writing out the cookie into the dir
5020 * XXXX Probably should do more sanity checking.
5022 numDirChunks = cm_NameEntries(dep->name, &onbytes);
5024 /* compute offset of cookie representing next entry */
5025 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5027 /* Need 8.3 name? */
5029 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
5030 && dep->fid.vnode != 0
5031 && !cm_Is8Dot3(dep->name)) {
5032 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5036 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %s (%s)",
5037 dep->fid.vnode, dep->fid.unique,
5038 osi_LogSaveString(smb_logp, dep->name),
5039 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
5041 /* When matching, we are using doing a case fold if we have a wildcard mask.
5042 * If we get a non-wildcard match, it's a lookup for a specific file.
5044 if (dep->fid.vnode != 0 &&
5045 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5047 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
5049 /* Eliminate entries that don't match requested attributes */
5050 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5051 smb_IsDotFile(dep->name)) {
5052 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5053 goto nextEntry; /* no hidden files */
5055 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5057 /* We have already done the cm_TryBulkStat above */
5058 fid.cell = scp->fid.cell;
5059 fid.volume = scp->fid.volume;
5060 fid.vnode = ntohl(dep->fid.vnode);
5061 fid.unique = ntohl(dep->fid.unique);
5062 fileType = cm_FindFileType(&fid);
5063 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5064 "has filetype %d", dep->name,
5066 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5067 fileType == CM_SCACHETYPE_DFSLINK ||
5068 fileType == CM_SCACHETYPE_INVALID)
5069 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5073 /* finally check if this name will fit */
5075 /* standard dir entry stuff */
5076 if (infoLevel < 0x101)
5077 ohbytes = 23; /* pre-NT */
5078 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
5079 ohbytes = 12; /* NT names only */
5081 ohbytes = 64; /* NT */
5083 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
5084 ohbytes += 26; /* Short name & length */
5086 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
5087 ohbytes += 4; /* if resume key required */
5090 if (infoLevel != SMB_INFO_STANDARD
5091 && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
5092 && infoLevel != SMB_FIND_FILE_NAMES_INFO)
5093 ohbytes += 4; /* EASIZE */
5095 /* add header to name & term. null */
5096 orbytes = onbytes + ohbytes + 1;
5098 /* now, we round up the record to a 4 byte alignment,
5099 * and we make sure that we have enough room here for
5100 * even the aligned version (so we don't have to worry
5101 * about an * overflow when we pad things out below).
5102 * That's the reason for the alignment arithmetic below.
5104 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5105 align = (4 - (orbytes & 3)) & 3;
5108 if (orbytes + bytesInBuffer + align > maxReturnData) {
5109 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5114 /* this is one of the entries to use: it is not deleted
5115 * and it matches the star pattern we're looking for.
5116 * Put out the name, preceded by its length.
5118 /* First zero everything else */
5119 memset(origOp, 0, ohbytes);
5121 if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
5122 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
5123 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
5124 *((u_long *)(op + 8)) = onbytes;
5126 *((u_long *)(op + 60)) = onbytes;
5127 strcpy(origOp+ohbytes, dep->name);
5128 if (smb_StoreAnsiFilenames)
5129 CharToOem(origOp+ohbytes, origOp+ohbytes);
5131 /* Short name if requested and needed */
5132 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
5133 if (NeedShortName) {
5134 strcpy(op + 70, shortName);
5135 if (smb_StoreAnsiFilenames)
5136 CharToOem(op + 70, op + 70);
5137 *(op + 68) = (char)(shortNameEnd - shortName);
5141 /* now, adjust the # of entries copied */
5144 /* NextEntryOffset and FileIndex */
5145 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
5146 int entryOffset = orbytes + align;
5147 *((u_long *)op) = entryOffset;
5148 *((u_long *)(op+4)) = nextEntryCookie;
5151 /* now we emit the attribute. This is tricky, since
5152 * we need to really stat the file to find out what
5153 * type of entry we've got. Right now, we're copying
5154 * out data from a buffer, while holding the scp
5155 * locked, so it isn't really convenient to stat
5156 * something now. We'll put in a place holder
5157 * now, and make a second pass before returning this
5158 * to get the real attributes. So, we just skip the
5159 * data for now, and adjust it later. We allocate a
5160 * patch record to make it easy to find this point
5161 * later. The replay will happen at a time when it is
5162 * safe to unlock the directory.
5164 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5165 curPatchp = malloc(sizeof(*curPatchp));
5166 osi_QAdd((osi_queue_t **) &dirListPatchesp,
5168 curPatchp->dptr = op;
5169 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5170 curPatchp->dptr += 8;
5172 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
5173 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5176 curPatchp->flags = 0;
5178 curPatchp->fid.cell = scp->fid.cell;
5179 curPatchp->fid.volume = scp->fid.volume;
5180 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
5181 curPatchp->fid.unique = ntohl(dep->fid.unique);
5184 curPatchp->dep = dep;
5187 if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5188 /* put out resume key */
5189 *((u_long *)origOp) = nextEntryCookie;
5191 /* Adjust byte ptr and count */
5192 origOp += orbytes; /* skip entire record */
5193 bytesInBuffer += orbytes;
5195 /* and pad the record out */
5196 while (--align >= 0) {
5200 } /* if we're including this name */
5201 else if (!starPattern &&
5203 dep->fid.vnode != 0 &&
5204 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
5205 /* We were looking for exact matches, but here's an inexact one*/
5210 /* and adjust curOffset to be where the new cookie is */
5211 thyper.HighPart = 0;
5212 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5213 curOffset = LargeIntegerAdd(thyper, curOffset);
5214 } /* while copying data for dir listing */
5216 /* If we didn't get a star pattern, we did an exact match during the first pass.
5217 * If there were no exact matches found, we fail over to inexact matches by
5218 * marking the query as a star pattern (matches all case permutations), and
5219 * re-running the query.
5221 if (returnedNames == 0 && !starPattern && foundInexact) {
5222 osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
5227 /* release the mutex */
5228 lock_ReleaseMutex(&scp->mx);
5230 buf_Release(bufferp);
5234 /* apply and free last set of patches; if not doing a star match, this
5235 * will be empty, but better safe (and freeing everything) than sorry.
5237 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
5240 /* now put out the final parameters */
5241 if (returnedNames == 0)
5243 if (p->opcode == 1) {
5245 outp->parmsp[0] = (unsigned short) dsp->cookie;
5246 outp->parmsp[1] = returnedNames;
5247 outp->parmsp[2] = eos;
5248 outp->parmsp[3] = 0; /* nothing wrong with EAS */
5249 outp->parmsp[4] = 0;
5250 /* don't need last name to continue
5251 * search, cookie is enough. Normally,
5252 * this is the offset of the file name
5253 * of the last entry returned.
5255 outp->totalParms = 10; /* in bytes */
5259 outp->parmsp[0] = returnedNames;
5260 outp->parmsp[1] = eos;
5261 outp->parmsp[2] = 0; /* EAS error */
5262 outp->parmsp[3] = 0; /* last name, as above */
5263 outp->totalParms = 8; /* in bytes */
5266 /* return # of bytes in the buffer */
5267 outp->totalData = bytesInBuffer;
5269 /* Return error code if unsuccessful on first request */
5270 if (code == 0 && p->opcode == 1 && returnedNames == 0)
5271 code = CM_ERROR_NOSUCHFILE;
5273 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
5274 p->opcode, dsp->cookie, returnedNames, code);
5276 /* if we're supposed to close the search after this request, or if
5277 * we're supposed to close the search if we're done, and we're done,
5278 * or if something went wrong, close the search.
5280 if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
5281 (returnedNames == 0) ||
5282 ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
5284 smb_DeleteDirSearch(dsp);
5287 smb_SendTran2Error(vcp, p, opx, code);
5289 smb_SendTran2Packet(vcp, outp, opx);
5291 smb_FreeTran2Packet(outp);
5292 smb_ReleaseDirSearch(dsp);
5293 cm_ReleaseSCache(scp);
5294 cm_ReleaseUser(userp);
5298 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5301 smb_dirSearch_t *dsp;
5303 dirHandle = smb_GetSMBParm(inp, 0);
5305 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
5307 dsp = smb_FindDirSearch(dirHandle);
5310 return CM_ERROR_BADFD;
5312 /* otherwise, we have an FD to destroy */
5313 smb_DeleteDirSearch(dsp);
5314 smb_ReleaseDirSearch(dsp);
5316 /* and return results */
5317 smb_SetSMBDataLength(outp, 0);
5322 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5324 smb_SetSMBDataLength(outp, 0);
5328 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5335 cm_scache_t *dscp; /* dir we're dealing with */
5336 cm_scache_t *scp; /* file we're creating */
5338 int initialModeBits;
5348 int parmSlot; /* which parm we're dealing with */
5357 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
5358 openFun = smb_GetSMBParm(inp, 8); /* open function */
5359 excl = ((openFun & 3) == 0);
5360 trunc = ((openFun & 3) == 2); /* truncate it */
5361 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
5362 openAction = 0; /* tracks what we did */
5364 attributes = smb_GetSMBParm(inp, 5);
5365 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
5367 /* compute initial mode bits based on read-only flag in attributes */
5368 initialModeBits = 0666;
5369 if (attributes & SMB_ATTR_READONLY)
5370 initialModeBits &= ~0222;
5372 pathp = smb_GetSMBData(inp, NULL);
5373 if (smb_StoreAnsiFilenames)
5374 OemToChar(pathp,pathp);
5376 spacep = inp->spacep;
5377 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5379 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5380 /* special case magic file name for receiving IOCTL requests
5381 * (since IOCTL calls themselves aren't getting through).
5384 osi_Log0(smb_logp, "IOCTL Open");
5387 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5388 smb_SetupIoctlFid(fidp, spacep);
5390 /* set inp->fid so that later read calls in same msg can find fid */
5391 inp->fid = fidp->fid;
5393 /* copy out remainder of the parms */
5395 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5397 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
5398 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
5399 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5400 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
5401 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
5402 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5403 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5404 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5406 /* and the final "always present" stuff */
5407 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
5408 /* next write out the "unique" ID */
5409 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
5410 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
5411 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5412 smb_SetSMBDataLength(outp, 0);
5414 /* and clean up fid reference */
5415 smb_ReleaseFID(fidp);
5419 #ifdef DEBUG_VERBOSE
5421 char *hexp, *asciip;
5422 asciip = (lastNamep ? lastNamep : pathp );
5423 hexp = osi_HexifyString(asciip);
5424 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
5428 userp = smb_GetUserFromVCP(vcp, inp);
5431 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5433 cm_ReleaseUser(userp);
5434 return CM_ERROR_NOSUCHPATH;
5436 code = cm_NameI(cm_data.rootSCachep, pathp,
5437 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5438 userp, tidPathp, &req, &scp);
5441 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5442 cm_ReleaseSCache(scp);
5443 cm_ReleaseUser(userp);
5444 if ( WANTS_DFS_PATHNAMES(inp) )
5445 return CM_ERROR_PATH_NOT_COVERED;
5447 return CM_ERROR_BADSHARENAME;
5449 #endif /* DFS_SUPPORT */
5452 code = cm_NameI(cm_data.rootSCachep, spacep->data,
5453 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5454 userp, tidPathp, &req, &dscp);
5456 cm_ReleaseUser(userp);
5461 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5462 cm_ReleaseSCache(dscp);
5463 cm_ReleaseUser(userp);
5464 if ( WANTS_DFS_PATHNAMES(inp) )
5465 return CM_ERROR_PATH_NOT_COVERED;
5467 return CM_ERROR_BADSHARENAME;
5469 #endif /* DFS_SUPPORT */
5470 /* otherwise, scp points to the parent directory. Do a lookup,
5471 * and truncate the file if we find it, otherwise we create the
5478 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
5480 if (code && code != CM_ERROR_NOSUCHFILE) {
5481 cm_ReleaseSCache(dscp);
5482 cm_ReleaseUser(userp);
5487 /* if we get here, if code is 0, the file exists and is represented by
5488 * scp. Otherwise, we have to create it. The dir may be represented
5489 * by dscp, or we may have found the file directly. If code is non-zero,
5493 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
5495 if (dscp) cm_ReleaseSCache(dscp);
5496 cm_ReleaseSCache(scp);
5497 cm_ReleaseUser(userp);
5502 /* oops, file shouldn't be there */
5504 cm_ReleaseSCache(dscp);
5505 cm_ReleaseSCache(scp);
5506 cm_ReleaseUser(userp);
5507 return CM_ERROR_EXISTS;
5511 setAttr.mask = CM_ATTRMASK_LENGTH;
5512 setAttr.length.LowPart = 0;
5513 setAttr.length.HighPart = 0;
5514 code = cm_SetAttr(scp, &setAttr, userp, &req);
5515 openAction = 3; /* truncated existing file */
5517 else openAction = 1; /* found existing file */
5519 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
5520 /* don't create if not found */
5521 if (dscp) cm_ReleaseSCache(dscp);
5522 cm_ReleaseUser(userp);
5523 return CM_ERROR_NOSUCHFILE;
5526 osi_assert(dscp != NULL);
5527 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
5528 osi_LogSaveString(smb_logp, lastNamep));
5529 openAction = 2; /* created file */
5530 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5531 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5532 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5536 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5537 smb_NotifyChange(FILE_ACTION_ADDED,
5538 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5539 dscp, lastNamep, NULL, TRUE);
5540 } else if (!excl && code == CM_ERROR_EXISTS) {
5541 /* not an exclusive create, and someone else tried
5542 * creating it already, then we open it anyway. We
5543 * don't bother retrying after this, since if this next
5544 * fails, that means that the file was deleted after we
5545 * started this call.
5547 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5551 setAttr.mask = CM_ATTRMASK_LENGTH;
5552 setAttr.length.LowPart = 0;
5553 setAttr.length.HighPart = 0;
5554 code = cm_SetAttr(scp, &setAttr, userp, &req);
5556 } /* lookup succeeded */
5560 /* we don't need this any longer */
5562 cm_ReleaseSCache(dscp);
5565 /* something went wrong creating or truncating the file */
5567 cm_ReleaseSCache(scp);
5568 cm_ReleaseUser(userp);
5572 /* make sure we're about to open a file */
5573 if (scp->fileType != CM_SCACHETYPE_FILE) {
5574 cm_ReleaseSCache(scp);
5575 cm_ReleaseUser(userp);
5576 return CM_ERROR_ISDIR;
5579 /* now all we have to do is open the file itself */
5580 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5584 lock_ObtainMutex(&fidp->mx);
5585 /* save a pointer to the vnode */
5587 lock_ObtainMutex(&scp->mx);
5588 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5589 lock_ReleaseMutex(&scp->mx);
5590 osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
5592 fidp->userp = userp;
5594 /* compute open mode */
5596 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5597 if (openMode == 1 || openMode == 2)
5598 fidp->flags |= SMB_FID_OPENWRITE;
5600 /* remember if the file was newly created */
5602 fidp->flags |= SMB_FID_CREATED;
5604 lock_ReleaseMutex(&fidp->mx);
5605 smb_ReleaseFID(fidp);
5607 cm_Open(scp, 0, userp);
5609 /* set inp->fid so that later read calls in same msg can find fid */
5610 inp->fid = fidp->fid;
5612 /* copy out remainder of the parms */
5614 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5615 lock_ObtainMutex(&scp->mx);
5617 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5618 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5619 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5620 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5621 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5622 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5623 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5624 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5625 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5627 /* and the final "always present" stuff */
5628 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5629 /* next write out the "unique" ID */
5630 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5631 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5632 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5633 lock_ReleaseMutex(&scp->mx);
5634 smb_SetSMBDataLength(outp, 0);
5636 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5638 cm_ReleaseUser(userp);
5639 /* leave scp held since we put it in fidp->scp */
5643 static void smb_GetLockParams(unsigned char LockType,
5645 unsigned int * ppid,
5646 LARGE_INTEGER * pOffset,
5647 LARGE_INTEGER * pLength)
5649 if (LockType & LOCKING_ANDX_LARGE_FILES) {
5651 *ppid = *((USHORT *) *buf);
5652 pOffset->HighPart = *((LONG *)(*buf + 4));
5653 pOffset->LowPart = *((DWORD *)(*buf + 8));
5654 pLength->HighPart = *((LONG *)(*buf + 12));
5655 pLength->LowPart = *((DWORD *)(*buf + 16));
5659 /* Not Large Files */
5660 *ppid = *((USHORT *) *buf);
5661 pOffset->HighPart = 0;
5662 pOffset->LowPart = *((DWORD *)(*buf + 2));
5663 pLength->HighPart = 0;
5664 pLength->LowPart = *((DWORD *)(*buf + 6));
5669 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5676 unsigned char LockType;
5677 unsigned short NumberOfUnlocks, NumberOfLocks;
5681 LARGE_INTEGER LOffset, LLength;
5682 smb_waitingLockRequest_t *wlRequest = NULL;
5683 cm_file_lock_t *lockp;
5691 fid = smb_GetSMBParm(inp, 2);
5692 fid = smb_ChainFID(fid, inp);
5694 fidp = smb_FindFID(vcp, fid, 0);
5696 return CM_ERROR_BADFD;
5698 lock_ObtainMutex(&fidp->mx);
5699 if (fidp->flags & SMB_FID_IOCTL) {
5700 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
5701 lock_ReleaseMutex(&fidp->mx);
5702 smb_ReleaseFID(fidp);
5703 return CM_ERROR_BADFD;
5706 osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
5708 lock_ReleaseMutex(&fidp->mx);
5710 /* set inp->fid so that later read calls in same msg can find fid */
5713 userp = smb_GetUserFromVCP(vcp, inp);
5716 lock_ObtainMutex(&scp->mx);
5717 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5718 CM_SCACHESYNC_NEEDCALLBACK
5719 | CM_SCACHESYNC_GETSTATUS
5720 | CM_SCACHESYNC_LOCK);
5722 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
5726 LockType = smb_GetSMBParm(inp, 3) & 0xff;
5727 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
5728 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
5729 NumberOfLocks = smb_GetSMBParm(inp, 7);
5731 if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
5732 (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
5734 /* We don't support these requests. Apparently, we can safely
5735 not deal with them too. */
5736 osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
5737 ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
5738 "LOCKING_ANDX_CANCEL_LOCK":
5739 "LOCKING_ANDX_CHANGE_LOCKTYPE"));
5740 /* No need to call osi_LogSaveString since these are string
5743 code = CM_ERROR_BADOP;
5748 op = smb_GetSMBData(inp, NULL);
5750 for (i=0; i<NumberOfUnlocks; i++) {
5751 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5753 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5755 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
5763 for (i=0; i<NumberOfLocks; i++) {
5764 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5766 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5768 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
5769 userp, &req, &lockp);
5771 if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
5772 (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
5774 code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
5775 userp, &req, &lockp);
5778 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
5779 smb_waitingLock_t * wLock;
5781 /* Put on waiting list */
5782 if(wlRequest == NULL) {
5786 LARGE_INTEGER tOffset, tLength;
5788 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
5790 osi_assert(wlRequest != NULL);
5792 wlRequest->vcp = vcp;
5794 wlRequest->scp = scp;
5795 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
5797 wlRequest->inp = smb_CopyPacket(inp);
5798 wlRequest->outp = smb_CopyPacket(outp);
5799 wlRequest->lockType = LockType;
5800 wlRequest->timeRemaining = Timeout;
5801 wlRequest->locks = NULL;
5803 /* The waiting lock request needs to have enough
5804 information to undo all the locks in the request.
5805 We do the following to store info about locks that
5806 have already been granted. Sure, we can get most
5807 of the info from the packet, but the packet doesn't
5808 hold the result of cm_Lock call. In practice we
5809 only receive packets with one or two locks, so we
5810 are only wasting a few bytes here and there and
5811 only for a limited period of time until the waiting
5812 lock times out or is freed. */
5814 for(opt = op_locks, j=i; j > 0; j--) {
5815 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
5817 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5819 wLock = malloc(sizeof(smb_waitingLock_t));
5821 osi_assert(wLock != NULL);
5824 wLock->LOffset = tOffset;
5825 wLock->LLength = tLength;
5826 wLock->lockp = NULL;
5827 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
5828 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5833 wLock = malloc(sizeof(smb_waitingLock_t));
5835 osi_assert(wLock != NULL);
5838 wLock->LOffset = LOffset;
5839 wLock->LLength = LLength;
5840 wLock->lockp = lockp;
5841 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
5842 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5845 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
5853 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
5860 /* Since something went wrong with the lock number i, we now
5861 have to go ahead and release any locks acquired before the
5862 failure. All locks before lock number i (of which there
5863 are i of them) have either been successful or are waiting.
5864 Either case requires calling cm_Unlock(). */
5866 /* And purge the waiting lock */
5867 if(wlRequest != NULL) {
5868 smb_waitingLock_t * wl;
5869 smb_waitingLock_t * wlNext;
5872 for(wl = wlRequest->locks; wl; wl = wlNext) {
5874 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
5876 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
5879 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
5881 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
5884 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
5889 smb_ReleaseVC(wlRequest->vcp);
5890 cm_ReleaseSCache(wlRequest->scp);
5891 smb_FreePacket(wlRequest->inp);
5892 smb_FreePacket(wlRequest->outp);
5901 if (wlRequest != NULL) {
5903 lock_ObtainWrite(&smb_globalLock);
5904 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
5906 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
5907 lock_ReleaseWrite(&smb_globalLock);
5909 /* don't send reply immediately */
5910 outp->flags |= SMB_PACKETFLAG_NOSEND;
5913 smb_SetSMBDataLength(outp, 0);
5917 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5920 lock_ReleaseMutex(&scp->mx);
5921 cm_ReleaseSCache(scp);
5922 cm_ReleaseUser(userp);
5923 smb_ReleaseFID(fidp);
5928 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5934 afs_uint32 searchTime;
5940 fid = smb_GetSMBParm(inp, 0);
5941 fid = smb_ChainFID(fid, inp);
5943 fidp = smb_FindFID(vcp, fid, 0);
5945 return CM_ERROR_BADFD;
5947 lock_ObtainMutex(&fidp->mx);
5948 if (fidp->flags & SMB_FID_IOCTL) {
5949 lock_ReleaseMutex(&fidp->mx);
5950 smb_ReleaseFID(fidp);
5951 return CM_ERROR_BADFD;
5954 osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
5956 lock_ReleaseMutex(&fidp->mx);
5958 userp = smb_GetUserFromVCP(vcp, inp);
5961 /* otherwise, stat the file */
5962 lock_ObtainMutex(&scp->mx);
5963 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5964 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5968 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5970 /* decode times. We need a search time, but the response to this
5971 * call provides the date first, not the time, as returned in the
5972 * searchTime variable. So we take the high-order bits first.
5974 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
5975 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
5976 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
5977 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
5978 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
5979 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
5980 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
5982 /* now handle file size and allocation size */
5983 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
5984 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
5985 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
5986 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
5988 /* file attribute */
5989 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
5991 /* and finalize stuff */
5992 smb_SetSMBDataLength(outp, 0);
5996 lock_ReleaseMutex(&scp->mx);
5997 cm_ReleaseSCache(scp);
5998 cm_ReleaseUser(userp);
5999 smb_ReleaseFID(fidp);
6003 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6009 afs_uint32 searchTime;
6017 fid = smb_GetSMBParm(inp, 0);
6018 fid = smb_ChainFID(fid, inp);
6020 fidp = smb_FindFID(vcp, fid, 0);
6022 return CM_ERROR_BADFD;
6024 lock_ObtainMutex(&fidp->mx);
6025 if (fidp->flags & SMB_FID_IOCTL) {
6026 lock_ReleaseMutex(&fidp->mx);
6027 smb_ReleaseFID(fidp);
6028 return CM_ERROR_BADFD;
6031 osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6033 lock_ReleaseMutex(&fidp->mx);
6035 userp = smb_GetUserFromVCP(vcp, inp);
6038 /* now prepare to call cm_setattr. This message only sets various times,
6039 * and AFS only implements mtime, and we'll set the mtime if that's
6040 * requested. The others we'll ignore.
6042 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
6044 if (searchTime != 0) {
6045 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
6047 if ( unixTime != -1 ) {
6048 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
6049 attrs.clientModTime = unixTime;
6050 code = cm_SetAttr(scp, &attrs, userp, &req);
6052 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
6054 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
6060 cm_ReleaseSCache(scp);
6061 cm_ReleaseUser(userp);
6062 smb_ReleaseFID(fidp);
6066 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6069 long count, written = 0, total_written = 0;
6076 int inDataBlockCount;
6078 fd = smb_GetSMBParm(inp, 2);
6079 count = smb_GetSMBParm(inp, 10);
6081 offset.HighPart = 0;
6082 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6084 if (*inp->wctp == 14) {
6085 /* we have a request with 64-bit file offsets */
6086 #ifdef AFS_LARGEFILES
6087 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6089 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6091 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
6092 /* we shouldn't have received this op if we didn't specify
6093 largefile support */
6094 return CM_ERROR_BADOP;
6099 op = inp->data + smb_GetSMBParm(inp, 11);
6100 inDataBlockCount = count;
6102 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
6103 fd, offset.HighPart, offset.LowPart, count);
6105 fd = smb_ChainFID(fd, inp);
6106 fidp = smb_FindFID(vcp, fd, 0);
6108 return CM_ERROR_BADFD;
6110 lock_ObtainMutex(&fidp->mx);
6111 if (fidp->flags & SMB_FID_IOCTL) {
6112 lock_ReleaseMutex(&fidp->mx);
6113 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
6114 smb_ReleaseFID(fidp);
6117 lock_ReleaseMutex(&fidp->mx);
6118 userp = smb_GetUserFromVCP(vcp, inp);
6120 /* special case: 0 bytes transferred means there is no data
6121 transferred. A slight departure from SMB_COM_WRITE where this
6122 means that we are supposed to truncate the file at this
6127 LARGE_INTEGER LOffset;
6128 LARGE_INTEGER LLength;
6130 pid = ((smb_t *) inp)->pid;
6131 key = cm_GenerateKey(vcp->vcID, pid, fd);
6133 LOffset.HighPart = offset.HighPart;
6134 LOffset.LowPart = offset.LowPart;
6135 LLength.HighPart = 0;
6136 LLength.LowPart = count;
6138 lock_ObtainMutex(&fidp->scp->mx);
6139 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6140 lock_ReleaseMutex(&fidp->scp->mx);
6147 * Work around bug in NT client
6149 * When copying a file, the NT client should first copy the data,
6150 * then copy the last write time. But sometimes the NT client does
6151 * these in the wrong order, so the data copies would inadvertently
6152 * cause the last write time to be overwritten. We try to detect this,
6153 * and don't set client mod time if we think that would go against the
6156 lock_ObtainMutex(&fidp->mx);
6157 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6158 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6159 fidp->scp->clientModTime = time(NULL);
6161 lock_ReleaseMutex(&fidp->mx);
6164 while ( code == 0 && count > 0 ) {
6166 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6168 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6170 if (code == 0 && written == 0)
6171 code = CM_ERROR_PARTIALWRITE;
6173 offset = LargeIntegerAdd(offset,
6174 ConvertLongToLargeInteger(written));
6176 total_written += written;
6182 /* slots 0 and 1 are reserved for request chaining and will be
6183 filled in when we return. */
6184 smb_SetSMBParm(outp, 2, total_written);
6185 smb_SetSMBParm(outp, 3, 0); /* reserved */
6186 smb_SetSMBParm(outp, 4, 0); /* reserved */
6187 smb_SetSMBParm(outp, 5, 0); /* reserved */
6188 smb_SetSMBDataLength(outp, 0);
6191 cm_ReleaseUser(userp);
6192 smb_ReleaseFID(fidp);
6197 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6201 long finalCount = 0;
6210 fd = smb_GetSMBParm(inp, 2);
6211 count = smb_GetSMBParm(inp, 5);
6212 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6214 if (*inp->wctp == 12) {
6215 /* a request with 64-bit offsets */
6216 #ifdef AFS_LARGEFILES
6217 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
6219 if (LargeIntegerLessThanZero(offset)) {
6220 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
6221 offset.HighPart, offset.LowPart);
6222 return CM_ERROR_BADSMB;
6225 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
6226 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
6227 return CM_ERROR_BADSMB;
6229 offset.HighPart = 0;
6233 offset.HighPart = 0;
6236 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
6237 fd, offset.HighPart, offset.LowPart, count);
6239 fd = smb_ChainFID(fd, inp);
6240 fidp = smb_FindFID(vcp, fd, 0);
6242 return CM_ERROR_BADFD;
6245 pid = ((smb_t *) inp)->pid;
6246 key = cm_GenerateKey(vcp->vcID, pid, fd);
6248 LARGE_INTEGER LOffset, LLength;
6250 LOffset.HighPart = offset.HighPart;
6251 LOffset.LowPart = offset.LowPart;
6252 LLength.HighPart = 0;
6253 LLength.LowPart = count;
6255 lock_ObtainMutex(&fidp->scp->mx);
6256 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6257 lock_ReleaseMutex(&fidp->scp->mx);
6261 smb_ReleaseFID(fidp);
6265 /* set inp->fid so that later read calls in same msg can find fid */
6268 lock_ObtainMutex(&fidp->mx);
6269 if (fidp->flags & SMB_FID_IOCTL) {
6270 lock_ReleaseMutex(&fidp->mx);
6271 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
6272 smb_ReleaseFID(fidp);
6275 lock_ReleaseMutex(&fidp->mx);
6277 userp = smb_GetUserFromVCP(vcp, inp);
6279 /* 0 and 1 are reserved for request chaining, were setup by our caller,
6280 * and will be further filled in after we return.
6282 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
6283 smb_SetSMBParm(outp, 3, 0); /* resvd */
6284 smb_SetSMBParm(outp, 4, 0); /* resvd */
6285 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
6286 /* fill in #6 when we have all the parameters' space reserved */
6287 smb_SetSMBParm(outp, 7, 0); /* resv'd */
6288 smb_SetSMBParm(outp, 8, 0); /* resv'd */
6289 smb_SetSMBParm(outp, 9, 0); /* resv'd */
6290 smb_SetSMBParm(outp, 10, 0); /* resv'd */
6291 smb_SetSMBParm(outp, 11, 0); /* reserved */
6293 /* get op ptr after putting in the parms, since otherwise we don't
6294 * know where the data really is.
6296 op = smb_GetSMBData(outp, NULL);
6298 /* now fill in offset from start of SMB header to first data byte (to op) */
6299 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
6301 /* set the packet data length the count of the # of bytes */
6302 smb_SetSMBDataLength(outp, count);
6305 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6307 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
6310 /* fix some things up */
6311 smb_SetSMBParm(outp, 5, finalCount);
6312 smb_SetSMBDataLength(outp, finalCount);
6314 cm_ReleaseUser(userp);
6315 smb_ReleaseFID(fidp);
6320 * Values for createDisp, copied from NTDDK.H
6322 #define FILE_SUPERSEDE 0 // (???)
6323 #define FILE_OPEN 1 // (open)
6324 #define FILE_CREATE 2 // (exclusive)
6325 #define FILE_OPEN_IF 3 // (non-exclusive)
6326 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
6327 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
6330 #define REQUEST_OPLOCK 2
6331 #define REQUEST_BATCH_OPLOCK 4
6332 #define OPEN_DIRECTORY 8
6333 #define EXTENDED_RESPONSE_REQUIRED 0x10
6335 /* CreateOptions field. */
6336 #define FILE_DIRECTORY_FILE 0x0001
6337 #define FILE_WRITE_THROUGH 0x0002
6338 #define FILE_SEQUENTIAL_ONLY 0x0004
6339 #define FILE_NON_DIRECTORY_FILE 0x0040
6340 #define FILE_NO_EA_KNOWLEDGE 0x0200
6341 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
6342 #define FILE_RANDOM_ACCESS 0x0800
6343 #define FILE_DELETE_ON_CLOSE 0x1000
6344 #define FILE_OPEN_BY_FILE_ID 0x2000
6346 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6348 char *pathp, *realPathp;
6352 cm_scache_t *dscp; /* parent dir */
6353 cm_scache_t *scp; /* file to create or open */
6354 cm_scache_t *targetScp; /* if scp is a symlink */
6358 unsigned short nameLength;
6360 unsigned int requestOpLock;
6361 unsigned int requestBatchOpLock;
6362 unsigned int mustBeDir;
6363 unsigned int extendedRespRequired;
6364 unsigned int treeCreate;
6366 unsigned int desiredAccess;
6367 unsigned int extAttributes;
6368 unsigned int createDisp;
6369 unsigned int createOptions;
6370 unsigned int shareAccess;
6371 int initialModeBits;
6372 unsigned short baseFid;
6373 smb_fid_t *baseFidp;
6375 cm_scache_t *baseDirp;
6376 unsigned short openAction;
6385 cm_lock_data_t *ldp = NULL;
6389 /* This code is very long and has a lot of if-then-else clauses
6390 * scp and dscp get reused frequently and we need to ensure that
6391 * we don't lose a reference. Start by ensuring that they are NULL.
6398 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
6399 flags = smb_GetSMBOffsetParm(inp, 3, 1)
6400 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
6401 requestOpLock = flags & REQUEST_OPLOCK;
6402 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6403 mustBeDir = flags & OPEN_DIRECTORY;
6404 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6407 * Why all of a sudden 32-bit FID?
6408 * We will reject all bits higher than 16.
6410 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
6411 return CM_ERROR_INVAL;
6412 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
6413 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
6414 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6415 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
6416 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
6417 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
6418 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
6419 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
6420 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
6421 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
6422 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
6424 /* mustBeDir is never set; createOptions directory bit seems to be
6427 if (createOptions & FILE_DIRECTORY_FILE)
6429 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6435 * compute initial mode bits based on read-only flag in
6436 * extended attributes
6438 initialModeBits = 0666;
6439 if (extAttributes & SMB_ATTR_READONLY)
6440 initialModeBits &= ~0222;
6442 pathp = smb_GetSMBData(inp, NULL);
6443 /* Sometimes path is not null-terminated, so we make a copy. */
6444 realPathp = malloc(nameLength+1);
6445 memcpy(realPathp, pathp, nameLength);
6446 realPathp[nameLength] = 0;
6447 if (smb_StoreAnsiFilenames)
6448 OemToChar(realPathp,realPathp);
6450 spacep = inp->spacep;
6451 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6453 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
6454 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
6455 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
6457 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
6458 /* special case magic file name for receiving IOCTL requests
6459 * (since IOCTL calls themselves aren't getting through).
6461 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6462 smb_SetupIoctlFid(fidp, spacep);
6463 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
6465 /* set inp->fid so that later read calls in same msg can find fid */
6466 inp->fid = fidp->fid;
6470 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6471 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6472 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
6474 memset(&ft, 0, sizeof(ft));
6475 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6476 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6477 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6478 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6479 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
6480 sz.HighPart = 0x7fff; sz.LowPart = 0;
6481 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
6482 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
6483 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6484 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6485 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
6486 smb_SetSMBDataLength(outp, 0);
6488 /* clean up fid reference */
6489 smb_ReleaseFID(fidp);
6494 #ifdef DEBUG_VERBOSE
6496 char *hexp, *asciip;
6497 asciip = (lastNamep? lastNamep : realPathp);
6498 hexp = osi_HexifyString( asciip );
6499 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
6504 userp = smb_GetUserFromVCP(vcp, inp);
6506 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
6508 return CM_ERROR_INVAL;
6513 baseDirp = cm_data.rootSCachep;
6514 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6515 if (code == CM_ERROR_TIDIPC) {
6516 /* Attempt to use a TID allocated for IPC. The client
6517 * is probably looking for DCE RPC end points which we
6518 * don't support OR it could be looking to make a DFS
6521 osi_Log0(smb_logp, "NTCreateX received IPC TID");
6524 cm_ReleaseUser(userp);
6525 return CM_ERROR_NOSUCHFILE;
6526 #endif /* DFS_SUPPORT */
6529 baseFidp = smb_FindFID(vcp, baseFid, 0);
6531 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
6533 cm_ReleaseUser(userp);
6534 return CM_ERROR_INVAL;
6536 baseDirp = baseFidp->scp;
6540 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
6542 /* compute open mode */
6544 if (desiredAccess & DELETE)
6545 fidflags |= SMB_FID_OPENDELETE;
6546 if (desiredAccess & AFS_ACCESS_READ)
6547 fidflags |= SMB_FID_OPENREAD_LISTDIR;
6548 if (desiredAccess & AFS_ACCESS_WRITE)
6549 fidflags |= SMB_FID_OPENWRITE;
6550 if (createOptions & FILE_DELETE_ON_CLOSE)
6551 fidflags |= SMB_FID_DELONCLOSE;
6552 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6553 fidflags |= SMB_FID_SEQUENTIAL;
6554 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6555 fidflags |= SMB_FID_RANDOM;
6557 /* and the share mode */
6558 if (shareAccess & FILE_SHARE_READ)
6559 fidflags |= SMB_FID_SHARE_READ;
6560 if (shareAccess & FILE_SHARE_WRITE)
6561 fidflags |= SMB_FID_SHARE_WRITE;
6563 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
6566 /* For an exclusive create, we want to do a case sensitive match for the last component. */
6567 if ( createDisp == FILE_CREATE ||
6568 createDisp == FILE_OVERWRITE ||
6569 createDisp == FILE_OVERWRITE_IF) {
6570 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6571 userp, tidPathp, &req, &dscp);
6574 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6575 cm_ReleaseSCache(dscp);
6576 cm_ReleaseUser(userp);
6579 smb_ReleaseFID(baseFidp);
6580 if ( WANTS_DFS_PATHNAMES(inp) )
6581 return CM_ERROR_PATH_NOT_COVERED;
6583 return CM_ERROR_BADSHARENAME;
6585 #endif /* DFS_SUPPORT */
6586 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6588 if (code == CM_ERROR_NOSUCHFILE) {
6589 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6590 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6591 if (code == 0 && realDirFlag == 1) {
6592 cm_ReleaseSCache(scp);
6593 cm_ReleaseSCache(dscp);
6594 cm_ReleaseUser(userp);
6597 smb_ReleaseFID(baseFidp);
6598 return CM_ERROR_EXISTS;
6602 /* we have both scp and dscp */
6604 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6605 userp, tidPathp, &req, &scp);
6607 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6608 cm_ReleaseSCache(scp);
6609 cm_ReleaseUser(userp);
6612 smb_ReleaseFID(baseFidp);
6613 if ( WANTS_DFS_PATHNAMES(inp) )
6614 return CM_ERROR_PATH_NOT_COVERED;
6616 return CM_ERROR_BADSHARENAME;
6618 #endif /* DFS_SUPPORT */
6619 /* we might have scp but not dscp */
6625 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6626 /* look up parent directory */
6627 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
6628 * the immediate parent. We have to work our way up realPathp until we hit something that we
6632 /* we might or might not have scp */
6638 code = cm_NameI(baseDirp, spacep->data,
6639 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6640 userp, tidPathp, &req, &dscp);
6643 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6645 cm_ReleaseSCache(scp);
6646 cm_ReleaseSCache(dscp);
6647 cm_ReleaseUser(userp);
6650 smb_ReleaseFID(baseFidp);
6651 if ( WANTS_DFS_PATHNAMES(inp) )
6652 return CM_ERROR_PATH_NOT_COVERED;
6654 return CM_ERROR_BADSHARENAME;
6656 #endif /* DFS_SUPPORT */
6659 (tp = strrchr(spacep->data,'\\')) &&
6660 (createDisp == FILE_CREATE) &&
6661 (realDirFlag == 1)) {
6664 treeStartp = realPathp + (tp - spacep->data);
6666 if (*tp && !smb_IsLegalFilename(tp)) {
6667 cm_ReleaseUser(userp);
6669 smb_ReleaseFID(baseFidp);
6672 cm_ReleaseSCache(scp);
6673 return CM_ERROR_BADNTFILENAME;
6677 } while (dscp == NULL && code == 0);
6681 /* we might have scp and we might have dscp */
6684 smb_ReleaseFID(baseFidp);
6687 osi_Log0(smb_logp,"NTCreateX parent not found");
6689 cm_ReleaseSCache(scp);
6691 cm_ReleaseSCache(dscp);
6692 cm_ReleaseUser(userp);
6697 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
6698 /* A file exists where we want a directory. */
6700 cm_ReleaseSCache(scp);
6701 cm_ReleaseSCache(dscp);
6702 cm_ReleaseUser(userp);
6704 return CM_ERROR_EXISTS;
6708 lastNamep = realPathp;
6712 if (!smb_IsLegalFilename(lastNamep)) {
6714 cm_ReleaseSCache(scp);
6716 cm_ReleaseSCache(dscp);
6717 cm_ReleaseUser(userp);
6719 return CM_ERROR_BADNTFILENAME;
6722 if (!foundscp && !treeCreate) {
6723 if ( createDisp == FILE_CREATE ||
6724 createDisp == FILE_OVERWRITE ||
6725 createDisp == FILE_OVERWRITE_IF)
6727 code = cm_Lookup(dscp, lastNamep,
6728 CM_FLAG_FOLLOW, userp, &req, &scp);
6730 code = cm_Lookup(dscp, lastNamep,
6731 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6734 if (code && code != CM_ERROR_NOSUCHFILE) {
6736 cm_ReleaseSCache(dscp);
6737 cm_ReleaseUser(userp);
6742 /* we have scp and dscp */
6744 /* we have scp but not dscp */
6746 smb_ReleaseFID(baseFidp);
6749 /* if we get here, if code is 0, the file exists and is represented by
6750 * scp. Otherwise, we have to create it. The dir may be represented
6751 * by dscp, or we may have found the file directly. If code is non-zero,
6754 if (code == 0 && !treeCreate) {
6755 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
6758 cm_ReleaseSCache(dscp);
6760 cm_ReleaseSCache(scp);
6761 cm_ReleaseUser(userp);
6766 if (createDisp == FILE_CREATE) {
6767 /* oops, file shouldn't be there */
6768 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6770 cm_ReleaseSCache(dscp);
6772 cm_ReleaseSCache(scp);
6773 cm_ReleaseUser(userp);
6775 return CM_ERROR_EXISTS;
6778 if ( createDisp == FILE_OVERWRITE ||
6779 createDisp == FILE_OVERWRITE_IF) {
6781 setAttr.mask = CM_ATTRMASK_LENGTH;
6782 setAttr.length.LowPart = 0;
6783 setAttr.length.HighPart = 0;
6784 /* now watch for a symlink */
6786 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6788 osi_assert(dscp != NULL);
6789 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6791 /* we have a more accurate file to use (the
6792 * target of the symbolic link). Otherwise,
6793 * we'll just use the symlink anyway.
6795 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6797 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6798 cm_ReleaseSCache(scp);
6800 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
6803 cm_ReleaseSCache(dscp);
6805 cm_ReleaseSCache(scp);
6806 cm_ReleaseUser(userp);
6812 code = cm_SetAttr(scp, &setAttr, userp, &req);
6813 openAction = 3; /* truncated existing file */
6816 openAction = 1; /* found existing file */
6818 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6819 /* don't create if not found */
6821 cm_ReleaseSCache(dscp);
6823 cm_ReleaseSCache(scp);
6824 cm_ReleaseUser(userp);
6826 return CM_ERROR_NOSUCHFILE;
6827 } else if (realDirFlag == 0 || realDirFlag == -1) {
6828 osi_assert(dscp != NULL);
6829 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
6830 osi_LogSaveString(smb_logp, lastNamep));
6831 openAction = 2; /* created file */
6832 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6833 setAttr.clientModTime = time(NULL);
6834 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
6837 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6838 smb_NotifyChange(FILE_ACTION_ADDED,
6839 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6840 dscp, lastNamep, NULL, TRUE);
6841 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6842 /* Not an exclusive create, and someone else tried
6843 * creating it already, then we open it anyway. We
6844 * don't bother retrying after this, since if this next
6845 * fails, that means that the file was deleted after we
6846 * started this call.
6848 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6851 if (createDisp == FILE_OVERWRITE_IF) {
6852 setAttr.mask = CM_ATTRMASK_LENGTH;
6853 setAttr.length.LowPart = 0;
6854 setAttr.length.HighPart = 0;
6856 /* now watch for a symlink */
6858 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6860 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6862 /* we have a more accurate file to use (the
6863 * target of the symbolic link). Otherwise,
6864 * we'll just use the symlink anyway.
6866 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6868 cm_ReleaseSCache(scp);
6872 code = cm_SetAttr(scp, &setAttr, userp, &req);
6874 } /* lookup succeeded */
6878 char *cp; /* This component */
6879 int clen = 0; /* length of component */
6880 cm_scache_t *tscp1, *tscp2;
6883 /* create directory */
6885 treeStartp = lastNamep;
6886 osi_assert(dscp != NULL);
6887 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
6888 osi_LogSaveString(smb_logp, treeStartp));
6889 openAction = 2; /* created directory */
6891 /* if the request is to create the root directory
6892 * it will appear as a directory name of the nul-string
6893 * and a code of CM_ERROR_NOSUCHFILE
6895 if ( !*treeStartp && code == CM_ERROR_NOSUCHFILE)
6896 code = CM_ERROR_EXISTS;
6898 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6899 setAttr.clientModTime = time(NULL);
6904 cm_HoldSCache(tscp1);
6908 tp = strchr(pp, '\\');
6911 clen = (int)strlen(cp);
6912 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
6914 clen = (int)(tp - pp);
6915 strncpy(cp,pp,clen);
6922 continue; /* the supplied path can't have consecutive slashes either , but */
6924 /* cp is the next component to be created. */
6925 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
6926 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
6927 smb_NotifyChange(FILE_ACTION_ADDED,
6928 FILE_NOTIFY_CHANGE_DIR_NAME,
6929 tscp1, cp, NULL, TRUE);
6931 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6932 /* Not an exclusive create, and someone else tried
6933 * creating it already, then we open it anyway. We
6934 * don't bother retrying after this, since if this next
6935 * fails, that means that the file was deleted after we
6936 * started this call.
6938 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
6939 userp, &req, &tscp2);
6944 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
6945 cm_ReleaseSCache(tscp1);
6946 tscp1 = tscp2; /* Newly created directory will be next parent */
6947 /* the hold is transfered to tscp1 from tscp2 */
6952 cm_ReleaseSCache(dscp);
6955 cm_ReleaseSCache(scp);
6958 * if we get here and code == 0, then scp is the last directory created, and dscp is the
6964 /* something went wrong creating or truncating the file */
6966 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6968 cm_ReleaseSCache(scp);
6970 cm_ReleaseSCache(dscp);
6971 cm_ReleaseUser(userp);
6976 /* make sure we have file vs. dir right (only applies for single component case) */
6977 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
6978 /* now watch for a symlink */
6980 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6981 cm_scache_t * targetScp = 0;
6982 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6984 /* we have a more accurate file to use (the
6985 * target of the symbolic link). Otherwise,
6986 * we'll just use the symlink anyway.
6988 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
6990 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6991 cm_ReleaseSCache(scp);
6996 if (scp->fileType != CM_SCACHETYPE_FILE) {
6998 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7000 cm_ReleaseSCache(dscp);
7001 cm_ReleaseSCache(scp);
7002 cm_ReleaseUser(userp);
7004 return CM_ERROR_ISDIR;
7008 /* (only applies to single component case) */
7009 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7011 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7012 cm_ReleaseSCache(scp);
7014 cm_ReleaseSCache(dscp);
7015 cm_ReleaseUser(userp);
7017 return CM_ERROR_NOTDIR;
7020 /* open the file itself */
7021 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7024 /* save a reference to the user */
7026 fidp->userp = userp;
7028 /* If we are restricting sharing, we should do so with a suitable
7030 if (scp->fileType == CM_SCACHETYPE_FILE &&
7031 !(fidflags & SMB_FID_SHARE_WRITE)) {
7033 LARGE_INTEGER LOffset, LLength;
7036 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7037 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7038 LLength.HighPart = 0;
7039 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7041 if (fidflags & SMB_FID_SHARE_READ) {
7042 sLockType = LOCKING_ANDX_SHARED_LOCK;
7047 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7049 lock_ObtainMutex(&scp->mx);
7050 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7051 lock_ReleaseMutex(&scp->mx);
7055 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7056 cm_ReleaseSCache(scp);
7058 cm_ReleaseSCache(dscp);
7059 cm_ReleaseUser(userp);
7060 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7061 smb_CloseFID(vcp, fidp, NULL, 0);
7062 smb_ReleaseFID(fidp);
7068 /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
7070 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7072 lock_ObtainMutex(&fidp->mx);
7073 /* save a pointer to the vnode */
7074 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
7075 lock_ObtainMutex(&scp->mx);
7076 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7077 lock_ReleaseMutex(&scp->mx);
7078 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
7080 fidp->flags = fidflags;
7082 /* remember if the file was newly created */
7084 fidp->flags |= SMB_FID_CREATED;
7086 /* save parent dir and pathname for delete or change notification */
7087 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7088 osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
7089 fidp->flags |= SMB_FID_NTOPEN;
7090 fidp->NTopen_dscp = dscp;
7092 fidp->NTopen_pathp = strdup(lastNamep);
7094 fidp->NTopen_wholepathp = realPathp;
7095 lock_ReleaseMutex(&fidp->mx);
7097 /* we don't need this any longer */
7099 cm_ReleaseSCache(dscp);
7103 cm_Open(scp, 0, userp);
7105 /* set inp->fid so that later read calls in same msg can find fid */
7106 inp->fid = fidp->fid;
7110 lock_ObtainMutex(&scp->mx);
7111 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
7112 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7113 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7114 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7115 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7116 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7117 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7118 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7119 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7121 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7122 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7123 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
7124 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
7125 smb_SetSMBParmByte(outp, parmSlot,
7126 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7127 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7128 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7129 lock_ReleaseMutex(&scp->mx);
7130 smb_SetSMBDataLength(outp, 0);
7132 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
7133 osi_LogSaveString(smb_logp, realPathp));
7135 cm_ReleaseUser(userp);
7136 smb_ReleaseFID(fidp);
7138 /* Can't free realPathp if we get here since
7139 fidp->NTopen_wholepathp is pointing there */
7141 /* leave scp held since we put it in fidp->scp */
7146 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
7147 * Instead, ultimately, would like to use a subroutine for common code.
7149 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7151 char *pathp, *realPathp;
7155 cm_scache_t *dscp; /* parent dir */
7156 cm_scache_t *scp; /* file to create or open */
7157 cm_scache_t *targetScp; /* if scp is a symlink */
7160 unsigned long nameLength;
7162 unsigned int requestOpLock;
7163 unsigned int requestBatchOpLock;
7164 unsigned int mustBeDir;
7165 unsigned int extendedRespRequired;
7167 unsigned int desiredAccess;
7168 #ifdef DEBUG_VERBOSE
7169 unsigned int allocSize;
7171 unsigned int shareAccess;
7172 unsigned int extAttributes;
7173 unsigned int createDisp;
7174 #ifdef DEBUG_VERBOSE
7177 unsigned int createOptions;
7178 int initialModeBits;
7179 unsigned short baseFid;
7180 smb_fid_t *baseFidp;
7182 cm_scache_t *baseDirp;
7183 unsigned short openAction;
7189 int parmOffset, dataOffset;
7195 cm_lock_data_t *ldp = NULL;
7202 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7203 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7204 parmp = inp->data + parmOffset;
7205 lparmp = (ULONG *) parmp;
7208 requestOpLock = flags & REQUEST_OPLOCK;
7209 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7210 mustBeDir = flags & OPEN_DIRECTORY;
7211 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7214 * Why all of a sudden 32-bit FID?
7215 * We will reject all bits higher than 16.
7217 if (lparmp[1] & 0xFFFF0000)
7218 return CM_ERROR_INVAL;
7219 baseFid = (unsigned short)lparmp[1];
7220 desiredAccess = lparmp[2];
7221 #ifdef DEBUG_VERBOSE
7222 allocSize = lparmp[3];
7223 #endif /* DEBUG_VERSOSE */
7224 extAttributes = lparmp[5];
7225 shareAccess = lparmp[6];
7226 createDisp = lparmp[7];
7227 createOptions = lparmp[8];
7228 #ifdef DEBUG_VERBOSE
7231 nameLength = lparmp[11];
7233 #ifdef DEBUG_VERBOSE
7234 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
7235 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
7236 osi_Log1(smb_logp,"... flags[%x]",flags);
7239 /* mustBeDir is never set; createOptions directory bit seems to be
7242 if (createOptions & FILE_DIRECTORY_FILE)
7244 else if (createOptions & FILE_NON_DIRECTORY_FILE)
7250 * compute initial mode bits based on read-only flag in
7251 * extended attributes
7253 initialModeBits = 0666;
7254 if (extAttributes & SMB_ATTR_READONLY)
7255 initialModeBits &= ~0222;
7257 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
7258 /* Sometimes path is not null-terminated, so we make a copy. */
7259 realPathp = malloc(nameLength+1);
7260 memcpy(realPathp, pathp, nameLength);
7261 realPathp[nameLength] = 0;
7262 if (smb_StoreAnsiFilenames)
7263 OemToChar(realPathp,realPathp);
7265 spacep = cm_GetSpace();
7266 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
7269 * Nothing here to handle SMB_IOCTL_FILENAME.
7270 * Will add it if necessary.
7273 #ifdef DEBUG_VERBOSE
7275 char *hexp, *asciip;
7276 asciip = (lastNamep? lastNamep : realPathp);
7277 hexp = osi_HexifyString( asciip );
7278 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
7283 userp = smb_GetUserFromVCP(vcp, inp);
7285 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
7287 return CM_ERROR_INVAL;
7292 baseDirp = cm_data.rootSCachep;
7293 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7294 if (code == CM_ERROR_TIDIPC) {
7295 /* Attempt to use a TID allocated for IPC. The client
7296 * is probably looking for DCE RPC end points which we
7297 * don't support OR it could be looking to make a DFS
7300 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
7303 cm_ReleaseUser(userp);
7304 return CM_ERROR_NOSUCHPATH;
7308 baseFidp = smb_FindFID(vcp, baseFid, 0);
7310 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
7312 cm_ReleaseUser(userp);
7313 return CM_ERROR_INVAL;
7315 baseDirp = baseFidp->scp;
7319 /* compute open mode */
7321 if (desiredAccess & DELETE)
7322 fidflags |= SMB_FID_OPENDELETE;
7323 if (desiredAccess & AFS_ACCESS_READ)
7324 fidflags |= SMB_FID_OPENREAD_LISTDIR;
7325 if (desiredAccess & AFS_ACCESS_WRITE)
7326 fidflags |= SMB_FID_OPENWRITE;
7327 if (createOptions & FILE_DELETE_ON_CLOSE)
7328 fidflags |= SMB_FID_DELONCLOSE;
7329 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7330 fidflags |= SMB_FID_SEQUENTIAL;
7331 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7332 fidflags |= SMB_FID_RANDOM;
7334 /* And the share mode */
7335 if (shareAccess & FILE_SHARE_READ)
7336 fidflags |= SMB_FID_SHARE_READ;
7337 if (shareAccess & FILE_SHARE_WRITE)
7338 fidflags |= SMB_FID_SHARE_WRITE;
7342 if ( createDisp == FILE_OPEN ||
7343 createDisp == FILE_OVERWRITE ||
7344 createDisp == FILE_OVERWRITE_IF) {
7345 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7346 userp, tidPathp, &req, &dscp);
7349 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7350 cm_ReleaseSCache(dscp);
7351 cm_ReleaseUser(userp);
7354 smb_ReleaseFID(baseFidp);
7355 if ( WANTS_DFS_PATHNAMES(inp) )
7356 return CM_ERROR_PATH_NOT_COVERED;
7358 return CM_ERROR_BADSHARENAME;
7360 #endif /* DFS_SUPPORT */
7361 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7363 if (code == CM_ERROR_NOSUCHFILE) {
7364 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7365 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7366 if (code == 0 && realDirFlag == 1) {
7367 cm_ReleaseSCache(scp);
7368 cm_ReleaseSCache(dscp);
7369 cm_ReleaseUser(userp);
7372 smb_ReleaseFID(baseFidp);
7373 return CM_ERROR_EXISTS;
7379 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7380 userp, tidPathp, &req, &scp);
7382 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7383 cm_ReleaseSCache(scp);
7384 cm_ReleaseUser(userp);
7387 smb_ReleaseFID(baseFidp);
7388 if ( WANTS_DFS_PATHNAMES(inp) )
7389 return CM_ERROR_PATH_NOT_COVERED;
7391 return CM_ERROR_BADSHARENAME;
7393 #endif /* DFS_SUPPORT */
7399 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7400 /* look up parent directory */
7402 code = cm_NameI(baseDirp, spacep->data,
7403 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7404 userp, tidPathp, &req, &dscp);
7406 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7407 cm_ReleaseSCache(dscp);
7408 cm_ReleaseUser(userp);
7411 smb_ReleaseFID(baseFidp);
7412 if ( WANTS_DFS_PATHNAMES(inp) )
7413 return CM_ERROR_PATH_NOT_COVERED;
7415 return CM_ERROR_BADSHARENAME;
7417 #endif /* DFS_SUPPORT */
7421 cm_FreeSpace(spacep);
7424 smb_ReleaseFID(baseFidp);
7427 cm_ReleaseUser(userp);
7433 lastNamep = realPathp;
7437 if (!smb_IsLegalFilename(lastNamep))
7438 return CM_ERROR_BADNTFILENAME;
7441 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
7442 code = cm_Lookup(dscp, lastNamep,
7443 CM_FLAG_FOLLOW, userp, &req, &scp);
7445 code = cm_Lookup(dscp, lastNamep,
7446 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7449 if (code && code != CM_ERROR_NOSUCHFILE) {
7450 cm_ReleaseSCache(dscp);
7451 cm_ReleaseUser(userp);
7458 smb_ReleaseFID(baseFidp);
7459 cm_FreeSpace(spacep);
7462 /* if we get here, if code is 0, the file exists and is represented by
7463 * scp. Otherwise, we have to create it. The dir may be represented
7464 * by dscp, or we may have found the file directly. If code is non-zero,
7468 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7471 cm_ReleaseSCache(dscp);
7472 cm_ReleaseSCache(scp);
7473 cm_ReleaseUser(userp);
7478 if (createDisp == FILE_CREATE) {
7479 /* oops, file shouldn't be there */
7480 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7482 cm_ReleaseSCache(dscp);
7483 cm_ReleaseSCache(scp);
7484 cm_ReleaseUser(userp);
7486 return CM_ERROR_EXISTS;
7489 if (createDisp == FILE_OVERWRITE ||
7490 createDisp == FILE_OVERWRITE_IF) {
7491 setAttr.mask = CM_ATTRMASK_LENGTH;
7492 setAttr.length.LowPart = 0;
7493 setAttr.length.HighPart = 0;
7495 /* now watch for a symlink */
7497 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7499 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7501 /* we have a more accurate file to use (the
7502 * target of the symbolic link). Otherwise,
7503 * we'll just use the symlink anyway.
7505 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7507 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7508 cm_ReleaseSCache(scp);
7510 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7513 cm_ReleaseSCache(dscp);
7515 cm_ReleaseSCache(scp);
7516 cm_ReleaseUser(userp);
7522 code = cm_SetAttr(scp, &setAttr, userp, &req);
7523 openAction = 3; /* truncated existing file */
7525 else openAction = 1; /* found existing file */
7527 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7528 /* don't create if not found */
7530 cm_ReleaseSCache(dscp);
7531 cm_ReleaseUser(userp);
7533 return CM_ERROR_NOSUCHFILE;
7535 else if (realDirFlag == 0 || realDirFlag == -1) {
7536 osi_assert(dscp != NULL);
7537 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
7538 osi_LogSaveString(smb_logp, lastNamep));
7539 openAction = 2; /* created file */
7540 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7541 setAttr.clientModTime = time(NULL);
7542 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7546 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7547 smb_NotifyChange(FILE_ACTION_ADDED,
7548 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7549 dscp, lastNamep, NULL, TRUE);
7550 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7551 /* Not an exclusive create, and someone else tried
7552 * creating it already, then we open it anyway. We
7553 * don't bother retrying after this, since if this next
7554 * fails, that means that the file was deleted after we
7555 * started this call.
7557 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7560 if (createDisp == FILE_OVERWRITE_IF) {
7561 setAttr.mask = CM_ATTRMASK_LENGTH;
7562 setAttr.length.LowPart = 0;
7563 setAttr.length.HighPart = 0;
7565 /* now watch for a symlink */
7567 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7569 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7571 /* we have a more accurate file to use (the
7572 * target of the symbolic link). Otherwise,
7573 * we'll just use the symlink anyway.
7575 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7577 cm_ReleaseSCache(scp);
7581 code = cm_SetAttr(scp, &setAttr, userp, &req);
7583 } /* lookup succeeded */
7586 /* create directory */
7587 osi_assert(dscp != NULL);
7589 "smb_ReceiveNTTranCreate creating directory %s",
7590 osi_LogSaveString(smb_logp, lastNamep));
7591 openAction = 2; /* created directory */
7592 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7593 setAttr.clientModTime = time(NULL);
7594 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
7595 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7596 smb_NotifyChange(FILE_ACTION_ADDED,
7597 FILE_NOTIFY_CHANGE_DIR_NAME,
7598 dscp, lastNamep, NULL, TRUE);
7600 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7601 /* Not an exclusive create, and someone else tried
7602 * creating it already, then we open it anyway. We
7603 * don't bother retrying after this, since if this next
7604 * fails, that means that the file was deleted after we
7605 * started this call.
7607 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7613 /* something went wrong creating or truncating the file */
7615 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7617 cm_ReleaseSCache(scp);
7618 cm_ReleaseUser(userp);
7623 /* make sure we have file vs. dir right */
7624 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7625 /* now watch for a symlink */
7627 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7629 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7631 /* we have a more accurate file to use (the
7632 * target of the symbolic link). Otherwise,
7633 * we'll just use the symlink anyway.
7635 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7638 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7639 cm_ReleaseSCache(scp);
7644 if (scp->fileType != CM_SCACHETYPE_FILE) {
7646 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7647 cm_ReleaseSCache(scp);
7648 cm_ReleaseUser(userp);
7650 return CM_ERROR_ISDIR;
7654 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7656 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7657 cm_ReleaseSCache(scp);
7658 cm_ReleaseUser(userp);
7660 return CM_ERROR_NOTDIR;
7663 /* open the file itself */
7664 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7667 /* save a reference to the user */
7669 fidp->userp = userp;
7671 /* If we are restricting sharing, we should do so with a suitable
7673 if (scp->fileType == CM_SCACHETYPE_FILE &&
7674 !(fidflags & SMB_FID_SHARE_WRITE)) {
7676 LARGE_INTEGER LOffset, LLength;
7679 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7680 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7681 LLength.HighPart = 0;
7682 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7684 if (fidflags & SMB_FID_SHARE_READ) {
7685 sLockType = LOCKING_ANDX_SHARED_LOCK;
7690 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7692 lock_ObtainMutex(&scp->mx);
7693 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7694 lock_ReleaseMutex(&scp->mx);
7698 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7699 cm_ReleaseSCache(scp);
7700 cm_ReleaseUser(userp);
7701 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7702 smb_CloseFID(vcp, fidp, NULL, 0);
7703 smb_ReleaseFID(fidp);
7705 return CM_ERROR_SHARING_VIOLATION;
7709 /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
7711 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7713 lock_ObtainMutex(&fidp->mx);
7714 /* save a pointer to the vnode */
7716 lock_ObtainMutex(&scp->mx);
7717 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7718 lock_ReleaseMutex(&scp->mx);
7719 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
7721 fidp->flags = fidflags;
7723 /* remember if the file was newly created */
7725 fidp->flags |= SMB_FID_CREATED;
7727 /* save parent dir and pathname for deletion or change notification */
7728 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7729 fidp->flags |= SMB_FID_NTOPEN;
7730 fidp->NTopen_dscp = dscp;
7731 osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
7733 fidp->NTopen_pathp = strdup(lastNamep);
7735 fidp->NTopen_wholepathp = realPathp;
7736 lock_ReleaseMutex(&fidp->mx);
7738 /* we don't need this any longer */
7740 cm_ReleaseSCache(dscp);
7742 cm_Open(scp, 0, userp);
7744 /* set inp->fid so that later read calls in same msg can find fid */
7745 inp->fid = fidp->fid;
7747 /* check whether we are required to send an extended response */
7748 if (!extendedRespRequired) {
7750 parmOffset = 8*4 + 39;
7751 parmOffset += 1; /* pad to 4 */
7752 dataOffset = parmOffset + 70;
7756 /* Total Parameter Count */
7757 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7758 /* Total Data Count */
7759 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7760 /* Parameter Count */
7761 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7762 /* Parameter Offset */
7763 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7764 /* Parameter Displacement */
7765 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7767 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7769 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7770 /* Data Displacement */
7771 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7772 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7773 smb_SetSMBDataLength(outp, 70);
7775 lock_ObtainMutex(&scp->mx);
7776 outData = smb_GetSMBData(outp, NULL);
7777 outData++; /* round to get to parmOffset */
7778 *outData = 0; outData++; /* oplock */
7779 *outData = 0; outData++; /* reserved */
7780 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7781 *((ULONG *)outData) = openAction; outData += 4;
7782 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
7783 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7784 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
7785 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
7786 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
7787 *((FILETIME *)outData) = ft; outData += 8; /* change time */
7788 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7789 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7790 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7791 *((USHORT *)outData) = 0; outData += 2; /* filetype */
7792 *((USHORT *)outData) = 0; outData += 2; /* dev state */
7793 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7794 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7795 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7796 outData += 2; /* is a dir? */
7797 lock_ReleaseMutex(&scp->mx);
7800 parmOffset = 8*4 + 39;
7801 parmOffset += 1; /* pad to 4 */
7802 dataOffset = parmOffset + 104;
7806 /* Total Parameter Count */
7807 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7808 /* Total Data Count */
7809 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7810 /* Parameter Count */
7811 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7812 /* Parameter Offset */
7813 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7814 /* Parameter Displacement */
7815 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7817 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7819 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7820 /* Data Displacement */
7821 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7822 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7823 smb_SetSMBDataLength(outp, 105);
7825 lock_ObtainMutex(&scp->mx);
7826 outData = smb_GetSMBData(outp, NULL);
7827 outData++; /* round to get to parmOffset */
7828 *outData = 0; outData++; /* oplock */
7829 *outData = 1; outData++; /* response type */
7830 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7831 *((ULONG *)outData) = openAction; outData += 4;
7832 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
7833 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7834 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
7835 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
7836 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
7837 *((FILETIME *)outData) = ft; outData += 8; /* change time */
7838 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7839 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7840 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7841 *((USHORT *)outData) = 0; outData += 2; /* filetype */
7842 *((USHORT *)outData) = 0; outData += 2; /* dev state */
7843 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7844 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7845 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7846 outData += 1; /* is a dir? */
7847 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
7848 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
7849 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
7850 lock_ReleaseMutex(&scp->mx);
7853 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
7855 cm_ReleaseUser(userp);
7856 smb_ReleaseFID(fidp);
7858 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
7859 /* leave scp held since we put it in fidp->scp */
7863 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
7866 smb_packet_t *savedPacketp;
7868 USHORT fid, watchtree;
7872 filter = smb_GetSMBParm(inp, 19) |
7873 (smb_GetSMBParm(inp, 20) << 16);
7874 fid = smb_GetSMBParm(inp, 21);
7875 watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
7877 fidp = smb_FindFID(vcp, fid, 0);
7879 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
7880 return CM_ERROR_BADFD;
7883 /* Create a copy of the Directory Watch Packet to use when sending the
7884 * notification if in the future a matching change is detected.
7886 savedPacketp = smb_CopyPacket(inp);
7888 if (savedPacketp->vcp)
7889 smb_ReleaseVC(savedPacketp->vcp);
7890 savedPacketp->vcp = vcp;
7892 /* Add the watch to the list of events to send notifications for */
7893 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7894 savedPacketp->nextp = smb_Directory_Watches;
7895 smb_Directory_Watches = savedPacketp;
7896 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7899 osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%s\"",
7900 fidp, scp, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
7901 osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
7902 filter, fid, watchtree);
7903 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
7904 osi_Log0(smb_logp, " Notify Change File Name");
7905 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
7906 osi_Log0(smb_logp, " Notify Change Directory Name");
7907 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
7908 osi_Log0(smb_logp, " Notify Change Attributes");
7909 if (filter & FILE_NOTIFY_CHANGE_SIZE)
7910 osi_Log0(smb_logp, " Notify Change Size");
7911 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
7912 osi_Log0(smb_logp, " Notify Change Last Write");
7913 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
7914 osi_Log0(smb_logp, " Notify Change Last Access");
7915 if (filter & FILE_NOTIFY_CHANGE_CREATION)
7916 osi_Log0(smb_logp, " Notify Change Creation");
7917 if (filter & FILE_NOTIFY_CHANGE_EA)
7918 osi_Log0(smb_logp, " Notify Change Extended Attributes");
7919 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
7920 osi_Log0(smb_logp, " Notify Change Security");
7921 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
7922 osi_Log0(smb_logp, " Notify Change Stream Name");
7923 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
7924 osi_Log0(smb_logp, " Notify Change Stream Size");
7925 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
7926 osi_Log0(smb_logp, " Notify Change Stream Write");
7928 lock_ObtainMutex(&scp->mx);
7930 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
7932 scp->flags |= CM_SCACHEFLAG_WATCHED;
7933 lock_ReleaseMutex(&scp->mx);
7934 smb_ReleaseFID(fidp);
7936 outp->flags |= SMB_PACKETFLAG_NOSEND;
7940 unsigned char nullSecurityDesc[36] = {
7941 0x01, /* security descriptor revision */
7942 0x00, /* reserved, should be zero */
7943 0x00, 0x80, /* security descriptor control;
7944 * 0x8000 : self-relative format */
7945 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
7946 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
7947 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
7948 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
7949 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7950 /* "null SID" owner SID */
7951 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
7952 /* "null SID" group SID */
7955 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7957 int parmOffset, parmCount, dataOffset, dataCount;
7965 ULONG securityInformation;
7967 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7968 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7969 parmp = inp->data + parmOffset;
7970 sparmp = (USHORT *) parmp;
7971 lparmp = (ULONG *) parmp;
7974 securityInformation = lparmp[1];
7976 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
7977 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
7985 parmOffset = 8*4 + 39;
7986 parmOffset += 1; /* pad to 4 */
7988 dataOffset = parmOffset + parmCount;
7992 /* Total Parameter Count */
7993 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
7994 /* Total Data Count */
7995 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
7996 /* Parameter Count */
7997 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
7998 /* Parameter Offset */
7999 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8000 /* Parameter Displacement */
8001 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8003 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8005 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8006 /* Data Displacement */
8007 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8008 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
8009 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
8011 outData = smb_GetSMBData(outp, NULL);
8012 outData++; /* round to get to parmOffset */
8013 *((ULONG *)outData) = 36; outData += 4; /* length */
8015 if (maxData >= 36) {
8016 memcpy(outData, nullSecurityDesc, 36);
8020 return CM_ERROR_BUFFERTOOSMALL;
8023 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8025 unsigned short function;
8027 function = smb_GetSMBParm(inp, 18);
8029 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
8031 /* We can handle long names */
8032 if (vcp->flags & SMB_VCFLAG_USENT)
8033 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
8037 return smb_ReceiveNTTranCreate(vcp, inp, outp);
8039 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
8042 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
8045 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
8047 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
8050 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
8052 return CM_ERROR_INVAL;
8056 * smb_NotifyChange -- find relevant change notification messages and
8059 * If we don't know the file name (i.e. a callback break), filename is
8060 * NULL, and we return a zero-length list.
8062 * At present there is not a single call to smb_NotifyChange that
8063 * has the isDirectParent parameter set to FALSE.
8065 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
8066 cm_scache_t *dscp, char *filename, char *otherFilename,
8067 BOOL isDirectParent)
8069 smb_packet_t *watch, *lastWatch, *nextWatch;
8070 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
8071 char *outData, *oldOutData;
8075 BOOL twoEntries = FALSE;
8076 ULONG otherNameLen, oldParmCount = 0;
8080 /* Get ready for rename within directory */
8081 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
8083 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
8086 osi_Log4(smb_logp,"in smb_NotifyChange for file [%s] dscp [%p] notification 0x%x parent %d",
8087 osi_LogSaveString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
8089 osi_Log0(smb_logp," FILE_ACTION_NONE");
8090 if (action == FILE_ACTION_ADDED)
8091 osi_Log0(smb_logp," FILE_ACTION_ADDED");
8092 if (action == FILE_ACTION_REMOVED)
8093 osi_Log0(smb_logp," FILE_ACTION_REMOVED");
8094 if (action == FILE_ACTION_MODIFIED)
8095 osi_Log0(smb_logp," FILE_ACTION_MODIFIED");
8096 if (action == FILE_ACTION_RENAMED_OLD_NAME)
8097 osi_Log0(smb_logp," FILE_ACTION_RENAMED_OLD_NAME");
8098 if (action == FILE_ACTION_RENAMED_NEW_NAME)
8099 osi_Log0(smb_logp," FILE_ACTION_RENAMED_NEW_NAME");
8101 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8102 watch = smb_Directory_Watches;
8104 filter = smb_GetSMBParm(watch, 19)
8105 | (smb_GetSMBParm(watch, 20) << 16);
8106 fid = smb_GetSMBParm(watch, 21);
8107 wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
8109 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
8110 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
8113 * Strange hack - bug in NT Client and NT Server that we must emulate?
8115 if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
8116 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
8118 fidp = smb_FindFID(watch->vcp, fid, 0);
8120 osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
8122 watch = watch->nextp;
8125 if (fidp->scp != dscp
8126 || (filter & notifyFilter) == 0
8127 || (!isDirectParent && !wtree)) {
8128 osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
8129 smb_ReleaseFID(fidp);
8131 watch = watch->nextp;
8134 smb_ReleaseFID(fidp);
8137 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
8138 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
8139 if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8140 osi_Log0(smb_logp, " Notify Change File Name");
8141 if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8142 osi_Log0(smb_logp, " Notify Change Directory Name");
8143 if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8144 osi_Log0(smb_logp, " Notify Change Attributes");
8145 if (filter & FILE_NOTIFY_CHANGE_SIZE)
8146 osi_Log0(smb_logp, " Notify Change Size");
8147 if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8148 osi_Log0(smb_logp, " Notify Change Last Write");
8149 if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8150 osi_Log0(smb_logp, " Notify Change Last Access");
8151 if (filter & FILE_NOTIFY_CHANGE_CREATION)
8152 osi_Log0(smb_logp, " Notify Change Creation");
8153 if (filter & FILE_NOTIFY_CHANGE_EA)
8154 osi_Log0(smb_logp, " Notify Change Extended Attributes");
8155 if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8156 osi_Log0(smb_logp, " Notify Change Security");
8157 if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8158 osi_Log0(smb_logp, " Notify Change Stream Name");
8159 if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8160 osi_Log0(smb_logp, " Notify Change Stream Size");
8161 if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8162 osi_Log0(smb_logp, " Notify Change Stream Write");
8164 /* A watch can only be notified once. Remove it from the list */
8165 nextWatch = watch->nextp;
8166 if (watch == smb_Directory_Watches)
8167 smb_Directory_Watches = nextWatch;
8169 lastWatch->nextp = nextWatch;
8171 /* Turn off WATCHED flag in dscp */
8172 lock_ObtainMutex(&dscp->mx);
8174 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8176 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
8177 lock_ReleaseMutex(&dscp->mx);
8179 /* Convert to response packet */
8180 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
8181 ((smb_t *) watch)->wct = 0;
8184 if (filename == NULL)
8187 nameLen = (ULONG)strlen(filename);
8188 parmCount = 3*4 + nameLen*2;
8189 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8191 otherNameLen = (ULONG)strlen(otherFilename);
8192 oldParmCount = parmCount;
8193 parmCount += 3*4 + otherNameLen*2;
8194 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8196 if (maxLen < parmCount)
8197 parmCount = 0; /* not enough room */
8199 parmOffset = 8*4 + 39;
8200 parmOffset += 1; /* pad to 4 */
8201 dataOffset = parmOffset + parmCount;
8205 /* Total Parameter Count */
8206 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8207 /* Total Data Count */
8208 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8209 /* Parameter Count */
8210 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8211 /* Parameter Offset */
8212 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
8213 /* Parameter Displacement */
8214 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8216 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8218 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
8219 /* Data Displacement */
8220 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8221 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
8222 smb_SetSMBDataLength(watch, parmCount + 1);
8224 if (parmCount != 0) {
8226 outData = smb_GetSMBData(watch, NULL);
8227 outData++; /* round to get to parmOffset */
8228 oldOutData = outData;
8229 *((DWORD *)outData) = oldParmCount; outData += 4;
8230 /* Next Entry Offset */
8231 *((DWORD *)outData) = action; outData += 4;
8233 *((DWORD *)outData) = nameLen*2; outData += 4;
8234 /* File Name Length */
8235 p = strdup(filename);
8236 if (smb_StoreAnsiFilenames)
8238 mbstowcs((WCHAR *)outData, p, nameLen);
8242 outData = oldOutData + oldParmCount;
8243 *((DWORD *)outData) = 0; outData += 4;
8244 /* Next Entry Offset */
8245 *((DWORD *)outData) = otherAction; outData += 4;
8247 *((DWORD *)outData) = otherNameLen*2;
8248 outData += 4; /* File Name Length */
8249 p = strdup(otherFilename);
8250 if (smb_StoreAnsiFilenames)
8252 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
8258 * If filename is null, we don't know the cause of the
8259 * change notification. We return zero data (see above),
8260 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
8261 * (= 0x010C). We set the error code here by hand, without
8262 * modifying wct and bcc.
8264 if (filename == NULL) {
8265 ((smb_t *) watch)->rcls = 0x0C;
8266 ((smb_t *) watch)->reh = 0x01;
8267 ((smb_t *) watch)->errLow = 0;
8268 ((smb_t *) watch)->errHigh = 0;
8269 /* Set NT Status codes flag */
8270 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8273 smb_SendPacket(watch->vcp, watch);
8274 smb_FreePacket(watch);
8277 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8280 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8282 unsigned char *replyWctp;
8283 smb_packet_t *watch, *lastWatch;
8284 USHORT fid, watchtree;
8288 osi_Log0(smb_logp, "SMB3 receive NT cancel");
8290 lock_ObtainMutex(&smb_Dir_Watch_Lock);
8291 watch = smb_Directory_Watches;
8293 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
8294 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
8295 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
8296 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
8297 if (watch == smb_Directory_Watches)
8298 smb_Directory_Watches = watch->nextp;
8300 lastWatch->nextp = watch->nextp;
8301 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8303 /* Turn off WATCHED flag in scp */
8304 fid = smb_GetSMBParm(watch, 21);
8305 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
8307 if (vcp != watch->vcp)
8308 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
8311 fidp = smb_FindFID(vcp, fid, 0);
8313 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
8315 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
8318 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
8319 lock_ObtainMutex(&scp->mx);
8321 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8323 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
8324 lock_ReleaseMutex(&scp->mx);
8325 smb_ReleaseFID(fidp);
8327 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
8330 /* assume STATUS32; return 0xC0000120 (CANCELED) */
8331 replyWctp = watch->wctp;
8335 ((smb_t *)watch)->rcls = 0x20;
8336 ((smb_t *)watch)->reh = 0x1;
8337 ((smb_t *)watch)->errLow = 0;
8338 ((smb_t *)watch)->errHigh = 0xC0;
8339 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8340 smb_SendPacket(vcp, watch);
8341 smb_FreePacket(watch);
8345 watch = watch->nextp;
8347 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8353 * NT rename also does hard links.
8356 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
8357 #define RENAME_FLAG_HARD_LINK 0x103
8358 #define RENAME_FLAG_RENAME 0x104
8359 #define RENAME_FLAG_COPY 0x105
8361 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8363 char *oldPathp, *newPathp;
8369 attrs = smb_GetSMBParm(inp, 0);
8370 rename_type = smb_GetSMBParm(inp, 1);
8372 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
8373 osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
8374 return CM_ERROR_NOACCESS;
8377 tp = smb_GetSMBData(inp, NULL);
8378 oldPathp = smb_ParseASCIIBlock(tp, &tp);
8379 if (smb_StoreAnsiFilenames)
8380 OemToChar(oldPathp,oldPathp);
8381 newPathp = smb_ParseASCIIBlock(tp, &tp);
8382 if (smb_StoreAnsiFilenames)
8383 OemToChar(newPathp,newPathp);
8385 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
8386 osi_LogSaveString(smb_logp, oldPathp),
8387 osi_LogSaveString(smb_logp, newPathp),
8388 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
8390 if (rename_type == RENAME_FLAG_RENAME) {
8391 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
8392 } else { /* RENAME_FLAG_HARD_LINK */
8393 code = smb_Link(vcp,inp,oldPathp,newPathp);
8400 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
8403 cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
8405 smb_username_t *unp;
8408 unp = smb_FindUserByName(usern, machine, flags);
8410 lock_ObtainMutex(&unp->mx);
8411 unp->userp = cm_NewUser();
8412 lock_ReleaseMutex(&unp->mx);
8413 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
8415 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
8419 smb_ReleaseUsername(unp);