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 | FILE_NOTIFY_CHANGE_CREATION,
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 */
2366 osi_Log2(afsd_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2368 lock_ObtainMutex(&scp->mx);
2369 scp->flags |= CM_SCACHEFLAG_SMB_FID;
2370 lock_ReleaseMutex(&scp->mx);
2373 fidp->userp = userp;
2375 /* compute open mode */
2377 fidp->flags |= SMB_FID_OPENREAD;
2378 if (openMode == 1 || openMode == 2)
2379 fidp->flags |= SMB_FID_OPENWRITE;
2381 /* remember that the file was newly created */
2383 fidp->flags |= SMB_FID_CREATED;
2385 lock_ReleaseMutex(&fidp->mx);
2387 smb_ReleaseFID(fidp);
2389 cm_Open(scp, 0, userp);
2391 /* copy out remainder of the parms */
2393 outp->parmsp[parmSlot++] = fidp->fid;
2394 lock_ObtainMutex(&scp->mx);
2396 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2397 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2398 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2399 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2400 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2401 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2402 outp->parmsp[parmSlot++] = openMode;
2403 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2404 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2406 /* and the final "always present" stuff */
2407 outp->parmsp[parmSlot++] = openAction;
2408 /* next write out the "unique" ID */
2409 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2410 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2411 outp->parmsp[parmSlot++] = 0;
2412 if (returnEALength) {
2413 outp->parmsp[parmSlot++] = 0;
2414 outp->parmsp[parmSlot++] = 0;
2416 lock_ReleaseMutex(&scp->mx);
2417 outp->totalData = 0; /* total # of data bytes */
2418 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2420 smb_SendTran2Packet(vcp, outp, op);
2422 smb_FreeTran2Packet(outp);
2424 cm_ReleaseUser(userp);
2425 /* leave scp held since we put it in fidp->scp */
2429 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2431 osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2432 return CM_ERROR_BADOP;
2435 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2437 osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2438 return CM_ERROR_BADOP;
2441 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2444 unsigned short infolevel;
2446 infolevel = p->parmsp[0];
2448 osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2450 return CM_ERROR_BADOP;
2453 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2455 smb_tran2Packet_t *outp;
2456 smb_tran2QFSInfo_t qi;
2458 static char FSname[8] = {'A', 0, 'F', 0, 'S', 0, 0, 0};
2460 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2462 switch (p->parmsp[0]) {
2463 case SMB_INFO_ALLOCATION:
2464 responseSize = sizeof(qi.u.allocInfo);
2466 case SMB_INFO_VOLUME:
2467 responseSize = sizeof(qi.u.volumeInfo);
2469 case SMB_QUERY_FS_VOLUME_INFO:
2470 responseSize = sizeof(qi.u.FSvolumeInfo);
2472 case SMB_QUERY_FS_SIZE_INFO:
2473 responseSize = sizeof(qi.u.FSsizeInfo);
2475 case SMB_QUERY_FS_DEVICE_INFO:
2476 responseSize = sizeof(qi.u.FSdeviceInfo);
2478 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2479 responseSize = sizeof(qi.u.FSattributeInfo);
2481 case SMB_INFO_UNIX: /* CIFS Unix Info */
2482 case SMB_INFO_MACOS: /* Mac FS Info */
2484 return CM_ERROR_BADOP;
2487 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2488 switch (p->parmsp[0]) {
2489 case SMB_INFO_ALLOCATION:
2491 qi.u.allocInfo.FSID = 0;
2492 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2493 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2494 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2495 qi.u.allocInfo.bytesPerSector = 1024;
2498 case SMB_INFO_VOLUME:
2500 qi.u.volumeInfo.vsn = 1234;
2501 qi.u.volumeInfo.vnCount = 4;
2502 /* we're supposed to pad it out with zeroes to the end */
2503 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2504 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2507 case SMB_QUERY_FS_VOLUME_INFO:
2508 /* FS volume info */
2509 memset((char *)&qi.u.FSvolumeInfo.vct, 0, 4);
2510 qi.u.FSvolumeInfo.vsn = 1234;
2511 qi.u.FSvolumeInfo.vnCount = 8;
2512 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0\0", 8);
2515 case SMB_QUERY_FS_SIZE_INFO:
2517 qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2518 qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2519 qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2520 qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2521 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2522 qi.u.FSsizeInfo.bytesPerSector = 1024;
2525 case SMB_QUERY_FS_DEVICE_INFO:
2526 /* FS device info */
2527 qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2528 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2531 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2532 /* FS attribute info */
2533 /* attributes, defined in WINNT.H:
2534 * FILE_CASE_SENSITIVE_SEARCH 0x1
2535 * FILE_CASE_PRESERVED_NAMES 0x2
2536 * FILE_VOLUME_QUOTAS 0x10
2537 * <no name defined> 0x4000
2538 * If bit 0x4000 is not set, Windows 95 thinks
2539 * we can't handle long (non-8.3) names,
2540 * despite our protestations to the contrary.
2542 qi.u.FSattributeInfo.attributes = 0x4003;
2543 qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
2544 qi.u.FSattributeInfo.FSnameLength = sizeof(FSname);
2545 memcpy(qi.u.FSattributeInfo.FSname, FSname, sizeof(FSname));
2549 /* copy out return data, and set corresponding sizes */
2550 outp->totalParms = 0;
2551 outp->totalData = responseSize;
2552 memcpy(outp->datap, &qi, responseSize);
2554 /* send and free the packets */
2555 smb_SendTran2Packet(vcp, outp, op);
2556 smb_FreeTran2Packet(outp);
2561 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2563 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2564 return CM_ERROR_BADOP;
2567 struct smb_ShortNameRock {
2571 size_t shortNameLen;
2574 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2577 struct smb_ShortNameRock *rockp;
2581 /* compare both names and vnodes, though probably just comparing vnodes
2582 * would be safe enough.
2584 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2586 if (ntohl(dep->fid.vnode) != rockp->vnode)
2588 /* This is the entry */
2589 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2590 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2591 return CM_ERROR_STOPNOW;
2594 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2595 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2597 struct smb_ShortNameRock rock;
2601 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2605 spacep = cm_GetSpace();
2606 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2608 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2610 cm_FreeSpace(spacep);
2615 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2616 cm_ReleaseSCache(dscp);
2617 cm_ReleaseUser(userp);
2618 return CM_ERROR_PATH_NOT_COVERED;
2620 #endif /* DFS_SUPPORT */
2622 if (!lastNamep) lastNamep = pathp;
2625 thyper.HighPart = 0;
2626 rock.shortName = shortName;
2628 rock.maskp = lastNamep;
2629 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2631 cm_ReleaseSCache(dscp);
2634 return CM_ERROR_NOSUCHFILE;
2635 if (code == CM_ERROR_STOPNOW) {
2636 *shortNameLenp = rock.shortNameLen;
2642 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2644 smb_tran2Packet_t *outp;
2647 unsigned short infoLevel;
2648 smb_tran2QPathInfo_t qpi;
2650 unsigned short attributes;
2651 unsigned long extAttributes;
2656 cm_scache_t *scp, *dscp;
2666 infoLevel = p->parmsp[0];
2667 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2669 else if (infoLevel == SMB_INFO_STANDARD)
2670 responseSize = sizeof(qpi.u.QPstandardInfo);
2671 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2672 responseSize = sizeof(qpi.u.QPeaSizeInfo);
2673 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2674 responseSize = sizeof(qpi.u.QPfileBasicInfo);
2675 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2676 responseSize = sizeof(qpi.u.QPfileStandardInfo);
2677 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2678 responseSize = sizeof(qpi.u.QPfileEaInfo);
2679 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2680 responseSize = sizeof(qpi.u.QPfileNameInfo);
2681 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
2682 responseSize = sizeof(qpi.u.QPfileAllInfo);
2683 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2684 responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2686 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2687 p->opcode, infoLevel);
2688 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
2692 pathp = (char *)(&p->parmsp[3]);
2693 if (smb_StoreAnsiFilenames)
2694 OemToChar(pathp,pathp);
2695 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2696 osi_LogSaveString(smb_logp, pathp));
2698 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2700 if (infoLevel > 0x100)
2701 outp->totalParms = 2;
2703 outp->totalParms = 0;
2704 outp->totalData = responseSize;
2706 /* now, if we're at infoLevel 6, we're only being asked to check
2707 * the syntax, so we just OK things now. In particular, we're *not*
2708 * being asked to verify anything about the state of any parent dirs.
2710 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2711 smb_SendTran2Packet(vcp, outp, opx);
2712 smb_FreeTran2Packet(outp);
2716 userp = smb_GetTran2User(vcp, p);
2718 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2719 smb_FreeTran2Packet(outp);
2720 return CM_ERROR_BADSMB;
2723 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2725 cm_ReleaseUser(userp);
2726 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2727 smb_FreeTran2Packet(outp);
2732 * XXX Strange hack XXX
2734 * As of Patch 7 (13 January 98), we are having the following problem:
2735 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2736 * requests to look up "desktop.ini" in all the subdirectories.
2737 * This can cause zillions of timeouts looking up non-existent cells
2738 * and volumes, especially in the top-level directory.
2740 * We have not found any way to avoid this or work around it except
2741 * to explicitly ignore the requests for mount points that haven't
2742 * yet been evaluated and for directories that haven't yet been
2745 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2746 spacep = cm_GetSpace();
2747 smb_StripLastComponent(spacep->data, &lastComp, pathp);
2748 #ifndef SPECIAL_FOLDERS
2749 /* Make sure that lastComp is not NULL */
2751 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2752 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2756 userp, tidPathp, &req, &dscp);
2759 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2760 if ( WANTS_DFS_PATHNAMES(p) )
2761 code = CM_ERROR_PATH_NOT_COVERED;
2763 code = CM_ERROR_BADSHARENAME;
2765 #endif /* DFS_SUPPORT */
2766 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2767 code = CM_ERROR_NOSUCHFILE;
2768 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2769 cm_buf_t *bp = buf_Find(dscp, &hzero);
2773 code = CM_ERROR_NOSUCHFILE;
2775 cm_ReleaseSCache(dscp);
2777 cm_FreeSpace(spacep);
2778 cm_ReleaseUser(userp);
2779 smb_SendTran2Error(vcp, p, opx, code);
2780 smb_FreeTran2Packet(outp);
2786 #endif /* SPECIAL_FOLDERS */
2788 cm_FreeSpace(spacep);
2791 /* now do namei and stat, and copy out the info */
2792 code = cm_NameI(cm_data.rootSCachep, pathp,
2793 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2796 cm_ReleaseUser(userp);
2797 smb_SendTran2Error(vcp, p, opx, code);
2798 smb_FreeTran2Packet(outp);
2803 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2804 cm_ReleaseSCache(scp);
2805 cm_ReleaseUser(userp);
2806 if ( WANTS_DFS_PATHNAMES(p) )
2807 code = CM_ERROR_PATH_NOT_COVERED;
2809 code = CM_ERROR_BADSHARENAME;
2810 smb_SendTran2Error(vcp, p, opx, code);
2811 smb_FreeTran2Packet(outp);
2814 #endif /* DFS_SUPPORT */
2816 lock_ObtainMutex(&scp->mx);
2817 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2818 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2819 if (code) goto done;
2821 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2823 /* now we have the status in the cache entry, and everything is locked.
2824 * Marshall the output data.
2826 /* for info level 108, figure out short name */
2827 if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
2828 code = cm_GetShortName(pathp, userp, &req,
2829 tidPathp, scp->fid.vnode, shortName,
2835 qpi.u.QPfileAltNameInfo.fileNameLength = (len + 1) * 2;
2836 mbstowcs((unsigned short *)qpi.u.QPfileAltNameInfo.fileName, shortName, len + 1);
2840 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2841 len = strlen(lastComp);
2842 qpi.u.QPfileNameInfo.fileNameLength = (len + 1) * 2;
2843 mbstowcs((unsigned short *)qpi.u.QPfileNameInfo.fileName, lastComp, len + 1);
2847 else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2848 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2849 qpi.u.QPstandardInfo.creationDateTime = dosTime;
2850 qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
2851 qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
2852 qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
2853 qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
2854 attributes = smb_Attributes(scp);
2855 qpi.u.QPstandardInfo.attributes = attributes;
2856 qpi.u.QPstandardInfo.eaSize = 0;
2858 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2859 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2860 qpi.u.QPfileBasicInfo.creationTime = ft;
2861 qpi.u.QPfileBasicInfo.lastAccessTime = ft;
2862 qpi.u.QPfileBasicInfo.lastWriteTime = ft;
2863 qpi.u.QPfileBasicInfo.changeTime = ft;
2864 extAttributes = smb_ExtAttributes(scp);
2865 qpi.u.QPfileBasicInfo.attributes = extAttributes;
2866 qpi.u.QPfileBasicInfo.reserved = 0;
2868 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2869 smb_fid_t *fidp = smb_FindFIDByScache(vcp, scp);
2871 qpi.u.QPfileStandardInfo.allocationSize = scp->length;
2872 qpi.u.QPfileStandardInfo.endOfFile = scp->length;
2873 qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
2874 qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
2875 qpi.u.QPfileStandardInfo.directory =
2876 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2877 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2878 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2879 qpi.u.QPfileStandardInfo.reserved = 0;
2882 lock_ReleaseMutex(&scp->mx);
2883 lock_ObtainMutex(&fidp->mx);
2884 lock_ObtainMutex(&scp->mx);
2885 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
2886 lock_ReleaseMutex(&fidp->mx);
2887 smb_ReleaseFID(fidp);
2890 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2891 qpi.u.QPfileEaInfo.eaSize = 0;
2893 else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
2894 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2895 qpi.u.QPfileAllInfo.creationTime = ft;
2896 qpi.u.QPfileAllInfo.lastAccessTime = ft;
2897 qpi.u.QPfileAllInfo.lastWriteTime = ft;
2898 qpi.u.QPfileAllInfo.changeTime = ft;
2899 extAttributes = smb_ExtAttributes(scp);
2900 qpi.u.QPfileAllInfo.attributes = extAttributes;
2901 qpi.u.QPfileAllInfo.allocationSize = scp->length;
2902 qpi.u.QPfileAllInfo.endOfFile = scp->length;
2903 qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
2904 qpi.u.QPfileAllInfo.deletePending = 0;
2905 qpi.u.QPfileAllInfo.directory =
2906 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2907 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2908 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2909 qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
2910 qpi.u.QPfileAllInfo.indexNumber.LowPart = scp->fid.volume;
2911 qpi.u.QPfileAllInfo.eaSize = 0;
2912 qpi.u.QPfileAllInfo.accessFlags = 0;
2913 qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
2914 qpi.u.QPfileAllInfo.indexNumber2.LowPart = scp->fid.unique;
2915 qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
2916 qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
2917 qpi.u.QPfileAllInfo.mode = 0;
2918 qpi.u.QPfileAllInfo.alignmentRequirement = 0;
2919 len = strlen(lastComp);
2920 qpi.u.QPfileAllInfo.fileNameLength = (len + 1) * 2;
2921 mbstowcs((unsigned short *)qpi.u.QPfileAllInfo.fileName, lastComp, len + 1);
2924 /* send and free the packets */
2926 lock_ReleaseMutex(&scp->mx);
2927 cm_ReleaseSCache(scp);
2928 cm_ReleaseUser(userp);
2930 memcpy(outp->datap, &qpi, responseSize);
2931 smb_SendTran2Packet(vcp, outp, opx);
2933 smb_SendTran2Error(vcp, p, opx, code);
2935 smb_FreeTran2Packet(outp);
2940 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2943 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2944 return CM_ERROR_BADOP;
2948 unsigned short infoLevel;
2950 smb_tran2Packet_t *outp;
2951 smb_tran2QPathInfo_t *spi;
2953 cm_scache_t *scp, *dscp;
2961 infoLevel = p->parmsp[0];
2962 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
2963 if (infoLevel != SMB_INFO_STANDARD &&
2964 infoLevel != SMB_INFO_QUERY_EA_SIZE &&
2965 infoLevel != SMB_INFO_QUERY_ALL_EAS) {
2966 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2967 p->opcode, infoLevel);
2968 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2972 pathp = (char *)(&p->parmsp[3]);
2973 if (smb_StoreAnsiFilenames)
2974 OemToChar(pathp,pathp);
2975 osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %s", infoLevel,
2976 osi_LogSaveString(smb_logp, pathp));
2978 userp = smb_GetTran2User(vcp, p);
2980 osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
2981 code = CM_ERROR_BADSMB;
2985 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2986 if (code == CM_ERROR_TIDIPC) {
2987 /* Attempt to use a TID allocated for IPC. The client
2988 * is probably looking for DCE RPC end points which we
2989 * don't support OR it could be looking to make a DFS
2992 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2993 cm_ReleaseUser(userp);
2994 return CM_ERROR_NOSUCHPATH;
2998 * XXX Strange hack XXX
3000 * As of Patch 7 (13 January 98), we are having the following problem:
3001 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3002 * requests to look up "desktop.ini" in all the subdirectories.
3003 * This can cause zillions of timeouts looking up non-existent cells
3004 * and volumes, especially in the top-level directory.
3006 * We have not found any way to avoid this or work around it except
3007 * to explicitly ignore the requests for mount points that haven't
3008 * yet been evaluated and for directories that haven't yet been
3011 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3012 spacep = cm_GetSpace();
3013 smb_StripLastComponent(spacep->data, &lastComp, pathp);
3014 #ifndef SPECIAL_FOLDERS
3015 /* Make sure that lastComp is not NULL */
3017 if (stricmp(lastComp, "\\desktop.ini") == 0) {
3018 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3022 userp, tidPathp, &req, &dscp);
3025 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3026 if ( WANTS_DFS_PATHNAMES(p) )
3027 code = CM_ERROR_PATH_NOT_COVERED;
3029 code = CM_ERROR_BADSHARENAME;
3031 #endif /* DFS_SUPPORT */
3032 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3033 code = CM_ERROR_NOSUCHFILE;
3034 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3035 cm_buf_t *bp = buf_Find(dscp, &hzero);
3039 code = CM_ERROR_NOSUCHFILE;
3041 cm_ReleaseSCache(dscp);
3043 cm_FreeSpace(spacep);
3044 cm_ReleaseUser(userp);
3045 smb_SendTran2Error(vcp, p, opx, code);
3051 #endif /* SPECIAL_FOLDERS */
3053 cm_FreeSpace(spacep);
3056 /* now do namei and stat, and copy out the info */
3057 code = cm_NameI(cm_data.rootSCachep, pathp,
3058 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3060 cm_ReleaseUser(userp);
3061 smb_SendTran2Error(vcp, p, opx, code);
3065 fidp = smb_FindFIDByScache(vcp, scp);
3067 cm_ReleaseUser(userp);
3068 cm_ReleaseSCache(scp);
3069 smb_SendTran2Error(vcp, p, opx, code);
3073 lock_ObtainMutex(&fidp->mx);
3074 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
3075 lock_ReleaseMutex(&fidp->mx);
3076 smb_ReleaseFID(fidp);
3077 cm_ReleaseUser(userp);
3078 cm_ReleaseSCache(scp);
3079 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3082 lock_ReleaseMutex(&fidp->mx);
3084 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3086 outp->totalParms = 2;
3087 outp->totalData = 0;
3089 spi = (smb_tran2QPathInfo_t *)p->datap;
3090 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3093 /* lock the vnode with a callback; we need the current status
3094 * to determine what the new status is, in some cases.
3096 lock_ObtainMutex(&scp->mx);
3097 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3098 CM_SCACHESYNC_GETSTATUS
3099 | CM_SCACHESYNC_NEEDCALLBACK);
3101 lock_ReleaseMutex(&scp->mx);
3104 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3106 lock_ReleaseMutex(&scp->mx);
3107 lock_ObtainMutex(&fidp->mx);
3108 lock_ObtainMutex(&scp->mx);
3110 /* prepare for setattr call */
3111 attr.mask = CM_ATTRMASK_LENGTH;
3112 attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3113 attr.length.HighPart = 0;
3115 if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3116 smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3117 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3118 fidp->flags |= SMB_FID_MTIMESETDONE;
3121 if (spi->u.QPstandardInfo.attributes != 0) {
3122 if ((scp->unixModeBits & 0222)
3123 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3124 /* make a writable file read-only */
3125 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3126 attr.unixModeBits = scp->unixModeBits & ~0222;
3128 else if ((scp->unixModeBits & 0222) == 0
3129 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3130 /* make a read-only file writable */
3131 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3132 attr.unixModeBits = scp->unixModeBits | 0222;
3135 lock_ReleaseMutex(&scp->mx);
3136 lock_ReleaseMutex(&fidp->mx);
3140 code = cm_SetAttr(scp, &attr, userp, &req);
3144 else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3145 /* we don't support EAs */
3146 code = CM_ERROR_INVAL;
3150 cm_ReleaseSCache(scp);
3151 cm_ReleaseUser(userp);
3152 smb_ReleaseFID(fidp);
3154 smb_SendTran2Packet(vcp, outp, opx);
3156 smb_SendTran2Error(vcp, p, opx, code);
3157 smb_FreeTran2Packet(outp);
3163 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3165 smb_tran2Packet_t *outp;
3167 unsigned long attributes;
3168 unsigned short infoLevel;
3175 smb_tran2QFileInfo_t qfi;
3182 fidp = smb_FindFID(vcp, fid, 0);
3185 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3189 infoLevel = p->parmsp[1];
3190 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3191 responseSize = sizeof(qfi.u.QFbasicInfo);
3192 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3193 responseSize = sizeof(qfi.u.QFstandardInfo);
3194 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3195 responseSize = sizeof(qfi.u.QFeaInfo);
3196 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3197 responseSize = sizeof(qfi.u.QFfileNameInfo);
3199 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3200 p->opcode, infoLevel);
3201 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
3202 smb_ReleaseFID(fidp);
3205 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3207 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3209 if (infoLevel > 0x100)
3210 outp->totalParms = 2;
3212 outp->totalParms = 0;
3213 outp->totalData = responseSize;
3215 userp = smb_GetTran2User(vcp, p);
3217 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3218 code = CM_ERROR_BADSMB;
3222 lock_ObtainMutex(&fidp->mx);
3223 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3225 osi_Log2(afsd_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3227 lock_ReleaseMutex(&fidp->mx);
3228 lock_ObtainMutex(&scp->mx);
3229 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3230 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3234 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3236 /* now we have the status in the cache entry, and everything is locked.
3237 * Marshall the output data.
3239 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3240 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3241 qfi.u.QFbasicInfo.creationTime = ft;
3242 qfi.u.QFbasicInfo.lastAccessTime = ft;
3243 qfi.u.QFbasicInfo.lastWriteTime = ft;
3244 qfi.u.QFbasicInfo.lastChangeTime = ft;
3245 attributes = smb_ExtAttributes(scp);
3246 qfi.u.QFbasicInfo.attributes = attributes;
3248 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3249 qfi.u.QFstandardInfo.allocationSize = scp->length;
3250 qfi.u.QFstandardInfo.endOfFile = scp->length;
3251 qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3252 qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3253 qfi.u.QFstandardInfo.directory =
3254 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3255 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3256 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3258 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3259 qfi.u.QFeaInfo.eaSize = 0;
3261 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3265 lock_ReleaseMutex(&scp->mx);
3266 lock_ObtainMutex(&fidp->mx);
3267 lock_ObtainMutex(&scp->mx);
3268 if (fidp->NTopen_wholepathp)
3269 name = fidp->NTopen_wholepathp;
3271 name = "\\"; /* probably can't happen */
3272 lock_ReleaseMutex(&fidp->mx);
3273 len = (unsigned long)strlen(name);
3274 outp->totalData = ((len+1)*2) + 4; /* this is actually what we want to return */
3275 qfi.u.QFfileNameInfo.fileNameLength = (len + 1) * 2;
3276 mbstowcs((unsigned short *)qfi.u.QFfileNameInfo.fileName, name, len + 1);
3279 /* send and free the packets */
3281 lock_ReleaseMutex(&scp->mx);
3282 cm_ReleaseSCache(scp);
3283 cm_ReleaseUser(userp);
3284 smb_ReleaseFID(fidp);
3286 memcpy(outp->datap, &qfi, responseSize);
3287 smb_SendTran2Packet(vcp, outp, opx);
3289 smb_SendTran2Error(vcp, p, opx, code);
3291 smb_FreeTran2Packet(outp);
3296 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3301 unsigned short infoLevel;
3302 smb_tran2Packet_t *outp;
3310 fidp = smb_FindFID(vcp, fid, 0);
3313 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3317 infoLevel = p->parmsp[1];
3318 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3319 if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3320 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3321 p->opcode, infoLevel);
3322 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
3323 smb_ReleaseFID(fidp);
3327 lock_ObtainMutex(&fidp->mx);
3328 if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) {
3329 lock_ReleaseMutex(&fidp->mx);
3330 smb_ReleaseFID(fidp);
3331 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3334 if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3335 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3336 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3337 lock_ReleaseMutex(&fidp->mx);
3338 smb_ReleaseFID(fidp);
3339 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3344 osi_Log2(afsd_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3346 lock_ReleaseMutex(&fidp->mx);
3348 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3350 outp->totalParms = 2;
3351 outp->totalData = 0;
3353 userp = smb_GetTran2User(vcp, p);
3355 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3356 code = CM_ERROR_BADSMB;
3360 if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3362 unsigned int attribute;
3364 smb_tran2QFileInfo_t *sfi;
3366 sfi = (smb_tran2QFileInfo_t *)p->datap;
3368 /* lock the vnode with a callback; we need the current status
3369 * to determine what the new status is, in some cases.
3371 lock_ObtainMutex(&scp->mx);
3372 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3373 CM_SCACHESYNC_GETSTATUS
3374 | CM_SCACHESYNC_NEEDCALLBACK);
3376 lock_ReleaseMutex(&scp->mx);
3380 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3382 lock_ReleaseMutex(&scp->mx);
3383 lock_ObtainMutex(&fidp->mx);
3384 lock_ObtainMutex(&scp->mx);
3386 /* prepare for setattr call */
3389 lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3390 /* when called as result of move a b, lastMod is (-1, -1).
3391 * If the check for -1 is not present, timestamp
3392 * of the resulting file will be 1969 (-1)
3394 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3395 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3396 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3397 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3398 fidp->flags |= SMB_FID_MTIMESETDONE;
3401 attribute = sfi->u.QFbasicInfo.attributes;
3402 if (attribute != 0) {
3403 if ((scp->unixModeBits & 0222)
3404 && (attribute & SMB_ATTR_READONLY) != 0) {
3405 /* make a writable file read-only */
3406 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3407 attr.unixModeBits = scp->unixModeBits & ~0222;
3409 else if ((scp->unixModeBits & 0222) == 0
3410 && (attribute & SMB_ATTR_READONLY) == 0) {
3411 /* make a read-only file writable */
3412 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3413 attr.unixModeBits = scp->unixModeBits | 0222;
3416 lock_ReleaseMutex(&scp->mx);
3417 lock_ReleaseMutex(&fidp->mx);
3421 code = cm_SetAttr(scp, &attr, userp, &req);
3425 else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3426 if (*((char *)(p->datap))) { /* File is Deleted */
3427 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3430 lock_ObtainMutex(&fidp->mx);
3431 fidp->flags |= SMB_FID_DELONCLOSE;
3432 lock_ReleaseMutex(&fidp->mx);
3437 lock_ObtainMutex(&fidp->mx);
3438 fidp->flags &= ~SMB_FID_DELONCLOSE;
3439 lock_ReleaseMutex(&fidp->mx);
3442 else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3443 infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3444 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3447 attr.mask = CM_ATTRMASK_LENGTH;
3448 attr.length.LowPart = size.LowPart;
3449 attr.length.HighPart = size.HighPart;
3450 code = cm_SetAttr(scp, &attr, userp, &req);
3454 cm_ReleaseSCache(scp);
3455 cm_ReleaseUser(userp);
3456 smb_ReleaseFID(fidp);
3458 smb_SendTran2Packet(vcp, outp, opx);
3460 smb_SendTran2Error(vcp, p, opx, code);
3461 smb_FreeTran2Packet(outp);
3467 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3469 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3470 return CM_ERROR_BADOP;
3474 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3476 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3477 return CM_ERROR_BADOP;
3481 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3483 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3484 return CM_ERROR_BADOP;
3488 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3490 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3491 return CM_ERROR_BADOP;
3495 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3497 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3498 return CM_ERROR_BADOP;
3502 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3504 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3505 return CM_ERROR_BADOP;
3508 struct smb_v2_referral {
3510 USHORT ReferralFlags;
3513 USHORT DfsPathOffset;
3514 USHORT DfsAlternativePathOffset;
3515 USHORT NetworkAddressOffset;
3519 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3521 /* This is a UNICODE only request (bit15 of Flags2) */
3522 /* The TID must be IPC$ */
3524 /* The documentation for the Flags response field is contradictory */
3526 /* Use Version 1 Referral Element Format */
3527 /* ServerType = 0; indicates the next server should be queried for the file */
3528 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3529 /* Node = UnicodeString of UNC path of the next share name */
3532 int maxReferralLevel = 0;
3533 char requestFileName[1024] = "";
3534 smb_tran2Packet_t *outp = 0;
3535 cm_user_t *userp = 0;
3537 CPINFO CodePageInfo;
3538 int i, nbnLen, reqLen;
3543 maxReferralLevel = p->parmsp[0];
3545 GetCPInfo(CP_ACP, &CodePageInfo);
3546 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
3547 requestFileName, 1024, NULL, NULL);
3549 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
3550 maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3552 nbnLen = strlen(cm_NetbiosName);
3553 reqLen = strlen(requestFileName);
3555 if (reqLen == nbnLen + 5 &&
3556 requestFileName[0] == '\\' &&
3557 !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3558 requestFileName[nbnLen+1] == '\\' &&
3559 (!_strnicmp("all",&requestFileName[nbnLen+2],3) ||
3560 !_strnicmp("*.",&requestFileName[nbnLen+2],2)))
3563 struct smb_v2_referral * v2ref;
3564 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
3566 sp = (USHORT *)outp->datap;
3568 sp[idx++] = reqLen; /* path consumed */
3569 sp[idx++] = 1; /* number of referrals */
3570 sp[idx++] = 0x03; /* flags */
3571 #ifdef DFS_VERSION_1
3572 sp[idx++] = 1; /* Version Number */
3573 sp[idx++] = reqLen + 4; /* Referral Size */
3574 sp[idx++] = 1; /* Type = SMB Server */
3575 sp[idx++] = 0; /* Do not strip path consumed */
3576 for ( i=0;i<=reqLen; i++ )
3577 sp[i+idx] = requestFileName[i];
3578 #else /* DFS_VERSION_2 */
3579 sp[idx++] = 2; /* Version Number */
3580 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3581 idx += (sizeof(struct smb_v2_referral) / 2);
3582 v2ref = (struct smb_v2_referral *) &sp[5];
3583 v2ref->ServerType = 1; /* SMB Server */
3584 v2ref->ReferralFlags = 0x03;
3585 v2ref->Proximity = 0; /* closest */
3586 v2ref->TimeToLive = 3600; /* seconds */
3587 v2ref->DfsPathOffset = idx * 2;
3588 v2ref->DfsAlternativePathOffset = idx * 2;
3589 v2ref->NetworkAddressOffset = 0;
3590 for ( i=0;i<=reqLen; i++ )
3591 sp[i+idx] = requestFileName[i];
3594 userp = smb_GetTran2User(vcp, p);
3596 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3597 code = CM_ERROR_BADSMB;
3602 code = CM_ERROR_NOSUCHPATH;
3607 cm_ReleaseUser(userp);
3609 smb_SendTran2Packet(vcp, outp, op);
3611 smb_SendTran2Error(vcp, p, op, code);
3613 smb_FreeTran2Packet(outp);
3616 #else /* DFS_SUPPORT */
3617 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3618 return CM_ERROR_BADOP;
3619 #endif /* DFS_SUPPORT */
3623 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3625 /* This is a UNICODE only request (bit15 of Flags2) */
3627 /* There is nothing we can do about this operation. The client is going to
3628 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3629 * Unfortunately, there is really nothing we can do about it other then log it
3630 * somewhere. Even then I don't think there is anything for us to do.
3631 * So let's return an error value.
3634 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3635 return CM_ERROR_BADOP;
3639 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3640 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3645 cm_scache_t *targetScp; /* target if scp is a symlink */
3650 unsigned short attr;
3651 unsigned long lattr;
3652 smb_dirListPatch_t *patchp;
3653 smb_dirListPatch_t *npatchp;
3655 for(patchp = *dirPatchespp; patchp; patchp =
3656 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3657 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3659 lock_ObtainMutex(&scp->mx);
3660 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3661 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3663 lock_ReleaseMutex(&scp->mx);
3664 cm_ReleaseSCache(scp);
3666 dptr = patchp->dptr;
3668 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3669 errors in the client. */
3670 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3671 /* 1969-12-31 23:59:59 +00 */
3672 ft.dwHighDateTime = 0x19DB200;
3673 ft.dwLowDateTime = 0x5BB78980;
3675 /* copy to Creation Time */
3676 *((FILETIME *)dptr) = ft;
3679 /* copy to Last Access Time */
3680 *((FILETIME *)dptr) = ft;
3683 /* copy to Last Write Time */
3684 *((FILETIME *)dptr) = ft;
3687 /* copy to Change Time */
3688 *((FILETIME *)dptr) = ft;
3691 /* merge in hidden attribute */
3692 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3693 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3697 /* 1969-12-31 23:59:58 +00*/
3698 dosTime = 0xEBBFBF7D;
3700 /* and copy out date */
3701 shortTemp = (dosTime>>16) & 0xffff;
3702 *((u_short *)dptr) = shortTemp;
3705 /* copy out creation time */
3706 shortTemp = dosTime & 0xffff;
3707 *((u_short *)dptr) = shortTemp;
3710 /* and copy out date */
3711 shortTemp = (dosTime>>16) & 0xffff;
3712 *((u_short *)dptr) = shortTemp;
3715 /* copy out access time */
3716 shortTemp = dosTime & 0xffff;
3717 *((u_short *)dptr) = shortTemp;
3720 /* and copy out date */
3721 shortTemp = (dosTime>>16) & 0xffff;
3722 *((u_short *)dptr) = shortTemp;
3725 /* copy out mod time */
3726 shortTemp = dosTime & 0xffff;
3727 *((u_short *)dptr) = shortTemp;
3730 /* merge in hidden (dot file) attribute */
3731 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3732 attr = SMB_ATTR_HIDDEN;
3733 *dptr++ = attr & 0xff;
3734 *dptr++ = (attr >> 8) & 0xff;
3740 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3742 /* now watch for a symlink */
3744 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3745 lock_ReleaseMutex(&scp->mx);
3746 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3748 /* we have a more accurate file to use (the
3749 * target of the symbolic link). Otherwise,
3750 * we'll just use the symlink anyway.
3752 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3754 cm_ReleaseSCache(scp);
3757 lock_ObtainMutex(&scp->mx);
3760 dptr = patchp->dptr;
3762 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3764 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3766 /* copy to Creation Time */
3767 *((FILETIME *)dptr) = ft;
3770 /* copy to Last Access Time */
3771 *((FILETIME *)dptr) = ft;
3774 /* copy to Last Write Time */
3775 *((FILETIME *)dptr) = ft;
3778 /* copy to Change Time */
3779 *((FILETIME *)dptr) = ft;
3782 /* Use length for both file length and alloc length */
3783 *((LARGE_INTEGER *)dptr) = scp->length;
3785 *((LARGE_INTEGER *)dptr) = scp->length;
3788 /* Copy attributes */
3789 lattr = smb_ExtAttributes(scp);
3790 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3791 if (lattr == SMB_ATTR_NORMAL)
3792 lattr = SMB_ATTR_DIRECTORY;
3794 lattr |= SMB_ATTR_DIRECTORY;
3796 /* merge in hidden (dot file) attribute */
3797 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3798 if (lattr == SMB_ATTR_NORMAL)
3799 lattr = SMB_ATTR_HIDDEN;
3801 lattr |= SMB_ATTR_HIDDEN;
3803 *((u_long *)dptr) = lattr;
3807 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3809 /* and copy out date */
3810 shortTemp = (dosTime>>16) & 0xffff;
3811 *((u_short *)dptr) = shortTemp;
3814 /* copy out creation time */
3815 shortTemp = dosTime & 0xffff;
3816 *((u_short *)dptr) = shortTemp;
3819 /* and copy out date */
3820 shortTemp = (dosTime>>16) & 0xffff;
3821 *((u_short *)dptr) = shortTemp;
3824 /* copy out access time */
3825 shortTemp = dosTime & 0xffff;
3826 *((u_short *)dptr) = shortTemp;
3829 /* and copy out date */
3830 shortTemp = (dosTime>>16) & 0xffff;
3831 *((u_short *)dptr) = shortTemp;
3834 /* copy out mod time */
3835 shortTemp = dosTime & 0xffff;
3836 *((u_short *)dptr) = shortTemp;
3839 /* copy out file length and alloc length,
3840 * using the same for both
3842 *((u_long *)dptr) = scp->length.LowPart;
3844 *((u_long *)dptr) = scp->length.LowPart;
3847 /* finally copy out attributes as short */
3848 attr = smb_Attributes(scp);
3849 /* merge in hidden (dot file) attribute */
3850 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3851 if (lattr == SMB_ATTR_NORMAL)
3852 lattr = SMB_ATTR_HIDDEN;
3854 lattr |= SMB_ATTR_HIDDEN;
3856 *dptr++ = attr & 0xff;
3857 *dptr++ = (attr >> 8) & 0xff;
3860 lock_ReleaseMutex(&scp->mx);
3861 cm_ReleaseSCache(scp);
3864 /* now free the patches */
3865 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3866 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3870 /* and mark the list as empty */
3871 *dirPatchespp = NULL;
3876 #ifndef USE_OLD_MATCHING
3877 // char table for case insensitive comparison
3878 char mapCaseTable[256];
3880 VOID initUpperCaseTable(VOID)
3883 for (i = 0; i < 256; ++i)
3884 mapCaseTable[i] = toupper(i);
3885 // make '"' match '.'
3886 mapCaseTable[(int)'"'] = toupper('.');
3887 // make '<' match '*'
3888 mapCaseTable[(int)'<'] = toupper('*');
3889 // make '>' match '?'
3890 mapCaseTable[(int)'>'] = toupper('?');
3893 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3895 // Note : this procedure works recursively calling itself.
3897 // PSZ pattern : string containing metacharacters.
3898 // PSZ name : file name to be compared with 'pattern'.
3900 // BOOL : TRUE/FALSE (match/mistmatch)
3903 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
3905 PSZ pename; // points to the last 'name' character
3907 pename = name + strlen(name) - 1;
3918 if (*pattern == '\0')
3920 for (p = pename; p >= name; --p) {
3921 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
3922 !casefold && (*p == *pattern)) &&
3923 szWildCardMatchFileName(pattern + 1, p + 1, casefold))
3928 if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
3929 (!casefold && *name != *pattern))
3936 /* if all we have left are wildcards, then we match */
3937 for (;*pattern; pattern++) {
3938 if (*pattern != '*' && *pattern != '?')
3944 /* do a case-folding search of the star name mask with the name in namep.
3945 * Return 1 if we match, otherwise 0.
3947 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3950 int i, j, star, qmark, casefold, retval;
3952 /* make sure we only match 8.3 names, if requested */
3953 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3956 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
3958 /* optimize the pattern:
3959 * if there is a mixture of '?' and '*',
3960 * for example the sequence "*?*?*?*"
3961 * must be turned into the form "*"
3963 newmask = (char *)malloc(strlen(maskp)+1);
3964 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3965 switch ( maskp[i] ) {
3977 } else if ( qmark ) {
3981 newmask[j++] = maskp[i];
3988 } else if ( qmark ) {
3992 newmask[j++] = '\0';
3994 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
4000 #else /* USE_OLD_MATCHING */
4001 /* do a case-folding search of the star name mask with the name in namep.
4002 * Return 1 if we match, otherwise 0.
4004 int smb_V3MatchMask(char *namep, char *maskp, int flags)
4006 unsigned char tcp1, tcp2; /* Pattern characters */
4007 unsigned char tcn1; /* Name characters */
4008 int sawDot = 0, sawStar = 0, req8dot3 = 0;
4009 char *starNamep, *starMaskp;
4010 static char nullCharp[] = {0};
4011 int casefold = flags & CM_FLAG_CASEFOLD;
4013 /* make sure we only match 8.3 names, if requested */
4014 req8dot3 = (flags & CM_FLAG_8DOT3);
4015 if (req8dot3 && !cm_Is8Dot3(namep))
4020 /* Next pattern character */
4023 /* Next name character */
4027 /* 0 - end of pattern */
4033 else if (tcp1 == '.' || tcp1 == '"') {
4043 * first dot in pattern;
4044 * must match dot or end of name
4049 else if (tcn1 == '.') {
4058 else if (tcp1 == '?') {
4059 if (tcn1 == 0 || tcn1 == '.')
4064 else if (tcp1 == '>') {
4065 if (tcn1 != 0 && tcn1 != '.')
4069 else if (tcp1 == '*' || tcp1 == '<') {
4073 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
4074 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
4089 * pattern character after '*' is not null or
4090 * period. If it is '?' or '>', we are not
4091 * going to understand it. If it is '*' or
4092 * '<', we are going to skip over it. None of
4093 * these are likely, I hope.
4095 /* skip over '*' and '<' */
4096 while (tcp2 == '*' || tcp2 == '<')
4099 /* skip over characters that don't match tcp2 */
4100 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
4101 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
4102 (!casefold && tcn1 != tcp2)))
4106 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
4109 /* Remember where we are */
4119 /* tcp1 is not a wildcard */
4120 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
4121 (!casefold && tcn1 == tcp1)) {
4126 /* if trying to match a star pattern, go back */
4128 maskp = starMaskp - 2;
4129 namep = starNamep + 1;
4138 #endif /* USE_OLD_MATCHING */
4140 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4145 long code = 0, code2 = 0;
4149 smb_dirListPatch_t *dirListPatchesp;
4150 smb_dirListPatch_t *curPatchp;
4153 long orbytes; /* # of bytes in this output record */
4154 long ohbytes; /* # of bytes, except file name */
4155 long onbytes; /* # of bytes in name, incl. term. null */
4156 osi_hyper_t dirLength;
4157 osi_hyper_t bufferOffset;
4158 osi_hyper_t curOffset;
4160 smb_dirSearch_t *dsp;
4164 cm_pageHeader_t *pageHeaderp;
4165 cm_user_t *userp = NULL;
4168 long nextEntryCookie;
4169 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4170 char *op; /* output data ptr */
4171 char *origOp; /* original value of op */
4172 cm_space_t *spacep; /* for pathname buffer */
4173 long maxReturnData; /* max # of return data */
4174 long maxReturnParms; /* max # of return parms */
4175 long bytesInBuffer; /* # data bytes in the output buffer */
4177 char *maskp; /* mask part of path */
4181 smb_tran2Packet_t *outp; /* response packet */
4184 char shortName[13]; /* 8.3 name if needed */
4196 if (p->opcode == 1) {
4197 /* find first; obtain basic parameters from request */
4198 attribute = p->parmsp[0];
4199 maxCount = p->parmsp[1];
4200 infoLevel = p->parmsp[3];
4201 searchFlags = p->parmsp[2];
4202 dsp = smb_NewDirSearch(1);
4203 dsp->attribute = attribute;
4204 pathp = ((char *) p->parmsp) + 12; /* points to path */
4205 if (smb_StoreAnsiFilenames)
4206 OemToChar(pathp,pathp);
4208 maskp = strrchr(pathp, '\\');
4212 maskp++; /* skip over backslash */
4213 strcpy(dsp->mask, maskp); /* and save mask */
4214 /* track if this is likely to match a lot of entries */
4215 starPattern = smb_V3IsStarMask(maskp);
4218 osi_assert(p->opcode == 2);
4219 /* find next; obtain basic parameters from request or open dir file */
4220 dsp = smb_FindDirSearch(p->parmsp[0]);
4221 maxCount = p->parmsp[1];
4222 infoLevel = p->parmsp[2];
4223 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4224 searchFlags = p->parmsp[5];
4226 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4227 p->parmsp[0], nextCookie);
4228 return CM_ERROR_BADFD;
4230 attribute = dsp->attribute;
4233 starPattern = 1; /* assume, since required a Find Next */
4236 switch ( infoLevel ) {
4237 case SMB_INFO_STANDARD:
4240 case SMB_INFO_QUERY_EA_SIZE:
4241 s = "InfoQueryEaSize";
4243 case SMB_INFO_QUERY_EAS_FROM_LIST:
4244 s = "InfoQueryEasFromList";
4246 case SMB_FIND_FILE_DIRECTORY_INFO:
4247 s = "FindFileDirectoryInfo";
4249 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4250 s = "FindFileFullDirectoryInfo";
4252 case SMB_FIND_FILE_NAMES_INFO:
4253 s = "FindFileNamesInfo";
4255 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4256 s = "FindFileBothDirectoryInfo";
4259 s = "unknownInfoLevel";
4262 osi_Log1(smb_logp, "T2 search dir info level: %s", s);
4265 "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4266 attribute, infoLevel, maxCount, searchFlags);
4268 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
4269 p->opcode, dsp->cookie, nextCookie);
4271 if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4272 osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4273 smb_ReleaseDirSearch(dsp);
4274 return CM_ERROR_INVAL;
4277 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4278 searchFlags &= ~4; /* no resume keys */
4280 dirListPatchesp = NULL;
4282 maxReturnData = p->maxReturnData;
4283 if (p->opcode == 1) /* find first */
4284 maxReturnParms = 10; /* bytes */
4286 maxReturnParms = 8; /* bytes */
4288 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4289 if (maxReturnData > 6000)
4290 maxReturnData = 6000;
4291 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4293 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4296 osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
4297 maxCount, osi_LogSaveString(smb_logp, pathp));
4299 /* bail out if request looks bad */
4300 if (p->opcode == 1 && !pathp) {
4301 smb_ReleaseDirSearch(dsp);
4302 smb_FreeTran2Packet(outp);
4303 return CM_ERROR_BADSMB;
4306 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
4307 dsp->cookie, nextCookie, attribute);
4309 userp = smb_GetTran2User(vcp, p);
4311 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
4312 smb_ReleaseDirSearch(dsp);
4313 smb_FreeTran2Packet(outp);
4314 return CM_ERROR_BADSMB;
4317 /* try to get the vnode for the path name next */
4318 lock_ObtainMutex(&dsp->mx);
4321 osi_Log2(afsd_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4325 spacep = cm_GetSpace();
4326 smb_StripLastComponent(spacep->data, NULL, pathp);
4327 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4329 cm_ReleaseUser(userp);
4330 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4331 smb_FreeTran2Packet(outp);
4332 lock_ReleaseMutex(&dsp->mx);
4333 smb_DeleteDirSearch(dsp);
4334 smb_ReleaseDirSearch(dsp);
4337 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4338 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4339 userp, tidPathp, &req, &scp);
4340 cm_FreeSpace(spacep);
4343 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4344 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4345 cm_ReleaseSCache(scp);
4346 cm_ReleaseUser(userp);
4347 if ( WANTS_DFS_PATHNAMES(p) )
4348 code = CM_ERROR_PATH_NOT_COVERED;
4350 code = CM_ERROR_BADSHARENAME;
4351 smb_SendTran2Error(vcp, p, opx, code);
4352 smb_FreeTran2Packet(outp);
4353 lock_ReleaseMutex(&dsp->mx);
4354 smb_DeleteDirSearch(dsp);
4355 smb_ReleaseDirSearch(dsp);
4358 #endif /* DFS_SUPPORT */
4360 osi_Log2(afsd_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4361 /* we need one hold for the entry we just stored into,
4362 * and one for our own processing. When we're done
4363 * with this function, we'll drop the one for our own
4364 * processing. We held it once from the namei call,
4365 * and so we do another hold now.
4368 lock_ObtainMutex(&scp->mx);
4369 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
4370 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4371 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4372 dsp->flags |= SMB_DIRSEARCH_BULKST;
4374 lock_ReleaseMutex(&scp->mx);
4377 lock_ReleaseMutex(&dsp->mx);
4379 cm_ReleaseUser(userp);
4380 smb_FreeTran2Packet(outp);
4381 smb_DeleteDirSearch(dsp);
4382 smb_ReleaseDirSearch(dsp);
4386 /* get the directory size */
4387 lock_ObtainMutex(&scp->mx);
4388 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4389 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4391 lock_ReleaseMutex(&scp->mx);
4392 cm_ReleaseSCache(scp);
4393 cm_ReleaseUser(userp);
4394 smb_FreeTran2Packet(outp);
4395 smb_DeleteDirSearch(dsp);
4396 smb_ReleaseDirSearch(dsp);
4400 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4403 dirLength = scp->length;
4405 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4406 curOffset.HighPart = 0;
4407 curOffset.LowPart = nextCookie;
4408 origOp = outp->datap;
4416 if (searchFlags & 4)
4417 /* skip over resume key */
4420 /* make sure that curOffset.LowPart doesn't point to the first
4421 * 32 bytes in the 2nd through last dir page, and that it doesn't
4422 * point at the first 13 32-byte chunks in the first dir page,
4423 * since those are dir and page headers, and don't contain useful
4426 temp = curOffset.LowPart & (2048-1);
4427 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4428 /* we're in the first page */
4429 if (temp < 13*32) temp = 13*32;
4432 /* we're in a later dir page */
4433 if (temp < 32) temp = 32;
4436 /* make sure the low order 5 bits are zero */
4439 /* now put temp bits back ito curOffset.LowPart */
4440 curOffset.LowPart &= ~(2048-1);
4441 curOffset.LowPart |= temp;
4443 /* check if we've passed the dir's EOF */
4444 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4445 osi_Log0(smb_logp, "T2 search dir passed eof");
4450 /* check if we've returned all the names that will fit in the
4451 * response packet; we check return count as well as the number
4452 * of bytes requested. We check the # of bytes after we find
4453 * the dir entry, since we'll need to check its size.
4455 if (returnedNames >= maxCount) {
4456 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4457 returnedNames, maxCount);
4461 /* see if we can use the bufferp we have now; compute in which
4462 * page the current offset would be, and check whether that's
4463 * the offset of the buffer we have. If not, get the buffer.
4465 thyper.HighPart = curOffset.HighPart;
4466 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4467 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4470 buf_Release(bufferp);
4473 lock_ReleaseMutex(&scp->mx);
4474 lock_ObtainRead(&scp->bufCreateLock);
4475 code = buf_Get(scp, &thyper, &bufferp);
4476 lock_ReleaseRead(&scp->bufCreateLock);
4477 lock_ObtainMutex(&dsp->mx);
4479 /* now, if we're doing a star match, do bulk fetching
4480 * of all of the status info for files in the dir.
4483 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
4486 lock_ObtainMutex(&scp->mx);
4487 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4488 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
4489 /* Don't bulk stat if risking timeout */
4490 int now = GetTickCount();
4491 if (now - req.startTime > RDRtimeout) {
4492 scp->bulkStatProgress = thyper;
4493 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4494 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4496 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4499 lock_ObtainMutex(&scp->mx);
4501 lock_ReleaseMutex(&dsp->mx);
4503 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
4507 bufferOffset = thyper;
4509 /* now get the data in the cache */
4511 code = cm_SyncOp(scp, bufferp, userp, &req,
4513 CM_SCACHESYNC_NEEDCALLBACK
4514 | CM_SCACHESYNC_READ);
4516 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
4520 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4522 if (cm_HaveBuffer(scp, bufferp, 0)) {
4523 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4527 /* otherwise, load the buffer and try again */
4528 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4531 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4532 scp, bufferp, code);
4537 buf_Release(bufferp);
4541 } /* if (wrong buffer) ... */
4543 /* now we have the buffer containing the entry we're interested
4544 * in; copy it out if it represents a non-deleted entry.
4546 entryInDir = curOffset.LowPart & (2048-1);
4547 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4549 /* page header will help tell us which entries are free. Page
4550 * header can change more often than once per buffer, since
4551 * AFS 3 dir page size may be less than (but not more than)
4552 * a buffer package buffer.
4554 /* only look intra-buffer */
4555 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4556 temp &= ~(2048 - 1); /* turn off intra-page bits */
4557 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4559 /* now determine which entry we're looking at in the page.
4560 * If it is free (there's a free bitmap at the start of the
4561 * dir), we should skip these 32 bytes.
4563 slotInPage = (entryInDir & 0x7e0) >> 5;
4564 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
4565 (1 << (slotInPage & 0x7)))) {
4566 /* this entry is free */
4567 numDirChunks = 1; /* only skip this guy */
4571 tp = bufferp->datap + entryInBuffer;
4572 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4574 /* while we're here, compute the next entry's location, too,
4575 * since we'll need it when writing out the cookie into the dir
4578 * XXXX Probably should do more sanity checking.
4580 numDirChunks = cm_NameEntries(dep->name, &onbytes);
4582 /* compute offset of cookie representing next entry */
4583 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4585 /* Need 8.3 name? */
4587 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4588 && dep->fid.vnode != 0
4589 && !cm_Is8Dot3(dep->name)) {
4590 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4594 osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %s (%s)",
4595 dep->fid.vnode, dep->fid.unique,
4596 osi_LogSaveString(smb_logp, dep->name),
4597 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4599 /* When matching, we are using doing a case fold if we have a wildcard mask.
4600 * If we get a non-wildcard match, it's a lookup for a specific file.
4602 if (dep->fid.vnode != 0 &&
4603 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
4605 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
4607 /* Eliminate entries that don't match requested attributes */
4608 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
4609 smb_IsDotFile(dep->name)) {
4610 osi_Log0(smb_logp, "T2 search dir skipping hidden");
4611 goto nextEntry; /* no hidden files */
4613 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4615 /* We have already done the cm_TryBulkStat above */
4616 fid.cell = scp->fid.cell;
4617 fid.volume = scp->fid.volume;
4618 fid.vnode = ntohl(dep->fid.vnode);
4619 fid.unique = ntohl(dep->fid.unique);
4620 fileType = cm_FindFileType(&fid);
4621 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
4622 "has filetype %d", dep->name,
4624 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4625 fileType == CM_SCACHETYPE_DFSLINK ||
4626 fileType == CM_SCACHETYPE_INVALID)
4627 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
4631 /* finally check if this name will fit */
4633 /* standard dir entry stuff */
4634 if (infoLevel < 0x101)
4635 ohbytes = 23; /* pre-NT */
4636 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4637 ohbytes = 12; /* NT names only */
4639 ohbytes = 64; /* NT */
4641 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
4642 ohbytes += 26; /* Short name & length */
4644 if (searchFlags & 4) {
4645 ohbytes += 4; /* if resume key required */
4648 if (infoLevel != SMB_INFO_STANDARD
4649 && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
4650 && infoLevel != SMB_FIND_FILE_NAMES_INFO)
4651 ohbytes += 4; /* EASIZE */
4653 /* add header to name & term. null */
4654 orbytes = onbytes + ohbytes + 1;
4656 /* now, we round up the record to a 4 byte alignment,
4657 * and we make sure that we have enough room here for
4658 * even the aligned version (so we don't have to worry
4659 * about an * overflow when we pad things out below).
4660 * That's the reason for the alignment arithmetic below.
4662 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4663 align = (4 - (orbytes & 3)) & 3;
4666 if (orbytes + bytesInBuffer + align > maxReturnData) {
4667 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4672 /* this is one of the entries to use: it is not deleted
4673 * and it matches the star pattern we're looking for.
4674 * Put out the name, preceded by its length.
4676 /* First zero everything else */
4677 memset(origOp, 0, ohbytes);
4679 if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
4680 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4681 else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4682 *((u_long *)(op + 8)) = onbytes;
4684 *((u_long *)(op + 60)) = onbytes;
4685 strcpy(origOp+ohbytes, dep->name);
4686 if (smb_StoreAnsiFilenames)
4687 CharToOem(origOp+ohbytes, origOp+ohbytes);
4689 /* Short name if requested and needed */
4690 if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4691 if (NeedShortName) {
4692 strcpy(op + 70, shortName);
4693 if (smb_StoreAnsiFilenames)
4694 CharToOem(op + 70, op + 70);
4695 *(op + 68) = (char)(shortNameEnd - shortName);
4699 /* now, adjust the # of entries copied */
4702 /* NextEntryOffset and FileIndex */
4703 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4704 int entryOffset = orbytes + align;
4705 *((u_long *)op) = entryOffset;
4706 *((u_long *)(op+4)) = nextEntryCookie;
4709 /* now we emit the attribute. This is tricky, since
4710 * we need to really stat the file to find out what
4711 * type of entry we've got. Right now, we're copying
4712 * out data from a buffer, while holding the scp
4713 * locked, so it isn't really convenient to stat
4714 * something now. We'll put in a place holder
4715 * now, and make a second pass before returning this
4716 * to get the real attributes. So, we just skip the
4717 * data for now, and adjust it later. We allocate a
4718 * patch record to make it easy to find this point
4719 * later. The replay will happen at a time when it is
4720 * safe to unlock the directory.
4722 if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4723 curPatchp = malloc(sizeof(*curPatchp));
4724 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4726 curPatchp->dptr = op;
4727 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4728 curPatchp->dptr += 8;
4730 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4731 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4734 curPatchp->flags = 0;
4736 curPatchp->fid.cell = scp->fid.cell;
4737 curPatchp->fid.volume = scp->fid.volume;
4738 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4739 curPatchp->fid.unique = ntohl(dep->fid.unique);
4742 curPatchp->dep = dep;
4745 if (searchFlags & 4)
4746 /* put out resume key */
4747 *((u_long *)origOp) = nextEntryCookie;
4749 /* Adjust byte ptr and count */
4750 origOp += orbytes; /* skip entire record */
4751 bytesInBuffer += orbytes;
4753 /* and pad the record out */
4754 while (--align >= 0) {
4758 } /* if we're including this name */
4759 else if (!starPattern &&
4761 dep->fid.vnode != 0 &&
4762 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4763 /* We were looking for exact matches, but here's an inexact one*/
4768 /* and adjust curOffset to be where the new cookie is */
4769 thyper.HighPart = 0;
4770 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4771 curOffset = LargeIntegerAdd(thyper, curOffset);
4772 } /* while copying data for dir listing */
4774 /* If we didn't get a star pattern, we did an exact match during the first pass.
4775 * If there were no exact matches found, we fail over to inexact matches by
4776 * marking the query as a star pattern (matches all case permutations), and
4777 * re-running the query.
4779 if (returnedNames == 0 && !starPattern && foundInexact) {
4780 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4785 /* release the mutex */
4786 lock_ReleaseMutex(&scp->mx);
4788 buf_Release(bufferp);
4792 /* apply and free last set of patches; if not doing a star match, this
4793 * will be empty, but better safe (and freeing everything) than sorry.
4795 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4798 /* now put out the final parameters */
4799 if (returnedNames == 0)
4801 if (p->opcode == 1) {
4803 outp->parmsp[0] = (unsigned short) dsp->cookie;
4804 outp->parmsp[1] = returnedNames;
4805 outp->parmsp[2] = eos;
4806 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4807 outp->parmsp[4] = 0;
4808 /* don't need last name to continue
4809 * search, cookie is enough. Normally,
4810 * this is the offset of the file name
4811 * of the last entry returned.
4813 outp->totalParms = 10; /* in bytes */
4817 outp->parmsp[0] = returnedNames;
4818 outp->parmsp[1] = eos;
4819 outp->parmsp[2] = 0; /* EAS error */
4820 outp->parmsp[3] = 0; /* last name, as above */
4821 outp->totalParms = 8; /* in bytes */
4824 /* return # of bytes in the buffer */
4825 outp->totalData = bytesInBuffer;
4827 /* Return error code if unsuccessful on first request */
4828 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4829 code = CM_ERROR_NOSUCHFILE;
4831 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
4832 p->opcode, dsp->cookie, returnedNames, code);
4834 /* if we're supposed to close the search after this request, or if
4835 * we're supposed to close the search if we're done, and we're done,
4836 * or if something went wrong, close the search.
4838 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4839 if ((searchFlags & 1) || (returnedNames == 0) ||
4840 ((searchFlags & 2) && eos) || code != 0)
4841 smb_DeleteDirSearch(dsp);
4843 smb_SendTran2Error(vcp, p, opx, code);
4845 smb_SendTran2Packet(vcp, outp, opx);
4847 smb_FreeTran2Packet(outp);
4848 smb_ReleaseDirSearch(dsp);
4849 cm_ReleaseSCache(scp);
4850 cm_ReleaseUser(userp);
4854 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4857 smb_dirSearch_t *dsp;
4859 dirHandle = smb_GetSMBParm(inp, 0);
4861 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4863 dsp = smb_FindDirSearch(dirHandle);
4866 return CM_ERROR_BADFD;
4868 /* otherwise, we have an FD to destroy */
4869 smb_DeleteDirSearch(dsp);
4870 smb_ReleaseDirSearch(dsp);
4872 /* and return results */
4873 smb_SetSMBDataLength(outp, 0);
4878 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4880 smb_SetSMBDataLength(outp, 0);
4884 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4891 cm_scache_t *dscp; /* dir we're dealing with */
4892 cm_scache_t *scp; /* file we're creating */
4894 int initialModeBits;
4904 int parmSlot; /* which parm we're dealing with */
4913 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4914 openFun = smb_GetSMBParm(inp, 8); /* open function */
4915 excl = ((openFun & 3) == 0);
4916 trunc = ((openFun & 3) == 2); /* truncate it */
4917 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4918 openAction = 0; /* tracks what we did */
4920 attributes = smb_GetSMBParm(inp, 5);
4921 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4923 /* compute initial mode bits based on read-only flag in attributes */
4924 initialModeBits = 0666;
4925 if (attributes & SMB_ATTR_READONLY)
4926 initialModeBits &= ~0222;
4928 pathp = smb_GetSMBData(inp, NULL);
4929 if (smb_StoreAnsiFilenames)
4930 OemToChar(pathp,pathp);
4932 spacep = inp->spacep;
4933 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4935 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4936 /* special case magic file name for receiving IOCTL requests
4937 * (since IOCTL calls themselves aren't getting through).
4940 osi_Log0(smb_logp, "IOCTL Open");
4943 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4944 smb_SetupIoctlFid(fidp, spacep);
4946 /* set inp->fid so that later read calls in same msg can find fid */
4947 inp->fid = fidp->fid;
4949 /* copy out remainder of the parms */
4951 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4953 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4954 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4955 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4956 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4957 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4958 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4959 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4960 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4962 /* and the final "always present" stuff */
4963 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4964 /* next write out the "unique" ID */
4965 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4966 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4967 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4968 smb_SetSMBDataLength(outp, 0);
4970 /* and clean up fid reference */
4971 smb_ReleaseFID(fidp);
4975 #ifdef DEBUG_VERBOSE
4977 char *hexp, *asciip;
4978 asciip = (lastNamep ? lastNamep : pathp );
4979 hexp = osi_HexifyString(asciip);
4980 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4984 userp = smb_GetUserFromVCP(vcp, inp);
4987 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4989 cm_ReleaseUser(userp);
4990 return CM_ERROR_NOSUCHPATH;
4992 code = cm_NameI(cm_data.rootSCachep, pathp,
4993 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4994 userp, tidPathp, &req, &scp);
4997 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4998 cm_ReleaseSCache(scp);
4999 cm_ReleaseUser(userp);
5000 if ( WANTS_DFS_PATHNAMES(inp) )
5001 return CM_ERROR_PATH_NOT_COVERED;
5003 return CM_ERROR_BADSHARENAME;
5005 #endif /* DFS_SUPPORT */
5008 code = cm_NameI(cm_data.rootSCachep, spacep->data,
5009 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5010 userp, tidPathp, &req, &dscp);
5012 cm_ReleaseUser(userp);
5017 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5018 cm_ReleaseSCache(dscp);
5019 cm_ReleaseUser(userp);
5020 if ( WANTS_DFS_PATHNAMES(inp) )
5021 return CM_ERROR_PATH_NOT_COVERED;
5023 return CM_ERROR_BADSHARENAME;
5025 #endif /* DFS_SUPPORT */
5026 /* otherwise, scp points to the parent directory. Do a lookup,
5027 * and truncate the file if we find it, otherwise we create the
5034 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
5036 if (code && code != CM_ERROR_NOSUCHFILE) {
5037 cm_ReleaseSCache(dscp);
5038 cm_ReleaseUser(userp);
5043 /* if we get here, if code is 0, the file exists and is represented by
5044 * scp. Otherwise, we have to create it. The dir may be represented
5045 * by dscp, or we may have found the file directly. If code is non-zero,
5049 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
5051 if (dscp) cm_ReleaseSCache(dscp);
5052 cm_ReleaseSCache(scp);
5053 cm_ReleaseUser(userp);
5058 /* oops, file shouldn't be there */
5060 cm_ReleaseSCache(dscp);
5061 cm_ReleaseSCache(scp);
5062 cm_ReleaseUser(userp);
5063 return CM_ERROR_EXISTS;
5067 setAttr.mask = CM_ATTRMASK_LENGTH;
5068 setAttr.length.LowPart = 0;
5069 setAttr.length.HighPart = 0;
5070 code = cm_SetAttr(scp, &setAttr, userp, &req);
5071 openAction = 3; /* truncated existing file */
5073 else openAction = 1; /* found existing file */
5075 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
5076 /* don't create if not found */
5077 if (dscp) cm_ReleaseSCache(dscp);
5078 cm_ReleaseUser(userp);
5079 return CM_ERROR_NOSUCHFILE;
5082 osi_assert(dscp != NULL);
5083 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
5084 osi_LogSaveString(smb_logp, lastNamep));
5085 openAction = 2; /* created file */
5086 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5087 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5088 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5092 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5093 smb_NotifyChange(FILE_ACTION_ADDED,
5094 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5095 dscp, lastNamep, NULL, TRUE);
5096 } else if (!excl && code == CM_ERROR_EXISTS) {
5097 /* not an exclusive create, and someone else tried
5098 * creating it already, then we open it anyway. We
5099 * don't bother retrying after this, since if this next
5100 * fails, that means that the file was deleted after we
5101 * started this call.
5103 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5107 setAttr.mask = CM_ATTRMASK_LENGTH;
5108 setAttr.length.LowPart = 0;
5109 setAttr.length.HighPart = 0;
5110 code = cm_SetAttr(scp, &setAttr, userp, &req);
5112 } /* lookup succeeded */
5116 /* we don't need this any longer */
5118 cm_ReleaseSCache(dscp);
5121 /* something went wrong creating or truncating the file */
5123 cm_ReleaseSCache(scp);
5124 cm_ReleaseUser(userp);
5128 /* make sure we're about to open a file */
5129 if (scp->fileType != CM_SCACHETYPE_FILE) {
5130 cm_ReleaseSCache(scp);
5131 cm_ReleaseUser(userp);
5132 return CM_ERROR_ISDIR;
5135 /* now all we have to do is open the file itself */
5136 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5140 lock_ObtainMutex(&fidp->mx);
5141 /* save a pointer to the vnode */
5143 lock_ObtainMutex(&scp->mx);
5144 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5145 lock_ReleaseMutex(&scp->mx);
5146 osi_Log2(afsd_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
5148 fidp->userp = userp;
5150 /* compute open mode */
5152 fidp->flags |= SMB_FID_OPENREAD;
5153 if (openMode == 1 || openMode == 2)
5154 fidp->flags |= SMB_FID_OPENWRITE;
5156 /* remember if the file was newly created */
5158 fidp->flags |= SMB_FID_CREATED;
5160 lock_ReleaseMutex(&fidp->mx);
5161 smb_ReleaseFID(fidp);
5163 cm_Open(scp, 0, userp);
5165 /* set inp->fid so that later read calls in same msg can find fid */
5166 inp->fid = fidp->fid;
5168 /* copy out remainder of the parms */
5170 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5171 lock_ObtainMutex(&scp->mx);
5173 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5174 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5175 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5176 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5177 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5178 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5179 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5180 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5181 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5183 /* and the final "always present" stuff */
5184 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5185 /* next write out the "unique" ID */
5186 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5187 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5188 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5189 lock_ReleaseMutex(&scp->mx);
5190 smb_SetSMBDataLength(outp, 0);
5192 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5194 cm_ReleaseUser(userp);
5195 /* leave scp held since we put it in fidp->scp */
5199 static void smb_GetLockParams(unsigned char LockType,
5201 unsigned int * ppid,
5202 LARGE_INTEGER * pOffset,
5203 LARGE_INTEGER * pLength)
5205 if (LockType & LOCKING_ANDX_LARGE_FILES) {
5207 *ppid = *((USHORT *) *buf);
5208 pOffset->HighPart = *((LONG *)(*buf + 4));
5209 pOffset->LowPart = *((DWORD *)(*buf + 8));
5210 pLength->HighPart = *((LONG *)(*buf + 12));
5211 pLength->LowPart = *((DWORD *)(*buf + 16));
5215 /* Not Large Files */
5216 *ppid = *((USHORT *) *buf);
5217 pOffset->HighPart = 0;
5218 pOffset->LowPart = *((DWORD *)(*buf + 2));
5219 pLength->HighPart = 0;
5220 pLength->LowPart = *((DWORD *)(*buf + 6));
5225 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5232 unsigned char LockType;
5233 unsigned short NumberOfUnlocks, NumberOfLocks;
5237 LARGE_INTEGER LOffset, LLength;
5238 smb_waitingLockRequest_t *wlRequest = NULL;
5239 cm_file_lock_t *lockp;
5247 fid = smb_GetSMBParm(inp, 2);
5248 fid = smb_ChainFID(fid, inp);
5250 fidp = smb_FindFID(vcp, fid, 0);
5252 return CM_ERROR_BADFD;
5254 lock_ObtainMutex(&fidp->mx);
5255 if (fidp->flags & SMB_FID_IOCTL) {
5256 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
5257 lock_ReleaseMutex(&fidp->mx);
5258 smb_ReleaseFID(fidp);
5259 return CM_ERROR_BADFD;
5262 osi_Log2(afsd_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
5264 lock_ReleaseMutex(&fidp->mx);
5266 /* set inp->fid so that later read calls in same msg can find fid */
5269 userp = smb_GetUserFromVCP(vcp, inp);
5272 lock_ObtainMutex(&scp->mx);
5273 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5274 CM_SCACHESYNC_NEEDCALLBACK
5275 | CM_SCACHESYNC_GETSTATUS
5276 | CM_SCACHESYNC_LOCK);
5278 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
5282 LockType = smb_GetSMBParm(inp, 3) & 0xff;
5283 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
5284 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
5285 NumberOfLocks = smb_GetSMBParm(inp, 7);
5287 if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
5288 (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
5290 /* We don't support these requests. Apparently, we can safely
5291 not deal with them too. */
5292 osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
5293 ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
5294 "LOCKING_ANDX_CANCEL_LOCK":
5295 "LOCKING_ANDX_CHANGE_LOCKTYPE"));
5296 /* No need to call osi_LogSaveString since these are string
5299 code = CM_ERROR_BADOP;
5304 op = smb_GetSMBData(inp, NULL);
5306 for (i=0; i<NumberOfUnlocks; i++) {
5307 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5309 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5311 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
5319 for (i=0; i<NumberOfLocks; i++) {
5320 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5322 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5324 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
5325 userp, &req, &lockp);
5327 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
5328 smb_waitingLock_t * wLock;
5330 /* Put on waiting list */
5331 if(wlRequest == NULL) {
5335 LARGE_INTEGER tOffset, tLength;
5337 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
5339 osi_assert(wlRequest != NULL);
5341 wlRequest->vcp = vcp;
5343 wlRequest->scp = scp;
5344 osi_Log2(afsd_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
5346 wlRequest->inp = smb_CopyPacket(inp);
5347 wlRequest->outp = smb_CopyPacket(outp);
5348 wlRequest->lockType = LockType;
5349 wlRequest->timeRemaining = Timeout;
5350 wlRequest->locks = NULL;
5352 /* The waiting lock request needs to have enough
5353 information to undo all the locks in the request.
5354 We do the following to store info about locks that
5355 have already been granted. Sure, we can get most
5356 of the info from the packet, but the packet doesn't
5357 hold the result of cm_Lock call. In practice we
5358 only receive packets with one or two locks, so we
5359 are only wasting a few bytes here and there and
5360 only for a limited period of time until the waiting
5361 lock times out or is freed. */
5363 for(opt = op_locks, j=i; j > 0; j--) {
5364 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
5366 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5368 wLock = malloc(sizeof(smb_waitingLock_t));
5370 osi_assert(wLock != NULL);
5373 wLock->LOffset = tOffset;
5374 wLock->LLength = tLength;
5375 wLock->lockp = NULL;
5376 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
5377 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5382 wLock = malloc(sizeof(smb_waitingLock_t));
5384 osi_assert(wLock != NULL);
5387 wLock->LOffset = LOffset;
5388 wLock->LLength = LLength;
5389 wLock->lockp = lockp;
5390 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
5391 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5394 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
5402 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
5409 /* Since something went wrong with the lock number i, we now
5410 have to go ahead and release any locks acquired before the
5411 failure. All locks before lock number i (of which there
5412 are i of them) have either been successful or are waiting.
5413 Either case requires calling cm_Unlock(). */
5415 /* And purge the waiting lock */
5416 if(wlRequest != NULL) {
5417 smb_waitingLock_t * wl;
5418 smb_waitingLock_t * wlNext;
5421 for(wl = wlRequest->locks; wl; wl = wlNext) {
5423 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
5425 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
5428 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
5430 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
5433 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
5438 smb_ReleaseVC(wlRequest->vcp);
5439 cm_ReleaseSCache(wlRequest->scp);
5440 smb_FreePacket(wlRequest->inp);
5441 smb_FreePacket(wlRequest->outp);
5450 if (wlRequest != NULL) {
5452 lock_ObtainWrite(&smb_globalLock);
5453 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
5455 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
5456 lock_ReleaseWrite(&smb_globalLock);
5458 /* don't send reply immediately */
5459 outp->flags |= SMB_PACKETFLAG_NOSEND;
5462 smb_SetSMBDataLength(outp, 0);
5466 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5469 lock_ReleaseMutex(&scp->mx);
5470 cm_ReleaseSCache(scp);
5471 cm_ReleaseUser(userp);
5472 smb_ReleaseFID(fidp);
5477 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5483 afs_uint32 searchTime;
5489 fid = smb_GetSMBParm(inp, 0);
5490 fid = smb_ChainFID(fid, inp);
5492 fidp = smb_FindFID(vcp, fid, 0);
5494 return CM_ERROR_BADFD;
5496 lock_ObtainMutex(&fidp->mx);
5497 if (fidp->flags & SMB_FID_IOCTL) {
5498 lock_ReleaseMutex(&fidp->mx);
5499 smb_ReleaseFID(fidp);
5500 return CM_ERROR_BADFD;
5503 osi_Log2(afsd_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
5505 lock_ReleaseMutex(&fidp->mx);
5507 userp = smb_GetUserFromVCP(vcp, inp);
5510 /* otherwise, stat the file */
5511 lock_ObtainMutex(&scp->mx);
5512 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5513 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5517 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5519 /* decode times. We need a search time, but the response to this
5520 * call provides the date first, not the time, as returned in the
5521 * searchTime variable. So we take the high-order bits first.
5523 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
5524 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
5525 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
5526 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
5527 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
5528 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
5529 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
5531 /* now handle file size and allocation size */
5532 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
5533 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
5534 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
5535 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
5537 /* file attribute */
5538 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
5540 /* and finalize stuff */
5541 smb_SetSMBDataLength(outp, 0);
5545 lock_ReleaseMutex(&scp->mx);
5546 cm_ReleaseSCache(scp);
5547 cm_ReleaseUser(userp);
5548 smb_ReleaseFID(fidp);
5552 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5558 afs_uint32 searchTime;
5566 fid = smb_GetSMBParm(inp, 0);
5567 fid = smb_ChainFID(fid, inp);
5569 fidp = smb_FindFID(vcp, fid, 0);
5571 return CM_ERROR_BADFD;
5573 lock_ObtainMutex(&fidp->mx);
5574 if (fidp->flags & SMB_FID_IOCTL) {
5575 lock_ReleaseMutex(&fidp->mx);
5576 smb_ReleaseFID(fidp);
5577 return CM_ERROR_BADFD;
5580 osi_Log2(afsd_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
5582 lock_ReleaseMutex(&fidp->mx);
5584 userp = smb_GetUserFromVCP(vcp, inp);
5587 /* now prepare to call cm_setattr. This message only sets various times,
5588 * and AFS only implements mtime, and we'll set the mtime if that's
5589 * requested. The others we'll ignore.
5591 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
5593 if (searchTime != 0) {
5594 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
5596 if ( unixTime != -1 ) {
5597 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
5598 attrs.clientModTime = unixTime;
5599 code = cm_SetAttr(scp, &attrs, userp, &req);
5601 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
5603 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
5609 cm_ReleaseSCache(scp);
5610 cm_ReleaseUser(userp);
5611 smb_ReleaseFID(fidp);
5615 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5618 long count, written = 0, total_written = 0;
5625 int inDataBlockCount;
5627 fd = smb_GetSMBParm(inp, 2);
5628 count = smb_GetSMBParm(inp, 10);
5630 offset.HighPart = 0;
5631 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5633 if (*inp->wctp == 14) {
5634 /* we have a request with 64-bit file offsets */
5635 #ifdef AFS_LARGEFILES
5636 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
5638 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
5640 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
5641 /* we shouldn't have received this op if we didn't specify
5642 largefile support */
5643 return CM_ERROR_BADOP;
5648 op = inp->data + smb_GetSMBParm(inp, 11);
5649 inDataBlockCount = count;
5651 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
5652 fd, offset.HighPart, offset.LowPart, count);
5654 fd = smb_ChainFID(fd, inp);
5655 fidp = smb_FindFID(vcp, fd, 0);
5657 return CM_ERROR_BADFD;
5659 lock_ObtainMutex(&fidp->mx);
5660 if (fidp->flags & SMB_FID_IOCTL) {
5661 lock_ReleaseMutex(&fidp->mx);
5662 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
5663 smb_ReleaseFID(fidp);
5666 lock_ReleaseMutex(&fidp->mx);
5667 userp = smb_GetUserFromVCP(vcp, inp);
5669 /* special case: 0 bytes transferred means there is no data
5670 transferred. A slight departure from SMB_COM_WRITE where this
5671 means that we are supposed to truncate the file at this
5676 LARGE_INTEGER LOffset;
5677 LARGE_INTEGER LLength;
5679 pid = ((smb_t *) inp)->pid;
5680 key = cm_GenerateKey(vcp->vcID, pid, fd);
5682 LOffset.HighPart = offset.HighPart;
5683 LOffset.LowPart = offset.LowPart;
5684 LLength.HighPart = 0;
5685 LLength.LowPart = count;
5687 lock_ObtainMutex(&fidp->scp->mx);
5688 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
5689 lock_ReleaseMutex(&fidp->scp->mx);
5696 * Work around bug in NT client
5698 * When copying a file, the NT client should first copy the data,
5699 * then copy the last write time. But sometimes the NT client does
5700 * these in the wrong order, so the data copies would inadvertently
5701 * cause the last write time to be overwritten. We try to detect this,
5702 * and don't set client mod time if we think that would go against the
5705 lock_ObtainMutex(&fidp->mx);
5706 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5707 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5708 fidp->scp->clientModTime = time(NULL);
5710 lock_ReleaseMutex(&fidp->mx);
5713 while ( code == 0 && count > 0 ) {
5715 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5717 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5719 if (code == 0 && written == 0)
5720 code = CM_ERROR_PARTIALWRITE;
5722 offset = LargeIntegerAdd(offset,
5723 ConvertLongToLargeInteger(written));
5725 total_written += written;
5731 /* slots 0 and 1 are reserved for request chaining and will be
5732 filled in when we return. */
5733 smb_SetSMBParm(outp, 2, total_written);
5734 smb_SetSMBParm(outp, 3, 0); /* reserved */
5735 smb_SetSMBParm(outp, 4, 0); /* reserved */
5736 smb_SetSMBParm(outp, 5, 0); /* reserved */
5737 smb_SetSMBDataLength(outp, 0);
5740 smb_ReleaseFID(fidp);
5741 cm_ReleaseUser(userp);
5746 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5750 long finalCount = 0;
5759 fd = smb_GetSMBParm(inp, 2);
5760 count = smb_GetSMBParm(inp, 5);
5761 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5763 if (*inp->wctp == 12) {
5764 /* a request with 64-bit offsets */
5765 #ifdef AFS_LARGEFILES
5766 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
5768 if (LargeIntegerLessThanZero(offset)) {
5769 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
5770 offset.HighPart, offset.LowPart);
5771 return CM_ERROR_BADSMB;
5774 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
5775 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
5776 return CM_ERROR_BADSMB;
5778 offset.HighPart = 0;
5782 offset.HighPart = 0;
5785 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
5786 fd, offset.HighPart, offset.LowPart, count);
5788 fd = smb_ChainFID(fd, inp);
5789 fidp = smb_FindFID(vcp, fd, 0);
5791 return CM_ERROR_BADFD;
5794 pid = ((smb_t *) inp)->pid;
5795 key = cm_GenerateKey(vcp->vcID, pid, fd);
5797 LARGE_INTEGER LOffset, LLength;
5799 LOffset.HighPart = offset.HighPart;
5800 LOffset.LowPart = offset.LowPart;
5801 LLength.HighPart = 0;
5802 LLength.LowPart = count;
5804 lock_ObtainMutex(&fidp->scp->mx);
5805 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
5806 lock_ReleaseMutex(&fidp->scp->mx);
5810 smb_ReleaseFID(fidp);
5814 /* set inp->fid so that later read calls in same msg can find fid */
5817 lock_ObtainMutex(&fidp->mx);
5818 if (fidp->flags & SMB_FID_IOCTL) {
5819 lock_ReleaseMutex(&fidp->mx);
5820 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
5821 smb_ReleaseFID(fidp);
5824 lock_ReleaseMutex(&fidp->mx);
5826 userp = smb_GetUserFromVCP(vcp, inp);
5828 /* 0 and 1 are reserved for request chaining, were setup by our caller,
5829 * and will be further filled in after we return.
5831 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
5832 smb_SetSMBParm(outp, 3, 0); /* resvd */
5833 smb_SetSMBParm(outp, 4, 0); /* resvd */
5834 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
5835 /* fill in #6 when we have all the parameters' space reserved */
5836 smb_SetSMBParm(outp, 7, 0); /* resv'd */
5837 smb_SetSMBParm(outp, 8, 0); /* resv'd */
5838 smb_SetSMBParm(outp, 9, 0); /* resv'd */
5839 smb_SetSMBParm(outp, 10, 0); /* resv'd */
5840 smb_SetSMBParm(outp, 11, 0); /* reserved */
5842 /* get op ptr after putting in the parms, since otherwise we don't
5843 * know where the data really is.
5845 op = smb_GetSMBData(outp, NULL);
5847 /* now fill in offset from start of SMB header to first data byte (to op) */
5848 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
5850 /* set the packet data length the count of the # of bytes */
5851 smb_SetSMBDataLength(outp, count);
5854 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5856 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5859 /* fix some things up */
5860 smb_SetSMBParm(outp, 5, finalCount);
5861 smb_SetSMBDataLength(outp, finalCount);
5863 smb_ReleaseFID(fidp);
5865 cm_ReleaseUser(userp);
5870 * Values for createDisp, copied from NTDDK.H
5872 #define FILE_SUPERSEDE 0 // (???)
5873 #define FILE_OPEN 1 // (open)
5874 #define FILE_CREATE 2 // (exclusive)
5875 #define FILE_OPEN_IF 3 // (non-exclusive)
5876 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
5877 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
5880 #define REQUEST_OPLOCK 2
5881 #define REQUEST_BATCH_OPLOCK 4
5882 #define OPEN_DIRECTORY 8
5883 #define EXTENDED_RESPONSE_REQUIRED 0x10
5885 /* CreateOptions field. */
5886 #define FILE_DIRECTORY_FILE 0x0001
5887 #define FILE_WRITE_THROUGH 0x0002
5888 #define FILE_SEQUENTIAL_ONLY 0x0004
5889 #define FILE_NON_DIRECTORY_FILE 0x0040
5890 #define FILE_NO_EA_KNOWLEDGE 0x0200
5891 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
5892 #define FILE_RANDOM_ACCESS 0x0800
5893 #define FILE_DELETE_ON_CLOSE 0x1000
5894 #define FILE_OPEN_BY_FILE_ID 0x2000
5896 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5898 char *pathp, *realPathp;
5902 cm_scache_t *dscp; /* parent dir */
5903 cm_scache_t *scp; /* file to create or open */
5904 cm_scache_t *targetScp; /* if scp is a symlink */
5908 unsigned short nameLength;
5910 unsigned int requestOpLock;
5911 unsigned int requestBatchOpLock;
5912 unsigned int mustBeDir;
5913 unsigned int extendedRespRequired;
5914 unsigned int treeCreate;
5916 unsigned int desiredAccess;
5917 unsigned int extAttributes;
5918 unsigned int createDisp;
5919 unsigned int createOptions;
5920 unsigned int shareAccess;
5921 int initialModeBits;
5922 unsigned short baseFid;
5923 smb_fid_t *baseFidp;
5925 cm_scache_t *baseDirp;
5926 unsigned short openAction;
5938 /* This code is very long and has a lot of if-then-else clauses
5939 * scp and dscp get reused frequently and we need to ensure that
5940 * we don't lose a reference. Start by ensuring that they are NULL.
5947 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
5948 flags = smb_GetSMBOffsetParm(inp, 3, 1)
5949 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
5950 requestOpLock = flags & REQUEST_OPLOCK;
5951 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
5952 mustBeDir = flags & OPEN_DIRECTORY;
5953 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
5956 * Why all of a sudden 32-bit FID?
5957 * We will reject all bits higher than 16.
5959 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
5960 return CM_ERROR_INVAL;
5961 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
5962 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
5963 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
5964 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
5965 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
5966 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
5967 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
5968 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
5969 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
5970 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
5971 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
5973 /* mustBeDir is never set; createOptions directory bit seems to be
5976 if (createOptions & FILE_DIRECTORY_FILE)
5978 else if (createOptions & FILE_NON_DIRECTORY_FILE)
5984 * compute initial mode bits based on read-only flag in
5985 * extended attributes
5987 initialModeBits = 0666;
5988 if (extAttributes & SMB_ATTR_READONLY)
5989 initialModeBits &= ~0222;
5991 pathp = smb_GetSMBData(inp, NULL);
5992 /* Sometimes path is not null-terminated, so we make a copy. */
5993 realPathp = malloc(nameLength+1);
5994 memcpy(realPathp, pathp, nameLength);
5995 realPathp[nameLength] = 0;
5996 if (smb_StoreAnsiFilenames)
5997 OemToChar(realPathp,realPathp);
5999 spacep = inp->spacep;
6000 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6002 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
6003 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
6004 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
6006 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
6007 /* special case magic file name for receiving IOCTL requests
6008 * (since IOCTL calls themselves aren't getting through).
6010 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6011 smb_SetupIoctlFid(fidp, spacep);
6012 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
6014 /* set inp->fid so that later read calls in same msg can find fid */
6015 inp->fid = fidp->fid;
6019 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6020 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6021 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
6023 memset(&ft, 0, sizeof(ft));
6024 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6025 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6026 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6027 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6028 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
6029 sz.HighPart = 0x7fff; sz.LowPart = 0;
6030 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
6031 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
6032 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6033 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6034 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
6035 smb_SetSMBDataLength(outp, 0);
6037 /* clean up fid reference */
6038 smb_ReleaseFID(fidp);
6043 #ifdef DEBUG_VERBOSE
6045 char *hexp, *asciip;
6046 asciip = (lastNamep? lastNamep : realPathp);
6047 hexp = osi_HexifyString( asciip );
6048 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
6053 userp = smb_GetUserFromVCP(vcp, inp);
6055 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
6057 return CM_ERROR_INVAL;
6062 baseDirp = cm_data.rootSCachep;
6063 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6064 if (code == CM_ERROR_TIDIPC) {
6065 /* Attempt to use a TID allocated for IPC. The client
6066 * is probably looking for DCE RPC end points which we
6067 * don't support OR it could be looking to make a DFS
6070 osi_Log0(smb_logp, "NTCreateX received IPC TID");
6073 cm_ReleaseUser(userp);
6074 return CM_ERROR_NOSUCHFILE;
6075 #endif /* DFS_SUPPORT */
6078 baseFidp = smb_FindFID(vcp, baseFid, 0);
6080 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
6082 cm_ReleaseUser(userp);
6083 return CM_ERROR_INVAL;
6085 baseDirp = baseFidp->scp;
6089 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
6091 /* compute open mode */
6093 if (desiredAccess & DELETE)
6094 fidflags |= SMB_FID_OPENDELETE;
6095 if (desiredAccess & AFS_ACCESS_READ)
6096 fidflags |= SMB_FID_OPENREAD;
6097 if (desiredAccess & AFS_ACCESS_WRITE)
6098 fidflags |= SMB_FID_OPENWRITE;
6099 if (createOptions & FILE_DELETE_ON_CLOSE)
6100 fidflags |= SMB_FID_DELONCLOSE;
6101 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6102 fidflags |= SMB_FID_SEQUENTIAL;
6103 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6104 fidflags |= SMB_FID_RANDOM;
6106 /* and the share mode */
6107 if (shareAccess & FILE_SHARE_READ)
6108 fidflags |= SMB_FID_SHARE_READ;
6109 if (shareAccess & FILE_SHARE_WRITE)
6110 fidflags |= SMB_FID_SHARE_WRITE;
6112 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
6115 /* For an exclusive create, we want to do a case sensitive match for the last component. */
6116 if ( createDisp == FILE_CREATE ||
6117 createDisp == FILE_OVERWRITE ||
6118 createDisp == FILE_OVERWRITE_IF) {
6119 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6120 userp, tidPathp, &req, &dscp);
6123 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6124 cm_ReleaseSCache(dscp);
6125 cm_ReleaseUser(userp);
6128 smb_ReleaseFID(baseFidp);
6129 if ( WANTS_DFS_PATHNAMES(inp) )
6130 return CM_ERROR_PATH_NOT_COVERED;
6132 return CM_ERROR_BADSHARENAME;
6134 #endif /* DFS_SUPPORT */
6135 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6137 if (code == CM_ERROR_NOSUCHFILE) {
6138 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6139 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6140 if (code == 0 && realDirFlag == 1) {
6141 cm_ReleaseSCache(scp);
6142 cm_ReleaseSCache(dscp);
6143 cm_ReleaseUser(userp);
6146 smb_ReleaseFID(baseFidp);
6147 return CM_ERROR_EXISTS;
6151 /* we have both scp and dscp */
6153 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6154 userp, tidPathp, &req, &scp);
6156 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6157 cm_ReleaseSCache(scp);
6158 cm_ReleaseUser(userp);
6161 smb_ReleaseFID(baseFidp);
6162 if ( WANTS_DFS_PATHNAMES(inp) )
6163 return CM_ERROR_PATH_NOT_COVERED;
6165 return CM_ERROR_BADSHARENAME;
6167 #endif /* DFS_SUPPORT */
6168 /* we might have scp but not dscp */
6174 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6175 /* look up parent directory */
6176 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
6177 * the immediate parent. We have to work our way up realPathp until we hit something that we
6181 /* we might or might not have scp */
6187 code = cm_NameI(baseDirp, spacep->data,
6188 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6189 userp, tidPathp, &req, &dscp);
6192 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6194 cm_ReleaseSCache(scp);
6195 cm_ReleaseSCache(dscp);
6196 cm_ReleaseUser(userp);
6199 smb_ReleaseFID(baseFidp);
6200 if ( WANTS_DFS_PATHNAMES(inp) )
6201 return CM_ERROR_PATH_NOT_COVERED;
6203 return CM_ERROR_BADSHARENAME;
6205 #endif /* DFS_SUPPORT */
6208 (tp = strrchr(spacep->data,'\\')) &&
6209 (createDisp == FILE_CREATE) &&
6210 (realDirFlag == 1)) {
6213 treeStartp = realPathp + (tp - spacep->data);
6215 if (*tp && !smb_IsLegalFilename(tp)) {
6217 smb_ReleaseFID(baseFidp);
6218 cm_ReleaseUser(userp);
6221 cm_ReleaseSCache(scp);
6222 return CM_ERROR_BADNTFILENAME;
6226 } while (dscp == NULL && code == 0);
6230 /* we might have scp and we might have dscp */
6233 smb_ReleaseFID(baseFidp);
6236 osi_Log0(smb_logp,"NTCreateX parent not found");
6238 cm_ReleaseSCache(scp);
6240 cm_ReleaseSCache(dscp);
6241 cm_ReleaseUser(userp);
6246 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
6247 /* A file exists where we want a directory. */
6249 cm_ReleaseSCache(scp);
6250 cm_ReleaseSCache(dscp);
6251 cm_ReleaseUser(userp);
6253 return CM_ERROR_EXISTS;
6257 lastNamep = realPathp;
6261 if (!smb_IsLegalFilename(lastNamep)) {
6263 cm_ReleaseSCache(scp);
6265 cm_ReleaseSCache(dscp);
6266 cm_ReleaseUser(userp);
6268 return CM_ERROR_BADNTFILENAME;
6271 if (!foundscp && !treeCreate) {
6272 if ( createDisp == FILE_CREATE ||
6273 createDisp == FILE_OVERWRITE ||
6274 createDisp == FILE_OVERWRITE_IF)
6276 code = cm_Lookup(dscp, lastNamep,
6277 CM_FLAG_FOLLOW, userp, &req, &scp);
6279 code = cm_Lookup(dscp, lastNamep,
6280 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6283 if (code && code != CM_ERROR_NOSUCHFILE) {
6285 cm_ReleaseSCache(dscp);
6286 cm_ReleaseUser(userp);
6291 /* we have scp and dscp */
6293 /* we have scp but not dscp */
6295 smb_ReleaseFID(baseFidp);
6298 /* if we get here, if code is 0, the file exists and is represented by
6299 * scp. Otherwise, we have to create it. The dir may be represented
6300 * by dscp, or we may have found the file directly. If code is non-zero,
6303 if (code == 0 && !treeCreate) {
6304 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req);
6307 cm_ReleaseSCache(dscp);
6309 cm_ReleaseSCache(scp);
6310 cm_ReleaseUser(userp);
6315 if (createDisp == FILE_CREATE) {
6316 /* oops, file shouldn't be there */
6318 cm_ReleaseSCache(dscp);
6320 cm_ReleaseSCache(scp);
6321 cm_ReleaseUser(userp);
6323 return CM_ERROR_EXISTS;
6326 if ( createDisp == FILE_OVERWRITE ||
6327 createDisp == FILE_OVERWRITE_IF) {
6329 setAttr.mask = CM_ATTRMASK_LENGTH;
6330 setAttr.length.LowPart = 0;
6331 setAttr.length.HighPart = 0;
6332 /* now watch for a symlink */
6334 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6336 osi_assert(dscp != NULL);
6337 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6339 /* we have a more accurate file to use (the
6340 * target of the symbolic link). Otherwise,
6341 * we'll just use the symlink anyway.
6343 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6345 cm_ReleaseSCache(scp);
6349 code = cm_SetAttr(scp, &setAttr, userp, &req);
6350 openAction = 3; /* truncated existing file */
6353 openAction = 1; /* found existing file */
6355 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6356 /* don't create if not found */
6358 cm_ReleaseSCache(dscp);
6360 cm_ReleaseSCache(scp);
6361 cm_ReleaseUser(userp);
6363 return CM_ERROR_NOSUCHFILE;
6364 } else if (realDirFlag == 0 || realDirFlag == -1) {
6365 osi_assert(dscp != NULL);
6366 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
6367 osi_LogSaveString(smb_logp, lastNamep));
6368 openAction = 2; /* created file */
6369 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6370 setAttr.clientModTime = time(NULL);
6371 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
6374 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6375 smb_NotifyChange(FILE_ACTION_ADDED,
6376 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6377 dscp, lastNamep, NULL, TRUE);
6378 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6379 /* Not an exclusive create, and someone else tried
6380 * creating it already, then we open it anyway. We
6381 * don't bother retrying after this, since if this next
6382 * fails, that means that the file was deleted after we
6383 * started this call.
6385 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6388 if (createDisp == FILE_OVERWRITE_IF) {
6389 setAttr.mask = CM_ATTRMASK_LENGTH;
6390 setAttr.length.LowPart = 0;
6391 setAttr.length.HighPart = 0;
6393 /* now watch for a symlink */
6395 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6397 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6399 /* we have a more accurate file to use (the
6400 * target of the symbolic link). Otherwise,
6401 * we'll just use the symlink anyway.
6403 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6405 cm_ReleaseSCache(scp);
6409 code = cm_SetAttr(scp, &setAttr, userp, &req);
6411 } /* lookup succeeded */
6415 char *cp; /* This component */
6416 int clen = 0; /* length of component */
6417 cm_scache_t *tscp1, *tscp2;
6420 /* create directory */
6422 treeStartp = lastNamep;
6423 osi_assert(dscp != NULL);
6424 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
6425 osi_LogSaveString(smb_logp, treeStartp));
6426 openAction = 2; /* created directory */
6428 /* if the request is to create the root directory
6429 * it will appear as a directory name of the nul-string
6430 * and a code of CM_ERROR_NOSUCHFILE
6432 if ( !*treeStartp && code == CM_ERROR_NOSUCHFILE)
6433 code = CM_ERROR_EXISTS;
6435 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6436 setAttr.clientModTime = time(NULL);
6441 cm_HoldSCache(tscp1);
6445 tp = strchr(pp, '\\');
6448 clen = (int)strlen(cp);
6449 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
6451 clen = (int)(tp - pp);
6452 strncpy(cp,pp,clen);
6459 continue; /* the supplied path can't have consecutive slashes either , but */
6461 /* cp is the next component to be created. */
6462 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
6463 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
6464 smb_NotifyChange(FILE_ACTION_ADDED,
6465 FILE_NOTIFY_CHANGE_DIR_NAME,
6466 tscp1, cp, NULL, TRUE);
6468 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6469 /* Not an exclusive create, and someone else tried
6470 * creating it already, then we open it anyway. We
6471 * don't bother retrying after this, since if this next
6472 * fails, that means that the file was deleted after we
6473 * started this call.
6475 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
6476 userp, &req, &tscp2);
6481 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
6482 cm_ReleaseSCache(tscp1);
6483 tscp1 = tscp2; /* Newly created directory will be next parent */
6484 /* the hold is transfered to tscp1 from tscp2 */
6489 cm_ReleaseSCache(dscp);
6492 cm_ReleaseSCache(scp);
6495 * if we get here and code == 0, then scp is the last directory created, and dscp is the
6501 /* something went wrong creating or truncating the file */
6503 cm_ReleaseSCache(scp);
6505 cm_ReleaseSCache(dscp);
6506 cm_ReleaseUser(userp);
6511 /* make sure we have file vs. dir right (only applies for single component case) */
6512 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
6513 /* now watch for a symlink */
6515 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6516 cm_scache_t * targetScp = 0;
6517 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6519 /* we have a more accurate file to use (the
6520 * target of the symbolic link). Otherwise,
6521 * we'll just use the symlink anyway.
6523 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
6524 cm_ReleaseSCache(scp);
6529 if (scp->fileType != CM_SCACHETYPE_FILE) {
6531 cm_ReleaseSCache(dscp);
6532 cm_ReleaseSCache(scp);
6533 cm_ReleaseUser(userp);
6535 return CM_ERROR_ISDIR;
6539 /* (only applies to single component case) */
6540 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
6541 cm_ReleaseSCache(scp);
6543 cm_ReleaseSCache(dscp);
6544 cm_ReleaseUser(userp);
6546 return CM_ERROR_NOTDIR;
6549 /* open the file itself */
6550 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6553 /* save a reference to the user */
6555 fidp->userp = userp;
6557 /* If we are restricting sharing, we should do so with a suitable
6559 if (scp->fileType == CM_SCACHETYPE_FILE &&
6560 !(fidflags & SMB_FID_SHARE_WRITE)) {
6562 LARGE_INTEGER LOffset, LLength;
6565 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
6566 LOffset.LowPart = SMB_FID_QLOCK_LOW;
6567 LLength.HighPart = 0;
6568 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
6570 if (fidflags & SMB_FID_SHARE_READ) {
6571 sLockType = LOCKING_ANDX_SHARED_LOCK;
6576 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
6578 lock_ObtainMutex(&scp->mx);
6579 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
6580 lock_ReleaseMutex(&scp->mx);
6583 /* shouldn't this be smb_CloseFID() fidp->flags = SMB_FID_DELETE; */
6584 smb_CloseFID(vcp, fidp, NULL, 0);
6585 smb_ReleaseFID(fidp);
6587 cm_ReleaseSCache(scp);
6589 cm_ReleaseSCache(dscp);
6590 cm_ReleaseUser(userp);
6597 lock_ObtainMutex(&fidp->mx);
6598 /* save a pointer to the vnode */
6599 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
6600 lock_ObtainMutex(&scp->mx);
6601 scp->flags |= CM_SCACHEFLAG_SMB_FID;
6602 lock_ReleaseMutex(&scp->mx);
6603 osi_Log2(afsd_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
6605 fidp->flags = fidflags;
6607 /* remember if the file was newly created */
6609 fidp->flags |= SMB_FID_CREATED;
6611 /* save parent dir and pathname for delete or change notification */
6612 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
6613 osi_Log2(afsd_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
6614 fidp->flags |= SMB_FID_NTOPEN;
6615 fidp->NTopen_dscp = dscp;
6617 fidp->NTopen_pathp = strdup(lastNamep);
6619 fidp->NTopen_wholepathp = realPathp;
6620 lock_ReleaseMutex(&fidp->mx);
6622 /* we don't need this any longer */
6624 cm_ReleaseSCache(dscp);
6628 cm_Open(scp, 0, userp);
6630 /* set inp->fid so that later read calls in same msg can find fid */
6631 inp->fid = fidp->fid;
6635 lock_ObtainMutex(&scp->mx);
6636 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6637 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6638 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
6639 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6640 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6641 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6642 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6643 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6644 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
6646 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6647 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6648 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6649 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6650 smb_SetSMBParmByte(outp, parmSlot,
6651 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
6652 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
6653 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
6654 lock_ReleaseMutex(&scp->mx);
6655 smb_SetSMBDataLength(outp, 0);
6657 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
6658 osi_LogSaveString(smb_logp, realPathp));
6660 smb_ReleaseFID(fidp);
6662 cm_ReleaseUser(userp);
6664 /* Can't free realPathp if we get here since
6665 fidp->NTopen_wholepathp is pointing there */
6667 /* leave scp held since we put it in fidp->scp */
6672 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
6673 * Instead, ultimately, would like to use a subroutine for common code.
6675 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6677 char *pathp, *realPathp;
6681 cm_scache_t *dscp; /* parent dir */
6682 cm_scache_t *scp; /* file to create or open */
6683 cm_scache_t *targetScp; /* if scp is a symlink */
6686 unsigned long nameLength;
6688 unsigned int requestOpLock;
6689 unsigned int requestBatchOpLock;
6690 unsigned int mustBeDir;
6691 unsigned int extendedRespRequired;
6693 unsigned int desiredAccess;
6694 #ifdef DEBUG_VERBOSE
6695 unsigned int allocSize;
6697 unsigned int shareAccess;
6698 unsigned int extAttributes;
6699 unsigned int createDisp;
6700 #ifdef DEBUG_VERBOSE
6703 unsigned int createOptions;
6704 int initialModeBits;
6705 unsigned short baseFid;
6706 smb_fid_t *baseFidp;
6708 cm_scache_t *baseDirp;
6709 unsigned short openAction;
6715 int parmOffset, dataOffset;
6727 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6728 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6729 parmp = inp->data + parmOffset;
6730 lparmp = (ULONG *) parmp;
6733 requestOpLock = flags & REQUEST_OPLOCK;
6734 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6735 mustBeDir = flags & OPEN_DIRECTORY;
6736 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6739 * Why all of a sudden 32-bit FID?
6740 * We will reject all bits higher than 16.
6742 if (lparmp[1] & 0xFFFF0000)
6743 return CM_ERROR_INVAL;
6744 baseFid = (unsigned short)lparmp[1];
6745 desiredAccess = lparmp[2];
6746 #ifdef DEBUG_VERBOSE
6747 allocSize = lparmp[3];
6748 #endif /* DEBUG_VERSOSE */
6749 extAttributes = lparmp[5];
6750 shareAccess = lparmp[6];
6751 createDisp = lparmp[7];
6752 createOptions = lparmp[8];
6753 #ifdef DEBUG_VERBOSE
6756 nameLength = lparmp[11];
6758 #ifdef DEBUG_VERBOSE
6759 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
6760 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
6761 osi_Log1(smb_logp,"... flags[%x]",flags);
6764 /* mustBeDir is never set; createOptions directory bit seems to be
6767 if (createOptions & FILE_DIRECTORY_FILE)
6769 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6775 * compute initial mode bits based on read-only flag in
6776 * extended attributes
6778 initialModeBits = 0666;
6779 if (extAttributes & SMB_ATTR_READONLY)
6780 initialModeBits &= ~0222;
6782 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
6783 /* Sometimes path is not null-terminated, so we make a copy. */
6784 realPathp = malloc(nameLength+1);
6785 memcpy(realPathp, pathp, nameLength);
6786 realPathp[nameLength] = 0;
6787 if (smb_StoreAnsiFilenames)
6788 OemToChar(realPathp,realPathp);
6790 spacep = cm_GetSpace();
6791 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6794 * Nothing here to handle SMB_IOCTL_FILENAME.
6795 * Will add it if necessary.
6798 #ifdef DEBUG_VERBOSE
6800 char *hexp, *asciip;
6801 asciip = (lastNamep? lastNamep : realPathp);
6802 hexp = osi_HexifyString( asciip );
6803 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
6808 userp = smb_GetUserFromVCP(vcp, inp);
6810 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
6812 return CM_ERROR_INVAL;
6817 baseDirp = cm_data.rootSCachep;
6818 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6819 if (code == CM_ERROR_TIDIPC) {
6820 /* Attempt to use a TID allocated for IPC. The client
6821 * is probably looking for DCE RPC end points which we
6822 * don't support OR it could be looking to make a DFS
6825 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
6828 cm_ReleaseUser(userp);
6829 return CM_ERROR_NOSUCHPATH;
6833 baseFidp = smb_FindFID(vcp, baseFid, 0);
6835 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
6837 cm_ReleaseUser(userp);
6838 return CM_ERROR_INVAL;
6840 baseDirp = baseFidp->scp;
6844 /* compute open mode */
6846 if (desiredAccess & DELETE)
6847 fidflags |= SMB_FID_OPENDELETE;
6848 if (desiredAccess & AFS_ACCESS_READ)
6849 fidflags |= SMB_FID_OPENREAD;
6850 if (desiredAccess & AFS_ACCESS_WRITE)
6851 fidflags |= SMB_FID_OPENWRITE;
6852 if (createOptions & FILE_DELETE_ON_CLOSE)
6853 fidflags |= SMB_FID_DELONCLOSE;
6854 if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6855 fidflags |= SMB_FID_SEQUENTIAL;
6856 if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6857 fidflags |= SMB_FID_RANDOM;
6859 /* And the share mode */
6860 if (shareAccess & FILE_SHARE_READ)
6861 fidflags |= SMB_FID_SHARE_READ;
6862 if (shareAccess & FILE_SHARE_WRITE)
6863 fidflags |= SMB_FID_SHARE_WRITE;
6867 if ( createDisp == FILE_OPEN ||
6868 createDisp == FILE_OVERWRITE ||
6869 createDisp == FILE_OVERWRITE_IF) {
6870 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6871 userp, tidPathp, &req, &dscp);
6874 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6875 cm_ReleaseSCache(dscp);
6876 cm_ReleaseUser(userp);
6879 smb_ReleaseFID(baseFidp);
6880 if ( WANTS_DFS_PATHNAMES(inp) )
6881 return CM_ERROR_PATH_NOT_COVERED;
6883 return CM_ERROR_BADSHARENAME;
6885 #endif /* DFS_SUPPORT */
6886 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6888 if (code == CM_ERROR_NOSUCHFILE) {
6889 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6890 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6891 if (code == 0 && realDirFlag == 1) {
6892 cm_ReleaseSCache(scp);
6893 cm_ReleaseSCache(dscp);
6894 cm_ReleaseUser(userp);
6897 smb_ReleaseFID(baseFidp);
6898 return CM_ERROR_EXISTS;
6904 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6905 userp, tidPathp, &req, &scp);
6907 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6908 cm_ReleaseSCache(scp);
6909 cm_ReleaseUser(userp);
6912 smb_ReleaseFID(baseFidp);
6913 if ( WANTS_DFS_PATHNAMES(inp) )
6914 return CM_ERROR_PATH_NOT_COVERED;
6916 return CM_ERROR_BADSHARENAME;
6918 #endif /* DFS_SUPPORT */
6924 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6925 /* look up parent directory */
6927 code = cm_NameI(baseDirp, spacep->data,
6928 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6929 userp, tidPathp, &req, &dscp);
6931 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6932 cm_ReleaseSCache(dscp);
6933 cm_ReleaseUser(userp);
6936 smb_ReleaseFID(baseFidp);
6937 if ( WANTS_DFS_PATHNAMES(inp) )
6938 return CM_ERROR_PATH_NOT_COVERED;
6940 return CM_ERROR_BADSHARENAME;
6942 #endif /* DFS_SUPPORT */
6946 cm_FreeSpace(spacep);
6949 smb_ReleaseFID(baseFidp);
6952 cm_ReleaseUser(userp);
6958 lastNamep = realPathp;
6962 if (!smb_IsLegalFilename(lastNamep))
6963 return CM_ERROR_BADNTFILENAME;
6966 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
6967 code = cm_Lookup(dscp, lastNamep,
6968 CM_FLAG_FOLLOW, userp, &req, &scp);
6970 code = cm_Lookup(dscp, lastNamep,
6971 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6974 if (code && code != CM_ERROR_NOSUCHFILE) {
6975 cm_ReleaseSCache(dscp);
6976 cm_ReleaseUser(userp);
6983 smb_ReleaseFID(baseFidp);
6984 cm_FreeSpace(spacep);
6987 /* if we get here, if code is 0, the file exists and is represented by
6988 * scp. Otherwise, we have to create it. The dir may be represented
6989 * by dscp, or we may have found the file directly. If code is non-zero,
6993 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
6997 cm_ReleaseSCache(dscp);
6998 cm_ReleaseSCache(scp);
6999 cm_ReleaseUser(userp);
7004 if (createDisp == FILE_CREATE) {
7005 /* oops, file shouldn't be there */
7007 cm_ReleaseSCache(dscp);
7008 cm_ReleaseSCache(scp);
7009 cm_ReleaseUser(userp);
7011 return CM_ERROR_EXISTS;
7014 if (createDisp == FILE_OVERWRITE ||
7015 createDisp == FILE_OVERWRITE_IF) {
7016 setAttr.mask = CM_ATTRMASK_LENGTH;
7017 setAttr.length.LowPart = 0;
7018 setAttr.length.HighPart = 0;
7020 /* now watch for a symlink */
7022 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7024 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7026 /* we have a more accurate file to use (the
7027 * target of the symbolic link). Otherwise,
7028 * we'll just use the symlink anyway.
7030 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7032 cm_ReleaseSCache(scp);
7036 code = cm_SetAttr(scp, &setAttr, userp, &req);
7037 openAction = 3; /* truncated existing file */
7039 else openAction = 1; /* found existing file */
7041 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7042 /* don't create if not found */
7044 cm_ReleaseSCache(dscp);
7045 cm_ReleaseUser(userp);
7047 return CM_ERROR_NOSUCHFILE;
7049 else if (realDirFlag == 0 || realDirFlag == -1) {
7050 osi_assert(dscp != NULL);
7051 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
7052 osi_LogSaveString(smb_logp, lastNamep));
7053 openAction = 2; /* created file */
7054 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7055 setAttr.clientModTime = time(NULL);
7056 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7060 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7061 smb_NotifyChange(FILE_ACTION_ADDED,
7062 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7063 dscp, lastNamep, NULL, TRUE);
7064 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7065 /* Not an exclusive create, and someone else tried
7066 * creating it already, then we open it anyway. We
7067 * don't bother retrying after this, since if this next
7068 * fails, that means that the file was deleted after we
7069 * started this call.
7071 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7074 if (createDisp == FILE_OVERWRITE_IF) {
7075 setAttr.mask = CM_ATTRMASK_LENGTH;
7076 setAttr.length.LowPart = 0;
7077 setAttr.length.HighPart = 0;
7079 /* now watch for a symlink */
7081 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7083 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7085 /* we have a more accurate file to use (the
7086 * target of the symbolic link). Otherwise,
7087 * we'll just use the symlink anyway.
7089 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7091 cm_ReleaseSCache(scp);
7095 code = cm_SetAttr(scp, &setAttr, userp, &req);
7097 } /* lookup succeeded */
7100 /* create directory */
7101 osi_assert(dscp != NULL);
7103 "smb_ReceiveNTTranCreate creating directory %s",
7104 osi_LogSaveString(smb_logp, lastNamep));
7105 openAction = 2; /* created directory */
7106 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7107 setAttr.clientModTime = time(NULL);
7108 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
7109 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7110 smb_NotifyChange(FILE_ACTION_ADDED,
7111 FILE_NOTIFY_CHANGE_DIR_NAME,
7112 dscp, lastNamep, NULL, TRUE);
7114 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7115 /* Not an exclusive create, and someone else tried
7116 * creating it already, then we open it anyway. We
7117 * don't bother retrying after this, since if this next
7118 * fails, that means that the file was deleted after we
7119 * started this call.
7121 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7127 /* something went wrong creating or truncating the file */
7129 cm_ReleaseSCache(scp);
7130 cm_ReleaseUser(userp);
7135 /* make sure we have file vs. dir right */
7136 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7137 /* now watch for a symlink */
7139 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7141 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7143 /* we have a more accurate file to use (the
7144 * target of the symbolic link). Otherwise,
7145 * we'll just use the symlink anyway.
7147 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7149 cm_ReleaseSCache(scp);
7154 if (scp->fileType != CM_SCACHETYPE_FILE) {
7155 cm_ReleaseSCache(scp);
7156 cm_ReleaseUser(userp);
7158 return CM_ERROR_ISDIR;
7162 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7163 cm_ReleaseSCache(scp);
7164 cm_ReleaseUser(userp);
7166 return CM_ERROR_NOTDIR;
7169 /* open the file itself */
7170 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7173 /* save a reference to the user */
7175 fidp->userp = userp;
7177 /* If we are restricting sharing, we should do so with a suitable
7179 if (scp->fileType == CM_SCACHETYPE_FILE &&
7180 !(fidflags & SMB_FID_SHARE_WRITE)) {
7182 LARGE_INTEGER LOffset, LLength;
7185 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7186 LOffset.LowPart = SMB_FID_QLOCK_LOW;
7187 LLength.HighPart = 0;
7188 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7190 if (fidflags & SMB_FID_SHARE_READ) {
7191 sLockType = LOCKING_ANDX_SHARED_LOCK;
7196 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7198 lock_ObtainMutex(&scp->mx);
7199 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7200 lock_ReleaseMutex(&scp->mx);
7203 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
7204 smb_CloseFID(vcp, fidp, NULL, 0);
7205 smb_ReleaseFID(fidp);
7207 cm_ReleaseSCache(scp);
7208 cm_ReleaseUser(userp);
7211 return CM_ERROR_SHARING_VIOLATION;
7215 lock_ObtainMutex(&fidp->mx);
7216 /* save a pointer to the vnode */
7218 lock_ObtainMutex(&scp->mx);
7219 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7220 lock_ReleaseMutex(&scp->mx);
7221 osi_Log2(afsd_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
7223 fidp->flags = fidflags;
7225 /* remember if the file was newly created */
7227 fidp->flags |= SMB_FID_CREATED;
7229 /* save parent dir and pathname for deletion or change notification */
7230 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7231 fidp->flags |= SMB_FID_NTOPEN;
7232 fidp->NTopen_dscp = dscp;
7233 osi_Log2(afsd_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
7235 fidp->NTopen_pathp = strdup(lastNamep);
7237 fidp->NTopen_wholepathp = realPathp;
7238 lock_ReleaseMutex(&fidp->mx);
7240 /* we don't need this any longer */
7242 cm_ReleaseSCache(dscp);
7244 cm_Open(scp, 0, userp);
7246 /* set inp->fid so that later read calls in same msg can find fid */
7247 inp->fid = fidp->fid;
7249 /* check whether we are required to send an extended response */
7250 if (!extendedRespRequired) {
7252 parmOffset = 8*4 + 39;
7253 parmOffset += 1; /* pad to 4 */
7254 dataOffset = parmOffset + 70;
7258 /* Total Parameter Count */
7259 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7260 /* Total Data Count */
7261 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7262 /* Parameter Count */
7263 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7264 /* Parameter Offset */
7265 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7266 /* Parameter Displacement */
7267 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7269 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7271 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7272 /* Data Displacement */
7273 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7274 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7275 smb_SetSMBDataLength(outp, 70);
7277 lock_ObtainMutex(&scp->mx);
7278 outData = smb_GetSMBData(outp, NULL);
7279 outData++; /* round to get to parmOffset */
7280 *outData = 0; outData++; /* oplock */
7281 *outData = 0; outData++; /* reserved */
7282 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7283 *((ULONG *)outData) = openAction; outData += 4;
7284 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
7285 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7286 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
7287 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
7288 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
7289 *((FILETIME *)outData) = ft; outData += 8; /* change time */
7290 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7291 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7292 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7293 *((USHORT *)outData) = 0; outData += 2; /* filetype */
7294 *((USHORT *)outData) = 0; outData += 2; /* dev state */
7295 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7296 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7297 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7298 outData += 2; /* is a dir? */
7299 lock_ReleaseMutex(&scp->mx);
7302 parmOffset = 8*4 + 39;
7303 parmOffset += 1; /* pad to 4 */
7304 dataOffset = parmOffset + 104;
7308 /* Total Parameter Count */
7309 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7310 /* Total Data Count */
7311 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7312 /* Parameter Count */
7313 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7314 /* Parameter Offset */
7315 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7316 /* Parameter Displacement */
7317 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7319 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7321 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7322 /* Data Displacement */
7323 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7324 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7325 smb_SetSMBDataLength(outp, 105);
7327 lock_ObtainMutex(&scp->mx);
7328 outData = smb_GetSMBData(outp, NULL);
7329 outData++; /* round to get to parmOffset */
7330 *outData = 0; outData++; /* oplock */
7331 *outData = 1; outData++; /* response type */
7332 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7333 *((ULONG *)outData) = openAction; outData += 4;
7334 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
7335 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7336 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
7337 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
7338 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
7339 *((FILETIME *)outData) = ft; outData += 8; /* change time */
7340 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7341 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7342 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7343 *((USHORT *)outData) = 0; outData += 2; /* filetype */
7344 *((USHORT *)outData) = 0; outData += 2; /* dev state */
7345 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7346 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7347 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7348 outData += 1; /* is a dir? */
7349 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
7350 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
7351 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
7352 lock_ReleaseMutex(&scp->mx);
7355 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
7357 smb_ReleaseFID(fidp);
7359 cm_ReleaseUser(userp);
7361 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
7362 /* leave scp held since we put it in fidp->scp */
7366 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
7369 smb_packet_t *savedPacketp;
7370 ULONG filter; USHORT fid, watchtree;
7374 filter = smb_GetSMBParm(inp, 19) |
7375 (smb_GetSMBParm(inp, 20) << 16);
7376 fid = smb_GetSMBParm(inp, 21);
7377 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
7379 fidp = smb_FindFID(vcp, fid, 0);
7381 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
7382 return CM_ERROR_BADFD;
7385 savedPacketp = smb_CopyPacket(inp);
7387 if (savedPacketp->vcp)
7388 smb_ReleaseVC(savedPacketp->vcp);
7389 savedPacketp->vcp = vcp;
7390 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7391 savedPacketp->nextp = smb_Directory_Watches;
7392 smb_Directory_Watches = savedPacketp;
7393 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7395 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
7396 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
7399 osi_Log2(afsd_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p", fidp, scp);
7400 lock_ObtainMutex(&scp->mx);
7402 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
7404 scp->flags |= CM_SCACHEFLAG_WATCHED;
7405 lock_ReleaseMutex(&scp->mx);
7406 smb_ReleaseFID(fidp);
7408 outp->flags |= SMB_PACKETFLAG_NOSEND;
7412 unsigned char nullSecurityDesc[36] = {
7413 0x01, /* security descriptor revision */
7414 0x00, /* reserved, should be zero */
7415 0x00, 0x80, /* security descriptor control;
7416 * 0x8000 : self-relative format */
7417 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
7418 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
7419 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
7420 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
7421 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7422 /* "null SID" owner SID */
7423 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
7424 /* "null SID" group SID */
7427 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7429 int parmOffset, parmCount, dataOffset, dataCount;
7437 ULONG securityInformation;
7439 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7440 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7441 parmp = inp->data + parmOffset;
7442 sparmp = (USHORT *) parmp;
7443 lparmp = (ULONG *) parmp;
7446 securityInformation = lparmp[1];
7448 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
7449 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
7457 parmOffset = 8*4 + 39;
7458 parmOffset += 1; /* pad to 4 */
7460 dataOffset = parmOffset + parmCount;
7464 /* Total Parameter Count */
7465 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
7466 /* Total Data Count */
7467 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
7468 /* Parameter Count */
7469 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
7470 /* Parameter Offset */
7471 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7472 /* Parameter Displacement */
7473 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7475 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
7477 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7478 /* Data Displacement */
7479 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7480 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7481 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
7483 outData = smb_GetSMBData(outp, NULL);
7484 outData++; /* round to get to parmOffset */
7485 *((ULONG *)outData) = 36; outData += 4; /* length */
7487 if (maxData >= 36) {
7488 memcpy(outData, nullSecurityDesc, 36);
7492 return CM_ERROR_BUFFERTOOSMALL;
7495 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7497 unsigned short function;
7499 function = smb_GetSMBParm(inp, 18);
7501 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
7503 /* We can handle long names */
7504 if (vcp->flags & SMB_VCFLAG_USENT)
7505 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
7509 return smb_ReceiveNTTranCreate(vcp, inp, outp);
7511 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
7514 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
7517 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
7519 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
7522 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
7524 return CM_ERROR_INVAL;
7528 * smb_NotifyChange -- find relevant change notification messages and
7531 * If we don't know the file name (i.e. a callback break), filename is
7532 * NULL, and we return a zero-length list.
7534 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
7535 cm_scache_t *dscp, char *filename, char *otherFilename,
7536 BOOL isDirectParent)
7538 smb_packet_t *watch, *lastWatch, *nextWatch;
7539 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
7540 char *outData, *oldOutData;
7544 BOOL twoEntries = FALSE;
7545 ULONG otherNameLen, oldParmCount = 0;
7549 /* Get ready for rename within directory */
7550 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
7552 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
7555 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
7556 osi_LogSaveString(smb_logp,filename),dscp);
7558 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7559 watch = smb_Directory_Watches;
7561 filter = smb_GetSMBParm(watch, 19)
7562 | (smb_GetSMBParm(watch, 20) << 16);
7563 fid = smb_GetSMBParm(watch, 21);
7564 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
7565 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
7566 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
7569 * Strange hack - bug in NT Client and NT Server that we
7572 if (filter == 3 && wtree)
7575 fidp = smb_FindFID(watch->vcp, fid, 0);
7577 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
7579 watch = watch->nextp;
7582 if (fidp->scp != dscp
7583 || (filter & notifyFilter) == 0
7584 || (!isDirectParent && !wtree)) {
7585 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
7586 smb_ReleaseFID(fidp);
7588 watch = watch->nextp;
7591 smb_ReleaseFID(fidp);
7594 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
7595 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
7597 nextWatch = watch->nextp;
7598 if (watch == smb_Directory_Watches)
7599 smb_Directory_Watches = nextWatch;
7601 lastWatch->nextp = nextWatch;
7603 /* Turn off WATCHED flag in dscp */
7604 lock_ObtainMutex(&dscp->mx);
7606 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
7608 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
7609 lock_ReleaseMutex(&dscp->mx);
7611 /* Convert to response packet */
7612 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
7613 ((smb_t *) watch)->wct = 0;
7616 if (filename == NULL)
7619 nameLen = (ULONG)strlen(filename);
7620 parmCount = 3*4 + nameLen*2;
7621 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
7623 otherNameLen = (ULONG)strlen(otherFilename);
7624 oldParmCount = parmCount;
7625 parmCount += 3*4 + otherNameLen*2;
7626 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
7628 if (maxLen < parmCount)
7629 parmCount = 0; /* not enough room */
7631 parmOffset = 8*4 + 39;
7632 parmOffset += 1; /* pad to 4 */
7633 dataOffset = parmOffset + parmCount;
7637 /* Total Parameter Count */
7638 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
7639 /* Total Data Count */
7640 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7641 /* Parameter Count */
7642 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
7643 /* Parameter Offset */
7644 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
7645 /* Parameter Displacement */
7646 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7648 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7650 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
7651 /* Data Displacement */
7652 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7653 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
7654 smb_SetSMBDataLength(watch, parmCount + 1);
7656 if (parmCount != 0) {
7658 outData = smb_GetSMBData(watch, NULL);
7659 outData++; /* round to get to parmOffset */
7660 oldOutData = outData;
7661 *((DWORD *)outData) = oldParmCount; outData += 4;
7662 /* Next Entry Offset */
7663 *((DWORD *)outData) = action; outData += 4;
7665 *((DWORD *)outData) = nameLen*2; outData += 4;
7666 /* File Name Length */
7667 p = strdup(filename);
7668 if (smb_StoreAnsiFilenames)
7670 mbstowcs((WCHAR *)outData, p, nameLen);
7674 outData = oldOutData + oldParmCount;
7675 *((DWORD *)outData) = 0; outData += 4;
7676 /* Next Entry Offset */
7677 *((DWORD *)outData) = otherAction; outData += 4;
7679 *((DWORD *)outData) = otherNameLen*2;
7680 outData += 4; /* File Name Length */
7681 p = strdup(otherFilename);
7682 if (smb_StoreAnsiFilenames)
7684 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
7690 * If filename is null, we don't know the cause of the
7691 * change notification. We return zero data (see above),
7692 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
7693 * (= 0x010C). We set the error code here by hand, without
7694 * modifying wct and bcc.
7696 if (filename == NULL) {
7697 ((smb_t *) watch)->rcls = 0x0C;
7698 ((smb_t *) watch)->reh = 0x01;
7699 ((smb_t *) watch)->errLow = 0;
7700 ((smb_t *) watch)->errHigh = 0;
7701 /* Set NT Status codes flag */
7702 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7705 smb_SendPacket(watch->vcp, watch);
7706 smb_FreePacket(watch);
7709 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7712 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7714 unsigned char *replyWctp;
7715 smb_packet_t *watch, *lastWatch;
7716 USHORT fid, watchtree;
7720 osi_Log0(smb_logp, "SMB3 receive NT cancel");
7722 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7723 watch = smb_Directory_Watches;
7725 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
7726 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
7727 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
7728 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
7729 if (watch == smb_Directory_Watches)
7730 smb_Directory_Watches = watch->nextp;
7732 lastWatch->nextp = watch->nextp;
7733 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7735 /* Turn off WATCHED flag in scp */
7736 fid = smb_GetSMBParm(watch, 21);
7737 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
7739 if (vcp != watch->vcp)
7740 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
7743 fidp = smb_FindFID(vcp, fid, 0);
7745 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
7747 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
7750 osi_Log2(afsd_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
7751 lock_ObtainMutex(&scp->mx);
7753 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
7755 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
7756 lock_ReleaseMutex(&scp->mx);
7757 smb_ReleaseFID(fidp);
7759 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
7762 /* assume STATUS32; return 0xC0000120 (CANCELED) */
7763 replyWctp = watch->wctp;
7767 ((smb_t *)watch)->rcls = 0x20;
7768 ((smb_t *)watch)->reh = 0x1;
7769 ((smb_t *)watch)->errLow = 0;
7770 ((smb_t *)watch)->errHigh = 0xC0;
7771 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7772 smb_SendPacket(vcp, watch);
7773 smb_FreePacket(watch);
7777 watch = watch->nextp;
7779 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7785 * NT rename also does hard links.
7788 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
7789 #define RENAME_FLAG_HARD_LINK 0x103
7790 #define RENAME_FLAG_RENAME 0x104
7791 #define RENAME_FLAG_COPY 0x105
7793 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7795 char *oldPathp, *newPathp;
7801 attrs = smb_GetSMBParm(inp, 0);
7802 rename_type = smb_GetSMBParm(inp, 1);
7804 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
7805 osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
7806 return CM_ERROR_NOACCESS;
7809 tp = smb_GetSMBData(inp, NULL);
7810 oldPathp = smb_ParseASCIIBlock(tp, &tp);
7811 if (smb_StoreAnsiFilenames)
7812 OemToChar(oldPathp,oldPathp);
7813 newPathp = smb_ParseASCIIBlock(tp, &tp);
7814 if (smb_StoreAnsiFilenames)
7815 OemToChar(newPathp,newPathp);
7817 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
7818 osi_LogSaveString(smb_logp, oldPathp),
7819 osi_LogSaveString(smb_logp, newPathp),
7820 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
7822 if (rename_type == RENAME_FLAG_RENAME) {
7823 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
7824 } else { /* RENAME_FLAG_HARD_LINK */
7825 code = smb_Link(vcp,inp,oldPathp,newPathp);
7832 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
7835 cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
7837 smb_username_t *unp;
7840 unp = smb_FindUserByName(usern, machine, flags);
7842 lock_ObtainMutex(&unp->mx);
7843 unp->userp = cm_NewUser();
7844 lock_ReleaseMutex(&unp->mx);
7845 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7847 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7851 smb_ReleaseUsername(unp);