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>
15 #define SECURITY_WIN32
30 extern osi_hyper_t hzero;
32 smb_packet_t *smb_Directory_Watches = NULL;
33 osi_mutex_t smb_Dir_Watch_Lock;
35 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
37 /* protected by the smb_globalLock */
38 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
40 /* retrieve a held reference to a user structure corresponding to an incoming
42 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
47 uidp = smb_FindUID(vcp, inp->uid, 0);
48 if (!uidp) return NULL;
50 lock_ObtainMutex(&uidp->mx);
52 up = uidp->unp->userp;
55 lock_ReleaseMutex(&uidp->mx);
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 attrs = SMB_ATTR_DIRECTORY;
77 * We used to mark a file RO if it was in an RO volume, but that
78 * turns out to be impolitic in NT. See defect 10007.
81 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
83 if ((scp->unixModeBits & 0222) == 0)
84 attrs |= SMB_ATTR_READONLY; /* Read-only */
87 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
92 int smb_V3IsStarMask(char *maskp)
97 if (tc == '?' || tc == '*')
102 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
105 /* skip over null-terminated string */
106 *chainpp = inp + strlen(inp) + 1;
111 /*DEBUG do not checkin*/
112 void OutputDebugF(char * format, ...) {
118 va_start( args, format );
119 len = _vscprintf( format, args ) // _vscprintf doesn't count
120 + 3; // terminating '\0' + '\n'
121 buffer = malloc( len * sizeof(char) );
122 vsprintf( buffer, format, args );
123 strcat(buffer, "\n");
124 OutputDebugString(buffer);
129 void OutputDebugHexDump(unsigned char * buffer, int len) {
133 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
135 OutputDebugF("Hexdump length [%d]",len);
140 OutputDebugString(buf);
141 sprintf(buf,"%5x",i);
142 memset(buf+5,' ',80);
148 j = j*3 + 7 + ((j>7)?1:0);
151 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
154 j = j + 56 + ((j>7)?1:0);
156 buf[j] = (k>32 && k<127)?k:'.';
159 OutputDebugString(buf);
164 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
165 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength){
166 SECURITY_STATUS status, istatus;
169 SecBufferDesc secOut;
177 OutputDebugF("Negotiating Extended Security");
179 status = AcquireCredentialsHandle(
181 SMB_EXT_SEC_PACKAGE_NAME,
190 if (status != SEC_E_OK) {
191 /* Really bad. We return an empty security blob */
192 OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
197 secOut.pBuffers = &secTok;
198 secOut.ulVersion = SECBUFFER_VERSION;
200 secTok.BufferType = SECBUFFER_TOKEN;
202 secTok.pvBuffer = NULL;
204 ctx.dwLower = ctx.dwUpper = 0;
206 status = AcceptSecurityContext(
210 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
211 SECURITY_NETWORK_DREP,
218 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
219 OutputDebugF("Completing token...");
220 istatus = CompleteAuthToken(&ctx, &secOut);
221 if ( istatus != SEC_E_OK )
222 OutputDebugF("Token completion failed: %x", istatus);
225 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
226 if (secTok.pvBuffer) {
227 *secBlobLength = secTok.cbBuffer;
228 *secBlob = malloc( secTok.cbBuffer );
229 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
232 if ( status != SEC_E_OK )
233 OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
236 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
238 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
239 FreeCredentialsHandle(&creds);
244 OutputDebugF("Returning initial token:");
245 OutputDebugHexDump(*secBlob,*secBlobLength);
247 OutputDebugF("No initial token");
252 struct smb_ext_context {
259 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
260 SECURITY_STATUS status, istatus;
264 SecBufferDesc secBufIn;
266 SecBufferDesc secBufOut;
269 struct smb_ext_context * secCtx = NULL;
270 struct smb_ext_context * newSecCtx = NULL;
271 void * assembledBlob = NULL;
272 int assembledBlobLength = 0;
275 OutputDebugF("In smb_AuthenticateUserExt");
278 *secBlobOutLength = 0;
280 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
281 secCtx = vcp->secCtx;
282 lock_ObtainMutex(&vcp->mx);
283 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
285 lock_ReleaseMutex(&vcp->mx);
289 OutputDebugF("Received incoming token:");
290 OutputDebugHexDump(secBlobIn,secBlobInLength);
294 OutputDebugF("Continuing with existing context.");
295 creds = secCtx->creds;
298 if (secCtx->partialToken) {
299 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
300 assembledBlob = malloc(assembledBlobLength);
301 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
302 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
305 status = AcquireCredentialsHandle(
307 SMB_EXT_SEC_PACKAGE_NAME,
316 if (status != SEC_E_OK) {
317 OutputDebugF("Can't acquire Credentials handle [%lX]", status);
318 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
326 secBufIn.cBuffers = 1;
327 secBufIn.pBuffers = &secTokIn;
328 secBufIn.ulVersion = SECBUFFER_VERSION;
330 secTokIn.BufferType = SECBUFFER_TOKEN;
332 secTokIn.cbBuffer = assembledBlobLength;
333 secTokIn.pvBuffer = assembledBlob;
335 secTokIn.cbBuffer = secBlobInLength;
336 secTokIn.pvBuffer = secBlobIn;
339 secBufOut.cBuffers = 1;
340 secBufOut.pBuffers = &secTokOut;
341 secBufOut.ulVersion = SECBUFFER_VERSION;
343 secTokOut.BufferType = SECBUFFER_TOKEN;
344 secTokOut.cbBuffer = 0;
345 secTokOut.pvBuffer = NULL;
347 status = AcceptSecurityContext(
349 ((secCtx)?&ctx:NULL),
351 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
352 SECURITY_NETWORK_DREP,
359 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
360 OutputDebugF("Completing token...");
361 istatus = CompleteAuthToken(&ctx, &secBufOut);
362 if ( istatus != SEC_E_OK )
363 OutputDebugF("Token completion failed: %lX", istatus);
366 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
367 OutputDebugF("Continue needed");
369 newSecCtx = malloc(sizeof(*newSecCtx));
371 newSecCtx->creds = creds;
372 newSecCtx->ctx = ctx;
373 newSecCtx->partialToken = NULL;
374 newSecCtx->partialTokenLen = 0;
376 lock_ObtainMutex( &vcp->mx );
377 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
378 vcp->secCtx = newSecCtx;
379 lock_ReleaseMutex( &vcp->mx );
381 code = CM_ERROR_GSSCONTINUE;
384 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
385 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
386 secTokOut.pvBuffer) {
387 OutputDebugF("Need to send token back to client");
389 *secBlobOutLength = secTokOut.cbBuffer;
390 *secBlobOut = malloc(secTokOut.cbBuffer);
391 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
393 OutputDebugF("Outgoing token:");
394 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
395 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
396 OutputDebugF("Incomplete message");
398 newSecCtx = malloc(sizeof(*newSecCtx));
400 newSecCtx->creds = creds;
401 newSecCtx->ctx = ctx;
402 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
403 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
404 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
406 lock_ObtainMutex( &vcp->mx );
407 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
408 vcp->secCtx = newSecCtx;
409 lock_ReleaseMutex( &vcp->mx );
411 code = CM_ERROR_GSSCONTINUE;
414 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
416 SecPkgContext_Names names;
418 OutputDebugF("Authentication completed");
419 OutputDebugF("Returned flags : [%lX]", flags);
421 if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
422 OutputDebugF("Received name [%s]", names.sUserName);
423 strcpy(usern, names.sUserName);
424 strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
425 FreeContextBuffer(names.sUserName);
427 /* Force the user to retry if the context is invalid */
428 OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
429 code = CM_ERROR_BADPASSWORD;
433 case SEC_E_INVALID_TOKEN:
434 OutputDebugF("Returning bad password :: INVALID_TOKEN");
436 case SEC_E_INVALID_HANDLE:
437 OutputDebugF("Returning bad password :: INVALID_HANDLE");
439 case SEC_E_LOGON_DENIED:
440 OutputDebugF("Returning bad password :: LOGON_DENIED");
442 case SEC_E_UNKNOWN_CREDENTIALS:
443 OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
445 case SEC_E_NO_CREDENTIALS:
446 OutputDebugF("Returning bad password :: NO_CREDENTIALS");
448 case SEC_E_CONTEXT_EXPIRED:
449 OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
451 case SEC_E_INCOMPLETE_CREDENTIALS:
452 OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
454 case SEC_E_WRONG_PRINCIPAL:
455 OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
457 case SEC_E_TIME_SKEW:
458 OutputDebugF("Returning bad password :: TIME_SKEW");
461 OutputDebugF("Returning bad password :: Status == %lX", status);
463 code = CM_ERROR_BADPASSWORD;
467 if (secCtx->partialToken) free(secCtx->partialToken);
475 if (secTokOut.pvBuffer)
476 FreeContextBuffer(secTokOut.pvBuffer);
478 if (code != CM_ERROR_GSSCONTINUE) {
479 DeleteSecurityContext(&ctx);
480 FreeCredentialsHandle(&creds);
488 #define P_RESP_LEN 128
490 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
491 So put stuff in a struct. */
492 struct Lm20AuthBlob {
493 MSV1_0_LM20_LOGON lmlogon;
494 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
495 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
496 WCHAR accountNameW[P_LEN];
497 WCHAR primaryDomainW[P_LEN];
498 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
499 TOKEN_GROUPS tgroups;
500 TOKEN_SOURCE tsource;
503 long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength) {
506 struct Lm20AuthBlob lmAuth;
507 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
508 QUOTA_LIMITS quotaLimits;
510 ULONG lmprofilepSize;
514 OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
515 OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
517 OutputDebugF("csPassword:");
518 OutputDebugHexDump(csPwd,csPwdLength);
519 OutputDebugF("ciPassword:");
520 OutputDebugHexDump(ciPwd,ciPwdLength);
522 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
523 OutputDebugF("ciPwdLength or csPwdLength is too long");
524 return CM_ERROR_BADPASSWORD;
527 memset(&lmAuth,0,sizeof(lmAuth));
529 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
531 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
532 mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
533 lmAuth.lmlogon.LogonDomainName.Length = wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR);
534 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
536 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
537 mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
538 lmAuth.lmlogon.UserName.Length = wcslen(lmAuth.accountNameW) * sizeof(WCHAR);
539 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
541 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
542 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
543 size = MAX_COMPUTERNAME_LENGTH + 1;
544 GetComputerNameW(lmAuth.workstationW, &size);
545 lmAuth.lmlogon.Workstation.Length = wcslen(lmAuth.workstationW) * sizeof(WCHAR);
547 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
549 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
550 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
551 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
552 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
554 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
555 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
556 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
557 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
559 lmAuth.lmlogon.ParameterControl = 0;
561 lmAuth.tgroups.GroupCount = 0;
562 lmAuth.tgroups.Groups[0].Sid = NULL;
563 lmAuth.tgroups.Groups[0].Attributes = 0;
565 lmAuth.tsource.SourceIdentifier.HighPart = 0;
566 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD) vcp;
567 strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
585 OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
586 OutputDebugF("Extended status is 0x%lX", ntsEx);
588 if (nts == ERROR_SUCCESS) {
590 LsaFreeReturnBuffer(lmprofilep);
591 CloseHandle(lmToken);
595 if (nts == 0xC000015BL)
596 return CM_ERROR_BADLOGONTYPE;
597 else /* our catchall is a bad password though we could be more specific */
598 return CM_ERROR_BADPASSWORD;
602 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
603 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName) {
608 /* check if we have sane input */
609 if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
612 /* we could get : [accountName][domainName]
618 atsign = strchr(accountName, '@');
620 if (atsign) /* [user@domain][] -> [user@domain][domain] */
625 /* if for some reason the client doesn't know what domain to use,
626 it will either return an empty string or a '?' */
627 if (!domain[0] || domain[0] == '?')
628 /* Empty domains and empty usernames are usually sent from tokenless contexts.
629 This way such logins will get an empty username (easy to check). I don't know
630 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
631 strcpy(usern,accountName);
633 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
634 strcpy(usern,domain);
637 strncat(usern,accountName,atsign - accountName);
639 strcat(usern,accountName);
647 /* When using SMB auth, all SMB sessions have to pass through here first to
648 * authenticate the user.
649 * Caveat: If not use the SMB auth the protocol does not require sending a
650 * session setup packet, which means that we can't rely on a UID in subsequent
651 * packets. Though in practice we get one anyway.
653 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
657 unsigned short newUid;
658 unsigned long caps = 0;
663 char usern[SMB_MAX_USERNAME_LENGTH];
664 char *secBlobOut = NULL;
665 int secBlobOutLength = 0;
667 /* Check for bad conns */
668 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
669 return CM_ERROR_REMOTECONN;
671 if (vcp->flags & SMB_VCFLAG_USENT) {
672 if (smb_authType == SMB_AUTH_EXTENDED) {
673 /* extended authentication */
677 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
678 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
681 secBlobInLength = smb_GetSMBParm(inp, 7);
682 secBlobIn = smb_GetSMBData(inp, NULL);
684 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
686 if (code == CM_ERROR_GSSCONTINUE) {
687 smb_SetSMBParm(outp, 2, 0);
688 smb_SetSMBParm(outp, 3, secBlobOutLength);
689 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
690 tp = smb_GetSMBData(outp, NULL);
691 if (secBlobOutLength) {
692 memcpy(tp, secBlobOut, secBlobOutLength);
694 tp += secBlobOutLength;
696 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
697 tp += smb_ServerOSLength;
698 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
699 tp += smb_ServerLanManagerLength;
700 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
701 tp += smb_ServerDomainNameLength;
704 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
706 unsigned ciPwdLength, csPwdLength;
712 /* TODO: parse for extended auth as well */
713 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
714 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
716 tp = smb_GetSMBData(inp, &datalen);
718 OutputDebugF("Session packet data size [%d]",datalen);
725 accountName = smb_ParseString(tp, &tp);
726 primaryDomain = smb_ParseString(tp, NULL);
728 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
729 /* shouldn't happen */
730 code = CM_ERROR_BADSMB;
731 goto after_read_packet;
734 /* capabilities are only valid for first session packet */
735 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
736 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
739 if (smb_authType == SMB_AUTH_NTLM) {
740 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
744 unsigned ciPwdLength;
749 ciPwdLength = smb_GetSMBParm(inp, 7);
750 tp = smb_GetSMBData(inp, NULL);
754 accountName = smb_ParseString(tp, &tp);
755 primaryDomain = smb_ParseString(tp, NULL);
757 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
758 /* shouldn't happen */
759 code = CM_ERROR_BADSMB;
760 goto after_read_packet;
763 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
766 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
767 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
772 /* note down that we received a session setup X and set the capabilities flag */
773 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
774 lock_ObtainMutex(&vcp->mx);
775 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
776 /* for the moment we can only deal with NTSTATUS */
777 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
778 vcp->flags |= SMB_VCFLAG_STATUS32;
780 lock_ReleaseMutex(&vcp->mx);
783 /* code would be non-zero if there was an authentication failure.
784 Ideally we would like to invalidate the uid for this session or break
785 early to avoid accidently stealing someone else's tokens. */
791 OutputDebugF("Received username=[%s]", usern);
793 /* On Windows 2000, this function appears to be called more often than
794 it is expected to be called. This resulted in multiple smb_user_t
795 records existing all for the same user session which results in all
796 of the users tokens disappearing.
798 To avoid this problem, we look for an existing smb_user_t record
799 based on the users name, and use that one if we find it.
802 uidp = smb_FindUserByNameThisSession(vcp, usern);
803 if (uidp) { /* already there, so don't create a new one */
806 newUid = (unsigned short)uidp->userID; /* For some reason these are different types!*/
807 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"FindUserByName:Lana[%d],lsn[%d],userid[%d],name[%s]",vcp->lana,vcp->lsn,newUid,usern);
808 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
809 smb_ReleaseUID(uidp);
812 /* do a global search for the username/machine name pair */
813 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
815 /* Create a new UID and cm_user_t structure */
818 userp = cm_NewUser();
819 lock_ObtainMutex(&vcp->mx);
820 if (!vcp->uidCounter)
821 vcp->uidCounter++; /* handle unlikely wraparounds */
822 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
823 lock_ReleaseMutex(&vcp->mx);
825 /* Create a new smb_user_t structure and connect them up */
826 lock_ObtainMutex(&unp->mx);
828 lock_ReleaseMutex(&unp->mx);
830 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
831 lock_ObtainMutex(&uidp->mx);
833 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d],TicketKTCName[%s]",(int)vcp,vcp->lana,vcp->lsn,newUid,usern);
834 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
835 lock_ReleaseMutex(&uidp->mx);
836 smb_ReleaseUID(uidp);
839 /* Return UID to the client */
840 ((smb_t *)outp)->uid = newUid;
841 /* Also to the next chained message */
842 ((smb_t *)inp)->uid = newUid;
844 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
845 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
847 smb_SetSMBParm(outp, 2, 0);
849 if (vcp->flags & SMB_VCFLAG_USENT) {
850 if (smb_authType == SMB_AUTH_EXTENDED) {
851 smb_SetSMBParm(outp, 3, secBlobOutLength);
852 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
853 tp = smb_GetSMBData(outp, NULL);
854 if (secBlobOutLength) {
855 memcpy(tp, secBlobOut, secBlobOutLength);
857 tp += secBlobOutLength;
859 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
860 tp += smb_ServerOSLength;
861 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
862 tp += smb_ServerLanManagerLength;
863 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
864 tp += smb_ServerDomainNameLength;
866 smb_SetSMBDataLength(outp, 0);
869 if (smb_authType == SMB_AUTH_EXTENDED) {
870 smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
871 tp = smb_GetSMBData(outp, NULL);
872 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
873 tp += smb_ServerOSLength;
874 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
875 tp += smb_ServerLanManagerLength;
876 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
877 tp += smb_ServerDomainNameLength;
879 smb_SetSMBDataLength(outp, 0);
886 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
890 /* don't get tokens from this VC */
891 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
893 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
895 /* find the tree and free it */
896 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
897 /* TODO: smb_ReleaseUID() ? */
899 char *s1 = NULL, *s2 = NULL;
901 if (s2 == NULL) s2 = " ";
902 if (s1 == NULL) {s1 = s2; s2 = " ";}
904 osi_Log4(smb_logp, "SMB3 user logoffX uid %d name %s%s%s", uidp->userID,
905 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "), s1, s2);
907 lock_ObtainMutex(&uidp->mx);
908 uidp->flags |= SMB_USERFLAG_DELETE;
910 * it doesn't get deleted right away
911 * because the vcp points to it
913 lock_ReleaseMutex(&uidp->mx);
916 osi_Log0(smb_logp, "SMB3 user logoffX");
918 smb_SetSMBDataLength(outp, 0);
922 #define SMB_SUPPORT_SEARCH_BITS 0x0001
924 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
928 unsigned short newTid;
938 osi_Log0(smb_logp, "SMB3 receive tree connect");
940 /* parse input parameters */
941 tp = smb_GetSMBData(inp, NULL);
942 passwordp = smb_ParseString(tp, &tp);
943 pathp = smb_ParseString(tp, &tp);
944 servicep = smb_ParseString(tp, &tp);
946 tp = strrchr(pathp, '\\');
948 return CM_ERROR_BADSMB;
950 strcpy(shareName, tp+1);
952 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0)
953 return CM_ERROR_NOIPC;
955 userp = smb_GetUser(vcp, inp);
957 lock_ObtainMutex(&vcp->mx);
958 newTid = vcp->tidCounter++;
959 lock_ReleaseMutex(&vcp->mx);
961 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
962 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
963 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
965 smb_ReleaseUID(uidp);
967 smb_ReleaseTID(tidp);
968 return CM_ERROR_BADSHARENAME;
970 lock_ObtainMutex(&tidp->mx);
972 tidp->pathname = sharePath;
973 lock_ReleaseMutex(&tidp->mx);
974 smb_ReleaseTID(tidp);
976 if (vcp->flags & SMB_VCFLAG_USENT)
978 int policy = smb_FindShareCSCPolicy(shareName);
979 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS | (policy << 2));
982 ((smb_t *)outp)->tid = newTid;
983 ((smb_t *)inp)->tid = newTid;
984 tp = smb_GetSMBData(outp, NULL);
988 smb_SetSMBDataLength(outp, 3);
990 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
994 /* must be called with global tran lock held */
995 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
997 smb_tran2Packet_t *tp;
1000 smbp = (smb_t *) inp->data;
1001 for(tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1002 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1008 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1009 int totalParms, int totalData)
1011 smb_tran2Packet_t *tp;
1014 smbp = (smb_t *) inp->data;
1015 tp = malloc(sizeof(*tp));
1016 memset(tp, 0, sizeof(*tp));
1019 tp->curData = tp->curParms = 0;
1020 tp->totalData = totalData;
1021 tp->totalParms = totalParms;
1022 tp->tid = smbp->tid;
1023 tp->mid = smbp->mid;
1024 tp->uid = smbp->uid;
1025 tp->pid = smbp->pid;
1026 tp->res[0] = smbp->res[0];
1027 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1028 tp->opcode = smb_GetSMBParm(inp, 14);
1029 if (totalParms != 0)
1030 tp->parmsp = malloc(totalParms);
1032 tp->datap = malloc(totalData);
1033 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1037 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1038 smb_tran2Packet_t *inp, smb_packet_t *outp,
1039 int totalParms, int totalData)
1041 smb_tran2Packet_t *tp;
1042 unsigned short parmOffset;
1043 unsigned short dataOffset;
1044 unsigned short dataAlign;
1046 tp = malloc(sizeof(*tp));
1047 memset(tp, 0, sizeof(*tp));
1049 tp->curData = tp->curParms = 0;
1050 tp->totalData = totalData;
1051 tp->totalParms = totalParms;
1052 tp->oldTotalParms = totalParms;
1057 tp->res[0] = inp->res[0];
1058 tp->opcode = inp->opcode;
1061 * We calculate where the parameters and data will start.
1062 * This calculation must parallel the calculation in
1063 * smb_SendTran2Packet.
1066 parmOffset = 10*2 + 35;
1067 parmOffset++; /* round to even */
1068 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1070 dataOffset = parmOffset + totalParms;
1071 dataAlign = dataOffset & 2; /* quad-align */
1072 dataOffset += dataAlign;
1073 tp->datap = outp->data + dataOffset;
1078 /* free a tran2 packet; must be called with smb_globalLock held */
1079 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1081 if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
1082 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1091 /* called with a VC, an input packet to respond to, and an error code.
1092 * sends an error response.
1094 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1095 smb_packet_t *tp, long code)
1098 unsigned short errCode;
1099 unsigned char errClass;
1100 unsigned long NTStatus;
1102 if (vcp->flags & SMB_VCFLAG_STATUS32)
1103 smb_MapNTError(code, &NTStatus);
1105 smb_MapCoreError(code, vcp, &errCode, &errClass);
1107 smb_FormatResponsePacket(vcp, NULL, tp);
1108 smbp = (smb_t *) tp;
1110 /* We can handle long names */
1111 if (vcp->flags & SMB_VCFLAG_USENT)
1112 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
1114 /* now copy important fields from the tran 2 packet */
1115 smbp->com = 0x32; /* tran 2 response */
1116 smbp->tid = t2p->tid;
1117 smbp->mid = t2p->mid;
1118 smbp->pid = t2p->pid;
1119 smbp->uid = t2p->uid;
1120 smbp->res[0] = t2p->res[0];
1121 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1122 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1123 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1124 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1125 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1126 smbp->flg2 |= 0x4000;
1129 smbp->rcls = errClass;
1130 smbp->errLow = (unsigned char) (errCode & 0xff);
1131 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1135 smb_SendPacket(vcp, tp);
1138 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1141 unsigned short parmOffset;
1142 unsigned short dataOffset;
1143 unsigned short totalLength;
1144 unsigned short dataAlign;
1147 smb_FormatResponsePacket(vcp, NULL, tp);
1148 smbp = (smb_t *) tp;
1150 /* We can handle long names */
1151 if (vcp->flags & SMB_VCFLAG_USENT)
1152 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
1154 /* now copy important fields from the tran 2 packet */
1155 smbp->com = 0x32; /* tran 2 response */
1156 smbp->tid = t2p->tid;
1157 smbp->mid = t2p->mid;
1158 smbp->pid = t2p->pid;
1159 smbp->uid = t2p->uid;
1160 smbp->res[0] = t2p->res[0];
1162 totalLength = 1 + t2p->totalData + t2p->totalParms;
1164 /* now add the core parameters (tran2 info) to the packet */
1165 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1166 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1167 smb_SetSMBParm(tp, 2, 0); /* reserved */
1168 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1169 parmOffset = 10*2 + 35; /* parm offset in packet */
1170 parmOffset++; /* round to even */
1171 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1172 * hdr, bcc and wct */
1173 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1174 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1175 dataOffset = parmOffset + t2p->oldTotalParms;
1176 dataAlign = dataOffset & 2; /* quad-align */
1177 dataOffset += dataAlign;
1178 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1179 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1180 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1183 datap = smb_GetSMBData(tp, NULL);
1184 *datap++ = 0; /* we rounded to even */
1186 totalLength += dataAlign;
1187 smb_SetSMBDataLength(tp, totalLength);
1189 /* next, send the datagram */
1190 smb_SendPacket(vcp, tp);
1193 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1195 smb_tran2Packet_t *asp;
1207 /* We sometimes see 0 word count. What to do? */
1208 if (*inp->wctp == 0) {
1213 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1215 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1216 ptbuf[0] = "Transaction2 word count = 0";
1217 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1218 1, inp->ncb_length, ptbuf, inp);
1219 DeregisterEventSource(h);
1221 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1224 smb_SetSMBDataLength(outp, 0);
1225 smb_SendPacket(vcp, outp);
1229 totalParms = smb_GetSMBParm(inp, 0);
1230 totalData = smb_GetSMBParm(inp, 1);
1232 firstPacket = (inp->inCom == 0x32);
1234 /* find the packet we're reassembling */
1235 lock_ObtainWrite(&smb_globalLock);
1236 asp = smb_FindTran2Packet(vcp, inp);
1238 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1240 lock_ReleaseWrite(&smb_globalLock);
1242 /* now merge in this latest packet; start by looking up offsets */
1244 parmDisp = dataDisp = 0;
1245 parmOffset = smb_GetSMBParm(inp, 10);
1246 dataOffset = smb_GetSMBParm(inp, 12);
1247 parmCount = smb_GetSMBParm(inp, 9);
1248 dataCount = smb_GetSMBParm(inp, 11);
1249 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1250 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1252 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1253 totalData, dataCount, asp->maxReturnData);
1256 parmDisp = smb_GetSMBParm(inp, 4);
1257 parmOffset = smb_GetSMBParm(inp, 3);
1258 dataDisp = smb_GetSMBParm(inp, 7);
1259 dataOffset = smb_GetSMBParm(inp, 6);
1260 parmCount = smb_GetSMBParm(inp, 2);
1261 dataCount = smb_GetSMBParm(inp, 5);
1263 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1264 parmCount, dataCount);
1267 /* now copy the parms and data */
1268 if ( parmCount != 0 )
1270 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1272 if ( dataCount != 0 ) {
1273 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1276 /* account for new bytes */
1277 asp->curData += dataCount;
1278 asp->curParms += parmCount;
1280 /* finally, if we're done, remove the packet from the queue and dispatch it */
1281 if (asp->totalData <= asp->curData && asp->totalParms <= asp->curParms) {
1282 /* we've received it all */
1283 lock_ObtainWrite(&smb_globalLock);
1284 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1285 lock_ReleaseWrite(&smb_globalLock);
1287 /* now dispatch it */
1288 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
1289 osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1290 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
1291 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
1294 osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1295 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1296 code = CM_ERROR_BADOP;
1299 /* if an error is returned, we're supposed to send an error packet,
1300 * otherwise the dispatched function already did the data sending.
1301 * We give dispatched proc the responsibility since it knows how much
1302 * space to allocate.
1305 smb_SendTran2Error(vcp, asp, outp, code);
1308 /* free the input tran 2 packet */
1309 lock_ObtainWrite(&smb_globalLock);
1310 smb_FreeTran2Packet(asp);
1311 lock_ReleaseWrite(&smb_globalLock);
1313 else if (firstPacket) {
1314 /* the first packet in a multi-packet request, we need to send an
1315 * ack to get more data.
1317 smb_SetSMBDataLength(outp, 0);
1318 smb_SendPacket(vcp, outp);
1324 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1327 smb_tran2Packet_t *outp;
1332 cm_scache_t *dscp; /* dir we're dealing with */
1333 cm_scache_t *scp; /* file we're creating */
1335 int initialModeBits;
1345 int parmSlot; /* which parm we're dealing with */
1346 long returnEALength;
1354 extraInfo = (p->parmsp[0] & 1); /* return extra info */
1355 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
1357 openFun = p->parmsp[6]; /* open function */
1358 excl = ((openFun & 3) == 0);
1359 trunc = ((openFun & 3) == 2); /* truncate it */
1360 openMode = (p->parmsp[1] & 0x7);
1361 openAction = 0; /* tracks what we did */
1363 attributes = p->parmsp[3];
1364 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
1366 /* compute initial mode bits based on read-only flag in attributes */
1367 initialModeBits = 0666;
1368 if (attributes & 1) initialModeBits &= ~0222;
1370 pathp = (char *) (&p->parmsp[14]);
1372 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
1374 spacep = cm_GetSpace();
1375 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
1377 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
1378 /* special case magic file name for receiving IOCTL requests
1379 * (since IOCTL calls themselves aren't getting through).
1381 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
1382 smb_SetupIoctlFid(fidp, spacep);
1384 /* copy out remainder of the parms */
1386 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
1388 outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
1389 outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
1390 outp->parmsp[parmSlot] = 0; parmSlot++;
1391 outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
1392 outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
1393 outp->parmsp[parmSlot] = openMode; parmSlot++;
1394 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
1395 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
1397 /* and the final "always present" stuff */
1398 outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
1399 /* next write out the "unique" ID */
1400 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
1401 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
1402 outp->parmsp[parmSlot] = 0; parmSlot++;
1403 if (returnEALength) {
1404 outp->parmsp[parmSlot] = 0; parmSlot++;
1405 outp->parmsp[parmSlot] = 0; parmSlot++;
1408 outp->totalData = 0;
1409 outp->totalParms = parmSlot * 2;
1411 smb_SendTran2Packet(vcp, outp, op);
1413 smb_FreeTran2Packet(outp);
1415 /* and clean up fid reference */
1416 smb_ReleaseFID(fidp);
1420 #ifdef DEBUG_VERBOSE
1422 char *hexp, *asciip;
1423 asciip = (lastNamep ? lastNamep : pathp);
1424 hexp = osi_HexifyString( asciip );
1425 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
1430 userp = smb_GetTran2User(vcp, p);
1431 /* In the off chance that userp is NULL, we log and abandon */
1433 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
1434 smb_FreeTran2Packet(outp);
1435 return CM_ERROR_BADSMB;
1438 tidPathp = smb_GetTIDPath(vcp, p->tid);
1441 code = cm_NameI(cm_rootSCachep, pathp,
1442 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
1443 userp, tidPathp, &req, &scp);
1445 code = cm_NameI(cm_rootSCachep, spacep->data,
1446 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
1447 userp, tidPathp, &req, &dscp);
1448 cm_FreeSpace(spacep);
1451 cm_ReleaseUser(userp);
1452 smb_FreeTran2Packet(outp);
1456 /* otherwise, scp points to the parent directory. Do a lookup,
1457 * and truncate the file if we find it, otherwise we create the
1460 if (!lastNamep) lastNamep = pathp;
1462 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
1464 if (code && code != CM_ERROR_NOSUCHFILE) {
1465 cm_ReleaseSCache(dscp);
1466 cm_ReleaseUser(userp);
1467 smb_FreeTran2Packet(outp);
1472 cm_FreeSpace(spacep);
1475 /* if we get here, if code is 0, the file exists and is represented by
1476 * scp. Otherwise, we have to create it.
1479 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
1481 if (dscp) cm_ReleaseSCache(dscp);
1482 cm_ReleaseSCache(scp);
1483 cm_ReleaseUser(userp);
1484 smb_FreeTran2Packet(outp);
1489 /* oops, file shouldn't be there */
1490 if (dscp) cm_ReleaseSCache(dscp);
1491 cm_ReleaseSCache(scp);
1492 cm_ReleaseUser(userp);
1493 smb_FreeTran2Packet(outp);
1494 return CM_ERROR_EXISTS;
1498 setAttr.mask = CM_ATTRMASK_LENGTH;
1499 setAttr.length.LowPart = 0;
1500 setAttr.length.HighPart = 0;
1501 code = cm_SetAttr(scp, &setAttr, userp, &req);
1502 openAction = 3; /* truncated existing file */
1504 else openAction = 1; /* found existing file */
1506 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
1507 /* don't create if not found */
1508 if (dscp) cm_ReleaseSCache(dscp);
1509 osi_assert(scp == NULL);
1510 cm_ReleaseUser(userp);
1511 smb_FreeTran2Packet(outp);
1512 return CM_ERROR_NOSUCHFILE;
1515 osi_assert(dscp != NULL && scp == NULL);
1516 openAction = 2; /* created file */
1517 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
1518 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
1519 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
1521 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
1522 smb_NotifyChange(FILE_ACTION_ADDED,
1523 FILE_NOTIFY_CHANGE_FILE_NAME,
1524 dscp, lastNamep, NULL, TRUE);
1525 if (!excl && code == CM_ERROR_EXISTS) {
1526 /* not an exclusive create, and someone else tried
1527 * creating it already, then we open it anyway. We
1528 * don't bother retrying after this, since if this next
1529 * fails, that means that the file was deleted after we
1530 * started this call.
1532 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
1536 setAttr.mask = CM_ATTRMASK_LENGTH;
1537 setAttr.length.LowPart = 0;
1538 setAttr.length.HighPart = 0;
1539 code = cm_SetAttr(scp, &setAttr, userp,
1542 } /* lookup succeeded */
1546 /* we don't need this any longer */
1547 if (dscp) cm_ReleaseSCache(dscp);
1550 /* something went wrong creating or truncating the file */
1551 if (scp) cm_ReleaseSCache(scp);
1552 cm_ReleaseUser(userp);
1553 smb_FreeTran2Packet(outp);
1557 /* make sure we're about to open a file */
1558 if (scp->fileType != CM_SCACHETYPE_FILE) {
1559 cm_ReleaseSCache(scp);
1560 cm_ReleaseUser(userp);
1561 smb_FreeTran2Packet(outp);
1562 return CM_ERROR_ISDIR;
1565 /* now all we have to do is open the file itself */
1566 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
1569 /* save a pointer to the vnode */
1572 /* compute open mode */
1573 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
1574 if (openMode == 1 || openMode == 2)
1575 fidp->flags |= SMB_FID_OPENWRITE;
1577 smb_ReleaseFID(fidp);
1579 cm_Open(scp, 0, userp);
1581 /* copy out remainder of the parms */
1583 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
1584 lock_ObtainMutex(&scp->mx);
1586 outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
1587 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1588 outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
1589 outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
1590 outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
1592 outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
1594 outp->parmsp[parmSlot] = openMode; parmSlot++;
1595 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
1596 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
1598 /* and the final "always present" stuff */
1599 outp->parmsp[parmSlot] = openAction; parmSlot++;
1600 /* next write out the "unique" ID */
1601 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
1602 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
1603 outp->parmsp[parmSlot] = 0; parmSlot++;
1604 if (returnEALength) {
1605 outp->parmsp[parmSlot] = 0; parmSlot++;
1606 outp->parmsp[parmSlot] = 0; parmSlot++;
1608 lock_ReleaseMutex(&scp->mx);
1609 outp->totalData = 0; /* total # of data bytes */
1610 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
1612 smb_SendTran2Packet(vcp, outp, op);
1614 smb_FreeTran2Packet(outp);
1616 cm_ReleaseUser(userp);
1617 /* leave scp held since we put it in fidp->scp */
1621 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1623 return CM_ERROR_BADOP;
1626 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1628 return CM_ERROR_BADOP;
1631 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1633 smb_tran2Packet_t *outp;
1634 smb_tran2QFSInfo_t qi;
1637 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
1639 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
1641 switch (p->parmsp[0]) {
1642 case 1: responseSize = sizeof(qi.u.allocInfo); break;
1643 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
1644 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
1645 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
1646 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
1647 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
1648 default: return CM_ERROR_INVAL;
1651 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
1652 switch (p->parmsp[0]) {
1655 qi.u.allocInfo.FSID = 0;
1656 qi.u.allocInfo.sectorsPerAllocUnit = 1;
1657 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
1658 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
1659 qi.u.allocInfo.bytesPerSector = 1024;
1664 qi.u.volumeInfo.vsn = 1234;
1665 qi.u.volumeInfo.vnCount = 4;
1666 /* we're supposed to pad it out with zeroes to the end */
1667 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
1668 memcpy(qi.u.volumeInfo.label, "AFS", 4);
1672 /* FS volume info */
1673 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
1674 qi.u.FSvolumeInfo.vsn = 1234;
1675 qi.u.FSvolumeInfo.vnCount = 8;
1676 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
1682 temp.LowPart = 0x7fffffff;
1683 qi.u.FSsizeInfo.totalAllocUnits = temp;
1684 temp.LowPart = 0x3fffffff;
1685 qi.u.FSsizeInfo.availAllocUnits = temp;
1686 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
1687 qi.u.FSsizeInfo.bytesPerSector = 1024;
1691 /* FS device info */
1692 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
1693 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
1697 /* FS attribute info */
1698 /* attributes, defined in WINNT.H:
1699 * FILE_CASE_SENSITIVE_SEARCH 0x1
1700 * FILE_CASE_PRESERVED_NAMES 0x2
1701 * <no name defined> 0x4000
1702 * If bit 0x4000 is not set, Windows 95 thinks
1703 * we can't handle long (non-8.3) names,
1704 * despite our protestations to the contrary.
1706 qi.u.FSattributeInfo.attributes = 0x4003;
1707 qi.u.FSattributeInfo.maxCompLength = 255;
1708 qi.u.FSattributeInfo.FSnameLength = 6;
1709 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
1713 /* copy out return data, and set corresponding sizes */
1714 outp->totalParms = 0;
1715 outp->totalData = responseSize;
1716 memcpy(outp->datap, &qi, responseSize);
1718 /* send and free the packets */
1719 smb_SendTran2Packet(vcp, outp, op);
1720 smb_FreeTran2Packet(outp);
1725 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1727 return CM_ERROR_BADOP;
1730 struct smb_ShortNameRock {
1734 size_t shortNameLen;
1737 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
1740 struct smb_ShortNameRock *rockp;
1744 /* compare both names and vnodes, though probably just comparing vnodes
1745 * would be safe enough.
1747 if (cm_stricmp(dep->name, rockp->maskp) != 0)
1749 if (ntohl(dep->fid.vnode) != rockp->vnode)
1751 /* This is the entry */
1752 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
1753 rockp->shortNameLen = shortNameEnd - rockp->shortName;
1754 return CM_ERROR_STOPNOW;
1757 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
1758 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
1760 struct smb_ShortNameRock rock;
1764 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
1768 spacep = cm_GetSpace();
1769 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
1771 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
1773 cm_FreeSpace(spacep);
1774 if (code) return code;
1776 if (!lastNamep) lastNamep = pathp;
1779 thyper.HighPart = 0;
1780 rock.shortName = shortName;
1782 rock.maskp = lastNamep;
1783 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
1786 cm_ReleaseSCache(dscp);
1789 return CM_ERROR_NOSUCHFILE;
1790 if (code == CM_ERROR_STOPNOW) {
1791 *shortNameLenp = rock.shortNameLen;
1797 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1799 smb_tran2Packet_t *outp;
1800 unsigned long dosTime;
1802 unsigned short infoLevel;
1804 unsigned short attributes;
1805 unsigned long extAttributes;
1810 cm_scache_t *scp, *dscp;
1819 infoLevel = p->parmsp[0];
1820 if (infoLevel == 6) nbytesRequired = 0;
1821 else if (infoLevel == 1) nbytesRequired = 22;
1822 else if (infoLevel == 2) nbytesRequired = 26;
1823 else if (infoLevel == 0x101) nbytesRequired = 40;
1824 else if (infoLevel == 0x102) nbytesRequired = 24;
1825 else if (infoLevel == 0x103) nbytesRequired = 4;
1826 else if (infoLevel == 0x108) nbytesRequired = 30;
1828 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1829 p->opcode, infoLevel);
1830 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1833 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
1834 osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
1836 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1838 if (infoLevel > 0x100)
1839 outp->totalParms = 2;
1841 outp->totalParms = 0;
1842 outp->totalData = nbytesRequired;
1844 /* now, if we're at infoLevel 6, we're only being asked to check
1845 * the syntax, so we just OK things now. In particular, we're *not*
1846 * being asked to verify anything about the state of any parent dirs.
1848 if (infoLevel == 6) {
1849 smb_SendTran2Packet(vcp, outp, opx);
1850 smb_FreeTran2Packet(outp);
1854 userp = smb_GetTran2User(vcp, p);
1856 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
1857 smb_FreeTran2Packet(outp);
1858 return CM_ERROR_BADSMB;
1861 tidPathp = smb_GetTIDPath(vcp, p->tid);
1864 * XXX Strange hack XXX
1866 * As of Patch 7 (13 January 98), we are having the following problem:
1867 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
1868 * requests to look up "desktop.ini" in all the subdirectories.
1869 * This can cause zillions of timeouts looking up non-existent cells
1870 * and volumes, especially in the top-level directory.
1872 * We have not found any way to avoid this or work around it except
1873 * to explicitly ignore the requests for mount points that haven't
1874 * yet been evaluated and for directories that haven't yet been
1877 if (infoLevel == 0x101) {
1878 spacep = cm_GetSpace();
1879 smb_StripLastComponent(spacep->data, &lastComp,
1880 (char *)(&p->parmsp[3]));
1881 /* Make sure that lastComp is not NULL */
1883 if (strcmp(lastComp, "\\desktop.ini") == 0) {
1884 code = cm_NameI(cm_rootSCachep, spacep->data,
1888 userp, tidPathp, &req, &dscp);
1890 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
1891 && !dscp->mountRootFidp)
1892 code = CM_ERROR_NOSUCHFILE;
1893 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
1894 cm_buf_t *bp = buf_Find(dscp, &hzero);
1898 code = CM_ERROR_NOSUCHFILE;
1900 cm_ReleaseSCache(dscp);
1902 cm_FreeSpace(spacep);
1903 cm_ReleaseUser(userp);
1904 smb_SendTran2Error(vcp, p, opx, code);
1905 smb_FreeTran2Packet(outp);
1911 cm_FreeSpace(spacep);
1914 /* now do namei and stat, and copy out the info */
1915 code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
1916 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
1919 cm_ReleaseUser(userp);
1920 smb_SendTran2Error(vcp, p, opx, code);
1921 smb_FreeTran2Packet(outp);
1925 lock_ObtainMutex(&scp->mx);
1926 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1927 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1928 if (code) goto done;
1930 /* now we have the status in the cache entry, and everything is locked.
1931 * Marshall the output data.
1934 /* for info level 108, figure out short name */
1935 if (infoLevel == 0x108) {
1936 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
1937 tidPathp, scp->fid.vnode, shortName,
1944 *((u_long *)op) = len * 2; op += 4;
1945 mbstowcs((unsigned short *)op, shortName, len);
1950 if (infoLevel == 1 || infoLevel == 2) {
1951 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1952 *((u_long *)op) = dosTime; op += 4; /* creation time */
1953 *((u_long *)op) = dosTime; op += 4; /* access time */
1954 *((u_long *)op) = dosTime; op += 4; /* write time */
1955 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
1956 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
1957 attributes = smb_Attributes(scp);
1958 *((u_short *)op) = attributes; op += 2; /* attributes */
1960 else if (infoLevel == 0x101) {
1961 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1962 *((FILETIME *)op) = ft; op += 8; /* creation time */
1963 *((FILETIME *)op) = ft; op += 8; /* last access time */
1964 *((FILETIME *)op) = ft; op += 8; /* last write time */
1965 *((FILETIME *)op) = ft; op += 8; /* last change time */
1966 extAttributes = smb_ExtAttributes(scp);
1967 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
1968 *((u_long *)op) = 0; op += 4; /* don't know what this is */
1970 else if (infoLevel == 0x102) {
1971 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
1972 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
1973 *((u_long *)op) = scp->linkCount; op += 4;
1976 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1979 else if (infoLevel == 0x103) {
1980 memset(op, 0, 4); op += 4; /* EA size */
1983 /* now, if we are being asked about extended attrs, return a 0 size */
1984 if (infoLevel == 2) {
1985 *((u_long *)op) = 0; op += 4;
1989 /* send and free the packets */
1991 lock_ReleaseMutex(&scp->mx);
1992 cm_ReleaseSCache(scp);
1993 cm_ReleaseUser(userp);
1995 smb_SendTran2Packet(vcp, outp, opx);
1997 smb_SendTran2Error(vcp, p, opx, code);
1998 smb_FreeTran2Packet(outp);
2003 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2005 return CM_ERROR_BADOP;
2008 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2010 smb_tran2Packet_t *outp;
2012 unsigned long attributes;
2013 unsigned short infoLevel;
2026 fidp = smb_FindFID(vcp, fid, 0);
2029 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2033 infoLevel = p->parmsp[1];
2034 if (infoLevel == 0x101) nbytesRequired = 40;
2035 else if (infoLevel == 0x102) nbytesRequired = 24;
2036 else if (infoLevel == 0x103) nbytesRequired = 4;
2037 else if (infoLevel == 0x104) nbytesRequired = 6;
2039 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2040 p->opcode, infoLevel);
2041 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2042 smb_ReleaseFID(fidp);
2045 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2047 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2049 if (infoLevel > 0x100)
2050 outp->totalParms = 2;
2052 outp->totalParms = 0;
2053 outp->totalData = nbytesRequired;
2055 userp = smb_GetTran2User(vcp, p);
2057 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2058 code = CM_ERROR_BADSMB;
2063 lock_ObtainMutex(&scp->mx);
2064 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2065 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2066 if (code) goto done;
2068 /* now we have the status in the cache entry, and everything is locked.
2069 * Marshall the output data.
2072 if (infoLevel == 0x101) {
2073 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2074 *((FILETIME *)op) = ft; op += 8; /* creation time */
2075 *((FILETIME *)op) = ft; op += 8; /* last access time */
2076 *((FILETIME *)op) = ft; op += 8; /* last write time */
2077 *((FILETIME *)op) = ft; op += 8; /* last change time */
2078 attributes = smb_ExtAttributes(scp);
2079 *((u_long *)op) = attributes; op += 4;
2080 *((u_long *)op) = 0; op += 4;
2082 else if (infoLevel == 0x102) {
2083 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2084 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2085 *((u_long *)op) = scp->linkCount; op += 4;
2086 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
2087 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2091 else if (infoLevel == 0x103) {
2092 *((u_long *)op) = 0; op += 4;
2094 else if (infoLevel == 0x104) {
2098 if (fidp->NTopen_wholepathp)
2099 name = fidp->NTopen_wholepathp;
2101 name = "\\"; /* probably can't happen */
2103 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
2104 *((u_long *)op) = len * 2; op += 4;
2105 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2108 /* send and free the packets */
2110 lock_ReleaseMutex(&scp->mx);
2111 cm_ReleaseUser(userp);
2112 smb_ReleaseFID(fidp);
2113 if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
2114 else smb_SendTran2Error(vcp, p, opx, code);
2115 smb_FreeTran2Packet(outp);
2120 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2125 unsigned short infoLevel;
2126 smb_tran2Packet_t *outp;
2134 fidp = smb_FindFID(vcp, fid, 0);
2137 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
2141 infoLevel = p->parmsp[1];
2142 if (infoLevel > 0x104 || infoLevel < 0x101) {
2143 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2144 p->opcode, infoLevel);
2145 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
2146 smb_ReleaseFID(fidp);
2150 if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
2151 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2152 smb_ReleaseFID(fidp);
2155 if ((infoLevel == 0x103 || infoLevel == 0x104)
2156 && !(fidp->flags & SMB_FID_OPENWRITE)) {
2157 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2158 smb_ReleaseFID(fidp);
2162 osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
2164 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
2166 outp->totalParms = 2;
2167 outp->totalData = 0;
2169 userp = smb_GetTran2User(vcp, p);
2171 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
2172 code = CM_ERROR_BADSMB;
2178 if (infoLevel == 0x101) {
2180 unsigned int attribute;
2183 /* lock the vnode with a callback; we need the current status
2184 * to determine what the new status is, in some cases.
2186 lock_ObtainMutex(&scp->mx);
2187 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2188 CM_SCACHESYNC_GETSTATUS
2189 | CM_SCACHESYNC_NEEDCALLBACK);
2191 lock_ReleaseMutex(&scp->mx);
2195 /* prepare for setattr call */
2198 lastMod = *((FILETIME *)(p->datap + 16));
2199 /* when called as result of move a b, lastMod is (-1, -1).
2200 * If the check for -1 is not present, timestamp
2201 * of the resulting file will be 1969 (-1)
2203 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
2204 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
2205 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
2206 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
2208 fidp->flags |= SMB_FID_MTIMESETDONE;
2211 attribute = *((u_long *)(p->datap + 32));
2212 if (attribute != 0) {
2213 if ((scp->unixModeBits & 0222)
2214 && (attribute & 1) != 0) {
2215 /* make a writable file read-only */
2216 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2217 attr.unixModeBits = scp->unixModeBits & ~0222;
2219 else if ((scp->unixModeBits & 0222) == 0
2220 && (attribute & 1) == 0) {
2221 /* make a read-only file writable */
2222 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2223 attr.unixModeBits = scp->unixModeBits | 0222;
2226 lock_ReleaseMutex(&scp->mx);
2230 code = cm_SetAttr(scp, &attr, userp, &req);
2234 else if (infoLevel == 0x103 || infoLevel == 0x104) {
2235 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
2238 attr.mask = CM_ATTRMASK_LENGTH;
2239 attr.length.LowPart = size.LowPart;
2240 attr.length.HighPart = size.HighPart;
2241 code = cm_SetAttr(scp, &attr, userp, &req);
2243 else if (infoLevel == 0x102) {
2244 if (*((char *)(p->datap))) {
2245 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
2248 fidp->flags |= SMB_FID_DELONCLOSE;
2252 fidp->flags &= ~SMB_FID_DELONCLOSE;
2256 cm_ReleaseUser(userp);
2257 smb_ReleaseFID(fidp);
2258 if (code == 0) smb_SendTran2Packet(vcp, outp, op);
2259 else smb_SendTran2Error(vcp, p, op, code);
2260 smb_FreeTran2Packet(outp);
2265 long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2267 return CM_ERROR_BADOP;
2270 long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2272 return CM_ERROR_BADOP;
2275 long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2277 return CM_ERROR_BADOP;
2280 long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2282 return CM_ERROR_BADOP;
2285 long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2287 return CM_ERROR_BADOP;
2290 long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
2291 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
2296 cm_scache_t *targetScp; /* target if scp is a symlink */
2301 unsigned short attr;
2302 unsigned long lattr;
2303 smb_dirListPatch_t *patchp;
2304 smb_dirListPatch_t *npatchp;
2306 for(patchp = *dirPatchespp; patchp; patchp =
2307 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
2308 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
2310 lock_ObtainMutex(&scp->mx);
2311 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
2312 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2314 lock_ReleaseMutex(&scp->mx);
2315 cm_ReleaseSCache(scp);
2319 /* now watch for a symlink */
2320 if (scp->fileType == CM_SCACHETYPE_SYMLINK) {
2321 lock_ReleaseMutex(&scp->mx);
2322 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
2324 /* we have a more accurate file to use (the
2325 * target of the symbolic link). Otherwise,
2326 * we'll just use the symlink anyway.
2328 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2330 cm_ReleaseSCache(scp);
2333 lock_ObtainMutex(&scp->mx);
2336 dptr = patchp->dptr;
2338 if (infoLevel >= 0x101) {
2340 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2342 /* copy to Creation Time */
2343 *((FILETIME *)dptr) = ft;
2346 /* copy to Last Access Time */
2347 *((FILETIME *)dptr) = ft;
2350 /* copy to Last Write Time */
2351 *((FILETIME *)dptr) = ft;
2354 /* copy to Change Time */
2355 *((FILETIME *)dptr) = ft;
2358 /* Use length for both file length and alloc length */
2359 *((LARGE_INTEGER *)dptr) = scp->length;
2361 *((LARGE_INTEGER *)dptr) = scp->length;
2364 /* Copy attributes */
2365 lattr = smb_ExtAttributes(scp);
2366 /* merge in hidden (dot file) attribute */
2367 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
2368 lattr |= SMB_ATTR_HIDDEN;
2369 *((u_long *)dptr) = lattr;
2374 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2376 /* and copy out date */
2377 shortTemp = (dosTime>>16) & 0xffff;
2378 *((u_short *)dptr) = shortTemp;
2381 /* copy out creation time */
2382 shortTemp = dosTime & 0xffff;
2383 *((u_short *)dptr) = shortTemp;
2386 /* and copy out date */
2387 shortTemp = (dosTime>>16) & 0xffff;
2388 *((u_short *)dptr) = shortTemp;
2391 /* copy out access time */
2392 shortTemp = dosTime & 0xffff;
2393 *((u_short *)dptr) = shortTemp;
2396 /* and copy out date */
2397 shortTemp = (dosTime>>16) & 0xffff;
2398 *((u_short *)dptr) = shortTemp;
2401 /* copy out mod time */
2402 shortTemp = dosTime & 0xffff;
2403 *((u_short *)dptr) = shortTemp;
2406 /* copy out file length and alloc length,
2407 * using the same for both
2409 *((u_long *)dptr) = scp->length.LowPart;
2411 *((u_long *)dptr) = scp->length.LowPart;
2414 /* finally copy out attributes as short */
2415 attr = smb_Attributes(scp);
2416 /* merge in hidden (dot file) attribute */
2417 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
2418 attr |= SMB_ATTR_HIDDEN;
2419 *dptr++ = attr & 0xff;
2420 *dptr++ = (attr >> 8) & 0xff;
2423 lock_ReleaseMutex(&scp->mx);
2424 cm_ReleaseSCache(scp);
2427 /* now free the patches */
2428 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
2429 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
2433 /* and mark the list as empty */
2434 *dirPatchespp = NULL;
2439 #ifndef USE_OLD_MATCHING
2440 // char table for case insensitive comparison
2441 char mapCaseTable[256];
2443 VOID initUpperCaseTable(VOID)
2446 for (i = 0; i < 256; ++i)
2447 mapCaseTable[i] = toupper(i);
2448 // make '"' match '.'
2449 mapCaseTable[(int)'"'] = toupper('.');
2452 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
2454 // Note : this procedure works recursively calling itself.
2456 // PSZ pattern : string containing metacharacters.
2457 // PSZ name : file name to be compared with 'pattern'.
2459 // BOOL : TRUE/FALSE (match/mistmatch)
2461 BOOL szWildCardMatchFileName(PSZ pattern, PSZ name) {
2462 PSZ pename; // points to the last 'name' character
2464 pename = name + strlen(name) - 1;
2468 if (*(++pattern) != '<' || *(++pattern) != '*') {
2469 if (*name == '.') return FALSE;
2475 while ((*pattern == '<') || (*pattern == '*') || (*pattern == '?')) ++pattern;
2476 if (!*pattern) return TRUE;
2477 for (p = pename; p >= name; --p) {
2478 if ((mapCaseTable[*p] == mapCaseTable[*pattern]) &&
2479 szWildCardMatchFileName(pattern + 1, p + 1))
2484 if (mapCaseTable[*name] != mapCaseTable[*pattern]) return FALSE;
2488 } /* endwhile */ return !*pattern;
2491 /* do a case-folding search of the star name mask with the name in namep.
2492 * Return 1 if we match, otherwise 0.
2494 int smb_V3MatchMask(char *namep, char *maskp, int flags)
2496 /* make sure we only match 8.3 names, if requested */
2497 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
2500 return szWildCardMatchFileName(maskp, namep) ? 1:0;
2503 #else /* USE_OLD_MATCHING */
2504 /* do a case-folding search of the star name mask with the name in namep.
2505 * Return 1 if we match, otherwise 0.
2507 int smb_V3MatchMask(char *namep, char *maskp, int flags)
2509 unsigned char tcp1, tcp2; /* Pattern characters */
2510 unsigned char tcn1; /* Name characters */
2511 int sawDot = 0, sawStar = 0, req8dot3 = 0;
2512 char *starNamep, *starMaskp;
2513 static char nullCharp[] = {0};
2514 int casefold = flags & CM_FLAG_CASEFOLD;
2516 /* make sure we only match 8.3 names, if requested */
2517 req8dot3 = (flags & CM_FLAG_8DOT3);
2518 if (req8dot3 && !cm_Is8Dot3(namep))
2523 /* Next pattern character */
2526 /* Next name character */
2530 /* 0 - end of pattern */
2536 else if (tcp1 == '.' || tcp1 == '"') {
2546 * first dot in pattern;
2547 * must match dot or end of name
2552 else if (tcn1 == '.') {
2561 else if (tcp1 == '?') {
2562 if (tcn1 == 0 || tcn1 == '.')
2567 else if (tcp1 == '>') {
2568 if (tcn1 != 0 && tcn1 != '.')
2572 else if (tcp1 == '*' || tcp1 == '<') {
2576 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
2577 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
2592 * pattern character after '*' is not null or
2593 * period. If it is '?' or '>', we are not
2594 * going to understand it. If it is '*' or
2595 * '<', we are going to skip over it. None of
2596 * these are likely, I hope.
2598 /* skip over '*' and '<' */
2599 while (tcp2 == '*' || tcp2 == '<')
2602 /* skip over characters that don't match tcp2 */
2603 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
2604 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
2605 (!casefold && tcn1 != tcp2)))
2609 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
2612 /* Remember where we are */
2622 /* tcp1 is not a wildcard */
2623 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
2624 (!casefold && tcn1 == tcp1)) {
2629 /* if trying to match a star pattern, go back */
2631 maskp = starMaskp - 2;
2632 namep = starNamep + 1;
2641 #endif /* USE_OLD_MATCHING */
2643 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2652 smb_dirListPatch_t *dirListPatchesp;
2653 smb_dirListPatch_t *curPatchp;
2656 long orbytes; /* # of bytes in this output record */
2657 long ohbytes; /* # of bytes, except file name */
2658 long onbytes; /* # of bytes in name, incl. term. null */
2659 osi_hyper_t dirLength;
2660 osi_hyper_t bufferOffset;
2661 osi_hyper_t curOffset;
2663 smb_dirSearch_t *dsp;
2667 cm_pageHeader_t *pageHeaderp;
2668 cm_user_t *userp = NULL;
2671 long nextEntryCookie;
2672 int numDirChunks; /* # of 32 byte dir chunks in this entry */
2673 char *op; /* output data ptr */
2674 char *origOp; /* original value of op */
2675 cm_space_t *spacep; /* for pathname buffer */
2676 long maxReturnData; /* max # of return data */
2677 long maxReturnParms; /* max # of return parms */
2678 long bytesInBuffer; /* # data bytes in the output buffer */
2680 char *maskp; /* mask part of path */
2684 smb_tran2Packet_t *outp; /* response packet */
2687 char shortName[13]; /* 8.3 name if needed */
2699 if (p->opcode == 1) {
2700 /* find first; obtain basic parameters from request */
2701 attribute = p->parmsp[0];
2702 maxCount = p->parmsp[1];
2703 infoLevel = p->parmsp[3];
2704 searchFlags = p->parmsp[2];
2705 dsp = smb_NewDirSearch(1);
2706 dsp->attribute = attribute;
2707 pathp = ((char *) p->parmsp) + 12; /* points to path */
2709 maskp = strrchr(pathp, '\\');
2710 if (maskp == NULL) maskp = pathp;
2711 else maskp++; /* skip over backslash */
2712 strcpy(dsp->mask, maskp); /* and save mask */
2713 /* track if this is likely to match a lot of entries */
2714 starPattern = smb_V3IsStarMask(maskp);
2717 osi_assert(p->opcode == 2);
2718 /* find next; obtain basic parameters from request or open dir file */
2719 dsp = smb_FindDirSearch(p->parmsp[0]);
2720 if (!dsp) return CM_ERROR_BADFD;
2721 attribute = dsp->attribute;
2722 maxCount = p->parmsp[1];
2723 infoLevel = p->parmsp[2];
2724 searchFlags = p->parmsp[5];
2726 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
2728 starPattern = 1; /* assume, since required a Find Next */
2732 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
2733 attribute, infoLevel, maxCount, searchFlags);
2735 osi_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
2736 p->opcode, nextCookie);
2738 if (infoLevel >= 0x101)
2739 searchFlags &= ~4; /* no resume keys */
2741 dirListPatchesp = NULL;
2743 maxReturnData = p->maxReturnData;
2744 if (p->opcode == 1) /* find first */
2745 maxReturnParms = 10; /* bytes */
2747 maxReturnParms = 8; /* bytes */
2749 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
2750 if (maxReturnData > 6000)
2751 maxReturnData = 6000;
2752 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
2754 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
2757 osi_Log1(smb_logp, "T2 receive search dir %s",
2758 osi_LogSaveString(smb_logp, pathp));
2760 /* bail out if request looks bad */
2761 if (p->opcode == 1 && !pathp) {
2762 smb_ReleaseDirSearch(dsp);
2763 smb_FreeTran2Packet(outp);
2764 return CM_ERROR_BADSMB;
2767 osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
2768 nextCookie, dsp->cookie);
2770 userp = smb_GetTran2User(vcp, p);
2772 osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p->uid);
2773 smb_ReleaseDirSearch(dsp);
2774 smb_FreeTran2Packet(outp);
2775 return CM_ERROR_BADSMB;
2778 /* try to get the vnode for the path name next */
2779 lock_ObtainMutex(&dsp->mx);
2786 spacep = cm_GetSpace();
2787 smb_StripLastComponent(spacep->data, NULL, pathp);
2788 lock_ReleaseMutex(&dsp->mx);
2790 tidPathp = smb_GetTIDPath(vcp, p->tid);
2791 code = cm_NameI(cm_rootSCachep, spacep->data,
2792 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2793 userp, tidPathp, &req, &scp);
2794 cm_FreeSpace(spacep);
2796 lock_ObtainMutex(&dsp->mx);
2798 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
2800 /* we need one hold for the entry we just stored into,
2801 * and one for our own processing. When we're done
2802 * with this function, we'll drop the one for our own
2803 * processing. We held it once from the namei call,
2804 * and so we do another hold now.
2807 lock_ObtainMutex(&scp->mx);
2808 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
2809 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
2810 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
2811 dsp->flags |= SMB_DIRSEARCH_BULKST;
2813 lock_ReleaseMutex(&scp->mx);
2816 lock_ReleaseMutex(&dsp->mx);
2818 cm_ReleaseUser(userp);
2819 smb_FreeTran2Packet(outp);
2820 smb_DeleteDirSearch(dsp);
2821 smb_ReleaseDirSearch(dsp);
2825 /* get the directory size */
2826 lock_ObtainMutex(&scp->mx);
2827 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2828 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2830 lock_ReleaseMutex(&scp->mx);
2831 cm_ReleaseSCache(scp);
2832 cm_ReleaseUser(userp);
2833 smb_FreeTran2Packet(outp);
2834 smb_DeleteDirSearch(dsp);
2835 smb_ReleaseDirSearch(dsp);
2840 dirLength = scp->length;
2842 bufferOffset.LowPart = bufferOffset.HighPart = 0;
2843 curOffset.HighPart = 0;
2844 curOffset.LowPart = nextCookie;
2845 origOp = outp->datap;
2853 if (searchFlags & 4)
2854 /* skip over resume key */
2857 /* make sure that curOffset.LowPart doesn't point to the first
2858 * 32 bytes in the 2nd through last dir page, and that it doesn't
2859 * point at the first 13 32-byte chunks in the first dir page,
2860 * since those are dir and page headers, and don't contain useful
2863 temp = curOffset.LowPart & (2048-1);
2864 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
2865 /* we're in the first page */
2866 if (temp < 13*32) temp = 13*32;
2869 /* we're in a later dir page */
2870 if (temp < 32) temp = 32;
2873 /* make sure the low order 5 bits are zero */
2876 /* now put temp bits back ito curOffset.LowPart */
2877 curOffset.LowPart &= ~(2048-1);
2878 curOffset.LowPart |= temp;
2880 /* check if we've passed the dir's EOF */
2881 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
2886 /* check if we've returned all the names that will fit in the
2887 * response packet; we check return count as well as the number
2888 * of bytes requested. We check the # of bytes after we find
2889 * the dir entry, since we'll need to check its size.
2891 if (returnedNames >= maxCount) {
2895 /* see if we can use the bufferp we have now; compute in which
2896 * page the current offset would be, and check whether that's
2897 * the offset of the buffer we have. If not, get the buffer.
2899 thyper.HighPart = curOffset.HighPart;
2900 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
2901 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
2904 buf_Release(bufferp);
2907 lock_ReleaseMutex(&scp->mx);
2908 lock_ObtainRead(&scp->bufCreateLock);
2909 code = buf_Get(scp, &thyper, &bufferp);
2910 lock_ReleaseRead(&scp->bufCreateLock);
2912 /* now, if we're doing a star match, do bulk fetching
2913 * of all of the status info for files in the dir.
2916 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
2919 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
2920 && LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
2921 /* Don't bulk stat if risking timeout */
2922 int now = GetCurrentTime();
2923 if (now - req.startTime > 5000) {
2924 scp->bulkStatProgress = thyper;
2925 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2926 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2928 cm_TryBulkStat(scp, &thyper, userp, &req);
2932 lock_ObtainMutex(&scp->mx);
2934 bufferOffset = thyper;
2936 /* now get the data in the cache */
2938 code = cm_SyncOp(scp, bufferp, userp, &req,
2940 CM_SCACHESYNC_NEEDCALLBACK
2941 | CM_SCACHESYNC_READ);
2944 if (cm_HaveBuffer(scp, bufferp, 0)) break;
2946 /* otherwise, load the buffer and try again */
2947 code = cm_GetBuffer(scp, bufferp, NULL, userp,
2952 buf_Release(bufferp);
2956 } /* if (wrong buffer) ... */
2958 /* now we have the buffer containing the entry we're interested
2959 * in; copy it out if it represents a non-deleted entry.
2961 entryInDir = curOffset.LowPart & (2048-1);
2962 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
2964 /* page header will help tell us which entries are free. Page
2965 * header can change more often than once per buffer, since
2966 * AFS 3 dir page size may be less than (but not more than)
2967 * a buffer package buffer.
2969 /* only look intra-buffer */
2970 temp = curOffset.LowPart & (buf_bufferSize - 1);
2971 temp &= ~(2048 - 1); /* turn off intra-page bits */
2972 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
2974 /* now determine which entry we're looking at in the page.
2975 * If it is free (there's a free bitmap at the start of the
2976 * dir), we should skip these 32 bytes.
2978 slotInPage = (entryInDir & 0x7e0) >> 5;
2979 if (!(pageHeaderp->freeBitmap[slotInPage>>3]
2980 & (1 << (slotInPage & 0x7)))) {
2981 /* this entry is free */
2982 numDirChunks = 1; /* only skip this guy */
2986 tp = bufferp->datap + entryInBuffer;
2987 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
2989 /* while we're here, compute the next entry's location, too,
2990 * since we'll need it when writing out the cookie into the dir
2993 * XXXX Probably should do more sanity checking.
2995 numDirChunks = cm_NameEntries(dep->name, &onbytes);
2997 /* compute offset of cookie representing next entry */
2998 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3000 /* Need 8.3 name? */
3002 if (infoLevel == 0x104
3003 && dep->fid.vnode != 0
3004 && !cm_Is8Dot3(dep->name)) {
3005 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3009 /* When matching, we are using doing a case fold if we have a wildcard mask.
3010 * If we get a non-wildcard match, it's a lookup for a specific file.
3012 if (dep->fid.vnode != 0 &&
3013 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0))
3015 && smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
3017 /* Eliminate entries that don't match requested attributes */
3018 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
3019 smb_IsDotFile(dep->name))
3020 goto nextEntry; /* no hidden files */
3022 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3024 /* We have already done the cm_TryBulkStat above */
3025 fid.cell = scp->fid.cell;
3026 fid.volume = scp->fid.volume;
3027 fid.vnode = ntohl(dep->fid.vnode);
3028 fid.unique = ntohl(dep->fid.unique);
3029 fileType = cm_FindFileType(&fid);
3030 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
3031 "has filetype %d", dep->name,
3033 if (fileType == CM_SCACHETYPE_DIRECTORY)
3037 /* finally check if this name will fit */
3039 /* standard dir entry stuff */
3040 if (infoLevel < 0x101)
3041 ohbytes = 23; /* pre-NT */
3042 else if (infoLevel == 0x103)
3043 ohbytes = 12; /* NT names only */
3045 ohbytes = 64; /* NT */
3047 if (infoLevel == 0x104)
3048 ohbytes += 26; /* Short name & length */
3050 if (searchFlags & 4) {
3051 ohbytes += 4; /* if resume key required */
3055 && infoLevel != 0x101
3056 && infoLevel != 0x103)
3057 ohbytes += 4; /* EASIZE */
3059 /* add header to name & term. null */
3060 orbytes = onbytes + ohbytes + 1;
3062 /* now, we round up the record to a 4 byte alignment,
3063 * and we make sure that we have enough room here for
3064 * even the aligned version (so we don't have to worry
3065 * about an * overflow when we pad things out below).
3066 * That's the reason for the alignment arithmetic below.
3068 if (infoLevel >= 0x101)
3069 align = (4 - (orbytes & 3)) & 3;
3072 if (orbytes + bytesInBuffer + align > maxReturnData)
3075 /* this is one of the entries to use: it is not deleted
3076 * and it matches the star pattern we're looking for.
3077 * Put out the name, preceded by its length.
3079 /* First zero everything else */
3080 memset(origOp, 0, ohbytes);
3082 if (infoLevel <= 0x101)
3083 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
3084 else if (infoLevel == 0x103)
3085 *((u_long *)(op + 8)) = onbytes;
3087 *((u_long *)(op + 60)) = onbytes;
3088 strcpy(origOp+ohbytes, dep->name);
3090 /* Short name if requested and needed */
3091 if (infoLevel == 0x104) {
3092 if (NeedShortName) {
3093 strcpy(op + 70, shortName);
3094 *(op + 68) = shortNameEnd - shortName;
3098 /* now, adjust the # of entries copied */
3101 /* NextEntryOffset and FileIndex */
3102 if (infoLevel >= 101) {
3103 int entryOffset = orbytes + align;
3104 *((u_long *)op) = entryOffset;
3105 *((u_long *)(op+4)) = nextEntryCookie;
3108 /* now we emit the attribute. This is tricky, since
3109 * we need to really stat the file to find out what
3110 * type of entry we've got. Right now, we're copying
3111 * out data from * a buffer, while holding the scp
3112 * locked, so it isn't really convenient to stat
3113 * something now. We'll put in a place holder
3114 * now, and make a second pass before returning this
3115 * to get the real attributes. So, we just skip the
3116 * data for now, and adjust it later. We allocate a
3117 * patch record to make it easy to find this point
3118 * later. The replay will happen at a time when it is
3119 * safe to unlock the directory.
3121 if (infoLevel != 0x103) {
3122 curPatchp = malloc(sizeof(*curPatchp));
3123 osi_QAdd((osi_queue_t **) &dirListPatchesp,
3125 curPatchp->dptr = op;
3126 if (infoLevel >= 0x101)
3127 curPatchp->dptr += 8;
3129 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
3130 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3133 curPatchp->flags = 0;
3135 curPatchp->fid.cell = scp->fid.cell;
3136 curPatchp->fid.volume = scp->fid.volume;
3137 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3138 curPatchp->fid.unique = ntohl(dep->fid.unique);
3141 curPatchp->dep = dep;
3144 if (searchFlags & 4)
3145 /* put out resume key */
3146 *((u_long *)origOp) = nextEntryCookie;
3148 /* Adjust byte ptr and count */
3149 origOp += orbytes; /* skip entire record */
3150 bytesInBuffer += orbytes;
3152 /* and pad the record out */
3153 while (--align >= 0) {
3158 } /* if we're including this name */
3159 else if (!NeedShortName &&
3162 dep->fid.vnode != 0 &&
3163 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
3164 /* We were looking for exact matches, but here's an inexact one*/
3169 /* and adjust curOffset to be where the new cookie is */
3170 thyper.HighPart = 0;
3171 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3172 curOffset = LargeIntegerAdd(thyper, curOffset);
3173 } /* while copying data for dir listing */
3175 /* If we didn't get a star pattern, we did an exact match during the first pass.
3176 * If there were no exact matches found, we fail over to inexact matches by
3177 * marking the query as a star pattern (matches all case permutations), and
3178 * re-running the query.
3180 if (returnedNames == 0 && !starPattern && foundInexact) {
3181 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
3186 /* release the mutex */
3187 lock_ReleaseMutex(&scp->mx);
3188 if (bufferp) buf_Release(bufferp);
3190 /* apply and free last set of patches; if not doing a star match, this
3191 * will be empty, but better safe (and freeing everything) than sorry.
3193 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
3196 /* now put out the final parameters */
3197 if (returnedNames == 0) eos = 1;
3198 if (p->opcode == 1) {
3200 outp->parmsp[0] = (unsigned short) dsp->cookie;
3201 outp->parmsp[1] = returnedNames;
3202 outp->parmsp[2] = eos;
3203 outp->parmsp[3] = 0; /* nothing wrong with EAS */
3204 outp->parmsp[4] = 0;
3205 /* don't need last name to continue
3206 * search, cookie is enough. Normally,
3207 * this is the offset of the file name
3208 * of the last entry returned.
3210 outp->totalParms = 10; /* in bytes */
3214 outp->parmsp[0] = returnedNames;
3215 outp->parmsp[1] = eos;
3216 outp->parmsp[2] = 0; /* EAS error */
3217 outp->parmsp[3] = 0; /* last name, as above */
3218 outp->totalParms = 8; /* in bytes */
3221 /* return # of bytes in the buffer */
3222 outp->totalData = bytesInBuffer;
3224 osi_Log2(smb_logp, "T2 search dir done, %d names, code %d",
3225 returnedNames, code);
3227 /* Return error code if unsuccessful on first request */
3228 if (code == 0 && p->opcode == 1 && returnedNames == 0)
3229 code = CM_ERROR_NOSUCHFILE;
3231 /* if we're supposed to close the search after this request, or if
3232 * we're supposed to close the search if we're done, and we're done,
3233 * or if something went wrong, close the search.
3235 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
3236 if ((searchFlags & 1) || (returnedNames == 0) ||
3237 ((searchFlags & 2) && eos) || code != 0)
3238 smb_DeleteDirSearch(dsp);
3240 smb_SendTran2Error(vcp, p, opx, code);
3242 smb_SendTran2Packet(vcp, outp, opx);
3244 smb_FreeTran2Packet(outp);
3245 smb_ReleaseDirSearch(dsp);
3246 cm_ReleaseSCache(scp);
3247 cm_ReleaseUser(userp);
3251 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3254 smb_dirSearch_t *dsp;
3256 dirHandle = smb_GetSMBParm(inp, 0);
3258 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
3260 dsp = smb_FindDirSearch(dirHandle);
3263 return CM_ERROR_BADFD;
3265 /* otherwise, we have an FD to destroy */
3266 smb_DeleteDirSearch(dsp);
3267 smb_ReleaseDirSearch(dsp);
3269 /* and return results */
3270 smb_SetSMBDataLength(outp, 0);
3275 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3277 smb_SetSMBDataLength(outp, 0);
3281 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3288 cm_scache_t *dscp; /* dir we're dealing with */
3289 cm_scache_t *scp; /* file we're creating */
3291 int initialModeBits;
3301 int parmSlot; /* which parm we're dealing with */
3309 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
3310 openFun = smb_GetSMBParm(inp, 8); /* open function */
3311 excl = ((openFun & 3) == 0);
3312 trunc = ((openFun & 3) == 2); /* truncate it */
3313 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
3314 openAction = 0; /* tracks what we did */
3316 attributes = smb_GetSMBParm(inp, 5);
3317 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
3319 /* compute initial mode bits based on read-only flag in attributes */
3320 initialModeBits = 0666;
3321 if (attributes & 1) initialModeBits &= ~0222;
3323 pathp = smb_GetSMBData(inp, NULL);
3325 spacep = inp->spacep;
3326 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
3328 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3329 /* special case magic file name for receiving IOCTL requests
3330 * (since IOCTL calls themselves aren't getting through).
3333 osi_Log0(smb_logp, "IOCTL Open");
3336 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3337 smb_SetupIoctlFid(fidp, spacep);
3339 /* set inp->fid so that later read calls in same msg can find fid */
3340 inp->fid = fidp->fid;
3342 /* copy out remainder of the parms */
3344 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3346 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
3347 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
3348 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
3349 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
3350 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
3351 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
3352 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
3353 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
3355 /* and the final "always present" stuff */
3356 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
3357 /* next write out the "unique" ID */
3358 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
3359 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
3360 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
3361 smb_SetSMBDataLength(outp, 0);