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 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
39 /* protected by the smb_globalLock */
40 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
42 /* retrieve a held reference to a user structure corresponding to an incoming
44 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
49 uidp = smb_FindUID(vcp, inp->uid, 0);
50 if (!uidp) return NULL;
52 lock_ObtainMutex(&uidp->mx);
54 up = uidp->unp->userp;
57 lock_ReleaseMutex(&uidp->mx);
65 * Return extended attributes.
66 * Right now, we aren't using any of the "new" bits, so this looks exactly
67 * like smb_Attributes() (see smb.c).
69 unsigned long smb_ExtAttributes(cm_scache_t *scp)
73 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
74 scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
76 attrs = SMB_ATTR_DIRECTORY;
77 #ifdef SPECIAL_FOLDERS
78 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
79 #endif /* SPECIAL_FOLDERS */
83 * We used to mark a file RO if it was in an RO volume, but that
84 * turns out to be impolitic in NT. See defect 10007.
87 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
89 if ((scp->unixModeBits & 0222) == 0)
90 attrs |= SMB_ATTR_READONLY; /* Read-only */
93 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
98 int smb_V3IsStarMask(char *maskp)
102 while (tc = *maskp++)
103 if (tc == '?' || tc == '*')
108 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
111 /* skip over null-terminated string */
112 *chainpp = inp + strlen(inp) + 1;
117 /*DEBUG do not checkin*/
118 void OutputDebugF(char * format, ...) {
123 va_start( args, format );
124 len = _vscprintf( format, args ) // _vscprintf doesn't count
125 + 3; // terminating '\0' + '\n'
126 buffer = malloc( len * sizeof(char) );
127 vsprintf( buffer, format, args );
128 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buffer));
129 strcat(buffer, "\n");
130 OutputDebugString(buffer);
134 void OutputDebugHexDump(unsigned char * buffer, int len) {
137 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
139 OutputDebugF("Hexdump length [%d]",len);
141 for (i=0;i<len;i++) {
144 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
146 OutputDebugString(buf);
148 sprintf(buf,"%5x",i);
149 memset(buf+5,' ',80);
154 j = j*3 + 7 + ((j>7)?1:0);
157 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
160 j = j + 56 + ((j>7)?1:0);
162 buf[j] = (k>32 && k<127)?k:'.';
165 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
167 OutputDebugString(buf);
172 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
173 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
174 SECURITY_STATUS status, istatus;
175 CredHandle creds = {0,0};
177 SecBufferDesc secOut;
185 OutputDebugF("Negotiating Extended Security");
187 status = AcquireCredentialsHandle( NULL,
188 SMB_EXT_SEC_PACKAGE_NAME,
197 if (status != SEC_E_OK) {
198 /* Really bad. We return an empty security blob */
199 OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
204 secOut.pBuffers = &secTok;
205 secOut.ulVersion = SECBUFFER_VERSION;
207 secTok.BufferType = SECBUFFER_TOKEN;
209 secTok.pvBuffer = NULL;
211 ctx.dwLower = ctx.dwUpper = 0;
213 status = AcceptSecurityContext( &creds,
216 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
217 SECURITY_NETWORK_DREP,
224 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
225 OutputDebugF("Completing token...");
226 istatus = CompleteAuthToken(&ctx, &secOut);
227 if ( istatus != SEC_E_OK )
228 OutputDebugF("Token completion failed: %x", istatus);
231 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
232 if (secTok.pvBuffer) {
233 *secBlobLength = secTok.cbBuffer;
234 *secBlob = malloc( secTok.cbBuffer );
235 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
238 if ( status != SEC_E_OK )
239 OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
242 /* Discard partial security context */
243 DeleteSecurityContext(&ctx);
245 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
247 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
248 FreeCredentialsHandle(&creds);
254 struct smb_ext_context {
261 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
262 SECURITY_STATUS status, istatus;
266 SecBufferDesc secBufIn;
268 SecBufferDesc secBufOut;
271 struct smb_ext_context * secCtx = NULL;
272 struct smb_ext_context * newSecCtx = NULL;
273 void * assembledBlob = NULL;
274 int assembledBlobLength = 0;
277 OutputDebugF("In smb_AuthenticateUserExt");
280 *secBlobOutLength = 0;
282 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
283 secCtx = vcp->secCtx;
284 lock_ObtainMutex(&vcp->mx);
285 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
287 lock_ReleaseMutex(&vcp->mx);
291 OutputDebugF("Received incoming token:");
292 OutputDebugHexDump(secBlobIn,secBlobInLength);
296 OutputDebugF("Continuing with existing context.");
297 creds = secCtx->creds;
300 if (secCtx->partialToken) {
301 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
302 assembledBlob = malloc(assembledBlobLength);
303 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
304 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
307 status = AcquireCredentialsHandle( NULL,
308 SMB_EXT_SEC_PACKAGE_NAME,
317 if (status != SEC_E_OK) {
318 OutputDebugF("Can't acquire Credentials handle [%lX]", status);
319 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
327 secBufIn.cBuffers = 1;
328 secBufIn.pBuffers = &secTokIn;
329 secBufIn.ulVersion = SECBUFFER_VERSION;
331 secTokIn.BufferType = SECBUFFER_TOKEN;
333 secTokIn.cbBuffer = assembledBlobLength;
334 secTokIn.pvBuffer = assembledBlob;
336 secTokIn.cbBuffer = secBlobInLength;
337 secTokIn.pvBuffer = secBlobIn;
340 secBufOut.cBuffers = 1;
341 secBufOut.pBuffers = &secTokOut;
342 secBufOut.ulVersion = SECBUFFER_VERSION;
344 secTokOut.BufferType = SECBUFFER_TOKEN;
345 secTokOut.cbBuffer = 0;
346 secTokOut.pvBuffer = NULL;
348 status = AcceptSecurityContext( &creds,
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 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
518 OutputDebugF("ciPwdLength or csPwdLength is too long");
519 return CM_ERROR_BADPASSWORD;
522 memset(&lmAuth,0,sizeof(lmAuth));
524 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
526 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
527 mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
528 lmAuth.lmlogon.LogonDomainName.Length = wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR);
529 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
531 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
532 mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
533 lmAuth.lmlogon.UserName.Length = wcslen(lmAuth.accountNameW) * sizeof(WCHAR);
534 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
536 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
537 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
538 size = MAX_COMPUTERNAME_LENGTH + 1;
539 GetComputerNameW(lmAuth.workstationW, &size);
540 lmAuth.lmlogon.Workstation.Length = wcslen(lmAuth.workstationW) * sizeof(WCHAR);
542 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
544 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
545 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
546 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
547 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
549 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
550 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
551 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
552 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
554 lmAuth.lmlogon.ParameterControl = 0;
556 lmAuth.tgroups.GroupCount = 0;
557 lmAuth.tgroups.Groups[0].Sid = NULL;
558 lmAuth.tgroups.Groups[0].Attributes = 0;
560 lmAuth.tsource.SourceIdentifier.HighPart = 0;
561 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD) vcp;
562 strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
564 nts = LsaLogonUser( smb_lsaHandle,
579 OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
580 OutputDebugF("Extended status is 0x%lX", ntsEx);
582 if (nts == ERROR_SUCCESS) {
584 LsaFreeReturnBuffer(lmprofilep);
585 CloseHandle(lmToken);
589 if (nts == 0xC000015BL)
590 return CM_ERROR_BADLOGONTYPE;
591 else /* our catchall is a bad password though we could be more specific */
592 return CM_ERROR_BADPASSWORD;
596 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
597 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName)
602 /* check if we have sane input */
603 if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
606 /* we could get : [accountName][domainName]
612 atsign = strchr(accountName, '@');
614 if (atsign) /* [user@domain][] -> [user@domain][domain] */
619 /* if for some reason the client doesn't know what domain to use,
620 it will either return an empty string or a '?' */
621 if (!domain[0] || domain[0] == '?')
622 /* Empty domains and empty usernames are usually sent from tokenless contexts.
623 This way such logins will get an empty username (easy to check). I don't know
624 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
625 strcpy(usern,accountName);
627 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
628 strcpy(usern,domain);
631 strncat(usern,accountName,atsign - accountName);
633 strcat(usern,accountName);
641 /* When using SMB auth, all SMB sessions have to pass through here first to
642 * authenticate the user.
643 * Caveat: If not use the SMB auth the protocol does not require sending a
644 * session setup packet, which means that we can't rely on a UID in subsequent
645 * packets. Though in practice we get one anyway.
647 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
651 unsigned short newUid;
652 unsigned long caps = 0;
657 char usern[SMB_MAX_USERNAME_LENGTH];
658 char *secBlobOut = NULL;
659 int secBlobOutLength = 0;
661 /* Check for bad conns */
662 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
663 return CM_ERROR_REMOTECONN;
665 if (vcp->flags & SMB_VCFLAG_USENT) {
666 if (smb_authType == SMB_AUTH_EXTENDED) {
667 /* extended authentication */
671 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
672 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
675 secBlobInLength = smb_GetSMBParm(inp, 7);
676 secBlobIn = smb_GetSMBData(inp, NULL);
678 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
680 if (code == CM_ERROR_GSSCONTINUE) {
681 smb_SetSMBParm(outp, 2, 0);
682 smb_SetSMBParm(outp, 3, secBlobOutLength);
683 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
684 tp = smb_GetSMBData(outp, NULL);
685 if (secBlobOutLength) {
686 memcpy(tp, secBlobOut, secBlobOutLength);
688 tp += secBlobOutLength;
690 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
691 tp += smb_ServerOSLength;
692 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
693 tp += smb_ServerLanManagerLength;
694 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
695 tp += smb_ServerDomainNameLength;
698 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
700 unsigned ciPwdLength, csPwdLength;
706 /* TODO: parse for extended auth as well */
707 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
708 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
710 tp = smb_GetSMBData(inp, &datalen);
712 OutputDebugF("Session packet data size [%d]",datalen);
719 accountName = smb_ParseString(tp, &tp);
720 primaryDomain = smb_ParseString(tp, NULL);
722 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
723 /* shouldn't happen */
724 code = CM_ERROR_BADSMB;
725 goto after_read_packet;
728 /* capabilities are only valid for first session packet */
729 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
730 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
733 if (smb_authType == SMB_AUTH_NTLM) {
734 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
738 unsigned ciPwdLength;
743 ciPwdLength = smb_GetSMBParm(inp, 7);
744 tp = smb_GetSMBData(inp, NULL);
748 accountName = smb_ParseString(tp, &tp);
749 primaryDomain = smb_ParseString(tp, NULL);
751 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
752 /* shouldn't happen */
753 code = CM_ERROR_BADSMB;
754 goto after_read_packet;
757 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
760 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
761 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
766 /* note down that we received a session setup X and set the capabilities flag */
767 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
768 lock_ObtainMutex(&vcp->mx);
769 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
770 /* for the moment we can only deal with NTSTATUS */
771 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
772 vcp->flags |= SMB_VCFLAG_STATUS32;
774 lock_ReleaseMutex(&vcp->mx);
777 /* code would be non-zero if there was an authentication failure.
778 Ideally we would like to invalidate the uid for this session or break
779 early to avoid accidently stealing someone else's tokens. */
785 OutputDebugF("Received username=[%s]", usern);
787 /* On Windows 2000, this function appears to be called more often than
788 it is expected to be called. This resulted in multiple smb_user_t
789 records existing all for the same user session which results in all
790 of the users tokens disappearing.
792 To avoid this problem, we look for an existing smb_user_t record
793 based on the users name, and use that one if we find it.
796 uidp = smb_FindUserByNameThisSession(vcp, usern);
797 if (uidp) { /* already there, so don't create a new one */
800 newUid = (unsigned short)uidp->userID; /* For some reason these are different types!*/
801 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"FindUserByName:Lana[%d],lsn[%d],userid[%d],name[%s]",vcp->lana,vcp->lsn,newUid,osi_LogSaveString(smb_logp, usern));
802 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
803 smb_ReleaseUID(uidp);
806 /* do a global search for the username/machine name pair */
807 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
809 /* Create a new UID and cm_user_t structure */
812 userp = cm_NewUser();
813 lock_ObtainMutex(&vcp->mx);
814 if (!vcp->uidCounter)
815 vcp->uidCounter++; /* handle unlikely wraparounds */
816 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
817 lock_ReleaseMutex(&vcp->mx);
819 /* Create a new smb_user_t structure and connect them up */
820 lock_ObtainMutex(&unp->mx);
822 lock_ReleaseMutex(&unp->mx);
824 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
825 lock_ObtainMutex(&uidp->mx);
827 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d],TicketKTCName[%s]",(int)vcp,vcp->lana,vcp->lsn,newUid,osi_LogSaveString(smb_logp, usern));
828 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
829 lock_ReleaseMutex(&uidp->mx);
830 smb_ReleaseUID(uidp);
833 /* Return UID to the client */
834 ((smb_t *)outp)->uid = newUid;
835 /* Also to the next chained message */
836 ((smb_t *)inp)->uid = newUid;
838 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
839 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
841 smb_SetSMBParm(outp, 2, 0);
843 if (vcp->flags & SMB_VCFLAG_USENT) {
844 if (smb_authType == SMB_AUTH_EXTENDED) {
845 smb_SetSMBParm(outp, 3, secBlobOutLength);
846 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
847 tp = smb_GetSMBData(outp, NULL);
848 if (secBlobOutLength) {
849 memcpy(tp, secBlobOut, secBlobOutLength);
851 tp += secBlobOutLength;
853 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
854 tp += smb_ServerOSLength;
855 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
856 tp += smb_ServerLanManagerLength;
857 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
858 tp += smb_ServerDomainNameLength;
860 smb_SetSMBDataLength(outp, 0);
863 if (smb_authType == SMB_AUTH_EXTENDED) {
864 smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
865 tp = smb_GetSMBData(outp, NULL);
866 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
867 tp += smb_ServerOSLength;
868 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
869 tp += smb_ServerLanManagerLength;
870 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
871 tp += smb_ServerDomainNameLength;
873 smb_SetSMBDataLength(outp, 0);
880 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
884 /* don't get tokens from this VC */
885 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
887 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
889 /* find the tree and free it */
890 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
891 /* TODO: smb_ReleaseUID() ? */
893 char *s1 = NULL, *s2 = NULL;
895 if (s2 == NULL) s2 = " ";
896 if (s1 == NULL) {s1 = s2; s2 = " ";}
898 osi_Log4(smb_logp, "SMB3 user logoffX uid %d name %s%s%s", uidp->userID,
899 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "), s1, s2);
901 lock_ObtainMutex(&uidp->mx);
902 uidp->flags |= SMB_USERFLAG_DELETE;
904 * it doesn't get deleted right away
905 * because the vcp points to it
907 lock_ReleaseMutex(&uidp->mx);
910 osi_Log0(smb_logp, "SMB3 user logoffX");
912 smb_SetSMBDataLength(outp, 0);
916 #define SMB_SUPPORT_SEARCH_BITS 0x0001
918 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
922 unsigned short newTid;
933 osi_Log0(smb_logp, "SMB3 receive tree connect");
935 /* parse input parameters */
936 tp = smb_GetSMBData(inp, NULL);
937 passwordp = smb_ParseString(tp, &tp);
938 pathp = smb_ParseString(tp, &tp);
939 servicep = smb_ParseString(tp, &tp);
941 tp = strrchr(pathp, '\\');
943 return CM_ERROR_BADSMB;
945 strcpy(shareName, tp+1);
947 osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
948 osi_LogSaveString(smb_logp, pathp),
949 osi_LogSaveString(smb_logp, shareName));
951 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
953 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
956 return CM_ERROR_NOIPC;
960 userp = smb_GetUser(vcp, inp);
962 lock_ObtainMutex(&vcp->mx);
963 newTid = vcp->tidCounter++;
964 lock_ReleaseMutex(&vcp->mx);
966 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
969 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
970 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
972 smb_ReleaseUID(uidp);
974 smb_ReleaseTID(tidp);
975 return CM_ERROR_BADSHARENAME;
978 if (vcp->flags & SMB_VCFLAG_USENT)
980 int policy = smb_FindShareCSCPolicy(shareName);
981 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS | (policy << 2));
984 smb_SetSMBParm(outp, 2, 0);
988 lock_ObtainMutex(&tidp->mx);
990 tidp->pathname = sharePath;
991 if(ipc) tidp->flags |= SMB_TIDFLAG_IPC;
992 lock_ReleaseMutex(&tidp->mx);
993 smb_ReleaseTID(tidp);
995 ((smb_t *)outp)->tid = newTid;
996 ((smb_t *)inp)->tid = newTid;
997 tp = smb_GetSMBData(outp, NULL);
1002 smb_SetSMBDataLength(outp, 3);
1005 smb_SetSMBDataLength(outp, 4);
1008 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1012 /* must be called with global tran lock held */
1013 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1015 smb_tran2Packet_t *tp;
1018 smbp = (smb_t *) inp->data;
1019 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1020 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1026 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1027 int totalParms, int totalData)
1029 smb_tran2Packet_t *tp;
1032 smbp = (smb_t *) inp->data;
1033 tp = malloc(sizeof(*tp));
1034 memset(tp, 0, sizeof(*tp));
1037 tp->curData = tp->curParms = 0;
1038 tp->totalData = totalData;
1039 tp->totalParms = totalParms;
1040 tp->tid = smbp->tid;
1041 tp->mid = smbp->mid;
1042 tp->uid = smbp->uid;
1043 tp->pid = smbp->pid;
1044 tp->res[0] = smbp->res[0];
1045 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1046 if (totalParms != 0)
1047 tp->parmsp = malloc(totalParms);
1049 tp->datap = malloc(totalData);
1050 if (smbp->com == 0x25 || smbp->com == 0x26)
1053 tp->opcode = smb_GetSMBParm(inp, 14);
1056 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1060 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1061 smb_tran2Packet_t *inp, smb_packet_t *outp,
1062 int totalParms, int totalData)
1064 smb_tran2Packet_t *tp;
1065 unsigned short parmOffset;
1066 unsigned short dataOffset;
1067 unsigned short dataAlign;
1069 tp = malloc(sizeof(*tp));
1070 memset(tp, 0, sizeof(*tp));
1072 tp->curData = tp->curParms = 0;
1073 tp->totalData = totalData;
1074 tp->totalParms = totalParms;
1075 tp->oldTotalParms = totalParms;
1080 tp->res[0] = inp->res[0];
1081 tp->opcode = inp->opcode;
1085 * We calculate where the parameters and data will start.
1086 * This calculation must parallel the calculation in
1087 * smb_SendTran2Packet.
1090 parmOffset = 10*2 + 35;
1091 parmOffset++; /* round to even */
1092 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1094 dataOffset = parmOffset + totalParms;
1095 dataAlign = dataOffset & 2; /* quad-align */
1096 dataOffset += dataAlign;
1097 tp->datap = outp->data + dataOffset;
1102 /* free a tran2 packet; must be called with smb_globalLock held */
1103 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1105 if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
1106 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1115 /* called with a VC, an input packet to respond to, and an error code.
1116 * sends an error response.
1118 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1119 smb_packet_t *tp, long code)
1122 unsigned short errCode;
1123 unsigned char errClass;
1124 unsigned long NTStatus;
1126 if (vcp->flags & SMB_VCFLAG_STATUS32)
1127 smb_MapNTError(code, &NTStatus);
1129 smb_MapCoreError(code, vcp, &errCode, &errClass);
1131 smb_FormatResponsePacket(vcp, NULL, tp);
1132 smbp = (smb_t *) tp;
1134 /* We can handle long names */
1135 if (vcp->flags & SMB_VCFLAG_USENT)
1136 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
1138 /* now copy important fields from the tran 2 packet */
1139 smbp->com = t2p->com;
1140 smbp->tid = t2p->tid;
1141 smbp->mid = t2p->mid;
1142 smbp->pid = t2p->pid;
1143 smbp->uid = t2p->uid;
1144 smbp->res[0] = t2p->res[0];
1145 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1146 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1147 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1148 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1149 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1150 smbp->flg2 |= 0x4000;
1153 smbp->rcls = errClass;
1154 smbp->errLow = (unsigned char) (errCode & 0xff);
1155 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1159 smb_SendPacket(vcp, tp);
1162 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1165 unsigned short parmOffset;
1166 unsigned short dataOffset;
1167 unsigned short totalLength;
1168 unsigned short dataAlign;
1171 smb_FormatResponsePacket(vcp, NULL, tp);
1172 smbp = (smb_t *) tp;
1174 /* We can handle long names */
1175 if (vcp->flags & SMB_VCFLAG_USENT)
1176 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
1178 /* now copy important fields from the tran 2 packet */
1179 smbp->com = t2p->com;
1180 smbp->tid = t2p->tid;
1181 smbp->mid = t2p->mid;
1182 smbp->pid = t2p->pid;
1183 smbp->uid = t2p->uid;
1184 smbp->res[0] = t2p->res[0];
1186 totalLength = 1 + t2p->totalData + t2p->totalParms;
1188 /* now add the core parameters (tran2 info) to the packet */
1189 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1190 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1191 smb_SetSMBParm(tp, 2, 0); /* reserved */
1192 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1193 parmOffset = 10*2 + 35; /* parm offset in packet */
1194 parmOffset++; /* round to even */
1195 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1196 * hdr, bcc and wct */
1197 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1198 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1199 dataOffset = parmOffset + t2p->oldTotalParms;
1200 dataAlign = dataOffset & 2; /* quad-align */
1201 dataOffset += dataAlign;
1202 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1203 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1204 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1207 datap = smb_GetSMBData(tp, NULL);
1208 *datap++ = 0; /* we rounded to even */
1210 totalLength += dataAlign;
1211 smb_SetSMBDataLength(tp, totalLength);
1213 /* next, send the datagram */
1214 smb_SendPacket(vcp, tp);
1217 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1219 smb_tran2Packet_t *asp;
1232 /* We sometimes see 0 word count. What to do? */
1233 if (*inp->wctp == 0) {
1238 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1240 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1241 ptbuf[0] = "Transaction2 word count = 0";
1242 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1243 1, inp->ncb_length, ptbuf, inp);
1244 DeregisterEventSource(h);
1246 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1249 smb_SetSMBDataLength(outp, 0);
1250 smb_SendPacket(vcp, outp);
1254 totalParms = smb_GetSMBParm(inp, 0);
1255 totalData = smb_GetSMBParm(inp, 1);
1257 firstPacket = (inp->inCom == 0x25);
1259 /* find the packet we're reassembling */
1260 lock_ObtainWrite(&smb_globalLock);
1261 asp = smb_FindTran2Packet(vcp, inp);
1263 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1265 lock_ReleaseWrite(&smb_globalLock);
1267 /* now merge in this latest packet; start by looking up offsets */
1269 parmDisp = dataDisp = 0;
1270 parmOffset = smb_GetSMBParm(inp, 10);
1271 dataOffset = smb_GetSMBParm(inp, 12);
1272 parmCount = smb_GetSMBParm(inp, 9);
1273 dataCount = smb_GetSMBParm(inp, 11);
1274 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1275 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1277 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1278 totalData, dataCount, asp->maxReturnData);
1281 parmDisp = smb_GetSMBParm(inp, 4);
1282 parmOffset = smb_GetSMBParm(inp, 3);
1283 dataDisp = smb_GetSMBParm(inp, 7);
1284 dataOffset = smb_GetSMBParm(inp, 6);
1285 parmCount = smb_GetSMBParm(inp, 2);
1286 dataCount = smb_GetSMBParm(inp, 5);
1288 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1289 parmCount, dataCount);
1292 /* now copy the parms and data */
1293 if ( asp->totalParms > 0 && parmCount != 0 )
1295 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1297 if ( asp->totalData > 0 && dataCount != 0 ) {
1298 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1301 /* account for new bytes */
1302 asp->curData += dataCount;
1303 asp->curParms += parmCount;
1305 /* finally, if we're done, remove the packet from the queue and dispatch it */
1306 if (asp->totalParms > 0 &&
1307 asp->curParms > 0 &&
1308 asp->totalData <= asp->curData &&
1309 asp->totalParms <= asp->curParms) {
1310 /* we've received it all */
1311 lock_ObtainWrite(&smb_globalLock);
1312 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1313 lock_ReleaseWrite(&smb_globalLock);
1315 /* now dispatch it */
1316 rapOp = asp->parmsp[0];
1318 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1319 osi_LogEvent("AFS-Dispatch-RAP[%s]",myCrt_RapDispatch(rapOp),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1320 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%x] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1321 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1324 osi_LogEvent("AFS-Dispatch-RAP [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1325 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1326 code = CM_ERROR_BADOP;
1329 /* if an error is returned, we're supposed to send an error packet,
1330 * otherwise the dispatched function already did the data sending.
1331 * We give dispatched proc the responsibility since it knows how much
1332 * space to allocate.
1335 smb_SendTran2Error(vcp, asp, outp, code);
1338 /* free the input tran 2 packet */
1339 lock_ObtainWrite(&smb_globalLock);
1340 smb_FreeTran2Packet(asp);
1341 lock_ReleaseWrite(&smb_globalLock);
1343 else if (firstPacket) {
1344 /* the first packet in a multi-packet request, we need to send an
1345 * ack to get more data.
1347 smb_SetSMBDataLength(outp, 0);
1348 smb_SendPacket(vcp, outp);
1354 /* ANSI versions. The unicode versions support arbitrary length
1355 share names, but we don't support unicode yet. */
1357 typedef struct smb_rap_share_info_0 {
1358 char shi0_netname[13];
1359 } smb_rap_share_info_0_t;
1361 typedef struct smb_rap_share_info_1 {
1362 char shi1_netname[13];
1365 DWORD shi1_remark; /* char *shi1_remark; data offset */
1366 } smb_rap_share_info_1_t;
1368 typedef struct smb_rap_share_info_2 {
1369 char shi2_netname[13];
1371 unsigned short shi2_type;
1372 DWORD shi2_remark; /* char *shi2_remark; data offset */
1373 unsigned short shi2_permissions;
1374 unsigned short shi2_max_uses;
1375 unsigned short shi2_current_uses;
1376 DWORD shi2_path; /* char *shi2_path; data offset */
1377 unsigned short shi2_passwd[9];
1378 unsigned short shi2_pad2;
1379 } smb_rap_share_info_2_t;
1381 #define SMB_RAP_MAX_SHARES 512
1383 typedef struct smb_rap_share_list {
1386 smb_rap_share_info_0_t * shares;
1387 } smb_rap_share_list_t;
1389 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1390 smb_rap_share_list_t * sp;
1395 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1396 return 0; /* skip over '.' and '..' */
1398 sp = (smb_rap_share_list_t *) vrockp;
1400 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1401 sp->shares[sp->cShare].shi0_netname[12] = 0;
1405 if (sp->cShare >= sp->maxShares)
1406 return CM_ERROR_STOPNOW;
1411 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1413 smb_tran2Packet_t *outp;
1414 unsigned short * tp;
1418 int outParmsTotal; /* total parameter bytes */
1419 int outDataTotal; /* total data bytes */
1427 HKEY hkSubmount = NULL;
1428 smb_rap_share_info_1_t * shares;
1431 char thisShare[256];
1434 smb_rap_share_list_t rootShares;
1439 tp = p->parmsp + 1; /* skip over function number (always 0) */
1440 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1441 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1445 if (infoLevel != 1) {
1446 return CM_ERROR_INVAL;
1449 /* first figure out how many shares there are */
1450 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1451 KEY_QUERY_VALUE, &hkParam);
1452 if (rv == ERROR_SUCCESS) {
1453 len = sizeof(allSubmount);
1454 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1455 (BYTE *) &allSubmount, &len);
1456 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1459 RegCloseKey (hkParam);
1462 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1463 0, KEY_QUERY_VALUE, &hkSubmount);
1464 if (rv == ERROR_SUCCESS) {
1465 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1466 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1467 if (rv != ERROR_SUCCESS)
1473 /* fetch the root shares */
1474 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1475 rootShares.cShare = 0;
1476 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1480 userp = smb_GetTran2User(vcp,p);
1482 thyper.HighPart = 0;
1485 cm_HoldSCache(cm_rootSCachep);
1486 cm_ApplyDir(cm_rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1487 cm_ReleaseSCache(cm_rootSCachep);
1489 cm_ReleaseUser(userp);
1491 nShares = rootShares.cShare + nRegShares + allSubmount;
1493 #define REMARK_LEN 1
1494 outParmsTotal = 8; /* 4 dwords */
1495 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1496 if(outDataTotal > bufsize) {
1497 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1498 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1501 nSharesRet = nShares;
1504 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1506 /* now for the submounts */
1507 shares = (smb_rap_share_info_1_t *) outp->datap;
1508 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1510 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1513 strcpy( shares[cshare].shi1_netname, "all" );
1514 shares[cshare].shi1_remark = cstrp - outp->datap;
1515 /* type and pad are zero already */
1521 for (i=0; i < nRegShares && cshare < nSharesRet; i++) {
1522 len = sizeof(thisShare);
1523 rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1524 if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1525 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1526 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1527 shares[cshare].shi1_remark = cstrp - outp->datap;
1532 nShares--; /* uncount key */
1535 RegCloseKey(hkSubmount);
1538 nonrootShares = cshare;
1540 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1541 /* in case there are collisions with submounts, submounts have higher priority */
1542 for (j=0; j < nonrootShares; j++)
1543 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1546 if (j < nonrootShares) {
1547 nShares--; /* uncount */
1551 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1552 shares[cshare].shi1_remark = cstrp - outp->datap;
1557 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1558 outp->parmsp[1] = 0;
1559 outp->parmsp[2] = cshare;
1560 outp->parmsp[3] = nShares;
1562 outp->totalData = cstrp - outp->datap;
1563 outp->totalParms = outParmsTotal;
1565 smb_SendTran2Packet(vcp, outp, op);
1566 smb_FreeTran2Packet(outp);
1568 free(rootShares.shares);
1573 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1575 smb_tran2Packet_t *outp;
1576 unsigned short * tp;
1578 BOOL shareFound = FALSE;
1579 unsigned short infoLevel;
1580 unsigned short bufsize;
1590 tp = p->parmsp + 1; /* skip over function number (always 1) */
1591 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1592 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1593 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1600 totalData = sizeof(smb_rap_share_info_0_t);
1601 else if(infoLevel == 1)
1602 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1603 else if(infoLevel == 2)
1604 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1606 return CM_ERROR_INVAL;
1608 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1610 if(!stricmp(shareName,"all")) {
1611 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1612 KEY_QUERY_VALUE, &hkParam);
1613 if (rv == ERROR_SUCCESS) {
1614 len = sizeof(allSubmount);
1615 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1616 (BYTE *) &allSubmount, &len);
1617 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1620 RegCloseKey (hkParam);
1627 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts", 0,
1628 KEY_QUERY_VALUE, &hkSubmount);
1629 if (rv == ERROR_SUCCESS) {
1630 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1631 if (rv == ERROR_SUCCESS) {
1634 RegCloseKey(hkSubmount);
1639 smb_FreeTran2Packet(outp);
1640 return CM_ERROR_BADSHARENAME;
1643 memset(outp->datap, 0, totalData);
1645 outp->parmsp[0] = 0;
1646 outp->parmsp[1] = 0;
1647 outp->parmsp[2] = totalData;
1649 if (infoLevel == 0) {
1650 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1651 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1652 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1653 } else if(infoLevel == 1) {
1654 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1655 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1656 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1657 info->shi1_remark = ((unsigned char *) (info + 1)) - outp->datap;
1658 /* type and pad are already zero */
1659 } else { /* infoLevel==2 */
1660 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1661 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1662 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1663 info->shi2_remark = ((unsigned char *) (info + 1)) - outp->datap;
1664 info->shi2_permissions = ACCESS_ALL;
1665 info->shi2_max_uses = (unsigned short) -1;
1666 info->shi2_path = 1 + (((unsigned char *) (info + 1)) - outp->datap);
1669 outp->totalData = totalData;
1670 outp->totalParms = totalParam;
1672 smb_SendTran2Packet(vcp, outp, op);
1673 smb_FreeTran2Packet(outp);
1678 typedef struct smb_rap_wksta_info_10 {
1679 DWORD wki10_computername; /*char *wki10_computername;*/
1680 DWORD wki10_username; /* char *wki10_username; */
1681 DWORD wki10_langroup; /* char *wki10_langroup;*/
1682 unsigned char wki10_ver_major;
1683 unsigned char wki10_ver_minor;
1684 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1685 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1686 } smb_rap_wksta_info_10_t;
1689 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1691 smb_tran2Packet_t *outp;
1695 unsigned short * tp;
1698 smb_rap_wksta_info_10_t * info;
1702 tp = p->parmsp + 1; /* Skip over function number */
1703 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1704 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1708 if (infoLevel != 10) {
1709 return CM_ERROR_INVAL;
1715 totalData = sizeof(*info) + /* info */
1716 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1717 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1718 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1719 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1720 1; /* wki10_oth_domains (null)*/
1722 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1724 memset(outp->parmsp,0,totalParams);
1725 memset(outp->datap,0,totalData);
1727 info = (smb_rap_wksta_info_10_t *) outp->datap;
1728 cstrp = (char *) (info + 1);
1730 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1731 strcpy(cstrp, smb_localNamep);
1732 cstrp += strlen(cstrp) + 1;
1734 info->wki10_username = (DWORD) (cstrp - outp->datap);
1735 uidp = smb_FindUID(vcp, p->uid, 0);
1737 lock_ObtainMutex(&uidp->mx);
1738 if(uidp->unp && uidp->unp->name)
1739 strcpy(cstrp, uidp->unp->name);
1740 lock_ReleaseMutex(&uidp->mx);
1741 smb_ReleaseUID(uidp);
1743 cstrp += strlen(cstrp) + 1;
1745 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1746 strcpy(cstrp, "WORKGROUP");
1747 cstrp += strlen(cstrp) + 1;
1749 /* TODO: Not sure what values these should take, but these work */
1750 info->wki10_ver_major = 5;
1751 info->wki10_ver_minor = 1;
1753 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1754 strcpy(cstrp, smb_ServerDomainName);
1755 cstrp += strlen(cstrp) + 1;
1757 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1758 cstrp ++; /* no other domains */
1760 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1761 outp->parmsp[2] = outp->totalData;
1762 outp->totalParms = totalParams;
1764 smb_SendTran2Packet(vcp,outp,op);
1765 smb_FreeTran2Packet(outp);
1770 typedef struct smb_rap_server_info_0 {
1772 } smb_rap_server_info_0_t;
1774 typedef struct smb_rap_server_info_1 {
1776 char sv1_version_major;
1777 char sv1_version_minor;
1778 unsigned long sv1_type;
1779 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1780 } smb_rap_server_info_1_t;
1782 char smb_ServerComment[] = "OpenAFS Client";
1783 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1785 #define SMB_SV_TYPE_SERVER 0x00000002L
1786 #define SMB_SV_TYPE_NT 0x00001000L
1787 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1789 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1791 smb_tran2Packet_t *outp;
1795 unsigned short * tp;
1798 smb_rap_server_info_0_t * info0;
1799 smb_rap_server_info_1_t * info1;
1802 tp = p->parmsp + 1; /* Skip over function number */
1803 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1804 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1808 if (infoLevel != 0 && infoLevel != 1) {
1809 return CM_ERROR_INVAL;
1815 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1816 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1818 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1820 memset(outp->parmsp,0,totalParams);
1821 memset(outp->datap,0,totalData);
1823 if (infoLevel == 0) {
1824 info0 = (smb_rap_server_info_0_t *) outp->datap;
1825 cstrp = (char *) (info0 + 1);
1826 strcpy(info0->sv0_name, "AFS");
1827 } else { /* infoLevel == 1 */
1828 info1 = (smb_rap_server_info_1_t *) outp->datap;
1829 cstrp = (char *) (info1 + 1);
1830 strcpy(info1->sv1_name, "AFS");
1833 SMB_SV_TYPE_SERVER |
1835 SMB_SV_TYPE_SERVER_NT;
1837 info1->sv1_version_major = 5;
1838 info1->sv1_version_minor = 1;
1839 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1841 strcpy(cstrp, smb_ServerComment);
1843 cstrp += smb_ServerCommentLen;
1846 totalData = cstrp - outp->datap;
1847 outp->totalData = min(bufsize,totalData); /* actual data size */
1848 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1849 outp->parmsp[2] = totalData;
1850 outp->totalParms = totalParams;
1852 smb_SendTran2Packet(vcp,outp,op);
1853 smb_FreeTran2Packet(outp);
1858 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1860 smb_tran2Packet_t *asp;
1872 /* We sometimes see 0 word count. What to do? */
1873 if (*inp->wctp == 0) {
1878 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1880 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1881 ptbuf[0] = "Transaction2 word count = 0";
1882 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1883 1, inp->ncb_length, ptbuf, inp);
1884 DeregisterEventSource(h);
1886 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1889 smb_SetSMBDataLength(outp, 0);
1890 smb_SendPacket(vcp, outp);
1894 totalParms = smb_GetSMBParm(inp, 0);
1895 totalData = smb_GetSMBParm(inp, 1);
1897 firstPacket = (inp->inCom == 0x32);
1899 /* find the packet we're reassembling */
1900 lock_ObtainWrite(&smb_globalLock);
1901 asp = smb_FindTran2Packet(vcp, inp);
1903 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1905 lock_ReleaseWrite(&smb_globalLock);
1907 /* now merge in this latest packet; start by looking up offsets */
1909 parmDisp = dataDisp = 0;
1910 parmOffset = smb_GetSMBParm(inp, 10);
1911 dataOffset = smb_GetSMBParm(inp, 12);
1912 parmCount = smb_GetSMBParm(inp, 9);
1913 dataCount = smb_GetSMBParm(inp, 11);
1914 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1915 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1917 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1918 totalData, dataCount, asp->maxReturnData);
1921 parmDisp = smb_GetSMBParm(inp, 4);
1922 parmOffset = smb_GetSMBParm(inp, 3);
1923 dataDisp = smb_GetSMBParm(inp, 7);
1924 dataOffset = smb_GetSMBParm(inp, 6);
1925 parmCount = smb_GetSMBParm(inp, 2);
1926 dataCount = smb_GetSMBParm(inp, 5);
1928 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1929 parmCount, dataCount);
1932 /* now copy the parms and data */
1933 if ( asp->totalParms > 0 && parmCount != 0 )
1935 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1937 if ( asp->totalData > 0 && dataCount != 0 ) {
1938 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1941 /* account for new bytes */
1942 asp->curData += dataCount;
1943 asp->curParms += parmCount;
1945 /* finally, if we're done, remove the packet from the queue and dispatch it */
1946 if (asp->totalParms > 0 &&
1947 asp->curParms > 0 &&
1948 asp->totalData <= asp->curData &&
1949 asp->totalParms <= asp->curParms) {
1950 /* we've received it all */
1951 lock_ObtainWrite(&smb_globalLock);
1952 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1953 lock_ReleaseWrite(&smb_globalLock);
1955 /* now dispatch it */
1956 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
1957 osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1958 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
1959 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
1962 osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1963 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1964 code = CM_ERROR_BADOP;
1967 /* if an error is returned, we're supposed to send an error packet,
1968 * otherwise the dispatched function already did the data sending.
1969 * We give dispatched proc the responsibility since it knows how much
1970 * space to allocate.
1973 smb_SendTran2Error(vcp, asp, outp, code);
1976 /* free the input tran 2 packet */
1977 lock_ObtainWrite(&smb_globalLock);
1978 smb_FreeTran2Packet(asp);
1979 lock_ReleaseWrite(&smb_globalLock);
1981 else if (firstPacket) {
1982 /* the first packet in a multi-packet request, we need to send an
1983 * ack to get more data.
1985 smb_SetSMBDataLength(outp, 0);
1986 smb_SendPacket(vcp, outp);
1992 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1995 smb_tran2Packet_t *outp;
2000 cm_scache_t *dscp; /* dir we're dealing with */
2001 cm_scache_t *scp; /* file we're creating */
2003 int initialModeBits;
2013 int parmSlot; /* which parm we're dealing with */
2014 long returnEALength;
2022 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2023 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2025 openFun = p->parmsp[6]; /* open function */
2026 excl = ((openFun & 3) == 0);
2027 trunc = ((openFun & 3) == 2); /* truncate it */
2028 openMode = (p->parmsp[1] & 0x7);
2029 openAction = 0; /* tracks what we did */
2031 attributes = p->parmsp[3];
2032 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2034 /* compute initial mode bits based on read-only flag in attributes */
2035 initialModeBits = 0666;
2036 if (attributes & 1) initialModeBits &= ~0222;
2038 pathp = (char *) (&p->parmsp[14]);
2040 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2042 spacep = cm_GetSpace();
2043 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2045 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2046 /* special case magic file name for receiving IOCTL requests
2047 * (since IOCTL calls themselves aren't getting through).
2049 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2050 smb_SetupIoctlFid(fidp, spacep);
2052 /* copy out remainder of the parms */
2054 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2056 outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
2057 outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
2058 outp->parmsp[parmSlot] = 0; parmSlot++;
2059 outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
2060 outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
2061 outp->parmsp[parmSlot] = openMode; parmSlot++;
2062 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2063 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2065 /* and the final "always present" stuff */
2066 outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
2067 /* next write out the "unique" ID */
2068 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
2069 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
2070 outp->parmsp[parmSlot] = 0; parmSlot++;
2071 if (returnEALength) {
2072 outp->parmsp[parmSlot] = 0; parmSlot++;
2073 outp->parmsp[parmSlot] = 0; parmSlot++;
2076 outp->totalData = 0;
2077 outp->totalParms = parmSlot * 2;
2079 smb_SendTran2Packet(vcp, outp, op);
2081 smb_FreeTran2Packet(outp);
2083 /* and clean up fid reference */
2084 smb_ReleaseFID(fidp);
2088 #ifdef DEBUG_VERBOSE
2090 char *hexp, *asciip;
2091 asciip = (lastNamep ? lastNamep : pathp);
2092 hexp = osi_HexifyString( asciip );
2093 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2098 userp = smb_GetTran2User(vcp, p);
2099 /* In the off chance that userp is NULL, we log and abandon */
2101 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2102 smb_FreeTran2Packet(outp);
2103 return CM_ERROR_BADSMB;
2106 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2107 if (code == CM_ERROR_TIDIPC) {
2108 /* Attempt to use TID allocated for IPC. The client is
2109 probably trying to locate DCE RPC end points, which
2110 we don't support. */
2111 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2112 cm_ReleaseUser(userp);
2113 smb_FreeTran2Packet(outp);
2114 return CM_ERROR_NOSUCHPATH;
2118 code = cm_NameI(cm_rootSCachep, pathp,
2119 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2120 userp, tidPathp, &req, &scp);
2122 code = cm_NameI(cm_rootSCachep, spacep->data,
2123 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2124 userp, tidPathp, &req, &dscp);
2125 cm_FreeSpace(spacep);
2128 cm_ReleaseUser(userp);
2129 smb_FreeTran2Packet(outp);
2133 /* otherwise, scp points to the parent directory. Do a lookup,
2134 * and truncate the file if we find it, otherwise we create the
2141 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2143 if (code && code != CM_ERROR_NOSUCHFILE) {
2144 cm_ReleaseSCache(dscp);
2145 cm_ReleaseUser(userp);
2146 smb_FreeTran2Packet(outp);
2151 cm_FreeSpace(spacep);
2154 /* if we get here, if code is 0, the file exists and is represented by
2155 * scp. Otherwise, we have to create it.
2158 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2160 if (dscp) cm_ReleaseSCache(dscp);
2161 cm_ReleaseSCache(scp);
2162 cm_ReleaseUser(userp);
2163 smb_FreeTran2Packet(outp);
2168 /* oops, file shouldn't be there */
2169 if (dscp) cm_ReleaseSCache(dscp);
2170 cm_ReleaseSCache(scp);
2171 cm_ReleaseUser(userp);
2172 smb_FreeTran2Packet(outp);
2173 return CM_ERROR_EXISTS;
2177 setAttr.mask = CM_ATTRMASK_LENGTH;
2178 setAttr.length.LowPart = 0;
2179 setAttr.length.HighPart = 0;
2180 code = cm_SetAttr(scp, &setAttr, userp, &req);
2181 openAction = 3; /* truncated existing file */
2184 openAction = 1; /* found existing file */
2186 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
2187 /* don't create if not found */
2188 if (dscp) cm_ReleaseSCache(dscp);
2189 osi_assert(scp == NULL);
2190 cm_ReleaseUser(userp);
2191 smb_FreeTran2Packet(outp);
2192 return CM_ERROR_NOSUCHFILE;
2195 osi_assert(dscp != NULL && scp == NULL);
2196 openAction = 2; /* created file */
2197 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2198 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2199 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2201 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2202 smb_NotifyChange(FILE_ACTION_ADDED,
2203 FILE_NOTIFY_CHANGE_FILE_NAME,
2204 dscp, lastNamep, NULL, TRUE);
2205 if (!excl && code == CM_ERROR_EXISTS) {
2206 /* not an exclusive create, and someone else tried
2207 * creating it already, then we open it anyway. We
2208 * don't bother retrying after this, since if this next
2209 * fails, that means that the file was deleted after we
2210 * started this call.
2212 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2216 setAttr.mask = CM_ATTRMASK_LENGTH;
2217 setAttr.length.LowPart = 0;
2218 setAttr.length.HighPart = 0;
2219 code = cm_SetAttr(scp, &setAttr, userp,
2222 } /* lookup succeeded */
2226 /* we don't need this any longer */
2227 if (dscp) cm_ReleaseSCache(dscp);
2230 /* something went wrong creating or truncating the file */
2231 if (scp) cm_ReleaseSCache(scp);
2232 cm_ReleaseUser(userp);
2233 smb_FreeTran2Packet(outp);
2237 /* make sure we're about to open a file */
2238 if (scp->fileType != CM_SCACHETYPE_FILE) {
2240 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2241 cm_scache_t * targetScp = 0;
2242 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2244 /* we have a more accurate file to use (the
2245 * target of the symbolic link). Otherwise,
2246 * we'll just use the symlink anyway.
2248 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2250 cm_ReleaseSCache(scp);
2254 if (scp->fileType != CM_SCACHETYPE_FILE) {
2255 cm_ReleaseSCache(scp);
2256 cm_ReleaseUser(userp);
2257 smb_FreeTran2Packet(outp);
2258 return CM_ERROR_ISDIR;
2262 /* now all we have to do is open the file itself */
2263 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2266 /* save a pointer to the vnode */
2269 /* compute open mode */
2270 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2271 if (openMode == 1 || openMode == 2)
2272 fidp->flags |= SMB_FID_OPENWRITE;
2274 smb_ReleaseFID(fidp);
2276 cm_Open(scp, 0, userp);
2278 /* copy out remainder of the parms */
2280 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2281 lock_ObtainMutex(&scp->mx);
2283 outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
2284 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2285 outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
2286 outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
2287 outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
2289 outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2291 outp->parmsp[parmSlot] = openMode; parmSlot++;
2292 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2293 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2295 /* and the final "always present" stuff */
2296 outp->parmsp[parmSlot] = openAction; parmSlot++;
2297 /* next write out the "unique" ID */
2298 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
2299 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
2300 outp->parmsp[parmSlot] = 0; parmSlot++;
2301 if (returnEALength) {
2302 outp->parmsp[parmSlot] = 0; parmSlot++;
2303 outp->parmsp[parmSlot] = 0; parmSlot++;
2305 lock_ReleaseMutex(&scp->mx);
2306 outp->totalData = 0; /* total # of data bytes */
2307 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2309 smb_SendTran2Packet(vcp, outp, op);
2311 smb_FreeTran2Packet(outp);
2313 cm_ReleaseUser(userp);
2314 /* leave scp held since we put it in fidp->scp */
2318 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2320 osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2321 return CM_ERROR_BADOP;
2324 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2326 osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2327 return CM_ERROR_BADOP;
2330 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2332 smb_tran2Packet_t *outp;
2333 smb_tran2QFSInfo_t qi;
2336 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
2338 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2340 switch (p->parmsp[0]) {
2341 case 1: responseSize = sizeof(qi.u.allocInfo); break;
2342 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
2343 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
2344 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
2345 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
2346 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
2347 default: return CM_ERROR_INVAL;
2350 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2351 switch (p->parmsp[0]) {
2354 qi.u.allocInfo.FSID = 0;
2355 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2356 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2357 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2358 qi.u.allocInfo.bytesPerSector = 1024;
2363 qi.u.volumeInfo.vsn = 1234;
2364 qi.u.volumeInfo.vnCount = 4;
2365 /* we're supposed to pad it out with zeroes to the end */
2366 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2367 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2371 /* FS volume info */
2372 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
2373 qi.u.FSvolumeInfo.vsn = 1234;
2374 qi.u.FSvolumeInfo.vnCount = 8;
2375 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
2381 temp.LowPart = 0x7fffffff;
2382 qi.u.FSsizeInfo.totalAllocUnits = temp;
2383 temp.LowPart = 0x3fffffff;
2384 qi.u.FSsizeInfo.availAllocUnits = temp;
2385 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2386 qi.u.FSsizeInfo.bytesPerSector = 1024;
2390 /* FS device info */
2391 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
2392 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2396 /* FS attribute info */
2397 /* attributes, defined in WINNT.H:
2398 * FILE_CASE_SENSITIVE_SEARCH 0x1
2399 * FILE_CASE_PRESERVED_NAMES 0x2
2400 * <no name defined> 0x4000
2401 * If bit 0x4000 is not set, Windows 95 thinks
2402 * we can't handle long (non-8.3) names,
2403 * despite our protestations to the contrary.
2405 qi.u.FSattributeInfo.attributes = 0x4003;
2406 qi.u.FSattributeInfo.maxCompLength = 255;
2407 qi.u.FSattributeInfo.FSnameLength = 6;
2408 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
2412 /* copy out return data, and set corresponding sizes */
2413 outp->totalParms = 0;
2414 outp->totalData = responseSize;
2415 memcpy(outp->datap, &qi, responseSize);
2417 /* send and free the packets */
2418 smb_SendTran2Packet(vcp, outp, op);
2419 smb_FreeTran2Packet(outp);
2424 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2426 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2427 return CM_ERROR_BADOP;
2430 struct smb_ShortNameRock {
2434 size_t shortNameLen;
2437 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2440 struct smb_ShortNameRock *rockp;
2444 /* compare both names and vnodes, though probably just comparing vnodes
2445 * would be safe enough.
2447 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2449 if (ntohl(dep->fid.vnode) != rockp->vnode)
2451 /* This is the entry */
2452 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2453 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2454 return CM_ERROR_STOPNOW;
2457 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2458 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2460 struct smb_ShortNameRock rock;
2464 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2468 spacep = cm_GetSpace();
2469 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2471 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
2473 cm_FreeSpace(spacep);
2474 if (code) return code;
2476 if (!lastNamep) lastNamep = pathp;
2479 thyper.HighPart = 0;
2480 rock.shortName = shortName;
2482 rock.maskp = lastNamep;
2483 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2485 cm_ReleaseSCache(dscp);
2488 return CM_ERROR_NOSUCHFILE;
2489 if (code == CM_ERROR_STOPNOW) {
2490 *shortNameLenp = rock.shortNameLen;
2496 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2498 smb_tran2Packet_t *outp;
2501 unsigned short infoLevel;
2503 unsigned short attributes;
2504 unsigned long extAttributes;
2509 cm_scache_t *scp, *dscp;
2518 infoLevel = p->parmsp[0];
2519 if (infoLevel == 6) nbytesRequired = 0;
2520 else if (infoLevel == 1) nbytesRequired = 22;
2521 else if (infoLevel == 2) nbytesRequired = 26;
2522 else if (infoLevel == 0x101) nbytesRequired = 40;
2523 else if (infoLevel == 0x102) nbytesRequired = 24;
2524 else if (infoLevel == 0x103) nbytesRequired = 4;
2525 else if (infoLevel == 0x108) nbytesRequired = 30;
2527 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2528 p->opcode, infoLevel);
2529 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2532 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2533 osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
2535 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2537 if (infoLevel > 0x100)
2538 outp->totalParms = 2;
2540 outp->totalParms = 0;
2541 outp->totalData = nbytesRequired;
2543 /* now, if we're at infoLevel 6, we're only being asked to check
2544 * the syntax, so we just OK things now. In particular, we're *not*
2545 * being asked to verify anything about the state of any parent dirs.
2547 if (infoLevel == 6) {
2548 smb_SendTran2Packet(vcp, outp, opx);
2549 smb_FreeTran2Packet(outp);
2553 userp = smb_GetTran2User(vcp, p);
2555 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2556 smb_FreeTran2Packet(outp);
2557 return CM_ERROR_BADSMB;
2560 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2562 cm_ReleaseUser(userp);
2563 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2564 smb_FreeTran2Packet(outp);
2569 * XXX Strange hack XXX
2571 * As of Patch 7 (13 January 98), we are having the following problem:
2572 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2573 * requests to look up "desktop.ini" in all the subdirectories.
2574 * This can cause zillions of timeouts looking up non-existent cells
2575 * and volumes, especially in the top-level directory.
2577 * We have not found any way to avoid this or work around it except
2578 * to explicitly ignore the requests for mount points that haven't
2579 * yet been evaluated and for directories that haven't yet been
2582 if (infoLevel == 0x101) {
2583 spacep = cm_GetSpace();
2584 smb_StripLastComponent(spacep->data, &lastComp,
2585 (char *)(&p->parmsp[3]));
2586 #ifndef SPECIAL_FOLDERS
2587 /* Make sure that lastComp is not NULL */
2589 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2590 code = cm_NameI(cm_rootSCachep, spacep->data,
2594 userp, tidPathp, &req, &dscp);
2596 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
2597 && !dscp->mountRootFidp)
2598 code = CM_ERROR_NOSUCHFILE;
2599 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2600 cm_buf_t *bp = buf_Find(dscp, &hzero);
2604 code = CM_ERROR_NOSUCHFILE;
2606 cm_ReleaseSCache(dscp);
2608 cm_FreeSpace(spacep);
2609 cm_ReleaseUser(userp);
2610 smb_SendTran2Error(vcp, p, opx, code);
2611 smb_FreeTran2Packet(outp);
2617 #endif /* SPECIAL_FOLDERS */
2619 cm_FreeSpace(spacep);
2622 /* now do namei and stat, and copy out the info */
2623 code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
2624 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2627 cm_ReleaseUser(userp);
2628 smb_SendTran2Error(vcp, p, opx, code);
2629 smb_FreeTran2Packet(outp);
2633 lock_ObtainMutex(&scp->mx);
2634 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2635 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2636 if (code) goto done;
2638 /* now we have the status in the cache entry, and everything is locked.
2639 * Marshall the output data.
2642 /* for info level 108, figure out short name */
2643 if (infoLevel == 0x108) {
2644 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
2645 tidPathp, scp->fid.vnode, shortName,
2652 *((u_long *)op) = len * 2; op += 4;
2653 mbstowcs((unsigned short *)op, shortName, len);
2658 if (infoLevel == 1 || infoLevel == 2) {
2659 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2660 *((u_long *)op) = dosTime; op += 4; /* creation time */
2661 *((u_long *)op) = dosTime; op += 4; /* access time */
2662 *((u_long *)op) = dosTime; op += 4; /* write time */
2663 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
2664 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
2665 attributes = smb_Attributes(scp);
2666 *((u_short *)op) = attributes; op += 2; /* attributes */
2668 else if (infoLevel == 0x101) {
2669 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2670 *((FILETIME *)op) = ft; op += 8; /* creation time */
2671 *((FILETIME *)op) = ft; op += 8; /* last access time */
2672 *((FILETIME *)op) = ft; op += 8; /* last write time */
2673 *((FILETIME *)op) = ft; op += 8; /* last change time */
2674 extAttributes = smb_ExtAttributes(scp);
2675 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
2676 *((u_long *)op) = 0; op += 4; /* don't know what this is */
2678 else if (infoLevel == 0x102) {
2679 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2680 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2681 *((u_long *)op) = scp->linkCount; op += 4;
2684 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2687 else if (infoLevel == 0x103) {
2688 memset(op, 0, 4); op += 4; /* EA size */
2691 /* now, if we are being asked about extended attrs, return a 0 size */
2692 if (infoLevel == 2) {
2693 *((u_long *)op) = 0; op += 4;
2697 /* send and free the packets */
2699 lock_ReleaseMutex(&scp->mx);
2700 cm_ReleaseSCache(scp);
2701 cm_ReleaseUser(userp);
2703 smb_SendTran2Packet(vcp, outp, opx);
2705 smb_SendTran2Error(vcp, p, opx, code);
2706 smb_FreeTran2Packet(outp);
2711 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2713 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2714 return CM_ERROR_BADOP;
2717 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2719 smb_tran2Packet_t *outp;
2721 unsigned long attributes;
2722 unsigned short infoLevel;
2735 fidp = smb_FindFID(vcp, fid, 0);
2738 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2742 infoLevel = p->parmsp[1];
2743 if (infoLevel == 0x101) nbytesRequired = 40;
2744 else if (infoLevel == 0x102) nbytesRequired = 24;
2745 else if (infoLevel == 0x103) nbytesRequired = 4;
2746 else if (infoLevel == 0x104) nbytesRequired = 6;
2748 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2749 p->opcode, infoLevel);
2750 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2751 smb_ReleaseFID(fidp);
2754 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2756 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2758 if (infoLevel > 0x100)
2759 outp->totalParms = 2;
2761 outp->totalParms = 0;
2762 outp->totalData = nbytesRequired;
2764 userp = smb_GetTran2User(vcp, p);
2766 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2767 code = CM_ERROR_BADSMB;
2772 lock_ObtainMutex(&scp->mx);
2773 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2774 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2778 /* now we have the status in the cache entry, and everything is locked.
2779 * Marshall the output data.
2782 if (infoLevel == 0x101) {
2783 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2784 *((FILETIME *)op) = ft; op += 8; /* creation time */
2785 *((FILETIME *)op) = ft; op += 8; /* last access time */
2786 *((FILETIME *)op) = ft; op += 8; /* last write time */
2787 *((FILETIME *)op) = ft; op += 8; /* last change time */
2788 attributes = smb_ExtAttributes(scp);
2789 *((u_long *)op) = attributes; op += 4;
2790 *((u_long *)op) = 0; op += 4;
2792 else if (infoLevel == 0x102) {
2793 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2794 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2795 *((u_long *)op) = scp->linkCount; op += 4;
2796 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
2797 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2801 else if (infoLevel == 0x103) {
2802 *((u_long *)op) = 0; op += 4;
2804 else if (infoLevel == 0x104) {
2808 if (fidp->NTopen_wholepathp)
2809 name = fidp->NTopen_wholepathp;
2811 name = "\\"; /* probably can't happen */
2813 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
2814 *((u_long *)op) = len * 2; op += 4;
2815 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2818 /* send and free the packets */
2820 lock_ReleaseMutex(&scp->mx);
2821 cm_ReleaseUser(userp);
2822 smb_ReleaseFID(fidp);
2824 smb_SendTran2Packet(vcp, outp, opx);
2826 smb_SendTran2Error(vcp, p, opx, code);
2827 smb_FreeTran2Packet(outp);
2832 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2837 unsigned short infoLevel;
2838 smb_tran2Packet_t *outp;
2846 fidp = smb_FindFID(vcp, fid, 0);
2849 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
2853 infoLevel = p->parmsp[1];
2854 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type=[%x] fid=[%x]", infoLevel, fid);
2855 if (infoLevel > 0x104 || infoLevel < 0x101) {
2856 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2857 p->opcode, infoLevel);
2858 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
2859 smb_ReleaseFID(fidp);
2863 if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
2864 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2865 smb_ReleaseFID(fidp);
2868 if ((infoLevel == 0x103 || infoLevel == 0x104)
2869 && !(fidp->flags & SMB_FID_OPENWRITE)) {
2870 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2871 smb_ReleaseFID(fidp);
2875 osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
2877 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
2879 outp->totalParms = 2;
2880 outp->totalData = 0;
2882 userp = smb_GetTran2User(vcp, p);
2884 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
2885 code = CM_ERROR_BADSMB;
2891 if (infoLevel == 0x101) {
2893 unsigned int attribute;
2896 /* lock the vnode with a callback; we need the current status
2897 * to determine what the new status is, in some cases.
2899 lock_ObtainMutex(&scp->mx);
2900 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2901 CM_SCACHESYNC_GETSTATUS
2902 | CM_SCACHESYNC_NEEDCALLBACK);
2904 lock_ReleaseMutex(&scp->mx);
2908 /* prepare for setattr call */
2911 lastMod = *((FILETIME *)(p->datap + 16));
2912 /* when called as result of move a b, lastMod is (-1, -1).
2913 * If the check for -1 is not present, timestamp
2914 * of the resulting file will be 1969 (-1)
2916 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
2917 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
2918 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
2919 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
2921 fidp->flags |= SMB_FID_MTIMESETDONE;
2924 attribute = *((u_long *)(p->datap + 32));
2925 if (attribute != 0) {
2926 if ((scp->unixModeBits & 0222)
2927 && (attribute & 1) != 0) {
2928 /* make a writable file read-only */
2929 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2930 attr.unixModeBits = scp->unixModeBits & ~0222;
2932 else if ((scp->unixModeBits & 0222) == 0
2933 && (attribute & 1) == 0) {
2934 /* make a read-only file writable */
2935 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2936 attr.unixModeBits = scp->unixModeBits | 0222;
2939 lock_ReleaseMutex(&scp->mx);
2943 code = cm_SetAttr(scp, &attr, userp, &req);
2947 else if (infoLevel == 0x103 || infoLevel == 0x104) {
2948 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
2951 attr.mask = CM_ATTRMASK_LENGTH;
2952 attr.length.LowPart = size.LowPart;
2953 attr.length.HighPart = size.HighPart;
2954 code = cm_SetAttr(scp, &attr, userp, &req);
2956 else if (infoLevel == 0x102) {
2957 if (*((char *)(p->datap))) {
2958 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
2961 fidp->flags |= SMB_FID_DELONCLOSE;
2965 fidp->flags &= ~SMB_FID_DELONCLOSE;
2970 cm_ReleaseUser(userp);
2971 smb_ReleaseFID(fidp);
2973 smb_SendTran2Packet(vcp, outp, op);
2975 smb_SendTran2Error(vcp, p, op, code);
2976 smb_FreeTran2Packet(outp);
2982 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2984 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
2985 return CM_ERROR_BADOP;
2989 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2991 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
2992 return CM_ERROR_BADOP;
2996 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2998 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
2999 return CM_ERROR_BADOP;
3003 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3005 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3006 return CM_ERROR_BADOP;
3010 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3012 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3013 return CM_ERROR_BADOP;
3017 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3019 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3020 return CM_ERROR_BADOP;
3024 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3026 osi_Log0(smb_logp,"ReceiveTran2GetDFSReferral - NOT_SUPPORTED");
3027 return CM_ERROR_BADOP;
3031 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3033 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3034 return CM_ERROR_BADOP;
3038 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3039 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3044 cm_scache_t *targetScp; /* target if scp is a symlink */
3049 unsigned short attr;
3050 unsigned long lattr;
3051 smb_dirListPatch_t *patchp;
3052 smb_dirListPatch_t *npatchp;
3054 for(patchp = *dirPatchespp; patchp; patchp =
3055 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3056 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3058 lock_ObtainMutex(&scp->mx);
3059 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3060 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3062 lock_ReleaseMutex(&scp->mx);
3063 cm_ReleaseSCache(scp);
3065 dptr = patchp->dptr;
3067 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3068 errors in the client. */
3069 if (infoLevel >= 0x101) {
3070 /* 1969-12-31 23:59:59 +00 */
3071 ft.dwHighDateTime = 0x19DB200;
3072 ft.dwLowDateTime = 0x5BB78980;
3074 /* copy to Creation Time */
3075 *((FILETIME *)dptr) = ft;
3078 /* copy to Last Access Time */
3079 *((FILETIME *)dptr) = ft;
3082 /* copy to Last Write Time */
3083 *((FILETIME *)dptr) = ft;
3086 /* copy to Change Time */
3087 *((FILETIME *)dptr) = ft;
3090 /* merge in hidden attribute */
3091 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3092 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3096 /* 1969-12-31 23:59:58 +00*/
3097 dosTime = 0xEBBFBF7D;
3099 /* and copy out date */
3100 shortTemp = (dosTime>>16) & 0xffff;
3101 *((u_short *)dptr) = shortTemp;
3104 /* copy out creation time */
3105 shortTemp = dosTime & 0xffff;
3106 *((u_short *)dptr) = shortTemp;
3109 /* and copy out date */
3110 shortTemp = (dosTime>>16) & 0xffff;
3111 *((u_short *)dptr) = shortTemp;
3114 /* copy out access time */
3115 shortTemp = dosTime & 0xffff;
3116 *((u_short *)dptr) = shortTemp;
3119 /* and copy out date */
3120 shortTemp = (dosTime>>16) & 0xffff;
3121 *((u_short *)dptr) = shortTemp;
3124 /* copy out mod time */
3125 shortTemp = dosTime & 0xffff;
3126 *((u_short *)dptr) = shortTemp;
3129 /* merge in hidden (dot file) attribute */
3130 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3131 attr = SMB_ATTR_HIDDEN;
3132 *dptr++ = attr & 0xff;
3133 *dptr++ = (attr >> 8) & 0xff;
3139 /* now watch for a symlink */
3141 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3142 lock_ReleaseMutex(&scp->mx);
3143 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3145 /* we have a more accurate file to use (the
3146 * target of the symbolic link). Otherwise,
3147 * we'll just use the symlink anyway.
3149 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3151 cm_ReleaseSCache(scp);
3154 lock_ObtainMutex(&scp->mx);
3157 dptr = patchp->dptr;
3159 if (infoLevel >= 0x101) {
3161 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3163 /* copy to Creation Time */
3164 *((FILETIME *)dptr) = ft;
3167 /* copy to Last Access Time */
3168 *((FILETIME *)dptr) = ft;
3171 /* copy to Last Write Time */
3172 *((FILETIME *)dptr) = ft;
3175 /* copy to Change Time */
3176 *((FILETIME *)dptr) = ft;
3179 /* Use length for both file length and alloc length */
3180 *((LARGE_INTEGER *)dptr) = scp->length;
3182 *((LARGE_INTEGER *)dptr) = scp->length;
3185 /* Copy attributes */
3186 lattr = smb_ExtAttributes(scp);
3187 /* merge in hidden (dot file) attribute */
3188 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3189 lattr |= SMB_ATTR_HIDDEN;
3190 *((u_long *)dptr) = lattr;
3195 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3197 /* and copy out date */
3198 shortTemp = (dosTime>>16) & 0xffff;
3199 *((u_short *)dptr) = shortTemp;
3202 /* copy out creation time */
3203 shortTemp = dosTime & 0xffff;
3204 *((u_short *)dptr) = shortTemp;
3207 /* and copy out date */
3208 shortTemp = (dosTime>>16) & 0xffff;
3209 *((u_short *)dptr) = shortTemp;
3212 /* copy out access time */
3213 shortTemp = dosTime & 0xffff;
3214 *((u_short *)dptr) = shortTemp;
3217 /* and copy out date */
3218 shortTemp = (dosTime>>16) & 0xffff;
3219 *((u_short *)dptr) = shortTemp;
3222 /* copy out mod time */
3223 shortTemp = dosTime & 0xffff;
3224 *((u_short *)dptr) = shortTemp;
3227 /* copy out file length and alloc length,
3228 * using the same for both
3230 *((u_long *)dptr) = scp->length.LowPart;
3232 *((u_long *)dptr) = scp->length.LowPart;
3235 /* finally copy out attributes as short */
3236 attr = smb_Attributes(scp);
3237 /* merge in hidden (dot file) attribute */
3238 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3239 attr |= SMB_ATTR_HIDDEN;
3240 *dptr++ = attr & 0xff;
3241 *dptr++ = (attr >> 8) & 0xff;
3244 lock_ReleaseMutex(&scp->mx);
3245 cm_ReleaseSCache(scp);
3248 /* now free the patches */
3249 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3250 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3254 /* and mark the list as empty */
3255 *dirPatchespp = NULL;
3260 #ifndef USE_OLD_MATCHING
3261 // char table for case insensitive comparison
3262 char mapCaseTable[256];
3264 VOID initUpperCaseTable(VOID)
3267 for (i = 0; i < 256; ++i)
3268 mapCaseTable[i] = toupper(i);
3269 // make '"' match '.'
3270 mapCaseTable[(int)'"'] = toupper('.');
3271 // make '<' match '*'
3272 mapCaseTable[(int)'<'] = toupper('*');
3273 // make '>' match '?'
3274 mapCaseTable[(int)'>'] = toupper('?');
3277 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3279 // Note : this procedure works recursively calling itself.
3281 // PSZ pattern : string containing metacharacters.
3282 // PSZ name : file name to be compared with 'pattern'.
3284 // BOOL : TRUE/FALSE (match/mistmatch)
3287 szWildCardMatchFileName(PSZ pattern, PSZ name)
3289 PSZ pename; // points to the last 'name' character
3291 pename = name + strlen(name) - 1;
3301 if (*pattern == '\0')
3303 for (p = pename; p >= name; --p) {
3304 if ((mapCaseTable[*p] == mapCaseTable[*pattern]) &&
3305 szWildCardMatchFileName(pattern + 1, p + 1))
3310 if (mapCaseTable[*name] != mapCaseTable[*pattern])
3317 if (*pattern == '\0' || *pattern == '*' && *(pattern+1) == '\0')
3323 /* do a case-folding search of the star name mask with the name in namep.
3324 * Return 1 if we match, otherwise 0.
3326 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3329 int i, j, star, qmark, retval;
3331 /* make sure we only match 8.3 names, if requested */
3332 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3335 /* optimize the pattern:
3336 * if there is a mixture of '?' and '*',
3337 * for example the sequence "*?*?*?*"
3338 * must be turned into the form "*"
3340 newmask = (char *)malloc(strlen(maskp)+1);
3341 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3342 switch ( maskp[i] ) {
3354 } else if ( qmark ) {
3358 newmask[j++] = maskp[i];
3365 } else if ( qmark ) {
3369 newmask[j++] = '\0';
3371 retval = szWildCardMatchFileName(newmask, namep) ? 1:0;
3377 #else /* USE_OLD_MATCHING */
3378 /* do a case-folding search of the star name mask with the name in namep.
3379 * Return 1 if we match, otherwise 0.
3381 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3383 unsigned char tcp1, tcp2; /* Pattern characters */
3384 unsigned char tcn1; /* Name characters */
3385 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3386 char *starNamep, *starMaskp;
3387 static char nullCharp[] = {0};
3388 int casefold = flags & CM_FLAG_CASEFOLD;
3390 /* make sure we only match 8.3 names, if requested */
3391 req8dot3 = (flags & CM_FLAG_8DOT3);
3392 if (req8dot3 && !cm_Is8Dot3(namep))
3397 /* Next pattern character */
3400 /* Next name character */
3404 /* 0 - end of pattern */
3410 else if (tcp1 == '.' || tcp1 == '"') {
3420 * first dot in pattern;
3421 * must match dot or end of name
3426 else if (tcn1 == '.') {
3435 else if (tcp1 == '?') {
3436 if (tcn1 == 0 || tcn1 == '.')
3441 else if (tcp1 == '>') {
3442 if (tcn1 != 0 && tcn1 != '.')
3446 else if (tcp1 == '*' || tcp1 == '<') {
3450 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3451 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3466 * pattern character after '*' is not null or
3467 * period. If it is '?' or '>', we are not
3468 * going to understand it. If it is '*' or
3469 * '<', we are going to skip over it. None of
3470 * these are likely, I hope.
3472 /* skip over '*' and '<' */
3473 while (tcp2 == '*' || tcp2 == '<')
3476 /* skip over characters that don't match tcp2 */
3477 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
3478 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
3479 (!casefold && tcn1 != tcp2)))
3483 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3486 /* Remember where we are */
3496 /* tcp1 is not a wildcard */
3497 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
3498 (!casefold && tcn1 == tcp1)) {
3503 /* if trying to match a star pattern, go back */
3505 maskp = starMaskp - 2;
3506 namep = starNamep + 1;
3515 #endif /* USE_OLD_MATCHING */
3517 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3526 smb_dirListPatch_t *dirListPatchesp;
3527 smb_dirListPatch_t *curPatchp;
3530 long orbytes; /* # of bytes in this output record */
3531 long ohbytes; /* # of bytes, except file name */
3532 long onbytes; /* # of bytes in name, incl. term. null */
3533 osi_hyper_t dirLength;
3534 osi_hyper_t bufferOffset;
3535 osi_hyper_t curOffset;
3537 smb_dirSearch_t *dsp;
3541 cm_pageHeader_t *pageHeaderp;
3542 cm_user_t *userp = NULL;
3545 long nextEntryCookie;
3546 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3547 char *op; /* output data ptr */
3548 char *origOp; /* original value of op */
3549 cm_space_t *spacep; /* for pathname buffer */
3550 long maxReturnData; /* max # of return data */
3551 long maxReturnParms; /* max # of return parms */
3552 long bytesInBuffer; /* # data bytes in the output buffer */
3554 char *maskp; /* mask part of path */
3558 smb_tran2Packet_t *outp; /* response packet */
3561 char shortName[13]; /* 8.3 name if needed */
3572 if (p->opcode == 1) {
3573 /* find first; obtain basic parameters from request */
3574 attribute = p->parmsp[0];
3575 maxCount = p->parmsp[1];
3576 infoLevel = p->parmsp[3];
3577 searchFlags = p->parmsp[2];
3578 dsp = smb_NewDirSearch(1);
3579 dsp->attribute = attribute;
3580 pathp = ((char *) p->parmsp) + 12; /* points to path */
3582 maskp = strrchr(pathp, '\\');
3586 maskp++; /* skip over backslash */
3587 strcpy(dsp->mask, maskp); /* and save mask */
3588 /* track if this is likely to match a lot of entries */
3589 starPattern = smb_V3IsStarMask(maskp);
3592 osi_assert(p->opcode == 2);
3593 /* find next; obtain basic parameters from request or open dir file */
3594 dsp = smb_FindDirSearch(p->parmsp[0]);
3596 return CM_ERROR_BADFD;
3597 attribute = dsp->attribute;
3598 maxCount = p->parmsp[1];
3599 infoLevel = p->parmsp[2];
3600 searchFlags = p->parmsp[5];
3602 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
3604 starPattern = 1; /* assume, since required a Find Next */
3608 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
3609 attribute, infoLevel, maxCount, searchFlags);
3611 osi_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
3612 p->opcode, nextCookie);
3614 if (infoLevel >= 0x101)
3615 searchFlags &= ~4; /* no resume keys */
3617 dirListPatchesp = NULL;
3619 maxReturnData = p->maxReturnData;
3620 if (p->opcode == 1) /* find first */
3621 maxReturnParms = 10; /* bytes */
3623 maxReturnParms = 8; /* bytes */
3625 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
3626 if (maxReturnData > 6000)
3627 maxReturnData = 6000;
3628 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
3630 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
3633 osi_Log1(smb_logp, "T2 receive search dir %s",
3634 osi_LogSaveString(smb_logp, pathp));
3636 /* bail out if request looks bad */
3637 if (p->opcode == 1 && !pathp) {
3638 smb_ReleaseDirSearch(dsp);
3639 smb_FreeTran2Packet(outp);
3640 return CM_ERROR_BADSMB;
3643 osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
3644 nextCookie, dsp->cookie);
3646 userp = smb_GetTran2User(vcp, p);
3648 osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p->uid);
3649 smb_ReleaseDirSearch(dsp);
3650 smb_FreeTran2Packet(outp);
3651 return CM_ERROR_BADSMB;
3654 /* try to get the vnode for the path name next */
3655 lock_ObtainMutex(&dsp->mx);
3662 spacep = cm_GetSpace();
3663 smb_StripLastComponent(spacep->data, NULL, pathp);
3664 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3666 lock_ReleaseMutex(&dsp->mx);
3667 cm_ReleaseUser(userp);
3668 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
3669 smb_FreeTran2Packet(outp);
3670 smb_DeleteDirSearch(dsp);
3671 smb_ReleaseDirSearch(dsp);
3674 code = cm_NameI(cm_rootSCachep, spacep->data,
3675 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3676 userp, tidPathp, &req, &scp);
3677 cm_FreeSpace(spacep);
3681 cm_ReleaseSCache(dsp->scp);
3683 /* we need one hold for the entry we just stored into,
3684 * and one for our own processing. When we're done
3685 * with this function, we'll drop the one for our own
3686 * processing. We held it once from the namei call,
3687 * and so we do another hold now.
3690 lock_ObtainMutex(&scp->mx);
3691 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
3692 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3693 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3694 dsp->flags |= SMB_DIRSEARCH_BULKST;
3696 lock_ReleaseMutex(&scp->mx);
3699 lock_ReleaseMutex(&dsp->mx);
3701 cm_ReleaseUser(userp);
3702 smb_FreeTran2Packet(outp);
3703 smb_DeleteDirSearch(dsp);
3704 smb_ReleaseDirSearch(dsp);
3708 /* get the directory size */
3709 lock_ObtainMutex(&scp->mx);
3710 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3711 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3713 lock_ReleaseMutex(&scp->mx);
3714 cm_ReleaseSCache(scp);
3715 cm_ReleaseUser(userp);
3716 smb_FreeTran2Packet(outp);
3717 smb_DeleteDirSearch(dsp);
3718 smb_ReleaseDirSearch(dsp);
3723 dirLength = scp->length;
3725 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3726 curOffset.HighPart = 0;
3727 curOffset.LowPart = nextCookie;
3728 origOp = outp->datap;
3736 if (searchFlags & 4)
3737 /* skip over resume key */
3740 /* make sure that curOffset.LowPart doesn't point to the first
3741 * 32 bytes in the 2nd through last dir page, and that it doesn't
3742 * point at the first 13 32-byte chunks in the first dir page,
3743 * since those are dir and page headers, and don't contain useful
3746 temp = curOffset.LowPart & (2048-1);
3747 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3748 /* we're in the first page */
3749 if (temp < 13*32) temp = 13*32;
3752 /* we're in a later dir page */
3753 if (temp < 32) temp = 32;
3756 /* make sure the low order 5 bits are zero */
3759 /* now put temp bits back ito curOffset.LowPart */
3760 curOffset.LowPart &= ~(2048-1);
3761 curOffset.LowPart |= temp;
3763 /* check if we've passed the dir's EOF */
3764 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
3769 /* check if we've returned all the names that will fit in the
3770 * response packet; we check return count as well as the number
3771 * of bytes requested. We check the # of bytes after we find
3772 * the dir entry, since we'll need to check its size.
3774 if (returnedNames >= maxCount) {
3778 /* see if we can use the bufferp we have now; compute in which
3779 * page the current offset would be, and check whether that's
3780 * the offset of the buffer we have. If not, get the buffer.
3782 thyper.HighPart = curOffset.HighPart;
3783 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3784 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3787 buf_Release(bufferp);
3790 lock_ReleaseMutex(&scp->mx);
3791 lock_ObtainRead(&scp->bufCreateLock);
3792 code = buf_Get(scp, &thyper, &bufferp);
3793 lock_ReleaseRead(&scp->bufCreateLock);
3794 lock_ObtainMutex(&dsp->mx);
3796 /* now, if we're doing a star match, do bulk fetching
3797 * of all of the status info for files in the dir.
3800 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
3803 lock_ObtainMutex(&scp->mx);
3804 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3805 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
3806 /* Don't bulk stat if risking timeout */
3807 int now = GetCurrentTime();
3808 if (now - req.startTime > 5000) {
3809 scp->bulkStatProgress = thyper;
3810 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3811 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3813 cm_TryBulkStat(scp, &thyper, userp, &req);
3816 lock_ObtainMutex(&scp->mx);
3818 lock_ReleaseMutex(&dsp->mx);
3822 bufferOffset = thyper;
3824 /* now get the data in the cache */
3826 code = cm_SyncOp(scp, bufferp, userp, &req,
3828 CM_SCACHESYNC_NEEDCALLBACK
3829 | CM_SCACHESYNC_READ);
3832 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3834 /* otherwise, load the buffer and try again */
3835 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3840 buf_Release(bufferp);
3844 } /* if (wrong buffer) ... */
3846 /* now we have the buffer containing the entry we're interested
3847 * in; copy it out if it represents a non-deleted entry.
3849 entryInDir = curOffset.LowPart & (2048-1);
3850 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3852 /* page header will help tell us which entries are free. Page
3853 * header can change more often than once per buffer, since
3854 * AFS 3 dir page size may be less than (but not more than)
3855 * a buffer package buffer.
3857 /* only look intra-buffer */
3858 temp = curOffset.LowPart & (buf_bufferSize - 1);
3859 temp &= ~(2048 - 1); /* turn off intra-page bits */
3860 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3862 /* now determine which entry we're looking at in the page.
3863 * If it is free (there's a free bitmap at the start of the
3864 * dir), we should skip these 32 bytes.
3866 slotInPage = (entryInDir & 0x7e0) >> 5;
3867 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
3868 (1 << (slotInPage & 0x7)))) {
3869 /* this entry is free */
3870 numDirChunks = 1; /* only skip this guy */
3874 tp = bufferp->datap + entryInBuffer;
3875 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3877 /* while we're here, compute the next entry's location, too,
3878 * since we'll need it when writing out the cookie into the dir
3881 * XXXX Probably should do more sanity checking.
3883 numDirChunks = cm_NameEntries(dep->name, &onbytes);
3885 /* compute offset of cookie representing next entry */
3886 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3888 /* Need 8.3 name? */
3890 if (infoLevel == 0x104
3891 && dep->fid.vnode != 0
3892 && !cm_Is8Dot3(dep->name)) {
3893 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3897 /* When matching, we are using doing a case fold if we have a wildcard mask.
3898 * If we get a non-wildcard match, it's a lookup for a specific file.
3900 if (dep->fid.vnode != 0 &&
3901 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
3903 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
3905 /* Eliminate entries that don't match requested attributes */
3906 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
3907 smb_IsDotFile(dep->name))
3908 goto nextEntry; /* no hidden files */
3910 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3912 /* We have already done the cm_TryBulkStat above */
3913 fid.cell = scp->fid.cell;
3914 fid.volume = scp->fid.volume;
3915 fid.vnode = ntohl(dep->fid.vnode);
3916 fid.unique = ntohl(dep->fid.unique);
3917 fileType = cm_FindFileType(&fid);
3918 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
3919 "has filetype %d", dep->name,
3921 if (fileType == CM_SCACHETYPE_DIRECTORY)
3925 /* finally check if this name will fit */
3927 /* standard dir entry stuff */
3928 if (infoLevel < 0x101)
3929 ohbytes = 23; /* pre-NT */
3930 else if (infoLevel == 0x103)
3931 ohbytes = 12; /* NT names only */
3933 ohbytes = 64; /* NT */
3935 if (infoLevel == 0x104)
3936 ohbytes += 26; /* Short name & length */
3938 if (searchFlags & 4) {
3939 ohbytes += 4; /* if resume key required */
3943 && infoLevel != 0x101
3944 && infoLevel != 0x103)
3945 ohbytes += 4; /* EASIZE */
3947 /* add header to name & term. null */
3948 orbytes = onbytes + ohbytes + 1;
3950 /* now, we round up the record to a 4 byte alignment,
3951 * and we make sure that we have enough room here for
3952 * even the aligned version (so we don't have to worry
3953 * about an * overflow when we pad things out below).
3954 * That's the reason for the alignment arithmetic below.
3956 if (infoLevel >= 0x101)
3957 align = (4 - (orbytes & 3)) & 3;
3960 if (orbytes + bytesInBuffer + align > maxReturnData)
3963 /* this is one of the entries to use: it is not deleted
3964 * and it matches the star pattern we're looking for.
3965 * Put out the name, preceded by its length.
3967 /* First zero everything else */
3968 memset(origOp, 0, ohbytes);
3970 if (infoLevel <= 0x101)
3971 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
3972 else if (infoLevel == 0x103)
3973 *((u_long *)(op + 8)) = onbytes;
3975 *((u_long *)(op + 60)) = onbytes;
3976 strcpy(origOp+ohbytes, dep->name);
3978 /* Short name if requested and needed */
3979 if (infoLevel == 0x104) {
3980 if (NeedShortName) {
3981 strcpy(op + 70, shortName);
3982 *(op + 68) = shortNameEnd - shortName;
3986 /* now, adjust the # of entries copied */
3989 /* NextEntryOffset and FileIndex */
3990 if (infoLevel >= 101) {
3991 int entryOffset = orbytes + align;
3992 *((u_long *)op) = entryOffset;
3993 *((u_long *)(op+4)) = nextEntryCookie;
3996 /* now we emit the attribute. This is tricky, since
3997 * we need to really stat the file to find out what
3998 * type of entry we've got. Right now, we're copying
3999 * out data from * a buffer, while holding the scp
4000 * locked, so it isn't really convenient to stat
4001 * something now. We'll put in a place holder
4002 * now, and make a second pass before returning this
4003 * to get the real attributes. So, we just skip the
4004 * data for now, and adjust it later. We allocate a
4005 * patch record to make it easy to find this point
4006 * later. The replay will happen at a time when it is
4007 * safe to unlock the directory.
4009 if (infoLevel != 0x103) {
4010 curPatchp = malloc(sizeof(*curPatchp));
4011 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4013 curPatchp->dptr = op;
4014 if (infoLevel >= 0x101)
4015 curPatchp->dptr += 8;
4017 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4018 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4021 curPatchp->flags = 0;
4023 curPatchp->fid.cell = scp->fid.cell;
4024 curPatchp->fid.volume = scp->fid.volume;
4025 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4026 curPatchp->fid.unique = ntohl(dep->fid.unique);
4029 curPatchp->dep = dep;
4032 if (searchFlags & 4)
4033 /* put out resume key */
4034 *((u_long *)origOp) = nextEntryCookie;
4036 /* Adjust byte ptr and count */
4037 origOp += orbytes; /* skip entire record */
4038 bytesInBuffer += orbytes;
4040 /* and pad the record out */
4041 while (--align >= 0) {
4045 } /* if we're including this name */
4046 else if (!NeedShortName &&
4049 dep->fid.vnode != 0 &&
4050 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4051 /* We were looking for exact matches, but here's an inexact one*/
4056 /* and adjust curOffset to be where the new cookie is */
4057 thyper.HighPart = 0;
4058 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4059 curOffset = LargeIntegerAdd(thyper, curOffset);
4060 } /* while copying data for dir listing */
4062 /* If we didn't get a star pattern, we did an exact match during the first pass.
4063 * If there were no exact matches found, we fail over to inexact matches by
4064 * marking the query as a star pattern (matches all case permutations), and
4065 * re-running the query.
4067 if (returnedNames == 0 && !starPattern && foundInexact) {
4068 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4073 /* release the mutex */
4074 lock_ReleaseMutex(&scp->mx);
4075 if (bufferp) buf_Release(bufferp);
4077 /* apply and free last set of patches; if not doing a star match, this
4078 * will be empty, but better safe (and freeing everything) than sorry.
4080 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4083 /* now put out the final parameters */
4084 if (returnedNames == 0) eos = 1;
4085 if (p->opcode == 1) {
4087 outp->parmsp[0] = (unsigned short) dsp->cookie;
4088 outp->parmsp[1] = returnedNames;
4089 outp->parmsp[2] = eos;
4090 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4091 outp->parmsp[4] = 0;
4092 /* don't need last name to continue
4093 * search, cookie is enough. Normally,
4094 * this is the offset of the file name
4095 * of the last entry returned.
4097 outp->totalParms = 10; /* in bytes */
4101 outp->parmsp[0] = returnedNames;
4102 outp->parmsp[1] = eos;
4103 outp->parmsp[2] = 0; /* EAS error */
4104 outp->parmsp[3] = 0; /* last name, as above */
4105 outp->totalParms = 8; /* in bytes */
4108 /* return # of bytes in the buffer */
4109 outp->totalData = bytesInBuffer;
4111 osi_Log2(smb_logp, "T2 search dir done, %d names, code %d",
4112 returnedNames, code);
4114 /* Return error code if unsuccessful on first request */
4115 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4116 code = CM_ERROR_NOSUCHFILE;
4118 /* if we're supposed to close the search after this request, or if
4119 * we're supposed to close the search if we're done, and we're done,
4120 * or if something went wrong, close the search.
4122 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4123 if ((searchFlags & 1) || (returnedNames == 0) ||
4124 ((searchFlags & 2) && eos) || code != 0)
4125 smb_DeleteDirSearch(dsp);
4127 smb_SendTran2Error(vcp, p, opx, code);
4129 smb_SendTran2Packet(vcp, outp, opx);
4131 smb_FreeTran2Packet(outp);
4132 smb_ReleaseDirSearch(dsp);
4133 cm_ReleaseSCache(scp);
4134 cm_ReleaseUser(userp);
4138 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4141 smb_dirSearch_t *dsp;
4143 dirHandle = smb_GetSMBParm(inp, 0);
4145 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4147 dsp = smb_FindDirSearch(dirHandle);
4150 return CM_ERROR_BADFD;
4152 /* otherwise, we have an FD to destroy */
4153 smb_DeleteDirSearch(dsp);
4154 smb_ReleaseDirSearch(dsp);
4156 /* and return results */
4157 smb_SetSMBDataLength(outp, 0);
4162 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4164 smb_SetSMBDataLength(outp, 0);
4168 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4175 cm_scache_t *dscp; /* dir we're dealing with */
4176 cm_scache_t *scp; /* file we're creating */
4178 int initialModeBits;
4188 int parmSlot; /* which parm we're dealing with */
4196 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4197 openFun = smb_GetSMBParm(inp, 8); /* open function */
4198 excl = ((openFun & 3) == 0);
4199 trunc = ((openFun & 3) == 2); /* truncate it */
4200 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4201 openAction = 0; /* tracks what we did */
4203 attributes = smb_GetSMBParm(inp, 5);
4204 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4206 /* compute initial mode bits based on read-only flag in attributes */
4207 initialModeBits = 0666;
4208 if (attributes & 1) initialModeBits &= ~0222;
4210 pathp = smb_GetSMBData(inp, NULL);
4212 spacep = inp->spacep;
4213 smb_StripLastComponent(spacep->data, &lastNamep, pathp);