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);
879 lock_ObtainMutex(&uidp->mx);
881 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
882 lock_ReleaseMutex(&uidp->mx);
883 smb_ReleaseUID(uidp);
886 /* Return UID to the client */
887 ((smb_t *)outp)->uid = newUid;
888 /* Also to the next chained message */
889 ((smb_t *)inp)->uid = newUid;
891 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
892 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
894 smb_SetSMBParm(outp, 2, 0);
896 if (vcp->flags & SMB_VCFLAG_USENT) {
897 if (smb_authType == SMB_AUTH_EXTENDED) {
898 smb_SetSMBParm(outp, 3, secBlobOutLength);
899 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
900 tp = smb_GetSMBData(outp, NULL);
901 if (secBlobOutLength) {
902 memcpy(tp, secBlobOut, secBlobOutLength);
904 tp += secBlobOutLength;
906 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
907 tp += smb_ServerOSLength;
908 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
909 tp += smb_ServerLanManagerLength;
910 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
911 tp += smb_ServerDomainNameLength;
913 smb_SetSMBDataLength(outp, 0);
916 if (smb_authType == SMB_AUTH_EXTENDED) {
917 smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
918 tp = smb_GetSMBData(outp, NULL);
919 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
920 tp += smb_ServerOSLength;
921 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
922 tp += smb_ServerLanManagerLength;
923 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
924 tp += smb_ServerDomainNameLength;
926 smb_SetSMBDataLength(outp, 0);
933 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
937 /* find the tree and free it */
938 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
940 smb_username_t * unp;
942 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %s", uidp->userID,
943 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "));
945 lock_ObtainMutex(&uidp->mx);
946 uidp->flags |= SMB_USERFLAG_DELETE;
948 * it doesn't get deleted right away
949 * because the vcp points to it
952 lock_ReleaseMutex(&uidp->mx);
955 /* we can't do this. we get logoff messages prior to a session
956 * disconnect even though it doesn't mean the user is logging out.
957 * we need to create a new pioctl and EventLogoff handler to set
958 * SMB_USERNAMEFLAG_LOGOFF.
960 if (unp && smb_LogoffTokenTransfer) {
961 lock_ObtainMutex(&unp->mx);
962 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
963 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
964 lock_ReleaseMutex(&unp->mx);
968 smb_ReleaseUID(uidp);
971 osi_Log0(smb_logp, "SMB3 user logoffX");
973 smb_SetSMBDataLength(outp, 0);
977 #define SMB_SUPPORT_SEARCH_BITS 0x0001
978 #define SMB_SHARE_IS_IN_DFS 0x0002
980 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
984 unsigned short newTid;
995 osi_Log0(smb_logp, "SMB3 receive tree connect");
997 /* parse input parameters */
998 tp = smb_GetSMBData(inp, NULL);
999 passwordp = smb_ParseString(tp, &tp);
1000 pathp = smb_ParseString(tp, &tp);
1001 if (smb_StoreAnsiFilenames)
1002 OemToChar(pathp,pathp);
1003 servicep = smb_ParseString(tp, &tp);
1005 tp = strrchr(pathp, '\\');
1007 return CM_ERROR_BADSMB;
1009 strcpy(shareName, tp+1);
1011 osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
1012 osi_LogSaveString(smb_logp, pathp),
1013 osi_LogSaveString(smb_logp, shareName));
1015 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
1017 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1020 return CM_ERROR_NOIPC;
1024 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1025 userp = smb_GetUserFromUID(uidp);
1027 lock_ObtainMutex(&vcp->mx);
1028 newTid = vcp->tidCounter++;
1029 lock_ReleaseMutex(&vcp->mx);
1031 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1034 if (!strcmp(shareName, "*."))
1035 strcpy(shareName, "all");
1036 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1038 smb_ReleaseUID(uidp);
1039 smb_ReleaseTID(tidp);
1040 return CM_ERROR_BADSHARENAME;
1043 if (vcp->flags & SMB_VCFLAG_USENT)
1045 int policy = smb_FindShareCSCPolicy(shareName);
1046 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1048 SMB_SHARE_IS_IN_DFS |
1053 smb_SetSMBParm(outp, 2, 0);
1056 smb_ReleaseUID(uidp);
1058 lock_ObtainMutex(&tidp->mx);
1059 tidp->userp = userp;
1060 tidp->pathname = sharePath;
1062 tidp->flags |= SMB_TIDFLAG_IPC;
1063 lock_ReleaseMutex(&tidp->mx);
1064 smb_ReleaseTID(tidp);
1066 ((smb_t *)outp)->tid = newTid;
1067 ((smb_t *)inp)->tid = newTid;
1068 tp = smb_GetSMBData(outp, NULL);
1070 /* XXX - why is this a drive letter? */
1079 smb_SetSMBDataLength(outp, 8);
1082 smb_SetSMBDataLength(outp, 4);
1085 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1089 /* must be called with global tran lock held */
1090 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1092 smb_tran2Packet_t *tp;
1095 smbp = (smb_t *) inp->data;
1096 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1097 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1103 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1104 int totalParms, int totalData)
1106 smb_tran2Packet_t *tp;
1109 smbp = (smb_t *) inp->data;
1110 tp = malloc(sizeof(*tp));
1111 memset(tp, 0, sizeof(*tp));
1114 tp->curData = tp->curParms = 0;
1115 tp->totalData = totalData;
1116 tp->totalParms = totalParms;
1117 tp->tid = smbp->tid;
1118 tp->mid = smbp->mid;
1119 tp->uid = smbp->uid;
1120 tp->pid = smbp->pid;
1121 tp->res[0] = smbp->res[0];
1122 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1123 if (totalParms != 0)
1124 tp->parmsp = malloc(totalParms);
1126 tp->datap = malloc(totalData);
1127 if (smbp->com == 0x25 || smbp->com == 0x26)
1130 tp->opcode = smb_GetSMBParm(inp, 14);
1133 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1137 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1138 smb_tran2Packet_t *inp, smb_packet_t *outp,
1139 int totalParms, int totalData)
1141 smb_tran2Packet_t *tp;
1142 unsigned short parmOffset;
1143 unsigned short dataOffset;
1144 unsigned short dataAlign;
1146 tp = malloc(sizeof(*tp));
1147 memset(tp, 0, sizeof(*tp));
1150 tp->curData = tp->curParms = 0;
1151 tp->totalData = totalData;
1152 tp->totalParms = totalParms;
1153 tp->oldTotalParms = totalParms;
1158 tp->res[0] = inp->res[0];
1159 tp->opcode = inp->opcode;
1163 * We calculate where the parameters and data will start.
1164 * This calculation must parallel the calculation in
1165 * smb_SendTran2Packet.
1168 parmOffset = 10*2 + 35;
1169 parmOffset++; /* round to even */
1170 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1172 dataOffset = parmOffset + totalParms;
1173 dataAlign = dataOffset & 2; /* quad-align */
1174 dataOffset += dataAlign;
1175 tp->datap = outp->data + dataOffset;
1180 /* free a tran2 packet */
1181 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1184 smb_ReleaseVC(t2p->vcp);
1187 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1196 /* called with a VC, an input packet to respond to, and an error code.
1197 * sends an error response.
1199 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1200 smb_packet_t *tp, long code)
1203 unsigned short errCode;
1204 unsigned char errClass;
1205 unsigned long NTStatus;
1207 if (vcp->flags & SMB_VCFLAG_STATUS32)
1208 smb_MapNTError(code, &NTStatus);
1210 smb_MapCoreError(code, vcp, &errCode, &errClass);
1212 smb_FormatResponsePacket(vcp, NULL, tp);
1213 smbp = (smb_t *) tp;
1215 /* We can handle long names */
1216 if (vcp->flags & SMB_VCFLAG_USENT)
1217 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1219 /* now copy important fields from the tran 2 packet */
1220 smbp->com = t2p->com;
1221 smbp->tid = t2p->tid;
1222 smbp->mid = t2p->mid;
1223 smbp->pid = t2p->pid;
1224 smbp->uid = t2p->uid;
1225 smbp->res[0] = t2p->res[0];
1226 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1227 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1228 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1229 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1230 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1231 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1234 smbp->rcls = errClass;
1235 smbp->errLow = (unsigned char) (errCode & 0xff);
1236 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1240 smb_SendPacket(vcp, tp);
1243 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1246 unsigned short parmOffset;
1247 unsigned short dataOffset;
1248 unsigned short totalLength;
1249 unsigned short dataAlign;
1252 smb_FormatResponsePacket(vcp, NULL, tp);
1253 smbp = (smb_t *) tp;
1255 /* We can handle long names */
1256 if (vcp->flags & SMB_VCFLAG_USENT)
1257 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1259 /* now copy important fields from the tran 2 packet */
1260 smbp->com = t2p->com;
1261 smbp->tid = t2p->tid;
1262 smbp->mid = t2p->mid;
1263 smbp->pid = t2p->pid;
1264 smbp->uid = t2p->uid;
1265 smbp->res[0] = t2p->res[0];
1267 totalLength = 1 + t2p->totalData + t2p->totalParms;
1269 /* now add the core parameters (tran2 info) to the packet */
1270 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1271 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1272 smb_SetSMBParm(tp, 2, 0); /* reserved */
1273 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1274 parmOffset = 10*2 + 35; /* parm offset in packet */
1275 parmOffset++; /* round to even */
1276 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1277 * hdr, bcc and wct */
1278 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1279 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1280 dataOffset = parmOffset + t2p->oldTotalParms;
1281 dataAlign = dataOffset & 2; /* quad-align */
1282 dataOffset += dataAlign;
1283 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1284 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1285 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1288 datap = smb_GetSMBData(tp, NULL);
1289 *datap++ = 0; /* we rounded to even */
1291 totalLength += dataAlign;
1292 smb_SetSMBDataLength(tp, totalLength);
1294 /* next, send the datagram */
1295 smb_SendPacket(vcp, tp);
1298 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1300 smb_tran2Packet_t *asp;
1313 /* We sometimes see 0 word count. What to do? */
1314 if (*inp->wctp == 0) {
1315 osi_Log0(smb_logp, "Transaction2 word count = 0");
1317 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1320 smb_SetSMBDataLength(outp, 0);
1321 smb_SendPacket(vcp, outp);
1325 totalParms = smb_GetSMBParm(inp, 0);
1326 totalData = smb_GetSMBParm(inp, 1);
1328 firstPacket = (inp->inCom == 0x25);
1330 /* find the packet we're reassembling */
1331 lock_ObtainWrite(&smb_globalLock);
1332 asp = smb_FindTran2Packet(vcp, inp);
1334 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1336 lock_ReleaseWrite(&smb_globalLock);
1338 /* now merge in this latest packet; start by looking up offsets */
1340 parmDisp = dataDisp = 0;
1341 parmOffset = smb_GetSMBParm(inp, 10);
1342 dataOffset = smb_GetSMBParm(inp, 12);
1343 parmCount = smb_GetSMBParm(inp, 9);
1344 dataCount = smb_GetSMBParm(inp, 11);
1345 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1346 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1348 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1349 totalData, dataCount, asp->maxReturnData);
1352 parmDisp = smb_GetSMBParm(inp, 4);
1353 parmOffset = smb_GetSMBParm(inp, 3);
1354 dataDisp = smb_GetSMBParm(inp, 7);
1355 dataOffset = smb_GetSMBParm(inp, 6);
1356 parmCount = smb_GetSMBParm(inp, 2);
1357 dataCount = smb_GetSMBParm(inp, 5);
1359 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1360 parmCount, dataCount);
1363 /* now copy the parms and data */
1364 if ( asp->totalParms > 0 && parmCount != 0 )
1366 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1368 if ( asp->totalData > 0 && dataCount != 0 ) {
1369 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1372 /* account for new bytes */
1373 asp->curData += dataCount;
1374 asp->curParms += parmCount;
1376 /* finally, if we're done, remove the packet from the queue and dispatch it */
1377 if (asp->totalParms > 0 &&
1378 asp->curParms > 0 &&
1379 asp->totalData <= asp->curData &&
1380 asp->totalParms <= asp->curParms) {
1381 /* we've received it all */
1382 lock_ObtainWrite(&smb_globalLock);
1383 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1384 lock_ReleaseWrite(&smb_globalLock);
1386 /* now dispatch it */
1387 rapOp = asp->parmsp[0];
1389 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1390 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1391 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1392 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
1395 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1396 code = CM_ERROR_BADOP;
1399 /* if an error is returned, we're supposed to send an error packet,
1400 * otherwise the dispatched function already did the data sending.
1401 * We give dispatched proc the responsibility since it knows how much
1402 * space to allocate.
1405 smb_SendTran2Error(vcp, asp, outp, code);
1408 /* free the input tran 2 packet */
1409 smb_FreeTran2Packet(asp);
1411 else if (firstPacket) {
1412 /* the first packet in a multi-packet request, we need to send an
1413 * ack to get more data.
1415 smb_SetSMBDataLength(outp, 0);
1416 smb_SendPacket(vcp, outp);
1422 /* ANSI versions. The unicode versions support arbitrary length
1423 share names, but we don't support unicode yet. */
1425 typedef struct smb_rap_share_info_0 {
1426 char shi0_netname[13];
1427 } smb_rap_share_info_0_t;
1429 typedef struct smb_rap_share_info_1 {
1430 char shi1_netname[13];
1433 DWORD shi1_remark; /* char *shi1_remark; data offset */
1434 } smb_rap_share_info_1_t;
1436 typedef struct smb_rap_share_info_2 {
1437 char shi2_netname[13];
1439 unsigned short shi2_type;
1440 DWORD shi2_remark; /* char *shi2_remark; data offset */
1441 unsigned short shi2_permissions;
1442 unsigned short shi2_max_uses;
1443 unsigned short shi2_current_uses;
1444 DWORD shi2_path; /* char *shi2_path; data offset */
1445 unsigned short shi2_passwd[9];
1446 unsigned short shi2_pad2;
1447 } smb_rap_share_info_2_t;
1449 #define SMB_RAP_MAX_SHARES 512
1451 typedef struct smb_rap_share_list {
1454 smb_rap_share_info_0_t * shares;
1455 } smb_rap_share_list_t;
1457 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1458 smb_rap_share_list_t * sp;
1463 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1464 return 0; /* skip over '.' and '..' */
1466 sp = (smb_rap_share_list_t *) vrockp;
1468 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1469 sp->shares[sp->cShare].shi0_netname[12] = 0;
1473 if (sp->cShare >= sp->maxShares)
1474 return CM_ERROR_STOPNOW;
1479 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1481 smb_tran2Packet_t *outp;
1482 unsigned short * tp;
1486 int outParmsTotal; /* total parameter bytes */
1487 int outDataTotal; /* total data bytes */
1490 DWORD allSubmount = 0;
1492 DWORD nRegShares = 0;
1493 DWORD nSharesRet = 0;
1495 HKEY hkSubmount = NULL;
1496 smb_rap_share_info_1_t * shares;
1499 char thisShare[256];
1502 smb_rap_share_list_t rootShares;
1507 tp = p->parmsp + 1; /* skip over function number (always 0) */
1508 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1509 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1513 if (infoLevel != 1) {
1514 return CM_ERROR_INVAL;
1517 /* first figure out how many shares there are */
1518 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1519 KEY_QUERY_VALUE, &hkParam);
1520 if (rv == ERROR_SUCCESS) {
1521 len = sizeof(allSubmount);
1522 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1523 (BYTE *) &allSubmount, &len);
1524 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1527 RegCloseKey (hkParam);
1530 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1531 0, KEY_QUERY_VALUE, &hkSubmount);
1532 if (rv == ERROR_SUCCESS) {
1533 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1534 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1535 if (rv != ERROR_SUCCESS)
1541 /* fetch the root shares */
1542 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1543 rootShares.cShare = 0;
1544 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1548 userp = smb_GetTran2User(vcp,p);
1550 thyper.HighPart = 0;
1553 cm_HoldSCache(cm_data.rootSCachep);
1554 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1555 cm_ReleaseSCache(cm_data.rootSCachep);
1557 cm_ReleaseUser(userp);
1559 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1561 #define REMARK_LEN 1
1562 outParmsTotal = 8; /* 4 dwords */
1563 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1564 if(outDataTotal > bufsize) {
1565 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1566 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1569 nSharesRet = nShares;
1572 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1574 /* now for the submounts */
1575 shares = (smb_rap_share_info_1_t *) outp->datap;
1576 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1578 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1581 strcpy( shares[cshare].shi1_netname, "all" );
1582 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1583 /* type and pad are zero already */
1589 for (i=0; i < nRegShares && cshare < nSharesRet; i++) {
1590 len = sizeof(thisShare);
1591 rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1592 if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1593 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1594 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1595 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1600 nShares--; /* uncount key */
1603 RegCloseKey(hkSubmount);
1606 nonrootShares = cshare;
1608 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1609 /* in case there are collisions with submounts, submounts have higher priority */
1610 for (j=0; j < nonrootShares; j++)
1611 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1614 if (j < nonrootShares) {
1615 nShares--; /* uncount */
1619 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1620 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1625 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1626 outp->parmsp[1] = 0;
1627 outp->parmsp[2] = cshare;
1628 outp->parmsp[3] = nShares;
1630 outp->totalData = (int)(cstrp - outp->datap);
1631 outp->totalParms = outParmsTotal;
1633 smb_SendTran2Packet(vcp, outp, op);
1634 smb_FreeTran2Packet(outp);
1636 free(rootShares.shares);
1641 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1643 smb_tran2Packet_t *outp;
1644 unsigned short * tp;
1646 BOOL shareFound = FALSE;
1647 unsigned short infoLevel;
1648 unsigned short bufsize;
1658 tp = p->parmsp + 1; /* skip over function number (always 1) */
1659 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1660 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1661 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1668 totalData = sizeof(smb_rap_share_info_0_t);
1669 else if(infoLevel == SMB_INFO_STANDARD)
1670 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1671 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1672 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1674 return CM_ERROR_INVAL;
1676 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1678 if(!stricmp(shareName,"all") || !strcmp(shareName,"*.")) {
1679 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1680 KEY_QUERY_VALUE, &hkParam);
1681 if (rv == ERROR_SUCCESS) {
1682 len = sizeof(allSubmount);
1683 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1684 (BYTE *) &allSubmount, &len);
1685 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1688 RegCloseKey (hkParam);
1695 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1696 KEY_QUERY_VALUE, &hkSubmount);
1697 if (rv == ERROR_SUCCESS) {
1698 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1699 if (rv == ERROR_SUCCESS) {
1702 RegCloseKey(hkSubmount);
1707 smb_FreeTran2Packet(outp);
1708 return CM_ERROR_BADSHARENAME;
1711 memset(outp->datap, 0, totalData);
1713 outp->parmsp[0] = 0;
1714 outp->parmsp[1] = 0;
1715 outp->parmsp[2] = totalData;
1717 if (infoLevel == 0) {
1718 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1719 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1720 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1721 } else if(infoLevel == SMB_INFO_STANDARD) {
1722 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1723 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1724 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1725 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1726 /* type and pad are already zero */
1727 } else { /* infoLevel==2 */
1728 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1729 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1730 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1731 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1732 info->shi2_permissions = ACCESS_ALL;
1733 info->shi2_max_uses = (unsigned short) -1;
1734 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
1737 outp->totalData = totalData;
1738 outp->totalParms = totalParam;
1740 smb_SendTran2Packet(vcp, outp, op);
1741 smb_FreeTran2Packet(outp);
1746 typedef struct smb_rap_wksta_info_10 {
1747 DWORD wki10_computername; /*char *wki10_computername;*/
1748 DWORD wki10_username; /* char *wki10_username; */
1749 DWORD wki10_langroup; /* char *wki10_langroup;*/
1750 unsigned char wki10_ver_major;
1751 unsigned char wki10_ver_minor;
1752 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1753 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1754 } smb_rap_wksta_info_10_t;
1757 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1759 smb_tran2Packet_t *outp;
1763 unsigned short * tp;
1766 smb_rap_wksta_info_10_t * info;
1770 tp = p->parmsp + 1; /* Skip over function number */
1771 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1772 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1776 if (infoLevel != 10) {
1777 return CM_ERROR_INVAL;
1783 totalData = sizeof(*info) + /* info */
1784 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1785 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1786 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1787 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1788 1; /* wki10_oth_domains (null)*/
1790 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1792 memset(outp->parmsp,0,totalParams);
1793 memset(outp->datap,0,totalData);
1795 info = (smb_rap_wksta_info_10_t *) outp->datap;
1796 cstrp = (char *) (info + 1);
1798 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1799 strcpy(cstrp, smb_localNamep);
1800 cstrp += strlen(cstrp) + 1;
1802 info->wki10_username = (DWORD) (cstrp - outp->datap);
1803 uidp = smb_FindUID(vcp, p->uid, 0);
1805 lock_ObtainMutex(&uidp->mx);
1806 if(uidp->unp && uidp->unp->name)
1807 strcpy(cstrp, uidp->unp->name);
1808 lock_ReleaseMutex(&uidp->mx);
1809 smb_ReleaseUID(uidp);
1811 cstrp += strlen(cstrp) + 1;
1813 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1814 strcpy(cstrp, "WORKGROUP");
1815 cstrp += strlen(cstrp) + 1;
1817 /* TODO: Not sure what values these should take, but these work */
1818 info->wki10_ver_major = 5;
1819 info->wki10_ver_minor = 1;
1821 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1822 strcpy(cstrp, smb_ServerDomainName);
1823 cstrp += strlen(cstrp) + 1;
1825 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1826 cstrp ++; /* no other domains */
1828 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1829 outp->parmsp[2] = outp->totalData;
1830 outp->totalParms = totalParams;
1832 smb_SendTran2Packet(vcp,outp,op);
1833 smb_FreeTran2Packet(outp);
1838 typedef struct smb_rap_server_info_0 {
1840 } smb_rap_server_info_0_t;
1842 typedef struct smb_rap_server_info_1 {
1844 char sv1_version_major;
1845 char sv1_version_minor;
1846 unsigned long sv1_type;
1847 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1848 } smb_rap_server_info_1_t;
1850 char smb_ServerComment[] = "OpenAFS Client";
1851 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1853 #define SMB_SV_TYPE_SERVER 0x00000002L
1854 #define SMB_SV_TYPE_NT 0x00001000L
1855 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1857 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1859 smb_tran2Packet_t *outp;
1863 unsigned short * tp;
1866 smb_rap_server_info_0_t * info0;
1867 smb_rap_server_info_1_t * info1;
1870 tp = p->parmsp + 1; /* Skip over function number */
1871 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1872 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1876 if (infoLevel != 0 && infoLevel != 1) {
1877 return CM_ERROR_INVAL;
1883 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1884 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1886 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1888 memset(outp->parmsp,0,totalParams);
1889 memset(outp->datap,0,totalData);
1891 if (infoLevel == 0) {
1892 info0 = (smb_rap_server_info_0_t *) outp->datap;
1893 cstrp = (char *) (info0 + 1);
1894 strcpy(info0->sv0_name, "AFS");
1895 } else { /* infoLevel == SMB_INFO_STANDARD */
1896 info1 = (smb_rap_server_info_1_t *) outp->datap;
1897 cstrp = (char *) (info1 + 1);
1898 strcpy(info1->sv1_name, "AFS");
1901 SMB_SV_TYPE_SERVER |
1903 SMB_SV_TYPE_SERVER_NT;
1905 info1->sv1_version_major = 5;
1906 info1->sv1_version_minor = 1;
1907 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1909 strcpy(cstrp, smb_ServerComment);
1911 cstrp += smb_ServerCommentLen;
1914 totalData = (DWORD)(cstrp - outp->datap);
1915 outp->totalData = min(bufsize,totalData); /* actual data size */
1916 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1917 outp->parmsp[2] = totalData;
1918 outp->totalParms = totalParams;
1920 smb_SendTran2Packet(vcp,outp,op);
1921 smb_FreeTran2Packet(outp);
1926 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1928 smb_tran2Packet_t *asp;
1940 /* We sometimes see 0 word count. What to do? */
1941 if (*inp->wctp == 0) {
1942 osi_Log0(smb_logp, "Transaction2 word count = 0");
1944 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1947 smb_SetSMBDataLength(outp, 0);
1948 smb_SendPacket(vcp, outp);
1952 totalParms = smb_GetSMBParm(inp, 0);
1953 totalData = smb_GetSMBParm(inp, 1);
1955 firstPacket = (inp->inCom == 0x32);
1957 /* find the packet we're reassembling */
1958 lock_ObtainWrite(&smb_globalLock);
1959 asp = smb_FindTran2Packet(vcp, inp);
1961 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1963 lock_ReleaseWrite(&smb_globalLock);
1965 /* now merge in this latest packet; start by looking up offsets */
1967 parmDisp = dataDisp = 0;
1968 parmOffset = smb_GetSMBParm(inp, 10);
1969 dataOffset = smb_GetSMBParm(inp, 12);
1970 parmCount = smb_GetSMBParm(inp, 9);
1971 dataCount = smb_GetSMBParm(inp, 11);
1972 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1973 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1975 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1976 totalData, dataCount, asp->maxReturnData);
1979 parmDisp = smb_GetSMBParm(inp, 4);
1980 parmOffset = smb_GetSMBParm(inp, 3);
1981 dataDisp = smb_GetSMBParm(inp, 7);
1982 dataOffset = smb_GetSMBParm(inp, 6);
1983 parmCount = smb_GetSMBParm(inp, 2);
1984 dataCount = smb_GetSMBParm(inp, 5);
1986 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1987 parmCount, dataCount);
1990 /* now copy the parms and data */
1991 if ( asp->totalParms > 0 && parmCount != 0 )
1993 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1995 if ( asp->totalData > 0 && dataCount != 0 ) {
1996 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1999 /* account for new bytes */
2000 asp->curData += dataCount;
2001 asp->curParms += parmCount;
2003 /* finally, if we're done, remove the packet from the queue and dispatch it */
2004 if (asp->totalParms > 0 &&
2005 asp->curParms > 0 &&
2006 asp->totalData <= asp->curData &&
2007 asp->totalParms <= asp->curParms) {
2008 /* we've received it all */
2009 lock_ObtainWrite(&smb_globalLock);
2010 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2011 lock_ReleaseWrite(&smb_globalLock);
2013 /* now dispatch it */
2014 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2015 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2016 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2019 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2020 code = CM_ERROR_BADOP;
2023 /* if an error is returned, we're supposed to send an error packet,
2024 * otherwise the dispatched function already did the data sending.
2025 * We give dispatched proc the responsibility since it knows how much
2026 * space to allocate.
2029 smb_SendTran2Error(vcp, asp, outp, code);
2032 /* free the input tran 2 packet */
2033 smb_FreeTran2Packet(asp);
2035 else if (firstPacket) {
2036 /* the first packet in a multi-packet request, we need to send an
2037 * ack to get more data.
2039 smb_SetSMBDataLength(outp, 0);
2040 smb_SendPacket(vcp, outp);
2046 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2049 smb_tran2Packet_t *outp;
2054 cm_scache_t *dscp; /* dir we're dealing with */
2055 cm_scache_t *scp; /* file we're creating */
2057 int initialModeBits;
2067 int parmSlot; /* which parm we're dealing with */
2068 long returnEALength;
2077 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2078 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2080 openFun = p->parmsp[6]; /* open function */
2081 excl = ((openFun & 3) == 0);
2082 trunc = ((openFun & 3) == 2); /* truncate it */
2083 openMode = (p->parmsp[1] & 0x7);
2084 openAction = 0; /* tracks what we did */
2086 attributes = p->parmsp[3];
2087 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2089 /* compute initial mode bits based on read-only flag in attributes */
2090 initialModeBits = 0666;
2092 initialModeBits &= ~0222;
2094 pathp = (char *) (&p->parmsp[14]);
2095 if (smb_StoreAnsiFilenames)
2096 OemToChar(pathp,pathp);
2098 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2100 spacep = cm_GetSpace();
2101 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2103 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2104 /* special case magic file name for receiving IOCTL requests
2105 * (since IOCTL calls themselves aren't getting through).
2107 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2108 smb_SetupIoctlFid(fidp, spacep);
2110 /* copy out remainder of the parms */
2112 outp->parmsp[parmSlot++] = fidp->fid;
2114 outp->parmsp[parmSlot++] = 0; /* attrs */
2115 outp->parmsp[parmSlot++] = 0; /* mod time */
2116 outp->parmsp[parmSlot++] = 0;
2117 outp->parmsp[parmSlot++] = 0; /* len */
2118 outp->parmsp[parmSlot++] = 0x7fff;
2119 outp->parmsp[parmSlot++] = openMode;
2120 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2121 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2123 /* and the final "always present" stuff */
2124 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2125 /* next write out the "unique" ID */
2126 outp->parmsp[parmSlot++] = 0x1234;
2127 outp->parmsp[parmSlot++] = 0x5678;
2128 outp->parmsp[parmSlot++] = 0;
2129 if (returnEALength) {
2130 outp->parmsp[parmSlot++] = 0;
2131 outp->parmsp[parmSlot++] = 0;
2134 outp->totalData = 0;
2135 outp->totalParms = parmSlot * 2;
2137 smb_SendTran2Packet(vcp, outp, op);
2139 smb_FreeTran2Packet(outp);
2141 /* and clean up fid reference */
2142 smb_ReleaseFID(fidp);
2146 #ifdef DEBUG_VERBOSE
2148 char *hexp, *asciip;
2149 asciip = (lastNamep ? lastNamep : pathp);
2150 hexp = osi_HexifyString( asciip );
2151 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2156 userp = smb_GetTran2User(vcp, p);
2157 /* In the off chance that userp is NULL, we log and abandon */
2159 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2160 smb_FreeTran2Packet(outp);
2161 return CM_ERROR_BADSMB;
2164 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2165 if (code == CM_ERROR_TIDIPC) {
2166 /* Attempt to use a TID allocated for IPC. The client
2167 * is probably looking for DCE RPC end points which we
2168 * don't support OR it could be looking to make a DFS
2171 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2173 cm_ReleaseUser(userp);
2174 smb_FreeTran2Packet(outp);
2175 return CM_ERROR_NOSUCHPATH;
2180 code = cm_NameI(cm_data.rootSCachep, pathp,
2181 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2182 userp, tidPathp, &req, &scp);
2184 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2185 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2186 userp, tidPathp, &req, &dscp);
2187 cm_FreeSpace(spacep);
2190 cm_ReleaseUser(userp);
2191 smb_FreeTran2Packet(outp);
2196 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2197 cm_ReleaseSCache(dscp);
2198 cm_ReleaseUser(userp);
2199 smb_FreeTran2Packet(outp);
2200 if ( WANTS_DFS_PATHNAMES(p) )
2201 return CM_ERROR_PATH_NOT_COVERED;
2203 return CM_ERROR_BADSHARENAME;
2205 #endif /* DFS_SUPPORT */
2207 /* otherwise, scp points to the parent directory. Do a lookup,
2208 * and truncate the file if we find it, otherwise we create the
2215 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2217 if (code && code != CM_ERROR_NOSUCHFILE) {
2218 cm_ReleaseSCache(dscp);
2219 cm_ReleaseUser(userp);
2220 smb_FreeTran2Packet(outp);
2225 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2226 cm_ReleaseSCache(scp);
2227 cm_ReleaseUser(userp);
2228 smb_FreeTran2Packet(outp);
2229 if ( WANTS_DFS_PATHNAMES(p) )
2230 return CM_ERROR_PATH_NOT_COVERED;
2232 return CM_ERROR_BADSHARENAME;
2234 #endif /* DFS_SUPPORT */
2236 /* macintosh is expensive to program for it */
2237 cm_FreeSpace(spacep);
2240 /* if we get here, if code is 0, the file exists and is represented by
2241 * scp. Otherwise, we have to create it.
2244 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2247 cm_ReleaseSCache(dscp);
2248 cm_ReleaseSCache(scp);
2249 cm_ReleaseUser(userp);
2250 smb_FreeTran2Packet(outp);
2255 /* oops, file shouldn't be there */
2257 cm_ReleaseSCache(dscp);
2258 cm_ReleaseSCache(scp);
2259 cm_ReleaseUser(userp);
2260 smb_FreeTran2Packet(outp);
2261 return CM_ERROR_EXISTS;
2265 setAttr.mask = CM_ATTRMASK_LENGTH;
2266 setAttr.length.LowPart = 0;
2267 setAttr.length.HighPart = 0;
2268 code = cm_SetAttr(scp, &setAttr, userp, &req);
2269 openAction = 3; /* truncated existing file */
2272 openAction = 1; /* found existing file */
2274 else if (!(openFun & 0x10)) {
2275 /* don't create if not found */
2277 cm_ReleaseSCache(dscp);
2278 osi_assert(scp == NULL);
2279 cm_ReleaseUser(userp);
2280 smb_FreeTran2Packet(outp);
2281 return CM_ERROR_NOSUCHFILE;
2284 osi_assert(dscp != NULL && scp == NULL);
2285 openAction = 2; /* created file */
2286 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2287 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2288 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2292 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2293 smb_NotifyChange(FILE_ACTION_ADDED,
2294 FILE_NOTIFY_CHANGE_FILE_NAME,
2295 dscp, lastNamep, NULL, TRUE);
2296 } else if (!excl && code == CM_ERROR_EXISTS) {
2297 /* not an exclusive create, and someone else tried
2298 * creating it already, then we open it anyway. We
2299 * don't bother retrying after this, since if this next
2300 * fails, that means that the file was deleted after we
2301 * started this call.
2303 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2307 setAttr.mask = CM_ATTRMASK_LENGTH;
2308 setAttr.length.LowPart = 0;
2309 setAttr.length.HighPart = 0;
2310 code = cm_SetAttr(scp, &setAttr, userp,
2313 } /* lookup succeeded */
2317 /* we don't need this any longer */
2319 cm_ReleaseSCache(dscp);
2322 /* something went wrong creating or truncating the file */
2324 cm_ReleaseSCache(scp);
2325 cm_ReleaseUser(userp);
2326 smb_FreeTran2Packet(outp);
2330 /* make sure we're about to open a file */
2331 if (scp->fileType != CM_SCACHETYPE_FILE) {
2333 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2334 cm_scache_t * targetScp = 0;
2335 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2337 /* we have a more accurate file to use (the
2338 * target of the symbolic link). Otherwise,
2339 * we'll just use the symlink anyway.
2341 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2343 cm_ReleaseSCache(scp);
2347 if (scp->fileType != CM_SCACHETYPE_FILE) {
2348 cm_ReleaseSCache(scp);
2349 cm_ReleaseUser(userp);
2350 smb_FreeTran2Packet(outp);
2351 return CM_ERROR_ISDIR;
2355 /* now all we have to do is open the file itself */
2356 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2360 lock_ObtainMutex(&fidp->mx);
2361 /* save a pointer to the vnode */
2364 fidp->userp = userp;
2366 /* compute open mode */
2368 fidp->flags |= SMB_FID_OPENREAD;
2369 if (openMode == 1 || openMode == 2)
2370 fidp->flags |= SMB_FID_OPENWRITE;
2372 /* remember that the file was newly created */
2374 fidp->flags |= SMB_FID_CREATED;
2376 lock_ReleaseMutex(&fidp->mx);
2378 smb_ReleaseFID(fidp);
2380 cm_Open(scp, 0, userp);
2382 /* copy out remainder of the parms */
2384 outp->parmsp[parmSlot++] = fidp->fid;
2385 lock_ObtainMutex(&scp->mx);
2387 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2388 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2389 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2390 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2391 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2392 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2393 outp->parmsp[parmSlot++] = openMode;
2394 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2395 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2397 /* and the final "always present" stuff */
2398 outp->parmsp[parmSlot++] = openAction;
2399 /* next write out the "unique" ID */
2400 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2401 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2402 outp->parmsp[parmSlot++] = 0;
2403 if (returnEALength) {
2404 outp->parmsp[parmSlot++] = 0;
2405 outp->parmsp[parmSlot++] = 0;
2407 lock_ReleaseMutex(&scp->mx);
2408 outp->totalData = 0; /* total # of data bytes */
2409 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2411 smb_SendTran2Packet(vcp, outp, op);
2413 smb_FreeTran2Packet(outp);
2415 cm_ReleaseUser(userp);
2416 /* leave scp held since we put it in fidp->scp */
2420 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2422 osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2423 return CM_ERROR_BADOP;
2426 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2428 osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2429 return CM_ERROR_BADOP;
2432 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2434 smb_tran2Packet_t *outp;
2435 smb_tran2QFSInfo_t qi;
2438 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
2440 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2442 switch (p->parmsp[0]) {
2443 case 1: responseSize = sizeof(qi.u.allocInfo); break;
2444 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
2446 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
2447 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
2448 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
2449 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
2450 case 0x200: /* CIFS Unix Info */
2451 case 0x301: /* Mac FS Info */
2453 return CM_ERROR_INVAL;
2456 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2457 switch (p->parmsp[0]) {
2460 qi.u.allocInfo.FSID = 0;
2461 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2462 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2463 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2464 qi.u.allocInfo.bytesPerSector = 1024;
2469 qi.u.volumeInfo.vsn = 1234;
2470 qi.u.volumeInfo.vnCount = 4;
2471 /* we're supposed to pad it out with zeroes to the end */
2472 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2473 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2477 /* FS volume info */
2478 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
2479 qi.u.FSvolumeInfo.vsn = 1234;
2480 qi.u.FSvolumeInfo.vnCount = 8;
2481 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
2487 temp.LowPart = 0x7fffffff;
2488 qi.u.FSsizeInfo.totalAllocUnits = temp;
2489 temp.LowPart = 0x3fffffff;
2490 qi.u.FSsizeInfo.availAllocUnits = temp;
2491 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2492 qi.u.FSsizeInfo.bytesPerSector = 1024;
2496 /* FS device info */
2497 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
2498 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2502 /* FS attribute info */
2503 /* attributes, defined in WINNT.H:
2504 * FILE_CASE_SENSITIVE_SEARCH 0x1
2505 * FILE_CASE_PRESERVED_NAMES 0x2
2506 * <no name defined> 0x4000
2507 * If bit 0x4000 is not set, Windows 95 thinks
2508 * we can't handle long (non-8.3) names,
2509 * despite our protestations to the contrary.
2511 qi.u.FSattributeInfo.attributes = 0x4003;
2512 qi.u.FSattributeInfo.maxCompLength = 255;
2513 qi.u.FSattributeInfo.FSnameLength = 6;
2514 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
2518 /* copy out return data, and set corresponding sizes */
2519 outp->totalParms = 0;
2520 outp->totalData = responseSize;
2521 memcpy(outp->datap, &qi, responseSize);
2523 /* send and free the packets */
2524 smb_SendTran2Packet(vcp, outp, op);
2525 smb_FreeTran2Packet(outp);
2530 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2532 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2533 return CM_ERROR_BADOP;
2536 struct smb_ShortNameRock {
2540 size_t shortNameLen;
2543 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2546 struct smb_ShortNameRock *rockp;
2550 /* compare both names and vnodes, though probably just comparing vnodes
2551 * would be safe enough.
2553 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2555 if (ntohl(dep->fid.vnode) != rockp->vnode)
2557 /* This is the entry */
2558 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2559 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2560 return CM_ERROR_STOPNOW;
2563 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2564 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2566 struct smb_ShortNameRock rock;
2570 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2574 spacep = cm_GetSpace();
2575 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2577 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2579 cm_FreeSpace(spacep);
2584 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2585 cm_ReleaseSCache(dscp);
2586 cm_ReleaseUser(userp);
2587 return CM_ERROR_PATH_NOT_COVERED;
2589 #endif /* DFS_SUPPORT */
2591 if (!lastNamep) lastNamep = pathp;
2594 thyper.HighPart = 0;
2595 rock.shortName = shortName;
2597 rock.maskp = lastNamep;
2598 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2600 cm_ReleaseSCache(dscp);
2603 return CM_ERROR_NOSUCHFILE;
2604 if (code == CM_ERROR_STOPNOW) {
2605 *shortNameLenp = rock.shortNameLen;
2611 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2613 smb_tran2Packet_t *outp;
2616 unsigned short infoLevel;
2618 unsigned short attributes;
2619 unsigned long extAttributes;
2624 cm_scache_t *scp, *dscp;
2634 infoLevel = p->parmsp[0];
2635 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2637 else if (infoLevel == SMB_INFO_STANDARD)
2638 nbytesRequired = 22;
2639 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2640 nbytesRequired = 26;
2641 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2642 nbytesRequired = 40;
2643 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2644 nbytesRequired = 24;
2645 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2647 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2648 nbytesRequired = 30;
2650 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2651 p->opcode, infoLevel);
2652 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2656 pathp = (char *)(&p->parmsp[3]);
2657 if (smb_StoreAnsiFilenames)
2658 OemToChar(pathp,pathp);
2659 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2660 osi_LogSaveString(smb_logp, pathp));
2662 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2664 if (infoLevel > 0x100)
2665 outp->totalParms = 2;
2667 outp->totalParms = 0;
2668 outp->totalData = nbytesRequired;
2670 /* now, if we're at infoLevel 6, we're only being asked to check
2671 * the syntax, so we just OK things now. In particular, we're *not*
2672 * being asked to verify anything about the state of any parent dirs.
2674 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2675 smb_SendTran2Packet(vcp, outp, opx);
2676 smb_FreeTran2Packet(outp);
2680 userp = smb_GetTran2User(vcp, p);
2682 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2683 smb_FreeTran2Packet(outp);
2684 return CM_ERROR_BADSMB;
2687 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2689 cm_ReleaseUser(userp);
2690 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2691 smb_FreeTran2Packet(outp);
2696 * XXX Strange hack XXX
2698 * As of Patch 7 (13 January 98), we are having the following problem:
2699 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2700 * requests to look up "desktop.ini" in all the subdirectories.
2701 * This can cause zillions of timeouts looking up non-existent cells
2702 * and volumes, especially in the top-level directory.
2704 * We have not found any way to avoid this or work around it except
2705 * to explicitly ignore the requests for mount points that haven't
2706 * yet been evaluated and for directories that haven't yet been
2709 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2710 spacep = cm_GetSpace();
2711 smb_StripLastComponent(spacep->data, &lastComp, pathp);
2712 #ifndef SPECIAL_FOLDERS
2713 /* Make sure that lastComp is not NULL */
2715 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2716 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2720 userp, tidPathp, &req, &dscp);
2723 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2724 if ( WANTS_DFS_PATHNAMES(p) )
2725 code = CM_ERROR_PATH_NOT_COVERED;
2727 code = CM_ERROR_BADSHARENAME;
2729 #endif /* DFS_SUPPORT */
2730 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2731 code = CM_ERROR_NOSUCHFILE;
2732 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2733 cm_buf_t *bp = buf_Find(dscp, &hzero);
2737 code = CM_ERROR_NOSUCHFILE;
2739 cm_ReleaseSCache(dscp);
2741 cm_FreeSpace(spacep);
2742 cm_ReleaseUser(userp);
2743 smb_SendTran2Error(vcp, p, opx, code);
2744 smb_FreeTran2Packet(outp);
2750 #endif /* SPECIAL_FOLDERS */
2752 cm_FreeSpace(spacep);
2755 /* now do namei and stat, and copy out the info */
2756 code = cm_NameI(cm_data.rootSCachep, pathp,
2757 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2760 cm_ReleaseUser(userp);
2761 smb_SendTran2Error(vcp, p, opx, code);
2762 smb_FreeTran2Packet(outp);
2767 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2768 cm_ReleaseSCache(scp);
2769 cm_ReleaseUser(userp);
2770 if ( WANTS_DFS_PATHNAMES(p) )
2771 code = CM_ERROR_PATH_NOT_COVERED;
2773 code = CM_ERROR_BADSHARENAME;
2774 smb_SendTran2Error(vcp, p, opx, code);
2775 smb_FreeTran2Packet(outp);
2778 #endif /* DFS_SUPPORT */
2780 lock_ObtainMutex(&scp->mx);
2781 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2782 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2783 if (code) goto done;
2785 /* now we have the status in the cache entry, and everything is locked.
2786 * Marshall the output data.
2789 /* for info level 108, figure out short name */
2790 if (infoLevel == 0x108) {
2791 code = cm_GetShortName(pathp, userp, &req,
2792 tidPathp, scp->fid.vnode, shortName,
2799 *((u_long *)op) = len * 2; op += 4;
2800 mbstowcs((unsigned short *)op, shortName, len);
2805 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2806 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2807 *((u_long *)op) = dosTime; op += 4; /* creation time */
2808 *((u_long *)op) = dosTime; op += 4; /* access time */
2809 *((u_long *)op) = dosTime; op += 4; /* write time */
2810 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
2811 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
2812 attributes = smb_Attributes(scp);
2813 *((u_short *)op) = attributes; op += 2; /* attributes */
2815 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2816 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2817 *((FILETIME *)op) = ft; op += 8; /* creation time */
2818 *((FILETIME *)op) = ft; op += 8; /* last access time */
2819 *((FILETIME *)op) = ft; op += 8; /* last write time */
2820 *((FILETIME *)op) = ft; op += 8; /* last change time */
2821 extAttributes = smb_ExtAttributes(scp);
2822 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
2823 *((u_long *)op) = 0; op += 4; /* don't know what this is */
2825 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2826 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2827 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2828 *((u_long *)op) = scp->linkCount; op += 4; /* Link count */
2829 *op++ = 0; /* Delete Pending */
2830 *op++ = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2831 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2832 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2836 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2837 memset(op, 0, 4); op += 4; /* EA size */
2840 /* now, if we are being asked about extended attrs, return a 0 size */
2841 if (infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2842 *((u_long *)op) = 0; op += 4;
2846 /* send and free the packets */
2848 lock_ReleaseMutex(&scp->mx);
2849 cm_ReleaseSCache(scp);
2850 cm_ReleaseUser(userp);
2852 smb_SendTran2Packet(vcp, outp, opx);
2854 smb_SendTran2Error(vcp, p, opx, code);
2855 smb_FreeTran2Packet(outp);
2860 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2862 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2863 return CM_ERROR_BADOP;
2866 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2868 smb_tran2Packet_t *outp;
2870 unsigned long attributes;
2871 unsigned short infoLevel;
2885 fidp = smb_FindFID(vcp, fid, 0);
2888 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2892 infoLevel = p->parmsp[1];
2893 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2894 nbytesRequired = 40;
2895 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2896 nbytesRequired = 24;
2897 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2899 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2902 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2903 p->opcode, infoLevel);
2904 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2905 smb_ReleaseFID(fidp);
2908 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2910 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2912 if (infoLevel > 0x100)
2913 outp->totalParms = 2;
2915 outp->totalParms = 0;
2916 outp->totalData = nbytesRequired;
2918 userp = smb_GetTran2User(vcp, p);
2920 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2921 code = CM_ERROR_BADSMB;
2925 lock_ObtainMutex(&fidp->mx);
2926 delonclose = fidp->flags & SMB_FID_DELONCLOSE;
2929 lock_ReleaseMutex(&fidp->mx);
2930 lock_ObtainMutex(&scp->mx);
2931 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2932 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2936 /* now we have the status in the cache entry, and everything is locked.
2937 * Marshall the output data.
2940 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2941 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2942 *((FILETIME *)op) = ft; op += 8; /* creation time */
2943 *((FILETIME *)op) = ft; op += 8; /* last access time */
2944 *((FILETIME *)op) = ft; op += 8; /* last write time */
2945 *((FILETIME *)op) = ft; op += 8; /* last change time */
2946 attributes = smb_ExtAttributes(scp);
2947 *((u_long *)op) = attributes; op += 4;
2948 *((u_long *)op) = 0; op += 4;
2950 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2951 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2952 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2953 *((u_long *)op) = scp->linkCount; op += 4; /* Link count */
2954 *op++ = (delonclose ? 1 : 0); /* Delete Pending */
2955 *op++ = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2956 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2957 scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
2961 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2962 *((u_long *)op) = 0; op += 4;
2964 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2968 lock_ReleaseMutex(&scp->mx);
2969 lock_ObtainMutex(&fidp->mx);
2970 lock_ObtainMutex(&scp->mx);
2971 if (fidp->NTopen_wholepathp)
2972 name = fidp->NTopen_wholepathp;
2974 name = "\\"; /* probably can't happen */
2975 lock_ReleaseMutex(&fidp->mx);
2976 len = (unsigned long)strlen(name);
2977 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
2978 *((u_long *)op) = len * 2; op += 4;
2979 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2982 /* send and free the packets */
2984 lock_ReleaseMutex(&scp->mx);
2985 cm_ReleaseSCache(scp);
2986 cm_ReleaseUser(userp);
2987 smb_ReleaseFID(fidp);
2989 smb_SendTran2Packet(vcp, outp, opx);
2991 smb_SendTran2Error(vcp, p, opx, code);
2992 smb_FreeTran2Packet(outp);
2997 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3002 unsigned short infoLevel;
3003 smb_tran2Packet_t *outp;
3011 fidp = smb_FindFID(vcp, fid, 0);
3014 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
3018 infoLevel = p->parmsp[1];
3019 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3020 if (infoLevel > 0x104 || infoLevel < 0x101) {
3021 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3022 p->opcode, infoLevel);
3023 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
3024 smb_ReleaseFID(fidp);
3028 lock_ObtainMutex(&fidp->mx);
3029 if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) {
3030 lock_ReleaseMutex(&fidp->mx);
3031 smb_ReleaseFID(fidp);
3032 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
3035 if ((infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO)
3036 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3037 lock_ReleaseMutex(&fidp->mx);
3038 smb_ReleaseFID(fidp);
3039 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
3045 lock_ReleaseMutex(&fidp->mx);
3047 osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
3049 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
3051 outp->totalParms = 2;
3052 outp->totalData = 0;
3054 userp = smb_GetTran2User(vcp, p);
3056 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3057 code = CM_ERROR_BADSMB;
3061 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3063 unsigned int attribute;
3066 /* lock the vnode with a callback; we need the current status
3067 * to determine what the new status is, in some cases.
3069 lock_ObtainMutex(&scp->mx);
3070 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3071 CM_SCACHESYNC_GETSTATUS
3072 | CM_SCACHESYNC_NEEDCALLBACK);
3073 lock_ReleaseMutex(&scp->mx);
3078 lock_ObtainMutex(&fidp->mx);
3079 lock_ObtainMutex(&scp->mx);
3081 /* prepare for setattr call */
3084 lastMod = *((FILETIME *)(p->datap + 16));
3085 /* when called as result of move a b, lastMod is (-1, -1).
3086 * If the check for -1 is not present, timestamp
3087 * of the resulting file will be 1969 (-1)
3089 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3090 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3091 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3092 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3093 fidp->flags |= SMB_FID_MTIMESETDONE;
3096 attribute = *((u_long *)(p->datap + 32));
3097 if (attribute != 0) {
3098 if ((scp->unixModeBits & 0222)
3099 && (attribute & 1) != 0) {
3100 /* make a writable file read-only */
3101 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3102 attr.unixModeBits = scp->unixModeBits & ~0222;
3104 else if ((scp->unixModeBits & 0222) == 0
3105 && (attribute & 1) == 0) {
3106 /* make a read-only file writable */
3107 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3108 attr.unixModeBits = scp->unixModeBits | 0222;
3111 lock_ReleaseMutex(&scp->mx);
3112 lock_ReleaseMutex(&fidp->mx);
3116 code = cm_SetAttr(scp, &attr, userp, &req);
3120 else if (infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3121 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3124 attr.mask = CM_ATTRMASK_LENGTH;
3125 attr.length.LowPart = size.LowPart;
3126 attr.length.HighPart = size.HighPart;
3127 code = cm_SetAttr(scp, &attr, userp, &req);
3129 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3130 if (*((char *)(p->datap))) {
3131 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3134 lock_ObtainMutex(&fidp->mx);
3135 fidp->flags |= SMB_FID_DELONCLOSE;
3136 lock_ReleaseMutex(&fidp->mx);
3141 lock_ObtainMutex(&fidp->mx);
3142 fidp->flags &= ~SMB_FID_DELONCLOSE;
3143 lock_ReleaseMutex(&fidp->mx);
3148 cm_ReleaseSCache(scp);
3149 cm_ReleaseUser(userp);
3150 smb_ReleaseFID(fidp);
3152 smb_SendTran2Packet(vcp, outp, op);
3154 smb_SendTran2Error(vcp, p, op, code);
3155 smb_FreeTran2Packet(outp);
3161 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3163 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3164 return CM_ERROR_BADOP;
3168 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3170 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3171 return CM_ERROR_BADOP;
3175 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3177 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3178 return CM_ERROR_BADOP;
3182 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3184 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3185 return CM_ERROR_BADOP;
3189 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3191 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3192 return CM_ERROR_BADOP;
3196 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3198 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3199 return CM_ERROR_BADOP;
3202 struct smb_v2_referral {
3204 USHORT ReferralFlags;
3207 USHORT DfsPathOffset;
3208 USHORT DfsAlternativePathOffset;
3209 USHORT NetworkAddressOffset;
3213 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3215 /* This is a UNICODE only request (bit15 of Flags2) */
3216 /* The TID must be IPC$ */
3218 /* The documentation for the Flags response field is contradictory */
3220 /* Use Version 1 Referral Element Format */
3221 /* ServerType = 0; indicates the next server should be queried for the file */
3222 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3223 /* Node = UnicodeString of UNC path of the next share name */
3226 int maxReferralLevel = 0;
3227 char requestFileName[1024] = "";
3228 smb_tran2Packet_t *outp = 0;
3229 cm_user_t *userp = 0;
3231 CPINFO CodePageInfo;
3232 int i, nbnLen, reqLen;
3237 maxReferralLevel = p->parmsp[0];
3239 GetCPInfo(CP_ACP, &CodePageInfo);
3240 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
3241 requestFileName, 1024, NULL, NULL);
3243 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
3244 maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3246 nbnLen = strlen(cm_NetbiosName);
3247 reqLen = strlen(requestFileName);
3249 if (reqLen == nbnLen + 5 &&
3250 requestFileName[0] == '\\' &&
3251 !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3252 requestFileName[nbnLen+1] == '\\' &&
3253 (!_strnicmp("all",&requestFileName[nbnLen+2],3) ||
3254 !_strnicmp("*.",&requestFileName[nbnLen+2],2)))
3257 struct smb_v2_referral * v2ref;
3258 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
3260 sp = (USHORT *)outp->datap;
3262 sp[idx++] = reqLen; /* path consumed */
3263 sp[idx++] = 1; /* number of referrals */
3264 sp[idx++] = 0x03; /* flags */
3265 #ifdef DFS_VERSION_1
3266 sp[idx++] = 1; /* Version Number */
3267 sp[idx++] = reqLen + 4; /* Referral Size */
3268 sp[idx++] = 1; /* Type = SMB Server */
3269 sp[idx++] = 0; /* Do not strip path consumed */
3270 for ( i=0;i<=reqLen; i++ )
3271 sp[i+idx] = requestFileName[i];
3272 #else /* DFS_VERSION_2 */
3273 sp[idx++] = 2; /* Version Number */
3274 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3275 idx += (sizeof(struct smb_v2_referral) / 2);
3276 v2ref = (struct smb_v2_referral *) &sp[5];
3277 v2ref->ServerType = 1; /* SMB Server */
3278 v2ref->ReferralFlags = 0x03;
3279 v2ref->Proximity = 0; /* closest */
3280 v2ref->TimeToLive = 3600; /* seconds */
3281 v2ref->DfsPathOffset = idx * 2;
3282 v2ref->DfsAlternativePathOffset = idx * 2;
3283 v2ref->NetworkAddressOffset = 0;
3284 for ( i=0;i<=reqLen; i++ )
3285 sp[i+idx] = requestFileName[i];
3288 userp = smb_GetTran2User(vcp, p);
3290 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3291 code = CM_ERROR_BADSMB;
3296 code = CM_ERROR_NOSUCHPATH;
3301 cm_ReleaseUser(userp);
3303 smb_SendTran2Packet(vcp, outp, op);
3305 smb_SendTran2Error(vcp, p, op, code);
3307 smb_FreeTran2Packet(outp);
3310 #else /* DFS_SUPPORT */
3311 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3312 return CM_ERROR_BADOP;
3313 #endif /* DFS_SUPPORT */
3317 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3319 /* This is a UNICODE only request (bit15 of Flags2) */
3321 /* There is nothing we can do about this operation. The client is going to
3322 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3323 * Unfortunately, there is really nothing we can do about it other then log it
3324 * somewhere. Even then I don't think there is anything for us to do.
3325 * So let's return an error value.
3328 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3329 return CM_ERROR_BADOP;
3333 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3334 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3339 cm_scache_t *targetScp; /* target if scp is a symlink */
3344 unsigned short attr;
3345 unsigned long lattr;
3346 smb_dirListPatch_t *patchp;
3347 smb_dirListPatch_t *npatchp;
3349 for(patchp = *dirPatchespp; patchp; patchp =
3350 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3351 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3353 lock_ObtainMutex(&scp->mx);
3354 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3355 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3357 lock_ReleaseMutex(&scp->mx);
3358 cm_ReleaseSCache(scp);
3360 dptr = patchp->dptr;
3362 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3363 errors in the client. */
3364 if (infoLevel >= 0x101) {
3365 /* 1969-12-31 23:59:59 +00 */
3366 ft.dwHighDateTime = 0x19DB200;
3367 ft.dwLowDateTime = 0x5BB78980;
3369 /* copy to Creation Time */
3370 *((FILETIME *)dptr) = ft;
3373 /* copy to Last Access Time */
3374 *((FILETIME *)dptr) = ft;
3377 /* copy to Last Write Time */
3378 *((FILETIME *)dptr) = ft;
3381 /* copy to Change Time */
3382 *((FILETIME *)dptr) = ft;
3385 /* merge in hidden attribute */
3386 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3387 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3391 /* 1969-12-31 23:59:58 +00*/
3392 dosTime = 0xEBBFBF7D;
3394 /* and copy out date */
3395 shortTemp = (dosTime>>16) & 0xffff;
3396 *((u_short *)dptr) = shortTemp;
3399 /* copy out creation time */
3400 shortTemp = dosTime & 0xffff;
3401 *((u_short *)dptr) = shortTemp;
3404 /* and copy out date */
3405 shortTemp = (dosTime>>16) & 0xffff;
3406 *((u_short *)dptr) = shortTemp;
3409 /* copy out access time */
3410 shortTemp = dosTime & 0xffff;
3411 *((u_short *)dptr) = shortTemp;
3414 /* and copy out date */
3415 shortTemp = (dosTime>>16) & 0xffff;
3416 *((u_short *)dptr) = shortTemp;
3419 /* copy out mod time */
3420 shortTemp = dosTime & 0xffff;
3421 *((u_short *)dptr) = shortTemp;
3424 /* merge in hidden (dot file) attribute */
3425 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3426 attr = SMB_ATTR_HIDDEN;
3427 *dptr++ = attr & 0xff;
3428 *dptr++ = (attr >> 8) & 0xff;
3434 /* now watch for a symlink */
3436 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3437 lock_ReleaseMutex(&scp->mx);
3438 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3440 /* we have a more accurate file to use (the
3441 * target of the symbolic link). Otherwise,
3442 * we'll just use the symlink anyway.
3444 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3446 cm_ReleaseSCache(scp);
3449 lock_ObtainMutex(&scp->mx);
3452 dptr = patchp->dptr;
3454 if (infoLevel >= 0x101) {
3456 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3458 /* copy to Creation Time */
3459 *((FILETIME *)dptr) = ft;
3462 /* copy to Last Access Time */
3463 *((FILETIME *)dptr) = ft;
3466 /* copy to Last Write Time */
3467 *((FILETIME *)dptr) = ft;
3470 /* copy to Change Time */
3471 *((FILETIME *)dptr) = ft;
3474 /* Use length for both file length and alloc length */
3475 *((LARGE_INTEGER *)dptr) = scp->length;
3477 *((LARGE_INTEGER *)dptr) = scp->length;
3480 /* Copy attributes */
3481 lattr = smb_ExtAttributes(scp);
3482 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3483 if (lattr == SMB_ATTR_NORMAL)
3484 lattr = SMB_ATTR_DIRECTORY;
3486 lattr |= SMB_ATTR_DIRECTORY;
3488 /* merge in hidden (dot file) attribute */
3489 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3490 if (lattr == SMB_ATTR_NORMAL)
3491 lattr = SMB_ATTR_HIDDEN;
3493 lattr |= SMB_ATTR_HIDDEN;
3495 *((u_long *)dptr) = lattr;
3499 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3501 /* and copy out date */
3502 shortTemp = (dosTime>>16) & 0xffff;
3503 *((u_short *)dptr) = shortTemp;
3506 /* copy out creation time */
3507 shortTemp = dosTime & 0xffff;
3508 *((u_short *)dptr) = shortTemp;
3511 /* and copy out date */
3512 shortTemp = (dosTime>>16) & 0xffff;
3513 *((u_short *)dptr) = shortTemp;
3516 /* copy out access time */
3517 shortTemp = dosTime & 0xffff;
3518 *((u_short *)dptr) = shortTemp;
3521 /* and copy out date */
3522 shortTemp = (dosTime>>16) & 0xffff;
3523 *((u_short *)dptr) = shortTemp;
3526 /* copy out mod time */
3527 shortTemp = dosTime & 0xffff;
3528 *((u_short *)dptr) = shortTemp;
3531 /* copy out file length and alloc length,
3532 * using the same for both
3534 *((u_long *)dptr) = scp->length.LowPart;
3536 *((u_long *)dptr) = scp->length.LowPart;
3539 /* finally copy out attributes as short */
3540 attr = smb_Attributes(scp);
3541 /* merge in hidden (dot file) attribute */
3542 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3543 if (lattr == SMB_ATTR_NORMAL)
3544 lattr = SMB_ATTR_HIDDEN;
3546 lattr |= SMB_ATTR_HIDDEN;
3548 *dptr++ = attr & 0xff;
3549 *dptr++ = (attr >> 8) & 0xff;
3552 lock_ReleaseMutex(&scp->mx);
3553 cm_ReleaseSCache(scp);
3556 /* now free the patches */
3557 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3558 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3562 /* and mark the list as empty */
3563 *dirPatchespp = NULL;
3568 #ifndef USE_OLD_MATCHING
3569 // char table for case insensitive comparison
3570 char mapCaseTable[256];
3572 VOID initUpperCaseTable(VOID)
3575 for (i = 0; i < 256; ++i)
3576 mapCaseTable[i] = toupper(i);
3577 // make '"' match '.'
3578 mapCaseTable[(int)'"'] = toupper('.');
3579 // make '<' match '*'
3580 mapCaseTable[(int)'<'] = toupper('*');
3581 // make '>' match '?'
3582 mapCaseTable[(int)'>'] = toupper('?');
3585 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3587 // Note : this procedure works recursively calling itself.
3589 // PSZ pattern : string containing metacharacters.
3590 // PSZ name : file name to be compared with 'pattern'.
3592 // BOOL : TRUE/FALSE (match/mistmatch)
3595 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
3597 PSZ pename; // points to the last 'name' character
3599 pename = name + strlen(name) - 1;
3610 if (*pattern == '\0')
3612 for (p = pename; p >= name; --p) {
3613 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
3614 !casefold && (*p == *pattern)) &&
3615 szWildCardMatchFileName(pattern + 1, p + 1, casefold))
3620 if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
3621 (!casefold && *name != *pattern))
3628 /* if all we have left are wildcards, then we match */
3629 for (;*pattern; pattern++) {
3630 if (*pattern != '*' && *pattern != '?')
3636 /* do a case-folding search of the star name mask with the name in namep.
3637 * Return 1 if we match, otherwise 0.
3639 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3642 int i, j, star, qmark, casefold, retval;
3644 /* make sure we only match 8.3 names, if requested */
3645 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3648 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
3650 /* optimize the pattern:
3651 * if there is a mixture of '?' and '*',
3652 * for example the sequence "*?*?*?*"
3653 * must be turned into the form "*"
3655 newmask = (char *)malloc(strlen(maskp)+1);
3656 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3657 switch ( maskp[i] ) {
3669 } else if ( qmark ) {
3673 newmask[j++] = maskp[i];
3680 } else if ( qmark ) {
3684 newmask[j++] = '\0';
3686 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
3692 #else /* USE_OLD_MATCHING */
3693 /* do a case-folding search of the star name mask with the name in namep.
3694 * Return 1 if we match, otherwise 0.
3696 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3698 unsigned char tcp1, tcp2; /* Pattern characters */
3699 unsigned char tcn1; /* Name characters */
3700 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3701 char *starNamep, *starMaskp;
3702 static char nullCharp[] = {0};
3703 int casefold = flags & CM_FLAG_CASEFOLD;
3705 /* make sure we only match 8.3 names, if requested */
3706 req8dot3 = (flags & CM_FLAG_8DOT3);
3707 if (req8dot3 && !cm_Is8Dot3(namep))
3712 /* Next pattern character */
3715 /* Next name character */
3719 /* 0 - end of pattern */
3725 else if (tcp1 == '.' || tcp1 == '"') {
3735 * first dot in pattern;
3736 * must match dot or end of name
3741 else if (tcn1 == '.') {
3750 else if (tcp1 == '?') {
3751 if (tcn1 == 0 || tcn1 == '.')
3756 else if (tcp1 == '>') {
3757 if (tcn1 != 0 && tcn1 != '.')
3761 else if (tcp1 == '*' || tcp1 == '<') {
3765 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3766 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3781 * pattern character after '*' is not null or
3782 * period. If it is '?' or '>', we are not
3783 * going to understand it. If it is '*' or
3784 * '<', we are going to skip over it. None of
3785 * these are likely, I hope.
3787 /* skip over '*' and '<' */
3788 while (tcp2 == '*' || tcp2 == '<')
3791 /* skip over characters that don't match tcp2 */
3792 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
3793 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
3794 (!casefold && tcn1 != tcp2)))
3798 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3801 /* Remember where we are */
3811 /* tcp1 is not a wildcard */
3812 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
3813 (!casefold && tcn1 == tcp1)) {
3818 /* if trying to match a star pattern, go back */
3820 maskp = starMaskp - 2;
3821 namep = starNamep + 1;
3830 #endif /* USE_OLD_MATCHING */
3832 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3837 long code = 0, code2 = 0;
3841 smb_dirListPatch_t *dirListPatchesp;
3842 smb_dirListPatch_t *curPatchp;
3845 long orbytes; /* # of bytes in this output record */
3846 long ohbytes; /* # of bytes, except file name */
3847 long onbytes; /* # of bytes in name, incl. term. null */
3848 osi_hyper_t dirLength;
3849 osi_hyper_t bufferOffset;
3850 osi_hyper_t curOffset;
3852 smb_dirSearch_t *dsp;
3856 cm_pageHeader_t *pageHeaderp;
3857 cm_user_t *userp = NULL;
3860 long nextEntryCookie;
3861 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3862 char *op; /* output data ptr */
3863 char *origOp; /* original value of op */
3864 cm_space_t *spacep; /* for pathname buffer */
3865 long maxReturnData; /* max # of return data */
3866 long maxReturnParms; /* max # of return parms */
3867 long bytesInBuffer; /* # data bytes in the output buffer */
3869 char *maskp; /* mask part of path */
3873 smb_tran2Packet_t *outp; /* response packet */
3876 char shortName[13]; /* 8.3 name if needed */
3887 if (p->opcode == 1) {
3888 /* find first; obtain basic parameters from request */
3889 attribute = p->parmsp[0];
3890 maxCount = p->parmsp[1];
3891 infoLevel = p->parmsp[3];
3892 searchFlags = p->parmsp[2];
3893 dsp = smb_NewDirSearch(1);
3894 dsp->attribute = attribute;
3895 pathp = ((char *) p->parmsp) + 12; /* points to path */
3896 if (smb_StoreAnsiFilenames)
3897 OemToChar(pathp,pathp);
3899 maskp = strrchr(pathp, '\\');
3903 maskp++; /* skip over backslash */
3904 strcpy(dsp->mask, maskp); /* and save mask */
3905 /* track if this is likely to match a lot of entries */
3906 starPattern = smb_V3IsStarMask(maskp);
3909 osi_assert(p->opcode == 2);
3910 /* find next; obtain basic parameters from request or open dir file */
3911 dsp = smb_FindDirSearch(p->parmsp[0]);
3912 maxCount = p->parmsp[1];
3913 infoLevel = p->parmsp[2];
3914 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
3915 searchFlags = p->parmsp[5];
3917 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
3918 p->parmsp[0], nextCookie);
3919 return CM_ERROR_BADFD;
3921 attribute = dsp->attribute;
3924 starPattern = 1; /* assume, since required a Find Next */
3928 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
3929 attribute, infoLevel, maxCount, searchFlags);
3931 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
3932 p->opcode, dsp->cookie, nextCookie);
3934 if (infoLevel >= 0x101)
3935 searchFlags &= ~4; /* no resume keys */
3937 dirListPatchesp = NULL;
3939 maxReturnData = p->maxReturnData;
3940 if (p->opcode == 1) /* find first */
3941 maxReturnParms = 10; /* bytes */
3943 maxReturnParms = 8; /* bytes */
3945 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
3946 if (maxReturnData > 6000)
3947 maxReturnData = 6000;
3948 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
3950 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
3953 osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
3954 maxCount, osi_LogSaveString(smb_logp, pathp));
3956 /* bail out if request looks bad */
3957 if (p->opcode == 1 && !pathp) {
3958 smb_ReleaseDirSearch(dsp);
3959 smb_FreeTran2Packet(outp);
3960 return CM_ERROR_BADSMB;
3963 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
3964 dsp->cookie, nextCookie, attribute);
3966 userp = smb_GetTran2User(vcp, p);
3968 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
3969 smb_ReleaseDirSearch(dsp);
3970 smb_FreeTran2Packet(outp);
3971 return CM_ERROR_BADSMB;
3974 /* try to get the vnode for the path name next */
3975 lock_ObtainMutex(&dsp->mx);
3981 spacep = cm_GetSpace();
3982 smb_StripLastComponent(spacep->data, NULL, pathp);
3983 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3985 cm_ReleaseUser(userp);
3986 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
3987 smb_FreeTran2Packet(outp);
3988 lock_ReleaseMutex(&dsp->mx);
3989 smb_DeleteDirSearch(dsp);
3990 smb_ReleaseDirSearch(dsp);
3993 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3994 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3995 userp, tidPathp, &req, &scp);
3996 cm_FreeSpace(spacep);
3999 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4000 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4001 cm_ReleaseSCache(scp);
4002 cm_ReleaseUser(userp);
4003 if ( WANTS_DFS_PATHNAMES(p) )
4004 code = CM_ERROR_PATH_NOT_COVERED;
4006 code = CM_ERROR_BADSHARENAME;
4007 smb_SendTran2Error(vcp, p, opx, code);
4008 smb_FreeTran2Packet(outp);
4009 lock_ReleaseMutex(&dsp->mx);
4010 smb_DeleteDirSearch(dsp);
4011 smb_ReleaseDirSearch(dsp);
4014 #endif /* DFS_SUPPORT */
4016 /* we need one hold for the entry we just stored into,
4017 * and one for our own processing. When we're done
4018 * with this function, we'll drop the one for our own
4019 * processing. We held it once from the namei call,
4020 * and so we do another hold now.
4023 lock_ObtainMutex(&scp->mx);
4024 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
4025 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4026 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4027 dsp->flags |= SMB_DIRSEARCH_BULKST;
4029 lock_ReleaseMutex(&scp->mx);
4032 lock_ReleaseMutex(&dsp->mx);
4034 cm_ReleaseUser(userp);
4035 smb_FreeTran2Packet(outp);
4036 smb_DeleteDirSearch(dsp);
4037 smb_ReleaseDirSearch(dsp);
4041 /* get the directory size */
4042 lock_ObtainMutex(&scp->mx);
4043 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4044 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4046 lock_ReleaseMutex(&scp->mx);
4047 cm_ReleaseSCache(scp);
4048 cm_ReleaseUser(userp);
4049 smb_FreeTran2Packet(outp);
4050 smb_DeleteDirSearch(dsp);
4051 smb_ReleaseDirSearch(dsp);
4056 dirLength = scp->length;
4058 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4059 curOffset.HighPart = 0;
4060 curOffset.LowPart = nextCookie;
4061 origOp = outp->datap;
4069 if (searchFlags & 4)
4070 /* skip over resume key */
4073 /* make sure that curOffset.LowPart doesn't point to the first
4074 * 32 bytes in the 2nd through last dir page, and that it doesn't
4075 * point at the first 13 32-byte chunks in the first dir page,
4076 * since those are dir and page headers, and don't contain useful
4079 temp = curOffset.LowPart & (2048-1);
4080 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4081 /* we're in the first page */
4082 if (temp < 13*32) temp = 13*32;
4085 /* we're in a later dir page */
4086 if (temp < 32) temp = 32;
4089 /* make sure the low order 5 bits are zero */
4092 /* now put temp bits back ito curOffset.LowPart */
4093 curOffset.LowPart &= ~(2048-1);
4094 curOffset.LowPart |= temp;
4096 /* check if we've passed the dir's EOF */
4097 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4098 osi_Log0(smb_logp, "T2 search dir passed eof");
4103 /* check if we've returned all the names that will fit in the
4104 * response packet; we check return count as well as the number
4105 * of bytes requested. We check the # of bytes after we find
4106 * the dir entry, since we'll need to check its size.
4108 if (returnedNames >= maxCount) {
4109 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4110 returnedNames, maxCount);
4114 /* see if we can use the bufferp we have now; compute in which
4115 * page the current offset would be, and check whether that's
4116 * the offset of the buffer we have. If not, get the buffer.
4118 thyper.HighPart = curOffset.HighPart;
4119 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4120 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4123 buf_Release(bufferp);
4126 lock_ReleaseMutex(&scp->mx);
4127 lock_ObtainRead(&scp->bufCreateLock);
4128 code = buf_Get(scp, &thyper, &bufferp);
4129 lock_ReleaseRead(&scp->bufCreateLock);
4130 lock_ObtainMutex(&dsp->mx);
4132 /* now, if we're doing a star match, do bulk fetching
4133 * of all of the status info for files in the dir.
4136 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
4139 lock_ObtainMutex(&scp->mx);
4140 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4141 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
4142 /* Don't bulk stat if risking timeout */
4143 int now = GetTickCount();
4144 if (now - req.startTime > 5000) {
4145 scp->bulkStatProgress = thyper;
4146 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4147 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4149 cm_TryBulkStat(scp, &thyper, userp, &req);
4152 lock_ObtainMutex(&scp->mx);
4154 lock_ReleaseMutex(&dsp->mx);
4156 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
4160 bufferOffset = thyper;
4162 /* now get the data in the cache */
4164 code = cm_SyncOp(scp, bufferp, userp, &req,
4166 CM_SCACHESYNC_NEEDCALLBACK
4167 | CM_SCACHESYNC_READ);
4169 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
4173 if (cm_HaveBuffer(scp, bufferp, 0)) {
4174 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4178 /* otherwise, load the buffer and try again */
4179 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4182 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4183 scp, bufferp, code);
4188 buf_Release(bufferp);
4192 } /* if (wrong buffer) ... */
4194 /* now we have the buffer containing the entry we're interested
4195 * in; copy it out if it represents a non-deleted entry.
4197 entryInDir = curOffset.LowPart & (2048-1);
4198 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4200 /* page header will help tell us which entries are free. Page
4201 * header can change more often than once per buffer, since
4202 * AFS 3 dir page size may be less than (but not more than)
4203 * a buffer package buffer.
4205 /* only look intra-buffer */
4206 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4207 temp &= ~(2048 - 1); /* turn off intra-page bits */
4208 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4210 /* now determine which entry we're looking at in the page.
4211 * If it is free (there's a free bitmap at the start of the
4212 * dir), we should skip these 32 bytes.
4214 slotInPage = (entryInDir & 0x7e0) >> 5;
4215 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
4216 (1 << (slotInPage & 0x7)))) {
4217 /* this entry is free */
4218 numDirChunks = 1; /* only skip this guy */
4222 tp = bufferp->datap + entryInBuffer;
4223 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4225 /* while we're here, compute the next entry's location, too,
4226 * since we'll need it when writing out the cookie into the dir
4229 * XXXX Probably should do more sanity checking.
4231 numDirChunks = cm_NameEntries(dep->name, &onbytes);
4233 /* compute offset of cookie representing next entry */
4234 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4236 /* Need 8.3 name? */
4238 if (infoLevel == SMB_QUERY_FILE_NAME_INFO
4239 && dep->fid.vnode != 0
4240 && !cm_Is8Dot3(dep->name)) {
4241 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4245 osi_Log3(smb_logp, "T2 search dir vn %u name %s (%s)",
4246 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4247 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4249 /* When matching, we are using doing a case fold if we have a wildcard mask.
4250 * If we get a non-wildcard match, it's a lookup for a specific file.
4252 if (dep->fid.vnode != 0 &&
4253 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
4255 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
4257 /* Eliminate entries that don't match requested attributes */
4258 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
4259 smb_IsDotFile(dep->name)) {
4260 osi_Log0(smb_logp, "T2 search dir skipping hidden");
4261 goto nextEntry; /* no hidden files */
4263 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4265 /* We have already done the cm_TryBulkStat above */
4266 fid.cell = scp->fid.cell;
4267 fid.volume = scp->fid.volume;
4268 fid.vnode = ntohl(dep->fid.vnode);
4269 fid.unique = ntohl(dep->fid.unique);
4270 fileType = cm_FindFileType(&fid);
4271 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
4272 "has filetype %d", dep->name,
4274 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4275 fileType == CM_SCACHETYPE_DFSLINK ||
4276 fileType == CM_SCACHETYPE_INVALID)
4277 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
4281 /* finally check if this name will fit */
4283 /* standard dir entry stuff */
4284 if (infoLevel < 0x101)
4285 ohbytes = 23; /* pre-NT */
4286 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
4287 ohbytes = 12; /* NT names only */
4289 ohbytes = 64; /* NT */
4291 if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
4292 ohbytes += 26; /* Short name & length */
4294 if (searchFlags & 4) {
4295 ohbytes += 4; /* if resume key required */
4299 && infoLevel != 0x101
4300 && infoLevel != 0x103)
4301 ohbytes += 4; /* EASIZE */
4303 /* add header to name & term. null */
4304 orbytes = onbytes + ohbytes + 1;
4306 /* now, we round up the record to a 4 byte alignment,
4307 * and we make sure that we have enough room here for
4308 * even the aligned version (so we don't have to worry
4309 * about an * overflow when we pad things out below).
4310 * That's the reason for the alignment arithmetic below.
4312 if (infoLevel >= 0x101)
4313 align = (4 - (orbytes & 3)) & 3;
4316 if (orbytes + bytesInBuffer + align > maxReturnData) {
4317 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4322 /* this is one of the entries to use: it is not deleted
4323 * and it matches the star pattern we're looking for.
4324 * Put out the name, preceded by its length.
4326 /* First zero everything else */
4327 memset(origOp, 0, ohbytes);
4329 if (infoLevel <= 0x101)
4330 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4331 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
4332 *((u_long *)(op + 8)) = onbytes;
4334 *((u_long *)(op + 60)) = onbytes;
4335 strcpy(origOp+ohbytes, dep->name);
4336 if (smb_StoreAnsiFilenames)
4337 CharToOem(origOp+ohbytes, origOp+ohbytes);
4339 /* Short name if requested and needed */
4340 if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
4341 if (NeedShortName) {
4342 strcpy(op + 70, shortName);
4343 if (smb_StoreAnsiFilenames)
4344 CharToOem(op + 70, op + 70);
4345 *(op + 68) = (char)(shortNameEnd - shortName);
4349 /* now, adjust the # of entries copied */
4352 /* NextEntryOffset and FileIndex */
4353 if (infoLevel >= 101) {
4354 int entryOffset = orbytes + align;
4355 *((u_long *)op) = entryOffset;
4356 *((u_long *)(op+4)) = nextEntryCookie;
4359 /* now we emit the attribute. This is tricky, since
4360 * we need to really stat the file to find out what
4361 * type of entry we've got. Right now, we're copying
4362 * out data from a buffer, while holding the scp
4363 * locked, so it isn't really convenient to stat
4364 * something now. We'll put in a place holder
4365 * now, and make a second pass before returning this
4366 * to get the real attributes. So, we just skip the
4367 * data for now, and adjust it later. We allocate a
4368 * patch record to make it easy to find this point
4369 * later. The replay will happen at a time when it is
4370 * safe to unlock the directory.
4372 if (infoLevel != 0x103) {
4373 curPatchp = malloc(sizeof(*curPatchp));
4374 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4376 curPatchp->dptr = op;
4377 if (infoLevel >= 0x101)
4378 curPatchp->dptr += 8;
4380 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4381 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4384 curPatchp->flags = 0;
4386 curPatchp->fid.cell = scp->fid.cell;
4387 curPatchp->fid.volume = scp->fid.volume;
4388 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4389 curPatchp->fid.unique = ntohl(dep->fid.unique);
4392 curPatchp->dep = dep;
4395 if (searchFlags & 4)
4396 /* put out resume key */
4397 *((u_long *)origOp) = nextEntryCookie;
4399 /* Adjust byte ptr and count */
4400 origOp += orbytes; /* skip entire record */
4401 bytesInBuffer += orbytes;
4403 /* and pad the record out */
4404 while (--align >= 0) {
4408 } /* if we're including this name */
4409 else if (!starPattern &&
4411 dep->fid.vnode != 0 &&
4412 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4413 /* We were looking for exact matches, but here's an inexact one*/
4418 /* and adjust curOffset to be where the new cookie is */
4419 thyper.HighPart = 0;
4420 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4421 curOffset = LargeIntegerAdd(thyper, curOffset);
4422 } /* while copying data for dir listing */
4424 /* If we didn't get a star pattern, we did an exact match during the first pass.
4425 * If there were no exact matches found, we fail over to inexact matches by
4426 * marking the query as a star pattern (matches all case permutations), and
4427 * re-running the query.
4429 if (returnedNames == 0 && !starPattern && foundInexact) {
4430 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4435 /* release the mutex */
4436 lock_ReleaseMutex(&scp->mx);
4438 buf_Release(bufferp);
4440 /* apply and free last set of patches; if not doing a star match, this
4441 * will be empty, but better safe (and freeing everything) than sorry.
4443 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4446 /* now put out the final parameters */
4447 if (returnedNames == 0)
4449 if (p->opcode == 1) {
4451 outp->parmsp[0] = (unsigned short) dsp->cookie;
4452 outp->parmsp[1] = returnedNames;
4453 outp->parmsp[2] = eos;
4454 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4455 outp->parmsp[4] = 0;
4456 /* don't need last name to continue
4457 * search, cookie is enough. Normally,
4458 * this is the offset of the file name
4459 * of the last entry returned.
4461 outp->totalParms = 10; /* in bytes */
4465 outp->parmsp[0] = returnedNames;
4466 outp->parmsp[1] = eos;
4467 outp->parmsp[2] = 0; /* EAS error */
4468 outp->parmsp[3] = 0; /* last name, as above */
4469 outp->totalParms = 8; /* in bytes */
4472 /* return # of bytes in the buffer */
4473 outp->totalData = bytesInBuffer;
4475 /* Return error code if unsuccessful on first request */
4476 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4477 code = CM_ERROR_NOSUCHFILE;
4479 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
4480 p->opcode, dsp->cookie, returnedNames, code);
4482 /* if we're supposed to close the search after this request, or if
4483 * we're supposed to close the search if we're done, and we're done,
4484 * or if something went wrong, close the search.
4486 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4487 if ((searchFlags & 1) || (returnedNames == 0) ||
4488 ((searchFlags & 2) && eos) || code != 0)
4489 smb_DeleteDirSearch(dsp);
4491 smb_SendTran2Error(vcp, p, opx, code);
4493 smb_SendTran2Packet(vcp, outp, opx);
4495 smb_FreeTran2Packet(outp);
4496 smb_ReleaseDirSearch(dsp);
4497 cm_ReleaseSCache(scp);
4498 cm_ReleaseUser(userp);
4502 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4505 smb_dirSearch_t *dsp;
4507 dirHandle = smb_GetSMBParm(inp, 0);
4509 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4511 dsp = smb_FindDirSearch(dirHandle);
4514 return CM_ERROR_BADFD;
4516 /* otherwise, we have an FD to destroy */
4517 smb_DeleteDirSearch(dsp);
4518 smb_ReleaseDirSearch(dsp);
4520 /* and return results */
4521 smb_SetSMBDataLength(outp, 0);
4526 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4528 smb_SetSMBDataLength(outp, 0);
4532 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4539 cm_scache_t *dscp; /* dir we're dealing with */
4540 cm_scache_t *scp; /* file we're creating */
4542 int initialModeBits;
4552 int parmSlot; /* which parm we're dealing with */
4561 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4562 openFun = smb_GetSMBParm(inp, 8); /* open function */
4563 excl = ((openFun & 3) == 0);
4564 trunc = ((openFun & 3) == 2); /* truncate it */
4565 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4566 openAction = 0; /* tracks what we did */
4568 attributes = smb_GetSMBParm(inp, 5);
4569 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4571 /* compute initial mode bits based on read-only flag in attributes */
4572 initialModeBits = 0666;
4573 if (attributes & 1) initialModeBits &= ~0222;
4575 pathp = smb_GetSMBData(inp, NULL);
4576 if (smb_StoreAnsiFilenames)
4577 OemToChar(pathp,pathp);
4579 spacep = inp->spacep;
4580 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4582 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4583 /* special case magic file name for receiving IOCTL requests
4584 * (since IOCTL calls themselves aren't getting through).
4587 osi_Log0(smb_logp, "IOCTL Open");
4590 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4591 smb_SetupIoctlFid(fidp, spacep);
4593 /* set inp->fid so that later read calls in same msg can find fid */
4594 inp->fid = fidp->fid;
4596 /* copy out remainder of the parms */
4598 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4600 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4601 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4602 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4603 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4604 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4605 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4606 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4607 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4609 /* and the final "always present" stuff */
4610 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4611 /* next write out the "unique" ID */
4612 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4613 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4614 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4615 smb_SetSMBDataLength(outp, 0);
4617 /* and clean up fid reference */
4618 smb_ReleaseFID(fidp);
4622 #ifdef DEBUG_VERBOSE
4624 char *hexp, *asciip;
4625 asciip = (lastNamep ? lastNamep : pathp );
4626 hexp = osi_HexifyString(asciip);
4627 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4631 userp = smb_GetUserFromVCP(vcp, inp);
4634 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4636 cm_ReleaseUser(userp);
4637 return CM_ERROR_NOSUCHPATH;
4639 code = cm_NameI(cm_data.rootSCachep, pathp,
4640 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4641 userp, tidPathp, &req, &scp);
4644 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4645 cm_ReleaseSCache(scp);
4646 cm_ReleaseUser(userp);
4647 if ( WANTS_DFS_PATHNAMES(inp) )
4648 return CM_ERROR_PATH_NOT_COVERED;
4650 return CM_ERROR_BADSHARENAME;
4652 #endif /* DFS_SUPPORT */
4655 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4656 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4657 userp, tidPathp, &req, &dscp);
4659 cm_ReleaseUser(userp);
4664 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4665 cm_ReleaseSCache(dscp);
4666 cm_ReleaseUser(userp);
4667 if ( WANTS_DFS_PATHNAMES(inp) )
4668 return CM_ERROR_PATH_NOT_COVERED;
4670 return CM_ERROR_BADSHARENAME;
4672 #endif /* DFS_SUPPORT */
4673 /* otherwise, scp points to the parent directory. Do a lookup,
4674 * and truncate the file if we find it, otherwise we create the
4681 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
4683 if (code && code != CM_ERROR_NOSUCHFILE) {
4684 cm_ReleaseSCache(dscp);
4685 cm_ReleaseUser(userp);
4690 /* if we get here, if code is 0, the file exists and is represented by
4691 * scp. Otherwise, we have to create it. The dir may be represented
4692 * by dscp, or we may have found the file directly. If code is non-zero,
4696 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
4698 if (dscp) cm_ReleaseSCache(dscp);
4699 cm_ReleaseSCache(scp);
4700 cm_ReleaseUser(userp);
4705 /* oops, file shouldn't be there */
4707 cm_ReleaseSCache(dscp);
4708 cm_ReleaseSCache(scp);
4709 cm_ReleaseUser(userp);
4710 return CM_ERROR_EXISTS;
4714 setAttr.mask = CM_ATTRMASK_LENGTH;
4715 setAttr.length.LowPart = 0;
4716 setAttr.length.HighPart = 0;
4717 code = cm_SetAttr(scp, &setAttr, userp, &req);
4718 openAction = 3; /* truncated existing file */
4720 else openAction = 1; /* found existing file */
4722 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
4723 /* don't create if not found */
4724 if (dscp) cm_ReleaseSCache(dscp);
4725 cm_ReleaseUser(userp);
4726 return CM_ERROR_NOSUCHFILE;
4729 osi_assert(dscp != NULL);
4730 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
4731 osi_LogSaveString(smb_logp, lastNamep));
4732 openAction = 2; /* created file */
4733 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4734 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
4735 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4739 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
4740 smb_NotifyChange(FILE_ACTION_ADDED,
4741 FILE_NOTIFY_CHANGE_FILE_NAME,
4742 dscp, lastNamep, NULL, TRUE);
4743 } else if (!excl && code == CM_ERROR_EXISTS) {
4744 /* not an exclusive create, and someone else tried
4745 * creating it already, then we open it anyway. We
4746 * don't bother retrying after this, since if this next
4747 * fails, that means that the file was deleted after we
4748 * started this call.
4750 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4754 setAttr.mask = CM_ATTRMASK_LENGTH;
4755 setAttr.length.LowPart = 0;
4756 setAttr.length.HighPart = 0;
4757 code = cm_SetAttr(scp, &setAttr, userp, &req);
4759 } /* lookup succeeded */
4763 /* we don't need this any longer */
4765 cm_ReleaseSCache(dscp);
4768 /* something went wrong creating or truncating the file */
4770 cm_ReleaseSCache(scp);
4771 cm_ReleaseUser(userp);
4775 /* make sure we're about to open a file */
4776 if (scp->fileType != CM_SCACHETYPE_FILE) {
4777 cm_ReleaseSCache(scp);
4778 cm_ReleaseUser(userp);
4779 return CM_ERROR_ISDIR;
4782 /* now all we have to do is open the file itself */
4783 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4787 lock_ObtainMutex(&fidp->mx);
4788 /* save a pointer to the vnode */
4791 fidp->userp = userp;
4793 /* compute open mode */
4795 fidp->flags |= SMB_FID_OPENREAD;
4796 if (openMode == 1 || openMode == 2)
4797 fidp->flags |= SMB_FID_OPENWRITE;
4799 /* remember if the file was newly created */
4801 fidp->flags |= SMB_FID_CREATED;
4803 lock_ReleaseMutex(&fidp->mx);
4804 smb_ReleaseFID(fidp);
4806 cm_Open(scp, 0, userp);
4808 /* set inp->fid so that later read calls in same msg can find fid */
4809 inp->fid = fidp->fid;
4811 /* copy out remainder of the parms */
4813 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4814 lock_ObtainMutex(&scp->mx);
4816 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
4817 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4818 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
4819 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
4820 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
4821 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
4822 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4823 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4824 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4826 /* and the final "always present" stuff */
4827 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
4828 /* next write out the "unique" ID */
4829 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
4830 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
4831 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4832 lock_ReleaseMutex(&scp->mx);
4833 smb_SetSMBDataLength(outp, 0);
4835 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
4837 cm_ReleaseUser(userp);
4838 /* leave scp held since we put it in fidp->scp */
4842 static void smb_GetLockParams(unsigned char LockType,
4844 unsigned int * ppid,
4845 LARGE_INTEGER * pOffset,
4846 LARGE_INTEGER * pLength)
4848 if (LockType & LOCKING_ANDX_LARGE_FILES) {
4850 *ppid = *((USHORT *) *buf);
4851 pOffset->HighPart = *((LONG *)(*buf + 4));
4852 pOffset->LowPart = *((DWORD *)(*buf + 8));
4853 pLength->HighPart = *((LONG *)(*buf + 12));
4854 pLength->LowPart = *((DWORD *)(*buf + 16));
4858 /* Not Large Files */
4859 *ppid = *((USHORT *) *buf);
4860 pOffset->HighPart = 0;
4861 pOffset->LowPart = *((DWORD *)(*buf + 2));
4862 pLength->HighPart = 0;
4863 pLength->LowPart = *((DWORD *)(*buf + 6));
4868 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4875 unsigned char LockType;
4876 unsigned short NumberOfUnlocks, NumberOfLocks;
4880 LARGE_INTEGER LOffset, LLength;
4881 smb_waitingLockRequest_t *wlRequest = NULL;
4882 cm_file_lock_t *lockp;
4890 fid = smb_GetSMBParm(inp, 2);
4891 fid = smb_ChainFID(fid, inp);
4893 fidp = smb_FindFID(vcp, fid, 0);
4895 return CM_ERROR_BADFD;
4897 lock_ObtainMutex(&fidp->mx);
4898 if (fidp->flags & SMB_FID_IOCTL) {
4899 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
4900 lock_ReleaseMutex(&fidp->mx);
4901 smb_ReleaseFID(fidp);
4902 return CM_ERROR_BADFD;
4906 lock_ReleaseMutex(&fidp->mx);
4908 /* set inp->fid so that later read calls in same msg can find fid */
4911 userp = smb_GetUserFromVCP(vcp, inp);
4914 lock_ObtainMutex(&scp->mx);
4915 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4916 CM_SCACHESYNC_NEEDCALLBACK
4917 | CM_SCACHESYNC_GETSTATUS
4918 | CM_SCACHESYNC_LOCK);
4920 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
4924 LockType = smb_GetSMBParm(inp, 3) & 0xff;
4925 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
4926 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
4927 NumberOfLocks = smb_GetSMBParm(inp, 7);
4929 if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
4930 (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
4932 /* We don't support these requests. Apparently, we can safely
4933 not deal with them too. */
4934 osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
4935 ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
4936 "LOCKING_ANDX_CANCEL_LOCK":
4937 "LOCKING_ANDX_CHANGE_LOCKTYPE"));
4938 /* No need to call osi_LogSaveString since these are string
4941 code = CM_ERROR_BADOP;
4946 op = smb_GetSMBData(inp, NULL);
4948 for (i=0; i<NumberOfUnlocks; i++) {
4949 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
4951 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
4953 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
4961 for (i=0; i<NumberOfLocks; i++) {
4962 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
4964 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
4966 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
4967 userp, &req, &lockp);
4969 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
4970 smb_waitingLock_t * wLock;
4972 /* Put on waiting list */
4973 if(wlRequest == NULL) {
4977 LARGE_INTEGER tOffset, tLength;
4979 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
4981 osi_assert(wlRequest != NULL);
4983 wlRequest->vcp = vcp;
4985 wlRequest->scp = scp;
4987 wlRequest->inp = smb_CopyPacket(inp);
4988 wlRequest->outp = smb_CopyPacket(outp);
4989 wlRequest->lockType = LockType;
4990 wlRequest->timeRemaining = Timeout;
4991 wlRequest->locks = NULL;
4993 /* The waiting lock request needs to have enough
4994 information to undo all the locks in the request.
4995 We do the following to store info about locks that
4996 have already been granted. Sure, we can get most
4997 of the info from the packet, but the packet doesn't
4998 hold the result of cm_Lock call. In practice we
4999 only receive packets with one or two locks, so we
5000 are only wasting a few bytes here and there and
5001 only for a limited period of time until the waiting
5002 lock times out or is freed. */
5004 for(opt = op_locks, j=i; j > 0; j--) {
5005 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
5007 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5009 wLock = malloc(sizeof(smb_waitingLock_t));
5011 osi_assert(wLock != NULL);
5014 wLock->LOffset = tOffset;
5015 wLock->LLength = tLength;
5016 wLock->lockp = NULL;
5017 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
5018 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5023 wLock = malloc(sizeof(smb_waitingLock_t));
5025 osi_assert(wLock != NULL);
5028 wLock->LOffset = LOffset;
5029 wLock->LLength = LLength;
5030 wLock->lockp = lockp;
5031 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
5032 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5035 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
5043 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
5050 /* Since something went wrong with the lock number i, we now
5051 have to go ahead and release any locks acquired before the
5052 failure. All locks before lock number i (of which there
5053 are i of them) have either been successful or are waiting.
5054 Either case requires calling cm_Unlock(). */
5056 /* And purge the waiting lock */
5057 if(wlRequest != NULL) {
5058 smb_waitingLock_t * wl;
5059 smb_waitingLock_t * wlNext;
5062 for(wl = wlRequest->locks; wl; wl = wlNext) {
5064 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
5066 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
5069 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
5071 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
5074 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
5079 smb_ReleaseVC(wlRequest->vcp);
5080 cm_ReleaseSCache(wlRequest->scp);
5081 smb_FreePacket(wlRequest->inp);
5082 smb_FreePacket(wlRequest->outp);
5091 if (wlRequest != NULL) {
5093 lock_ObtainWrite(&smb_globalLock);
5094 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
5096 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
5097 lock_ReleaseWrite(&smb_globalLock);
5099 /* don't send reply immediately */
5100 outp->flags |= SMB_PACKETFLAG_NOSEND;
5103 smb_SetSMBDataLength(outp, 0);
5107 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5110 lock_ReleaseMutex(&scp->mx);
5111 cm_ReleaseSCache(scp);
5112 cm_ReleaseUser(userp);
5113 smb_ReleaseFID(fidp);
5118 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5124 afs_uint32 searchTime;
5130 fid = smb_GetSMBParm(inp, 0);
5131 fid = smb_ChainFID(fid, inp);
5133 fidp = smb_FindFID(vcp, fid, 0);
5135 return CM_ERROR_BADFD;
5137 lock_ObtainMutex(&fidp->mx);
5138 if (fidp->flags & SMB_FID_IOCTL) {
5139 lock_ReleaseMutex(&fidp->mx);
5140 smb_ReleaseFID(fidp);
5141 return CM_ERROR_BADFD;
5145 lock_ReleaseMutex(&fidp->mx);
5147 userp = smb_GetUserFromVCP(vcp, inp);
5150 /* otherwise, stat the file */
5151 lock_ObtainMutex(&scp->mx);
5152 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5153 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5157 /* decode times. We need a search time, but the response to this
5158 * call provides the date first, not the time, as returned in the
5159 * searchTime variable. So we take the high-order bits first.
5161 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
5162 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
5163 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
5164 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
5165 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
5166 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
5167 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
5169 /* now handle file size and allocation size */
5170 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
5171 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
5172 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
5173 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
5175 /* file attribute */
5176 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
5178 /* and finalize stuff */
5179 smb_SetSMBDataLength(outp, 0);
5183 lock_ReleaseMutex(&scp->mx);
5184 cm_ReleaseSCache(scp);
5185 cm_ReleaseUser(userp);
5186 smb_ReleaseFID(fidp);
5190 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5196 afs_uint32 searchTime;
5204 fid = smb_GetSMBParm(inp, 0);
5205 fid = smb_ChainFID(fid, inp);
5207 fidp = smb_FindFID(vcp, fid, 0);
5209 return CM_ERROR_BADFD;
5211 lock_ObtainMutex(&fidp->mx);
5212 if (fidp->flags & SMB_FID_IOCTL) {
5213 lock_ReleaseMutex(&fidp->mx);
5214 smb_ReleaseFID(fidp);
5215 return CM_ERROR_BADFD;
5219 lock_ReleaseMutex(&fidp->mx);
5221 userp = smb_GetUserFromVCP(vcp, inp);
5224 /* now prepare to call cm_setattr. This message only sets various times,
5225 * and AFS only implements mtime, and we'll set the mtime if that's
5226 * requested. The others we'll ignore.
5228 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
5230 if (searchTime != 0) {
5231 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
5233 if ( unixTime != -1 ) {
5234 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
5235 attrs.clientModTime = unixTime;
5236 code = cm_SetAttr(scp, &attrs, userp, &req);
5238 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
5240 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
5246 cm_ReleaseSCache(scp);
5247 cm_ReleaseUser(userp);
5248 smb_ReleaseFID(fidp);
5252 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5255 long count, written = 0, total_written = 0;
5261 cm_attr_t truncAttr; /* attribute struct used for truncating file */
5263 int inDataBlockCount;
5265 fd = smb_GetSMBParm(inp, 2);
5266 count = smb_GetSMBParm(inp, 10);
5268 offset.HighPart = 0;
5269 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5271 if (*inp->wctp == 14) {
5272 /* we have a request with 64-bit file offsets */
5273 #ifdef AFS_LARGEFILES
5274 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
5276 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
5278 osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
5279 /* we shouldn't have received this op if we didn't specify
5280 largefile support */
5281 return CM_ERROR_BADOP;
5286 op = inp->data + smb_GetSMBParm(inp, 11);
5287 inDataBlockCount = count;
5289 osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
5290 fd, offset.HighPart, offset.LowPart, count);
5292 fd = smb_ChainFID(fd, inp);
5293 fidp = smb_FindFID(vcp, fd, 0);
5295 return CM_ERROR_BADFD;
5297 lock_ObtainMutex(&fidp->mx);
5298 if (fidp->flags & SMB_FID_IOCTL) {
5299 lock_ReleaseMutex(&fidp->mx);
5300 code = smb_IoctlV3Write(fidp, vcp, inp, outp);
5301 smb_ReleaseFID(fidp);
5304 lock_ReleaseMutex(&fidp->mx);
5305 userp = smb_GetUserFromVCP(vcp, inp);
5307 /* special case: 0 bytes transferred means there is no data
5308 transferred. A slight departure from SMB_COM_WRITE where this
5309 means that we are supposed to truncate the file at this
5314 LARGE_INTEGER LOffset;
5315 LARGE_INTEGER LLength;
5317 pid = ((smb_t *) inp)->pid;
5318 key = cm_GenerateKey(vcp->vcID, pid, fd);
5320 LOffset.HighPart = offset.HighPart;
5321 LOffset.LowPart = offset.LowPart;
5322 LLength.HighPart = 0;
5323 LLength.LowPart = count;
5325 lock_ObtainMutex(&fidp->scp->mx);
5326 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
5327 lock_ReleaseMutex(&fidp->scp->mx);
5334 * Work around bug in NT client
5336 * When copying a file, the NT client should first copy the data,
5337 * then copy the last write time. But sometimes the NT client does
5338 * these in the wrong order, so the data copies would inadvertently
5339 * cause the last write time to be overwritten. We try to detect this,
5340 * and don't set client mod time if we think that would go against the
5343 lock_ObtainMutex(&fidp->mx);
5344 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5345 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5346 fidp->scp->clientModTime = time(NULL);
5348 lock_ReleaseMutex(&fidp->mx);
5351 while ( code == 0 && count > 0 ) {
5353 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5355 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5357 if (code == 0 && written == 0)
5358 code = CM_ERROR_PARTIALWRITE;
5360 offset = LargeIntegerAdd(offset,
5361 ConvertLongToLargeInteger(written));
5363 total_written += written;
5369 /* slots 0 and 1 are reserved for request chaining and will be
5370 filled in when we return. */
5371 smb_SetSMBParm(outp, 2, total_written);
5372 smb_SetSMBParm(outp, 3, 0); /* reserved */
5373 smb_SetSMBParm(outp, 4, 0); /* reserved */
5374 smb_SetSMBParm(outp, 5, 0); /* reserved */
5375 smb_SetSMBDataLength(outp, 0);
5378 smb_ReleaseFID(fidp);
5379 cm_ReleaseUser(userp);
5384 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5388 long finalCount = 0;
5397 fd = smb_GetSMBParm(inp, 2);
5398 count = smb_GetSMBParm(inp, 5);
5399 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5401 if (*inp->wctp == 12) {
5402 /* a request with 64-bit offsets */
5403 #ifdef AFS_LARGEFILES
5404 offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
5406 if (LargeIntegerLessThanZero(offset)) {
5407 osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
5408 offset.HighPart, offset.LowPart);
5409 return CM_ERROR_BADSMB;
5412 if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
5413 osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit. Dropping");
5414 return CM_ERROR_BADSMB;
5416 offset.HighPart = 0;
5420 offset.HighPart = 0;
5423 osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
5424 fd, offset.HighPart, offset.LowPart, count);
5426 fd = smb_ChainFID(fd, inp);
5427 fidp = smb_FindFID(vcp, fd, 0);
5429 return CM_ERROR_BADFD;
5432 pid = ((smb_t *) inp)->pid;
5433 key = cm_GenerateKey(vcp->vcID, pid, fd);
5435 LARGE_INTEGER LOffset, LLength;
5437 LOffset.HighPart = offset.HighPart;
5438 LOffset.LowPart = offset.LowPart;
5439 LLength.HighPart = 0;
5440 LLength.LowPart = count;
5442 lock_ObtainMutex(&fidp->scp->mx);
5443 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
5444 lock_ReleaseMutex(&fidp->scp->mx);
5448 smb_ReleaseFID(fidp);
5452 /* set inp->fid so that later read calls in same msg can find fid */
5455 lock_ObtainMutex(&fidp->mx);
5456 if (fidp->flags & SMB_FID_IOCTL) {
5457 lock_ReleaseMutex(&fidp->mx);
5458 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
5459 smb_ReleaseFID(fidp);
5462 lock_ReleaseMutex(&fidp->mx);
5464 userp = smb_GetUserFromVCP(vcp, inp);
5466 /* 0 and 1 are reserved for request chaining, were setup by our caller,
5467 * and will be further filled in after we return.
5469 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
5470 smb_SetSMBParm(outp, 3, 0); /* resvd */
5471 smb_SetSMBParm(outp, 4, 0); /* resvd */
5472 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
5473 /* fill in #6 when we have all the parameters' space reserved */
5474 smb_SetSMBParm(outp, 7, 0); /* resv'd */
5475 smb_SetSMBParm(outp, 8, 0); /* resv'd */
5476 smb_SetSMBParm(outp, 9, 0); /* resv'd */
5477 smb_SetSMBParm(outp, 10, 0); /* resv'd */
5478 smb_SetSMBParm(outp, 11, 0); /* reserved */
5480 /* get op ptr after putting in the parms, since otherwise we don't
5481 * know where the data really is.
5483 op = smb_GetSMBData(outp, NULL);
5485 /* now fill in offset from start of SMB header to first data byte (to op) */
5486 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
5488 /* set the packet data length the count of the # of bytes */
5489 smb_SetSMBDataLength(outp, count);
5492 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5494 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5497 /* fix some things up */
5498 smb_SetSMBParm(outp, 5, finalCount);
5499 smb_SetSMBDataLength(outp, finalCount);
5501 smb_ReleaseFID(fidp);
5503 cm_ReleaseUser(userp);
5508 * Values for createDisp, copied from NTDDK.H
5510 #define FILE_SUPERSEDE 0 // (???)
5511 #define FILE_OPEN 1 // (open)
5512 #define FILE_CREATE 2 // (exclusive)
5513 #define FILE_OPEN_IF 3 // (non-exclusive)
5514 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
5515 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
5518 #define REQUEST_OPLOCK 2
5519 #define REQUEST_BATCH_OPLOCK 4
5520 #define OPEN_DIRECTORY 8
5521 #define EXTENDED_RESPONSE_REQUIRED 0x10
5523 /* CreateOptions field. */
5524 #define FILE_DIRECTORY_FILE 0x0001
5525 #define FILE_WRITE_THROUGH 0x0002
5526 #define FILE_SEQUENTIAL_ONLY 0x0004
5527 #define FILE_NON_DIRECTORY_FILE 0x0040
5528 #define FILE_NO_EA_KNOWLEDGE 0x0200
5529 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
5530 #define FILE_RANDOM_ACCESS 0x0800
5531 #define FILE_DELETE_ON_CLOSE 0x1000
5532 #define FILE_OPEN_BY_FILE_ID 0x2000
5534 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5536 char *pathp, *realPathp;
5540 cm_scache_t *dscp; /* parent dir */
5541 cm_scache_t *scp; /* file to create or open */
5542 cm_scache_t *targetScp; /* if scp is a symlink */
5546 unsigned short nameLength;
5548 unsigned int requestOpLock;
5549 unsigned int requestBatchOpLock;
5550 unsigned int mustBeDir;
5551 unsigned int extendedRespRequired;
5552 unsigned int treeCreate;
5554 unsigned int desiredAccess;
5555 unsigned int extAttributes;
5556 unsigned int createDisp;
5557 unsigned int createOptions;
5558 unsigned int shareAccess;
5559 int initialModeBits;
5560 unsigned short baseFid;
5561 smb_fid_t *baseFidp;
5563 cm_scache_t *baseDirp;
5564 unsigned short openAction;
5576 /* This code is very long and has a lot of if-then-else clauses
5577 * scp and dscp get reused frequently and we need to ensure that
5578 * we don't lose a reference. Start by ensuring that they are NULL.
5585 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
5586 flags = smb_GetSMBOffsetParm(inp, 3, 1)
5587 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
5588 requestOpLock = flags & REQUEST_OPLOCK;
5589 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
5590 mustBeDir = flags & OPEN_DIRECTORY;
5591 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
5594 * Why all of a sudden 32-bit FID?
5595 * We will reject all bits higher than 16.
5597 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
5598 return CM_ERROR_INVAL;
5599 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
5600 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
5601 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
5602 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
5603 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
5604 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
5605 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
5606 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
5607 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
5608 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
5609 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
5611 /* mustBeDir is never set; createOptions directory bit seems to be
5614 if (createOptions & FILE_DIRECTORY_FILE)
5616 else if (createOptions & FILE_NON_DIRECTORY_FILE)
5622 * compute initial mode bits based on read-only flag in
5623 * extended attributes
5625 initialModeBits = 0666;
5626 if (extAttributes & SMB_ATTR_READONLY)
5627 initialModeBits &= ~0222;
5629 pathp = smb_GetSMBData(inp, NULL);
5630 /* Sometimes path is not null-terminated, so we make a copy. */
5631 realPathp = malloc(nameLength+1);
5632 memcpy(realPathp, pathp, nameLength);
5633 realPathp[nameLength] = 0;
5634 if (smb_StoreAnsiFilenames)
5635 OemToChar(realPathp,realPathp);
5637 spacep = inp->spacep;
5638 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5640 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
5641 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
5642 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
5644 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5645 /* special case magic file name for receiving IOCTL requests
5646 * (since IOCTL calls themselves aren't getting through).
5648 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5649 smb_SetupIoctlFid(fidp, spacep);
5650 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
5652 /* set inp->fid so that later read calls in same msg can find fid */
5653 inp->fid = fidp->fid;
5657 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5658 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5659 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
5661 memset(&ft, 0, sizeof(ft));
5662 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5663 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5664 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5665 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5666 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
5667 sz.HighPart = 0x7fff; sz.LowPart = 0;
5668 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
5669 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
5670 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
5671 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
5672 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
5673 smb_SetSMBDataLength(outp, 0);
5675 /* clean up fid reference */
5676 smb_ReleaseFID(fidp);
5681 #ifdef DEBUG_VERBOSE
5683 char *hexp, *asciip;
5684 asciip = (lastNamep? lastNamep : realPathp);
5685 hexp = osi_HexifyString( asciip );
5686 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
5691 userp = smb_GetUserFromVCP(vcp, inp);
5693 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
5695 return CM_ERROR_INVAL;
5700 baseDirp = cm_data.rootSCachep;
5701 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5702 if (code == CM_ERROR_TIDIPC) {
5703 /* Attempt to use a TID allocated for IPC. The client
5704 * is probably looking for DCE RPC end points which we
5705 * don't support OR it could be looking to make a DFS
5708 osi_Log0(smb_logp, "NTCreateX received IPC TID");
5711 cm_ReleaseUser(userp);
5712 return CM_ERROR_NOSUCHFILE;
5713 #endif /* DFS_SUPPORT */
5716 baseFidp = smb_FindFID(vcp, baseFid, 0);
5718 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
5720 cm_ReleaseUser(userp);
5721 return CM_ERROR_INVAL;
5723 baseDirp = baseFidp->scp;
5727 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
5729 /* compute open mode */
5731 if (desiredAccess & DELETE)
5732 fidflags |= SMB_FID_OPENDELETE;
5733 if (desiredAccess & AFS_ACCESS_READ)
5734 fidflags |= SMB_FID_OPENREAD;
5735 if (desiredAccess & AFS_ACCESS_WRITE)
5736 fidflags |= SMB_FID_OPENWRITE;
5737 if (createOptions & FILE_DELETE_ON_CLOSE)
5738 fidflags |= SMB_FID_DELONCLOSE;
5740 /* and the share mode */
5741 if (shareAccess & FILE_SHARE_READ)
5742 fidflags |= SMB_FID_SHARE_READ;
5743 if (shareAccess & FILE_SHARE_WRITE)
5744 fidflags |= SMB_FID_SHARE_WRITE;
5746 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
5749 /* For an exclusive create, we want to do a case sensitive match for the last component. */
5750 if ( createDisp == FILE_CREATE ||
5751 createDisp == FILE_OVERWRITE ||
5752 createDisp == FILE_OVERWRITE_IF) {
5753 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5754 userp, tidPathp, &req, &dscp);
5757 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5758 cm_ReleaseSCache(dscp);
5759 cm_ReleaseUser(userp);
5762 smb_ReleaseFID(baseFidp);
5763 if ( WANTS_DFS_PATHNAMES(inp) )
5764 return CM_ERROR_PATH_NOT_COVERED;
5766 return CM_ERROR_BADSHARENAME;
5768 #endif /* DFS_SUPPORT */
5769 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5771 if (code == CM_ERROR_NOSUCHFILE) {
5772 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
5773 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
5774 if (code == 0 && realDirFlag == 1) {
5775 cm_ReleaseSCache(scp);
5776 cm_ReleaseSCache(dscp);
5777 cm_ReleaseUser(userp);
5780 smb_ReleaseFID(baseFidp);
5781 return CM_ERROR_EXISTS;
5785 /* we have both scp and dscp */
5787 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5788 userp, tidPathp, &req, &scp);
5790 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5791 cm_ReleaseSCache(scp);
5792 cm_ReleaseUser(userp);
5795 smb_ReleaseFID(baseFidp);
5796 if ( WANTS_DFS_PATHNAMES(inp) )
5797 return CM_ERROR_PATH_NOT_COVERED;
5799 return CM_ERROR_BADSHARENAME;
5801 #endif /* DFS_SUPPORT */
5802 /* we might have scp but not dscp */
5808 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
5809 /* look up parent directory */
5810 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
5811 * the immediate parent. We have to work our way up realPathp until we hit something that we
5815 /* we might or might not have scp */
5821 code = cm_NameI(baseDirp, spacep->data,
5822 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5823 userp, tidPathp, &req, &dscp);
5826 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5828 cm_ReleaseSCache(scp);
5829 cm_ReleaseSCache(dscp);
5830 cm_ReleaseUser(userp);
5833 smb_ReleaseFID(baseFidp);
5834 if ( WANTS_DFS_PATHNAMES(inp) )
5835 return CM_ERROR_PATH_NOT_COVERED;
5837 return CM_ERROR_BADSHARENAME;
5839 #endif /* DFS_SUPPORT */
5842 (tp = strrchr(spacep->data,'\\')) &&
5843 (createDisp == FILE_CREATE) &&
5844 (realDirFlag == 1)) {
5847 treeStartp = realPathp + (tp - spacep->data);
5849 if (*tp && !smb_IsLegalFilename(tp)) {
5851 smb_ReleaseFID(baseFidp);
5852 cm_ReleaseUser(userp);
5855 cm_ReleaseSCache(scp);
5856 return CM_ERROR_BADNTFILENAME;
5860 } while (dscp == NULL && code == 0);
5864 /* we might have scp and we might have dscp */
5867 smb_ReleaseFID(baseFidp);
5870 osi_Log0(smb_logp,"NTCreateX parent not found");
5872 cm_ReleaseSCache(scp);
5874 cm_ReleaseSCache(dscp);
5875 cm_ReleaseUser(userp);
5880 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
5881 /* A file exists where we want a directory. */
5883 cm_ReleaseSCache(scp);
5884 cm_ReleaseSCache(dscp);
5885 cm_ReleaseUser(userp);
5887 return CM_ERROR_EXISTS;
5891 lastNamep = realPathp;
5895 if (!smb_IsLegalFilename(lastNamep)) {
5897 cm_ReleaseSCache(scp);
5899 cm_ReleaseSCache(dscp);
5900 cm_ReleaseUser(userp);
5902 return CM_ERROR_BADNTFILENAME;
5905 if (!foundscp && !treeCreate) {
5906 if ( createDisp == FILE_CREATE ||
5907 createDisp == FILE_OVERWRITE ||
5908 createDisp == FILE_OVERWRITE_IF)
5910 code = cm_Lookup(dscp, lastNamep,
5911 CM_FLAG_FOLLOW, userp, &req, &scp);
5913 code = cm_Lookup(dscp, lastNamep,
5914 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5917 if (code && code != CM_ERROR_NOSUCHFILE) {
5919 cm_ReleaseSCache(dscp);
5920 cm_ReleaseUser(userp);
5925 /* we have scp and dscp */
5927 /* we have scp but not dscp */
5929 smb_ReleaseFID(baseFidp);
5932 /* if we get here, if code is 0, the file exists and is represented by
5933 * scp. Otherwise, we have to create it. The dir may be represented
5934 * by dscp, or we may have found the file directly. If code is non-zero,
5937 if (code == 0 && !treeCreate) {
5938 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req);
5941 cm_ReleaseSCache(dscp);
5943 cm_ReleaseSCache(scp);
5944 cm_ReleaseUser(userp);
5949 if (createDisp == FILE_CREATE) {
5950 /* oops, file shouldn't be there */
5952 cm_ReleaseSCache(dscp);
5954 cm_ReleaseSCache(scp);
5955 cm_ReleaseUser(userp);
5957 return CM_ERROR_EXISTS;
5960 if ( createDisp == FILE_OVERWRITE ||
5961 createDisp == FILE_OVERWRITE_IF) {
5963 setAttr.mask = CM_ATTRMASK_LENGTH;
5964 setAttr.length.LowPart = 0;
5965 setAttr.length.HighPart = 0;
5966 /* now watch for a symlink */
5968 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5970 osi_assert(dscp != NULL);
5971 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5973 /* we have a more accurate file to use (the
5974 * target of the symbolic link). Otherwise,
5975 * we'll just use the symlink anyway.
5977 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5979 cm_ReleaseSCache(scp);
5983 code = cm_SetAttr(scp, &setAttr, userp, &req);
5984 openAction = 3; /* truncated existing file */
5987 openAction = 1; /* found existing file */
5989 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
5990 /* don't create if not found */
5992 cm_ReleaseSCache(dscp);
5994 cm_ReleaseSCache(scp);
5995 cm_ReleaseUser(userp);
5997 return CM_ERROR_NOSUCHFILE;
5998 } else if (realDirFlag == 0 || realDirFlag == -1) {
5999 osi_assert(dscp != NULL);
6000 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
6001 osi_LogSaveString(smb_logp, lastNamep));
6002 openAction = 2; /* created file */
6003 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6004 setAttr.clientModTime = time(NULL);
6005 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
6008 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6009 smb_NotifyChange(FILE_ACTION_ADDED,
6010 FILE_NOTIFY_CHANGE_FILE_NAME,
6011 dscp, lastNamep, NULL, TRUE);
6012 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6013 /* Not an exclusive create, and someone else tried
6014 * creating it already, then we open it anyway. We
6015 * don't bother retrying after this, since if this next
6016 * fails, that means that the file was deleted after we
6017 * started this call.
6019 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6022 if (createDisp == FILE_OVERWRITE_IF) {
6023 setAttr.mask = CM_ATTRMASK_LENGTH;
6024 setAttr.length.LowPart = 0;
6025 setAttr.length.HighPart = 0;
6027 /* now watch for a symlink */
6029 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6031 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6033 /* we have a more accurate file to use (the
6034 * target of the symbolic link). Otherwise,
6035 * we'll just use the symlink anyway.
6037 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6039 cm_ReleaseSCache(scp);
6043 code = cm_SetAttr(scp, &setAttr, userp, &req);
6045 } /* lookup succeeded */
6049 char *cp; /* This component */
6050 int clen = 0; /* length of component */
6051 cm_scache_t *tscp1, *tscp2;
6054 /* create directory */
6056 treeStartp = lastNamep;
6057 osi_assert(dscp != NULL);
6058 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
6059 osi_LogSaveString(smb_logp, treeStartp));
6060 openAction = 2; /* created directory */
6062 /* if the request is to create the root directory
6063 * it will appear as a directory name of the nul-string
6064 * and a code of CM_ERROR_NOSUCHFILE
6066 if ( !*treeStartp && code == CM_ERROR_NOSUCHFILE)
6067 code = CM_ERROR_EXISTS;
6069 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6070 setAttr.clientModTime = time(NULL);
6075 cm_HoldSCache(tscp1);
6079 tp = strchr(pp, '\\');
6082 clen = (int)strlen(cp);
6083 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
6085 clen = (int)(tp - pp);
6086 strncpy(cp,pp,clen);
6093 continue; /* the supplied path can't have consecutive slashes either , but */
6095 /* cp is the next component to be created. */
6096 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
6097 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
6098 smb_NotifyChange(FILE_ACTION_ADDED,
6099 FILE_NOTIFY_CHANGE_DIR_NAME,
6100 tscp1, cp, NULL, TRUE);
6102 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6103 /* Not an exclusive create, and someone else tried
6104 * creating it already, then we open it anyway. We
6105 * don't bother retrying after this, since if this next
6106 * fails, that means that the file was deleted after we
6107 * started this call.
6109 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
6110 userp, &req, &tscp2);
6115 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
6116 cm_ReleaseSCache(tscp1);
6117 tscp1 = tscp2; /* Newly created directory will be next parent */
6118 /* the hold is transfered to tscp1 from tscp2 */
6123 cm_ReleaseSCache(dscp);
6126 cm_ReleaseSCache(scp);
6129 * if we get here and code == 0, then scp is the last directory created, and dscp is the
6135 /* something went wrong creating or truncating the file */
6137 cm_ReleaseSCache(scp);
6139 cm_ReleaseSCache(dscp);
6140 cm_ReleaseUser(userp);
6145 /* make sure we have file vs. dir right (only applies for single component case) */
6146 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
6147 /* now watch for a symlink */
6149 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6150 cm_scache_t * targetScp = 0;
6151 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6153 /* we have a more accurate file to use (the
6154 * target of the symbolic link). Otherwise,
6155 * we'll just use the symlink anyway.
6157 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
6158 cm_ReleaseSCache(scp);
6163 if (scp->fileType != CM_SCACHETYPE_FILE) {
6165 cm_ReleaseSCache(dscp);
6166 cm_ReleaseSCache(scp);
6167 cm_ReleaseUser(userp);
6169 return CM_ERROR_ISDIR;
6173 /* (only applies to single component case) */
6174 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
6175 cm_ReleaseSCache(scp);
6177 cm_ReleaseSCache(dscp);
6178 cm_ReleaseUser(userp);
6180 return CM_ERROR_NOTDIR;
6183 /* open the file itself */
6184 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6187 /* save a reference to the user */
6189 fidp->userp = userp;
6191 /* If we are restricting sharing, we should do so with a suitable
6193 if (scp->fileType == CM_SCACHETYPE_FILE &&
6194 !(fidflags & SMB_FID_SHARE_WRITE)) {
6196 LARGE_INTEGER LOffset, LLength;
6199 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
6200 LOffset.LowPart = SMB_FID_QLOCK_LOW;
6201 LLength.HighPart = 0;
6202 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
6204 if (fidflags & SMB_FID_SHARE_READ) {
6205 sLockType = LOCKING_ANDX_SHARED_LOCK;
6210 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
6212 lock_ObtainMutex(&scp->mx);
6213 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
6214 lock_ReleaseMutex(&scp->mx);
6217 /* shouldn't this be smb_CloseFID() fidp->flags = SMB_FID_DELETE; */
6218 smb_CloseFID(vcp, fidp, NULL, 0);
6219 smb_ReleaseFID(fidp);
6221 cm_ReleaseSCache(scp);
6223 cm_ReleaseSCache(dscp);
6224 cm_ReleaseUser(userp);
6231 lock_ObtainMutex(&fidp->mx);
6232 /* save a pointer to the vnode */
6233 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
6235 fidp->flags = fidflags;
6237 /* remember if the file was newly created */
6239 fidp->flags |= SMB_FID_CREATED;
6241 /* save parent dir and pathname for delete or change notification */
6242 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
6243 fidp->flags |= SMB_FID_NTOPEN;
6244 fidp->NTopen_dscp = dscp;
6245 cm_HoldSCache(dscp);
6246 fidp->NTopen_pathp = strdup(lastNamep);
6248 fidp->NTopen_wholepathp = realPathp;
6249 lock_ReleaseMutex(&fidp->mx);
6251 /* we don't need this any longer */
6253 cm_ReleaseSCache(dscp);
6257 cm_Open(scp, 0, userp);
6259 /* set inp->fid so that later read calls in same msg can find fid */
6260 inp->fid = fidp->fid;
6264 lock_ObtainMutex(&scp->mx);
6265 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6266 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6267 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
6268 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6269 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6270 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6271 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6272 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6273 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
6275 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6276 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6277 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6278 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6279 smb_SetSMBParmByte(outp, parmSlot,
6280 (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
6281 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
6282 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
6283 lock_ReleaseMutex(&scp->mx);
6284 smb_SetSMBDataLength(outp, 0);
6286 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
6287 osi_LogSaveString(smb_logp, realPathp));
6289 smb_ReleaseFID(fidp);
6291 cm_ReleaseUser(userp);
6293 /* Can't free realPathp if we get here since
6294 fidp->NTopen_wholepathp is pointing there */
6296 /* leave scp held since we put it in fidp->scp */
6301 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
6302 * Instead, ultimately, would like to use a subroutine for common code.
6304 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6306 char *pathp, *realPathp;
6310 cm_scache_t *dscp; /* parent dir */
6311 cm_scache_t *scp; /* file to create or open */
6312 cm_scache_t *targetScp; /* if scp is a symlink */
6315 unsigned long nameLength;
6317 unsigned int requestOpLock;
6318 unsigned int requestBatchOpLock;
6319 unsigned int mustBeDir;
6320 unsigned int extendedRespRequired;
6322 unsigned int desiredAccess;
6323 #ifdef DEBUG_VERBOSE
6324 unsigned int allocSize;
6326 unsigned int shareAccess;
6327 unsigned int extAttributes;
6328 unsigned int createDisp;
6329 #ifdef DEBUG_VERBOSE
6332 unsigned int createOptions;
6333 int initialModeBits;
6334 unsigned short baseFid;
6335 smb_fid_t *baseFidp;
6337 cm_scache_t *baseDirp;
6338 unsigned short openAction;
6344 int parmOffset, dataOffset;
6356 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6357 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6358 parmp = inp->data + parmOffset;
6359 lparmp = (ULONG *) parmp;
6362 requestOpLock = flags & REQUEST_OPLOCK;
6363 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6364 mustBeDir = flags & OPEN_DIRECTORY;
6365 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6368 * Why all of a sudden 32-bit FID?
6369 * We will reject all bits higher than 16.
6371 if (lparmp[1] & 0xFFFF0000)
6372 return CM_ERROR_INVAL;
6373 baseFid = (unsigned short)lparmp[1];
6374 desiredAccess = lparmp[2];
6375 #ifdef DEBUG_VERBOSE
6376 allocSize = lparmp[3];
6377 #endif /* DEBUG_VERSOSE */
6378 extAttributes = lparmp[5];
6379 shareAccess = lparmp[6];
6380 createDisp = lparmp[7];
6381 createOptions = lparmp[8];
6382 #ifdef DEBUG_VERBOSE
6385 nameLength = lparmp[11];
6387 #ifdef DEBUG_VERBOSE
6388 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
6389 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
6390 osi_Log1(smb_logp,"... flags[%x]",flags);
6393 /* mustBeDir is never set; createOptions directory bit seems to be
6396 if (createOptions & FILE_DIRECTORY_FILE)
6398 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6404 * compute initial mode bits based on read-only flag in
6405 * extended attributes
6407 initialModeBits = 0666;
6408 if (extAttributes & 1)
6409 initialModeBits &= ~0222;
6411 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
6412 /* Sometimes path is not null-terminated, so we make a copy. */
6413 realPathp = malloc(nameLength+1);
6414 memcpy(realPathp, pathp, nameLength);
6415 realPathp[nameLength] = 0;
6416 if (smb_StoreAnsiFilenames)
6417 OemToChar(realPathp,realPathp);
6419 spacep = cm_GetSpace();
6420 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6423 * Nothing here to handle SMB_IOCTL_FILENAME.
6424 * Will add it if necessary.
6427 #ifdef DEBUG_VERBOSE
6429 char *hexp, *asciip;
6430 asciip = (lastNamep? lastNamep : realPathp);
6431 hexp = osi_HexifyString( asciip );
6432 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
6437 userp = smb_GetUserFromVCP(vcp, inp);
6439 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
6441 return CM_ERROR_INVAL;
6446 baseDirp = cm_data.rootSCachep;
6447 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6448 if (code == CM_ERROR_TIDIPC) {
6449 /* Attempt to use a TID allocated for IPC. The client
6450 * is probably looking for DCE RPC end points which we
6451 * don't support OR it could be looking to make a DFS
6454 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
6457 cm_ReleaseUser(userp);
6458 return CM_ERROR_NOSUCHPATH;
6462 baseFidp = smb_FindFID(vcp, baseFid, 0);
6464 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
6466 cm_ReleaseUser(userp);
6467 return CM_ERROR_INVAL;
6469 baseDirp = baseFidp->scp;
6473 /* compute open mode */
6475 if (desiredAccess & DELETE)
6476 fidflags |= SMB_FID_OPENDELETE;
6477 if (desiredAccess & AFS_ACCESS_READ)
6478 fidflags |= SMB_FID_OPENREAD;
6479 if (desiredAccess & AFS_ACCESS_WRITE)
6480 fidflags |= SMB_FID_OPENWRITE;
6481 if (createOptions & FILE_DELETE_ON_CLOSE)
6482 fidflags |= SMB_FID_DELONCLOSE;
6484 /* And the share mode */
6485 if (shareAccess & FILE_SHARE_READ)
6486 fidflags |= SMB_FID_SHARE_READ;
6487 if (shareAccess & FILE_SHARE_WRITE)
6488 fidflags |= SMB_FID_SHARE_WRITE;
6492 if ( createDisp == FILE_OPEN ||
6493 createDisp == FILE_OVERWRITE ||
6494 createDisp == FILE_OVERWRITE_IF) {
6495 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6496 userp, tidPathp, &req, &dscp);
6499 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6500 cm_ReleaseSCache(dscp);
6501 cm_ReleaseUser(userp);
6504 smb_ReleaseFID(baseFidp);
6505 if ( WANTS_DFS_PATHNAMES(inp) )
6506 return CM_ERROR_PATH_NOT_COVERED;
6508 return CM_ERROR_BADSHARENAME;
6510 #endif /* DFS_SUPPORT */
6511 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6513 if (code == CM_ERROR_NOSUCHFILE) {
6514 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6515 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6516 if (code == 0 && realDirFlag == 1) {
6517 cm_ReleaseSCache(scp);
6518 cm_ReleaseSCache(dscp);
6519 cm_ReleaseUser(userp);
6522 smb_ReleaseFID(baseFidp);
6523 return CM_ERROR_EXISTS;
6529 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6530 userp, tidPathp, &req, &scp);
6532 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6533 cm_ReleaseSCache(scp);
6534 cm_ReleaseUser(userp);
6537 smb_ReleaseFID(baseFidp);
6538 if ( WANTS_DFS_PATHNAMES(inp) )
6539 return CM_ERROR_PATH_NOT_COVERED;
6541 return CM_ERROR_BADSHARENAME;
6543 #endif /* DFS_SUPPORT */
6549 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6550 /* look up parent directory */
6552 code = cm_NameI(baseDirp, spacep->data,
6553 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6554 userp, tidPathp, &req, &dscp);
6556 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6557 cm_ReleaseSCache(dscp);
6558 cm_ReleaseUser(userp);
6561 smb_ReleaseFID(baseFidp);
6562 if ( WANTS_DFS_PATHNAMES(inp) )
6563 return CM_ERROR_PATH_NOT_COVERED;
6565 return CM_ERROR_BADSHARENAME;
6567 #endif /* DFS_SUPPORT */
6571 cm_FreeSpace(spacep);
6574 smb_ReleaseFID(baseFidp);
6577 cm_ReleaseUser(userp);
6583 lastNamep = realPathp;
6587 if (!smb_IsLegalFilename(lastNamep))
6588 return CM_ERROR_BADNTFILENAME;
6591 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
6592 code = cm_Lookup(dscp, lastNamep,
6593 CM_FLAG_FOLLOW, userp, &req, &scp);
6595 code = cm_Lookup(dscp, lastNamep,
6596 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6599 if (code && code != CM_ERROR_NOSUCHFILE) {
6600 cm_ReleaseSCache(dscp);
6601 cm_ReleaseUser(userp);
6608 smb_ReleaseFID(baseFidp);
6609 cm_FreeSpace(spacep);
6612 /* if we get here, if code is 0, the file exists and is represented by
6613 * scp. Otherwise, we have to create it. The dir may be represented
6614 * by dscp, or we may have found the file directly. If code is non-zero,
6618 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
6622 cm_ReleaseSCache(dscp);
6623 cm_ReleaseSCache(scp);
6624 cm_ReleaseUser(userp);
6629 if (createDisp == FILE_CREATE) {
6630 /* oops, file shouldn't be there */
6632 cm_ReleaseSCache(dscp);
6633 cm_ReleaseSCache(scp);
6634 cm_ReleaseUser(userp);
6636 return CM_ERROR_EXISTS;
6639 if (createDisp == FILE_OVERWRITE ||
6640 createDisp == FILE_OVERWRITE_IF) {
6641 setAttr.mask = CM_ATTRMASK_LENGTH;
6642 setAttr.length.LowPart = 0;
6643 setAttr.length.HighPart = 0;
6645 /* now watch for a symlink */
6647 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6649 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6651 /* we have a more accurate file to use (the
6652 * target of the symbolic link). Otherwise,
6653 * we'll just use the symlink anyway.
6655 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6657 cm_ReleaseSCache(scp);
6661 code = cm_SetAttr(scp, &setAttr, userp, &req);
6662 openAction = 3; /* truncated existing file */
6664 else openAction = 1; /* found existing file */
6666 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6667 /* don't create if not found */
6669 cm_ReleaseSCache(dscp);
6670 cm_ReleaseUser(userp);
6672 return CM_ERROR_NOSUCHFILE;
6674 else if (realDirFlag == 0 || realDirFlag == -1) {
6675 osi_assert(dscp != NULL);
6676 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
6677 osi_LogSaveString(smb_logp, lastNamep));
6678 openAction = 2; /* created file */
6679 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6680 setAttr.clientModTime = time(NULL);
6681 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6685 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6686 smb_NotifyChange(FILE_ACTION_ADDED,
6687 FILE_NOTIFY_CHANGE_FILE_NAME,
6688 dscp, lastNamep, NULL, TRUE);
6689 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6690 /* Not an exclusive create, and someone else tried
6691 * creating it already, then we open it anyway. We
6692 * don't bother retrying after this, since if this next
6693 * fails, that means that the file was deleted after we
6694 * started this call.
6696 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6699 if (createDisp == FILE_OVERWRITE_IF) {
6700 setAttr.mask = CM_ATTRMASK_LENGTH;
6701 setAttr.length.LowPart = 0;
6702 setAttr.length.HighPart = 0;
6704 /* now watch for a symlink */
6706 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6708 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6710 /* we have a more accurate file to use (the
6711 * target of the symbolic link). Otherwise,
6712 * we'll just use the symlink anyway.
6714 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6716 cm_ReleaseSCache(scp);
6720 code = cm_SetAttr(scp, &setAttr, userp, &req);
6722 } /* lookup succeeded */
6725 /* create directory */
6726 osi_assert(dscp != NULL);
6728 "smb_ReceiveNTTranCreate creating directory %s",
6729 osi_LogSaveString(smb_logp, lastNamep));
6730 openAction = 2; /* created directory */
6731 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6732 setAttr.clientModTime = time(NULL);
6733 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6734 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6735 smb_NotifyChange(FILE_ACTION_ADDED,
6736 FILE_NOTIFY_CHANGE_DIR_NAME,
6737 dscp, lastNamep, NULL, TRUE);
6739 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6740 /* Not an exclusive create, and someone else tried
6741 * creating it already, then we open it anyway. We
6742 * don't bother retrying after this, since if this next
6743 * fails, that means that the file was deleted after we
6744 * started this call.
6746 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6752 /* something went wrong creating or truncating the file */
6754 cm_ReleaseSCache(scp);
6755 cm_ReleaseUser(userp);
6760 /* make sure we have file vs. dir right */
6761 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
6762 /* now watch for a symlink */
6764 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6766 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6768 /* we have a more accurate file to use (the
6769 * target of the symbolic link). Otherwise,
6770 * we'll just use the symlink anyway.
6772 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6774 cm_ReleaseSCache(scp);
6779 if (scp->fileType != CM_SCACHETYPE_FILE) {
6780 cm_ReleaseSCache(scp);
6781 cm_ReleaseUser(userp);
6783 return CM_ERROR_ISDIR;
6787 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
6788 cm_ReleaseSCache(scp);
6789 cm_ReleaseUser(userp);
6791 return CM_ERROR_NOTDIR;
6794 /* open the file itself */
6795 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6798 /* save a reference to the user */
6800 fidp->userp = userp;
6802 /* If we are restricting sharing, we should do so with a suitable
6804 if (scp->fileType == CM_SCACHETYPE_FILE &&
6805 !(fidflags & SMB_FID_SHARE_WRITE)) {
6807 LARGE_INTEGER LOffset, LLength;
6810 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
6811 LOffset.LowPart = SMB_FID_QLOCK_LOW;
6812 LLength.HighPart = 0;
6813 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
6815 if (fidflags & SMB_FID_SHARE_READ) {
6816 sLockType = LOCKING_ANDX_SHARED_LOCK;
6821 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
6823 lock_ObtainMutex(&scp->mx);
6824 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
6825 lock_ReleaseMutex(&scp->mx);
6828 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
6829 smb_CloseFID(vcp, fidp, NULL, 0);
6830 smb_ReleaseFID(fidp);
6832 cm_ReleaseSCache(scp);
6833 cm_ReleaseUser(userp);
6836 return CM_ERROR_SHARING_VIOLATION;
6840 lock_ObtainMutex(&fidp->mx);
6841 /* save a pointer to the vnode */
6844 fidp->flags = fidflags;
6846 /* remember if the file was newly created */
6848 fidp->flags |= SMB_FID_CREATED;
6850 /* save parent dir and pathname for deletion or change notification */
6851 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
6852 fidp->flags |= SMB_FID_NTOPEN;
6853 fidp->NTopen_dscp = dscp;
6854 cm_HoldSCache(dscp);
6855 fidp->NTopen_pathp = strdup(lastNamep);
6857 fidp->NTopen_wholepathp = realPathp;
6858 lock_ReleaseMutex(&fidp->mx);
6860 /* we don't need this any longer */
6862 cm_ReleaseSCache(dscp);
6864 cm_Open(scp, 0, userp);
6866 /* set inp->fid so that later read calls in same msg can find fid */
6867 inp->fid = fidp->fid;
6869 /* check whether we are required to send an extended response */
6870 if (!extendedRespRequired) {
6872 parmOffset = 8*4 + 39;
6873 parmOffset += 1; /* pad to 4 */
6874 dataOffset = parmOffset + 70;
6878 /* Total Parameter Count */
6879 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
6880 /* Total Data Count */
6881 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6882 /* Parameter Count */
6883 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
6884 /* Parameter Offset */
6885 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6886 /* Parameter Displacement */
6887 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6889 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6891 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6892 /* Data Displacement */
6893 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6894 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6895 smb_SetSMBDataLength(outp, 70);
6897 lock_ObtainMutex(&scp->mx);
6898 outData = smb_GetSMBData(outp, NULL);
6899 outData++; /* round to get to parmOffset */
6900 *outData = 0; outData++; /* oplock */
6901 *outData = 0; outData++; /* reserved */
6902 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
6903 *((ULONG *)outData) = openAction; outData += 4;
6904 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
6905 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6906 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
6907 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
6908 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
6909 *((FILETIME *)outData) = ft; outData += 8; /* change time */
6910 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
6911 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
6912 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
6913 *((USHORT *)outData) = 0; outData += 2; /* filetype */
6914 *((USHORT *)outData) = 0; outData += 2; /* dev state */
6915 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
6916 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
6917 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
6918 outData += 2; /* is a dir? */
6919 lock_ReleaseMutex(&scp->mx);
6922 parmOffset = 8*4 + 39;
6923 parmOffset += 1; /* pad to 4 */
6924 dataOffset = parmOffset + 104;
6928 /* Total Parameter Count */
6929 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
6930 /* Total Data Count */
6931 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6932 /* Parameter Count */
6933 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
6934 /* Parameter Offset */
6935 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6936 /* Parameter Displacement */
6937 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6939 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6941 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6942 /* Data Displacement */
6943 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6944 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6945 smb_SetSMBDataLength(outp, 105);
6947 lock_ObtainMutex(&scp->mx);
6948 outData = smb_GetSMBData(outp, NULL);
6949 outData++; /* round to get to parmOffset */
6950 *outData = 0; outData++; /* oplock */
6951 *outData = 1; outData++; /* response type */
6952 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
6953 *((ULONG *)outData) = openAction; outData += 4;
6954 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
6955 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6956 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
6957 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
6958 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
6959 *((FILETIME *)outData) = ft; outData += 8; /* change time */
6960 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
6961 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
6962 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
6963 *((USHORT *)outData) = 0; outData += 2; /* filetype */
6964 *((USHORT *)outData) = 0; outData += 2; /* dev state */
6965 *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
6966 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
6967 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
6968 outData += 1; /* is a dir? */
6969 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
6970 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
6971 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
6972 lock_ReleaseMutex(&scp->mx);
6975 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
6977 smb_ReleaseFID(fidp);
6979 cm_ReleaseUser(userp);
6981 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
6982 /* leave scp held since we put it in fidp->scp */
6986 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
6989 smb_packet_t *savedPacketp;
6990 ULONG filter; USHORT fid, watchtree;
6994 filter = smb_GetSMBParm(inp, 19) |
6995 (smb_GetSMBParm(inp, 20) << 16);
6996 fid = smb_GetSMBParm(inp, 21);
6997 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
6999 fidp = smb_FindFID(vcp, fid, 0);
7001 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
7002 return CM_ERROR_BADFD;
7005 savedPacketp = smb_CopyPacket(inp);
7007 if (savedPacketp->vcp)
7008 smb_ReleaseVC(savedPacketp->vcp);
7009 savedPacketp->vcp = vcp;
7010 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7011 savedPacketp->nextp = smb_Directory_Watches;
7012 smb_Directory_Watches = savedPacketp;
7013 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7015 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
7016 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
7019 lock_ObtainMutex(&scp->mx);
7021 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
7023 scp->flags |= CM_SCACHEFLAG_WATCHED;
7024 lock_ReleaseMutex(&scp->mx);
7025 smb_ReleaseFID(fidp);
7027 outp->flags |= SMB_PACKETFLAG_NOSEND;
7031 unsigned char nullSecurityDesc[36] = {
7032 0x01, /* security descriptor revision */
7033 0x00, /* reserved, should be zero */
7034 0x00, 0x80, /* security descriptor control;
7035 * 0x8000 : self-relative format */
7036 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
7037 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
7038 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
7039 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
7040 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7041 /* "null SID" owner SID */
7042 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
7043 /* "null SID" group SID */
7046 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7048 int parmOffset, parmCount, dataOffset, dataCount;
7056 ULONG securityInformation;
7058 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7059 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7060 parmp = inp->data + parmOffset;
7061 sparmp = (USHORT *) parmp;
7062 lparmp = (ULONG *) parmp;
7065 securityInformation = lparmp[1];
7067 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
7068 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
7076 parmOffset = 8*4 + 39;
7077 parmOffset += 1; /* pad to 4 */
7079 dataOffset = parmOffset + parmCount;
7083 /* Total Parameter Count */
7084 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
7085 /* Total Data Count */
7086 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
7087 /* Parameter Count */
7088 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
7089 /* Parameter Offset */
7090 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7091 /* Parameter Displacement */
7092 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7094 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
7096 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7097 /* Data Displacement */
7098 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7099 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
7100 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
7102 outData = smb_GetSMBData(outp, NULL);
7103 outData++; /* round to get to parmOffset */
7104 *((ULONG *)outData) = 36; outData += 4; /* length */
7106 if (maxData >= 36) {
7107 memcpy(outData, nullSecurityDesc, 36);
7111 return CM_ERROR_BUFFERTOOSMALL;
7114 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7116 unsigned short function;
7118 function = smb_GetSMBParm(inp, 18);
7120 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
7122 /* We can handle long names */
7123 if (vcp->flags & SMB_VCFLAG_USENT)
7124 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
7128 return smb_ReceiveNTTranCreate(vcp, inp, outp);
7130 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
7133 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
7136 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
7138 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
7141 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
7143 return CM_ERROR_INVAL;
7147 * smb_NotifyChange -- find relevant change notification messages and
7150 * If we don't know the file name (i.e. a callback break), filename is
7151 * NULL, and we return a zero-length list.
7153 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
7154 cm_scache_t *dscp, char *filename, char *otherFilename,
7155 BOOL isDirectParent)
7157 smb_packet_t *watch, *lastWatch, *nextWatch;
7158 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
7159 char *outData, *oldOutData;
7163 BOOL twoEntries = FALSE;
7164 ULONG otherNameLen, oldParmCount = 0;
7168 /* Get ready for rename within directory */
7169 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
7171 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
7174 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
7175 osi_LogSaveString(smb_logp,filename),dscp);
7177 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7178 watch = smb_Directory_Watches;
7180 filter = smb_GetSMBParm(watch, 19)
7181 | (smb_GetSMBParm(watch, 20) << 16);
7182 fid = smb_GetSMBParm(watch, 21);
7183 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
7184 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
7185 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
7188 * Strange hack - bug in NT Client and NT Server that we
7191 if (filter == 3 && wtree)
7194 fidp = smb_FindFID(watch->vcp, fid, 0);
7196 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
7198 watch = watch->nextp;
7201 if (fidp->scp != dscp
7202 || (filter & notifyFilter) == 0
7203 || (!isDirectParent && !wtree)) {
7204 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
7205 smb_ReleaseFID(fidp);
7207 watch = watch->nextp;
7210 smb_ReleaseFID(fidp);
7213 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
7214 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
7216 nextWatch = watch->nextp;
7217 if (watch == smb_Directory_Watches)
7218 smb_Directory_Watches = nextWatch;
7220 lastWatch->nextp = nextWatch;
7222 /* Turn off WATCHED flag in dscp */
7223 lock_ObtainMutex(&dscp->mx);
7225 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
7227 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
7228 lock_ReleaseMutex(&dscp->mx);
7230 /* Convert to response packet */
7231 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
7232 ((smb_t *) watch)->wct = 0;
7235 if (filename == NULL)
7238 nameLen = (ULONG)strlen(filename);
7239 parmCount = 3*4 + nameLen*2;
7240 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
7242 otherNameLen = (ULONG)strlen(otherFilename);
7243 oldParmCount = parmCount;
7244 parmCount += 3*4 + otherNameLen*2;
7245 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
7247 if (maxLen < parmCount)
7248 parmCount = 0; /* not enough room */
7250 parmOffset = 8*4 + 39;
7251 parmOffset += 1; /* pad to 4 */
7252 dataOffset = parmOffset + parmCount;
7256 /* Total Parameter Count */
7257 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
7258 /* Total Data Count */
7259 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7260 /* Parameter Count */
7261 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
7262 /* Parameter Offset */
7263 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
7264 /* Parameter Displacement */
7265 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7267 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7269 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
7270 /* Data Displacement */
7271 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7272 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
7273 smb_SetSMBDataLength(watch, parmCount + 1);
7275 if (parmCount != 0) {
7277 outData = smb_GetSMBData(watch, NULL);
7278 outData++; /* round to get to parmOffset */
7279 oldOutData = outData;
7280 *((DWORD *)outData) = oldParmCount; outData += 4;
7281 /* Next Entry Offset */
7282 *((DWORD *)outData) = action; outData += 4;
7284 *((DWORD *)outData) = nameLen*2; outData += 4;
7285 /* File Name Length */
7286 p = strdup(filename);
7287 if (smb_StoreAnsiFilenames)
7289 mbstowcs((WCHAR *)outData, p, nameLen);
7293 outData = oldOutData + oldParmCount;
7294 *((DWORD *)outData) = 0; outData += 4;
7295 /* Next Entry Offset */
7296 *((DWORD *)outData) = otherAction; outData += 4;
7298 *((DWORD *)outData) = otherNameLen*2;
7299 outData += 4; /* File Name Length */
7300 p = strdup(otherFilename);
7301 if (smb_StoreAnsiFilenames)
7303 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
7309 * If filename is null, we don't know the cause of the
7310 * change notification. We return zero data (see above),
7311 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
7312 * (= 0x010C). We set the error code here by hand, without
7313 * modifying wct and bcc.
7315 if (filename == NULL) {
7316 ((smb_t *) watch)->rcls = 0x0C;
7317 ((smb_t *) watch)->reh = 0x01;
7318 ((smb_t *) watch)->errLow = 0;
7319 ((smb_t *) watch)->errHigh = 0;
7320 /* Set NT Status codes flag */
7321 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7324 smb_SendPacket(watch->vcp, watch);
7325 smb_FreePacket(watch);
7328 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7331 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7333 unsigned char *replyWctp;
7334 smb_packet_t *watch, *lastWatch;
7335 USHORT fid, watchtree;
7339 osi_Log0(smb_logp, "SMB3 receive NT cancel");
7341 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7342 watch = smb_Directory_Watches;
7344 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
7345 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
7346 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
7347 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
7348 if (watch == smb_Directory_Watches)
7349 smb_Directory_Watches = watch->nextp;
7351 lastWatch->nextp = watch->nextp;
7352 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7354 /* Turn off WATCHED flag in scp */
7355 fid = smb_GetSMBParm(watch, 21);
7356 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
7358 if (vcp != watch->vcp)
7359 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
7362 fidp = smb_FindFID(vcp, fid, 0);
7364 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
7366 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
7369 lock_ObtainMutex(&scp->mx);
7371 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
7373 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
7374 lock_ReleaseMutex(&scp->mx);
7375 smb_ReleaseFID(fidp);
7377 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
7380 /* assume STATUS32; return 0xC0000120 (CANCELED) */
7381 replyWctp = watch->wctp;
7385 ((smb_t *)watch)->rcls = 0x20;
7386 ((smb_t *)watch)->reh = 0x1;
7387 ((smb_t *)watch)->errLow = 0;
7388 ((smb_t *)watch)->errHigh = 0xC0;
7389 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7390 smb_SendPacket(vcp, watch);
7391 smb_FreePacket(watch);
7395 watch = watch->nextp;
7397 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7403 * NT rename also does hard links.
7406 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
7407 #define RENAME_FLAG_HARD_LINK 0x103
7408 #define RENAME_FLAG_RENAME 0x104
7409 #define RENAME_FLAG_COPY 0x105
7411 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7413 char *oldPathp, *newPathp;
7419 attrs = smb_GetSMBParm(inp, 0);
7420 rename_type = smb_GetSMBParm(inp, 1);
7422 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
7423 osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
7424 return CM_ERROR_NOACCESS;
7427 tp = smb_GetSMBData(inp, NULL);
7428 oldPathp = smb_ParseASCIIBlock(tp, &tp);
7429 if (smb_StoreAnsiFilenames)
7430 OemToChar(oldPathp,oldPathp);
7431 newPathp = smb_ParseASCIIBlock(tp, &tp);
7432 if (smb_StoreAnsiFilenames)
7433 OemToChar(newPathp,newPathp);
7435 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
7436 osi_LogSaveString(smb_logp, oldPathp),
7437 osi_LogSaveString(smb_logp, newPathp),
7438 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
7440 if (rename_type == RENAME_FLAG_RENAME) {
7441 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
7442 } else { /* RENAME_FLAG_HARD_LINK */
7443 code = smb_Link(vcp,inp,oldPathp,newPathp);
7450 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
7453 cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
7455 smb_username_t *unp;
7458 unp = smb_FindUserByName(usern, machine, flags);
7460 lock_ObtainMutex(&unp->mx);
7461 unp->userp = cm_NewUser();
7462 lock_ReleaseMutex(&unp->mx);
7463 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7465 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7469 smb_ReleaseUsername(unp);