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
31 extern osi_hyper_t hzero;
33 smb_packet_t *smb_Directory_Watches = NULL;
34 osi_mutex_t smb_Dir_Watch_Lock;
36 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
38 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
40 /* protected by the smb_globalLock */
41 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
43 /* retrieve a held reference to a user structure corresponding to an incoming
45 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
50 uidp = smb_FindUID(vcp, inp->uid, 0);
51 if (!uidp) return NULL;
53 lock_ObtainMutex(&uidp->mx);
55 up = uidp->unp->userp;
58 lock_ReleaseMutex(&uidp->mx);
66 * Return extended attributes.
67 * Right now, we aren't using any of the "new" bits, so this looks exactly
68 * like smb_Attributes() (see smb.c).
70 unsigned long smb_ExtAttributes(cm_scache_t *scp)
74 if (scp->fileType == CM_SCACHETYPE_DIRECTORY
75 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
76 attrs = SMB_ATTR_DIRECTORY;
80 * We used to mark a file RO if it was in an RO volume, but that
81 * turns out to be impolitic in NT. See defect 10007.
84 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
86 if ((scp->unixModeBits & 0222) == 0)
87 attrs |= SMB_ATTR_READONLY; /* Read-only */
90 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
95 int smb_V3IsStarMask(char *maskp)
100 if (tc == '?' || tc == '*')
105 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
108 /* skip over null-terminated string */
109 *chainpp = inp + strlen(inp) + 1;
114 /*DEBUG do not checkin*/
115 void OutputDebugF(char * format, ...) {
120 va_start( args, format );
121 len = _vscprintf( format, args ) // _vscprintf doesn't count
122 + 3; // terminating '\0' + '\n'
123 buffer = malloc( len * sizeof(char) );
124 vsprintf( buffer, format, args );
125 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buffer));
126 strcat(buffer, "\n");
127 OutputDebugString(buffer);
131 void OutputDebugHexDump(unsigned char * buffer, int len) {
134 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
136 OutputDebugF("Hexdump length [%d]",len);
141 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
143 OutputDebugString(buf);
145 sprintf(buf,"%5x",i);
146 memset(buf+5,' ',80);
151 j = j*3 + 7 + ((j>7)?1:0);
154 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
157 j = j + 56 + ((j>7)?1:0);
159 buf[j] = (k>32 && k<127)?k:'.';
162 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
164 OutputDebugString(buf);
169 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
170 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength){
171 SECURITY_STATUS status, istatus;
172 CredHandle creds = {0,0};
174 SecBufferDesc secOut;
182 OutputDebugF("Negotiating Extended Security");
184 status = AcquireCredentialsHandle(
186 SMB_EXT_SEC_PACKAGE_NAME,
195 if (status != SEC_E_OK) {
196 /* Really bad. We return an empty security blob */
197 OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
202 secOut.pBuffers = &secTok;
203 secOut.ulVersion = SECBUFFER_VERSION;
205 secTok.BufferType = SECBUFFER_TOKEN;
207 secTok.pvBuffer = NULL;
209 ctx.dwLower = ctx.dwUpper = 0;
211 status = AcceptSecurityContext(
215 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
216 SECURITY_NETWORK_DREP,
223 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
224 OutputDebugF("Completing token...");
225 istatus = CompleteAuthToken(&ctx, &secOut);
226 if ( istatus != SEC_E_OK )
227 OutputDebugF("Token completion failed: %x", istatus);
230 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
231 if (secTok.pvBuffer) {
232 *secBlobLength = secTok.cbBuffer;
233 *secBlob = malloc( secTok.cbBuffer );
234 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
237 if ( status != SEC_E_OK )
238 OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
241 /* Discard partial security context */
242 DeleteSecurityContext(&ctx);
244 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
246 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
247 FreeCredentialsHandle(&creds);
253 struct smb_ext_context {
260 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
261 SECURITY_STATUS status, istatus;
265 SecBufferDesc secBufIn;
267 SecBufferDesc secBufOut;
270 struct smb_ext_context * secCtx = NULL;
271 struct smb_ext_context * newSecCtx = NULL;
272 void * assembledBlob = NULL;
273 int assembledBlobLength = 0;
276 OutputDebugF("In smb_AuthenticateUserExt");
279 *secBlobOutLength = 0;
281 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
282 secCtx = vcp->secCtx;
283 lock_ObtainMutex(&vcp->mx);
284 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
286 lock_ReleaseMutex(&vcp->mx);
290 OutputDebugF("Received incoming token:");
291 OutputDebugHexDump(secBlobIn,secBlobInLength);
295 OutputDebugF("Continuing with existing context.");
296 creds = secCtx->creds;
299 if (secCtx->partialToken) {
300 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
301 assembledBlob = malloc(assembledBlobLength);
302 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
303 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
306 status = AcquireCredentialsHandle(
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(
350 ((secCtx)?&ctx:NULL),
352 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
353 SECURITY_NETWORK_DREP,
360 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
361 OutputDebugF("Completing token...");
362 istatus = CompleteAuthToken(&ctx, &secBufOut);
363 if ( istatus != SEC_E_OK )
364 OutputDebugF("Token completion failed: %lX", istatus);
367 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
368 OutputDebugF("Continue needed");
370 newSecCtx = malloc(sizeof(*newSecCtx));
372 newSecCtx->creds = creds;
373 newSecCtx->ctx = ctx;
374 newSecCtx->partialToken = NULL;
375 newSecCtx->partialTokenLen = 0;
377 lock_ObtainMutex( &vcp->mx );
378 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
379 vcp->secCtx = newSecCtx;
380 lock_ReleaseMutex( &vcp->mx );
382 code = CM_ERROR_GSSCONTINUE;
385 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
386 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
387 secTokOut.pvBuffer) {
388 OutputDebugF("Need to send token back to client");
390 *secBlobOutLength = secTokOut.cbBuffer;
391 *secBlobOut = malloc(secTokOut.cbBuffer);
392 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
394 OutputDebugF("Outgoing token:");
395 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
396 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
397 OutputDebugF("Incomplete message");
399 newSecCtx = malloc(sizeof(*newSecCtx));
401 newSecCtx->creds = creds;
402 newSecCtx->ctx = ctx;
403 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
404 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
405 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
407 lock_ObtainMutex( &vcp->mx );
408 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
409 vcp->secCtx = newSecCtx;
410 lock_ReleaseMutex( &vcp->mx );
412 code = CM_ERROR_GSSCONTINUE;
415 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
417 SecPkgContext_Names names;
419 OutputDebugF("Authentication completed");
420 OutputDebugF("Returned flags : [%lX]", flags);
422 if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
423 OutputDebugF("Received name [%s]", names.sUserName);
424 strcpy(usern, names.sUserName);
425 strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
426 FreeContextBuffer(names.sUserName);
428 /* Force the user to retry if the context is invalid */
429 OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
430 code = CM_ERROR_BADPASSWORD;
434 case SEC_E_INVALID_TOKEN:
435 OutputDebugF("Returning bad password :: INVALID_TOKEN");
437 case SEC_E_INVALID_HANDLE:
438 OutputDebugF("Returning bad password :: INVALID_HANDLE");
440 case SEC_E_LOGON_DENIED:
441 OutputDebugF("Returning bad password :: LOGON_DENIED");
443 case SEC_E_UNKNOWN_CREDENTIALS:
444 OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
446 case SEC_E_NO_CREDENTIALS:
447 OutputDebugF("Returning bad password :: NO_CREDENTIALS");
449 case SEC_E_CONTEXT_EXPIRED:
450 OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
452 case SEC_E_INCOMPLETE_CREDENTIALS:
453 OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
455 case SEC_E_WRONG_PRINCIPAL:
456 OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
458 case SEC_E_TIME_SKEW:
459 OutputDebugF("Returning bad password :: TIME_SKEW");
462 OutputDebugF("Returning bad password :: Status == %lX", status);
464 code = CM_ERROR_BADPASSWORD;
468 if (secCtx->partialToken) free(secCtx->partialToken);
476 if (secTokOut.pvBuffer)
477 FreeContextBuffer(secTokOut.pvBuffer);
479 if (code != CM_ERROR_GSSCONTINUE) {
480 DeleteSecurityContext(&ctx);
481 FreeCredentialsHandle(&creds);
489 #define P_RESP_LEN 128
491 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
492 So put stuff in a struct. */
493 struct Lm20AuthBlob {
494 MSV1_0_LM20_LOGON lmlogon;
495 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
496 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
497 WCHAR accountNameW[P_LEN];
498 WCHAR primaryDomainW[P_LEN];
499 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
500 TOKEN_GROUPS tgroups;
501 TOKEN_SOURCE tsource;
504 long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength) {
507 struct Lm20AuthBlob lmAuth;
508 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
509 QUOTA_LIMITS quotaLimits;
511 ULONG lmprofilepSize;
515 OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
516 OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
518 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
519 OutputDebugF("ciPwdLength or csPwdLength is too long");
520 return CM_ERROR_BADPASSWORD;
523 memset(&lmAuth,0,sizeof(lmAuth));
525 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
527 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
528 mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
529 lmAuth.lmlogon.LogonDomainName.Length = wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR);
530 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
532 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
533 mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
534 lmAuth.lmlogon.UserName.Length = wcslen(lmAuth.accountNameW) * sizeof(WCHAR);
535 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
537 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
538 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
539 size = MAX_COMPUTERNAME_LENGTH + 1;
540 GetComputerNameW(lmAuth.workstationW, &size);
541 lmAuth.lmlogon.Workstation.Length = wcslen(lmAuth.workstationW) * sizeof(WCHAR);
543 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
545 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
546 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
547 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
548 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
550 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
551 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
552 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
553 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
555 lmAuth.lmlogon.ParameterControl = 0;
557 lmAuth.tgroups.GroupCount = 0;
558 lmAuth.tgroups.Groups[0].Sid = NULL;
559 lmAuth.tgroups.Groups[0].Attributes = 0;
561 lmAuth.tsource.SourceIdentifier.HighPart = 0;
562 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD) vcp;
563 strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
581 OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
582 OutputDebugF("Extended status is 0x%lX", ntsEx);
584 if (nts == ERROR_SUCCESS) {
586 LsaFreeReturnBuffer(lmprofilep);
587 CloseHandle(lmToken);
591 if (nts == 0xC000015BL)
592 return CM_ERROR_BADLOGONTYPE;
593 else /* our catchall is a bad password though we could be more specific */
594 return CM_ERROR_BADPASSWORD;
598 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
599 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName) {
604 /* check if we have sane input */
605 if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
608 /* we could get : [accountName][domainName]
614 atsign = strchr(accountName, '@');
616 if (atsign) /* [user@domain][] -> [user@domain][domain] */
621 /* if for some reason the client doesn't know what domain to use,
622 it will either return an empty string or a '?' */
623 if (!domain[0] || domain[0] == '?')
624 /* Empty domains and empty usernames are usually sent from tokenless contexts.
625 This way such logins will get an empty username (easy to check). I don't know
626 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
627 strcpy(usern,accountName);
629 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
630 strcpy(usern,domain);
633 strncat(usern,accountName,atsign - accountName);
635 strcat(usern,accountName);
643 /* When using SMB auth, all SMB sessions have to pass through here first to
644 * authenticate the user.
645 * Caveat: If not use the SMB auth the protocol does not require sending a
646 * session setup packet, which means that we can't rely on a UID in subsequent
647 * packets. Though in practice we get one anyway.
649 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
653 unsigned short newUid;
654 unsigned long caps = 0;
659 char usern[SMB_MAX_USERNAME_LENGTH];
660 char *secBlobOut = NULL;
661 int secBlobOutLength = 0;
663 /* Check for bad conns */
664 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
665 return CM_ERROR_REMOTECONN;
667 if (vcp->flags & SMB_VCFLAG_USENT) {
668 if (smb_authType == SMB_AUTH_EXTENDED) {
669 /* extended authentication */
673 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
674 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
677 secBlobInLength = smb_GetSMBParm(inp, 7);
678 secBlobIn = smb_GetSMBData(inp, NULL);
680 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
682 if (code == CM_ERROR_GSSCONTINUE) {
683 smb_SetSMBParm(outp, 2, 0);
684 smb_SetSMBParm(outp, 3, secBlobOutLength);
685 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
686 tp = smb_GetSMBData(outp, NULL);
687 if (secBlobOutLength) {
688 memcpy(tp, secBlobOut, secBlobOutLength);
690 tp += secBlobOutLength;
692 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
693 tp += smb_ServerOSLength;
694 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
695 tp += smb_ServerLanManagerLength;
696 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
697 tp += smb_ServerDomainNameLength;
700 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
702 unsigned ciPwdLength, csPwdLength;
708 /* TODO: parse for extended auth as well */
709 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
710 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
712 tp = smb_GetSMBData(inp, &datalen);
714 OutputDebugF("Session packet data size [%d]",datalen);
721 accountName = smb_ParseString(tp, &tp);
722 primaryDomain = smb_ParseString(tp, NULL);
724 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
725 /* shouldn't happen */
726 code = CM_ERROR_BADSMB;
727 goto after_read_packet;
730 /* capabilities are only valid for first session packet */
731 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
732 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
735 if (smb_authType == SMB_AUTH_NTLM) {
736 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
740 unsigned ciPwdLength;
745 ciPwdLength = smb_GetSMBParm(inp, 7);
746 tp = smb_GetSMBData(inp, NULL);
750 accountName = smb_ParseString(tp, &tp);
751 primaryDomain = smb_ParseString(tp, NULL);
753 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
754 /* shouldn't happen */
755 code = CM_ERROR_BADSMB;
756 goto after_read_packet;
759 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
762 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
763 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
768 /* note down that we received a session setup X and set the capabilities flag */
769 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
770 lock_ObtainMutex(&vcp->mx);
771 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
772 /* for the moment we can only deal with NTSTATUS */
773 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
774 vcp->flags |= SMB_VCFLAG_STATUS32;
776 lock_ReleaseMutex(&vcp->mx);
779 /* code would be non-zero if there was an authentication failure.
780 Ideally we would like to invalidate the uid for this session or break
781 early to avoid accidently stealing someone else's tokens. */
787 OutputDebugF("Received username=[%s]", usern);
789 /* On Windows 2000, this function appears to be called more often than
790 it is expected to be called. This resulted in multiple smb_user_t
791 records existing all for the same user session which results in all
792 of the users tokens disappearing.
794 To avoid this problem, we look for an existing smb_user_t record
795 based on the users name, and use that one if we find it.
798 uidp = smb_FindUserByNameThisSession(vcp, usern);
799 if (uidp) { /* already there, so don't create a new one */
802 newUid = (unsigned short)uidp->userID; /* For some reason these are different types!*/
803 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));
804 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
805 smb_ReleaseUID(uidp);
808 /* do a global search for the username/machine name pair */
809 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
811 /* Create a new UID and cm_user_t structure */
814 userp = cm_NewUser();
815 lock_ObtainMutex(&vcp->mx);
816 if (!vcp->uidCounter)
817 vcp->uidCounter++; /* handle unlikely wraparounds */
818 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
819 lock_ReleaseMutex(&vcp->mx);
821 /* Create a new smb_user_t structure and connect them up */
822 lock_ObtainMutex(&unp->mx);
824 lock_ReleaseMutex(&unp->mx);
826 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
827 lock_ObtainMutex(&uidp->mx);
829 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));
830 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
831 lock_ReleaseMutex(&uidp->mx);
832 smb_ReleaseUID(uidp);
835 /* Return UID to the client */
836 ((smb_t *)outp)->uid = newUid;
837 /* Also to the next chained message */
838 ((smb_t *)inp)->uid = newUid;
840 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
841 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
843 smb_SetSMBParm(outp, 2, 0);
845 if (vcp->flags & SMB_VCFLAG_USENT) {
846 if (smb_authType == SMB_AUTH_EXTENDED) {
847 smb_SetSMBParm(outp, 3, secBlobOutLength);
848 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
849 tp = smb_GetSMBData(outp, NULL);
850 if (secBlobOutLength) {
851 memcpy(tp, secBlobOut, secBlobOutLength);
853 tp += secBlobOutLength;
855 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
856 tp += smb_ServerOSLength;
857 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
858 tp += smb_ServerLanManagerLength;
859 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
860 tp += smb_ServerDomainNameLength;
862 smb_SetSMBDataLength(outp, 0);
865 if (smb_authType == SMB_AUTH_EXTENDED) {
866 smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
867 tp = smb_GetSMBData(outp, NULL);
868 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
869 tp += smb_ServerOSLength;
870 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
871 tp += smb_ServerLanManagerLength;
872 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
873 tp += smb_ServerDomainNameLength;
875 smb_SetSMBDataLength(outp, 0);
882 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
886 /* don't get tokens from this VC */
887 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
889 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
891 /* find the tree and free it */
892 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
893 /* TODO: smb_ReleaseUID() ? */
895 char *s1 = NULL, *s2 = NULL;
897 if (s2 == NULL) s2 = " ";
898 if (s1 == NULL) {s1 = s2; s2 = " ";}
900 osi_Log4(smb_logp, "SMB3 user logoffX uid %d name %s%s%s", uidp->userID,
901 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "), s1, s2);
903 lock_ObtainMutex(&uidp->mx);
904 uidp->flags |= SMB_USERFLAG_DELETE;
906 * it doesn't get deleted right away
907 * because the vcp points to it
909 lock_ReleaseMutex(&uidp->mx);
912 osi_Log0(smb_logp, "SMB3 user logoffX");
914 smb_SetSMBDataLength(outp, 0);
918 #define SMB_SUPPORT_SEARCH_BITS 0x0001
920 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
924 unsigned short newTid;
935 osi_Log0(smb_logp, "SMB3 receive tree connect");
937 /* parse input parameters */
938 tp = smb_GetSMBData(inp, NULL);
939 passwordp = smb_ParseString(tp, &tp);
940 pathp = smb_ParseString(tp, &tp);
941 servicep = smb_ParseString(tp, &tp);
943 tp = strrchr(pathp, '\\');
945 return CM_ERROR_BADSMB;
947 strcpy(shareName, tp+1);
949 osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
950 osi_LogSaveString(smb_logp, pathp),
951 osi_LogSaveString(smb_logp, shareName));
953 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
955 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
958 return CM_ERROR_NOIPC;
962 userp = smb_GetUser(vcp, inp);
964 lock_ObtainMutex(&vcp->mx);
965 newTid = vcp->tidCounter++;
966 lock_ReleaseMutex(&vcp->mx);
968 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
971 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
972 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
974 smb_ReleaseUID(uidp);
976 smb_ReleaseTID(tidp);
977 return CM_ERROR_BADSHARENAME;
980 if (vcp->flags & SMB_VCFLAG_USENT)
982 int policy = smb_FindShareCSCPolicy(shareName);
983 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS | (policy << 2));
986 smb_SetSMBParm(outp, 2, 0);
990 lock_ObtainMutex(&tidp->mx);
992 tidp->pathname = sharePath;
993 if(ipc) tidp->flags |= SMB_TIDFLAG_IPC;
994 lock_ReleaseMutex(&tidp->mx);
995 smb_ReleaseTID(tidp);
997 ((smb_t *)outp)->tid = newTid;
998 ((smb_t *)inp)->tid = newTid;
999 tp = smb_GetSMBData(outp, NULL);
1004 smb_SetSMBDataLength(outp, 3);
1007 smb_SetSMBDataLength(outp, 4);
1010 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1014 /* must be called with global tran lock held */
1015 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1017 smb_tran2Packet_t *tp;
1020 smbp = (smb_t *) inp->data;
1021 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1022 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1028 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1029 int totalParms, int totalData)
1031 smb_tran2Packet_t *tp;
1034 smbp = (smb_t *) inp->data;
1035 tp = malloc(sizeof(*tp));
1036 memset(tp, 0, sizeof(*tp));
1039 tp->curData = tp->curParms = 0;
1040 tp->totalData = totalData;
1041 tp->totalParms = totalParms;
1042 tp->tid = smbp->tid;
1043 tp->mid = smbp->mid;
1044 tp->uid = smbp->uid;
1045 tp->pid = smbp->pid;
1046 tp->res[0] = smbp->res[0];
1047 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1048 if (totalParms != 0)
1049 tp->parmsp = malloc(totalParms);
1051 tp->datap = malloc(totalData);
1052 if (smbp->com == 0x25 || smbp->com == 0x26)
1055 tp->opcode = smb_GetSMBParm(inp, 14);
1058 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1062 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1063 smb_tran2Packet_t *inp, smb_packet_t *outp,
1064 int totalParms, int totalData)
1066 smb_tran2Packet_t *tp;
1067 unsigned short parmOffset;
1068 unsigned short dataOffset;
1069 unsigned short dataAlign;
1071 tp = malloc(sizeof(*tp));
1072 memset(tp, 0, sizeof(*tp));
1074 tp->curData = tp->curParms = 0;
1075 tp->totalData = totalData;
1076 tp->totalParms = totalParms;
1077 tp->oldTotalParms = totalParms;
1082 tp->res[0] = inp->res[0];
1083 tp->opcode = inp->opcode;
1087 * We calculate where the parameters and data will start.
1088 * This calculation must parallel the calculation in
1089 * smb_SendTran2Packet.
1092 parmOffset = 10*2 + 35;
1093 parmOffset++; /* round to even */
1094 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1096 dataOffset = parmOffset + totalParms;
1097 dataAlign = dataOffset & 2; /* quad-align */
1098 dataOffset += dataAlign;
1099 tp->datap = outp->data + dataOffset;
1104 /* free a tran2 packet; must be called with smb_globalLock held */
1105 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1107 if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
1108 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1117 /* called with a VC, an input packet to respond to, and an error code.
1118 * sends an error response.
1120 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1121 smb_packet_t *tp, long code)
1124 unsigned short errCode;
1125 unsigned char errClass;
1126 unsigned long NTStatus;
1128 if (vcp->flags & SMB_VCFLAG_STATUS32)
1129 smb_MapNTError(code, &NTStatus);
1131 smb_MapCoreError(code, vcp, &errCode, &errClass);
1133 smb_FormatResponsePacket(vcp, NULL, tp);
1134 smbp = (smb_t *) tp;
1136 /* We can handle long names */
1137 if (vcp->flags & SMB_VCFLAG_USENT)
1138 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
1140 /* now copy important fields from the tran 2 packet */
1141 smbp->com = t2p->com;
1142 smbp->tid = t2p->tid;
1143 smbp->mid = t2p->mid;
1144 smbp->pid = t2p->pid;
1145 smbp->uid = t2p->uid;
1146 smbp->res[0] = t2p->res[0];
1147 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1148 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1149 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1150 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1151 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1152 smbp->flg2 |= 0x4000;
1155 smbp->rcls = errClass;
1156 smbp->errLow = (unsigned char) (errCode & 0xff);
1157 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1161 smb_SendPacket(vcp, tp);
1164 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1167 unsigned short parmOffset;
1168 unsigned short dataOffset;
1169 unsigned short totalLength;
1170 unsigned short dataAlign;
1173 smb_FormatResponsePacket(vcp, NULL, tp);
1174 smbp = (smb_t *) tp;
1176 /* We can handle long names */
1177 if (vcp->flags & SMB_VCFLAG_USENT)
1178 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
1180 /* now copy important fields from the tran 2 packet */
1181 smbp->com = t2p->com;
1182 smbp->tid = t2p->tid;
1183 smbp->mid = t2p->mid;
1184 smbp->pid = t2p->pid;
1185 smbp->uid = t2p->uid;
1186 smbp->res[0] = t2p->res[0];
1188 totalLength = 1 + t2p->totalData + t2p->totalParms;
1190 /* now add the core parameters (tran2 info) to the packet */
1191 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1192 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1193 smb_SetSMBParm(tp, 2, 0); /* reserved */
1194 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1195 parmOffset = 10*2 + 35; /* parm offset in packet */
1196 parmOffset++; /* round to even */
1197 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1198 * hdr, bcc and wct */
1199 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1200 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1201 dataOffset = parmOffset + t2p->oldTotalParms;
1202 dataAlign = dataOffset & 2; /* quad-align */
1203 dataOffset += dataAlign;
1204 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1205 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1206 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1209 datap = smb_GetSMBData(tp, NULL);
1210 *datap++ = 0; /* we rounded to even */
1212 totalLength += dataAlign;
1213 smb_SetSMBDataLength(tp, totalLength);
1215 /* next, send the datagram */
1216 smb_SendPacket(vcp, tp);
1219 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1221 smb_tran2Packet_t *asp;
1234 /* We sometimes see 0 word count. What to do? */
1235 if (*inp->wctp == 0) {
1240 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1242 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1243 ptbuf[0] = "Transaction2 word count = 0";
1244 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1245 1, inp->ncb_length, ptbuf, inp);
1246 DeregisterEventSource(h);
1248 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1251 smb_SetSMBDataLength(outp, 0);
1252 smb_SendPacket(vcp, outp);
1256 totalParms = smb_GetSMBParm(inp, 0);
1257 totalData = smb_GetSMBParm(inp, 1);
1259 firstPacket = (inp->inCom == 0x25);
1261 /* find the packet we're reassembling */
1262 lock_ObtainWrite(&smb_globalLock);
1263 asp = smb_FindTran2Packet(vcp, inp);
1265 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1267 lock_ReleaseWrite(&smb_globalLock);
1269 /* now merge in this latest packet; start by looking up offsets */
1271 parmDisp = dataDisp = 0;
1272 parmOffset = smb_GetSMBParm(inp, 10);
1273 dataOffset = smb_GetSMBParm(inp, 12);
1274 parmCount = smb_GetSMBParm(inp, 9);
1275 dataCount = smb_GetSMBParm(inp, 11);
1276 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1277 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1279 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1280 totalData, dataCount, asp->maxReturnData);
1283 parmDisp = smb_GetSMBParm(inp, 4);
1284 parmOffset = smb_GetSMBParm(inp, 3);
1285 dataDisp = smb_GetSMBParm(inp, 7);
1286 dataOffset = smb_GetSMBParm(inp, 6);
1287 parmCount = smb_GetSMBParm(inp, 2);
1288 dataCount = smb_GetSMBParm(inp, 5);
1290 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1291 parmCount, dataCount);
1294 /* now copy the parms and data */
1295 if ( asp->totalParms > 0 && parmCount != 0 )
1297 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1299 if ( asp->totalData > 0 && dataCount != 0 ) {
1300 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1303 /* account for new bytes */
1304 asp->curData += dataCount;
1305 asp->curParms += parmCount;
1307 /* finally, if we're done, remove the packet from the queue and dispatch it */
1308 if (asp->totalParms > 0 &&
1309 asp->curParms > 0 &&
1310 asp->totalData <= asp->curData &&
1311 asp->totalParms <= asp->curParms) {
1312 /* we've received it all */
1313 lock_ObtainWrite(&smb_globalLock);
1314 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1315 lock_ReleaseWrite(&smb_globalLock);
1317 /* now dispatch it */
1318 rapOp = asp->parmsp[0];
1320 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1321 osi_LogEvent("AFS-Dispatch-RAP[%s]",myCrt_RapDispatch(rapOp),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1322 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%x] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1323 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1326 osi_LogEvent("AFS-Dispatch-RAP [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1327 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1328 code = CM_ERROR_BADOP;
1331 /* if an error is returned, we're supposed to send an error packet,
1332 * otherwise the dispatched function already did the data sending.
1333 * We give dispatched proc the responsibility since it knows how much
1334 * space to allocate.
1337 smb_SendTran2Error(vcp, asp, outp, code);
1340 /* free the input tran 2 packet */
1341 lock_ObtainWrite(&smb_globalLock);
1342 smb_FreeTran2Packet(asp);
1343 lock_ReleaseWrite(&smb_globalLock);
1345 else if (firstPacket) {
1346 /* the first packet in a multi-packet request, we need to send an
1347 * ack to get more data.
1349 smb_SetSMBDataLength(outp, 0);
1350 smb_SendPacket(vcp, outp);
1356 /* ANSI versions. The unicode versions support arbitrary length
1357 share names, but we don't support unicode yet. */
1359 typedef struct smb_rap_share_info_0 {
1360 char shi0_netname[13];
1361 } smb_rap_share_info_0_t;
1363 typedef struct smb_rap_share_info_1 {
1364 char shi1_netname[13];
1367 DWORD shi1_remark; /* char *shi1_remark; data offset */
1368 } smb_rap_share_info_1_t;
1370 typedef struct smb_rap_share_info_2 {
1371 char shi2_netname[13];
1373 unsigned short shi2_type;
1374 DWORD shi2_remark; /* char *shi2_remark; data offset */
1375 unsigned short shi2_permissions;
1376 unsigned short shi2_max_uses;
1377 unsigned short shi2_current_uses;
1378 DWORD shi2_path; /* char *shi2_path; data offset */
1379 unsigned short shi2_passwd[9];
1380 unsigned short shi2_pad2;
1381 } smb_rap_share_info_2_t;
1383 #define SMB_RAP_MAX_SHARES 512
1385 typedef struct smb_rap_share_list {
1388 smb_rap_share_info_0_t * shares;
1389 } smb_rap_share_list_t;
1391 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1392 smb_rap_share_list_t * sp;
1397 if(name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1398 return 0; /* skip over '.' and '..' */
1400 sp = (smb_rap_share_list_t *) vrockp;
1402 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1403 sp->shares[sp->cShare].shi0_netname[12] = 0;
1407 if(sp->cShare >= sp->maxShares)
1408 return CM_ERROR_STOPNOW;
1413 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1415 smb_tran2Packet_t *outp;
1416 unsigned short * tp;
1420 int outParmsTotal; /* total parameter bytes */
1421 int outDataTotal; /* total data bytes */
1429 HKEY hkSubmount = NULL;
1430 smb_rap_share_info_1_t * shares;
1433 char thisShare[256];
1436 smb_rap_share_list_t rootShares;
1441 tp = p->parmsp + 1; /* skip over function number (always 0) */
1442 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1443 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1447 if(infoLevel != 1) {
1448 return CM_ERROR_INVAL;
1451 /* first figure out how many shares there are */
1452 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1453 KEY_QUERY_VALUE, &hkParam);
1454 if (rv == ERROR_SUCCESS) {
1455 len = sizeof(allSubmount);
1456 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1457 (BYTE *) &allSubmount, &len);
1458 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1461 RegCloseKey (hkParam);
1464 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1465 0, KEY_QUERY_VALUE, &hkSubmount);
1466 if (rv == ERROR_SUCCESS) {
1467 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1468 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1469 if (rv != ERROR_SUCCESS)
1475 /* fetch the root shares */
1476 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1477 rootShares.cShare = 0;
1478 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1482 userp = smb_GetTran2User(vcp,p);
1484 thyper.HighPart = 0;
1487 cm_HoldSCache(cm_rootSCachep);
1488 cm_ApplyDir(cm_rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1489 cm_ReleaseSCache(cm_rootSCachep);
1491 cm_ReleaseUser(userp);
1493 nShares = rootShares.cShare + nRegShares + allSubmount;
1495 #define REMARK_LEN 1
1496 outParmsTotal = 8; /* 4 dwords */
1497 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1498 if(outDataTotal > bufsize) {
1499 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1500 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1503 nSharesRet = nShares;
1506 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1508 /* now for the submounts */
1509 shares = (smb_rap_share_info_1_t *) outp->datap;
1510 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1512 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1515 strcpy( shares[cshare].shi1_netname, "all" );
1516 shares[cshare].shi1_remark = cstrp - outp->datap;
1517 /* type and pad are zero already */
1523 for(i=0; i < nRegShares && cshare < nSharesRet; i++) {
1524 len = sizeof(thisShare);
1525 rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1526 if(rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1527 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1528 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1529 shares[cshare].shi1_remark = cstrp - outp->datap;
1534 nShares--; /* uncount key */
1537 RegCloseKey(hkSubmount);
1540 nonrootShares = cshare;
1542 for(i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1543 /* in case there are collisions with submounts, submounts have higher priority */
1544 for(j=0; j < nonrootShares; j++)
1545 if(!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1548 if(j < nonrootShares) {
1549 nShares--; /* uncount */
1553 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1554 shares[cshare].shi1_remark = cstrp - outp->datap;
1559 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1560 outp->parmsp[1] = 0;
1561 outp->parmsp[2] = cshare;
1562 outp->parmsp[3] = nShares;
1564 outp->totalData = cstrp - outp->datap;
1565 outp->totalParms = outParmsTotal;
1567 smb_SendTran2Packet(vcp, outp, op);
1568 smb_FreeTran2Packet(outp);
1570 free(rootShares.shares);
1575 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1577 smb_tran2Packet_t *outp;
1578 unsigned short * tp;
1580 BOOL shareFound = FALSE;
1581 unsigned short infoLevel;
1582 unsigned short bufsize;
1592 tp = p->parmsp + 1; /* skip over function number (always 1) */
1593 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1594 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1595 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1602 totalData = sizeof(smb_rap_share_info_0_t);
1603 else if(infoLevel == 1)
1604 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1605 else if(infoLevel == 2)
1606 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1608 return CM_ERROR_INVAL;
1610 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1612 if(!stricmp(shareName,"all")) {
1613 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1614 KEY_QUERY_VALUE, &hkParam);
1615 if (rv == ERROR_SUCCESS) {
1616 len = sizeof(allSubmount);
1617 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1618 (BYTE *) &allSubmount, &len);
1619 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1622 RegCloseKey (hkParam);
1629 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts", 0,
1630 KEY_QUERY_VALUE, &hkSubmount);
1631 if(rv == ERROR_SUCCESS) {
1632 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1633 if(rv == ERROR_SUCCESS) {
1636 RegCloseKey(hkSubmount);
1641 smb_FreeTran2Packet(outp);
1642 return CM_ERROR_BADSHARENAME;
1645 memset(outp->datap, 0, totalData);
1647 outp->parmsp[0] = 0;
1648 outp->parmsp[1] = 0;
1649 outp->parmsp[2] = totalData;
1651 if(infoLevel == 0) {
1652 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1653 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1654 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1655 } else if(infoLevel == 1) {
1656 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1657 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1658 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1659 info->shi1_remark = ((unsigned char *) (info + 1)) - outp->datap;
1660 /* type and pad are already zero */
1661 } else { /* infoLevel==2 */
1662 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1663 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1664 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1665 info->shi2_remark = ((unsigned char *) (info + 1)) - outp->datap;
1666 info->shi2_permissions = ACCESS_ALL;
1667 info->shi2_max_uses = (unsigned short) -1;
1668 info->shi2_path = 1 + (((unsigned char *) (info + 1)) - outp->datap);
1671 outp->totalData = totalData;
1672 outp->totalParms = totalParam;
1674 smb_SendTran2Packet(vcp, outp, op);
1675 smb_FreeTran2Packet(outp);
1680 typedef struct smb_rap_wksta_info_10 {
1681 DWORD wki10_computername; /*char *wki10_computername;*/
1682 DWORD wki10_username; /* char *wki10_username; */
1683 DWORD wki10_langroup; /* char *wki10_langroup;*/
1684 unsigned char wki10_ver_major;
1685 unsigned char wki10_ver_minor;
1686 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1687 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1688 } smb_rap_wksta_info_10_t;
1691 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1693 smb_tran2Packet_t *outp;
1697 unsigned short * tp;
1700 smb_rap_wksta_info_10_t * info;
1704 tp = p->parmsp + 1; /* Skip over function number */
1705 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1706 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1710 if(infoLevel != 10) {
1711 return CM_ERROR_INVAL;
1717 totalData = sizeof(*info) + /* info */
1718 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1719 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1720 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1721 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1722 1; /* wki10_oth_domains (null)*/
1724 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1726 memset(outp->parmsp,0,totalParams);
1727 memset(outp->datap,0,totalData);
1729 info = (smb_rap_wksta_info_10_t *) outp->datap;
1730 cstrp = (char *) (info + 1);
1732 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1733 strcpy(cstrp, smb_localNamep);
1734 cstrp += strlen(cstrp) + 1;
1736 info->wki10_username = (DWORD) (cstrp - outp->datap);
1737 uidp = smb_FindUID(vcp, p->uid, 0);
1739 lock_ObtainMutex(&uidp->mx);
1740 if(uidp->unp && uidp->unp->name)
1741 strcpy(cstrp, uidp->unp->name);
1742 lock_ReleaseMutex(&uidp->mx);
1743 smb_ReleaseUID(uidp);
1745 cstrp += strlen(cstrp) + 1;
1747 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1748 strcpy(cstrp, "WORKGROUP");
1749 cstrp += strlen(cstrp) + 1;
1751 /* TODO: Not sure what values these should take, but these work */
1752 info->wki10_ver_major = 5;
1753 info->wki10_ver_minor = 1;
1755 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1756 strcpy(cstrp, smb_ServerDomainName);
1757 cstrp += strlen(cstrp) + 1;
1759 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1760 cstrp ++; /* no other domains */
1762 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1763 outp->parmsp[2] = outp->totalData;
1764 outp->totalParms = totalParams;
1766 smb_SendTran2Packet(vcp,outp,op);
1767 smb_FreeTran2Packet(outp);
1772 typedef struct smb_rap_server_info_0 {
1774 } smb_rap_server_info_0_t;
1776 typedef struct smb_rap_server_info_1 {
1778 char sv1_version_major;
1779 char sv1_version_minor;
1780 unsigned long sv1_type;
1781 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1782 } smb_rap_server_info_1_t;
1784 char smb_ServerComment[] = "OpenAFS Client";
1785 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1787 #define SMB_SV_TYPE_SERVER 0x00000002L
1788 #define SMB_SV_TYPE_NT 0x00001000L
1789 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1791 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1793 smb_tran2Packet_t *outp;
1797 unsigned short * tp;
1800 smb_rap_server_info_0_t * info0;
1801 smb_rap_server_info_1_t * info1;
1804 tp = p->parmsp + 1; /* Skip over function number */
1805 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1806 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1810 if(infoLevel != 0 && infoLevel != 1) {
1811 return CM_ERROR_INVAL;
1817 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1818 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1820 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1822 memset(outp->parmsp,0,totalParams);
1823 memset(outp->datap,0,totalData);
1825 if(infoLevel == 0) {
1826 info0 = (smb_rap_server_info_0_t *) outp->datap;
1827 cstrp = (char *) (info0 + 1);
1828 strcpy(info0->sv0_name, "AFS");
1829 } else { /* infoLevel == 1 */
1830 info1 = (smb_rap_server_info_1_t *) outp->datap;
1831 cstrp = (char *) (info1 + 1);
1832 strcpy(info1->sv1_name, "AFS");
1835 SMB_SV_TYPE_SERVER |
1837 SMB_SV_TYPE_SERVER_NT;
1839 info1->sv1_version_major = 5;
1840 info1->sv1_version_minor = 1;
1841 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1843 strcpy(cstrp, smb_ServerComment);
1845 cstrp += smb_ServerCommentLen;
1848 totalData = cstrp - outp->datap;
1849 outp->totalData = min(bufsize,totalData); /* actual data size */
1850 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1851 outp->parmsp[2] = totalData;
1852 outp->totalParms = totalParams;
1854 smb_SendTran2Packet(vcp,outp,op);
1855 smb_FreeTran2Packet(outp);
1860 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1862 smb_tran2Packet_t *asp;
1874 /* We sometimes see 0 word count. What to do? */
1875 if (*inp->wctp == 0) {
1880 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1882 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1883 ptbuf[0] = "Transaction2 word count = 0";
1884 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1885 1, inp->ncb_length, ptbuf, inp);
1886 DeregisterEventSource(h);
1888 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1891 smb_SetSMBDataLength(outp, 0);
1892 smb_SendPacket(vcp, outp);
1896 totalParms = smb_GetSMBParm(inp, 0);
1897 totalData = smb_GetSMBParm(inp, 1);
1899 firstPacket = (inp->inCom == 0x32);
1901 /* find the packet we're reassembling */
1902 lock_ObtainWrite(&smb_globalLock);
1903 asp = smb_FindTran2Packet(vcp, inp);
1905 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1907 lock_ReleaseWrite(&smb_globalLock);
1909 /* now merge in this latest packet; start by looking up offsets */
1911 parmDisp = dataDisp = 0;
1912 parmOffset = smb_GetSMBParm(inp, 10);
1913 dataOffset = smb_GetSMBParm(inp, 12);
1914 parmCount = smb_GetSMBParm(inp, 9);
1915 dataCount = smb_GetSMBParm(inp, 11);
1916 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1917 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1919 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1920 totalData, dataCount, asp->maxReturnData);
1923 parmDisp = smb_GetSMBParm(inp, 4);
1924 parmOffset = smb_GetSMBParm(inp, 3);
1925 dataDisp = smb_GetSMBParm(inp, 7);
1926 dataOffset = smb_GetSMBParm(inp, 6);
1927 parmCount = smb_GetSMBParm(inp, 2);
1928 dataCount = smb_GetSMBParm(inp, 5);
1930 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1931 parmCount, dataCount);
1934 /* now copy the parms and data */
1935 if ( asp->totalParms > 0 && parmCount != 0 )
1937 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1939 if ( asp->totalData > 0 && dataCount != 0 ) {
1940 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1943 /* account for new bytes */
1944 asp->curData += dataCount;
1945 asp->curParms += parmCount;
1947 /* finally, if we're done, remove the packet from the queue and dispatch it */
1948 if (asp->totalParms > 0 &&
1949 asp->curParms > 0 &&
1950 asp->totalData <= asp->curData &&
1951 asp->totalParms <= asp->curParms) {
1952 /* we've received it all */
1953 lock_ObtainWrite(&smb_globalLock);
1954 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1955 lock_ReleaseWrite(&smb_globalLock);
1957 /* now dispatch it */
1958 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
1959 osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1960 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
1961 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
1964 osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1965 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1966 code = CM_ERROR_BADOP;
1969 /* if an error is returned, we're supposed to send an error packet,
1970 * otherwise the dispatched function already did the data sending.
1971 * We give dispatched proc the responsibility since it knows how much
1972 * space to allocate.
1975 smb_SendTran2Error(vcp, asp, outp, code);
1978 /* free the input tran 2 packet */
1979 lock_ObtainWrite(&smb_globalLock);
1980 smb_FreeTran2Packet(asp);
1981 lock_ReleaseWrite(&smb_globalLock);
1983 else if (firstPacket) {
1984 /* the first packet in a multi-packet request, we need to send an
1985 * ack to get more data.
1987 smb_SetSMBDataLength(outp, 0);
1988 smb_SendPacket(vcp, outp);
1994 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1997 smb_tran2Packet_t *outp;
2002 cm_scache_t *dscp; /* dir we're dealing with */
2003 cm_scache_t *scp; /* file we're creating */
2005 int initialModeBits;
2015 int parmSlot; /* which parm we're dealing with */
2016 long returnEALength;
2024 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2025 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2027 openFun = p->parmsp[6]; /* open function */
2028 excl = ((openFun & 3) == 0);
2029 trunc = ((openFun & 3) == 2); /* truncate it */
2030 openMode = (p->parmsp[1] & 0x7);
2031 openAction = 0; /* tracks what we did */
2033 attributes = p->parmsp[3];
2034 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2036 /* compute initial mode bits based on read-only flag in attributes */
2037 initialModeBits = 0666;
2038 if (attributes & 1) initialModeBits &= ~0222;
2040 pathp = (char *) (&p->parmsp[14]);
2042 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2044 spacep = cm_GetSpace();
2045 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2047 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2048 /* special case magic file name for receiving IOCTL requests
2049 * (since IOCTL calls themselves aren't getting through).
2051 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2052 smb_SetupIoctlFid(fidp, spacep);
2054 /* copy out remainder of the parms */
2056 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2058 outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
2059 outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
2060 outp->parmsp[parmSlot] = 0; parmSlot++;
2061 outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
2062 outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
2063 outp->parmsp[parmSlot] = openMode; parmSlot++;
2064 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2065 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2067 /* and the final "always present" stuff */
2068 outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
2069 /* next write out the "unique" ID */
2070 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
2071 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
2072 outp->parmsp[parmSlot] = 0; parmSlot++;
2073 if (returnEALength) {
2074 outp->parmsp[parmSlot] = 0; parmSlot++;
2075 outp->parmsp[parmSlot] = 0; parmSlot++;
2078 outp->totalData = 0;
2079 outp->totalParms = parmSlot * 2;
2081 smb_SendTran2Packet(vcp, outp, op);
2083 smb_FreeTran2Packet(outp);
2085 /* and clean up fid reference */
2086 smb_ReleaseFID(fidp);
2090 #ifdef DEBUG_VERBOSE
2092 char *hexp, *asciip;
2093 asciip = (lastNamep ? lastNamep : pathp);
2094 hexp = osi_HexifyString( asciip );
2095 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2100 userp = smb_GetTran2User(vcp, p);
2101 /* In the off chance that userp is NULL, we log and abandon */
2103 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2104 smb_FreeTran2Packet(outp);
2105 return CM_ERROR_BADSMB;
2108 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2109 if (code == CM_ERROR_TIDIPC) {
2110 /* Attempt to use TID allocated for IPC. The client is
2111 probably trying to locate DCE RPC end points, which
2112 we don't support. */
2113 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2114 cm_ReleaseUser(userp);
2115 smb_FreeTran2Packet(outp);
2116 return CM_ERROR_NOSUCHPATH;
2120 code = cm_NameI(cm_rootSCachep, pathp,
2121 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2122 userp, tidPathp, &req, &scp);
2124 code = cm_NameI(cm_rootSCachep, spacep->data,
2125 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2126 userp, tidPathp, &req, &dscp);
2127 cm_FreeSpace(spacep);
2130 cm_ReleaseUser(userp);
2131 smb_FreeTran2Packet(outp);
2135 /* otherwise, scp points to the parent directory. Do a lookup,
2136 * and truncate the file if we find it, otherwise we create the
2143 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2145 if (code && code != CM_ERROR_NOSUCHFILE) {
2146 cm_ReleaseSCache(dscp);
2147 cm_ReleaseUser(userp);
2148 smb_FreeTran2Packet(outp);
2153 cm_FreeSpace(spacep);
2156 /* if we get here, if code is 0, the file exists and is represented by
2157 * scp. Otherwise, we have to create it.
2160 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2162 if (dscp) cm_ReleaseSCache(dscp);
2163 cm_ReleaseSCache(scp);
2164 cm_ReleaseUser(userp);
2165 smb_FreeTran2Packet(outp);
2170 /* oops, file shouldn't be there */
2171 if (dscp) cm_ReleaseSCache(dscp);
2172 cm_ReleaseSCache(scp);
2173 cm_ReleaseUser(userp);
2174 smb_FreeTran2Packet(outp);
2175 return CM_ERROR_EXISTS;
2179 setAttr.mask = CM_ATTRMASK_LENGTH;
2180 setAttr.length.LowPart = 0;
2181 setAttr.length.HighPart = 0;
2182 code = cm_SetAttr(scp, &setAttr, userp, &req);
2183 openAction = 3; /* truncated existing file */
2186 openAction = 1; /* found existing file */
2188 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
2189 /* don't create if not found */
2190 if (dscp) cm_ReleaseSCache(dscp);
2191 osi_assert(scp == NULL);
2192 cm_ReleaseUser(userp);
2193 smb_FreeTran2Packet(outp);
2194 return CM_ERROR_NOSUCHFILE;
2197 osi_assert(dscp != NULL && scp == NULL);
2198 openAction = 2; /* created file */
2199 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2200 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2201 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2203 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2204 smb_NotifyChange(FILE_ACTION_ADDED,
2205 FILE_NOTIFY_CHANGE_FILE_NAME,
2206 dscp, lastNamep, NULL, TRUE);
2207 if (!excl && code == CM_ERROR_EXISTS) {
2208 /* not an exclusive create, and someone else tried
2209 * creating it already, then we open it anyway. We
2210 * don't bother retrying after this, since if this next
2211 * fails, that means that the file was deleted after we
2212 * started this call.
2214 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2218 setAttr.mask = CM_ATTRMASK_LENGTH;
2219 setAttr.length.LowPart = 0;
2220 setAttr.length.HighPart = 0;
2221 code = cm_SetAttr(scp, &setAttr, userp,
2224 } /* lookup succeeded */
2228 /* we don't need this any longer */
2229 if (dscp) cm_ReleaseSCache(dscp);
2232 /* something went wrong creating or truncating the file */
2233 if (scp) cm_ReleaseSCache(scp);
2234 cm_ReleaseUser(userp);
2235 smb_FreeTran2Packet(outp);
2239 /* make sure we're about to open a file */
2240 if (scp->fileType != CM_SCACHETYPE_FILE) {
2242 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2243 cm_scache_t * targetScp = 0;
2244 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2246 /* we have a more accurate file to use (the
2247 * target of the symbolic link). Otherwise,
2248 * we'll just use the symlink anyway.
2250 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2252 cm_ReleaseSCache(scp);
2256 if (scp->fileType != CM_SCACHETYPE_FILE) {
2257 cm_ReleaseSCache(scp);
2258 cm_ReleaseUser(userp);
2259 smb_FreeTran2Packet(outp);
2260 return CM_ERROR_ISDIR;
2264 /* now all we have to do is open the file itself */
2265 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2268 /* save a pointer to the vnode */
2271 /* compute open mode */
2272 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2273 if (openMode == 1 || openMode == 2)
2274 fidp->flags |= SMB_FID_OPENWRITE;
2276 smb_ReleaseFID(fidp);
2278 cm_Open(scp, 0, userp);
2280 /* copy out remainder of the parms */
2282 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2283 lock_ObtainMutex(&scp->mx);
2285 outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
2286 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2287 outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
2288 outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
2289 outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
2291 outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2293 outp->parmsp[parmSlot] = openMode; parmSlot++;
2294 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2295 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2297 /* and the final "always present" stuff */
2298 outp->parmsp[parmSlot] = openAction; parmSlot++;
2299 /* next write out the "unique" ID */
2300 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
2301 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
2302 outp->parmsp[parmSlot] = 0; parmSlot++;
2303 if (returnEALength) {
2304 outp->parmsp[parmSlot] = 0; parmSlot++;
2305 outp->parmsp[parmSlot] = 0; parmSlot++;
2307 lock_ReleaseMutex(&scp->mx);
2308 outp->totalData = 0; /* total # of data bytes */
2309 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2311 smb_SendTran2Packet(vcp, outp, op);
2313 smb_FreeTran2Packet(outp);
2315 cm_ReleaseUser(userp);
2316 /* leave scp held since we put it in fidp->scp */
2320 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2322 osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2323 return CM_ERROR_BADOP;
2326 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2328 osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2329 return CM_ERROR_BADOP;
2332 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2334 smb_tran2Packet_t *outp;
2335 smb_tran2QFSInfo_t qi;
2338 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
2340 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2342 switch (p->parmsp[0]) {
2343 case 1: responseSize = sizeof(qi.u.allocInfo); break;
2344 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
2345 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
2346 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
2347 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
2348 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
2349 default: return CM_ERROR_INVAL;
2352 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2353 switch (p->parmsp[0]) {
2356 qi.u.allocInfo.FSID = 0;
2357 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2358 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2359 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2360 qi.u.allocInfo.bytesPerSector = 1024;
2365 qi.u.volumeInfo.vsn = 1234;
2366 qi.u.volumeInfo.vnCount = 4;
2367 /* we're supposed to pad it out with zeroes to the end */
2368 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2369 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2373 /* FS volume info */
2374 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
2375 qi.u.FSvolumeInfo.vsn = 1234;
2376 qi.u.FSvolumeInfo.vnCount = 8;
2377 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
2383 temp.LowPart = 0x7fffffff;
2384 qi.u.FSsizeInfo.totalAllocUnits = temp;
2385 temp.LowPart = 0x3fffffff;
2386 qi.u.FSsizeInfo.availAllocUnits = temp;
2387 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2388 qi.u.FSsizeInfo.bytesPerSector = 1024;
2392 /* FS device info */
2393 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
2394 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2398 /* FS attribute info */
2399 /* attributes, defined in WINNT.H:
2400 * FILE_CASE_SENSITIVE_SEARCH 0x1
2401 * FILE_CASE_PRESERVED_NAMES 0x2
2402 * <no name defined> 0x4000
2403 * If bit 0x4000 is not set, Windows 95 thinks
2404 * we can't handle long (non-8.3) names,
2405 * despite our protestations to the contrary.
2407 qi.u.FSattributeInfo.attributes = 0x4003;
2408 qi.u.FSattributeInfo.maxCompLength = 255;
2409 qi.u.FSattributeInfo.FSnameLength = 6;
2410 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
2414 /* copy out return data, and set corresponding sizes */
2415 outp->totalParms = 0;
2416 outp->totalData = responseSize;
2417 memcpy(outp->datap, &qi, responseSize);
2419 /* send and free the packets */
2420 smb_SendTran2Packet(vcp, outp, op);
2421 smb_FreeTran2Packet(outp);
2426 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2428 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2429 return CM_ERROR_BADOP;
2432 struct smb_ShortNameRock {
2436 size_t shortNameLen;
2439 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2442 struct smb_ShortNameRock *rockp;
2446 /* compare both names and vnodes, though probably just comparing vnodes
2447 * would be safe enough.
2449 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2451 if (ntohl(dep->fid.vnode) != rockp->vnode)
2453 /* This is the entry */
2454 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2455 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2456 return CM_ERROR_STOPNOW;
2459 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2460 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2462 struct smb_ShortNameRock rock;
2466 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2470 spacep = cm_GetSpace();
2471 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2473 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
2475 cm_FreeSpace(spacep);
2476 if (code) return code;
2478 if (!lastNamep) lastNamep = pathp;
2481 thyper.HighPart = 0;
2482 rock.shortName = shortName;
2484 rock.maskp = lastNamep;
2485 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
2488 cm_ReleaseSCache(dscp);
2491 return CM_ERROR_NOSUCHFILE;
2492 if (code == CM_ERROR_STOPNOW) {
2493 *shortNameLenp = rock.shortNameLen;
2499 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2501 smb_tran2Packet_t *outp;
2504 unsigned short infoLevel;
2506 unsigned short attributes;
2507 unsigned long extAttributes;
2512 cm_scache_t *scp, *dscp;
2521 infoLevel = p->parmsp[0];
2522 if (infoLevel == 6) nbytesRequired = 0;
2523 else if (infoLevel == 1) nbytesRequired = 22;
2524 else if (infoLevel == 2) nbytesRequired = 26;
2525 else if (infoLevel == 0x101) nbytesRequired = 40;
2526 else if (infoLevel == 0x102) nbytesRequired = 24;
2527 else if (infoLevel == 0x103) nbytesRequired = 4;
2528 else if (infoLevel == 0x108) nbytesRequired = 30;
2530 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2531 p->opcode, infoLevel);
2532 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2535 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2536 osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
2538 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2540 if (infoLevel > 0x100)
2541 outp->totalParms = 2;
2543 outp->totalParms = 0;
2544 outp->totalData = nbytesRequired;
2546 /* now, if we're at infoLevel 6, we're only being asked to check
2547 * the syntax, so we just OK things now. In particular, we're *not*
2548 * being asked to verify anything about the state of any parent dirs.
2550 if (infoLevel == 6) {
2551 smb_SendTran2Packet(vcp, outp, opx);
2552 smb_FreeTran2Packet(outp);
2556 userp = smb_GetTran2User(vcp, p);
2558 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2559 smb_FreeTran2Packet(outp);
2560 return CM_ERROR_BADSMB;
2563 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2565 cm_ReleaseUser(userp);
2566 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2567 smb_FreeTran2Packet(outp);
2572 * XXX Strange hack XXX
2574 * As of Patch 7 (13 January 98), we are having the following problem:
2575 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2576 * requests to look up "desktop.ini" in all the subdirectories.
2577 * This can cause zillions of timeouts looking up non-existent cells
2578 * and volumes, especially in the top-level directory.
2580 * We have not found any way to avoid this or work around it except
2581 * to explicitly ignore the requests for mount points that haven't
2582 * yet been evaluated and for directories that haven't yet been
2585 if (infoLevel == 0x101) {
2586 spacep = cm_GetSpace();
2587 smb_StripLastComponent(spacep->data, &lastComp,
2588 (char *)(&p->parmsp[3]));
2589 /* Make sure that lastComp is not NULL */
2591 if (strcmp(lastComp, "\\desktop.ini") == 0) {
2592 code = cm_NameI(cm_rootSCachep, spacep->data,
2596 userp, tidPathp, &req, &dscp);
2598 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
2599 && !dscp->mountRootFidp)
2600 code = CM_ERROR_NOSUCHFILE;
2601 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2602 cm_buf_t *bp = buf_Find(dscp, &hzero);
2606 code = CM_ERROR_NOSUCHFILE;
2608 cm_ReleaseSCache(dscp);
2610 cm_FreeSpace(spacep);
2611 cm_ReleaseUser(userp);
2612 smb_SendTran2Error(vcp, p, opx, code);
2613 smb_FreeTran2Packet(outp);
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)
3286 BOOL szWildCardMatchFileName(PSZ pattern, PSZ name) {
3287 PSZ pename; // points to the last 'name' character
3289 pename = name + strlen(name) - 1;
3294 if (*(++pattern) != '<' || *(++pattern) != '*') {
3302 while ((*pattern == '<') || (*pattern == '*') || (*pattern == '?') || (*pattern == '>'))
3306 for (p = pename; p >= name; --p) {
3307 if ((mapCaseTable[*p] == mapCaseTable[*pattern]) &&
3308 szWildCardMatchFileName(pattern + 1, p + 1))
3313 if (mapCaseTable[*name] != mapCaseTable[*pattern])
3322 /* do a case-folding search of the star name mask with the name in namep.
3323 * Return 1 if we match, otherwise 0.
3325 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3327 /* make sure we only match 8.3 names, if requested */
3328 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3331 return szWildCardMatchFileName(maskp, namep) ? 1:0;
3334 #else /* USE_OLD_MATCHING */
3335 /* do a case-folding search of the star name mask with the name in namep.
3336 * Return 1 if we match, otherwise 0.
3338 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3340 unsigned char tcp1, tcp2; /* Pattern characters */
3341 unsigned char tcn1; /* Name characters */
3342 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3343 char *starNamep, *starMaskp;
3344 static char nullCharp[] = {0};
3345 int casefold = flags & CM_FLAG_CASEFOLD;
3347 /* make sure we only match 8.3 names, if requested */
3348 req8dot3 = (flags & CM_FLAG_8DOT3);
3349 if (req8dot3 && !cm_Is8Dot3(namep))
3354 /* Next pattern character */
3357 /* Next name character */
3361 /* 0 - end of pattern */
3367 else if (tcp1 == '.' || tcp1 == '"') {
3377 * first dot in pattern;
3378 * must match dot or end of name
3383 else if (tcn1 == '.') {
3392 else if (tcp1 == '?') {
3393 if (tcn1 == 0 || tcn1 == '.')
3398 else if (tcp1 == '>') {
3399 if (tcn1 != 0 && tcn1 != '.')
3403 else if (tcp1 == '*' || tcp1 == '<') {
3407 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3408 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3423 * pattern character after '*' is not null or
3424 * period. If it is '?' or '>', we are not
3425 * going to understand it. If it is '*' or
3426 * '<', we are going to skip over it. None of
3427 * these are likely, I hope.
3429 /* skip over '*' and '<' */
3430 while (tcp2 == '*' || tcp2 == '<')
3433 /* skip over characters that don't match tcp2 */
3434 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
3435 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
3436 (!casefold && tcn1 != tcp2)))
3440 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3443 /* Remember where we are */
3453 /* tcp1 is not a wildcard */
3454 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
3455 (!casefold && tcn1 == tcp1)) {
3460 /* if trying to match a star pattern, go back */
3462 maskp = starMaskp - 2;
3463 namep = starNamep + 1;
3472 #endif /* USE_OLD_MATCHING */
3474 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3483 smb_dirListPatch_t *dirListPatchesp;
3484 smb_dirListPatch_t *curPatchp;
3487 long orbytes; /* # of bytes in this output record */
3488 long ohbytes; /* # of bytes, except file name */
3489 long onbytes; /* # of bytes in name, incl. term. null */
3490 osi_hyper_t dirLength;
3491 osi_hyper_t bufferOffset;
3492 osi_hyper_t curOffset;
3494 smb_dirSearch_t *dsp;
3498 cm_pageHeader_t *pageHeaderp;
3499 cm_user_t *userp = NULL;
3502 long nextEntryCookie;
3503 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3504 char *op; /* output data ptr */
3505 char *origOp; /* original value of op */
3506 cm_space_t *spacep; /* for pathname buffer */
3507 long maxReturnData; /* max # of return data */
3508 long maxReturnParms; /* max # of return parms */
3509 long bytesInBuffer; /* # data bytes in the output buffer */
3511 char *maskp; /* mask part of path */
3515 smb_tran2Packet_t *outp; /* response packet */
3518 char shortName[13]; /* 8.3 name if needed */
3530 if (p->opcode == 1) {
3531 /* find first; obtain basic parameters from request */
3532 attribute = p->parmsp[0];
3533 maxCount = p->parmsp[1];
3534 infoLevel = p->parmsp[3];
3535 searchFlags = p->parmsp[2];
3536 dsp = smb_NewDirSearch(1);
3537 dsp->attribute = attribute;
3538 pathp = ((char *) p->parmsp) + 12; /* points to path */
3540 maskp = strrchr(pathp, '\\');
3541 if (maskp == NULL) maskp = pathp;
3542 else maskp++; /* skip over backslash */
3543 strcpy(dsp->mask, maskp); /* and save mask */
3544 /* track if this is likely to match a lot of entries */
3545 starPattern = smb_V3IsStarMask(maskp);
3548 osi_assert(p->opcode == 2);
3549 /* find next; obtain basic parameters from request or open dir file */
3550 dsp = smb_FindDirSearch(p->parmsp[0]);
3551 if (!dsp) return CM_ERROR_BADFD;
3552 attribute = dsp->attribute;
3553 maxCount = p->parmsp[1];
3554 infoLevel = p->parmsp[2];
3555 searchFlags = p->parmsp[5];
3557 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
3559 starPattern = 1; /* assume, since required a Find Next */
3563 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
3564 attribute, infoLevel, maxCount, searchFlags);
3566 osi_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
3567 p->opcode, nextCookie);
3569 if (infoLevel >= 0x101)
3570 searchFlags &= ~4; /* no resume keys */
3572 dirListPatchesp = NULL;
3574 maxReturnData = p->maxReturnData;
3575 if (p->opcode == 1) /* find first */
3576 maxReturnParms = 10; /* bytes */
3578 maxReturnParms = 8; /* bytes */
3580 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
3581 if (maxReturnData > 6000)
3582 maxReturnData = 6000;
3583 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
3585 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
3588 osi_Log1(smb_logp, "T2 receive search dir %s",
3589 osi_LogSaveString(smb_logp, pathp));
3591 /* bail out if request looks bad */
3592 if (p->opcode == 1 && !pathp) {
3593 smb_ReleaseDirSearch(dsp);
3594 smb_FreeTran2Packet(outp);
3595 return CM_ERROR_BADSMB;
3598 osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
3599 nextCookie, dsp->cookie);
3601 userp = smb_GetTran2User(vcp, p);
3603 osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p->uid);
3604 smb_ReleaseDirSearch(dsp);
3605 smb_FreeTran2Packet(outp);
3606 return CM_ERROR_BADSMB;
3609 /* try to get the vnode for the path name next */
3610 lock_ObtainMutex(&dsp->mx);
3617 spacep = cm_GetSpace();
3618 smb_StripLastComponent(spacep->data, NULL, pathp);
3619 lock_ReleaseMutex(&dsp->mx);
3621 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3623 cm_ReleaseUser(userp);
3624 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
3625 smb_FreeTran2Packet(outp);
3626 smb_DeleteDirSearch(dsp);
3627 smb_ReleaseDirSearch(dsp);
3630 code = cm_NameI(cm_rootSCachep, spacep->data,
3631 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3632 userp, tidPathp, &req, &scp);
3633 cm_FreeSpace(spacep);
3635 lock_ObtainMutex(&dsp->mx);
3637 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
3639 /* we need one hold for the entry we just stored into,
3640 * and one for our own processing. When we're done
3641 * with this function, we'll drop the one for our own
3642 * processing. We held it once from the namei call,
3643 * and so we do another hold now.
3646 lock_ObtainMutex(&scp->mx);
3647 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3648 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3649 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3650 dsp->flags |= SMB_DIRSEARCH_BULKST;
3652 lock_ReleaseMutex(&scp->mx);
3655 lock_ReleaseMutex(&dsp->mx);
3657 cm_ReleaseUser(userp);
3658 smb_FreeTran2Packet(outp);
3659 smb_DeleteDirSearch(dsp);
3660 smb_ReleaseDirSearch(dsp);
3664 /* get the directory size */
3665 lock_ObtainMutex(&scp->mx);
3666 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3667 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3669 lock_ReleaseMutex(&scp->mx);
3670 cm_ReleaseSCache(scp);
3671 cm_ReleaseUser(userp);
3672 smb_FreeTran2Packet(outp);
3673 smb_DeleteDirSearch(dsp);
3674 smb_ReleaseDirSearch(dsp);
3679 dirLength = scp->length;
3681 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3682 curOffset.HighPart = 0;
3683 curOffset.LowPart = nextCookie;
3684 origOp = outp->datap;
3692 if (searchFlags & 4)
3693 /* skip over resume key */
3696 /* make sure that curOffset.LowPart doesn't point to the first
3697 * 32 bytes in the 2nd through last dir page, and that it doesn't
3698 * point at the first 13 32-byte chunks in the first dir page,
3699 * since those are dir and page headers, and don't contain useful
3702 temp = curOffset.LowPart & (2048-1);
3703 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3704 /* we're in the first page */
3705 if (temp < 13*32) temp = 13*32;
3708 /* we're in a later dir page */
3709 if (temp < 32) temp = 32;
3712 /* make sure the low order 5 bits are zero */
3715 /* now put temp bits back ito curOffset.LowPart */
3716 curOffset.LowPart &= ~(2048-1);
3717 curOffset.LowPart |= temp;
3719 /* check if we've passed the dir's EOF */
3720 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
3725 /* check if we've returned all the names that will fit in the
3726 * response packet; we check return count as well as the number
3727 * of bytes requested. We check the # of bytes after we find
3728 * the dir entry, since we'll need to check its size.
3730 if (returnedNames >= maxCount) {
3734 /* see if we can use the bufferp we have now; compute in which
3735 * page the current offset would be, and check whether that's
3736 * the offset of the buffer we have. If not, get the buffer.
3738 thyper.HighPart = curOffset.HighPart;
3739 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3740 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3743 buf_Release(bufferp);
3746 lock_ReleaseMutex(&scp->mx);
3747 lock_ObtainRead(&scp->bufCreateLock);
3748 code = buf_Get(scp, &thyper, &bufferp);
3749 lock_ReleaseRead(&scp->bufCreateLock);
3751 /* now, if we're doing a star match, do bulk fetching
3752 * of all of the status info for files in the dir.
3755 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
3758 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
3759 && LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
3760 /* Don't bulk stat if risking timeout */
3761 int now = GetCurrentTime();
3762 if (now - req.startTime > 5000) {
3763 scp->bulkStatProgress = thyper;
3764 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3765 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3767 cm_TryBulkStat(scp, &thyper, userp, &req);
3771 lock_ObtainMutex(&scp->mx);
3773 bufferOffset = thyper;
3775 /* now get the data in the cache */
3777 code = cm_SyncOp(scp, bufferp, userp, &req,
3779 CM_SCACHESYNC_NEEDCALLBACK
3780 | CM_SCACHESYNC_READ);
3783 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3785 /* otherwise, load the buffer and try again */
3786 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3791 buf_Release(bufferp);
3795 } /* if (wrong buffer) ... */
3797 /* now we have the buffer containing the entry we're interested
3798 * in; copy it out if it represents a non-deleted entry.
3800 entryInDir = curOffset.LowPart & (2048-1);
3801 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3803 /* page header will help tell us which entries are free. Page
3804 * header can change more often than once per buffer, since
3805 * AFS 3 dir page size may be less than (but not more than)
3806 * a buffer package buffer.
3808 /* only look intra-buffer */
3809 temp = curOffset.LowPart & (buf_bufferSize - 1);
3810 temp &= ~(2048 - 1); /* turn off intra-page bits */
3811 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3813 /* now determine which entry we're looking at in the page.
3814 * If it is free (there's a free bitmap at the start of the
3815 * dir), we should skip these 32 bytes.
3817 slotInPage = (entryInDir & 0x7e0) >> 5;
3818 if (!(pageHeaderp->freeBitmap[slotInPage>>3]
3819 & (1 << (slotInPage & 0x7)))) {
3820 /* this entry is free */
3821 numDirChunks = 1; /* only skip this guy */
3825 tp = bufferp->datap + entryInBuffer;
3826 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3828 /* while we're here, compute the next entry's location, too,
3829 * since we'll need it when writing out the cookie into the dir
3832 * XXXX Probably should do more sanity checking.
3834 numDirChunks = cm_NameEntries(dep->name, &onbytes);
3836 /* compute offset of cookie representing next entry */
3837 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3839 /* Need 8.3 name? */
3841 if (infoLevel == 0x104
3842 && dep->fid.vnode != 0
3843 && !cm_Is8Dot3(dep->name)) {
3844 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3848 /* When matching, we are using doing a case fold if we have a wildcard mask.
3849 * If we get a non-wildcard match, it's a lookup for a specific file.
3851 if (dep->fid.vnode != 0 &&
3852 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0))
3854 && smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
3856 /* Eliminate entries that don't match requested attributes */
3857 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
3858 smb_IsDotFile(dep->name))
3859 goto nextEntry; /* no hidden files */
3861 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3863 /* We have already done the cm_TryBulkStat above */
3864 fid.cell = scp->fid.cell;
3865 fid.volume = scp->fid.volume;
3866 fid.vnode = ntohl(dep->fid.vnode);
3867 fid.unique = ntohl(dep->fid.unique);
3868 fileType = cm_FindFileType(&fid);
3869 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
3870 "has filetype %d", dep->name,
3872 if (fileType == CM_SCACHETYPE_DIRECTORY)
3876 /* finally check if this name will fit */
3878 /* standard dir entry stuff */
3879 if (infoLevel < 0x101)
3880 ohbytes = 23; /* pre-NT */
3881 else if (infoLevel == 0x103)
3882 ohbytes = 12; /* NT names only */
3884 ohbytes = 64; /* NT */
3886 if (infoLevel == 0x104)
3887 ohbytes += 26; /* Short name & length */
3889 if (searchFlags & 4) {
3890 ohbytes += 4; /* if resume key required */
3894 && infoLevel != 0x101
3895 && infoLevel != 0x103)
3896 ohbytes += 4; /* EASIZE */
3898 /* add header to name & term. null */
3899 orbytes = onbytes + ohbytes + 1;
3901 /* now, we round up the record to a 4 byte alignment,
3902 * and we make sure that we have enough room here for
3903 * even the aligned version (so we don't have to worry
3904 * about an * overflow when we pad things out below).
3905 * That's the reason for the alignment arithmetic below.
3907 if (infoLevel >= 0x101)
3908 align = (4 - (orbytes & 3)) & 3;
3911 if (orbytes + bytesInBuffer + align > maxReturnData)
3914 /* this is one of the entries to use: it is not deleted
3915 * and it matches the star pattern we're looking for.
3916 * Put out the name, preceded by its length.
3918 /* First zero everything else */
3919 memset(origOp, 0, ohbytes);
3921 if (infoLevel <= 0x101)
3922 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
3923 else if (infoLevel == 0x103)
3924 *((u_long *)(op + 8)) = onbytes;
3926 *((u_long *)(op + 60)) = onbytes;
3927 strcpy(origOp+ohbytes, dep->name);
3929 /* Short name if requested and needed */
3930 if (infoLevel == 0x104) {
3931 if (NeedShortName) {
3932 strcpy(op + 70, shortName);
3933 *(op + 68) = shortNameEnd - shortName;
3937 /* now, adjust the # of entries copied */
3940 /* NextEntryOffset and FileIndex */
3941 if (infoLevel >= 101) {
3942 int entryOffset = orbytes + align;
3943 *((u_long *)op) = entryOffset;
3944 *((u_long *)(op+4)) = nextEntryCookie;
3947 /* now we emit the attribute. This is tricky, since
3948 * we need to really stat the file to find out what
3949 * type of entry we've got. Right now, we're copying
3950 * out data from * a buffer, while holding the scp
3951 * locked, so it isn't really convenient to stat
3952 * something now. We'll put in a place holder
3953 * now, and make a second pass before returning this
3954 * to get the real attributes. So, we just skip the
3955 * data for now, and adjust it later. We allocate a
3956 * patch record to make it easy to find this point
3957 * later. The replay will happen at a time when it is
3958 * safe to unlock the directory.
3960 if (infoLevel != 0x103) {
3961 curPatchp = malloc(sizeof(*curPatchp));
3962 osi_QAdd((osi_queue_t **) &dirListPatchesp,
3964 curPatchp->dptr = op;
3965 if (infoLevel >= 0x101)
3966 curPatchp->dptr += 8;
3968 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
3969 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3972 curPatchp->flags = 0;
3974 curPatchp->fid.cell = scp->fid.cell;
3975 curPatchp->fid.volume = scp->fid.volume;
3976 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3977 curPatchp->fid.unique = ntohl(dep->fid.unique);
3980 curPatchp->dep = dep;
3983 if (searchFlags & 4)
3984 /* put out resume key */
3985 *((u_long *)origOp) = nextEntryCookie;
3987 /* Adjust byte ptr and count */
3988 origOp += orbytes; /* skip entire record */
3989 bytesInBuffer += orbytes;
3991 /* and pad the record out */
3992 while (--align >= 0) {
3997 } /* if we're including this name */
3998 else if (!NeedShortName &&
4001 dep->fid.vnode != 0 &&
4002 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4003 /* We were looking for exact matches, but here's an inexact one*/
4008 /* and adjust curOffset to be where the new cookie is */
4009 thyper.HighPart = 0;
4010 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4011 curOffset = LargeIntegerAdd(thyper, curOffset);
4012 } /* while copying data for dir listing */
4014 /* If we didn't get a star pattern, we did an exact match during the first pass.
4015 * If there were no exact matches found, we fail over to inexact matches by
4016 * marking the query as a star pattern (matches all case permutations), and
4017 * re-running the query.
4019 if (returnedNames == 0 && !starPattern && foundInexact) {
4020 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4025 /* release the mutex */
4026 lock_ReleaseMutex(&scp->mx);
4027 if (bufferp) buf_Release(bufferp);
4029 /* apply and free last set of patches; if not doing a star match, this
4030 * will be empty, but better safe (and freeing everything) than sorry.
4032 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4035 /* now put out the final parameters */
4036 if (returnedNames == 0) eos = 1;
4037 if (p->opcode == 1) {
4039 outp->parmsp[0] = (unsigned short) dsp->cookie;
4040 outp->parmsp[1] = returnedNames;
4041 outp->parmsp[2] = eos;
4042 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4043 outp->parmsp[4] = 0;
4044 /* don't need last name to continue
4045 * search, cookie is enough. Normally,
4046 * this is the offset of the file name
4047 * of the last entry returned.
4049 outp->totalParms = 10; /* in bytes */
4053 outp->parmsp[0] = returnedNames;
4054 outp->parmsp[1] = eos;
4055 outp->parmsp[2] = 0; /* EAS error */
4056 outp->parmsp[3] = 0; /* last name, as above */
4057 outp->totalParms = 8; /* in bytes */
4060 /* return # of bytes in the buffer */
4061 outp->totalData = bytesInBuffer;
4063 osi_Log2(smb_logp, "T2 search dir done, %d names, code %d",
4064 returnedNames, code);
4066 /* Return error code if unsuccessful on first request */
4067 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4068 code = CM_ERROR_NOSUCHFILE;
4070 /* if we're supposed to close the search after this request, or if
4071 * we're supposed to close the search if we're done, and we're done,
4072 * or if something went wrong, close the search.
4074 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4075 if ((searchFlags & 1) || (returnedNames == 0) ||
4076 ((searchFlags & 2) && eos) || code != 0)
4077 smb_DeleteDirSearch(dsp);
4079 smb_SendTran2Error(vcp, p, opx, code);
4081 smb_SendTran2Packet(vcp, outp, opx);
4083 smb_FreeTran2Packet(outp);
4084 smb_ReleaseDirSearch(dsp);
4085 cm_ReleaseSCache(scp);
4086 cm_ReleaseUser(userp);
4090 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4093 smb_dirSearch_t *dsp;
4095 dirHandle = smb_GetSMBParm(inp, 0);
4097 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4099 dsp = smb_FindDirSearch(dirHandle);
4102 return CM_ERROR_BADFD;
4104 /* otherwise, we have an FD to destroy */
4105 smb_DeleteDirSearch(dsp);
4106 smb_ReleaseDirSearch(dsp);
4108 /* and return results */
4109 smb_SetSMBDataLength(outp, 0);
4114 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4116 smb_SetSMBDataLength(outp, 0);
4120 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4127 cm_scache_t *dscp; /* dir we're dealing with */
4128 cm_scache_t *scp; /* file we're creating */
4130 int initialModeBits;
4140 int parmSlot; /* which parm we're dealing with */
4148 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4149 openFun = smb_GetSMBParm(inp, 8); /* open function */
4150 excl = ((openFun & 3) == 0);
4151 trunc = ((openFun & 3) == 2); /* truncate it */
4152 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4153 openAction = 0; /* tracks what we did */
4155 attributes = smb_GetSMBParm(inp, 5);
4156 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4158 /* compute initial mode bits based on read-only flag in attributes */
4159 initialModeBits = 0666;
4160 if (attributes & 1) initialModeBits &= ~0222;
4162 pathp = smb_GetSMBData(inp, NULL);
4164 spacep = inp->spacep;
4165 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4167 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4168 /* special case magic file name for receiving IOCTL requests
4169 * (since IOCTL calls themselves aren't getting through).
4172 osi_Log0(smb_logp, "IOCTL Open");
4175 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4176 smb_SetupIoctlFid(fidp, spacep);
4178 /* set inp->fid so that later read calls in same msg can find fid */
4179 inp->fid = fidp->fid;
4181 /* copy out remainder of the parms */
4183 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4185 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4186 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4187 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4188 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4189 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4190 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4191 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4192 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4194 /* and the final "always present" stuff */
4195 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4196 /* next write out the "unique" ID */
4197 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4198 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4199 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4200 smb_SetSMBDataLength(outp, 0);
4202 /* and clean up fid reference */
4203 smb_ReleaseFID(fidp);
4207 #ifdef DEBUG_VERBOSE
4209 char *hexp, *asciip;
4210 asciip = (lastNamep ? lastNamep : pathp );
4211 hexp = osi_HexifyString(asciip);
4212 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4216 userp = smb_GetUser(vcp, inp);
4219 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4221 cm_ReleaseUser(userp);
4222 return CM_ERROR_NOSUCHPATH;
4224 code = cm_NameI(cm_rootSCachep, pathp,
4225 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4226 userp, tidPathp, &req, &scp);
4228 code = cm_NameI(cm_rootSCachep, spacep->data,
4229 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4230 userp, tidPathp, &req, &dscp);
4233 cm_ReleaseUser(userp);
4237 /* otherwise, scp points to the parent directory. Do a lookup,
4238 * and truncate the file if we find it, otherwise we create the
4241 if (!lastNamep) lastNamep = pathp;
4243 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
4245 if (code && code != CM_ERROR_NOSUCHFILE) {
4246 cm_ReleaseSCache(dscp);
4247 cm_ReleaseUser(userp);
4252 /* if we get here, if code is 0, the file exists and is represented by
4253 * scp. Otherwise, we have to create it. The dir may be represented
4254 * by dscp, or we may have found the file directly. If code is non-zero,
4258 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
4260 if (dscp) cm_ReleaseSCache(dscp);
4261 cm_ReleaseSCache(scp);
4262 cm_ReleaseUser(userp);
4267 /* oops, file shouldn't be there */
4268 if (dscp) cm_ReleaseSCache(dscp);
4269 cm_ReleaseSCache(scp);
4270 cm_ReleaseUser(userp);
4271 return CM_ERROR_EXISTS;
4275 setAttr.mask = CM_ATTRMASK_LENGTH;
4276 setAttr.length.LowPart = 0;
4277 setAttr.length.HighPart = 0;
4278 code = cm_SetAttr(scp, &setAttr, userp, &req);
4279 openAction = 3; /* truncated existing file */
4281 else openAction = 1; /* found existing file */
4283 else if (!(openFun & 0x10)) {
4284 /* don't create if not found */
4285 if (dscp) cm_ReleaseSCache(dscp);
4286 cm_ReleaseUser(userp);
4287 return CM_ERROR_NOSUCHFILE;
4290 osi_assert(dscp != NULL);
4291 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
4292 osi_LogSaveString(smb_logp, lastNamep));
4293 openAction = 2; /* created file */
4294 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4295 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
4296 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4298 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4299 smb_NotifyChange(FILE_ACTION_ADDED,
4300 FILE_NOTIFY_CHANGE_FILE_NAME,
4301 dscp, lastNamep, NULL, TRUE);
4302 if (!excl && code == CM_ERROR_EXISTS) {
4303 /* not an exclusive create, and someone else tried
4304 * creating it already, then we open it anyway. We
4305 * don't bother retrying after this, since if this next
4306 * fails, that means that the file was deleted after we
4307 * started this call.
4309 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4313 setAttr.mask = CM_ATTRMASK_LENGTH;
4314 setAttr.length.LowPart = 0;
4315 setAttr.length.HighPart = 0;
4316 code = cm_SetAttr(scp, &setAttr, userp, &req);
4318 } /* lookup succeeded */
4322 /* we don't need this any longer */
4323 if (dscp) cm_ReleaseSCache(dscp);
4326 /* something went wrong creating or truncating the file */
4327 if (scp) cm_ReleaseSCache(scp);
4328 cm_ReleaseUser(userp);
4332 /* make sure we're about to open a file */
4333 if (scp->fileType != CM_SCACHETYPE_FILE) {
4334 cm_ReleaseSCache(scp);
4335 cm_ReleaseUser(userp);
4336 return CM_ERROR_ISDIR;
4339 /* now all we have to do is open the file itself */
4340 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4343 /* save a pointer to the vnode */
4346 /* compute open mode */
4347 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
4348 if (openMode == 1 || openMode == 2)
4349 fidp->flags |= SMB_FID_OPENWRITE;
4351 smb_ReleaseFID(fidp);
4353 cm_Open(scp, 0, userp);
4355 /* set inp->fid so that later read calls in same msg can find fid */
4356 inp->fid = fidp->fid;
4358 /* copy out remainder of the parms */
4360 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4361 lock_ObtainMutex(&scp->mx);
4363 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
4364 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4365 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
4366 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
4367 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
4368 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
4369 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4370 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4371 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4373 /* and the final "always present" stuff */
4374 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
4375 /* next write out the "unique" ID */
4376 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
4377 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
4378 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4379 lock_ReleaseMutex(&scp->mx);
4380 smb_SetSMBDataLength(outp, 0);
4382 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
4384 cm_ReleaseUser(userp);
4385 /* leave scp held since we put it in fidp->scp */
4389 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4396 unsigned char LockType;
4397 unsigned short NumberOfUnlocks, NumberOfLocks;
4398 unsigned long Timeout;
4400 LARGE_INTEGER LOffset, LLength;
4401 smb_waitingLock_t *waitingLock;
4408 fid = smb_GetSMBParm(inp, 2);
4409 fid = smb_ChainFID(fid, inp);
4411 fidp = smb_FindFID(vcp, fid, 0);
4412 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4413 return CM_ERROR_BADFD;
4415 /* set inp->fid so that later read calls in same msg can find fid */
4418 userp = smb_GetUser(vcp, inp);
4422 lock_ObtainMutex(&scp->mx);
4423 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4424 CM_SCACHESYNC_NEEDCALLBACK
4425 | CM_SCACHESYNC_GETSTATUS
4426 | CM_SCACHESYNC_LOCK);
4427 if (code) goto doneSync;
4429 LockType = smb_GetSMBParm(inp, 3) & 0xff;
4430 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
4431 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
4432 NumberOfLocks = smb_GetSMBParm(inp, 7);
4434 op = smb_GetSMBData(inp, NULL);
4436 for (i=0; i<NumberOfUnlocks; i++) {
4437 if (LockType & 0x10) {
4439 LOffset.HighPart = *((LONG *)(op + 4));
4440 LOffset.LowPart = *((DWORD *)(op + 8));
4441 LLength.HighPart = *((LONG *)(op + 12));
4442 LLength.LowPart = *((DWORD *)(op + 16));
4446 /* Not Large Files */
4447 LOffset.HighPart = 0;
4448 LOffset.LowPart = *((DWORD *)(op + 2));
4449 LLength.HighPart = 0;
4450 LLength.LowPart = *((DWORD *)(op + 6));
4453 if (LargeIntegerNotEqualToZero(LOffset))
4455 /* Do not check length -- length check done in cm_Unlock */
4457 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
4458 if (code) goto done;
4461 for (i=0; i<NumberOfLocks; i++) {
4462 if (LockType & 0x10) {
4464 LOffset.HighPart = *((LONG *)(op + 4));
4465 LOffset.LowPart = *((DWORD *)(op + 8));
4466 LLength.HighPart = *((LONG *)(op + 12));
4467 LLength.LowPart = *((DWORD *)(op + 16));
4471 /* Not Large Files */
4472 LOffset.HighPart = 0;
4473 LOffset.LowPart = *((DWORD *)(op + 2));
4474 LLength.HighPart = 0;
4475 LLength.LowPart = *((DWORD *)(op + 6));
4478 if (LargeIntegerNotEqualToZero(LOffset))
4480 if (LargeIntegerLessThan(LOffset, scp->length))
4483 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
4484 userp, &req, &lockp);
4485 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
4486 /* Put on waiting list */
4487 waitingLock = malloc(sizeof(smb_waitingLock_t));
4488 waitingLock->vcp = vcp;
4489 waitingLock->inp = smb_CopyPacket(inp);
4490 waitingLock->outp = smb_CopyPacket(outp);
4491 waitingLock->timeRemaining = Timeout;
4492 waitingLock->lockp = lockp;
4493 lock_ObtainWrite(&smb_globalLock);
4494 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
4496 osi_Wakeup((long) &smb_allWaitingLocks);
4497 lock_ReleaseWrite(&smb_globalLock);
4498 /* don't send reply immediately */
4499 outp->flags |= SMB_PACKETFLAG_NOSEND;
4505 /* release any locks acquired before the failure */
4508 smb_SetSMBDataLength(outp, 0);
4510 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
4512 lock_ReleaseMutex(&scp->mx);
4513 cm_ReleaseUser(userp);
4514 smb_ReleaseFID(fidp);
4519 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4531 fid = smb_GetSMBParm(inp, 0);
4532 fid = smb_ChainFID(fid, inp);
4534 fidp = smb_FindFID(vcp, fid, 0);
4535 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4536 return CM_ERROR_BADFD;
4539 userp = smb_GetUser(vcp, inp);
4543 /* otherwise, stat the file */
4544 lock_ObtainMutex(&scp->mx);
4545 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4546 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4547 if (code) goto done;
4549 /* decode times. We need a search time, but the response to this
4550 * call provides the date first, not the time, as returned in the
4551 * searchTime variable. So we take the high-order bits first.
4553 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
4554 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
4555 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
4556 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
4557 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
4558 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
4559 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
4561 /* now handle file size and allocation size */
4562 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
4563 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
4564 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
4565 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
4567 /* file attribute */
4568 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
4570 /* and finalize stuff */
4571 smb_SetSMBDataLength(outp, 0);
4575 lock_ReleaseMutex(&scp->mx);
4576 cm_ReleaseUser(userp);
4577 smb_ReleaseFID(fidp);
4581 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4595 fid = smb_GetSMBParm(inp, 0);
4596 fid = smb_ChainFID(fid, inp);
4598 fidp = smb_FindFID(vcp, fid, 0);
4599 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4600 return CM_ERROR_BADFD;
4603 userp = smb_GetUser(vcp, inp);
4607 /* now prepare to call cm_setattr. This message only sets various times,
4608 * and AFS only implements mtime, and we'll set the mtime if that's
4609 * requested. The others we'll ignore.
4611 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
4613 if (searchTime != 0) {
4614 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
4616 if ( unixTime != -1 ) {
4617 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
4618 attrs.clientModTime = unixTime;
4619 code = cm_SetAttr(scp, &attrs, userp, &req);
4621 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
4623 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
4628 cm_ReleaseUser(userp);
4629 smb_ReleaseFID(fidp);
4634 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4637 long count, finalCount;
4644 fd = smb_GetSMBParm(inp, 2);
4645 count = smb_GetSMBParm(inp, 5);
4646 offset.HighPart = 0; /* too bad */
4647 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
4649 osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
4650 fd, offset.LowPart, count);
4652 fd = smb_ChainFID(fd, inp);
4653 fidp = smb_FindFID(vcp, fd, 0);
4655 return CM_ERROR_BADFD;
4657 /* set inp->fid so that later read calls in same msg can find fid */
4660 if (fidp->flags & SMB_FID_IOCTL) {
4661 return smb_IoctlV3Read(fidp, vcp, inp, outp);
4664 userp = smb_GetUser(vcp, inp);
4666 /* 0 and 1 are reserved for request chaining, were setup by our caller,
4667 * and will be further filled in after we return.
4669 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
4670 smb_SetSMBParm(outp, 3, 0); /* resvd */
4671 smb_SetSMBParm(outp, 4, 0); /* resvd */
4672 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
4673 /* fill in #6 when we have all the parameters' space reserved */
4674 smb_SetSMBParm(outp, 7, 0); /* resv'd */
4675 smb_SetSMBParm(outp, 8, 0); /* resv'd */
4676 smb_SetSMBParm(outp, 9, 0); /* resv'd */
4677 smb_SetSMBParm(outp, 10, 0); /* resv'd */
4678 smb_SetSMBParm(outp, 11, 0); /* reserved */
4680 /* get op ptr after putting in the parms, since otherwise we don't
4681 * know where the data really is.
4683 op = smb_GetSMBData(outp, NULL);
4685 /* now fill in offset from start of SMB header to first data byte (to op) */
4686 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
4688 /* set the packet data length the count of the # of bytes */
4689 smb_SetSMBDataLength(outp, count);
4692 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
4694 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
4697 /* fix some things up */
4698 smb_SetSMBParm(outp, 5, finalCount);
4699 smb_SetSMBDataLength(outp, finalCount);
4701 smb_ReleaseFID(fidp);
4703 cm_ReleaseUser(userp);
4708 * Values for createDisp, copied from NTDDK.H
4710 #define FILE_SUPERSEDE 0 // (???)
4711 #define FILE_OPEN 1 // (open)
4712 #define FILE_CREATE 2 // (exclusive)
4713 #define FILE_OPEN_IF 3 // (non-exclusive)
4714 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
4715 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
4717 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4719 char *pathp, *realPathp;
4723 cm_scache_t *dscp; /* parent dir */
4724 cm_scache_t *scp; /* file to create or open */
4725 cm_scache_t *targetScp; /* if scp is a symlink */
4729 unsigned short nameLength;
4731 unsigned int requestOpLock;
4732 unsigned int requestBatchOpLock;
4733 unsigned int mustBeDir;
4734 unsigned int treeCreate;
4736 unsigned int desiredAccess;
4737 unsigned int extAttributes;
4738 unsigned int createDisp;
4739 unsigned int createOptions;
4740 int initialModeBits;
4741 unsigned short baseFid;
4742 smb_fid_t *baseFidp;
4744 cm_scache_t *baseDirp;
4745 unsigned short openAction;
4760 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
4761 flags = smb_GetSMBOffsetParm(inp, 3, 1)
4762 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
4763 requestOpLock = flags & 0x02;
4764 requestBatchOpLock = flags & 0x04;
4765 mustBeDir = flags & 0x08;
4768 * Why all of a sudden 32-bit FID?
4769 * We will reject all bits higher than 16.
4771 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
4772 return CM_ERROR_INVAL;
4773 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
4774 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
4775 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
4776 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
4777 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
4778 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
4779 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
4780 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
4781 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
4783 /* mustBeDir is never set; createOptions directory bit seems to be
4786 if (createOptions & 1)
4788 else if (createOptions & 0x40)
4794 * compute initial mode bits based on read-only flag in
4795 * extended attributes
4797 initialModeBits = 0666;
4798 if (extAttributes & 1)
4799 initialModeBits &= ~0222;
4801 pathp = smb_GetSMBData(inp, NULL);
4802 /* Sometimes path is not null-terminated, so we make a copy. */
4803 realPathp = malloc(nameLength+1);
4804 memcpy(realPathp, pathp, nameLength);
4805 realPathp[nameLength] = 0;
4807 spacep = inp->spacep;
4808 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
4810 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
4811 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
4812 osi_Log2(smb_logp,"... flags=[%x] lastNamep=[%s]", flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
4814 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4815 /* special case magic file name for receiving IOCTL requests
4816 * (since IOCTL calls themselves aren't getting through).
4818 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4819 smb_SetupIoctlFid(fidp, spacep);
4820 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
4822 /* set inp->fid so that later read calls in same msg can find fid */
4823 inp->fid = fidp->fid;
4827 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
4828 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4829 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
4831 memset(&ft, 0, sizeof(ft));
4832 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4833 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4834 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4835 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4836 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
4837 sz.HighPart = 0x7fff; sz.LowPart = 0;
4838 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
4839 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
4840 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
4841 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
4842 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
4843 smb_SetSMBDataLength(outp, 0);
4845 /* clean up fid reference */
4846 smb_ReleaseFID(fidp);
4851 #ifdef DEBUG_VERBOSE
4853 char *hexp, *asciip;
4854 asciip = (lastNamep? lastNamep : realPathp);
4855 hexp = osi_HexifyString( asciip );
4856 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
4860 userp = smb_GetUser(vcp, inp);
4862 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
4864 return CM_ERROR_INVAL;
4868 baseDirp = cm_rootSCachep;
4869 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4870 if (code == CM_ERROR_TIDIPC) {
4871 /* Attempt to use a TID allocated for IPC. The client
4872 * is probably looking for DCE RPC end points which we
4874 osi_Log0(smb_logp, "NTCreateX received IPC TID");
4876 cm_ReleaseUser(userp);
4877 return CM_ERROR_NOSUCHFILE;
4881 baseFidp = smb_FindFID(vcp, baseFid, 0);
4883 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
4885 cm_ReleaseUser(userp);
4886 return CM_ERROR_INVAL;
4888 baseDirp = baseFidp->scp;
4892 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
4894 /* compute open mode */
4896 if (desiredAccess & DELETE)
4897 fidflags |= SMB_FID_OPENDELETE;
4898 if (desiredAccess & AFS_ACCESS_READ)
4899 fidflags |= SMB_FID_OPENREAD;
4900 if (desiredAccess & AFS_ACCESS_WRITE)
4901 fidflags |= SMB_FID_OPENWRITE;
4905 /* For an exclusive create, we want to do a case sensitive match for the last component. */
4906 if ( createDisp == FILE_CREATE ||
4907 createDisp == FILE_OVERWRITE ||
4908 createDisp == FILE_OVERWRITE_IF) {
4909 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4910 userp, tidPathp, &req, &dscp);
4912 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
4914 if (code == CM_ERROR_NOSUCHFILE) {
4915 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
4916 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
4917 if (code == 0 && realDirFlag == 1) {
4918 cm_ReleaseSCache(scp);
4919 cm_ReleaseSCache(dscp);
4920 cm_ReleaseUser(userp);
4922 return CM_ERROR_EXISTS;
4928 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4929 userp, tidPathp, &req, &scp);
4934 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
4935 /* look up parent directory */
4936 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
4937 * the immediate parent. We have to work our way up realPathp until we hit something that we
4945 code = cm_NameI(baseDirp, spacep->data,
4946 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4947 userp, tidPathp, &req, &dscp);
4950 (tp = strrchr(spacep->data,'\\')) &&
4951 (createDisp == FILE_CREATE) &&
4952 (realDirFlag == 1)) {
4955 treeStartp = realPathp + (tp - spacep->data);
4957 if (*tp && !smb_IsLegalFilename(tp)) {
4959 smb_ReleaseFID(baseFidp);
4960 cm_ReleaseUser(userp);
4962 return CM_ERROR_BADNTFILENAME;
4972 smb_ReleaseFID(baseFidp);
4975 osi_Log0(smb_logp,"NTCreateX parent not found");
4976 cm_ReleaseUser(userp);
4981 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
4982 /* A file exists where we want a directory. */
4983 cm_ReleaseSCache(dscp);
4984 cm_ReleaseUser(userp);
4986 return CM_ERROR_EXISTS;
4990 lastNamep = realPathp;
4994 if (!smb_IsLegalFilename(lastNamep)) {
4995 cm_ReleaseSCache(dscp);
4996 cm_ReleaseUser(userp);
4998 return CM_ERROR_BADNTFILENAME;
5001 if (!foundscp && !treeCreate) {
5002 if ( createDisp == FILE_CREATE ||
5003 createDisp == FILE_OVERWRITE ||
5004 createDisp == FILE_OVERWRITE_IF) {
5005 code = cm_Lookup(dscp, lastNamep,
5006 CM_FLAG_FOLLOW, userp, &req, &scp);
5008 code = cm_Lookup(dscp, lastNamep,
5009 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5012 if (code && code != CM_ERROR_NOSUCHFILE) {
5013 cm_ReleaseSCache(dscp);
5014 cm_ReleaseUser(userp);
5022 smb_ReleaseFID(baseFidp);
5025 /* if we get here, if code is 0, the file exists and is represented by
5026 * scp. Otherwise, we have to create it. The dir may be represented
5027 * by dscp, or we may have found the file directly. If code is non-zero,
5030 if (code == 0 && !treeCreate) {
5031 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
5034 if (dscp) cm_ReleaseSCache(dscp);
5035 cm_ReleaseSCache(scp);
5036 cm_ReleaseUser(userp);
5041 if (createDisp == FILE_CREATE) {
5042 /* oops, file shouldn't be there */
5043 if (dscp) cm_ReleaseSCache(dscp);
5044 cm_ReleaseSCache(scp);
5045 cm_ReleaseUser(userp);
5047 return CM_ERROR_EXISTS;
5050 if ( createDisp == FILE_OVERWRITE ||
5051 createDisp == FILE_OVERWRITE_IF) {
5052 setAttr.mask = CM_ATTRMASK_LENGTH;
5053 setAttr.length.LowPart = 0;
5054 setAttr.length.HighPart = 0;
5055 /* now watch for a symlink */
5057 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5059 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5061 /* we have a more accurate file to use (the
5062 * target of the symbolic link). Otherwise,
5063 * we'll just use the symlink anyway.
5065 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5067 cm_ReleaseSCache(scp);
5071 code = cm_SetAttr(scp, &setAttr, userp, &req);
5072 openAction = 3; /* truncated existing file */
5074 else openAction = 1; /* found existing file */
5076 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
5077 /* don't create if not found */
5078 if (dscp) cm_ReleaseSCache(dscp);
5079 cm_ReleaseUser(userp);
5081 return CM_ERROR_NOSUCHFILE;
5083 else if (realDirFlag == 0 || realDirFlag == -1) {
5084 osi_assert(dscp != NULL);
5085 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
5086 osi_LogSaveString(smb_logp, lastNamep));
5087 openAction = 2; /* created file */
5088 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5089 setAttr.clientModTime = time(NULL);
5090 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5092 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5093 smb_NotifyChange(FILE_ACTION_ADDED,
5094 FILE_NOTIFY_CHANGE_FILE_NAME,
5095 dscp, lastNamep, NULL, TRUE);
5096 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
5097 /* Not an exclusive create, and someone else tried
5098 * creating it already, then we open it anyway. We
5099 * don't bother retrying after this, since if this next
5100 * fails, that means that the file was deleted after we
5101 * started this call.
5103 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5106 if (createDisp == FILE_OVERWRITE_IF) {
5107 setAttr.mask = CM_ATTRMASK_LENGTH;
5108 setAttr.length.LowPart = 0;
5109 setAttr.length.HighPart = 0;
5111 /* now watch for a symlink */
5113 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5115 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5117 /* we have a more accurate file to use (the
5118 * target of the symbolic link). Otherwise,
5119 * we'll just use the symlink anyway.
5121 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5123 cm_ReleaseSCache(scp);
5127 code = cm_SetAttr(scp, &setAttr, userp, &req);
5129 } /* lookup succeeded */
5134 char *cp; /* This component */
5135 int clen = 0; /* length of component */
5139 /* create directory */
5141 treeStartp = lastNamep;
5142 osi_assert(dscp != NULL);
5143 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
5144 osi_LogSaveString(smb_logp, treeStartp));
5145 openAction = 2; /* created directory */
5147 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5148 setAttr.clientModTime = time(NULL);
5155 tp = strchr(pp, '\\');
5159 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
5163 strncpy(cp,pp,clen);
5170 continue; /* the supplied path can't have consecutive slashes either , but */
5172 /* cp is the next component to be created. */
5173 code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
5174 if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
5175 smb_NotifyChange(FILE_ACTION_ADDED,
5176 FILE_NOTIFY_CHANGE_DIR_NAME,
5177 tscp, cp, NULL, TRUE);
5179 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
5180 /* Not an exclusive create, and someone else tried
5181 * creating it already, then we open it anyway. We
5182 * don't bother retrying after this, since if this next
5183 * fails, that means that the file was deleted after we
5184 * started this call.
5186 code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
5191 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
5192 cm_ReleaseSCache(tscp);
5193 tscp = scp; /* Newly created directory will be next parent */
5198 * if we get here and code == 0, then scp is the last directory created, and tscp is the
5199 * parent of scp. dscp got released if dscp != tscp. both tscp and scp are held.
5205 /* something went wrong creating or truncating the file */
5206 if (scp) cm_ReleaseSCache(scp);
5207 if (dscp) cm_ReleaseSCache(dscp);
5208 cm_ReleaseUser(userp);
5213 /* make sure we have file vs. dir right (only applies for single component case) */
5214 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5215 /* now watch for a symlink */
5217 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5218 cm_scache_t * targetScp = 0;
5219 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5221 /* we have a more accurate file to use (the
5222 * target of the symbolic link). Otherwise,
5223 * we'll just use the symlink anyway.
5225 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5227 cm_ReleaseSCache(scp);
5232 if (scp->fileType != CM_SCACHETYPE_FILE) {
5233 cm_ReleaseSCache(scp);
5234 cm_ReleaseUser(userp);
5236 return CM_ERROR_ISDIR;
5240 /* (only applies to single component case) */
5241 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5242 cm_ReleaseSCache(scp);
5243 if (dscp) cm_ReleaseSCache(dscp);
5244 cm_ReleaseUser(userp);
5246 return CM_ERROR_NOTDIR;
5249 /* open the file itself */
5250 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5252 /* save a pointer to the vnode */
5255 fidp->flags = fidflags;
5257 /* save parent dir and pathname for delete or change notification */
5258 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5259 fidp->flags |= SMB_FID_NTOPEN;
5260 fidp->NTopen_dscp = dscp;
5261 cm_HoldSCache(dscp);
5262 fidp->NTopen_pathp = strdup(lastNamep);
5264 fidp->NTopen_wholepathp = realPathp;
5266 /* we don't need this any longer */
5267 if (dscp) cm_ReleaseSCache(dscp);
5268 cm_Open(scp, 0, userp);
5270 /* set inp->fid so that later read calls in same msg can find fid */
5271 inp->fid = fidp->fid;
5275 lock_ObtainMutex(&scp->mx);
5276 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5277 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5278 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
5279 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5280 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5281 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5282 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5283 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5284 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
5286 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5287 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5288 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
5289 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
5290 smb_SetSMBParmByte(outp, parmSlot,
5291 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
5292 lock_ReleaseMutex(&scp->mx);
5293 smb_SetSMBDataLength(outp, 0);
5295 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
5296 osi_LogSaveString(smb_logp, realPathp));
5298 smb_ReleaseFID(fidp);
5300 cm_ReleaseUser(userp);
5302 /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
5304 /* leave scp held since we put it in fidp->scp */
5309 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
5310 * Instead, ultimately, would like to use a subroutine for common code.
5312 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5314 char *pathp, *realPathp;
5318 cm_scache_t *dscp; /* parent dir */
5319 cm_scache_t *scp; /* file to create or open */
5320 cm_scache_t *targetScp; /* if scp is a symlink */
5323 unsigned long nameLength;
5325 unsigned int requestOpLock;
5326 unsigned int requestBatchOpLock;
5327 unsigned int mustBeDir;
5328 unsigned int extendedRespRequired;
5330 unsigned int desiredAccess;
5331 #ifdef DEBUG_VERBOSE
5332 unsigned int allocSize;
5333 unsigned int shareAccess;
5335 unsigned int extAttributes;
5336 unsigned int createDisp;
5337 #ifdef DEBUG_VERBOSE
5340 unsigned int createOptions;
5341 int initialModeBits;
5342 unsigned short baseFid;
5343 smb_fid_t *baseFidp;
5345 cm_scache_t *baseDirp;
5346 unsigned short openAction;
5352 int parmOffset, dataOffset;
5363 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
5364 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
5365 parmp = inp->data + parmOffset;
5366 lparmp = (ULONG *) parmp;
5369 requestOpLock = flags & 0x02;
5370 requestBatchOpLock = flags & 0x04;
5371 mustBeDir = flags & 0x08;
5372 extendedRespRequired = flags & 0x10;
5375 * Why all of a sudden 32-bit FID?
5376 * We will reject all bits higher than 16.
5378 if (lparmp[1] & 0xFFFF0000)
5379 return CM_ERROR_INVAL;
5380 baseFid = (unsigned short)lparmp[1];
5381 desiredAccess = lparmp[2];
5382 #ifdef DEBUG_VERBOSE
5383 allocSize = lparmp[3];
5384 #endif /* DEBUG_VERSOSE */
5385 extAttributes = lparmp[5];
5387 shareAccess = lparmp[6];
5389 createDisp = lparmp[7];
5390 createOptions = lparmp[8];
5391 #ifdef DEBUG_VERBOSE
5394 nameLength = lparmp[11];
5396 #ifdef DEBUG_VERBOSE
5397 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
5398 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
5399 osi_Log1(smb_logp,"... flags[%x]",flags);
5402 /* mustBeDir is never set; createOptions directory bit seems to be
5405 if (createOptions & 1)
5407 else if (createOptions & 0x40)
5413 * compute initial mode bits based on read-only flag in
5414 * extended attributes
5416 initialModeBits = 0666;
5417 if (extAttributes & 1)
5418 initialModeBits &= ~0222;
5420 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
5421 /* Sometimes path is not null-terminated, so we make a copy. */
5422 realPathp = malloc(nameLength+1);
5423 memcpy(realPathp, pathp, nameLength);
5424 realPathp[nameLength] = 0;
5426 spacep = cm_GetSpace();
5427 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5430 * Nothing here to handle SMB_IOCTL_FILENAME.
5431 * Will add it if necessary.
5434 #ifdef DEBUG_VERBOSE
5436 char *hexp, *asciip;
5437 asciip = (lastNamep? lastNamep : realPathp);
5438 hexp = osi_HexifyString( asciip );
5439 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
5444 userp = smb_GetUser(vcp, inp);
5446 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
5448 return CM_ERROR_INVAL;
5452 baseDirp = cm_rootSCachep;
5453 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5454 if(code == CM_ERROR_TIDIPC) {
5455 /* Attempt to use TID allocated for IPC. The client is
5456 * probably trying to locate DCE RPC endpoints, which we
5458 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
5460 cm_ReleaseUser(userp);
5461 return CM_ERROR_NOSUCHPATH;
5465 baseFidp = smb_FindFID(vcp, baseFid, 0);
5467 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
5469 cm_ReleaseUser(userp);
5470 return CM_ERROR_INVAL;
5472 baseDirp = baseFidp->scp;
5476 /* compute open mode */
5478 if (desiredAccess & DELETE)
5479 fidflags |= SMB_FID_OPENDELETE;
5480 if (desiredAccess & AFS_ACCESS_READ)
5481 fidflags |= SMB_FID_OPENREAD;
5482 if (desiredAccess & AFS_ACCESS_WRITE)
5483 fidflags |= SMB_FID_OPENWRITE;
5487 if ( createDisp == FILE_OPEN ||
5488 createDisp == FILE_OVERWRITE ||
5489 createDisp == FILE_OVERWRITE_IF) {
5490 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5491 userp, tidPathp, &req, &dscp);
5493 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5495 if (code == CM_ERROR_NOSUCHFILE) {
5496 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
5497 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
5498 if (code == 0 && realDirFlag == 1) {
5499 cm_ReleaseSCache(scp);
5500 cm_ReleaseSCache(dscp);
5501 cm_ReleaseUser(userp);
5503 return CM_ERROR_EXISTS;
5509 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5510 userp, tidPathp, &req, &scp);
5516 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
5517 /* look up parent directory */
5519 code = cm_NameI(baseDirp, spacep->data,
5520 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5521 userp, tidPathp, &req, &dscp);
5525 cm_FreeSpace(spacep);
5528 smb_ReleaseFID(baseFidp);
5533 cm_ReleaseUser(userp);
5538 if (!lastNamep) lastNamep = realPathp;
5541 if (!smb_IsLegalFilename(lastNamep))
5542 return CM_ERROR_BADNTFILENAME;
5545 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
5546 code = cm_Lookup(dscp, lastNamep,
5547 CM_FLAG_FOLLOW, userp, &req, &scp);
5549 code = cm_Lookup(dscp, lastNamep,
5550 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5553 if (code && code != CM_ERROR_NOSUCHFILE) {
5554 cm_ReleaseSCache(dscp);
5555 cm_ReleaseUser(userp);
5563 smb_ReleaseFID(baseFidp);
5566 cm_FreeSpace(spacep);
5569 /* if we get here, if code is 0, the file exists and is represented by
5570 * scp. Otherwise, we have to create it. The dir may be represented
5571 * by dscp, or we may have found the file directly. If code is non-zero,
5575 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
5578 if (dscp) cm_ReleaseSCache(dscp);
5579 cm_ReleaseSCache(scp);
5580 cm_ReleaseUser(userp);
5585 if (createDisp == FILE_CREATE) {
5586 /* oops, file shouldn't be there */
5587 if (dscp) cm_ReleaseSCache(dscp);
5588 cm_ReleaseSCache(scp);
5589 cm_ReleaseUser(userp);
5591 return CM_ERROR_EXISTS;
5594 if (createDisp == FILE_OVERWRITE ||
5595 createDisp == FILE_OVERWRITE_IF) {
5596 setAttr.mask = CM_ATTRMASK_LENGTH;
5597 setAttr.length.LowPart = 0;
5598 setAttr.length.HighPart = 0;
5600 /* now watch for a symlink */
5602 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5604 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5606 /* we have a more accurate file to use (the
5607 * target of the symbolic link). Otherwise,
5608 * we'll just use the symlink anyway.
5610 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5612 cm_ReleaseSCache(scp);
5616 code = cm_SetAttr(scp, &setAttr, userp, &req);
5617 openAction = 3; /* truncated existing file */
5619 else openAction = 1; /* found existing file */
5621 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
5622 /* don't create if not found */
5623 if (dscp) cm_ReleaseSCache(dscp);
5624 cm_ReleaseUser(userp);
5626 return CM_ERROR_NOSUCHFILE;
5628 else if (realDirFlag == 0 || realDirFlag == -1) {
5629 osi_assert(dscp != NULL);
5630 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
5631 osi_LogSaveString(smb_logp, lastNamep));
5632 openAction = 2; /* created file */
5633 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5634 setAttr.clientModTime = time(NULL);
5635 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5637 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5638 smb_NotifyChange(FILE_ACTION_ADDED,
5639 FILE_NOTIFY_CHANGE_FILE_NAME,
5640 dscp, lastNamep, NULL, TRUE);
5641 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
5642 /* Not an exclusive create, and someone else tried
5643 * creating it already, then we open it anyway. We
5644 * don't bother retrying after this, since if this next
5645 * fails, that means that the file was deleted after we
5646 * started this call.
5648 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5651 if (createDisp == FILE_OVERWRITE_IF) {
5652 setAttr.mask = CM_ATTRMASK_LENGTH;
5653 setAttr.length.LowPart = 0;
5654 setAttr.length.HighPart = 0;
5656 /* now watch for a symlink */
5658 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5660 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5662 /* we have a more accurate file to use (the
5663 * target of the symbolic link). Otherwise,
5664 * we'll just use the symlink anyway.
5666 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5668 cm_ReleaseSCache(scp);
5672 code = cm_SetAttr(scp, &setAttr, userp, &req);
5674 } /* lookup succeeded */
5678 /* create directory */
5679 osi_assert(dscp != NULL);
5681 "smb_ReceiveNTTranCreate creating directory %s",
5682 osi_LogSaveString(smb_logp, lastNamep));
5683 openAction = 2; /* created directory */
5684 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5685 setAttr.clientModTime = time(NULL);
5686 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5687 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5688 smb_NotifyChange(FILE_ACTION_ADDED,
5689 FILE_NOTIFY_CHANGE_DIR_NAME,
5690 dscp, lastNamep, NULL, TRUE);
5692 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
5693 /* Not an exclusive create, and someone else tried
5694 * creating it already, then we open it anyway. We
5695 * don't bother retrying after this, since if this next
5696 * fails, that means that the file was deleted after we
5697 * started this call.
5699 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5705 /* something went wrong creating or truncating the file */
5706 if (scp) cm_ReleaseSCache(scp);
5707 cm_ReleaseUser(userp);
5712 /* make sure we have file vs. dir right */
5713 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5714 /* now watch for a symlink */
5716 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5718 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5720 /* we have a more accurate file to use (the
5721 * target of the symbolic link). Otherwise,
5722 * we'll just use the symlink anyway.
5724 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5726 cm_ReleaseSCache(scp);
5731 if (scp->fileType != CM_SCACHETYPE_FILE) {
5732 cm_ReleaseSCache(scp);
5733 cm_ReleaseUser(userp);
5735 return CM_ERROR_ISDIR;
5739 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5740 cm_ReleaseSCache(scp);
5741 cm_ReleaseUser(userp);
5743 return CM_ERROR_NOTDIR;
5746 /* open the file itself */
5747 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5750 /* save a pointer to the vnode */
5753 fidp->flags = fidflags;
5755 /* save parent dir and pathname for deletion or change notification */
5756 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5757 fidp->flags |= SMB_FID_NTOPEN;
5758 fidp->NTopen_dscp = dscp;
5759 cm_HoldSCache(dscp);
5760 fidp->NTopen_pathp = strdup(lastNamep);
5762 fidp->NTopen_wholepathp = realPathp;
5764 /* we don't need this any longer */
5765 if (dscp) cm_ReleaseSCache(dscp);
5767 cm_Open(scp, 0, userp);
5769 /* set inp->fid so that later read calls in same msg can find fid */
5770 inp->fid = fidp->fid;
5772 /* check whether we are required to send an extended response */
5773 if (!extendedRespRequired) {
5775 parmOffset = 8*4 + 39;
5776 parmOffset += 1; /* pad to 4 */
5777 dataOffset = parmOffset + 70;
5781 /* Total Parameter Count */
5782 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
5783 /* Total Data Count */
5784 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5785 /* Parameter Count */
5786 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
5787 /* Parameter Offset */
5788 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5789 /* Parameter Displacement */
5790 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5792 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5794 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5795 /* Data Displacement */
5796 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5797 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5798 smb_SetSMBDataLength(outp, 70);
5800 lock_ObtainMutex(&scp->mx);
5801 outData = smb_GetSMBData(outp, NULL);
5802 outData++; /* round to get to parmOffset */
5803 *outData = 0; outData++; /* oplock */
5804 *outData = 0; outData++; /* reserved */
5805 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
5806 *((ULONG *)outData) = openAction; outData += 4;
5807 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
5808 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5809 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
5810 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
5811 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
5812 *((FILETIME *)outData) = ft; outData += 8; /* change time */
5813 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
5814 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
5815 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
5816 *((USHORT *)outData) = 0; outData += 2; /* filetype */
5817 *((USHORT *)outData) = 0; outData += 2; /* dev state */
5818 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
5819 outData += 2; /* is a dir? */
5820 lock_ReleaseMutex(&scp->mx);
5823 parmOffset = 8*4 + 39;
5824 parmOffset += 1; /* pad to 4 */
5825 dataOffset = parmOffset + 104;
5829 /* Total Parameter Count */
5830 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
5831 /* Total Data Count */
5832 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5833 /* Parameter Count */
5834 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
5835 /* Parameter Offset */
5836 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5837 /* Parameter Displacement */
5838 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5840 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5842 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5843 /* Data Displacement */
5844 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5845 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5846 smb_SetSMBDataLength(outp, 105);
5848 lock_ObtainMutex(&scp->mx);
5849 outData = smb_GetSMBData(outp, NULL);
5850 outData++; /* round to get to parmOffset */
5851 *outData = 0; outData++; /* oplock */
5852 *outData = 1; outData++; /* response type */
5853 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
5854 *((ULONG *)outData) = openAction; outData += 4;
5855 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
5856 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5857 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
5858 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
5859 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
5860 *((FILETIME *)outData) = ft; outData += 8; /* change time */
5861 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
5862 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
5863 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
5864 *((USHORT *)outData) = 0; outData += 2; /* filetype */
5865 *((USHORT *)outData) = 0; outData += 2; /* dev state */
5866 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
5867 outData += 1; /* is a dir? */
5868 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
5869 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
5870 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
5871 lock_ReleaseMutex(&scp->mx);
5874 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
5876 smb_ReleaseFID(fidp);
5878 cm_ReleaseUser(userp);
5880 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
5881 /* leave scp held since we put it in fidp->scp */
5885 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
5888 smb_packet_t *savedPacketp;
5889 ULONG filter; USHORT fid, watchtree;
5893 filter = smb_GetSMBParm(inp, 19)
5894 | (smb_GetSMBParm(inp, 20) << 16);
5895 fid = smb_GetSMBParm(inp, 21);
5896 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
5898 fidp = smb_FindFID(vcp, fid, 0);
5900 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
5901 return CM_ERROR_BADFD;
5904 savedPacketp = smb_CopyPacket(inp);
5906 savedPacketp->vcp = vcp;
5907 lock_ObtainMutex(&smb_Dir_Watch_Lock);
5908 savedPacketp->nextp = smb_Directory_Watches;
5909 smb_Directory_Watches = savedPacketp;
5910 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
5912 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
5913 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
5916 lock_ObtainMutex(&scp->mx);
5918 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
5920 scp->flags |= CM_SCACHEFLAG_WATCHED;
5921 lock_ReleaseMutex(&scp->mx);
5922 smb_ReleaseFID(fidp);
5924 outp->flags |= SMB_PACKETFLAG_NOSEND;
5928 unsigned char nullSecurityDesc[36] = {
5929 0x01, /* security descriptor revision */
5930 0x00, /* reserved, should be zero */
5931 0x00, 0x80, /* security descriptor control;
5932 * 0x8000 : self-relative format */
5933 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
5934 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
5935 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
5936 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
5937 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5938 /* "null SID" owner SID */
5939 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5940 /* "null SID" group SID */
5943 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5945 int parmOffset, parmCount, dataOffset, dataCount;
5953 ULONG securityInformation;
5955 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
5956 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
5957 parmp = inp->data + parmOffset;
5958 sparmp = (USHORT *) parmp;
5959 lparmp = (ULONG *) parmp;
5962 securityInformation = lparmp[1];
5964 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
5965 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
5973 parmOffset = 8*4 + 39;
5974 parmOffset += 1; /* pad to 4 */
5976 dataOffset = parmOffset + parmCount;
5980 /* Total Parameter Count */
5981 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
5982 /* Total Data Count */
5983 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
5984 /* Parameter Count */
5985 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
5986 /* Parameter Offset */
5987 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5988 /* Parameter Displacement */
5989 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5991 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
5993 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5994 /* Data Displacement */
5995 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5996 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5997 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
5999 outData = smb_GetSMBData(outp, NULL);
6000 outData++; /* round to get to parmOffset */
6001 *((ULONG *)outData) = 36; outData += 4; /* length */
6003 if (maxData >= 36) {
6004 memcpy(outData, nullSecurityDesc, 36);
6008 return CM_ERROR_BUFFERTOOSMALL;
6011 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6013 unsigned short function;
6015 function = smb_GetSMBParm(inp, 18);
6017 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
6019 /* We can handle long names */
6020 if (vcp->flags & SMB_VCFLAG_USENT)
6021 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
6025 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
6027 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
6029 return smb_ReceiveNTTranCreate(vcp, inp, outp);
6031 return CM_ERROR_INVAL;
6036 * smb_NotifyChange -- find relevant change notification messages and
6039 * If we don't know the file name (i.e. a callback break), filename is
6040 * NULL, and we return a zero-length list.
6042 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
6043 cm_scache_t *dscp, char *filename, char *otherFilename,
6044 BOOL isDirectParent)
6046 smb_packet_t *watch, *lastWatch, *nextWatch;
6047 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
6048 char *outData, *oldOutData;
6052 BOOL twoEntries = FALSE;
6053 ULONG otherNameLen, oldParmCount = 0;
6058 /* Get ready for rename within directory */
6059 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
6061 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
6064 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
6065 osi_LogSaveString(smb_logp,filename),dscp);
6067 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6068 watch = smb_Directory_Watches;
6070 filter = smb_GetSMBParm(watch, 19)
6071 | (smb_GetSMBParm(watch, 20) << 16);
6072 fid = smb_GetSMBParm(watch, 21);
6073 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
6074 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
6075 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
6079 * Strange hack - bug in NT Client and NT Server that we
6082 if (filter == 3 && wtree)
6085 fidp = smb_FindFID(vcp, fid, 0);
6087 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
6089 watch = watch->nextp;
6092 if (fidp->scp != dscp
6093 || (filter & notifyFilter) == 0
6094 || (!isDirectParent && !wtree)) {
6095 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
6096 smb_ReleaseFID(fidp);
6098 watch = watch->nextp;
6101 smb_ReleaseFID(fidp);
6104 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
6105 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
6107 nextWatch = watch->nextp;
6108 if (watch == smb_Directory_Watches)
6109 smb_Directory_Watches = nextWatch;
6111 lastWatch->nextp = nextWatch;
6113 /* Turn off WATCHED flag in dscp */
6114 lock_ObtainMutex(&dscp->mx);
6116 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6118 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
6119 lock_ReleaseMutex(&dscp->mx);
6121 /* Convert to response packet */
6122 ((smb_t *) watch)->reb = 0x80;
6123 ((smb_t *) watch)->wct = 0;
6126 if (filename == NULL)
6129 nameLen = strlen(filename);
6130 parmCount = 3*4 + nameLen*2;
6131 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6133 otherNameLen = strlen(otherFilename);
6134 oldParmCount = parmCount;
6135 parmCount += 3*4 + otherNameLen*2;
6136 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6138 if (maxLen < parmCount)
6139 parmCount = 0; /* not enough room */
6141 parmOffset = 8*4 + 39;
6142 parmOffset += 1; /* pad to 4 */
6143 dataOffset = parmOffset + parmCount;
6147 /* Total Parameter Count */
6148 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6149 /* Total Data Count */
6150 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6151 /* Parameter Count */
6152 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6153 /* Parameter Offset */
6154 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
6155 /* Parameter Displacement */
6156 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6158 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6160 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
6161 /* Data Displacement */
6162 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6163 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
6164 smb_SetSMBDataLength(watch, parmCount + 1);
6166 if (parmCount != 0) {
6167 outData = smb_GetSMBData(watch, NULL);
6168 outData++; /* round to get to parmOffset */
6169 oldOutData = outData;
6170 *((DWORD *)outData) = oldParmCount; outData += 4;
6171 /* Next Entry Offset */
6172 *((DWORD *)outData) = action; outData += 4;
6174 *((DWORD *)outData) = nameLen*2; outData += 4;
6175 /* File Name Length */
6176 mbstowcs((WCHAR *)outData, filename, nameLen);
6179 outData = oldOutData + oldParmCount;
6180 *((DWORD *)outData) = 0; outData += 4;
6181 /* Next Entry Offset */
6182 *((DWORD *)outData) = otherAction; outData += 4;
6184 *((DWORD *)outData) = otherNameLen*2;
6185 outData += 4; /* File Name Length */
6186 mbstowcs((WCHAR *)outData, otherFilename,
6187 otherNameLen); /* File Name */
6192 * If filename is null, we don't know the cause of the
6193 * change notification. We return zero data (see above),
6194 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
6195 * (= 0x010C). We set the error code here by hand, without
6196 * modifying wct and bcc.
6198 if (filename == NULL) {
6199 ((smb_t *) watch)->rcls = 0x0C;
6200 ((smb_t *) watch)->reh = 0x01;
6201 ((smb_t *) watch)->errLow = 0;
6202 ((smb_t *) watch)->errHigh = 0;
6203 /* Set NT Status codes flag */
6204 ((smb_t *) watch)->flg2 |= 0x4000;
6207 smb_SendPacket(vcp, watch);
6209 smb_FreePacket(watch);
6212 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6215 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6217 unsigned char *replyWctp;
6218 smb_packet_t *watch, *lastWatch;
6219 USHORT fid, watchtree;
6223 osi_Log0(smb_logp, "SMB3 receive NT cancel");
6225 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6226 watch = smb_Directory_Watches;
6228 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
6229 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
6230 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
6231 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
6232 if (watch == smb_Directory_Watches)
6233 smb_Directory_Watches = watch->nextp;
6235 lastWatch->nextp = watch->nextp;
6236 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6238 /* Turn off WATCHED flag in scp */
6239 fid = smb_GetSMBParm(watch, 21);
6240 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
6242 if (vcp != watch->vcp)
6243 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
6246 fidp = smb_FindFID(vcp, fid, 0);
6248 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
6250 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
6253 lock_ObtainMutex(&scp->mx);
6255 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6257 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
6258 lock_ReleaseMutex(&scp->mx);
6259 smb_ReleaseFID(fidp);
6261 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
6264 /* assume STATUS32; return 0xC0000120 (CANCELED) */
6265 replyWctp = watch->wctp;
6269 ((smb_t *)watch)->rcls = 0x20;
6270 ((smb_t *)watch)->reh = 0x1;
6271 ((smb_t *)watch)->errLow = 0;
6272 ((smb_t *)watch)->errHigh = 0xC0;
6273 ((smb_t *)watch)->flg2 |= 0x4000;
6274 smb_SendPacket(vcp, watch);
6276 smb_ReleaseVC(watch->vcp);
6277 smb_FreePacket(watch);
6281 watch = watch->nextp;
6283 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6289 * NT rename also does hard links.
6292 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
6293 #define RENAME_FLAG_HARD_LINK 0x103
6294 #define RENAME_FLAG_RENAME 0x104
6295 #define RENAME_FLAG_COPY 0x105
6297 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6299 char *oldname, *newname;
6306 attrs = smb_GetSMBParm(inp, 0);
6307 rename_type = smb_GetSMBParm(inp, 1);
6309 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
6310 osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
6311 return CM_ERROR_NOACCESS;
6314 tp = smb_GetSMBData(inp, NULL);
6315 oldname = smb_ParseASCIIBlock(tp, &tp);
6316 newname = smb_ParseASCIIBlock(tp, &tp);
6318 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
6319 osi_LogSaveString(smb_logp, oldname),
6320 osi_LogSaveString(smb_logp, newname),
6321 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
6323 if (rename_type == RENAME_FLAG_RENAME) {
6324 code = smb_Rename(vcp,inp,oldname,newname,attrs);
6325 } else { /* RENAME_FLAG_HARD_LINK */
6326 code = smb_Link(vcp,inp,oldname,newname);
6333 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
6336 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
6339 smb_username_t *unp;
6341 unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
6343 lock_ObtainMutex(&unp->mx);
6344 unp->userp = cm_NewUser();
6345 lock_ReleaseMutex(&unp->mx);
6346 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6347 osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
6349 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6350 osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);