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];
1506 smb_rap_share_list_t rootShares;
1511 tp = p->parmsp + 1; /* skip over function number (always 0) */
1512 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1513 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1517 if (infoLevel != 1) {
1518 return CM_ERROR_INVAL;
1521 /* first figure out how many shares there are */
1522 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1523 KEY_QUERY_VALUE, &hkParam);
1524 if (rv == ERROR_SUCCESS) {
1525 len = sizeof(allSubmount);
1526 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1527 (BYTE *) &allSubmount, &len);
1528 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1531 RegCloseKey (hkParam);
1534 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1535 0, KEY_QUERY_VALUE, &hkSubmount);
1536 if (rv == ERROR_SUCCESS) {
1537 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1538 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1539 if (rv != ERROR_SUCCESS)
1545 /* fetch the root shares */
1546 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1547 rootShares.cShare = 0;
1548 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1552 userp = smb_GetTran2User(vcp,p);
1554 thyper.HighPart = 0;
1557 cm_HoldSCache(cm_data.rootSCachep);
1558 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1559 cm_ReleaseSCache(cm_data.rootSCachep);
1561 cm_ReleaseUser(userp);
1563 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1565 #define REMARK_LEN 1
1566 outParmsTotal = 8; /* 4 dwords */
1567 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1568 if(outDataTotal > bufsize) {
1569 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1570 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1573 nSharesRet = nShares;
1576 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1578 /* now for the submounts */
1579 shares = (smb_rap_share_info_1_t *) outp->datap;
1580 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1582 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1585 strcpy( shares[cshare].shi1_netname, "all" );
1586 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1587 /* type and pad are zero already */
1593 for (i=0; i < nRegShares && cshare < nSharesRet; i++) {
1594 len = sizeof(thisShare);
1595 rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1596 if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1597 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1598 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1599 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1604 nShares--; /* uncount key */
1607 RegCloseKey(hkSubmount);
1610 nonrootShares = cshare;
1612 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1613 /* in case there are collisions with submounts, submounts have higher priority */
1614 for (j=0; j < nonrootShares; j++)
1615 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1618 if (j < nonrootShares) {
1619 nShares--; /* uncount */
1623 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1624 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1629 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1630 outp->parmsp[1] = 0;
1631 outp->parmsp[2] = cshare;
1632 outp->parmsp[3] = nShares;
1634 outp->totalData = (int)(cstrp - outp->datap);
1635 outp->totalParms = outParmsTotal;
1637 smb_SendTran2Packet(vcp, outp, op);
1638 smb_FreeTran2Packet(outp);
1640 free(rootShares.shares);
1645 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1647 smb_tran2Packet_t *outp;
1648 unsigned short * tp;
1650 BOOL shareFound = FALSE;
1651 unsigned short infoLevel;
1652 unsigned short bufsize;
1662 tp = p->parmsp + 1; /* skip over function number (always 1) */
1663 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1664 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1665 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1672 totalData = sizeof(smb_rap_share_info_0_t);
1673 else if(infoLevel == SMB_INFO_STANDARD)
1674 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1675 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1676 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1678 return CM_ERROR_INVAL;
1680 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1682 if(!stricmp(shareName,"all") || !strcmp(shareName,"*.")) {
1683 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1684 KEY_QUERY_VALUE, &hkParam);
1685 if (rv == ERROR_SUCCESS) {
1686 len = sizeof(allSubmount);
1687 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1688 (BYTE *) &allSubmount, &len);
1689 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1692 RegCloseKey (hkParam);
1699 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1700 KEY_QUERY_VALUE, &hkSubmount);
1701 if (rv == ERROR_SUCCESS) {
1702 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1703 if (rv == ERROR_SUCCESS) {
1706 RegCloseKey(hkSubmount);
1711 smb_FreeTran2Packet(outp);
1712 return CM_ERROR_BADSHARENAME;
1715 memset(outp->datap, 0, totalData);
1717 outp->parmsp[0] = 0;
1718 outp->parmsp[1] = 0;
1719 outp->parmsp[2] = totalData;
1721 if (infoLevel == 0) {
1722 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1723 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1724 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1725 } else if(infoLevel == SMB_INFO_STANDARD) {
1726 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1727 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1728 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1729 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1730 /* type and pad are already zero */
1731 } else { /* infoLevel==2 */
1732 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1733 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1734 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1735 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1736 info->shi2_permissions = ACCESS_ALL;
1737 info->shi2_max_uses = (unsigned short) -1;
1738 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
1741 outp->totalData = totalData;
1742 outp->totalParms = totalParam;
1744 smb_SendTran2Packet(vcp, outp, op);
1745 smb_FreeTran2Packet(outp);
1750 typedef struct smb_rap_wksta_info_10 {
1751 DWORD wki10_computername; /*char *wki10_computername;*/
1752 DWORD wki10_username; /* char *wki10_username; */
1753 DWORD wki10_langroup; /* char *wki10_langroup;*/
1754 unsigned char wki10_ver_major;
1755 unsigned char wki10_ver_minor;
1756 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1757 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1758 } smb_rap_wksta_info_10_t;
1761 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1763 smb_tran2Packet_t *outp;
1767 unsigned short * tp;
1770 smb_rap_wksta_info_10_t * info;
1774 tp = p->parmsp + 1; /* Skip over function number */
1775 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1776 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1780 if (infoLevel != 10) {
1781 return CM_ERROR_INVAL;
1787 totalData = sizeof(*info) + /* info */
1788 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1789 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1790 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1791 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1792 1; /* wki10_oth_domains (null)*/
1794 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1796 memset(outp->parmsp,0,totalParams);
1797 memset(outp->datap,0,totalData);
1799 info = (smb_rap_wksta_info_10_t *) outp->datap;
1800 cstrp = (char *) (info + 1);
1802 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1803 strcpy(cstrp, smb_localNamep);
1804 cstrp += strlen(cstrp) + 1;
1806 info->wki10_username = (DWORD) (cstrp - outp->datap);
1807 uidp = smb_FindUID(vcp, p->uid, 0);
1809 lock_ObtainMutex(&uidp->mx);
1810 if(uidp->unp && uidp->unp->name)
1811 strcpy(cstrp, uidp->unp->name);
1812 lock_ReleaseMutex(&uidp->mx);
1813 smb_ReleaseUID(uidp);
1815 cstrp += strlen(cstrp) + 1;
1817 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1818 strcpy(cstrp, "WORKGROUP");
1819 cstrp += strlen(cstrp) + 1;
1821 /* TODO: Not sure what values these should take, but these work */
1822 info->wki10_ver_major = 5;
1823 info->wki10_ver_minor = 1;
1825 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1826 strcpy(cstrp, smb_ServerDomainName);
1827 cstrp += strlen(cstrp) + 1;
1829 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1830 cstrp ++; /* no other domains */
1832 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1833 outp->parmsp[2] = outp->totalData;
1834 outp->totalParms = totalParams;
1836 smb_SendTran2Packet(vcp,outp,op);
1837 smb_FreeTran2Packet(outp);
1842 typedef struct smb_rap_server_info_0 {
1844 } smb_rap_server_info_0_t;
1846 typedef struct smb_rap_server_info_1 {
1848 char sv1_version_major;
1849 char sv1_version_minor;
1850 unsigned long sv1_type;
1851 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1852 } smb_rap_server_info_1_t;
1854 char smb_ServerComment[] = "OpenAFS Client";
1855 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1857 #define SMB_SV_TYPE_SERVER 0x00000002L
1858 #define SMB_SV_TYPE_NT 0x00001000L
1859 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1861 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1863 smb_tran2Packet_t *outp;
1867 unsigned short * tp;
1870 smb_rap_server_info_0_t * info0;
1871 smb_rap_server_info_1_t * info1;
1874 tp = p->parmsp + 1; /* Skip over function number */
1875 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1876 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1880 if (infoLevel != 0 && infoLevel != 1) {
1881 return CM_ERROR_INVAL;
1887 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1888 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1890 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1892 memset(outp->parmsp,0,totalParams);
1893 memset(outp->datap,0,totalData);
1895 if (infoLevel == 0) {
1896 info0 = (smb_rap_server_info_0_t *) outp->datap;
1897 cstrp = (char *) (info0 + 1);
1898 strcpy(info0->sv0_name, "AFS");
1899 } else { /* infoLevel == SMB_INFO_STANDARD */
1900 info1 = (smb_rap_server_info_1_t *) outp->datap;
1901 cstrp = (char *) (info1 + 1);
1902 strcpy(info1->sv1_name, "AFS");
1905 SMB_SV_TYPE_SERVER |
1907 SMB_SV_TYPE_SERVER_NT;
1909 info1->sv1_version_major = 5;
1910 info1->sv1_version_minor = 1;
1911 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1913 strcpy(cstrp, smb_ServerComment);
1915 cstrp += smb_ServerCommentLen;
1918 totalData = (DWORD)(cstrp - outp->datap);
1919 outp->totalData = min(bufsize,totalData); /* actual data size */
1920 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1921 outp->parmsp[2] = totalData;
1922 outp->totalParms = totalParams;
1924 smb_SendTran2Packet(vcp,outp,op);
1925 smb_FreeTran2Packet(outp);
1930 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1932 smb_tran2Packet_t *asp;
1944 /* We sometimes see 0 word count. What to do? */
1945 if (*inp->wctp == 0) {
1946 osi_Log0(smb_logp, "Transaction2 word count = 0");
1948 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1951 smb_SetSMBDataLength(outp, 0);
1952 smb_SendPacket(vcp, outp);
1956 totalParms = smb_GetSMBParm(inp, 0);
1957 totalData = smb_GetSMBParm(inp, 1);
1959 firstPacket = (inp->inCom == 0x32);
1961 /* find the packet we're reassembling */
1962 lock_ObtainWrite(&smb_globalLock);
1963 asp = smb_FindTran2Packet(vcp, inp);
1965 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1967 lock_ReleaseWrite(&smb_globalLock);
1969 /* now merge in this latest packet; start by looking up offsets */
1971 parmDisp = dataDisp = 0;
1972 parmOffset = smb_GetSMBParm(inp, 10);
1973 dataOffset = smb_GetSMBParm(inp, 12);
1974 parmCount = smb_GetSMBParm(inp, 9);
1975 dataCount = smb_GetSMBParm(inp, 11);
1976 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1977 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1979 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1980 totalData, dataCount, asp->maxReturnData);
1983 parmDisp = smb_GetSMBParm(inp, 4);
1984 parmOffset = smb_GetSMBParm(inp, 3);
1985 dataDisp = smb_GetSMBParm(inp, 7);
1986 dataOffset = smb_GetSMBParm(inp, 6);
1987 parmCount = smb_GetSMBParm(inp, 2);
1988 dataCount = smb_GetSMBParm(inp, 5);
1990 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1991 parmCount, dataCount);
1994 /* now copy the parms and data */
1995 if ( asp->totalParms > 0 && parmCount != 0 )
1997 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1999 if ( asp->totalData > 0 && dataCount != 0 ) {
2000 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2003 /* account for new bytes */
2004 asp->curData += dataCount;
2005 asp->curParms += parmCount;
2007 /* finally, if we're done, remove the packet from the queue and dispatch it */
2008 if (asp->totalParms > 0 &&
2009 asp->curParms > 0 &&
2010 asp->totalData <= asp->curData &&
2011 asp->totalParms <= asp->curParms) {
2012 /* we've received it all */
2013 lock_ObtainWrite(&smb_globalLock);
2014 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2015 lock_ReleaseWrite(&smb_globalLock);
2017 /* now dispatch it */
2018 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2019 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2020 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2023 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2024 code = CM_ERROR_BADOP;
2027 /* if an error is returned, we're supposed to send an error packet,
2028 * otherwise the dispatched function already did the data sending.
2029 * We give dispatched proc the responsibility since it knows how much
2030 * space to allocate.
2033 smb_SendTran2Error(vcp, asp, outp, code);
2036 /* free the input tran 2 packet */
2037 smb_FreeTran2Packet(asp);
2039 else if (firstPacket) {
2040 /* the first packet in a multi-packet request, we need to send an
2041 * ack to get more data.
2043 smb_SetSMBDataLength(outp, 0);
2044 smb_SendPacket(vcp, outp);
2050 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2053 smb_tran2Packet_t *outp;
2058 cm_scache_t *dscp; /* dir we're dealing with */
2059 cm_scache_t *scp; /* file we're creating */
2061 int initialModeBits;
2071 int parmSlot; /* which parm we're dealing with */
2072 long returnEALength;
2081 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2082 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2084 openFun = p->parmsp[6]; /* open function */
2085 excl = ((openFun & 3) == 0);
2086 trunc = ((openFun & 3) == 2); /* truncate it */
2087 openMode = (p->parmsp[1] & 0x7);
2088 openAction = 0; /* tracks what we did */
2090 attributes = p->parmsp[3];
2091 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2093 /* compute initial mode bits based on read-only flag in attributes */
2094 initialModeBits = 0666;
2095 if (attributes & SMB_ATTR_READONLY)
2096 initialModeBits &= ~0222;
2098 pathp = (char *) (&p->parmsp[14]);
2099 if (smb_StoreAnsiFilenames)
2100 OemToChar(pathp,pathp);
2102 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2104 spacep = cm_GetSpace();
2105 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2107 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2108 /* special case magic file name for receiving IOCTL requests
2109 * (since IOCTL calls themselves aren't getting through).
2111 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2112 smb_SetupIoctlFid(fidp, spacep);
2114 /* copy out remainder of the parms */
2116 outp->parmsp[parmSlot++] = fidp->fid;
2118 outp->parmsp[parmSlot++] = 0; /* attrs */
2119 outp->parmsp[parmSlot++] = 0; /* mod time */
2120 outp->parmsp[parmSlot++] = 0;
2121 outp->parmsp[parmSlot++] = 0; /* len */
2122 outp->parmsp[parmSlot++] = 0x7fff;
2123 outp->parmsp[parmSlot++] = openMode;
2124 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2125 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2127 /* and the final "always present" stuff */
2128 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2129 /* next write out the "unique" ID */
2130 outp->parmsp[parmSlot++] = 0x1234;
2131 outp->parmsp[parmSlot++] = 0x5678;
2132 outp->parmsp[parmSlot++] = 0;
2133 if (returnEALength) {
2134 outp->parmsp[parmSlot++] = 0;
2135 outp->parmsp[parmSlot++] = 0;
2138 outp->totalData = 0;
2139 outp->totalParms = parmSlot * 2;
2141 smb_SendTran2Packet(vcp, outp, op);
2143 smb_FreeTran2Packet(outp);
2145 /* and clean up fid reference */
2146 smb_ReleaseFID(fidp);
2150 #ifdef DEBUG_VERBOSE
2152 char *hexp, *asciip;
2153 asciip = (lastNamep ? lastNamep : pathp);
2154 hexp = osi_HexifyString( asciip );
2155 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2160 userp = smb_GetTran2User(vcp, p);
2161 /* In the off chance that userp is NULL, we log and abandon */
2163 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2164 smb_FreeTran2Packet(outp);
2165 return CM_ERROR_BADSMB;
2168 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2169 if (code == CM_ERROR_TIDIPC) {
2170 /* Attempt to use a TID allocated for IPC. The client
2171 * is probably looking for DCE RPC end points which we
2172 * don't support OR it could be looking to make a DFS
2175 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2177 cm_ReleaseUser(userp);
2178 smb_FreeTran2Packet(outp);
2179 return CM_ERROR_NOSUCHPATH;
2184 code = cm_NameI(cm_data.rootSCachep, pathp,
2185 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2186 userp, tidPathp, &req, &scp);
2188 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2189 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2190 userp, tidPathp, &req, &dscp);
2191 cm_FreeSpace(spacep);
2194 cm_ReleaseUser(userp);
2195 smb_FreeTran2Packet(outp);
2200 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2201 cm_ReleaseSCache(dscp);
2202 cm_ReleaseUser(userp);
2203 smb_FreeTran2Packet(outp);
2204 if ( WANTS_DFS_PATHNAMES(p) )
2205 return CM_ERROR_PATH_NOT_COVERED;
2207 return CM_ERROR_BADSHARENAME;
2209 #endif /* DFS_SUPPORT */
2211 /* otherwise, scp points to the parent directory. Do a lookup,
2212 * and truncate the file if we find it, otherwise we create the
2219 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2221 if (code && code != CM_ERROR_NOSUCHFILE) {
2222 cm_ReleaseSCache(dscp);
2223 cm_ReleaseUser(userp);
2224 smb_FreeTran2Packet(outp);
2229 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2230 cm_ReleaseSCache(scp);
2231 cm_ReleaseUser(userp);
2232 smb_FreeTran2Packet(outp);
2233 if ( WANTS_DFS_PATHNAMES(p) )
2234 return CM_ERROR_PATH_NOT_COVERED;
2236 return CM_ERROR_BADSHARENAME;
2238 #endif /* DFS_SUPPORT */
2240 /* macintosh is expensive to program for it */
2241 cm_FreeSpace(spacep);
2244 /* if we get here, if code is 0, the file exists and is represented by
2245 * scp. Otherwise, we have to create it.
2248 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2251 cm_ReleaseSCache(dscp);
2252 cm_ReleaseSCache(scp);
2253 cm_ReleaseUser(userp);
2254 smb_FreeTran2Packet(outp);
2259 /* oops, file shouldn't be there */
2261 cm_ReleaseSCache(dscp);
2262 cm_ReleaseSCache(scp);
2263 cm_ReleaseUser(userp);
2264 smb_FreeTran2Packet(outp);
2265 return CM_ERROR_EXISTS;
2269 setAttr.mask = CM_ATTRMASK_LENGTH;
2270 setAttr.length.LowPart = 0;
2271 setAttr.length.HighPart = 0;
2272 code = cm_SetAttr(scp, &setAttr, userp, &req);
2273 openAction = 3; /* truncated existing file */
2276 openAction = 1; /* found existing file */
2278 else if (!(openFun & 0x10)) {
2279 /* don't create if not found */
2281 cm_ReleaseSCache(dscp);
2282 osi_assert(scp == NULL);
2283 cm_ReleaseUser(userp);
2284 smb_FreeTran2Packet(outp);
2285 return CM_ERROR_NOSUCHFILE;
2288 osi_assert(dscp != NULL && scp == NULL);
2289 openAction = 2; /* created file */
2290 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2291 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2292 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2296 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2297 smb_NotifyChange(FILE_ACTION_ADDED,
2298 FILE_NOTIFY_CHANGE_FILE_NAME,
2299 dscp, lastNamep, NULL, TRUE);
2300 } else if (!excl && code == CM_ERROR_EXISTS) {
2301 /* not an exclusive create, and someone else tried
2302 * creating it already, then we open it anyway. We
2303 * don't bother retrying after this, since if this next
2304 * fails, that means that the file was deleted after we
2305 * started this call.
2307 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2311 setAttr.mask = CM_ATTRMASK_LENGTH;
2312 setAttr.length.LowPart = 0;
2313 setAttr.length.HighPart = 0;
2314 code = cm_SetAttr(scp, &setAttr, userp,
2317 } /* lookup succeeded */
2321 /* we don't need this any longer */
2323 cm_ReleaseSCache(dscp);
2326 /* something went wrong creating or truncating the file */
2328 cm_ReleaseSCache(scp);
2329 cm_ReleaseUser(userp);
2330 smb_FreeTran2Packet(outp);
2334 /* make sure we're about to open a file */
2335 if (scp->fileType != CM_SCACHETYPE_FILE) {
2337 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2338 cm_scache_t * targetScp = 0;
2339 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2341 /* we have a more accurate file to use (the
2342 * target of the symbolic link). Otherwise,
2343 * we'll just use the symlink anyway.
2345 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2347 cm_ReleaseSCache(scp);
2351 if (scp->fileType != CM_SCACHETYPE_FILE) {
2352 cm_ReleaseSCache(scp);
2353 cm_ReleaseUser(userp);
2354 smb_FreeTran2Packet(outp);
2355 return CM_ERROR_ISDIR;
2359 /* now all we have to do is open the file itself */
2360 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2364 lock_ObtainMutex(&fidp->mx);
2365 /* save a pointer to the vnode */
2368 fidp->userp = userp;
2370 /* compute open mode */
2372 fidp->flags |= SMB_FID_OPENREAD;
2373 if (openMode == 1 || openMode == 2)
2374 fidp->flags |= SMB_FID_OPENWRITE;
2376 /* remember that the file was newly created */
2378 fidp->flags |= SMB_FID_CREATED;
2380 lock_ReleaseMutex(&fidp->mx);
2382 smb_ReleaseFID(fidp);
2384 cm_Open(scp, 0, userp);
2386 /* copy out remainder of the parms */
2388 outp->parmsp[parmSlot++] = fidp->fid;
2389 lock_ObtainMutex(&scp->mx);
2391 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2392 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2393 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2394 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2395 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2396 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2397 outp->parmsp[parmSlot++] = openMode;
2398 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2399 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2401 /* and the final "always present" stuff */
2402 outp->parmsp[parmSlot++] = openAction;
2403 /* next write out the "unique" ID */
2404 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2405 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2406 outp->parmsp[parmSlot++] = 0;
2407 if (returnEALength) {
2408 outp->parmsp[parmSlot++] = 0;
2409 outp->parmsp[parmSlot++] = 0;
2411 lock_ReleaseMutex(&scp->mx);
2412 outp->totalData = 0; /* total # of data bytes */
2413 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2415 smb_SendTran2Packet(vcp, outp, op);
2417 smb_FreeTran2Packet(outp);
2419 cm_ReleaseUser(userp);
2420 /* leave scp held since we put it in fidp->scp */
2424 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2426 osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2427 return CM_ERROR_BADOP;
2430 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2432 osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2433 return CM_ERROR_BADOP;
2436 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2438 smb_tran2Packet_t *outp;
2439 smb_tran2QFSInfo_t qi;
2441 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
2443 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2445 switch (p->parmsp[0]) {
2446 case SMB_INFO_ALLOCATION:
2447 responseSize = sizeof(qi.u.allocInfo);
2449 case SMB_INFO_VOLUME:
2450 responseSize = sizeof(qi.u.volumeInfo);
2452 case SMB_QUERY_FS_VOLUME_INFO:
2453 responseSize = sizeof(qi.u.FSvolumeInfo);
2455 case SMB_QUERY_FS_SIZE_INFO:
2456 responseSize = sizeof(qi.u.FSsizeInfo);
2458 case SMB_QUERY_FS_DEVICE_INFO:
2459 responseSize = sizeof(qi.u.FSdeviceInfo);
2461 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2462 responseSize = sizeof(qi.u.FSattributeInfo);
2464 case SMB_INFO_UNIX: /* CIFS Unix Info */
2465 case SMB_INFO_MACOS: /* Mac FS Info */
2467 return CM_ERROR_INVAL;
2470 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2471 switch (p->parmsp[0]) {
2472 case SMB_INFO_ALLOCATION:
2474 qi.u.allocInfo.FSID = 0;
2475 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2476 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2477 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2478 qi.u.allocInfo.bytesPerSector = 1024;
2481 case SMB_INFO_VOLUME:
2483 qi.u.volumeInfo.vsn = 1234;
2484 qi.u.volumeInfo.vnCount = 4;
2485 /* we're supposed to pad it out with zeroes to the end */
2486 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2487 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2490 case SMB_QUERY_FS_VOLUME_INFO:
2491 /* FS volume info */
2492 memset((char *)&qi.u.FSvolumeInfo.vct, 0, 4);
2493 qi.u.FSvolumeInfo.vsn = 1234;
2494 qi.u.FSvolumeInfo.vnCount = 8;
2495 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
2498 case SMB_QUERY_FS_SIZE_INFO:
2500 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2501 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2502 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2503 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2504 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2505 qi.u.FSsizeInfo.bytesPerSector = 1024;
2508 case SMB_QUERY_FS_DEVICE_INFO:
2509 /* FS device info */
2510 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2511 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2514 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2515 /* FS attribute info */
2516 /* attributes, defined in WINNT.H:
2517 * FILE_CASE_SENSITIVE_SEARCH 0x1
2518 * FILE_CASE_PRESERVED_NAMES 0x2
2519 * FILE_VOLUME_QUOTAS 0x10
2520 * <no name defined> 0x4000
2521 * If bit 0x4000 is not set, Windows 95 thinks
2522 * we can't handle long (non-8.3) names,
2523 * despite our protestations to the contrary.
2525 qi.u.FSattributeInfo.attributes = 0x4013;
2526 qi.u.FSattributeInfo.maxCompLength = 255;
2527 qi.u.FSattributeInfo.FSnameLength = 6;
2528 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
2532 /* copy out return data, and set corresponding sizes */
2533 outp->totalParms = 0;
2534 outp->totalData = responseSize;
2535 memcpy(outp->datap, &qi, responseSize);
2537 /* send and free the packets */
2538 smb_SendTran2Packet(vcp, outp, op);
2539 smb_FreeTran2Packet(outp);
2544 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2546 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2547 return CM_ERROR_BADOP;
2550 struct smb_ShortNameRock {
2554 size_t shortNameLen;
2557 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2560 struct smb_ShortNameRock *rockp;
2564 /* compare both names and vnodes, though probably just comparing vnodes
2565 * would be safe enough.
2567 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2569 if (ntohl(dep->fid.vnode) != rockp->vnode)
2571 /* This is the entry */
2572 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2573 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2574 return CM_ERROR_STOPNOW;
2577 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2578 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2580 struct smb_ShortNameRock rock;
2584 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2588 spacep = cm_GetSpace();
2589 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2591 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2593 cm_FreeSpace(spacep);
2598 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2599 cm_ReleaseSCache(dscp);
2600 cm_ReleaseUser(userp);
2601 return CM_ERROR_PATH_NOT_COVERED;
2603 #endif /* DFS_SUPPORT */
2605 if (!lastNamep) lastNamep = pathp;
2608 thyper.HighPart = 0;
2609 rock.shortName = shortName;
2611 rock.maskp = lastNamep;
2612 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2614 cm_ReleaseSCache(dscp);
2617 return CM_ERROR_NOSUCHFILE;
2618 if (code == CM_ERROR_STOPNOW) {
2619 *shortNameLenp = rock.shortNameLen;
2625 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2627 smb_tran2Packet_t *outp;
2630 unsigned short infoLevel;
2631 smb_tran2QPathInfo_t qpi;
2633 unsigned short attributes;
2634 unsigned long extAttributes;
2639 cm_scache_t *scp, *dscp;
2652 fidp = smb_FindFID(vcp, fid, 0);
2654 lock_ObtainMutex(&fidp->mx);
2655 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
2656 lock_ReleaseMutex(&fidp->mx);
2657 smb_ReleaseFID(fidp);
2661 infoLevel = p->parmsp[0];
2662 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2664 else if (infoLevel == SMB_INFO_STANDARD)
2665 responseSize = sizeof(qpi.u.QPstandardInfo);
2666 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2667 responseSize = sizeof(qpi.u.QPeaSizeInfo);
2668 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2669 responseSize = sizeof(qpi.u.QPfileBasicInfo);
2670 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2671 responseSize = sizeof(qpi.u.QPfileStandardInfo);
2672 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2673 responseSize = sizeof(qpi.u.QPfileEaInfo);
2674 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2675 responseSize = sizeof(qpi.u.QPfileNameInfo);
2676 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
2677 responseSize = sizeof(qpi.u.QPfileAllInfo);
2678 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2679 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2681 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2682 p->opcode, infoLevel);
2683 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
2687 pathp = (char *)(&p->parmsp[3]);
2688 if (smb_StoreAnsiFilenames)
2689 OemToChar(pathp,pathp);
2690 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2691 osi_LogSaveString(smb_logp, pathp));
2693 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2695 if (infoLevel > 0x100)
2696 outp->totalParms = 2;
2698 outp->totalParms = 0;
2699 outp->totalData = responseSize;
2701 /* now, if we're at infoLevel 6, we're only being asked to check
2702 * the syntax, so we just OK things now. In particular, we're *not*
2703 * being asked to verify anything about the state of any parent dirs.
2705 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2706 smb_SendTran2Packet(vcp, outp, opx);
2707 smb_FreeTran2Packet(outp);
2711 userp = smb_GetTran2User(vcp, p);
2713 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2714 smb_FreeTran2Packet(outp);
2715 return CM_ERROR_BADSMB;
2718 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2720 cm_ReleaseUser(userp);
2721 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2722 smb_FreeTran2Packet(outp);
2727 * XXX Strange hack XXX
2729 * As of Patch 7 (13 January 98), we are having the following problem:
2730 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2731 * requests to look up "desktop.ini" in all the subdirectories.
2732 * This can cause zillions of timeouts looking up non-existent cells
2733 * and volumes, especially in the top-level directory.
2735 * We have not found any way to avoid this or work around it except
2736 * to explicitly ignore the requests for mount points that haven't
2737 * yet been evaluated and for directories that haven't yet been
2740 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2741 spacep = cm_GetSpace();
2742 smb_StripLastComponent(spacep->data, &lastComp, pathp);
2743 #ifndef SPECIAL_FOLDERS
2744 /* Make sure that lastComp is not NULL */
2746 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2747 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2751 userp, tidPathp, &req, &dscp);
2754 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2755 if ( WANTS_DFS_PATHNAMES(p) )
2756 code = CM_ERROR_PATH_NOT_COVERED;
2758 code = CM_ERROR_BADSHARENAME;
2760 #endif /* DFS_SUPPORT */
2761 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2762 code = CM_ERROR_NOSUCHFILE;
2763 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2764 cm_buf_t *bp = buf_Find(dscp, &hzero);
2768 code = CM_ERROR_NOSUCHFILE;
2770 cm_ReleaseSCache(dscp);
2772 cm_FreeSpace(spacep);
2773 cm_ReleaseUser(userp);
2774 smb_SendTran2Error(vcp, p, opx, code);
2775 smb_FreeTran2Packet(outp);
2781 #endif /* SPECIAL_FOLDERS */
2783 cm_FreeSpace(spacep);
2786 /* now do namei and stat, and copy out the info */
2787 code = cm_NameI(cm_data.rootSCachep, pathp,
2788 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2791 cm_ReleaseUser(userp);
2792 smb_SendTran2Error(vcp, p, opx, code);
2793 smb_FreeTran2Packet(outp);
2798 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2799 cm_ReleaseSCache(scp);
2800 cm_ReleaseUser(userp);
2801 if ( WANTS_DFS_PATHNAMES(p) )
2802 code = CM_ERROR_PATH_NOT_COVERED;
2804 code = CM_ERROR_BADSHARENAME;
2805 smb_SendTran2Error(vcp, p, opx, code);
2806 smb_FreeTran2Packet(outp);
2809 #endif /* DFS_SUPPORT */
2811 lock_ObtainMutex(&scp->mx);
2812 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2813 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2814 if (code) goto done;
2816 /* now we have the status in the cache entry, and everything is locked.
2817 * Marshall the output data.
2819 /* for info level 108, figure out short name */
2820 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
2821 code = cm_GetShortName(pathp, userp, &req,
2822 tidPathp, scp->fid.vnode, shortName,
2828 qpi.u.QPfileAltNameInfo.fileNameLength = len * 2;
2829 mbstowcs((unsigned short *)qpi.u.QPfileAltNameInfo.fileName, shortName, len);
2833 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2834 len = strlen(lastComp);
2835 qpi.u.QPfileNameInfo.fileNameLength = len * 2;
2836 mbstowcs((unsigned short *)qpi.u.QPfileNameInfo.fileName, lastComp, len);
2840 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2841 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2842 qpi.u.QPstandardInfo.creationDateTime = dosTime;
2843 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
2844 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
2845 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
2846 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
2847 attributes = smb_Attributes(scp);
2848 qpi.u.QPstandardInfo.attributes = attributes;
2849 qpi.u.QPstandardInfo.eaSize = 0;
2851 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2852 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2853 qpi.u.QPfileBasicInfo.creationTime = ft;
2854 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
2855 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
2856 qpi.u.QPfileBasicInfo.changeTime = ft;
2857 extAttributes = smb_ExtAttributes(scp);
2858 qpi.u.QPfileBasicInfo.attributes = extAttributes;
2860 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2861 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
2862 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
2863 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
2864 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
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);
2870 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2871 qpi.u.QPfileEaInfo.eaSize = 0;
2873 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
2874 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2875 qpi.u.QPfileAllInfo.creationTime = ft;
2876 qpi.u.QPfileAllInfo.lastAccessTime = ft;
2877 qpi.u.QPfileAllInfo.lastWriteTime = ft;
2878 qpi.u.QPfileAllInfo.changeTime = ft;
2879 extAttributes = smb_ExtAttributes(scp);
2880 qpi.u.QPfileAllInfo.attributes = extAttributes;
2881 qpi.u.QPfileAllInfo.allocationSize = scp->length;
2882 qpi.u.QPfileAllInfo.endOfFile = scp->length;
2883 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
2884 qpi.u.QPfileAllInfo.deletePending = 0;
2885 qpi.u.QPfileAllInfo.directory =
2886 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2887 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2888 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2889 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
2890 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
2891 qpi.u.QPfileAllInfo.eaSize = 0;
2892 qpi.u.QPfileAllInfo.accessFlags = 0;
2893 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
2894 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
2895 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
2896 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
2897 qpi.u.QPfileAllInfo.mode = 0;
2898 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
2899 len = strlen(lastComp);
2900 qpi.u.QPfileAllInfo.fileNameLength = len * 2;
2901 mbstowcs((unsigned short *)qpi.u.QPfileAllInfo.fileName, lastComp, len);
2904 /* send and free the packets */
2906 lock_ReleaseMutex(&scp->mx);
2907 cm_ReleaseSCache(scp);
2908 cm_ReleaseUser(userp);
2910 memcpy(outp->datap, &qpi, responseSize);
2911 smb_SendTran2Packet(vcp, outp, opx);
2913 smb_SendTran2Error(vcp, p, opx, code);
2915 smb_FreeTran2Packet(outp);
2920 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2923 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2924 return CM_ERROR_BADOP;
2929 unsigned short infoLevel;
2930 smb_tran2Packet_t *outp;
2931 smb_tran2QPathInfo_t *spi;
2939 fidp = smb_FindFID(vcp, fid, 0);
2942 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2946 infoLevel = p->parmsp[1];
2947 osi_Log2(smb_logp,"ReceiveTran2SetPathInfo type 0x%x fid %d", infoLevel, fid);
2948 if (infoLevel != SMB_INFO_STANDARD &&
2949 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
2950 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
2951 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2952 p->opcode, infoLevel);
2953 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2954 smb_ReleaseFID(fidp);
2958 lock_ObtainMutex(&fidp->mx);
2959 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
2960 lock_ReleaseMutex(&fidp->mx);
2961 smb_ReleaseFID(fidp);
2962 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
2968 lock_ReleaseMutex(&fidp->mx);
2970 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
2972 outp->totalParms = 2;
2973 outp->totalData = 0;
2975 userp = smb_GetTran2User(vcp, p);
2977 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
2978 code = CM_ERROR_BADSMB;
2982 spi = (smb_tran2QPathInfo_t *)p->datap;
2983 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2986 /* lock the vnode with a callback; we need the current status
2987 * to determine what the new status is, in some cases.
2989 lock_ObtainMutex(&scp->mx);
2990 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2991 CM_SCACHESYNC_GETSTATUS
2992 | CM_SCACHESYNC_NEEDCALLBACK);
2993 lock_ReleaseMutex(&scp->mx);
2998 lock_ObtainMutex(&fidp->mx);
2999 lock_ObtainMutex(&scp->mx);
3001 /* prepare for setattr call */
3002 attr.mask = CM_ATTRMASK_LENGTH;
3003 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3004 attr.length.HighPart = 0;
3006 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3007 smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3008 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3009 fidp->flags |= SMB_FID_MTIMESETDONE;
3012 if (spi->u.QPstandardInfo.attributes != 0) {
3013 if ((scp->unixModeBits & 0222)
3014 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3015 /* make a writable file read-only */
3016 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3017 attr.unixModeBits = scp->unixModeBits & ~0222;
3019 else if ((scp->unixModeBits & 0222) == 0
3020 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3021 /* make a read-only file writable */
3022 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3023 attr.unixModeBits = scp->unixModeBits | 0222;
3026 lock_ReleaseMutex(&scp->mx);
3027 lock_ReleaseMutex(&fidp->mx);
3031 code = cm_SetAttr(scp, &attr, userp, &req);
3035 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3036 /* we don't support EAs */
3037 code = CM_ERROR_INVAL;
3041 cm_ReleaseSCache(scp);
3042 cm_ReleaseUser(userp);
3043 smb_ReleaseFID(fidp);
3045 smb_SendTran2Packet(vcp, outp, opx);
3047 smb_SendTran2Error(vcp, p, opx, code);
3048 smb_FreeTran2Packet(outp);
3054 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3056 smb_tran2Packet_t *outp;
3058 unsigned long attributes;
3059 unsigned short infoLevel;
3066 smb_tran2QFileInfo_t qfi;
3073 fidp = smb_FindFID(vcp, fid, 0);
3076 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3080 infoLevel = p->parmsp[1];
3081 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3082 responseSize = sizeof(qfi.u.QFbasicInfo);
3083 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3084 responseSize = sizeof(qfi.u.QFstandardInfo);
3085 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3086 responseSize = sizeof(qfi.u.QFeaInfo);
3087 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3088 responseSize = sizeof(qfi.u.QFfileNameInfo);
3090 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3091 p->opcode, infoLevel);
3092 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
3093 smb_ReleaseFID(fidp);
3096 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3098 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3100 if (infoLevel > 0x100)
3101 outp->totalParms = 2;
3103 outp->totalParms = 0;
3104 outp->totalData = responseSize;
3106 userp = smb_GetTran2User(vcp, p);
3108 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3109 code = CM_ERROR_BADSMB;
3113 lock_ObtainMutex(&fidp->mx);
3114 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3117 lock_ReleaseMutex(&fidp->mx);
3118 lock_ObtainMutex(&scp->mx);
3119 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3120 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3124 /* now we have the status in the cache entry, and everything is locked.
3125 * Marshall the output data.
3127 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3128 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3129 qfi.u.QFbasicInfo.creationTime = ft;
3130 qfi.u.QFbasicInfo.lastAccessTime = ft;
3131 qfi.u.QFbasicInfo.lastWriteTime = ft;
3132 qfi.u.QFbasicInfo.lastChangeTime = ft;
3133 attributes = smb_ExtAttributes(scp);
3134 qfi.u.QFbasicInfo.attributes = attributes;
3136 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3137 qfi.u.QFstandardInfo.allocationSize = scp->length;
3138 qfi.u.QFstandardInfo.endOfFile = scp->length;
3139 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3140 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3141 qfi.u.QFstandardInfo.directory =
3142 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3143 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3144 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3146 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3147 qfi.u.QFeaInfo.eaSize = 0;
3149 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3153 lock_ReleaseMutex(&scp->mx);
3154 lock_ObtainMutex(&fidp->mx);
3155 lock_ObtainMutex(&scp->mx);
3156 if (fidp->NTopen_wholepathp)
3157 name = fidp->NTopen_wholepathp;
3159 name = "\\"; /* probably can't happen */
3160 lock_ReleaseMutex(&fidp->mx);
3161 len = (unsigned long)strlen(name);
3162 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
3163 qfi.u.QFfileNameInfo.fileNameLength = len * 2;
3164 mbstowcs((unsigned short *)qfi.u.QFfileNameInfo.fileName, name, len);
3167 /* send and free the packets */
3169 lock_ReleaseMutex(&scp->mx);
3170 cm_ReleaseSCache(scp);
3171 cm_ReleaseUser(userp);
3172 smb_ReleaseFID(fidp);
3174 memcpy(outp->datap, &qfi, responseSize);
3175 smb_SendTran2Packet(vcp, outp, opx);
3177 smb_SendTran2Error(vcp, p, opx, code);
3179 smb_FreeTran2Packet(outp);
3184 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3189 unsigned short infoLevel;
3190 smb_tran2Packet_t *outp;
3198 fidp = smb_FindFID(vcp, fid, 0);
3201 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3205 infoLevel = p->parmsp[1];
3206 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3207 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3208 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3209 p->opcode, infoLevel);
3210 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
3211 smb_ReleaseFID(fidp);
3215 lock_ObtainMutex(&fidp->mx);
3216 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) {
3217 lock_ReleaseMutex(&fidp->mx);
3218 smb_ReleaseFID(fidp);
3219 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3222 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3223 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3224 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3225 lock_ReleaseMutex(&fidp->mx);
3226 smb_ReleaseFID(fidp);
3227 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3233 lock_ReleaseMutex(&fidp->mx);
3235 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3237 outp->totalParms = 2;
3238 outp->totalData = 0;
3240 userp = smb_GetTran2User(vcp, p);
3242 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3243 code = CM_ERROR_BADSMB;
3247 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3249 unsigned int attribute;
3251 smb_tran2QFileInfo_t *sfi;
3253 sfi = (smb_tran2QFileInfo_t *)p->datap;
3255 /* lock the vnode with a callback; we need the current status
3256 * to determine what the new status is, in some cases.
3258 lock_ObtainMutex(&scp->mx);
3259 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3260 CM_SCACHESYNC_GETSTATUS
3261 | CM_SCACHESYNC_NEEDCALLBACK);
3262 lock_ReleaseMutex(&scp->mx);
3266 lock_ObtainMutex(&fidp->mx);
3267 lock_ObtainMutex(&scp->mx);
3269 /* prepare for setattr call */
3272 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3273 /* when called as result of move a b, lastMod is (-1, -1).
3274 * If the check for -1 is not present, timestamp
3275 * of the resulting file will be 1969 (-1)
3277 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3278 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3279 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3280 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3281 fidp->flags |= SMB_FID_MTIMESETDONE;
3284 attribute = sfi->u.QFbasicInfo.attributes;
3285 if (attribute != 0) {
3286 if ((scp->unixModeBits & 0222)
3287 && (attribute & SMB_ATTR_READONLY) != 0) {
3288 /* make a writable file read-only */
3289 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3290 attr.unixModeBits = scp->unixModeBits & ~0222;
3292 else if ((scp->unixModeBits & 0222) == 0
3293 && (attribute & SMB_ATTR_READONLY) == 0) {
3294 /* make a read-only file writable */
3295 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3296 attr.unixModeBits = scp->unixModeBits | 0222;
3299 lock_ReleaseMutex(&scp->mx);
3300 lock_ReleaseMutex(&fidp->mx);
3304 code = cm_SetAttr(scp, &attr, userp, &req);
3308 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3309 if (*((char *)(p->datap))) { /* File is Deleted */
3310 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3313 lock_ObtainMutex(&fidp->mx);
3314 fidp->flags |= SMB_FID_DELONCLOSE;
3315 lock_ReleaseMutex(&fidp->mx);
3320 lock_ObtainMutex(&fidp->mx);
3321 fidp->flags &= ~SMB_FID_DELONCLOSE;
3322 lock_ReleaseMutex(&fidp->mx);
3325 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO) {
3326 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3329 attr.mask = CM_ATTRMASK_LENGTH;
3330 attr.length.LowPart = size.LowPart;
3331 attr.length.HighPart = size.HighPart;
3332 code = cm_SetAttr(scp, &attr, userp, &req);
3334 else if (infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3335 unsigned short size = *((unsigned short *)(p->datap));
3338 attr.mask = CM_ATTRMASK_LENGTH;
3339 attr.length.LowPart = size;
3340 code = cm_SetAttr(scp, &attr, userp, &req);
3344 cm_ReleaseSCache(scp);
3345 cm_ReleaseUser(userp);
3346 smb_ReleaseFID(fidp);
3348 smb_SendTran2Packet(vcp, outp, opx);
3350 smb_SendTran2Error(vcp, p, opx, code);
3351 smb_FreeTran2Packet(outp);
3357 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3359 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3360 return CM_ERROR_BADOP;
3364 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3366 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3367 return CM_ERROR_BADOP;
3371 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3373 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3374 return CM_ERROR_BADOP;
3378 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3380 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3381 return CM_ERROR_BADOP;
3385 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3387 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3388 return CM_ERROR_BADOP;
3392 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3394 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3395 return CM_ERROR_BADOP;
3398 struct smb_v2_referral {
3400 USHORT ReferralFlags;
3403 USHORT DfsPathOffset;
3404 USHORT DfsAlternativePathOffset;
3405 USHORT NetworkAddressOffset;
3409 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3411 /* This is a UNICODE only request (bit15 of Flags2) */
3412 /* The TID must be IPC$ */
3414 /* The documentation for the Flags response field is contradictory */
3416 /* Use Version 1 Referral Element Format */
3417 /* ServerType = 0; indicates the next server should be queried for the file */
3418 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3419 /* Node = UnicodeString of UNC path of the next share name */
3422 int maxReferralLevel = 0;
3423 char requestFileName[1024] = "";
3424 smb_tran2Packet_t *outp = 0;
3425 cm_user_t *userp = 0;
3427 CPINFO CodePageInfo;
3428 int i, nbnLen, reqLen;
3433 maxReferralLevel = p->parmsp[0];
3435 GetCPInfo(CP_ACP, &CodePageInfo);
3436 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
3437 requestFileName, 1024, NULL, NULL);
3439 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
3440 maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3442 nbnLen = strlen(cm_NetbiosName);
3443 reqLen = strlen(requestFileName);
3445 if (reqLen == nbnLen + 5 &&
3446 requestFileName[0] == '\\' &&
3447 !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3448 requestFileName[nbnLen+1] == '\\' &&
3449 (!_strnicmp("all",&requestFileName[nbnLen+2],3) ||
3450 !_strnicmp("*.",&requestFileName[nbnLen+2],2)))
3453 struct smb_v2_referral * v2ref;
3454 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
3456 sp = (USHORT *)outp->datap;
3458 sp[idx++] = reqLen; /* path consumed */
3459 sp[idx++] = 1; /* number of referrals */
3460 sp[idx++] = 0x03; /* flags */
3461 #ifdef DFS_VERSION_1
3462 sp[idx++] = 1; /* Version Number */
3463 sp[idx++] = reqLen + 4; /* Referral Size */
3464 sp[idx++] = 1; /* Type = SMB Server */
3465 sp[idx++] = 0; /* Do not strip path consumed */
3466 for ( i=0;i<=reqLen; i++ )
3467 sp[i+idx] = requestFileName[i];
3468 #else /* DFS_VERSION_2 */
3469 sp[idx++] = 2; /* Version Number */
3470 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3471 idx += (sizeof(struct smb_v2_referral) / 2);
3472 v2ref = (struct smb_v2_referral *) &sp[5];
3473 v2ref->ServerType = 1; /* SMB Server */
3474 v2ref->ReferralFlags = 0x03;
3475 v2ref->Proximity = 0; /* closest */
3476 v2ref->TimeToLive = 3600; /* seconds */
3477 v2ref->DfsPathOffset = idx * 2;
3478 v2ref->DfsAlternativePathOffset = idx * 2;
3479 v2ref->NetworkAddressOffset = 0;
3480 for ( i=0;i<=reqLen; i++ )
3481 sp[i+idx] = requestFileName[i];
3484 userp = smb_GetTran2User(vcp, p);
3486 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3487 code = CM_ERROR_BADSMB;
3492 code = CM_ERROR_NOSUCHPATH;
3497 cm_ReleaseUser(userp);
3499 smb_SendTran2Packet(vcp, outp, op);
3501 smb_SendTran2Error(vcp, p, op, code);
3503 smb_FreeTran2Packet(outp);
3506 #else /* DFS_SUPPORT */
3507 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3508 return CM_ERROR_BADOP;
3509 #endif /* DFS_SUPPORT */
3513 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3515 /* This is a UNICODE only request (bit15 of Flags2) */
3517 /* There is nothing we can do about this operation. The client is going to
3518 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3519 * Unfortunately, there is really nothing we can do about it other then log it
3520 * somewhere. Even then I don't think there is anything for us to do.
3521 * So let's return an error value.
3524 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3525 return CM_ERROR_BADOP;
3529 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3530 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3535 cm_scache_t *targetScp; /* target if scp is a symlink */
3540 unsigned short attr;
3541 unsigned long lattr;
3542 smb_dirListPatch_t *patchp;
3543 smb_dirListPatch_t *npatchp;
3545 for(patchp = *dirPatchespp; patchp; patchp =
3546 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3547 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3549 lock_ObtainMutex(&scp->mx);
3550 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3551 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3553 lock_ReleaseMutex(&scp->mx);
3554 cm_ReleaseSCache(scp);
3556 dptr = patchp->dptr;
3558 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3559 errors in the client. */
3560 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3561 /* 1969-12-31 23:59:59 +00 */
3562 ft.dwHighDateTime = 0x19DB200;
3563 ft.dwLowDateTime = 0x5BB78980;
3565 /* copy to Creation Time */
3566 *((FILETIME *)dptr) = ft;
3569 /* copy to Last Access Time */
3570 *((FILETIME *)dptr) = ft;
3573 /* copy to Last Write Time */
3574 *((FILETIME *)dptr) = ft;
3577 /* copy to Change Time */
3578 *((FILETIME *)dptr) = ft;
3581 /* merge in hidden attribute */
3582 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3583 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3587 /* 1969-12-31 23:59:58 +00*/
3588 dosTime = 0xEBBFBF7D;
3590 /* and copy out date */
3591 shortTemp = (dosTime>>16) & 0xffff;
3592 *((u_short *)dptr) = shortTemp;
3595 /* copy out creation time */
3596 shortTemp = dosTime & 0xffff;
3597 *((u_short *)dptr) = shortTemp;
3600 /* and copy out date */
3601 shortTemp = (dosTime>>16) & 0xffff;
3602 *((u_short *)dptr) = shortTemp;
3605 /* copy out access time */
3606 shortTemp = dosTime & 0xffff;
3607 *((u_short *)dptr) = shortTemp;
3610 /* and copy out date */
3611 shortTemp = (dosTime>>16) & 0xffff;
3612 *((u_short *)dptr) = shortTemp;
3615 /* copy out mod time */
3616 shortTemp = dosTime & 0xffff;
3617 *((u_short *)dptr) = shortTemp;
3620 /* merge in hidden (dot file) attribute */
3621 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3622 attr = SMB_ATTR_HIDDEN;
3623 *dptr++ = attr & 0xff;
3624 *dptr++ = (attr >> 8) & 0xff;
3630 /* now watch for a symlink */
3632 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3633 lock_ReleaseMutex(&scp->mx);
3634 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3636 /* we have a more accurate file to use (the
3637 * target of the symbolic link). Otherwise,
3638 * we'll just use the symlink anyway.
3640 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3642 cm_ReleaseSCache(scp);
3645 lock_ObtainMutex(&scp->mx);
3648 dptr = patchp->dptr;
3650 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3652 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3654 /* copy to Creation Time */
3655 *((FILETIME *)dptr) = ft;
3658 /* copy to Last Access Time */
3659 *((FILETIME *)dptr) = ft;
3662 /* copy to Last Write Time */
3663 *((FILETIME *)dptr) = ft;
3666 /* copy to Change Time */
3667 *((FILETIME *)dptr) = ft;
3670 /* Use length for both file length and alloc length */
3671 *((LARGE_INTEGER *)dptr) = scp->length;
3673 *((LARGE_INTEGER *)dptr) = scp->length;
3676 /* Copy attributes */
3677 lattr = smb_ExtAttributes(scp);
3678 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3679 if (lattr == SMB_ATTR_NORMAL)
3680 lattr = SMB_ATTR_DIRECTORY;
3682 lattr |= SMB_ATTR_DIRECTORY;
3684 /* merge in hidden (dot file) attribute */
3685 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3686 if (lattr == SMB_ATTR_NORMAL)
3687 lattr = SMB_ATTR_HIDDEN;
3689 lattr |= SMB_ATTR_HIDDEN;
3691 *((u_long *)dptr) = lattr;
3695 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3697 /* and copy out date */
3698 shortTemp = (dosTime>>16) & 0xffff;
3699 *((u_short *)dptr) = shortTemp;
3702 /* copy out creation time */
3703 shortTemp = dosTime & 0xffff;
3704 *((u_short *)dptr) = shortTemp;
3707 /* and copy out date */
3708 shortTemp = (dosTime>>16) & 0xffff;
3709 *((u_short *)dptr) = shortTemp;
3712 /* copy out access time */
3713 shortTemp = dosTime & 0xffff;
3714 *((u_short *)dptr) = shortTemp;
3717 /* and copy out date */
3718 shortTemp = (dosTime>>16) & 0xffff;
3719 *((u_short *)dptr) = shortTemp;
3722 /* copy out mod time */
3723 shortTemp = dosTime & 0xffff;
3724 *((u_short *)dptr) = shortTemp;
3727 /* copy out file length and alloc length,
3728 * using the same for both
3730 *((u_long *)dptr) = scp->length.LowPart;
3732 *((u_long *)dptr) = scp->length.LowPart;
3735 /* finally copy out attributes as short */
3736 attr = smb_Attributes(scp);
3737 /* merge in hidden (dot file) attribute */
3738 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3739 if (lattr == SMB_ATTR_NORMAL)
3740 lattr = SMB_ATTR_HIDDEN;
3742 lattr |= SMB_ATTR_HIDDEN;
3744 *dptr++ = attr & 0xff;
3745 *dptr++ = (attr >> 8) & 0xff;
3748 lock_ReleaseMutex(&scp->mx);
3749 cm_ReleaseSCache(scp);
3752 /* now free the patches */
3753 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3754 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3758 /* and mark the list as empty */
3759 *dirPatchespp = NULL;
3764 #ifndef USE_OLD_MATCHING
3765 // char table for case insensitive comparison
3766 char mapCaseTable[256];
3768 VOID initUpperCaseTable(VOID)
3771 for (i = 0; i < 256; ++i)
3772 mapCaseTable[i] = toupper(i);
3773 // make '"' match '.'
3774 mapCaseTable[(int)'"'] = toupper('.');
3775 // make '<' match '*'
3776 mapCaseTable[(int)'<'] = toupper('*');
3777 // make '>' match '?'
3778 mapCaseTable[(int)'>'] = toupper('?');
3781 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3783 // Note : this procedure works recursively calling itself.
3785 // PSZ pattern : string containing metacharacters.
3786 // PSZ name : file name to be compared with 'pattern'.
3788 // BOOL : TRUE/FALSE (match/mistmatch)
3791 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
3793 PSZ pename; // points to the last 'name' character
3795 pename = name + strlen(name) - 1;
3806 if (*pattern == '\0')
3808 for (p = pename; p >= name; --p) {
3809 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
3810 !casefold && (*p == *pattern)) &&
3811 szWildCardMatchFileName(pattern + 1, p + 1, casefold))
3816 if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
3817 (!casefold && *name != *pattern))
3824 /* if all we have left are wildcards, then we match */
3825 for (;*pattern; pattern++) {
3826 if (*pattern != '*' && *pattern != '?')
3832 /* do a case-folding search of the star name mask with the name in namep.
3833 * Return 1 if we match, otherwise 0.
3835 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3838 int i, j, star, qmark, casefold, retval;
3840 /* make sure we only match 8.3 names, if requested */
3841 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3844 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
3846 /* optimize the pattern:
3847 * if there is a mixture of '?' and '*',
3848 * for example the sequence "*?*?*?*"
3849 * must be turned into the form "*"
3851 newmask = (char *)malloc(strlen(maskp)+1);
3852 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3853 switch ( maskp[i] ) {
3865 } else if ( qmark ) {
3869 newmask[j++] = maskp[i];
3876 } else if ( qmark ) {
3880 newmask[j++] = '\0';
3882 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
3888 #else /* USE_OLD_MATCHING */
3889 /* do a case-folding search of the star name mask with the name in namep.
3890 * Return 1 if we match, otherwise 0.
3892 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3894 unsigned char tcp1, tcp2; /* Pattern characters */
3895 unsigned char tcn1; /* Name characters */
3896 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3897 char *starNamep, *starMaskp;
3898 static char nullCharp[] = {0};
3899 int casefold = flags & CM_FLAG_CASEFOLD;
3901 /* make sure we only match 8.3 names, if requested */
3902 req8dot3 = (flags & CM_FLAG_8DOT3);
3903 if (req8dot3 && !cm_Is8Dot3(namep))
3908 /* Next pattern character */
3911 /* Next name character */
3915 /* 0 - end of pattern */
3921 else if (tcp1 == '.' || tcp1 == '"') {
3931 * first dot in pattern;
3932 * must match dot or end of name
3937 else if (tcn1 == '.') {
3946 else if (tcp1 == '?') {
3947 if (tcn1 == 0 || tcn1 == '.')
3952 else if (tcp1 == '>') {
3953 if (tcn1 != 0 && tcn1 != '.')
3957 else if (tcp1 == '*' || tcp1 == '<') {
3961 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3962 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3977 * pattern character after '*' is not null or
3978 * period. If it is '?' or '>', we are not
3979 * going to understand it. If it is '*' or
3980 * '<', we are going to skip over it. None of
3981 * these are likely, I hope.
3983 /* skip over '*' and '<' */
3984 while (tcp2 == '*' || tcp2 == '<')
3987 /* skip over characters that don't match tcp2 */
3988 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
3989 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
3990 (!casefold && tcn1 != tcp2)))
3994 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3997 /* Remember where we are */
4007 /* tcp1 is not a wildcard */
4008 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
4009 (!casefold && tcn1 == tcp1)) {
4014 /* if trying to match a star pattern, go back */
4016 maskp = starMaskp - 2;
4017 namep = starNamep + 1;
4026 #endif /* USE_OLD_MATCHING */
4028 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4033 long code = 0, code2 = 0;
4037 smb_dirListPatch_t *dirListPatchesp;
4038 smb_dirListPatch_t *curPatchp;
4041 long orbytes; /* # of bytes in this output record */
4042 long ohbytes; /* # of bytes, except file name */
4043 long onbytes; /* # of bytes in name, incl. term. null */
4044 osi_hyper_t dirLength;
4045 osi_hyper_t bufferOffset;
4046 osi_hyper_t curOffset;
4048 smb_dirSearch_t *dsp;
4052 cm_pageHeader_t *pageHeaderp;
4053 cm_user_t *userp = NULL;
4056 long nextEntryCookie;
4057 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4058 char *op; /* output data ptr */
4059 char *origOp; /* original value of op */
4060 cm_space_t *spacep; /* for pathname buffer */
4061 long maxReturnData; /* max # of return data */
4062 long maxReturnParms; /* max # of return parms */
4063 long bytesInBuffer; /* # data bytes in the output buffer */
4065 char *maskp; /* mask part of path */
4069 smb_tran2Packet_t *outp; /* response packet */
4072 char shortName[13]; /* 8.3 name if needed */
4084 if (p->opcode == 1) {
4085 /* find first; obtain basic parameters from request */
4086 attribute = p->parmsp[0];
4087 maxCount = p->parmsp[1];
4088 infoLevel = p->parmsp[3];
4089 searchFlags = p->parmsp[2];
4090 dsp = smb_NewDirSearch(1);
4091 dsp->attribute = attribute;
4092 pathp = ((char *) p->parmsp) + 12; /* points to path */
4093 if (smb_StoreAnsiFilenames)
4094 OemToChar(pathp,pathp);
4096 maskp = strrchr(pathp, '\\');
4100 maskp++; /* skip over backslash */
4101 strcpy(dsp->mask, maskp); /* and save mask */
4102 /* track if this is likely to match a lot of entries */
4103 starPattern = smb_V3IsStarMask(maskp);
4106 osi_assert(p->opcode == 2);
4107 /* find next; obtain basic parameters from request or open dir file */
4108 dsp = smb_FindDirSearch(p->parmsp[0]);
4109 maxCount = p->parmsp[1];
4110 infoLevel = p->parmsp[2];
4111 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4112 searchFlags = p->parmsp[5];
4114 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4115 p->parmsp[0], nextCookie);
4116 return CM_ERROR_BADFD;
4118 attribute = dsp->attribute;
4121 starPattern = 1; /* assume, since required a Find Next */
4124 switch ( infoLevel ) {
4125 case SMB_INFO_STANDARD:
4128 case SMB_INFO_QUERY_EA_SIZE:
4129 s = "InfoQueryEaSize";
4131 case SMB_INFO_QUERY_EAS_FROM_LIST:
4132 s = "InfoQueryEasFromList";
4134 case SMB_FIND_FILE_DIRECTORY_INFO:
4135 s = "FindFileDirectoryInfo";
4137 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4138 s = "FindFileFullDirectoryInfo";
4140 case SMB_FIND_FILE_NAMES_INFO:
4141 s = "FindFileNamesInfo";
4143 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4144 s = "FindFileBothDirectoryInfo";
4147 s = "unknownInfoLevel";
4150 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
4153 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4154 attribute, infoLevel, maxCount, searchFlags);
4156 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
4157 p->opcode, dsp->cookie, nextCookie);
4159 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4160 searchFlags &= ~4; /* no resume keys */
4162 dirListPatchesp = NULL;
4164 maxReturnData = p->maxReturnData;
4165 if (p->opcode == 1) /* find first */
4166 maxReturnParms = 10; /* bytes */
4168 maxReturnParms = 8; /* bytes */
4170 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4171 if (maxReturnData > 6000)
4172 maxReturnData = 6000;
4173 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4175 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4178 osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
4179 maxCount, osi_LogSaveString(smb_logp, pathp));
4181 /* bail out if request looks bad */
4182 if (p->opcode == 1 && !pathp) {
4183 smb_ReleaseDirSearch(dsp);
4184 smb_FreeTran2Packet(outp);
4185 return CM_ERROR_BADSMB;
4188 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
4189 dsp->cookie, nextCookie, attribute);
4191 userp = smb_GetTran2User(vcp, p);
4193 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
4194 smb_ReleaseDirSearch(dsp);
4195 smb_FreeTran2Packet(outp);
4196 return CM_ERROR_BADSMB;
4199 /* try to get the vnode for the path name next */
4200 lock_ObtainMutex(&dsp->mx);
4206 spacep = cm_GetSpace();
4207 smb_StripLastComponent(spacep->data, NULL, pathp);
4208 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4210 cm_ReleaseUser(userp);
4211 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4212 smb_FreeTran2Packet(outp);
4213 lock_ReleaseMutex(&dsp->mx);
4214 smb_DeleteDirSearch(dsp);
4215 smb_ReleaseDirSearch(dsp);
4218 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4219 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4220 userp, tidPathp, &req, &scp);
4221 cm_FreeSpace(spacep);
4224 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4225 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4226 cm_ReleaseSCache(scp);
4227 cm_ReleaseUser(userp);
4228 if ( WANTS_DFS_PATHNAMES(p) )
4229 code = CM_ERROR_PATH_NOT_COVERED;
4231 code = CM_ERROR_BADSHARENAME;
4232 smb_SendTran2Error(vcp, p, opx, code);
4233 smb_FreeTran2Packet(outp);
4234 lock_ReleaseMutex(&dsp->mx);
4235 smb_DeleteDirSearch(dsp);
4236 smb_ReleaseDirSearch(dsp);
4239 #endif /* DFS_SUPPORT */
4241 /* we need one hold for the entry we just stored into,
4242 * and one for our own processing. When we're done
4243 * with this function, we'll drop the one for our own
4244 * processing. We held it once from the namei call,
4245 * and so we do another hold now.
4248 lock_ObtainMutex(&scp->mx);
4249 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
4250 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4251 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4252 dsp->flags |= SMB_DIRSEARCH_BULKST;
4254 lock_ReleaseMutex(&scp->mx);
4257 lock_ReleaseMutex(&dsp->mx);
4259 cm_ReleaseUser(userp);
4260 smb_FreeTran2Packet(outp);
4261 smb_DeleteDirSearch(dsp);
4262 smb_ReleaseDirSearch(dsp);
4266 /* get the directory size */
4267 lock_ObtainMutex(&scp->mx);
4268 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4269 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4271 lock_ReleaseMutex(&scp->mx);
4272 cm_ReleaseSCache(scp);
4273 cm_ReleaseUser(userp);
4274 smb_FreeTran2Packet(outp);
4275 smb_DeleteDirSearch(dsp);
4276 smb_ReleaseDirSearch(dsp);
4281 dirLength = scp->length;
4283 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4284 curOffset.HighPart = 0;
4285 curOffset.LowPart = nextCookie;
4286 origOp = outp->datap;
4294 if (searchFlags & 4)
4295 /* skip over resume key */
4298 /* make sure that curOffset.LowPart doesn't point to the first
4299 * 32 bytes in the 2nd through last dir page, and that it doesn't
4300 * point at the first 13 32-byte chunks in the first dir page,
4301 * since those are dir and page headers, and don't contain useful
4304 temp = curOffset.LowPart & (2048-1);
4305 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4306 /* we're in the first page */
4307 if (temp < 13*32) temp = 13*32;
4310 /* we're in a later dir page */
4311 if (temp < 32) temp = 32;
4314 /* make sure the low order 5 bits are zero */
4317 /* now put temp bits back ito curOffset.LowPart */
4318 curOffset.LowPart &= ~(2048-1);
4319 curOffset.LowPart |= temp;
4321 /* check if we've passed the dir's EOF */
4322 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4323 osi_Log0(smb_logp, "T2 search dir passed eof");
4328 /* check if we've returned all the names that will fit in the
4329 * response packet; we check return count as well as the number
4330 * of bytes requested. We check the # of bytes after we find
4331 * the dir entry, since we'll need to check its size.
4333 if (returnedNames >= maxCount) {
4334 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4335 returnedNames, maxCount);
4339 /* see if we can use the bufferp we have now; compute in which
4340 * page the current offset would be, and check whether that's
4341 * the offset of the buffer we have. If not, get the buffer.
4343 thyper.HighPart = curOffset.HighPart;
4344 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4345 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4348 buf_Release(bufferp);
4351 lock_ReleaseMutex(&scp->mx);
4352 lock_ObtainRead(&scp->bufCreateLock);
4353 code = buf_Get(scp, &thyper, &bufferp);
4354 lock_ReleaseRead(&scp->bufCreateLock);
4355 lock_ObtainMutex(&dsp->mx);
4357 /* now, if we're doing a star match, do bulk fetching
4358 * of all of the status info for files in the dir.
4361 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
4364 lock_ObtainMutex(&scp->mx);
4365 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4366 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
4367 /* Don't bulk stat if risking timeout */
4368 int now = GetTickCount();
4369 if (now - req.startTime > RDRtimeout) {
4370 scp->bulkStatProgress = thyper;
4371 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4372 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4374 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4377 lock_ObtainMutex(&scp->mx);
4379 lock_ReleaseMutex(&dsp->mx);
4381 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
4385 bufferOffset = thyper;
4387 /* now get the data in the cache */
4389 code = cm_SyncOp(scp, bufferp, userp, &req,
4391 CM_SCACHESYNC_NEEDCALLBACK
4392 | CM_SCACHESYNC_READ);
4394 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
4398 if (cm_HaveBuffer(scp, bufferp, 0)) {
4399 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4403 /* otherwise, load the buffer and try again */
4404 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4407 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4408 scp, bufferp, code);
4413 buf_Release(bufferp);
4417 } /* if (wrong buffer) ... */
4419 /* now we have the buffer containing the entry we're interested
4420 * in; copy it out if it represents a non-deleted entry.
4422 entryInDir = curOffset.LowPart & (2048-1);
4423 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4425 /* page header will help tell us which entries are free. Page
4426 * header can change more often than once per buffer, since
4427 * AFS 3 dir page size may be less than (but not more than)
4428 * a buffer package buffer.
4430 /* only look intra-buffer */
4431 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4432 temp &= ~(2048 - 1); /* turn off intra-page bits */
4433 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4435 /* now determine which entry we're looking at in the page.
4436 * If it is free (there's a free bitmap at the start of the
4437 * dir), we should skip these 32 bytes.
4439 slotInPage = (entryInDir & 0x7e0) >> 5;
4440 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
4441 (1 << (slotInPage & 0x7)))) {
4442 /* this entry is free */
4443 numDirChunks = 1; /* only skip this guy */
4447 tp = bufferp->datap + entryInBuffer;
4448 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4450 /* while we're here, compute the next entry's location, too,
4451 * since we'll need it when writing out the cookie into the dir
4454 * XXXX Probably should do more sanity checking.
4456 numDirChunks = cm_NameEntries(dep->name, &onbytes);
4458 /* compute offset of cookie representing next entry */
4459 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4461 /* Need 8.3 name? */
4463 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4464 && dep->fid.vnode != 0
4465 && !cm_Is8Dot3(dep->name)) {
4466 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4470 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %s (%s)",
4471 dep->fid.vnode, dep->fid.unique,
4472 osi_LogSaveString(smb_logp, dep->name),
4473 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4475 /* When matching, we are using doing a case fold if we have a wildcard mask.
4476 * If we get a non-wildcard match, it's a lookup for a specific file.
4478 if (dep->fid.vnode != 0 &&
4479 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
4481 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
4483 /* Eliminate entries that don't match requested attributes */
4484 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
4485 smb_IsDotFile(dep->name)) {
4486 osi_Log0(smb_logp, "T2 search dir skipping hidden");
4487 goto nextEntry; /* no hidden files */
4489 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4491 /* We have already done the cm_TryBulkStat above */
4492 fid.cell = scp->fid.cell;
4493 fid.volume = scp->fid.volume;
4494 fid.vnode = ntohl(dep->fid.vnode);
4495 fid.unique = ntohl(dep->fid.unique);
4496 fileType = cm_FindFileType(&fid);
4497 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
4498 "has filetype %d", dep->name,
4500 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4501 fileType == CM_SCACHETYPE_DFSLINK ||
4502 fileType == CM_SCACHETYPE_INVALID)
4503 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
4507 /* finally check if this name will fit */
4509 /* standard dir entry stuff */
4510 if (infoLevel < 0x101)
4511 ohbytes = 23; /* pre-NT */
4512 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4513 ohbytes = 12; /* NT names only */
4515 ohbytes = 64; /* NT */
4517 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
4518 ohbytes += 26; /* Short name & length */
4520 if (searchFlags & 4) {
4521 ohbytes += 4; /* if resume key required */
4524 if (infoLevel != SMB_INFO_STANDARD
4525 && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
4526 && infoLevel != SMB_FIND_FILE_NAMES_INFO)
4527 ohbytes += 4; /* EASIZE */
4529 /* add header to name & term. null */
4530 orbytes = onbytes + ohbytes + 1;
4532 /* now, we round up the record to a 4 byte alignment,
4533 * and we make sure that we have enough room here for
4534 * even the aligned version (so we don't have to worry
4535 * about an * overflow when we pad things out below).
4536 * That's the reason for the alignment arithmetic below.
4538 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4539 align = (4 - (orbytes & 3)) & 3;
4542 if (orbytes + bytesInBuffer + align > maxReturnData) {
4543 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4548 /* this is one of the entries to use: it is not deleted
4549 * and it matches the star pattern we're looking for.
4550 * Put out the name, preceded by its length.
4552 /* First zero everything else */
4553 memset(origOp, 0, ohbytes);
4555 if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
4556 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4557 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4558 *((u_long *)(op + 8)) = onbytes;
4560 *((u_long *)(op + 60)) = onbytes;
4561 strcpy(origOp+ohbytes, dep->name);
4562 if (smb_StoreAnsiFilenames)
4563 CharToOem(origOp+ohbytes, origOp+ohbytes);
4565 /* Short name if requested and needed */
4566 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4567 if (NeedShortName) {
4568 strcpy(op + 70, shortName);
4569 if (smb_StoreAnsiFilenames)
4570 CharToOem(op + 70, op + 70);
4571 *(op + 68) = (char)(shortNameEnd - shortName);
4575 /* now, adjust the # of entries copied */
4578 /* NextEntryOffset and FileIndex */
4579 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4580 int entryOffset = orbytes + align;
4581 *((u_long *)op) = entryOffset;
4582 *((u_long *)(op+4)) = nextEntryCookie;
4585 /* now we emit the attribute. This is tricky, since
4586 * we need to really stat the file to find out what
4587 * type of entry we've got. Right now, we're copying
4588 * out data from a buffer, while holding the scp
4589 * locked, so it isn't really convenient to stat
4590 * something now. We'll put in a place holder
4591 * now, and make a second pass before returning this
4592 * to get the real attributes. So, we just skip the
4593 * data for now, and adjust it later. We allocate a
4594 * patch record to make it easy to find this point
4595 * later. The replay will happen at a time when it is
4596 * safe to unlock the directory.
4598 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4599 curPatchp = malloc(sizeof(*curPatchp));
4600 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4602 curPatchp->dptr = op;
4603 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4604 curPatchp->dptr += 8;
4606 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4607 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4610 curPatchp->flags = 0;
4612 curPatchp->fid.cell = scp->fid.cell;
4613 curPatchp->fid.volume = scp->fid.volume;
4614 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4615 curPatchp->fid.unique = ntohl(dep->fid.unique);
4618 curPatchp->dep = dep;
4621 if (searchFlags & 4)
4622 /* put out resume key */
4623 *((u_long *)origOp) = nextEntryCookie;
4625 /* Adjust byte ptr and count */
4626 origOp += orbytes; /* skip entire record */
4627 bytesInBuffer += orbytes;
4629 /* and pad the record out */
4630 while (--align >= 0) {
4634 } /* if we're including this name */
4635 else if (!starPattern &&
4637 dep->fid.vnode != 0 &&
4638 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4639 /* We were looking for exact matches, but here's an inexact one*/
4644 /* and adjust curOffset to be where the new cookie is */
4645 thyper.HighPart = 0;
4646 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4647 curOffset = LargeIntegerAdd(thyper, curOffset);
4648 } /* while copying data for dir listing */
4650 /* If we didn't get a star pattern, we did an exact match during the first pass.
4651 * If there were no exact matches found, we fail over to inexact matches by
4652 * marking the query as a star pattern (matches all case permutations), and
4653 * re-running the query.
4655 if (returnedNames == 0 && !starPattern && foundInexact) {
4656 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4661 /* release the mutex */
4662 lock_ReleaseMutex(&scp->mx);
4664 buf_Release(bufferp);
4666 /* apply and free last set of patches; if not doing a star match, this
4667 * will be empty, but better safe (and freeing everything) than sorry.
4669 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4672 /* now put out the final parameters */
4673 if (returnedNames == 0)
4675 if (p->opcode == 1) {
4677 outp->parmsp[0] = (unsigned short) dsp->cookie;
4678 outp->parmsp[1] = returnedNames;
4679 outp->parmsp[2] = eos;
4680 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4681 outp->parmsp[4] = 0;
4682 /* don't need last name to continue
4683 * search, cookie is enough. Normally,
4684 * this is the offset of the file name
4685 * of the last entry returned.
4687 outp->totalParms = 10; /* in bytes */
4691 outp->parmsp[0] = returnedNames;
4692 outp->parmsp[1] = eos;
4693 outp->parmsp[2] = 0; /* EAS error */
4694 outp->parmsp[3] = 0; /* last name, as above */
4695 outp->totalParms = 8; /* in bytes */
4698 /* return # of bytes in the buffer */
4699 outp->totalData = bytesInBuffer;
4701 /* Return error code if unsuccessful on first request */
4702 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4703 code = CM_ERROR_NOSUCHFILE;
4705 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
4706 p->opcode, dsp->cookie, returnedNames, code);
4708 /* if we're supposed to close the search after this request, or if
4709 * we're supposed to close the search if we're done, and we're done,
4710 * or if something went wrong, close the search.
4712 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4713 if ((searchFlags & 1) || (returnedNames == 0) ||
4714 ((searchFlags & 2) && eos) || code != 0)
4715 smb_DeleteDirSearch(dsp);
4717 smb_SendTran2Error(vcp, p, opx, code);
4719 smb_SendTran2Packet(vcp, outp, opx);
4721 smb_FreeTran2Packet(outp);
4722 smb_ReleaseDirSearch(dsp);
4723 cm_ReleaseSCache(scp);
4724 cm_ReleaseUser(userp);
4728 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4731 smb_dirSearch_t *dsp;
4733 dirHandle = smb_GetSMBParm(inp, 0);
4735 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4737 dsp = smb_FindDirSearch(dirHandle);
4740 return CM_ERROR_BADFD;
4742 /* otherwise, we have an FD to destroy */
4743 smb_DeleteDirSearch(dsp);
4744 smb_ReleaseDirSearch(dsp);
4746 /* and return results */
4747 smb_SetSMBDataLength(outp, 0);
4752 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4754 smb_SetSMBDataLength(outp, 0);
4758 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4765 cm_scache_t *dscp; /* dir we're dealing with */
4766 cm_scache_t *scp; /* file we're creating */
4768 int initialModeBits;
4778 int parmSlot; /* which parm we're dealing with */
4787 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4788 openFun = smb_GetSMBParm(inp, 8); /* open function */
4789 excl = ((openFun & 3) == 0);
4790 trunc = ((openFun & 3) == 2); /* truncate it */
4791 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4792 openAction = 0; /* tracks what we did */
4794 attributes = smb_GetSMBParm(inp, 5);
4795 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4797 /* compute initial mode bits based on read-only flag in attributes */
4798 initialModeBits = 0666;
4799 if (attributes & SMB_ATTR_READONLY)
4800 initialModeBits &= ~0222;
4802 pathp = smb_GetSMBData(inp, NULL);
4803 if (smb_StoreAnsiFilenames)
4804 OemToChar(pathp,pathp);
4806 spacep = inp->spacep;
4807 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4809 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4810 /* special case magic file name for receiving IOCTL requests
4811 * (since IOCTL calls themselves aren't getting through).
4814 osi_Log0(smb_logp, "IOCTL Open");
4817 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4818 smb_SetupIoctlFid(fidp, spacep);
4820 /* set inp->fid so that later read calls in same msg can find fid */
4821 inp->fid = fidp->fid;
4823 /* copy out remainder of the parms */
4825 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4827 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4828 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4829 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4830 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4831 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4832 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4833 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4834 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4836 /* and the final "always present" stuff */
4837 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4838 /* next write out the "unique" ID */
4839 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4840 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4841 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4842 smb_SetSMBDataLength(outp, 0);
4844 /* and clean up fid reference */
4845 smb_ReleaseFID(fidp);
4849 #ifdef DEBUG_VERBOSE
4851 char *hexp, *asciip;
4852 asciip = (lastNamep ? lastNamep : pathp );
4853 hexp = osi_HexifyString(asciip);
4854 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4858 userp = smb_GetUserFromVCP(vcp, inp);
4861 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4863 cm_ReleaseUser(userp);
4864 return CM_ERROR_NOSUCHPATH;
4866 code = cm_NameI(cm_data.rootSCachep, pathp,
4867 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4868 userp, tidPathp, &req, &scp);
4871 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4872 cm_ReleaseSCache(scp);
4873 cm_ReleaseUser(userp);
4874 if ( WANTS_DFS_PATHNAMES(inp) )
4875 return CM_ERROR_PATH_NOT_COVERED;
4877 return CM_ERROR_BADSHARENAME;
4879 #endif /* DFS_SUPPORT */
4882 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4883 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4884 userp, tidPathp, &req, &dscp);
4886 cm_ReleaseUser(userp);
4891 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4892 cm_ReleaseSCache(dscp);
4893 cm_ReleaseUser(userp);
4894 if ( WANTS_DFS_PATHNAMES(inp) )
4895 return CM_ERROR_PATH_NOT_COVERED;
4897 return CM_ERROR_BADSHARENAME;
4899 #endif /* DFS_SUPPORT */
4900 /* otherwise, scp points to the parent directory. Do a lookup,
4901 * and truncate the file if we find it, otherwise we create the
4908 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
4910 if (code && code != CM_ERROR_NOSUCHFILE) {
4911 cm_ReleaseSCache(dscp);
4912 cm_ReleaseUser(userp);
4917 /* if we get here, if code is 0, the file exists and is represented by
4918 * scp. Otherwise, we have to create it. The dir may be represented
4919 * by dscp, or we may have found the file directly. If code is non-zero,
4923 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
4925 if (dscp) cm_ReleaseSCache(dscp);
4926 cm_ReleaseSCache(scp);
4927 cm_ReleaseUser(userp);
4932 /* oops, file shouldn't be there */
4934 cm_ReleaseSCache(dscp);
4935 cm_ReleaseSCache(scp);
4936 cm_ReleaseUser(userp);
4937 return CM_ERROR_EXISTS;
4941 setAttr.mask = CM_ATTRMASK_LENGTH;
4942 setAttr.length.LowPart = 0;
4943 setAttr.length.HighPart = 0;
4944 code = cm_SetAttr(scp, &setAttr, userp, &req);
4945 openAction = 3; /* truncated existing file */
4947 else openAction = 1; /* found existing file */
4949 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
4950 /* don't create if not found */
4951 if (dscp) cm_ReleaseSCache(dscp);
4952 cm_ReleaseUser(userp);
4953 return CM_ERROR_NOSUCHFILE;
4956 osi_assert(dscp != NULL);
4957 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
4958 osi_LogSaveString(smb_logp, lastNamep));
4959 openAction = 2; /* created file */
4960 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4961 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
4962 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4966 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
4967 smb_NotifyChange(FILE_ACTION_ADDED,
4968 FILE_NOTIFY_CHANGE_FILE_NAME,
4969 dscp, lastNamep, NULL, TRUE);
4970 } else if (!excl && code == CM_ERROR_EXISTS) {
4971 /* not an exclusive create, and someone else tried
4972 * creating it already, then we open it anyway. We
4973 * don't bother retrying after this, since if this next
4974 * fails, that means that the file was deleted after we
4975 * started this call.
4977 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4981 setAttr.mask = CM_ATTRMASK_LENGTH;
4982 setAttr.length.LowPart = 0;
4983 setAttr.length.HighPart = 0;
4984 code = cm_SetAttr(scp, &setAttr, userp, &req);
4986 } /* lookup succeeded */
4990 /* we don't need this any longer */
4992 cm_ReleaseSCache(dscp);
4995 /* something went wrong creating or truncating the file */
4997 cm_ReleaseSCache(scp);
4998 cm_ReleaseUser(userp);
5002 /* make sure we're about to open a file */
5003 if (scp->fileType != CM_SCACHETYPE_FILE) {
5004 cm_ReleaseSCache(scp);
5005 cm_ReleaseUser(userp);
5006 return CM_ERROR_ISDIR;
5009 /* now all we have to do is open the file itself */
5010 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5014 lock_ObtainMutex(&fidp->mx);
5015 /* save a pointer to the vnode */
5018 fidp->userp = userp;
5020 /* compute open mode */
5022 fidp->flags |= SMB_FID_OPENREAD;
5023 if (openMode == 1 || openMode == 2)
5024 fidp->flags |= SMB_FID_OPENWRITE;
5026 /* remember if the file was newly created */
5028 fidp->flags |= SMB_FID_CREATED;
5030 lock_ReleaseMutex(&fidp->mx);
5031 smb_ReleaseFID(fidp);
5033 cm_Open(scp, 0, userp);
5035 /* set inp->fid so that later read calls in same msg can find fid */
5036 inp->fid = fidp->fid;
5038 /* copy out remainder of the parms */
5040 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5041 lock_ObtainMutex(&scp->mx);
5043 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5044 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5045 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5046 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5047 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5048 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5049 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5050 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5051 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5053 /* and the final "always present" stuff */
5054 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5055 /* next write out the "unique" ID */
5056 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5057 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5058 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5059 lock_ReleaseMutex(&scp->mx);
5060 smb_SetSMBDataLength(outp, 0);
5062 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5064 cm_ReleaseUser(userp);
5065 /* leave scp held since we put it in fidp->scp */
5069 static void smb_GetLockParams(unsigned char LockType,
5071 unsigned int * ppid,
5072 LARGE_INTEGER * pOffset,
5073 LARGE_INTEGER * pLength)
5075 if (LockType & LOCKING_ANDX_LARGE_FILES) {
5077 *ppid = *((USHORT *) *buf);
5078 pOffset->HighPart = *((LONG *)(*buf + 4));
5079 pOffset->LowPart = *((DWORD *)(*buf + 8));
5080 pLength->HighPart = *((LONG *)(*buf + 12));
5081 pLength->LowPart = *((DWORD *)(*buf + 16));
5085 /* Not Large Files */
5086 *ppid = *((USHORT *) *buf);
5087 pOffset->HighPart = 0;
5088 pOffset->LowPart = *((DWORD *)(*buf + 2));
5089 pLength->HighPart = 0;
5090 pLength->LowPart = *((DWORD *)(*buf + 6));
5095 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5102 unsigned char LockType;
5103 unsigned short NumberOfUnlocks, NumberOfLocks;
5107 LARGE_INTEGER LOffset, LLength;
5108 smb_waitingLockRequest_t *wlRequest = NULL;
5109 cm_file_lock_t *lockp;
5117 fid = smb_GetSMBParm(inp, 2);
5118 fid = smb_ChainFID(fid, inp);
5120 fidp = smb_FindFID(vcp, fid, 0);
5122 return CM_ERROR_BADFD;
5124 lock_ObtainMutex(&fidp->mx);
5125 if (fidp->flags & SMB_FID_IOCTL) {
5126 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
5127 lock_ReleaseMutex(&fidp->mx);
5128 smb_ReleaseFID(fidp);
5129 return CM_ERROR_BADFD;
5133 lock_ReleaseMutex(&fidp->mx);
5135 /* set inp->fid so that later read calls in same msg can find fid */
5138 userp = smb_GetUserFromVCP(vcp, inp);
5141 lock_ObtainMutex(&scp->mx);
5142 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5143 CM_SCACHESYNC_NEEDCALLBACK
5144 | CM_SCACHESYNC_GETSTATUS
5145 | CM_SCACHESYNC_LOCK);
5147 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
5151 LockType = smb_GetSMBParm(inp, 3) & 0xff;
5152 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
5153 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
5154 NumberOfLocks = smb_GetSMBParm(inp, 7);
5156 if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
5157 (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
5159 /* We don't support these requests. Apparently, we can safely
5160 not deal with them too. */
5161 osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
5162 ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
5163 "LOCKING_ANDX_CANCEL_LOCK":
5164 "LOCKING_ANDX_CHANGE_LOCKTYPE"));
5165 /* No need to call osi_LogSaveString since these are string
5168 code = CM_ERROR_BADOP;
5173 op = smb_GetSMBData(inp, NULL);
5175 for (i=0; i<NumberOfUnlocks; i++) {
5176 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5178 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5180 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
5188 for (i=0; i<NumberOfLocks; i++) {
5189 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5191 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5193 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
5194 userp, &req, &lockp);
5196 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
5197 smb_waitingLock_t * wLock;
5199 /* Put on waiting list */
5200 if(wlRequest == NULL) {
5204 LARGE_INTEGER tOffset, tLength;
5206 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
5208 osi_assert(wlRequest != NULL);
5210 wlRequest->vcp = vcp;
5212 wlRequest->scp = scp;
5214 wlRequest->inp = smb_CopyPacket(inp);
5215 wlRequest->outp = smb_CopyPacket(outp);
5216 wlRequest->lockType = LockType;
5217 wlRequest->timeRemaining = Timeout;
5218 wlRequest->locks = NULL;
5220 /* The waiting lock request needs to have enough
5221 information to undo all the locks in the request.
5222 We do the following to store info about locks that
5223 have already been granted. Sure, we can get most
5224 of the info from the packet, but the packet doesn't
5225 hold the result of cm_Lock call. In practice we
5226 only receive packets with one or two locks, so we
5227 are only wasting a few bytes here and there and
5228 only for a limited period of time until the waiting
5229 lock times out or is freed. */
5231 for(opt = op_locks, j=i; j > 0; j--) {
5232 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
5234 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5236 wLock = malloc(sizeof(smb_waitingLock_t));
5238 osi_assert(wLock != NULL);
5241 wLock->LOffset = tOffset;
5242 wLock->LLength = tLength;
5243 wLock->lockp = NULL;
5244 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
5245 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5250 wLock = malloc(sizeof(smb_waitingLock_t));
5252 osi_assert(wLock != NULL);
5255 wLock->LOffset = LOffset;
5256 wLock->LLength = LLength;
5257 wLock->lockp = lockp;
5258 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
5259 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5262 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
5270 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
5277 /* Since something went wrong with the lock number i, we now
5278 have to go ahead and release any locks acquired before the
5279 failure. All locks before lock number i (of which there
5280 are i of them) have either been successful or are waiting.
5281 Either case requires calling cm_Unlock(). */
5283 /* And purge the waiting lock */
5284 if(wlRequest != NULL) {
5285 smb_waitingLock_t * wl;
5286 smb_waitingLock_t * wlNext;
5289 for(wl = wlRequest->locks; wl; wl = wlNext) {
5291 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
5293 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
5296 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
5298 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
5301 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
5306 smb_ReleaseVC(wlRequest->vcp);
5307 cm_ReleaseSCache(wlRequest->scp);
5308 smb_FreePacket(wlRequest->inp);
5309 smb_FreePacket(wlRequest->outp);
5318 if (wlRequest != NULL) {
5320 lock_ObtainWrite(&smb_globalLock);
5321 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
5323 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
5324 lock_ReleaseWrite(&smb_globalLock);
5326 /* don't send reply immediately */
5327 outp->flags |= SMB_PACKETFLAG_NOSEND;
5330 smb_SetSMBDataLength(outp, 0);
5334 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5337 lock_ReleaseMutex(&scp->mx);
5338 cm_ReleaseSCache(scp);
5339 cm_ReleaseUser(userp);
5340 smb_ReleaseFID(fidp);
5345 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5351 afs_uint32 searchTime;
5357 fid = smb_GetSMBParm(inp, 0);
5358 fid = smb_ChainFID(fid, inp);
5360 fidp = smb_FindFID(vcp, fid, 0);
5362 return CM_ERROR_BADFD;
5364 lock_ObtainMutex(&fidp->mx);
5365 if (fidp->flags & SMB_FID_IOCTL) {
5366 lock_ReleaseMutex(&fidp->mx);
5367 smb_ReleaseFID(fidp);
5368 return CM_ERROR_BADFD;
5372 lock_ReleaseMutex(&fidp->mx);
5374 userp = smb_GetUserFromVCP(vcp, inp);
5377 /* otherwise, stat the file */
5378 lock_ObtainMutex(&scp->mx);
5379 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5380 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5384 /* decode times. We need a search time, but the response to this
5385 * call provides the date first, not the time, as returned in the
5386 * searchTime variable. So we take the high-order bits first.
5388 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
5389 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
5390 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
5391 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
5392 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
5393 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
5394 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
5396 /* now handle file size and allocation size */
5397 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
5398 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
5399 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
5400 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
5402 /* file attribute */
5403 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
5405 /* and finalize stuff */
5406 smb_SetSMBDataLength(outp, 0);
5410 lock_ReleaseMutex(&scp->mx);
5411 cm_ReleaseSCache(scp);
5412 cm_ReleaseUser(userp);
5413 smb_ReleaseFID(fidp);
5417 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5423 afs_uint32 searchTime;
5431 fid = smb_GetSMBParm(inp, 0);
5432 fid = smb_ChainFID(fid, inp);
5434 fidp = smb_FindFID(vcp, fid, 0);
5436 return CM_ERROR_BADFD;
5438 lock_ObtainMutex(&fidp->mx);
5439 if (fidp->flags & SMB_FID_IOCTL) {
5440 lock_ReleaseMutex(&fidp->mx);
5441 smb_ReleaseFID(fidp);
5442 return CM_ERROR_BADFD;
5446 lock_ReleaseMutex(&fidp->mx);
5448 userp = smb_GetUserFromVCP(vcp, inp);
5451 /* now prepare to call cm_setattr. This message only sets various times,
5452 * and AFS only implements mtime, and we'll set the mtime if that's
5453 * requested. The others we'll ignore.
5455 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
5457 if (searchTime != 0) {
5458 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
5460 if ( unixTime != -1 ) {
5461 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
5462 attrs.clientModTime = unixTime;
5463 code = cm_SetAttr(scp, &attrs, userp, &req);
5465 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
5467 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
5473 cm_ReleaseSCache(scp);
5474 cm_ReleaseUser(userp);
5475 smb_ReleaseFID(fidp);
5479 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5482 long count, written = 0, total_written = 0;
5489 int inDataBlockCount;
5491 fd = smb_GetSMBParm(inp, 2);
5492 count = smb_GetSMBParm(inp, 10);
5494 offset.HighPart = 0;
5495 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5497 if (*inp->wctp == 14) {
5498 /* we have a request with 64-bit file offsets */
5499 #ifdef AFS_LARGEFILES
5500 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
5502 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
5504 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
5505 /* we shouldn't have received this op if we didn't specify
5506 largefile support */
5507 return CM_ERROR_BADOP;
5512 op = inp->data + smb_GetSMBParm(inp, 11);
5513 inDataBlockCount = count;
5515 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
5516 fd, offset.HighPart, offset.LowPart, count);
5518 fd = smb_ChainFID(fd, inp);
5519 fidp = smb_FindFID(vcp, fd, 0);
5521 return CM_ERROR_BADFD;
5523 lock_ObtainMutex(&fidp->mx);
5524 if (fidp->flags & SMB_FID_IOCTL) {
5525 lock_ReleaseMutex(&fidp->mx);
5526 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
5527 smb_ReleaseFID(fidp);
5530 lock_ReleaseMutex(&fidp->mx);
5531 userp = smb_GetUserFromVCP(vcp, inp);
5533 /* special case: 0 bytes transferred means there is no data
5534 transferred. A slight departure from SMB_COM_WRITE where this
5535 means that we are supposed to truncate the file at this
5540 LARGE_INTEGER LOffset;
5541 LARGE_INTEGER LLength;
5543 pid = ((smb_t *) inp)->pid;
5544 key = cm_GenerateKey(vcp->vcID, pid, fd);
5546 LOffset.HighPart = offset.HighPart;
5547 LOffset.LowPart = offset.LowPart;
5548 LLength.HighPart = 0;
5549 LLength.LowPart = count;
5551 lock_ObtainMutex(&fidp->scp->mx);
5552 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
5553 lock_ReleaseMutex(&fidp->scp->mx);
5560 * Work around bug in NT client
5562 * When copying a file, the NT client should first copy the data,
5563 * then copy the last write time. But sometimes the NT client does
5564 * these in the wrong order, so the data copies would inadvertently
5565 * cause the last write time to be overwritten. We try to detect this,
5566 * and don't set client mod time if we think that would go against the
5569 lock_ObtainMutex(&fidp->mx);
5570 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5571 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5572 fidp->scp->clientModTime = time(NULL);
5574 lock_ReleaseMutex(&fidp->mx);
5577 while ( code == 0 && count > 0 ) {
5579 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5581 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5583 if (code == 0 && written == 0)
5584 code = CM_ERROR_PARTIALWRITE;
5586 offset = LargeIntegerAdd(offset,
5587 ConvertLongToLargeInteger(written));
5589 total_written += written;
5595 /* slots 0 and 1 are reserved for request chaining and will be
5596 filled in when we return. */
5597 smb_SetSMBParm(outp, 2, total_written);
5598 smb_SetSMBParm(outp, 3, 0); /* reserved */
5599 smb_SetSMBParm(outp, 4, 0); /* reserved */
5600 smb_SetSMBParm(outp, 5, 0); /* reserved */
5601 smb_SetSMBDataLength(outp, 0);
5604 smb_ReleaseFID(fidp);
5605 cm_ReleaseUser(userp);
5610 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5614 long finalCount = 0;
5623 fd = smb_GetSMBParm(inp, 2);
5624 count = smb_GetSMBParm(inp, 5);
5625 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5627 if (*inp->wctp == 12) {
5628 /* a request with 64-bit offsets */
5629 #ifdef AFS_LARGEFILES
5630 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
5632 if (LargeIntegerLessThanZero(offset)) {
5633 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
5634 offset.HighPart, offset.LowPart);
5635 return CM_ERROR_BADSMB;
5638 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
5639 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
5640 return CM_ERROR_BADSMB;
5642 offset.HighPart = 0;
5646 offset.HighPart = 0;
5649 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
5650 fd, offset.HighPart, offset.LowPart, count);
5652 fd = smb_ChainFID(fd, inp);
5653 fidp = smb_FindFID(vcp, fd, 0);
5655 return CM_ERROR_BADFD;
5658 pid = ((smb_t *) inp)->pid;
5659 key = cm_GenerateKey(vcp->vcID, pid, fd);
5661 LARGE_INTEGER LOffset, LLength;
5663 LOffset.HighPart = offset.HighPart;
5664 LOffset.LowPart = offset.LowPart;
5665 LLength.HighPart = 0;
5666 LLength.LowPart = count;
5668 lock_ObtainMutex(&fidp->scp->mx);
5669 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
5670 lock_ReleaseMutex(&fidp->scp->mx);
5674 smb_ReleaseFID(fidp);
5678 /* set inp->fid so that later read calls in same msg can find fid */
5681 lock_ObtainMutex(&fidp->mx);
5682 if (fidp->flags & SMB_FID_IOCTL) {
5683 lock_ReleaseMutex(&fidp->mx);
5684 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
5685 smb_ReleaseFID(fidp);
5688 lock_ReleaseMutex(&fidp->mx);
5690 userp = smb_GetUserFromVCP(vcp, inp);
5692 /* 0 and 1 are reserved for request chaining, were setup by our caller,
5693 * and will be further filled in after we return.
5695 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
5696 smb_SetSMBParm(outp, 3, 0); /* resvd */
5697 smb_SetSMBParm(outp, 4, 0); /* resvd */
5698 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
5699 /* fill in #6 when we have all the parameters' space reserved */
5700 smb_SetSMBParm(outp, 7, 0); /* resv'd */
5701 smb_SetSMBParm(outp, 8, 0); /* resv'd */
5702 smb_SetSMBParm(outp, 9, 0); /* resv'd */
5703 smb_SetSMBParm(outp, 10, 0); /* resv'd */
5704 smb_SetSMBParm(outp, 11, 0); /* reserved */
5706 /* get op ptr after putting in the parms, since otherwise we don't
5707 * know where the data really is.
5709 op = smb_GetSMBData(outp, NULL);
5711 /* now fill in offset from start of SMB header to first data byte (to op) */
5712 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
5714 /* set the packet data length the count of the # of bytes */
5715 smb_SetSMBDataLength(outp, count);
5718 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5720 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5723 /* fix some things up */
5724 smb_SetSMBParm(outp, 5, finalCount);
5725 smb_SetSMBDataLength(outp, finalCount);
5727 smb_ReleaseFID(fidp);
5729 cm_ReleaseUser(userp);
5734 * Values for createDisp, copied from NTDDK.H
5736 #define FILE_SUPERSEDE 0 // (???)
5737 #define FILE_OPEN 1 // (open)
5738 #define FILE_CREATE 2 // (exclusive)
5739 #define FILE_OPEN_IF 3 // (non-exclusive)
5740 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
5741 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
5744 #define REQUEST_OPLOCK 2
5745 #define REQUEST_BATCH_OPLOCK 4
5746 #define OPEN_DIRECTORY 8
5747 #define EXTENDED_RESPONSE_REQUIRED 0x10
5749 /* CreateOptions field. */
5750 #define FILE_DIRECTORY_FILE 0x0001
5751 #define FILE_WRITE_THROUGH 0x0002
5752 #define FILE_SEQUENTIAL_ONLY 0x0004
5753 #define FILE_NON_DIRECTORY_FILE 0x0040
5754 #define FILE_NO_EA_KNOWLEDGE 0x0200
5755 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
5756 #define FILE_RANDOM_ACCESS 0x0800
5757 #define FILE_DELETE_ON_CLOSE 0x1000
5758 #define FILE_OPEN_BY_FILE_ID 0x2000
5760 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5762 char *pathp, *realPathp;
5766 cm_scache_t *dscp; /* parent dir */
5767 cm_scache_t *scp; /* file to create or open */
5768 cm_scache_t *targetScp; /* if scp is a symlink */
5772 unsigned short nameLength;
5774 unsigned int requestOpLock;
5775 unsigned int requestBatchOpLock;
5776 unsigned int mustBeDir;
5777 unsigned int extendedRespRequired;
5778 unsigned int treeCreate;
5780 unsigned int desiredAccess;
5781 unsigned int extAttributes;
5782 unsigned int createDisp;
5783 unsigned int createOptions;
5784 unsigned int shareAccess;
5785 int initialModeBits;
5786 unsigned short baseFid;
5787 smb_fid_t *baseFidp;
5789 cm_scache_t *baseDirp;
5790 unsigned short openAction;
5802 /* This code is very long and has a lot of if-then-else clauses
5803 * scp and dscp get reused frequently and we need to ensure that
5804 * we don't lose a reference. Start by ensuring that they are NULL.
5811 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
5812 flags = smb_GetSMBOffsetParm(inp, 3, 1)
5813 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
5814 requestOpLock = flags & REQUEST_OPLOCK;
5815 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
5816 mustBeDir = flags & OPEN_DIRECTORY;
5817 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
5820 * Why all of a sudden 32-bit FID?
5821 * We will reject all bits higher than 16.
5823 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
5824 return CM_ERROR_INVAL;
5825 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
5826 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
5827 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
5828 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
5829 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
5830 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
5831 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
5832 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
5833 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
5834 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
5835 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
5837 /* mustBeDir is never set; createOptions directory bit seems to be
5840 if (createOptions & FILE_DIRECTORY_FILE)
5842 else if (createOptions & FILE_NON_DIRECTORY_FILE)
5848 * compute initial mode bits based on read-only flag in
5849 * extended attributes
5851 initialModeBits = 0666;
5852 if (extAttributes & SMB_ATTR_READONLY)
5853 initialModeBits &= ~0222;
5855 pathp = smb_GetSMBData(inp, NULL);
5856 /* Sometimes path is not null-terminated, so we make a copy. */
5857 realPathp = malloc(nameLength+1);
5858 memcpy(realPathp, pathp, nameLength);
5859 realPathp[nameLength] = 0;
5860 if (smb_StoreAnsiFilenames)
5861 OemToChar(realPathp,realPathp);
5863 spacep = inp->spacep;
5864 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5866 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
5867 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
5868 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
5870 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5871 /* special case magic file name for receiving IOCTL requests
5872 * (since IOCTL calls themselves aren't getting through).
5874 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5875 smb_SetupIoctlFid(fidp, spacep);
5876 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
5878 /* set inp->fid so that later read calls in same msg can find fid */
5879 inp->fid = fidp->fid;
5883 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5884 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5885 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
5887 memset(&ft, 0, sizeof(ft));
5888 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5889 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5890 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5891 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5892 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
5893 sz.HighPart = 0x7fff; sz.LowPart = 0;
5894 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
5895 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
5896 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
5897 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
5898 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
5899 smb_SetSMBDataLength(outp, 0);
5901 /* clean up fid reference */
5902 smb_ReleaseFID(fidp);
5907 #ifdef DEBUG_VERBOSE
5909 char *hexp, *asciip;
5910 asciip = (lastNamep? lastNamep : realPathp);
5911 hexp = osi_HexifyString( asciip );
5912 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
5917 userp = smb_GetUserFromVCP(vcp, inp);
5919 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
5921 return CM_ERROR_INVAL;
5926 baseDirp = cm_data.rootSCachep;
5927 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5928 if (code == CM_ERROR_TIDIPC) {
5929 /* Attempt to use a TID allocated for IPC. The client
5930 * is probably looking for DCE RPC end points which we
5931 * don't support OR it could be looking to make a DFS
5934 osi_Log0(smb_logp, "NTCreateX received IPC TID");
5937 cm_ReleaseUser(userp);
5938 return CM_ERROR_NOSUCHFILE;
5939 #endif /* DFS_SUPPORT */
5942 baseFidp = smb_FindFID(vcp, baseFid, 0);
5944 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
5946 cm_ReleaseUser(userp);
5947 return CM_ERROR_INVAL;
5949 baseDirp = baseFidp->scp;
5953 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
5955 /* compute open mode */
5957 if (desiredAccess & DELETE)
5958 fidflags |= SMB_FID_OPENDELETE;
5959 if (desiredAccess & AFS_ACCESS_READ)
5960 fidflags |= SMB_FID_OPENREAD;
5961 if (desiredAccess & AFS_ACCESS_WRITE)
5962 fidflags |= SMB_FID_OPENWRITE;
5963 if (createOptions & FILE_DELETE_ON_CLOSE)
5964 fidflags |= SMB_FID_DELONCLOSE;
5966 /* and the share mode */
5967 if (shareAccess & FILE_SHARE_READ)
5968 fidflags |= SMB_FID_SHARE_READ;
5969 if (shareAccess & FILE_SHARE_WRITE)
5970 fidflags |= SMB_FID_SHARE_WRITE;
5972 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
5975 /* For an exclusive create, we want to do a case sensitive match for the last component. */
5976 if ( createDisp == FILE_CREATE ||
5977 createDisp == FILE_OVERWRITE ||
5978 createDisp == FILE_OVERWRITE_IF) {
5979 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5980 userp, tidPathp, &req, &dscp);
5983 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5984 cm_ReleaseSCache(dscp);
5985 cm_ReleaseUser(userp);
5988 smb_ReleaseFID(baseFidp);
5989 if ( WANTS_DFS_PATHNAMES(inp) )
5990 return CM_ERROR_PATH_NOT_COVERED;
5992 return CM_ERROR_BADSHARENAME;
5994 #endif /* DFS_SUPPORT */
5995 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5997 if (code == CM_ERROR_NOSUCHFILE) {
5998 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
5999 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6000 if (code == 0 && realDirFlag == 1) {
6001 cm_ReleaseSCache(scp);
6002 cm_ReleaseSCache(dscp);
6003 cm_ReleaseUser(userp);
6006 smb_ReleaseFID(baseFidp);
6007 return CM_ERROR_EXISTS;
6011 /* we have both scp and dscp */
6013 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6014 userp, tidPathp, &req, &scp);
6016 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6017 cm_ReleaseSCache(scp);
6018 cm_ReleaseUser(userp);
6021 smb_ReleaseFID(baseFidp);
6022 if ( WANTS_DFS_PATHNAMES(inp) )
6023 return CM_ERROR_PATH_NOT_COVERED;
6025 return CM_ERROR_BADSHARENAME;
6027 #endif /* DFS_SUPPORT */
6028 /* we might have scp but not dscp */
6034 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6035 /* look up parent directory */
6036 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
6037 * the immediate parent. We have to work our way up realPathp until we hit something that we
6041 /* we might or might not have scp */
6047 code = cm_NameI(baseDirp, spacep->data,
6048 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6049 userp, tidPathp, &req, &dscp);
6052 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6054 cm_ReleaseSCache(scp);
6055 cm_ReleaseSCache(dscp);
6056 cm_ReleaseUser(userp);
6059 smb_ReleaseFID(baseFidp);
6060 if ( WANTS_DFS_PATHNAMES(inp) )
6061 return CM_ERROR_PATH_NOT_COVERED;
6063 return CM_ERROR_BADSHARENAME;
6065 #endif /* DFS_SUPPORT */
6068 (tp = strrchr(spacep->data,'\\')) &&
6069 (createDisp == FILE_CREATE) &&
6070 (realDirFlag == 1)) {
6073 treeStartp = realPathp + (tp - spacep->data);
6075 if (*tp && !smb_IsLegalFilename(tp)) {
6077 smb_ReleaseFID(baseFidp);
6078 cm_ReleaseUser(userp);
6081 cm_ReleaseSCache(scp);
6082 return CM_ERROR_BADNTFILENAME;
6086 } while (dscp == NULL && code == 0);
6090 /* we might have scp and we might have dscp */
6093 smb_ReleaseFID(baseFidp);
6096 osi_Log0(smb_logp,"NTCreateX parent not found");
6098 cm_ReleaseSCache(scp);
6100 cm_ReleaseSCache(dscp);
6101 cm_ReleaseUser(userp);
6106 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
6107 /* A file exists where we want a directory. */
6109 cm_ReleaseSCache(scp);
6110 cm_ReleaseSCache(dscp);
6111 cm_ReleaseUser(userp);
6113 return CM_ERROR_EXISTS;
6117 lastNamep = realPathp;
6121 if (!smb_IsLegalFilename(lastNamep)) {
6123 cm_ReleaseSCache(scp);
6125 cm_ReleaseSCache(dscp);
6126 cm_ReleaseUser(userp);
6128 return CM_ERROR_BADNTFILENAME;
6131 if (!foundscp && !treeCreate) {
6132 if ( createDisp == FILE_CREATE ||
6133 createDisp == FILE_OVERWRITE ||
6134 createDisp == FILE_OVERWRITE_IF)
6136 code = cm_Lookup(dscp, lastNamep,
6137 CM_FLAG_FOLLOW, userp, &req, &scp);
6139 code = cm_Lookup(dscp, lastNamep,
6140 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6143 if (code && code != CM_ERROR_NOSUCHFILE) {
6145 cm_ReleaseSCache(dscp);
6146 cm_ReleaseUser(userp);
6151 /* we have scp and dscp */
6153 /* we have scp but not dscp */
6155 smb_ReleaseFID(baseFidp);
6158 /* if we get here, if code is 0, the file exists and is represented by
6159 * scp. Otherwise, we have to create it. The dir may be represented
6160 * by dscp, or we may have found the file directly. If code is non-zero,
6163 if (code == 0 && !treeCreate) {
6164 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req);
6167 cm_ReleaseSCache(dscp);
6169 cm_ReleaseSCache(scp);
6170 cm_ReleaseUser(userp);
6175 if (createDisp == FILE_CREATE) {
6176 /* oops, file shouldn't be there */
6178 cm_ReleaseSCache(dscp);
6180 cm_ReleaseSCache(scp);
6181 cm_ReleaseUser(userp);
6183 return CM_ERROR_EXISTS;
6186 if ( createDisp == FILE_OVERWRITE ||
6187 createDisp == FILE_OVERWRITE_IF) {
6189 setAttr.mask = CM_ATTRMASK_LENGTH;
6190 setAttr.length.LowPart = 0;
6191 setAttr.length.HighPart = 0;
6192 /* now watch for a symlink */
6194 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6196 osi_assert(dscp != NULL);
6197 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6199 /* we have a more accurate file to use (the
6200 * target of the symbolic link). Otherwise,
6201 * we'll just use the symlink anyway.
6203 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6205 cm_ReleaseSCache(scp);
6209 code = cm_SetAttr(scp, &setAttr, userp, &req);
6210 openAction = 3; /* truncated existing file */
6213 openAction = 1; /* found existing file */
6215 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6216 /* don't create if not found */
6218 cm_ReleaseSCache(dscp);
6220 cm_ReleaseSCache(scp);
6221 cm_ReleaseUser(userp);
6223 return CM_ERROR_NOSUCHFILE;
6224 } else if (realDirFlag == 0 || realDirFlag == -1) {
6225 osi_assert(dscp != NULL);
6226 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
6227 osi_LogSaveString(smb_logp, lastNamep));
6228 openAction = 2; /* created file */
6229 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6230 setAttr.clientModTime = time(NULL);
6231 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
6234 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6235 smb_NotifyChange(FILE_ACTION_ADDED,
6236 FILE_NOTIFY_CHANGE_FILE_NAME,
6237 dscp, lastNamep, NULL, TRUE);
6238 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6239 /* Not an exclusive create, and someone else tried
6240 * creating it already, then we open it anyway. We
6241 * don't bother retrying after this, since if this next
6242 * fails, that means that the file was deleted after we
6243 * started this call.
6245 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6248 if (createDisp == FILE_OVERWRITE_IF) {
6249 setAttr.mask = CM_ATTRMASK_LENGTH;
6250 setAttr.length.LowPart = 0;
6251 setAttr.length.HighPart = 0;
6253 /* now watch for a symlink */
6255 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6257 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6259 /* we have a more accurate file to use (the
6260 * target of the symbolic link). Otherwise,
6261 * we'll just use the symlink anyway.
6263 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6265 cm_ReleaseSCache(scp);
6269 code = cm_SetAttr(scp, &setAttr, userp, &req);
6271 } /* lookup succeeded */
6275 char *cp; /* This component */
6276 int clen = 0; /* length of component */
6277 cm_scache_t *tscp1, *tscp2;
6280 /* create directory */
6282 treeStartp = lastNamep;
6283 osi_assert(dscp != NULL);
6284 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
6285 osi_LogSaveString(smb_logp, treeStartp));
6286 openAction = 2; /* created directory */
6288 /* if the request is to create the root directory
6289 * it will appear as a directory name of the nul-string
6290 * and a code of CM_ERROR_NOSUCHFILE
6292 if ( !*treeStartp && code == CM_ERROR_NOSUCHFILE)
6293 code = CM_ERROR_EXISTS;
6295 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6296 setAttr.clientModTime = time(NULL);
6301 cm_HoldSCache(tscp1);
6305 tp = strchr(pp, '\\');
6308 clen = (int)strlen(cp);
6309 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
6311 clen = (int)(tp - pp);
6312 strncpy(cp,pp,clen);
6319 continue; /* the supplied path can't have consecutive slashes either , but */
6321 /* cp is the next component to be created. */
6322 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
6323 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
6324 smb_NotifyChange(FILE_ACTION_ADDED,
6325 FILE_NOTIFY_CHANGE_DIR_NAME,
6326 tscp1, cp, NULL, TRUE);
6328 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6329 /* Not an exclusive create, and someone else tried
6330 * creating it already, then we open it anyway. We
6331 * don't bother retrying after this, since if this next
6332 * fails, that means that the file was deleted after we
6333 * started this call.
6335 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
6336 userp, &req, &tscp2);
6341 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
6342 cm_ReleaseSCache(tscp1);
6343 tscp1 = tscp2; /* Newly created directory will be next parent */
6344 /* the hold is transfered to tscp1 from tscp2 */
6349 cm_ReleaseSCache(dscp);
6352 cm_ReleaseSCache(scp);
6355 * if we get here and code == 0, then scp is the last directory created, and dscp is the
6361 /* something went wrong creating or truncating the file */
6363 cm_ReleaseSCache(scp);
6365 cm_ReleaseSCache(dscp);
6366 cm_ReleaseUser(userp);
6371 /* make sure we have file vs. dir right (only applies for single component case) */
6372 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
6373 /* now watch for a symlink */
6375 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6376 cm_scache_t * targetScp = 0;
6377 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6379 /* we have a more accurate file to use (the
6380 * target of the symbolic link). Otherwise,
6381 * we'll just use the symlink anyway.
6383 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
6384 cm_ReleaseSCache(scp);
6389 if (scp->fileType != CM_SCACHETYPE_FILE) {
6391 cm_ReleaseSCache(dscp);
6392 cm_ReleaseSCache(scp);
6393 cm_ReleaseUser(userp);
6395 return CM_ERROR_ISDIR;
6399 /* (only applies to single component case) */
6400 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
6401 cm_ReleaseSCache(scp);
6403 cm_ReleaseSCache(dscp);
6404 cm_ReleaseUser(userp);
6406 return CM_ERROR_NOTDIR;
6409 /* open the file itself */
6410 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6413 /* save a reference to the user */
6415 fidp->userp = userp;
6417 /* If we are restricting sharing, we should do so with a suitable
6419 if (scp->fileType == CM_SCACHETYPE_FILE &&
6420 !(fidflags & SMB_FID_SHARE_WRITE)) {
6422 LARGE_INTEGER LOffset, LLength;
6425 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
6426 LOffset.LowPart = SMB_FID_QLOCK_LOW;
6427 LLength.HighPart = 0;
6428 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
6430 if (fidflags & SMB_FID_SHARE_READ) {
6431 sLockType = LOCKING_ANDX_SHARED_LOCK;
6436 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
6438 lock_ObtainMutex(&scp->mx);
6439 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
6440 lock_ReleaseMutex(&scp->mx);
6443 /* shouldn't this be smb_CloseFID() fidp->flags = SMB_FID_DELETE; */
6444 smb_CloseFID(vcp, fidp, NULL, 0);
6445 smb_ReleaseFID(fidp);
6447 cm_ReleaseSCache(scp);
6449 cm_ReleaseSCache(dscp);
6450 cm_ReleaseUser(userp);
6457 lock_ObtainMutex(&fidp->mx);
6458 /* save a pointer to the vnode */
6459 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
6461 fidp->flags = fidflags;
6463 /* remember if the file was newly created */
6465 fidp->flags |= SMB_FID_CREATED;
6467 /* save parent dir and pathname for delete or change notification */
6468 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
6469 fidp->flags |= SMB_FID_NTOPEN;
6470 fidp->NTopen_dscp = dscp;
6471 cm_HoldSCache(dscp);
6472 fidp->NTopen_pathp = strdup(lastNamep);
6474 fidp->NTopen_wholepathp = realPathp;
6475 lock_ReleaseMutex(&fidp->mx);
6477 /* we don't need this any longer */
6479 cm_ReleaseSCache(dscp);
6483 cm_Open(scp, 0, userp);
6485 /* set inp->fid so that later read calls in same msg can find fid */
6486 inp->fid = fidp->fid;
6490 lock_ObtainMutex(&scp->mx);
6491 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6492 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6493 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
6494 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6495 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6496 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6497 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6498 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6499 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
6501 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6502 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6503 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6504 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6505 smb_SetSMBParmByte(outp, parmSlot,
6506 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
6507 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
6508 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
6509 lock_ReleaseMutex(&scp->mx);
6510 smb_SetSMBDataLength(outp, 0);
6512 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
6513 osi_LogSaveString(smb_logp, realPathp));
6515 smb_ReleaseFID(fidp);
6517 cm_ReleaseUser(userp);
6519 /* Can't free realPathp if we get here since
6520 fidp->NTopen_wholepathp is pointing there */
6522 /* leave scp held since we put it in fidp->scp */
6527 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
6528 * Instead, ultimately, would like to use a subroutine for common code.
6530 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6532 char *pathp, *realPathp;
6536 cm_scache_t *dscp; /* parent dir */
6537 cm_scache_t *scp; /* file to create or open */
6538 cm_scache_t *targetScp; /* if scp is a symlink */
6541 unsigned long nameLength;
6543 unsigned int requestOpLock;
6544 unsigned int requestBatchOpLock;
6545 unsigned int mustBeDir;
6546 unsigned int extendedRespRequired;
6548 unsigned int desiredAccess;
6549 #ifdef DEBUG_VERBOSE
6550 unsigned int allocSize;
6552 unsigned int shareAccess;
6553 unsigned int extAttributes;
6554 unsigned int createDisp;
6555 #ifdef DEBUG_VERBOSE
6558 unsigned int createOptions;
6559 int initialModeBits;
6560 unsigned short baseFid;
6561 smb_fid_t *baseFidp;
6563 cm_scache_t *baseDirp;
6564 unsigned short openAction;
6570 int parmOffset, dataOffset;
6582 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6583 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6584 parmp = inp->data + parmOffset;
6585 lparmp = (ULONG *) parmp;
6588 requestOpLock = flags & REQUEST_OPLOCK;
6589 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6590 mustBeDir = flags & OPEN_DIRECTORY;
6591 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6594 * Why all of a sudden 32-bit FID?
6595 * We will reject all bits higher than 16.
6597 if (lparmp[1] & 0xFFFF0000)
6598 return CM_ERROR_INVAL;
6599 baseFid = (unsigned short)lparmp[1];
6600 desiredAccess = lparmp[2];
6601 #ifdef DEBUG_VERBOSE
6602 allocSize = lparmp[3];
6603 #endif /* DEBUG_VERSOSE */
6604 extAttributes = lparmp[5];
6605 shareAccess = lparmp[6];
6606 createDisp = lparmp[7];
6607 createOptions = lparmp[8];
6608 #ifdef DEBUG_VERBOSE
6611 nameLength = lparmp[11];
6613 #ifdef DEBUG_VERBOSE
6614 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
6615 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
6616 osi_Log1(smb_logp,"... flags[%x]",flags);
6619 /* mustBeDir is never set; createOptions directory bit seems to be
6622 if (createOptions & FILE_DIRECTORY_FILE)
6624 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6630 * compute initial mode bits based on read-only flag in
6631 * extended attributes
6633 initialModeBits = 0666;
6634 if (extAttributes & SMB_ATTR_READONLY)
6635 initialModeBits &= ~0222;
6637 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
6638 /* Sometimes path is not null-terminated, so we make a copy. */
6639 realPathp = malloc(nameLength+1);
6640 memcpy(realPathp, pathp, nameLength);
6641 realPathp[nameLength] = 0;
6642 if (smb_StoreAnsiFilenames)
6643 OemToChar(realPathp,realPathp);
6645 spacep = cm_GetSpace();
6646 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6649 * Nothing here to handle SMB_IOCTL_FILENAME.
6650 * Will add it if necessary.
6653 #ifdef DEBUG_VERBOSE
6655 char *hexp, *asciip;
6656 asciip = (lastNamep? lastNamep : realPathp);
6657 hexp = osi_HexifyString( asciip );
6658 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
6663 userp = smb_GetUserFromVCP(vcp, inp);
6665 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
6667 return CM_ERROR_INVAL;
6672 baseDirp = cm_data.rootSCachep;
6673 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6674 if (code == CM_ERROR_TIDIPC) {
6675 /* Attempt to use a TID allocated for IPC. The client
6676 * is probably looking for DCE RPC end points which we
6677 * don't support OR it could be looking to make a DFS
6680 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
6683 cm_ReleaseUser(userp);
6684 return CM_ERROR_NOSUCHPATH;
6688 baseFidp = smb_FindFID(vcp, baseFid, 0);
6690 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
6692 cm_ReleaseUser(userp);
6693 return CM_ERROR_INVAL;
6695 baseDirp = baseFidp->scp;
6699 /* compute open mode */
6701 if (desiredAccess & DELETE)
6702 fidflags |= SMB_FID_OPENDELETE;
6703 if (desiredAccess & AFS_ACCESS_READ)
6704 fidflags |= SMB_FID_OPENREAD;
6705 if (desiredAccess & AFS_ACCESS_WRITE)
6706 fidflags |= SMB_FID_OPENWRITE;
6707 if (createOptions & FILE_DELETE_ON_CLOSE)
6708 fidflags |= SMB_FID_DELONCLOSE;
6710 /* And the share mode */
6711 if (shareAccess & FILE_SHARE_READ)
6712 fidflags |= SMB_FID_SHARE_READ;
6713 if (shareAccess & FILE_SHARE_WRITE)
6714 fidflags |= SMB_FID_SHARE_WRITE;
6718 if ( createDisp == FILE_OPEN ||
6719 createDisp == FILE_OVERWRITE ||
6720 createDisp == FILE_OVERWRITE_IF) {
6721 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6722 userp, tidPathp, &req, &dscp);
6725 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6726 cm_ReleaseSCache(dscp);
6727 cm_ReleaseUser(userp);
6730 smb_ReleaseFID(baseFidp);
6731 if ( WANTS_DFS_PATHNAMES(inp) )
6732 return CM_ERROR_PATH_NOT_COVERED;
6734 return CM_ERROR_BADSHARENAME;
6736 #endif /* DFS_SUPPORT */
6737 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6739 if (code == CM_ERROR_NOSUCHFILE) {
6740 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6741 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6742 if (code == 0 && realDirFlag == 1) {
6743 cm_ReleaseSCache(scp);
6744 cm_ReleaseSCache(dscp);
6745 cm_ReleaseUser(userp);
6748 smb_ReleaseFID(baseFidp);
6749 return CM_ERROR_EXISTS;
6755 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6756 userp, tidPathp, &req, &scp);
6758 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6759 cm_ReleaseSCache(scp);
6760 cm_ReleaseUser(userp);
6763 smb_ReleaseFID(baseFidp);
6764 if ( WANTS_DFS_PATHNAMES(inp) )
6765 return CM_ERROR_PATH_NOT_COVERED;
6767 return CM_ERROR_BADSHARENAME;
6769 #endif /* DFS_SUPPORT */
6775 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6776 /* look up parent directory */
6778 code = cm_NameI(baseDirp, spacep->data,
6779 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6780 userp, tidPathp, &req, &dscp);
6782 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6783 cm_ReleaseSCache(dscp);
6784 cm_ReleaseUser(userp);
6787 smb_ReleaseFID(baseFidp);
6788 if ( WANTS_DFS_PATHNAMES(inp) )
6789 return CM_ERROR_PATH_NOT_COVERED;
6791 return CM_ERROR_BADSHARENAME;
6793 #endif /* DFS_SUPPORT */
6797 cm_FreeSpace(spacep);
6800 smb_ReleaseFID(baseFidp);
6803 cm_ReleaseUser(userp);
6809 lastNamep = realPathp;
6813 if (!smb_IsLegalFilename(lastNamep))
6814 return CM_ERROR_BADNTFILENAME;
6817 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
6818 code = cm_Lookup(dscp, lastNamep,
6819 CM_FLAG_FOLLOW, userp, &req, &scp);
6821 code = cm_Lookup(dscp, lastNamep,
6822 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6825 if (code && code != CM_ERROR_NOSUCHFILE) {
6826 cm_ReleaseSCache(dscp);
6827 cm_ReleaseUser(userp);
6834 smb_ReleaseFID(baseFidp);
6835 cm_FreeSpace(spacep);
6838 /* if we get here, if code is 0, the file exists and is represented by
6839 * scp. Otherwise, we have to create it. The dir may be represented
6840 * by dscp, or we may have found the file directly. If code is non-zero,
6844 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
6848 cm_ReleaseSCache(dscp);
6849 cm_ReleaseSCache(scp);
6850 cm_ReleaseUser(userp);
6855 if (createDisp == FILE_CREATE) {
6856 /* oops, file shouldn't be there */
6858 cm_ReleaseSCache(dscp);
6859 cm_ReleaseSCache(scp);
6860 cm_ReleaseUser(userp);
6862 return CM_ERROR_EXISTS;
6865 if (createDisp == FILE_OVERWRITE ||
6866 createDisp == FILE_OVERWRITE_IF) {
6867 setAttr.mask = CM_ATTRMASK_LENGTH;
6868 setAttr.length.LowPart = 0;
6869 setAttr.length.HighPart = 0;
6871 /* now watch for a symlink */
6873 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6875 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6877 /* we have a more accurate file to use (the
6878 * target of the symbolic link). Otherwise,
6879 * we'll just use the symlink anyway.
6881 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6883 cm_ReleaseSCache(scp);
6887 code = cm_SetAttr(scp, &setAttr, userp, &req);
6888 openAction = 3; /* truncated existing file */
6890 else openAction = 1; /* found existing file */
6892 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6893 /* don't create if not found */
6895 cm_ReleaseSCache(dscp);
6896 cm_ReleaseUser(userp);
6898 return CM_ERROR_NOSUCHFILE;
6900 else if (realDirFlag == 0 || realDirFlag == -1) {
6901 osi_assert(dscp != NULL);
6902 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
6903 osi_LogSaveString(smb_logp, lastNamep));
6904 openAction = 2; /* created file */
6905 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6906 setAttr.clientModTime = time(NULL);
6907 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6911 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6912 smb_NotifyChange(FILE_ACTION_ADDED,
6913 FILE_NOTIFY_CHANGE_FILE_NAME,
6914 dscp, lastNamep, NULL, TRUE);
6915 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6916 /* Not an exclusive create, and someone else tried
6917 * creating it already, then we open it anyway. We
6918 * don't bother retrying after this, since if this next
6919 * fails, that means that the file was deleted after we
6920 * started this call.
6922 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6925 if (createDisp == FILE_OVERWRITE_IF) {
6926 setAttr.mask = CM_ATTRMASK_LENGTH;
6927 setAttr.length.LowPart = 0;
6928 setAttr.length.HighPart = 0;
6930 /* now watch for a symlink */
6932 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6934 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6936 /* we have a more accurate file to use (the
6937 * target of the symbolic link). Otherwise,
6938 * we'll just use the symlink anyway.
6940 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6942 cm_ReleaseSCache(scp);
6946 code = cm_SetAttr(scp, &setAttr, userp, &req);
6948 } /* lookup succeeded */
6951 /* create directory */
6952 osi_assert(dscp != NULL);
6954 "smb_ReceiveNTTranCreate creating directory %s",
6955 osi_LogSaveString(smb_logp, lastNamep));
6956 openAction = 2; /* created directory */
6957 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6958 setAttr.clientModTime = time(NULL);
6959 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6960 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6961 smb_NotifyChange(FILE_ACTION_ADDED,
6962 FILE_NOTIFY_CHANGE_DIR_NAME,
6963 dscp, lastNamep, NULL, TRUE);
6965 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6966 /* Not an exclusive create, and someone else tried
6967 * creating it already, then we open it anyway. We
6968 * don't bother retrying after this, since if this next
6969 * fails, that means that the file was deleted after we
6970 * started this call.
6972 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6978 /* something went wrong creating or truncating the file */
6980 cm_ReleaseSCache(scp);
6981 cm_ReleaseUser(userp);
6986 /* make sure we have file vs. dir right */
6987 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
6988 /* now watch for a symlink */
6990 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6992 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6994 /* we have a more accurate file to use (the
6995 * target of the symbolic link). Otherwise,
6996 * we'll just use the symlink anyway.
6998 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7000 cm_ReleaseSCache(scp);
7005 if (scp->fileType != CM_SCACHETYPE_FILE) {
7006 cm_ReleaseSCache(scp);
7007 cm_ReleaseUser(userp);
7009 return CM_ERROR_ISDIR;
7013 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7014 cm_ReleaseSCache(scp);
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);
7054 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7055 smb_CloseFID(vcp, fidp, NULL, 0);
7056 smb_ReleaseFID(fidp);
7058 cm_ReleaseSCache(scp);
7059 cm_ReleaseUser(userp);
7062 return CM_ERROR_SHARING_VIOLATION;
7066 lock_ObtainMutex(&fidp->mx);
7067 /* save a pointer to the vnode */
7070 fidp->flags = fidflags;
7072 /* remember if the file was newly created */
7074 fidp->flags |= SMB_FID_CREATED;
7076 /* save parent dir and pathname for deletion or change notification */
7077 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7078 fidp->flags |= SMB_FID_NTOPEN;
7079 fidp->NTopen_dscp = dscp;
7080 cm_HoldSCache(dscp);
7081 fidp->NTopen_pathp = strdup(lastNamep);
7083 fidp->NTopen_wholepathp = realPathp;
7084 lock_ReleaseMutex(&fidp->mx);
7086 /* we don't need this any longer */
7088 cm_ReleaseSCache(dscp);
7090 cm_Open(scp, 0, userp);
7092 /* set inp->fid so that later read calls in same msg can find fid */
7093 inp->fid = fidp->fid;
7095 /* check whether we are required to send an extended response */
7096 if (!extendedRespRequired) {
7098 parmOffset = 8*4 + 39;
7099 parmOffset += 1; /* pad to 4 */
7100 dataOffset = parmOffset + 70;
7104 /* Total Parameter Count */
7105 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7106 /* Total Data Count */
7107 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7108 /* Parameter Count */
7109 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7110 /* Parameter Offset */
7111 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7112 /* Parameter Displacement */
7113 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7115 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7117 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7118 /* Data Displacement */
7119 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7120 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7121 smb_SetSMBDataLength(outp, 70);
7123 lock_ObtainMutex(&scp->mx);
7124 outData = smb_GetSMBData(outp, NULL);
7125 outData++; /* round to get to parmOffset */
7126 *outData = 0; outData++; /* oplock */
7127 *outData = 0; outData++; /* reserved */
7128 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7129 *((ULONG *)outData) = openAction; outData += 4;
7130 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
7131 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7132 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
7133 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
7134 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
7135 *((FILETIME *)outData) = ft; outData += 8; /* change time */
7136 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7137 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7138 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7139 *((USHORT *)outData) = 0; outData += 2; /* filetype */
7140 *((USHORT *)outData) = 0; outData += 2; /* dev state */
7141 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7142 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7143 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7144 outData += 2; /* is a dir? */
7145 lock_ReleaseMutex(&scp->mx);
7148 parmOffset = 8*4 + 39;
7149 parmOffset += 1; /* pad to 4 */
7150 dataOffset = parmOffset + 104;
7154 /* Total Parameter Count */
7155 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7156 /* Total Data Count */
7157 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7158 /* Parameter Count */
7159 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7160 /* Parameter Offset */
7161 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7162 /* Parameter Displacement */
7163 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7165 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7167 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7168 /* Data Displacement */
7169 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7170 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7171 smb_SetSMBDataLength(outp, 105);
7173 lock_ObtainMutex(&scp->mx);
7174 outData = smb_GetSMBData(outp, NULL);
7175 outData++; /* round to get to parmOffset */
7176 *outData = 0; outData++; /* oplock */
7177 *outData = 1; outData++; /* response type */
7178 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7179 *((ULONG *)outData) = openAction; outData += 4;
7180 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
7181 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7182 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
7183 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
7184 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
7185 *((FILETIME *)outData) = ft; outData += 8; /* change time */
7186 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7187 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7188 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7189 *((USHORT *)outData) = 0; outData += 2; /* filetype */
7190 *((USHORT *)outData) = 0; outData += 2; /* dev state */
7191 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7192 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7193 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7194 outData += 1; /* is a dir? */
7195 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
7196 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
7197 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
7198 lock_ReleaseMutex(&scp->mx);
7201 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
7203 smb_ReleaseFID(fidp);
7205 cm_ReleaseUser(userp);
7207 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
7208 /* leave scp held since we put it in fidp->scp */
7212 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
7215 smb_packet_t *savedPacketp;
7216 ULONG filter; USHORT fid, watchtree;
7220 filter = smb_GetSMBParm(inp, 19) |
7221 (smb_GetSMBParm(inp, 20) << 16);
7222 fid = smb_GetSMBParm(inp, 21);
7223 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
7225 fidp = smb_FindFID(vcp, fid, 0);
7227 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
7228 return CM_ERROR_BADFD;
7231 savedPacketp = smb_CopyPacket(inp);
7233 if (savedPacketp->vcp)
7234 smb_ReleaseVC(savedPacketp->vcp);
7235 savedPacketp->vcp = vcp;
7236 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7237 savedPacketp->nextp = smb_Directory_Watches;
7238 smb_Directory_Watches = savedPacketp;
7239 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7241 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
7242 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
7245 lock_ObtainMutex(&scp->mx);
7247 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
7249 scp->flags |= CM_SCACHEFLAG_WATCHED;
7250 lock_ReleaseMutex(&scp->mx);
7251 smb_ReleaseFID(fidp);
7253 outp->flags |= SMB_PACKETFLAG_NOSEND;
7257 unsigned char nullSecurityDesc[36] = {
7258 0x01, /* security descriptor revision */
7259 0x00, /* reserved, should be zero */
7260 0x00, 0x80, /* security descriptor control;
7261 * 0x8000 : self-relative format */
7262 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
7263 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
7264 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
7265 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
7266 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7267 /* "null SID" owner SID */
7268 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
7269 /* "null SID" group SID */
7272 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7274 int parmOffset, parmCount, dataOffset, dataCount;
7282 ULONG securityInformation;
7284 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7285 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7286 parmp = inp->data + parmOffset;
7287 sparmp = (USHORT *) parmp;
7288 lparmp = (ULONG *) parmp;
7291 securityInformation = lparmp[1];
7293 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
7294 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
7302 parmOffset = 8*4 + 39;
7303 parmOffset += 1; /* pad to 4 */
7305 dataOffset = parmOffset + parmCount;
7309 /* Total Parameter Count */
7310 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
7311 /* Total Data Count */
7312 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
7313 /* Parameter Count */
7314 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
7315 /* Parameter Offset */
7316 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7317 /* Parameter Displacement */
7318 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7320 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
7322 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7323 /* Data Displacement */
7324 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7325 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7326 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
7328 outData = smb_GetSMBData(outp, NULL);
7329 outData++; /* round to get to parmOffset */
7330 *((ULONG *)outData) = 36; outData += 4; /* length */
7332 if (maxData >= 36) {
7333 memcpy(outData, nullSecurityDesc, 36);
7337 return CM_ERROR_BUFFERTOOSMALL;
7340 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7342 unsigned short function;
7344 function = smb_GetSMBParm(inp, 18);
7346 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
7348 /* We can handle long names */
7349 if (vcp->flags & SMB_VCFLAG_USENT)
7350 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
7354 return smb_ReceiveNTTranCreate(vcp, inp, outp);
7356 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
7359 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
7362 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
7364 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
7367 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
7369 return CM_ERROR_INVAL;
7373 * smb_NotifyChange -- find relevant change notification messages and
7376 * If we don't know the file name (i.e. a callback break), filename is
7377 * NULL, and we return a zero-length list.
7379 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
7380 cm_scache_t *dscp, char *filename, char *otherFilename,
7381 BOOL isDirectParent)
7383 smb_packet_t *watch, *lastWatch, *nextWatch;
7384 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
7385 char *outData, *oldOutData;
7389 BOOL twoEntries = FALSE;
7390 ULONG otherNameLen, oldParmCount = 0;
7394 /* Get ready for rename within directory */
7395 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
7397 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
7400 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
7401 osi_LogSaveString(smb_logp,filename),dscp);
7403 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7404 watch = smb_Directory_Watches;
7406 filter = smb_GetSMBParm(watch, 19)
7407 | (smb_GetSMBParm(watch, 20) << 16);
7408 fid = smb_GetSMBParm(watch, 21);
7409 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
7410 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
7411 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
7414 * Strange hack - bug in NT Client and NT Server that we
7417 if (filter == 3 && wtree)
7420 fidp = smb_FindFID(watch->vcp, fid, 0);
7422 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
7424 watch = watch->nextp;
7427 if (fidp->scp != dscp
7428 || (filter & notifyFilter) == 0
7429 || (!isDirectParent && !wtree)) {
7430 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
7431 smb_ReleaseFID(fidp);
7433 watch = watch->nextp;
7436 smb_ReleaseFID(fidp);
7439 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
7440 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
7442 nextWatch = watch->nextp;
7443 if (watch == smb_Directory_Watches)
7444 smb_Directory_Watches = nextWatch;
7446 lastWatch->nextp = nextWatch;
7448 /* Turn off WATCHED flag in dscp */
7449 lock_ObtainMutex(&dscp->mx);
7451 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
7453 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
7454 lock_ReleaseMutex(&dscp->mx);
7456 /* Convert to response packet */
7457 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
7458 ((smb_t *) watch)->wct = 0;
7461 if (filename == NULL)
7464 nameLen = (ULONG)strlen(filename);
7465 parmCount = 3*4 + nameLen*2;
7466 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
7468 otherNameLen = (ULONG)strlen(otherFilename);
7469 oldParmCount = parmCount;
7470 parmCount += 3*4 + otherNameLen*2;
7471 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
7473 if (maxLen < parmCount)
7474 parmCount = 0; /* not enough room */
7476 parmOffset = 8*4 + 39;
7477 parmOffset += 1; /* pad to 4 */
7478 dataOffset = parmOffset + parmCount;
7482 /* Total Parameter Count */
7483 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
7484 /* Total Data Count */
7485 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7486 /* Parameter Count */
7487 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
7488 /* Parameter Offset */
7489 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
7490 /* Parameter Displacement */
7491 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7493 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7495 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
7496 /* Data Displacement */
7497 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7498 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
7499 smb_SetSMBDataLength(watch, parmCount + 1);
7501 if (parmCount != 0) {
7503 outData = smb_GetSMBData(watch, NULL);
7504 outData++; /* round to get to parmOffset */
7505 oldOutData = outData;
7506 *((DWORD *)outData) = oldParmCount; outData += 4;
7507 /* Next Entry Offset */
7508 *((DWORD *)outData) = action; outData += 4;
7510 *((DWORD *)outData) = nameLen*2; outData += 4;
7511 /* File Name Length */
7512 p = strdup(filename);
7513 if (smb_StoreAnsiFilenames)
7515 mbstowcs((WCHAR *)outData, p, nameLen);
7519 outData = oldOutData + oldParmCount;
7520 *((DWORD *)outData) = 0; outData += 4;
7521 /* Next Entry Offset */
7522 *((DWORD *)outData) = otherAction; outData += 4;
7524 *((DWORD *)outData) = otherNameLen*2;
7525 outData += 4; /* File Name Length */
7526 p = strdup(otherFilename);
7527 if (smb_StoreAnsiFilenames)
7529 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
7535 * If filename is null, we don't know the cause of the
7536 * change notification. We return zero data (see above),
7537 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
7538 * (= 0x010C). We set the error code here by hand, without
7539 * modifying wct and bcc.
7541 if (filename == NULL) {
7542 ((smb_t *) watch)->rcls = 0x0C;
7543 ((smb_t *) watch)->reh = 0x01;
7544 ((smb_t *) watch)->errLow = 0;
7545 ((smb_t *) watch)->errHigh = 0;
7546 /* Set NT Status codes flag */
7547 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7550 smb_SendPacket(watch->vcp, watch);
7551 smb_FreePacket(watch);
7554 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7557 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7559 unsigned char *replyWctp;
7560 smb_packet_t *watch, *lastWatch;
7561 USHORT fid, watchtree;
7565 osi_Log0(smb_logp, "SMB3 receive NT cancel");
7567 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7568 watch = smb_Directory_Watches;
7570 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
7571 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
7572 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
7573 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
7574 if (watch == smb_Directory_Watches)
7575 smb_Directory_Watches = watch->nextp;
7577 lastWatch->nextp = watch->nextp;
7578 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7580 /* Turn off WATCHED flag in scp */
7581 fid = smb_GetSMBParm(watch, 21);
7582 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
7584 if (vcp != watch->vcp)
7585 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
7588 fidp = smb_FindFID(vcp, fid, 0);
7590 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
7592 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
7595 lock_ObtainMutex(&scp->mx);
7597 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
7599 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
7600 lock_ReleaseMutex(&scp->mx);
7601 smb_ReleaseFID(fidp);
7603 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
7606 /* assume STATUS32; return 0xC0000120 (CANCELED) */
7607 replyWctp = watch->wctp;
7611 ((smb_t *)watch)->rcls = 0x20;
7612 ((smb_t *)watch)->reh = 0x1;
7613 ((smb_t *)watch)->errLow = 0;
7614 ((smb_t *)watch)->errHigh = 0xC0;
7615 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7616 smb_SendPacket(vcp, watch);
7617 smb_FreePacket(watch);
7621 watch = watch->nextp;
7623 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7629 * NT rename also does hard links.
7632 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
7633 #define RENAME_FLAG_HARD_LINK 0x103
7634 #define RENAME_FLAG_RENAME 0x104
7635 #define RENAME_FLAG_COPY 0x105
7637 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7639 char *oldPathp, *newPathp;
7645 attrs = smb_GetSMBParm(inp, 0);
7646 rename_type = smb_GetSMBParm(inp, 1);
7648 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
7649 osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
7650 return CM_ERROR_NOACCESS;
7653 tp = smb_GetSMBData(inp, NULL);
7654 oldPathp = smb_ParseASCIIBlock(tp, &tp);
7655 if (smb_StoreAnsiFilenames)
7656 OemToChar(oldPathp,oldPathp);
7657 newPathp = smb_ParseASCIIBlock(tp, &tp);
7658 if (smb_StoreAnsiFilenames)
7659 OemToChar(newPathp,newPathp);
7661 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
7662 osi_LogSaveString(smb_logp, oldPathp),
7663 osi_LogSaveString(smb_logp, newPathp),
7664 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
7666 if (rename_type == RENAME_FLAG_RENAME) {
7667 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
7668 } else { /* RENAME_FLAG_HARD_LINK */
7669 code = smb_Link(vcp,inp,oldPathp,newPathp);
7676 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
7679 cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
7681 smb_username_t *unp;
7684 unp = smb_FindUserByName(usern, machine, flags);
7686 lock_ObtainMutex(&unp->mx);
7687 unp->userp = cm_NewUser();
7688 lock_ReleaseMutex(&unp->mx);
7689 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7691 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7695 smb_ReleaseUsername(unp);