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);
138 for (i=0;i<len;i++) {
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( NULL,
185 SMB_EXT_SEC_PACKAGE_NAME,
194 if (status != SEC_E_OK) {
195 /* Really bad. We return an empty security blob */
196 OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
201 secOut.pBuffers = &secTok;
202 secOut.ulVersion = SECBUFFER_VERSION;
204 secTok.BufferType = SECBUFFER_TOKEN;
206 secTok.pvBuffer = NULL;
208 ctx.dwLower = ctx.dwUpper = 0;
210 status = AcceptSecurityContext( &creds,
213 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
214 SECURITY_NETWORK_DREP,
221 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
222 OutputDebugF("Completing token...");
223 istatus = CompleteAuthToken(&ctx, &secOut);
224 if ( istatus != SEC_E_OK )
225 OutputDebugF("Token completion failed: %x", istatus);
228 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
229 if (secTok.pvBuffer) {
230 *secBlobLength = secTok.cbBuffer;
231 *secBlob = malloc( secTok.cbBuffer );
232 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
235 if ( status != SEC_E_OK )
236 OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
239 /* Discard partial security context */
240 DeleteSecurityContext(&ctx);
242 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
244 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
245 FreeCredentialsHandle(&creds);
251 struct smb_ext_context {
258 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
259 SECURITY_STATUS status, istatus;
263 SecBufferDesc secBufIn;
265 SecBufferDesc secBufOut;
268 struct smb_ext_context * secCtx = NULL;
269 struct smb_ext_context * newSecCtx = NULL;
270 void * assembledBlob = NULL;
271 int assembledBlobLength = 0;
274 OutputDebugF("In smb_AuthenticateUserExt");
277 *secBlobOutLength = 0;
279 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
280 secCtx = vcp->secCtx;
281 lock_ObtainMutex(&vcp->mx);
282 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
284 lock_ReleaseMutex(&vcp->mx);
288 OutputDebugF("Received incoming token:");
289 OutputDebugHexDump(secBlobIn,secBlobInLength);
293 OutputDebugF("Continuing with existing context.");
294 creds = secCtx->creds;
297 if (secCtx->partialToken) {
298 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
299 assembledBlob = malloc(assembledBlobLength);
300 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
301 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
304 status = AcquireCredentialsHandle( NULL,
305 SMB_EXT_SEC_PACKAGE_NAME,
314 if (status != SEC_E_OK) {
315 OutputDebugF("Can't acquire Credentials handle [%lX]", status);
316 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
324 secBufIn.cBuffers = 1;
325 secBufIn.pBuffers = &secTokIn;
326 secBufIn.ulVersion = SECBUFFER_VERSION;
328 secTokIn.BufferType = SECBUFFER_TOKEN;
330 secTokIn.cbBuffer = assembledBlobLength;
331 secTokIn.pvBuffer = assembledBlob;
333 secTokIn.cbBuffer = secBlobInLength;
334 secTokIn.pvBuffer = secBlobIn;
337 secBufOut.cBuffers = 1;
338 secBufOut.pBuffers = &secTokOut;
339 secBufOut.ulVersion = SECBUFFER_VERSION;
341 secTokOut.BufferType = SECBUFFER_TOKEN;
342 secTokOut.cbBuffer = 0;
343 secTokOut.pvBuffer = NULL;
345 status = AcceptSecurityContext( &creds,
346 ((secCtx)?&ctx:NULL),
348 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
349 SECURITY_NETWORK_DREP,
356 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
357 OutputDebugF("Completing token...");
358 istatus = CompleteAuthToken(&ctx, &secBufOut);
359 if ( istatus != SEC_E_OK )
360 OutputDebugF("Token completion failed: %lX", istatus);
363 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
364 OutputDebugF("Continue needed");
366 newSecCtx = malloc(sizeof(*newSecCtx));
368 newSecCtx->creds = creds;
369 newSecCtx->ctx = ctx;
370 newSecCtx->partialToken = NULL;
371 newSecCtx->partialTokenLen = 0;
373 lock_ObtainMutex( &vcp->mx );
374 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
375 vcp->secCtx = newSecCtx;
376 lock_ReleaseMutex( &vcp->mx );
378 code = CM_ERROR_GSSCONTINUE;
381 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
382 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
383 secTokOut.pvBuffer) {
384 OutputDebugF("Need to send token back to client");
386 *secBlobOutLength = secTokOut.cbBuffer;
387 *secBlobOut = malloc(secTokOut.cbBuffer);
388 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
390 OutputDebugF("Outgoing token:");
391 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
392 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
393 OutputDebugF("Incomplete message");
395 newSecCtx = malloc(sizeof(*newSecCtx));
397 newSecCtx->creds = creds;
398 newSecCtx->ctx = ctx;
399 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
400 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
401 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
403 lock_ObtainMutex( &vcp->mx );
404 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
405 vcp->secCtx = newSecCtx;
406 lock_ReleaseMutex( &vcp->mx );
408 code = CM_ERROR_GSSCONTINUE;
411 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
413 SecPkgContext_Names names;
415 OutputDebugF("Authentication completed");
416 OutputDebugF("Returned flags : [%lX]", flags);
418 if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
419 OutputDebugF("Received name [%s]", names.sUserName);
420 strcpy(usern, names.sUserName);
421 strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
422 FreeContextBuffer(names.sUserName);
424 /* Force the user to retry if the context is invalid */
425 OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
426 code = CM_ERROR_BADPASSWORD;
430 case SEC_E_INVALID_TOKEN:
431 OutputDebugF("Returning bad password :: INVALID_TOKEN");
433 case SEC_E_INVALID_HANDLE:
434 OutputDebugF("Returning bad password :: INVALID_HANDLE");
436 case SEC_E_LOGON_DENIED:
437 OutputDebugF("Returning bad password :: LOGON_DENIED");
439 case SEC_E_UNKNOWN_CREDENTIALS:
440 OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
442 case SEC_E_NO_CREDENTIALS:
443 OutputDebugF("Returning bad password :: NO_CREDENTIALS");
445 case SEC_E_CONTEXT_EXPIRED:
446 OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
448 case SEC_E_INCOMPLETE_CREDENTIALS:
449 OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
451 case SEC_E_WRONG_PRINCIPAL:
452 OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
454 case SEC_E_TIME_SKEW:
455 OutputDebugF("Returning bad password :: TIME_SKEW");
458 OutputDebugF("Returning bad password :: Status == %lX", status);
460 code = CM_ERROR_BADPASSWORD;
464 if (secCtx->partialToken) free(secCtx->partialToken);
472 if (secTokOut.pvBuffer)
473 FreeContextBuffer(secTokOut.pvBuffer);
475 if (code != CM_ERROR_GSSCONTINUE) {
476 DeleteSecurityContext(&ctx);
477 FreeCredentialsHandle(&creds);
485 #define P_RESP_LEN 128
487 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
488 So put stuff in a struct. */
489 struct Lm20AuthBlob {
490 MSV1_0_LM20_LOGON lmlogon;
491 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
492 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
493 WCHAR accountNameW[P_LEN];
494 WCHAR primaryDomainW[P_LEN];
495 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
496 TOKEN_GROUPS tgroups;
497 TOKEN_SOURCE tsource;
500 long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
503 struct Lm20AuthBlob lmAuth;
504 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
505 QUOTA_LIMITS quotaLimits;
507 ULONG lmprofilepSize;
511 OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
512 OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
514 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
515 OutputDebugF("ciPwdLength or csPwdLength is too long");
516 return CM_ERROR_BADPASSWORD;
519 memset(&lmAuth,0,sizeof(lmAuth));
521 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
523 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
524 mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
525 lmAuth.lmlogon.LogonDomainName.Length = wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR);
526 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
528 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
529 mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
530 lmAuth.lmlogon.UserName.Length = wcslen(lmAuth.accountNameW) * sizeof(WCHAR);
531 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
533 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
534 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
535 size = MAX_COMPUTERNAME_LENGTH + 1;
536 GetComputerNameW(lmAuth.workstationW, &size);
537 lmAuth.lmlogon.Workstation.Length = wcslen(lmAuth.workstationW) * sizeof(WCHAR);
539 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
541 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
542 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
543 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
544 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
546 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
547 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
548 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
549 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
551 lmAuth.lmlogon.ParameterControl = 0;
553 lmAuth.tgroups.GroupCount = 0;
554 lmAuth.tgroups.Groups[0].Sid = NULL;
555 lmAuth.tgroups.Groups[0].Attributes = 0;
557 lmAuth.tsource.SourceIdentifier.HighPart = 0;
558 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD) vcp;
559 strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
561 nts = LsaLogonUser( smb_lsaHandle,
576 OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
577 OutputDebugF("Extended status is 0x%lX", ntsEx);
579 if (nts == ERROR_SUCCESS) {
581 LsaFreeReturnBuffer(lmprofilep);
582 CloseHandle(lmToken);
586 if (nts == 0xC000015BL)
587 return CM_ERROR_BADLOGONTYPE;
588 else /* our catchall is a bad password though we could be more specific */
589 return CM_ERROR_BADPASSWORD;
593 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
594 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName)
599 /* check if we have sane input */
600 if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
603 /* we could get : [accountName][domainName]
609 atsign = strchr(accountName, '@');
611 if (atsign) /* [user@domain][] -> [user@domain][domain] */
616 /* if for some reason the client doesn't know what domain to use,
617 it will either return an empty string or a '?' */
618 if (!domain[0] || domain[0] == '?')
619 /* Empty domains and empty usernames are usually sent from tokenless contexts.
620 This way such logins will get an empty username (easy to check). I don't know
621 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
622 strcpy(usern,accountName);
624 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
625 strcpy(usern,domain);
628 strncat(usern,accountName,atsign - accountName);
630 strcat(usern,accountName);
638 /* When using SMB auth, all SMB sessions have to pass through here first to
639 * authenticate the user.
640 * Caveat: If not use the SMB auth the protocol does not require sending a
641 * session setup packet, which means that we can't rely on a UID in subsequent
642 * packets. Though in practice we get one anyway.
644 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
648 unsigned short newUid;
649 unsigned long caps = 0;
654 char usern[SMB_MAX_USERNAME_LENGTH];
655 char *secBlobOut = NULL;
656 int secBlobOutLength = 0;
658 /* Check for bad conns */
659 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
660 return CM_ERROR_REMOTECONN;
662 if (vcp->flags & SMB_VCFLAG_USENT) {
663 if (smb_authType == SMB_AUTH_EXTENDED) {
664 /* extended authentication */
668 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
669 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
672 secBlobInLength = smb_GetSMBParm(inp, 7);
673 secBlobIn = smb_GetSMBData(inp, NULL);
675 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
677 if (code == CM_ERROR_GSSCONTINUE) {
678 smb_SetSMBParm(outp, 2, 0);
679 smb_SetSMBParm(outp, 3, secBlobOutLength);
680 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
681 tp = smb_GetSMBData(outp, NULL);
682 if (secBlobOutLength) {
683 memcpy(tp, secBlobOut, secBlobOutLength);
685 tp += secBlobOutLength;
687 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
688 tp += smb_ServerOSLength;
689 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
690 tp += smb_ServerLanManagerLength;
691 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
692 tp += smb_ServerDomainNameLength;
695 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
697 unsigned ciPwdLength, csPwdLength;
703 /* TODO: parse for extended auth as well */
704 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
705 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
707 tp = smb_GetSMBData(inp, &datalen);
709 OutputDebugF("Session packet data size [%d]",datalen);
716 accountName = smb_ParseString(tp, &tp);
717 primaryDomain = smb_ParseString(tp, NULL);
719 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
720 /* shouldn't happen */
721 code = CM_ERROR_BADSMB;
722 goto after_read_packet;
725 /* capabilities are only valid for first session packet */
726 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
727 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
730 if (smb_authType == SMB_AUTH_NTLM) {
731 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
735 unsigned ciPwdLength;
740 ciPwdLength = smb_GetSMBParm(inp, 7);
741 tp = smb_GetSMBData(inp, NULL);
745 accountName = smb_ParseString(tp, &tp);
746 primaryDomain = smb_ParseString(tp, NULL);
748 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
749 /* shouldn't happen */
750 code = CM_ERROR_BADSMB;
751 goto after_read_packet;
754 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
757 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
758 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
763 /* note down that we received a session setup X and set the capabilities flag */
764 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
765 lock_ObtainMutex(&vcp->mx);
766 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
767 /* for the moment we can only deal with NTSTATUS */
768 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
769 vcp->flags |= SMB_VCFLAG_STATUS32;
771 lock_ReleaseMutex(&vcp->mx);
774 /* code would be non-zero if there was an authentication failure.
775 Ideally we would like to invalidate the uid for this session or break
776 early to avoid accidently stealing someone else's tokens. */
782 OutputDebugF("Received username=[%s]", usern);
784 /* On Windows 2000, this function appears to be called more often than
785 it is expected to be called. This resulted in multiple smb_user_t
786 records existing all for the same user session which results in all
787 of the users tokens disappearing.
789 To avoid this problem, we look for an existing smb_user_t record
790 based on the users name, and use that one if we find it.
793 uidp = smb_FindUserByNameThisSession(vcp, usern);
794 if (uidp) { /* already there, so don't create a new one */
797 newUid = (unsigned short)uidp->userID; /* For some reason these are different types!*/
798 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));
799 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
800 smb_ReleaseUID(uidp);
803 /* do a global search for the username/machine name pair */
804 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
806 /* Create a new UID and cm_user_t structure */
809 userp = cm_NewUser();
810 lock_ObtainMutex(&vcp->mx);
811 if (!vcp->uidCounter)
812 vcp->uidCounter++; /* handle unlikely wraparounds */
813 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
814 lock_ReleaseMutex(&vcp->mx);
816 /* Create a new smb_user_t structure and connect them up */
817 lock_ObtainMutex(&unp->mx);
819 lock_ReleaseMutex(&unp->mx);
821 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
822 lock_ObtainMutex(&uidp->mx);
824 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));
825 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
826 lock_ReleaseMutex(&uidp->mx);
827 smb_ReleaseUID(uidp);
830 /* Return UID to the client */
831 ((smb_t *)outp)->uid = newUid;
832 /* Also to the next chained message */
833 ((smb_t *)inp)->uid = newUid;
835 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
836 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
838 smb_SetSMBParm(outp, 2, 0);
840 if (vcp->flags & SMB_VCFLAG_USENT) {
841 if (smb_authType == SMB_AUTH_EXTENDED) {
842 smb_SetSMBParm(outp, 3, secBlobOutLength);
843 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
844 tp = smb_GetSMBData(outp, NULL);
845 if (secBlobOutLength) {
846 memcpy(tp, secBlobOut, secBlobOutLength);
848 tp += secBlobOutLength;
850 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
851 tp += smb_ServerOSLength;
852 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
853 tp += smb_ServerLanManagerLength;
854 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
855 tp += smb_ServerDomainNameLength;
857 smb_SetSMBDataLength(outp, 0);
860 if (smb_authType == SMB_AUTH_EXTENDED) {
861 smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
862 tp = smb_GetSMBData(outp, NULL);
863 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
864 tp += smb_ServerOSLength;
865 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
866 tp += smb_ServerLanManagerLength;
867 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
868 tp += smb_ServerDomainNameLength;
870 smb_SetSMBDataLength(outp, 0);
877 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
881 /* don't get tokens from this VC */
882 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
884 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
886 /* find the tree and free it */
887 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
888 /* TODO: smb_ReleaseUID() ? */
890 char *s1 = NULL, *s2 = NULL;
892 if (s2 == NULL) s2 = " ";
893 if (s1 == NULL) {s1 = s2; s2 = " ";}
895 osi_Log4(smb_logp, "SMB3 user logoffX uid %d name %s%s%s", uidp->userID,
896 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "), s1, s2);
898 lock_ObtainMutex(&uidp->mx);
899 uidp->flags |= SMB_USERFLAG_DELETE;
901 * it doesn't get deleted right away
902 * because the vcp points to it
904 lock_ReleaseMutex(&uidp->mx);
907 osi_Log0(smb_logp, "SMB3 user logoffX");
909 smb_SetSMBDataLength(outp, 0);
913 #define SMB_SUPPORT_SEARCH_BITS 0x0001
915 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
919 unsigned short newTid;
930 osi_Log0(smb_logp, "SMB3 receive tree connect");
932 /* parse input parameters */
933 tp = smb_GetSMBData(inp, NULL);
934 passwordp = smb_ParseString(tp, &tp);
935 pathp = smb_ParseString(tp, &tp);
936 servicep = smb_ParseString(tp, &tp);
938 tp = strrchr(pathp, '\\');
940 return CM_ERROR_BADSMB;
942 strcpy(shareName, tp+1);
944 osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
945 osi_LogSaveString(smb_logp, pathp),
946 osi_LogSaveString(smb_logp, shareName));
948 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
950 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
953 return CM_ERROR_NOIPC;
957 userp = smb_GetUser(vcp, inp);
959 lock_ObtainMutex(&vcp->mx);
960 newTid = vcp->tidCounter++;
961 lock_ReleaseMutex(&vcp->mx);
963 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
966 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
967 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
969 smb_ReleaseUID(uidp);
971 smb_ReleaseTID(tidp);
972 return CM_ERROR_BADSHARENAME;
975 if (vcp->flags & SMB_VCFLAG_USENT)
977 int policy = smb_FindShareCSCPolicy(shareName);
978 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS | (policy << 2));
981 smb_SetSMBParm(outp, 2, 0);
985 lock_ObtainMutex(&tidp->mx);
987 tidp->pathname = sharePath;
988 if(ipc) tidp->flags |= SMB_TIDFLAG_IPC;
989 lock_ReleaseMutex(&tidp->mx);
990 smb_ReleaseTID(tidp);
992 ((smb_t *)outp)->tid = newTid;
993 ((smb_t *)inp)->tid = newTid;
994 tp = smb_GetSMBData(outp, NULL);
999 smb_SetSMBDataLength(outp, 3);
1002 smb_SetSMBDataLength(outp, 4);
1005 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1009 /* must be called with global tran lock held */
1010 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1012 smb_tran2Packet_t *tp;
1015 smbp = (smb_t *) inp->data;
1016 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1017 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1023 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1024 int totalParms, int totalData)
1026 smb_tran2Packet_t *tp;
1029 smbp = (smb_t *) inp->data;
1030 tp = malloc(sizeof(*tp));
1031 memset(tp, 0, sizeof(*tp));
1034 tp->curData = tp->curParms = 0;
1035 tp->totalData = totalData;
1036 tp->totalParms = totalParms;
1037 tp->tid = smbp->tid;
1038 tp->mid = smbp->mid;
1039 tp->uid = smbp->uid;
1040 tp->pid = smbp->pid;
1041 tp->res[0] = smbp->res[0];
1042 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1043 if (totalParms != 0)
1044 tp->parmsp = malloc(totalParms);
1046 tp->datap = malloc(totalData);
1047 if (smbp->com == 0x25 || smbp->com == 0x26)
1050 tp->opcode = smb_GetSMBParm(inp, 14);
1053 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1057 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1058 smb_tran2Packet_t *inp, smb_packet_t *outp,
1059 int totalParms, int totalData)
1061 smb_tran2Packet_t *tp;
1062 unsigned short parmOffset;
1063 unsigned short dataOffset;
1064 unsigned short dataAlign;
1066 tp = malloc(sizeof(*tp));
1067 memset(tp, 0, sizeof(*tp));
1069 tp->curData = tp->curParms = 0;
1070 tp->totalData = totalData;
1071 tp->totalParms = totalParms;
1072 tp->oldTotalParms = totalParms;
1077 tp->res[0] = inp->res[0];
1078 tp->opcode = inp->opcode;
1082 * We calculate where the parameters and data will start.
1083 * This calculation must parallel the calculation in
1084 * smb_SendTran2Packet.
1087 parmOffset = 10*2 + 35;
1088 parmOffset++; /* round to even */
1089 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1091 dataOffset = parmOffset + totalParms;
1092 dataAlign = dataOffset & 2; /* quad-align */
1093 dataOffset += dataAlign;
1094 tp->datap = outp->data + dataOffset;
1099 /* free a tran2 packet; must be called with smb_globalLock held */
1100 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1102 if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
1103 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1112 /* called with a VC, an input packet to respond to, and an error code.
1113 * sends an error response.
1115 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1116 smb_packet_t *tp, long code)
1119 unsigned short errCode;
1120 unsigned char errClass;
1121 unsigned long NTStatus;
1123 if (vcp->flags & SMB_VCFLAG_STATUS32)
1124 smb_MapNTError(code, &NTStatus);
1126 smb_MapCoreError(code, vcp, &errCode, &errClass);
1128 smb_FormatResponsePacket(vcp, NULL, tp);
1129 smbp = (smb_t *) tp;
1131 /* We can handle long names */
1132 if (vcp->flags & SMB_VCFLAG_USENT)
1133 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
1135 /* now copy important fields from the tran 2 packet */
1136 smbp->com = t2p->com;
1137 smbp->tid = t2p->tid;
1138 smbp->mid = t2p->mid;
1139 smbp->pid = t2p->pid;
1140 smbp->uid = t2p->uid;
1141 smbp->res[0] = t2p->res[0];
1142 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1143 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1144 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1145 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1146 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1147 smbp->flg2 |= 0x4000;
1150 smbp->rcls = errClass;
1151 smbp->errLow = (unsigned char) (errCode & 0xff);
1152 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1156 smb_SendPacket(vcp, tp);
1159 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1162 unsigned short parmOffset;
1163 unsigned short dataOffset;
1164 unsigned short totalLength;
1165 unsigned short dataAlign;
1168 smb_FormatResponsePacket(vcp, NULL, tp);
1169 smbp = (smb_t *) tp;
1171 /* We can handle long names */
1172 if (vcp->flags & SMB_VCFLAG_USENT)
1173 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
1175 /* now copy important fields from the tran 2 packet */
1176 smbp->com = t2p->com;
1177 smbp->tid = t2p->tid;
1178 smbp->mid = t2p->mid;
1179 smbp->pid = t2p->pid;
1180 smbp->uid = t2p->uid;
1181 smbp->res[0] = t2p->res[0];
1183 totalLength = 1 + t2p->totalData + t2p->totalParms;
1185 /* now add the core parameters (tran2 info) to the packet */
1186 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1187 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1188 smb_SetSMBParm(tp, 2, 0); /* reserved */
1189 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1190 parmOffset = 10*2 + 35; /* parm offset in packet */
1191 parmOffset++; /* round to even */
1192 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1193 * hdr, bcc and wct */
1194 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1195 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1196 dataOffset = parmOffset + t2p->oldTotalParms;
1197 dataAlign = dataOffset & 2; /* quad-align */
1198 dataOffset += dataAlign;
1199 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1200 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1201 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1204 datap = smb_GetSMBData(tp, NULL);
1205 *datap++ = 0; /* we rounded to even */
1207 totalLength += dataAlign;
1208 smb_SetSMBDataLength(tp, totalLength);
1210 /* next, send the datagram */
1211 smb_SendPacket(vcp, tp);
1214 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1216 smb_tran2Packet_t *asp;
1229 /* We sometimes see 0 word count. What to do? */
1230 if (*inp->wctp == 0) {
1235 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1237 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1238 ptbuf[0] = "Transaction2 word count = 0";
1239 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1240 1, inp->ncb_length, ptbuf, inp);
1241 DeregisterEventSource(h);
1243 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1246 smb_SetSMBDataLength(outp, 0);
1247 smb_SendPacket(vcp, outp);
1251 totalParms = smb_GetSMBParm(inp, 0);
1252 totalData = smb_GetSMBParm(inp, 1);
1254 firstPacket = (inp->inCom == 0x25);
1256 /* find the packet we're reassembling */
1257 lock_ObtainWrite(&smb_globalLock);
1258 asp = smb_FindTran2Packet(vcp, inp);
1260 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1262 lock_ReleaseWrite(&smb_globalLock);
1264 /* now merge in this latest packet; start by looking up offsets */
1266 parmDisp = dataDisp = 0;
1267 parmOffset = smb_GetSMBParm(inp, 10);
1268 dataOffset = smb_GetSMBParm(inp, 12);
1269 parmCount = smb_GetSMBParm(inp, 9);
1270 dataCount = smb_GetSMBParm(inp, 11);
1271 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1272 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1274 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1275 totalData, dataCount, asp->maxReturnData);
1278 parmDisp = smb_GetSMBParm(inp, 4);
1279 parmOffset = smb_GetSMBParm(inp, 3);
1280 dataDisp = smb_GetSMBParm(inp, 7);
1281 dataOffset = smb_GetSMBParm(inp, 6);
1282 parmCount = smb_GetSMBParm(inp, 2);
1283 dataCount = smb_GetSMBParm(inp, 5);
1285 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1286 parmCount, dataCount);
1289 /* now copy the parms and data */
1290 if ( asp->totalParms > 0 && parmCount != 0 )
1292 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1294 if ( asp->totalData > 0 && dataCount != 0 ) {
1295 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1298 /* account for new bytes */
1299 asp->curData += dataCount;
1300 asp->curParms += parmCount;
1302 /* finally, if we're done, remove the packet from the queue and dispatch it */
1303 if (asp->totalParms > 0 &&
1304 asp->curParms > 0 &&
1305 asp->totalData <= asp->curData &&
1306 asp->totalParms <= asp->curParms) {
1307 /* we've received it all */
1308 lock_ObtainWrite(&smb_globalLock);
1309 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1310 lock_ReleaseWrite(&smb_globalLock);
1312 /* now dispatch it */
1313 rapOp = asp->parmsp[0];
1315 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1316 osi_LogEvent("AFS-Dispatch-RAP[%s]",myCrt_RapDispatch(rapOp),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1317 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%x] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1318 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1321 osi_LogEvent("AFS-Dispatch-RAP [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1322 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1323 code = CM_ERROR_BADOP;
1326 /* if an error is returned, we're supposed to send an error packet,
1327 * otherwise the dispatched function already did the data sending.
1328 * We give dispatched proc the responsibility since it knows how much
1329 * space to allocate.
1332 smb_SendTran2Error(vcp, asp, outp, code);
1335 /* free the input tran 2 packet */
1336 lock_ObtainWrite(&smb_globalLock);
1337 smb_FreeTran2Packet(asp);
1338 lock_ReleaseWrite(&smb_globalLock);
1340 else if (firstPacket) {
1341 /* the first packet in a multi-packet request, we need to send an
1342 * ack to get more data.
1344 smb_SetSMBDataLength(outp, 0);
1345 smb_SendPacket(vcp, outp);
1351 /* ANSI versions. The unicode versions support arbitrary length
1352 share names, but we don't support unicode yet. */
1354 typedef struct smb_rap_share_info_0 {
1355 char shi0_netname[13];
1356 } smb_rap_share_info_0_t;
1358 typedef struct smb_rap_share_info_1 {
1359 char shi1_netname[13];
1362 DWORD shi1_remark; /* char *shi1_remark; data offset */
1363 } smb_rap_share_info_1_t;
1365 typedef struct smb_rap_share_info_2 {
1366 char shi2_netname[13];
1368 unsigned short shi2_type;
1369 DWORD shi2_remark; /* char *shi2_remark; data offset */
1370 unsigned short shi2_permissions;
1371 unsigned short shi2_max_uses;
1372 unsigned short shi2_current_uses;
1373 DWORD shi2_path; /* char *shi2_path; data offset */
1374 unsigned short shi2_passwd[9];
1375 unsigned short shi2_pad2;
1376 } smb_rap_share_info_2_t;
1378 #define SMB_RAP_MAX_SHARES 512
1380 typedef struct smb_rap_share_list {
1383 smb_rap_share_info_0_t * shares;
1384 } smb_rap_share_list_t;
1386 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1387 smb_rap_share_list_t * sp;
1392 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1393 return 0; /* skip over '.' and '..' */
1395 sp = (smb_rap_share_list_t *) vrockp;
1397 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1398 sp->shares[sp->cShare].shi0_netname[12] = 0;
1402 if (sp->cShare >= sp->maxShares)
1403 return CM_ERROR_STOPNOW;
1408 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1410 smb_tran2Packet_t *outp;
1411 unsigned short * tp;
1415 int outParmsTotal; /* total parameter bytes */
1416 int outDataTotal; /* total data bytes */
1424 HKEY hkSubmount = NULL;
1425 smb_rap_share_info_1_t * shares;
1428 char thisShare[256];
1431 smb_rap_share_list_t rootShares;
1436 tp = p->parmsp + 1; /* skip over function number (always 0) */
1437 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1438 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1442 if (infoLevel != 1) {
1443 return CM_ERROR_INVAL;
1446 /* first figure out how many shares there are */
1447 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1448 KEY_QUERY_VALUE, &hkParam);
1449 if (rv == ERROR_SUCCESS) {
1450 len = sizeof(allSubmount);
1451 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1452 (BYTE *) &allSubmount, &len);
1453 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1456 RegCloseKey (hkParam);
1459 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1460 0, KEY_QUERY_VALUE, &hkSubmount);
1461 if (rv == ERROR_SUCCESS) {
1462 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1463 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1464 if (rv != ERROR_SUCCESS)
1470 /* fetch the root shares */
1471 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1472 rootShares.cShare = 0;
1473 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1477 userp = smb_GetTran2User(vcp,p);
1479 thyper.HighPart = 0;
1482 cm_HoldSCache(cm_rootSCachep);
1483 cm_ApplyDir(cm_rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1484 cm_ReleaseSCache(cm_rootSCachep);
1486 cm_ReleaseUser(userp);
1488 nShares = rootShares.cShare + nRegShares + allSubmount;
1490 #define REMARK_LEN 1
1491 outParmsTotal = 8; /* 4 dwords */
1492 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1493 if(outDataTotal > bufsize) {
1494 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1495 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1498 nSharesRet = nShares;
1501 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1503 /* now for the submounts */
1504 shares = (smb_rap_share_info_1_t *) outp->datap;
1505 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1507 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1510 strcpy( shares[cshare].shi1_netname, "all" );
1511 shares[cshare].shi1_remark = cstrp - outp->datap;
1512 /* type and pad are zero already */
1518 for (i=0; i < nRegShares && cshare < nSharesRet; i++) {
1519 len = sizeof(thisShare);
1520 rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1521 if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1522 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1523 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1524 shares[cshare].shi1_remark = cstrp - outp->datap;
1529 nShares--; /* uncount key */
1532 RegCloseKey(hkSubmount);
1535 nonrootShares = cshare;
1537 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1538 /* in case there are collisions with submounts, submounts have higher priority */
1539 for (j=0; j < nonrootShares; j++)
1540 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1543 if (j < nonrootShares) {
1544 nShares--; /* uncount */
1548 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1549 shares[cshare].shi1_remark = cstrp - outp->datap;
1554 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1555 outp->parmsp[1] = 0;
1556 outp->parmsp[2] = cshare;
1557 outp->parmsp[3] = nShares;
1559 outp->totalData = cstrp - outp->datap;
1560 outp->totalParms = outParmsTotal;
1562 smb_SendTran2Packet(vcp, outp, op);
1563 smb_FreeTran2Packet(outp);
1565 free(rootShares.shares);
1570 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1572 smb_tran2Packet_t *outp;
1573 unsigned short * tp;
1575 BOOL shareFound = FALSE;
1576 unsigned short infoLevel;
1577 unsigned short bufsize;
1587 tp = p->parmsp + 1; /* skip over function number (always 1) */
1588 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1589 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1590 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1597 totalData = sizeof(smb_rap_share_info_0_t);
1598 else if(infoLevel == 1)
1599 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1600 else if(infoLevel == 2)
1601 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1603 return CM_ERROR_INVAL;
1605 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1607 if(!stricmp(shareName,"all")) {
1608 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1609 KEY_QUERY_VALUE, &hkParam);
1610 if (rv == ERROR_SUCCESS) {
1611 len = sizeof(allSubmount);
1612 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1613 (BYTE *) &allSubmount, &len);
1614 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1617 RegCloseKey (hkParam);
1624 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts", 0,
1625 KEY_QUERY_VALUE, &hkSubmount);
1626 if (rv == ERROR_SUCCESS) {
1627 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1628 if (rv == ERROR_SUCCESS) {
1631 RegCloseKey(hkSubmount);
1636 smb_FreeTran2Packet(outp);
1637 return CM_ERROR_BADSHARENAME;
1640 memset(outp->datap, 0, totalData);
1642 outp->parmsp[0] = 0;
1643 outp->parmsp[1] = 0;
1644 outp->parmsp[2] = totalData;
1646 if (infoLevel == 0) {
1647 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1648 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1649 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1650 } else if(infoLevel == 1) {
1651 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1652 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1653 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1654 info->shi1_remark = ((unsigned char *) (info + 1)) - outp->datap;
1655 /* type and pad are already zero */
1656 } else { /* infoLevel==2 */
1657 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1658 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1659 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1660 info->shi2_remark = ((unsigned char *) (info + 1)) - outp->datap;
1661 info->shi2_permissions = ACCESS_ALL;
1662 info->shi2_max_uses = (unsigned short) -1;
1663 info->shi2_path = 1 + (((unsigned char *) (info + 1)) - outp->datap);
1666 outp->totalData = totalData;
1667 outp->totalParms = totalParam;
1669 smb_SendTran2Packet(vcp, outp, op);
1670 smb_FreeTran2Packet(outp);
1675 typedef struct smb_rap_wksta_info_10 {
1676 DWORD wki10_computername; /*char *wki10_computername;*/
1677 DWORD wki10_username; /* char *wki10_username; */
1678 DWORD wki10_langroup; /* char *wki10_langroup;*/
1679 unsigned char wki10_ver_major;
1680 unsigned char wki10_ver_minor;
1681 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1682 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1683 } smb_rap_wksta_info_10_t;
1686 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1688 smb_tran2Packet_t *outp;
1692 unsigned short * tp;
1695 smb_rap_wksta_info_10_t * info;
1699 tp = p->parmsp + 1; /* Skip over function number */
1700 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1701 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1705 if (infoLevel != 10) {
1706 return CM_ERROR_INVAL;
1712 totalData = sizeof(*info) + /* info */
1713 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1714 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1715 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1716 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1717 1; /* wki10_oth_domains (null)*/
1719 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1721 memset(outp->parmsp,0,totalParams);
1722 memset(outp->datap,0,totalData);
1724 info = (smb_rap_wksta_info_10_t *) outp->datap;
1725 cstrp = (char *) (info + 1);
1727 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1728 strcpy(cstrp, smb_localNamep);
1729 cstrp += strlen(cstrp) + 1;
1731 info->wki10_username = (DWORD) (cstrp - outp->datap);
1732 uidp = smb_FindUID(vcp, p->uid, 0);
1734 lock_ObtainMutex(&uidp->mx);
1735 if(uidp->unp && uidp->unp->name)
1736 strcpy(cstrp, uidp->unp->name);
1737 lock_ReleaseMutex(&uidp->mx);
1738 smb_ReleaseUID(uidp);
1740 cstrp += strlen(cstrp) + 1;
1742 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1743 strcpy(cstrp, "WORKGROUP");
1744 cstrp += strlen(cstrp) + 1;
1746 /* TODO: Not sure what values these should take, but these work */
1747 info->wki10_ver_major = 5;
1748 info->wki10_ver_minor = 1;
1750 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1751 strcpy(cstrp, smb_ServerDomainName);
1752 cstrp += strlen(cstrp) + 1;
1754 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1755 cstrp ++; /* no other domains */
1757 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1758 outp->parmsp[2] = outp->totalData;
1759 outp->totalParms = totalParams;
1761 smb_SendTran2Packet(vcp,outp,op);
1762 smb_FreeTran2Packet(outp);
1767 typedef struct smb_rap_server_info_0 {
1769 } smb_rap_server_info_0_t;
1771 typedef struct smb_rap_server_info_1 {
1773 char sv1_version_major;
1774 char sv1_version_minor;
1775 unsigned long sv1_type;
1776 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1777 } smb_rap_server_info_1_t;
1779 char smb_ServerComment[] = "OpenAFS Client";
1780 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1782 #define SMB_SV_TYPE_SERVER 0x00000002L
1783 #define SMB_SV_TYPE_NT 0x00001000L
1784 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1786 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1788 smb_tran2Packet_t *outp;
1792 unsigned short * tp;
1795 smb_rap_server_info_0_t * info0;
1796 smb_rap_server_info_1_t * info1;
1799 tp = p->parmsp + 1; /* Skip over function number */
1800 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1801 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1805 if (infoLevel != 0 && infoLevel != 1) {
1806 return CM_ERROR_INVAL;
1812 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1813 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1815 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1817 memset(outp->parmsp,0,totalParams);
1818 memset(outp->datap,0,totalData);
1820 if (infoLevel == 0) {
1821 info0 = (smb_rap_server_info_0_t *) outp->datap;
1822 cstrp = (char *) (info0 + 1);
1823 strcpy(info0->sv0_name, "AFS");
1824 } else { /* infoLevel == 1 */
1825 info1 = (smb_rap_server_info_1_t *) outp->datap;
1826 cstrp = (char *) (info1 + 1);
1827 strcpy(info1->sv1_name, "AFS");
1830 SMB_SV_TYPE_SERVER |
1832 SMB_SV_TYPE_SERVER_NT;
1834 info1->sv1_version_major = 5;
1835 info1->sv1_version_minor = 1;
1836 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1838 strcpy(cstrp, smb_ServerComment);
1840 cstrp += smb_ServerCommentLen;
1843 totalData = cstrp - outp->datap;
1844 outp->totalData = min(bufsize,totalData); /* actual data size */
1845 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1846 outp->parmsp[2] = totalData;
1847 outp->totalParms = totalParams;
1849 smb_SendTran2Packet(vcp,outp,op);
1850 smb_FreeTran2Packet(outp);
1855 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1857 smb_tran2Packet_t *asp;
1869 /* We sometimes see 0 word count. What to do? */
1870 if (*inp->wctp == 0) {
1875 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1877 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1878 ptbuf[0] = "Transaction2 word count = 0";
1879 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1880 1, inp->ncb_length, ptbuf, inp);
1881 DeregisterEventSource(h);
1883 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1886 smb_SetSMBDataLength(outp, 0);
1887 smb_SendPacket(vcp, outp);
1891 totalParms = smb_GetSMBParm(inp, 0);
1892 totalData = smb_GetSMBParm(inp, 1);
1894 firstPacket = (inp->inCom == 0x32);
1896 /* find the packet we're reassembling */
1897 lock_ObtainWrite(&smb_globalLock);
1898 asp = smb_FindTran2Packet(vcp, inp);
1900 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1902 lock_ReleaseWrite(&smb_globalLock);
1904 /* now merge in this latest packet; start by looking up offsets */
1906 parmDisp = dataDisp = 0;
1907 parmOffset = smb_GetSMBParm(inp, 10);
1908 dataOffset = smb_GetSMBParm(inp, 12);
1909 parmCount = smb_GetSMBParm(inp, 9);
1910 dataCount = smb_GetSMBParm(inp, 11);
1911 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1912 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1914 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1915 totalData, dataCount, asp->maxReturnData);
1918 parmDisp = smb_GetSMBParm(inp, 4);
1919 parmOffset = smb_GetSMBParm(inp, 3);
1920 dataDisp = smb_GetSMBParm(inp, 7);
1921 dataOffset = smb_GetSMBParm(inp, 6);
1922 parmCount = smb_GetSMBParm(inp, 2);
1923 dataCount = smb_GetSMBParm(inp, 5);
1925 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1926 parmCount, dataCount);
1929 /* now copy the parms and data */
1930 if ( asp->totalParms > 0 && parmCount != 0 )
1932 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1934 if ( asp->totalData > 0 && dataCount != 0 ) {
1935 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1938 /* account for new bytes */
1939 asp->curData += dataCount;
1940 asp->curParms += parmCount;
1942 /* finally, if we're done, remove the packet from the queue and dispatch it */
1943 if (asp->totalParms > 0 &&
1944 asp->curParms > 0 &&
1945 asp->totalData <= asp->curData &&
1946 asp->totalParms <= asp->curParms) {
1947 /* we've received it all */
1948 lock_ObtainWrite(&smb_globalLock);
1949 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1950 lock_ReleaseWrite(&smb_globalLock);
1952 /* now dispatch it */
1953 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
1954 osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1955 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
1956 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
1959 osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1960 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1961 code = CM_ERROR_BADOP;
1964 /* if an error is returned, we're supposed to send an error packet,
1965 * otherwise the dispatched function already did the data sending.
1966 * We give dispatched proc the responsibility since it knows how much
1967 * space to allocate.
1970 smb_SendTran2Error(vcp, asp, outp, code);
1973 /* free the input tran 2 packet */
1974 lock_ObtainWrite(&smb_globalLock);
1975 smb_FreeTran2Packet(asp);
1976 lock_ReleaseWrite(&smb_globalLock);
1978 else if (firstPacket) {
1979 /* the first packet in a multi-packet request, we need to send an
1980 * ack to get more data.
1982 smb_SetSMBDataLength(outp, 0);
1983 smb_SendPacket(vcp, outp);
1989 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1992 smb_tran2Packet_t *outp;
1997 cm_scache_t *dscp; /* dir we're dealing with */
1998 cm_scache_t *scp; /* file we're creating */
2000 int initialModeBits;
2010 int parmSlot; /* which parm we're dealing with */
2011 long returnEALength;
2019 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2020 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2022 openFun = p->parmsp[6]; /* open function */
2023 excl = ((openFun & 3) == 0);
2024 trunc = ((openFun & 3) == 2); /* truncate it */
2025 openMode = (p->parmsp[1] & 0x7);
2026 openAction = 0; /* tracks what we did */
2028 attributes = p->parmsp[3];
2029 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2031 /* compute initial mode bits based on read-only flag in attributes */
2032 initialModeBits = 0666;
2033 if (attributes & 1) initialModeBits &= ~0222;
2035 pathp = (char *) (&p->parmsp[14]);
2037 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2039 spacep = cm_GetSpace();
2040 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2042 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2043 /* special case magic file name for receiving IOCTL requests
2044 * (since IOCTL calls themselves aren't getting through).
2046 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2047 smb_SetupIoctlFid(fidp, spacep);
2049 /* copy out remainder of the parms */
2051 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2053 outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
2054 outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
2055 outp->parmsp[parmSlot] = 0; parmSlot++;
2056 outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
2057 outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
2058 outp->parmsp[parmSlot] = openMode; parmSlot++;
2059 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2060 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2062 /* and the final "always present" stuff */
2063 outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
2064 /* next write out the "unique" ID */
2065 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
2066 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
2067 outp->parmsp[parmSlot] = 0; parmSlot++;
2068 if (returnEALength) {
2069 outp->parmsp[parmSlot] = 0; parmSlot++;
2070 outp->parmsp[parmSlot] = 0; parmSlot++;
2073 outp->totalData = 0;
2074 outp->totalParms = parmSlot * 2;
2076 smb_SendTran2Packet(vcp, outp, op);
2078 smb_FreeTran2Packet(outp);
2080 /* and clean up fid reference */
2081 smb_ReleaseFID(fidp);
2085 #ifdef DEBUG_VERBOSE
2087 char *hexp, *asciip;
2088 asciip = (lastNamep ? lastNamep : pathp);
2089 hexp = osi_HexifyString( asciip );
2090 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2095 userp = smb_GetTran2User(vcp, p);
2096 /* In the off chance that userp is NULL, we log and abandon */
2098 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2099 smb_FreeTran2Packet(outp);
2100 return CM_ERROR_BADSMB;
2103 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2104 if (code == CM_ERROR_TIDIPC) {
2105 /* Attempt to use TID allocated for IPC. The client is
2106 probably trying to locate DCE RPC end points, which
2107 we don't support. */
2108 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2109 cm_ReleaseUser(userp);
2110 smb_FreeTran2Packet(outp);
2111 return CM_ERROR_NOSUCHPATH;
2115 code = cm_NameI(cm_rootSCachep, pathp,
2116 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2117 userp, tidPathp, &req, &scp);
2119 code = cm_NameI(cm_rootSCachep, spacep->data,
2120 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2121 userp, tidPathp, &req, &dscp);
2122 cm_FreeSpace(spacep);
2125 cm_ReleaseUser(userp);
2126 smb_FreeTran2Packet(outp);
2130 /* otherwise, scp points to the parent directory. Do a lookup,
2131 * and truncate the file if we find it, otherwise we create the
2138 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2140 if (code && code != CM_ERROR_NOSUCHFILE) {
2141 cm_ReleaseSCache(dscp);
2142 cm_ReleaseUser(userp);
2143 smb_FreeTran2Packet(outp);
2148 cm_FreeSpace(spacep);
2151 /* if we get here, if code is 0, the file exists and is represented by
2152 * scp. Otherwise, we have to create it.
2155 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2157 if (dscp) cm_ReleaseSCache(dscp);
2158 cm_ReleaseSCache(scp);
2159 cm_ReleaseUser(userp);
2160 smb_FreeTran2Packet(outp);
2165 /* oops, file shouldn't be there */
2166 if (dscp) cm_ReleaseSCache(dscp);
2167 cm_ReleaseSCache(scp);
2168 cm_ReleaseUser(userp);
2169 smb_FreeTran2Packet(outp);
2170 return CM_ERROR_EXISTS;
2174 setAttr.mask = CM_ATTRMASK_LENGTH;
2175 setAttr.length.LowPart = 0;
2176 setAttr.length.HighPart = 0;
2177 code = cm_SetAttr(scp, &setAttr, userp, &req);
2178 openAction = 3; /* truncated existing file */
2181 openAction = 1; /* found existing file */
2183 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
2184 /* don't create if not found */
2185 if (dscp) cm_ReleaseSCache(dscp);
2186 osi_assert(scp == NULL);
2187 cm_ReleaseUser(userp);
2188 smb_FreeTran2Packet(outp);
2189 return CM_ERROR_NOSUCHFILE;
2192 osi_assert(dscp != NULL && scp == NULL);
2193 openAction = 2; /* created file */
2194 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2195 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2196 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2198 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2199 smb_NotifyChange(FILE_ACTION_ADDED,
2200 FILE_NOTIFY_CHANGE_FILE_NAME,
2201 dscp, lastNamep, NULL, TRUE);
2202 if (!excl && code == CM_ERROR_EXISTS) {
2203 /* not an exclusive create, and someone else tried
2204 * creating it already, then we open it anyway. We
2205 * don't bother retrying after this, since if this next
2206 * fails, that means that the file was deleted after we
2207 * started this call.
2209 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2213 setAttr.mask = CM_ATTRMASK_LENGTH;
2214 setAttr.length.LowPart = 0;
2215 setAttr.length.HighPart = 0;
2216 code = cm_SetAttr(scp, &setAttr, userp,
2219 } /* lookup succeeded */
2223 /* we don't need this any longer */
2224 if (dscp) cm_ReleaseSCache(dscp);
2227 /* something went wrong creating or truncating the file */
2228 if (scp) cm_ReleaseSCache(scp);
2229 cm_ReleaseUser(userp);
2230 smb_FreeTran2Packet(outp);
2234 /* make sure we're about to open a file */
2235 if (scp->fileType != CM_SCACHETYPE_FILE) {
2237 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2238 cm_scache_t * targetScp = 0;
2239 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2241 /* we have a more accurate file to use (the
2242 * target of the symbolic link). Otherwise,
2243 * we'll just use the symlink anyway.
2245 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2247 cm_ReleaseSCache(scp);
2251 if (scp->fileType != CM_SCACHETYPE_FILE) {
2252 cm_ReleaseSCache(scp);
2253 cm_ReleaseUser(userp);
2254 smb_FreeTran2Packet(outp);
2255 return CM_ERROR_ISDIR;
2259 /* now all we have to do is open the file itself */
2260 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2263 /* save a pointer to the vnode */
2266 /* compute open mode */
2267 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2268 if (openMode == 1 || openMode == 2)
2269 fidp->flags |= SMB_FID_OPENWRITE;
2271 smb_ReleaseFID(fidp);
2273 cm_Open(scp, 0, userp);
2275 /* copy out remainder of the parms */
2277 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2278 lock_ObtainMutex(&scp->mx);
2280 outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
2281 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2282 outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
2283 outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
2284 outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
2286 outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2288 outp->parmsp[parmSlot] = openMode; parmSlot++;
2289 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2290 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2292 /* and the final "always present" stuff */
2293 outp->parmsp[parmSlot] = openAction; parmSlot++;
2294 /* next write out the "unique" ID */
2295 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
2296 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
2297 outp->parmsp[parmSlot] = 0; parmSlot++;
2298 if (returnEALength) {
2299 outp->parmsp[parmSlot] = 0; parmSlot++;
2300 outp->parmsp[parmSlot] = 0; parmSlot++;
2302 lock_ReleaseMutex(&scp->mx);
2303 outp->totalData = 0; /* total # of data bytes */
2304 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2306 smb_SendTran2Packet(vcp, outp, op);
2308 smb_FreeTran2Packet(outp);
2310 cm_ReleaseUser(userp);
2311 /* leave scp held since we put it in fidp->scp */
2315 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2317 osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2318 return CM_ERROR_BADOP;
2321 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2323 osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2324 return CM_ERROR_BADOP;
2327 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2329 smb_tran2Packet_t *outp;
2330 smb_tran2QFSInfo_t qi;
2333 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
2335 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2337 switch (p->parmsp[0]) {
2338 case 1: responseSize = sizeof(qi.u.allocInfo); break;
2339 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
2340 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
2341 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
2342 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
2343 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
2344 default: return CM_ERROR_INVAL;
2347 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2348 switch (p->parmsp[0]) {
2351 qi.u.allocInfo.FSID = 0;
2352 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2353 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2354 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2355 qi.u.allocInfo.bytesPerSector = 1024;
2360 qi.u.volumeInfo.vsn = 1234;
2361 qi.u.volumeInfo.vnCount = 4;
2362 /* we're supposed to pad it out with zeroes to the end */
2363 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2364 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2368 /* FS volume info */
2369 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
2370 qi.u.FSvolumeInfo.vsn = 1234;
2371 qi.u.FSvolumeInfo.vnCount = 8;
2372 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
2378 temp.LowPart = 0x7fffffff;
2379 qi.u.FSsizeInfo.totalAllocUnits = temp;
2380 temp.LowPart = 0x3fffffff;
2381 qi.u.FSsizeInfo.availAllocUnits = temp;
2382 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2383 qi.u.FSsizeInfo.bytesPerSector = 1024;
2387 /* FS device info */
2388 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
2389 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2393 /* FS attribute info */
2394 /* attributes, defined in WINNT.H:
2395 * FILE_CASE_SENSITIVE_SEARCH 0x1
2396 * FILE_CASE_PRESERVED_NAMES 0x2
2397 * <no name defined> 0x4000
2398 * If bit 0x4000 is not set, Windows 95 thinks
2399 * we can't handle long (non-8.3) names,
2400 * despite our protestations to the contrary.
2402 qi.u.FSattributeInfo.attributes = 0x4003;
2403 qi.u.FSattributeInfo.maxCompLength = 255;
2404 qi.u.FSattributeInfo.FSnameLength = 6;
2405 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
2409 /* copy out return data, and set corresponding sizes */
2410 outp->totalParms = 0;
2411 outp->totalData = responseSize;
2412 memcpy(outp->datap, &qi, responseSize);
2414 /* send and free the packets */
2415 smb_SendTran2Packet(vcp, outp, op);
2416 smb_FreeTran2Packet(outp);
2421 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2423 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2424 return CM_ERROR_BADOP;
2427 struct smb_ShortNameRock {
2431 size_t shortNameLen;
2434 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2437 struct smb_ShortNameRock *rockp;
2441 /* compare both names and vnodes, though probably just comparing vnodes
2442 * would be safe enough.
2444 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2446 if (ntohl(dep->fid.vnode) != rockp->vnode)
2448 /* This is the entry */
2449 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2450 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2451 return CM_ERROR_STOPNOW;
2454 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2455 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2457 struct smb_ShortNameRock rock;
2461 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2465 spacep = cm_GetSpace();
2466 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2468 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
2470 cm_FreeSpace(spacep);
2471 if (code) return code;
2473 if (!lastNamep) lastNamep = pathp;
2476 thyper.HighPart = 0;
2477 rock.shortName = shortName;
2479 rock.maskp = lastNamep;
2480 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
2483 cm_ReleaseSCache(dscp);
2486 return CM_ERROR_NOSUCHFILE;
2487 if (code == CM_ERROR_STOPNOW) {
2488 *shortNameLenp = rock.shortNameLen;
2494 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2496 smb_tran2Packet_t *outp;
2499 unsigned short infoLevel;
2501 unsigned short attributes;
2502 unsigned long extAttributes;
2507 cm_scache_t *scp, *dscp;
2516 infoLevel = p->parmsp[0];
2517 if (infoLevel == 6) nbytesRequired = 0;
2518 else if (infoLevel == 1) nbytesRequired = 22;
2519 else if (infoLevel == 2) nbytesRequired = 26;
2520 else if (infoLevel == 0x101) nbytesRequired = 40;
2521 else if (infoLevel == 0x102) nbytesRequired = 24;
2522 else if (infoLevel == 0x103) nbytesRequired = 4;
2523 else if (infoLevel == 0x108) nbytesRequired = 30;
2525 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2526 p->opcode, infoLevel);
2527 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2530 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2531 osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
2533 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2535 if (infoLevel > 0x100)
2536 outp->totalParms = 2;
2538 outp->totalParms = 0;
2539 outp->totalData = nbytesRequired;
2541 /* now, if we're at infoLevel 6, we're only being asked to check
2542 * the syntax, so we just OK things now. In particular, we're *not*
2543 * being asked to verify anything about the state of any parent dirs.
2545 if (infoLevel == 6) {
2546 smb_SendTran2Packet(vcp, outp, opx);
2547 smb_FreeTran2Packet(outp);
2551 userp = smb_GetTran2User(vcp, p);
2553 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2554 smb_FreeTran2Packet(outp);
2555 return CM_ERROR_BADSMB;
2558 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2560 cm_ReleaseUser(userp);
2561 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2562 smb_FreeTran2Packet(outp);
2567 * XXX Strange hack XXX
2569 * As of Patch 7 (13 January 98), we are having the following problem:
2570 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2571 * requests to look up "desktop.ini" in all the subdirectories.
2572 * This can cause zillions of timeouts looking up non-existent cells
2573 * and volumes, especially in the top-level directory.
2575 * We have not found any way to avoid this or work around it except
2576 * to explicitly ignore the requests for mount points that haven't
2577 * yet been evaluated and for directories that haven't yet been
2580 if (infoLevel == 0x101) {
2581 spacep = cm_GetSpace();
2582 smb_StripLastComponent(spacep->data, &lastComp,
2583 (char *)(&p->parmsp[3]));
2584 /* Make sure that lastComp is not NULL */
2586 if (strcmp(lastComp, "\\desktop.ini") == 0) {
2587 code = cm_NameI(cm_rootSCachep, spacep->data,
2591 userp, tidPathp, &req, &dscp);
2593 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
2594 && !dscp->mountRootFidp)
2595 code = CM_ERROR_NOSUCHFILE;
2596 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2597 cm_buf_t *bp = buf_Find(dscp, &hzero);
2601 code = CM_ERROR_NOSUCHFILE;
2603 cm_ReleaseSCache(dscp);
2605 cm_FreeSpace(spacep);
2606 cm_ReleaseUser(userp);
2607 smb_SendTran2Error(vcp, p, opx, code);
2608 smb_FreeTran2Packet(outp);
2614 cm_FreeSpace(spacep);
2617 /* now do namei and stat, and copy out the info */
2618 code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
2619 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2622 cm_ReleaseUser(userp);
2623 smb_SendTran2Error(vcp, p, opx, code);
2624 smb_FreeTran2Packet(outp);
2628 lock_ObtainMutex(&scp->mx);
2629 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2630 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2631 if (code) goto done;
2633 /* now we have the status in the cache entry, and everything is locked.
2634 * Marshall the output data.
2637 /* for info level 108, figure out short name */
2638 if (infoLevel == 0x108) {
2639 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
2640 tidPathp, scp->fid.vnode, shortName,
2647 *((u_long *)op) = len * 2; op += 4;
2648 mbstowcs((unsigned short *)op, shortName, len);
2653 if (infoLevel == 1 || infoLevel == 2) {
2654 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2655 *((u_long *)op) = dosTime; op += 4; /* creation time */
2656 *((u_long *)op) = dosTime; op += 4; /* access time */
2657 *((u_long *)op) = dosTime; op += 4; /* write time */
2658 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
2659 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
2660 attributes = smb_Attributes(scp);
2661 *((u_short *)op) = attributes; op += 2; /* attributes */
2663 else if (infoLevel == 0x101) {
2664 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2665 *((FILETIME *)op) = ft; op += 8; /* creation time */
2666 *((FILETIME *)op) = ft; op += 8; /* last access time */
2667 *((FILETIME *)op) = ft; op += 8; /* last write time */
2668 *((FILETIME *)op) = ft; op += 8; /* last change time */
2669 extAttributes = smb_ExtAttributes(scp);
2670 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
2671 *((u_long *)op) = 0; op += 4; /* don't know what this is */
2673 else if (infoLevel == 0x102) {
2674 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2675 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2676 *((u_long *)op) = scp->linkCount; op += 4;
2679 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2682 else if (infoLevel == 0x103) {
2683 memset(op, 0, 4); op += 4; /* EA size */
2686 /* now, if we are being asked about extended attrs, return a 0 size */
2687 if (infoLevel == 2) {
2688 *((u_long *)op) = 0; op += 4;
2692 /* send and free the packets */
2694 lock_ReleaseMutex(&scp->mx);
2695 cm_ReleaseSCache(scp);
2696 cm_ReleaseUser(userp);
2698 smb_SendTran2Packet(vcp, outp, opx);
2700 smb_SendTran2Error(vcp, p, opx, code);
2701 smb_FreeTran2Packet(outp);
2706 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2708 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2709 return CM_ERROR_BADOP;
2712 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2714 smb_tran2Packet_t *outp;
2716 unsigned long attributes;
2717 unsigned short infoLevel;
2730 fidp = smb_FindFID(vcp, fid, 0);
2733 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2737 infoLevel = p->parmsp[1];
2738 if (infoLevel == 0x101) nbytesRequired = 40;
2739 else if (infoLevel == 0x102) nbytesRequired = 24;
2740 else if (infoLevel == 0x103) nbytesRequired = 4;
2741 else if (infoLevel == 0x104) nbytesRequired = 6;
2743 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2744 p->opcode, infoLevel);
2745 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2746 smb_ReleaseFID(fidp);
2749 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2751 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2753 if (infoLevel > 0x100)
2754 outp->totalParms = 2;
2756 outp->totalParms = 0;
2757 outp->totalData = nbytesRequired;
2759 userp = smb_GetTran2User(vcp, p);
2761 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2762 code = CM_ERROR_BADSMB;
2767 lock_ObtainMutex(&scp->mx);
2768 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2769 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2773 /* now we have the status in the cache entry, and everything is locked.
2774 * Marshall the output data.
2777 if (infoLevel == 0x101) {
2778 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2779 *((FILETIME *)op) = ft; op += 8; /* creation time */
2780 *((FILETIME *)op) = ft; op += 8; /* last access time */
2781 *((FILETIME *)op) = ft; op += 8; /* last write time */
2782 *((FILETIME *)op) = ft; op += 8; /* last change time */
2783 attributes = smb_ExtAttributes(scp);
2784 *((u_long *)op) = attributes; op += 4;
2785 *((u_long *)op) = 0; op += 4;
2787 else if (infoLevel == 0x102) {
2788 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2789 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2790 *((u_long *)op) = scp->linkCount; op += 4;
2791 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
2792 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2796 else if (infoLevel == 0x103) {
2797 *((u_long *)op) = 0; op += 4;
2799 else if (infoLevel == 0x104) {
2803 if (fidp->NTopen_wholepathp)
2804 name = fidp->NTopen_wholepathp;
2806 name = "\\"; /* probably can't happen */
2808 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
2809 *((u_long *)op) = len * 2; op += 4;
2810 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2813 /* send and free the packets */
2815 lock_ReleaseMutex(&scp->mx);
2816 cm_ReleaseUser(userp);
2817 smb_ReleaseFID(fidp);
2819 smb_SendTran2Packet(vcp, outp, opx);
2821 smb_SendTran2Error(vcp, p, opx, code);
2822 smb_FreeTran2Packet(outp);
2827 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2832 unsigned short infoLevel;
2833 smb_tran2Packet_t *outp;
2841 fidp = smb_FindFID(vcp, fid, 0);
2844 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
2848 infoLevel = p->parmsp[1];
2849 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type=[%x] fid=[%x]", infoLevel, fid);
2850 if (infoLevel > 0x104 || infoLevel < 0x101) {
2851 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2852 p->opcode, infoLevel);
2853 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
2854 smb_ReleaseFID(fidp);
2858 if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
2859 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2860 smb_ReleaseFID(fidp);
2863 if ((infoLevel == 0x103 || infoLevel == 0x104)
2864 && !(fidp->flags & SMB_FID_OPENWRITE)) {
2865 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2866 smb_ReleaseFID(fidp);
2870 osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
2872 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
2874 outp->totalParms = 2;
2875 outp->totalData = 0;
2877 userp = smb_GetTran2User(vcp, p);
2879 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
2880 code = CM_ERROR_BADSMB;
2886 if (infoLevel == 0x101) {
2888 unsigned int attribute;
2891 /* lock the vnode with a callback; we need the current status
2892 * to determine what the new status is, in some cases.
2894 lock_ObtainMutex(&scp->mx);
2895 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2896 CM_SCACHESYNC_GETSTATUS
2897 | CM_SCACHESYNC_NEEDCALLBACK);
2899 lock_ReleaseMutex(&scp->mx);
2903 /* prepare for setattr call */
2906 lastMod = *((FILETIME *)(p->datap + 16));
2907 /* when called as result of move a b, lastMod is (-1, -1).
2908 * If the check for -1 is not present, timestamp
2909 * of the resulting file will be 1969 (-1)
2911 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
2912 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
2913 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
2914 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
2916 fidp->flags |= SMB_FID_MTIMESETDONE;
2919 attribute = *((u_long *)(p->datap + 32));
2920 if (attribute != 0) {
2921 if ((scp->unixModeBits & 0222)
2922 && (attribute & 1) != 0) {
2923 /* make a writable file read-only */
2924 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2925 attr.unixModeBits = scp->unixModeBits & ~0222;
2927 else if ((scp->unixModeBits & 0222) == 0
2928 && (attribute & 1) == 0) {
2929 /* make a read-only file writable */
2930 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2931 attr.unixModeBits = scp->unixModeBits | 0222;
2934 lock_ReleaseMutex(&scp->mx);
2938 code = cm_SetAttr(scp, &attr, userp, &req);
2942 else if (infoLevel == 0x103 || infoLevel == 0x104) {
2943 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
2946 attr.mask = CM_ATTRMASK_LENGTH;
2947 attr.length.LowPart = size.LowPart;
2948 attr.length.HighPart = size.HighPart;
2949 code = cm_SetAttr(scp, &attr, userp, &req);
2951 else if (infoLevel == 0x102) {
2952 if (*((char *)(p->datap))) {
2953 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
2956 fidp->flags |= SMB_FID_DELONCLOSE;
2960 fidp->flags &= ~SMB_FID_DELONCLOSE;
2965 cm_ReleaseUser(userp);
2966 smb_ReleaseFID(fidp);
2968 smb_SendTran2Packet(vcp, outp, op);
2970 smb_SendTran2Error(vcp, p, op, code);
2971 smb_FreeTran2Packet(outp);
2977 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2979 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
2980 return CM_ERROR_BADOP;
2984 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2986 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
2987 return CM_ERROR_BADOP;
2991 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2993 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
2994 return CM_ERROR_BADOP;
2998 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3000 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3001 return CM_ERROR_BADOP;
3005 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3007 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3008 return CM_ERROR_BADOP;
3012 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3014 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3015 return CM_ERROR_BADOP;
3019 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3021 osi_Log0(smb_logp,"ReceiveTran2GetDFSReferral - NOT_SUPPORTED");
3022 return CM_ERROR_BADOP;
3026 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3028 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3029 return CM_ERROR_BADOP;
3033 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3034 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3039 cm_scache_t *targetScp; /* target if scp is a symlink */
3044 unsigned short attr;
3045 unsigned long lattr;
3046 smb_dirListPatch_t *patchp;
3047 smb_dirListPatch_t *npatchp;
3049 for(patchp = *dirPatchespp; patchp; patchp =
3050 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3051 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3053 lock_ObtainMutex(&scp->mx);
3054 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3055 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3057 lock_ReleaseMutex(&scp->mx);
3058 cm_ReleaseSCache(scp);
3060 dptr = patchp->dptr;
3062 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3063 errors in the client. */
3064 if (infoLevel >= 0x101) {
3065 /* 1969-12-31 23:59:59 +00 */
3066 ft.dwHighDateTime = 0x19DB200;
3067 ft.dwLowDateTime = 0x5BB78980;
3069 /* copy to Creation Time */
3070 *((FILETIME *)dptr) = ft;
3073 /* copy to Last Access Time */
3074 *((FILETIME *)dptr) = ft;
3077 /* copy to Last Write Time */
3078 *((FILETIME *)dptr) = ft;
3081 /* copy to Change Time */
3082 *((FILETIME *)dptr) = ft;
3085 /* merge in hidden attribute */
3086 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3087 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3091 /* 1969-12-31 23:59:58 +00*/
3092 dosTime = 0xEBBFBF7D;
3094 /* and copy out date */
3095 shortTemp = (dosTime>>16) & 0xffff;
3096 *((u_short *)dptr) = shortTemp;
3099 /* copy out creation time */
3100 shortTemp = dosTime & 0xffff;
3101 *((u_short *)dptr) = shortTemp;
3104 /* and copy out date */
3105 shortTemp = (dosTime>>16) & 0xffff;
3106 *((u_short *)dptr) = shortTemp;
3109 /* copy out access time */
3110 shortTemp = dosTime & 0xffff;
3111 *((u_short *)dptr) = shortTemp;
3114 /* and copy out date */
3115 shortTemp = (dosTime>>16) & 0xffff;
3116 *((u_short *)dptr) = shortTemp;
3119 /* copy out mod time */
3120 shortTemp = dosTime & 0xffff;
3121 *((u_short *)dptr) = shortTemp;
3124 /* merge in hidden (dot file) attribute */
3125 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3126 attr = SMB_ATTR_HIDDEN;
3127 *dptr++ = attr & 0xff;
3128 *dptr++ = (attr >> 8) & 0xff;
3134 /* now watch for a symlink */
3136 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3137 lock_ReleaseMutex(&scp->mx);
3138 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3140 /* we have a more accurate file to use (the
3141 * target of the symbolic link). Otherwise,
3142 * we'll just use the symlink anyway.
3144 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3146 cm_ReleaseSCache(scp);
3149 lock_ObtainMutex(&scp->mx);
3152 dptr = patchp->dptr;
3154 if (infoLevel >= 0x101) {
3156 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3158 /* copy to Creation Time */
3159 *((FILETIME *)dptr) = ft;
3162 /* copy to Last Access Time */
3163 *((FILETIME *)dptr) = ft;
3166 /* copy to Last Write Time */
3167 *((FILETIME *)dptr) = ft;
3170 /* copy to Change Time */
3171 *((FILETIME *)dptr) = ft;
3174 /* Use length for both file length and alloc length */
3175 *((LARGE_INTEGER *)dptr) = scp->length;
3177 *((LARGE_INTEGER *)dptr) = scp->length;
3180 /* Copy attributes */
3181 lattr = smb_ExtAttributes(scp);
3182 /* merge in hidden (dot file) attribute */
3183 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3184 lattr |= SMB_ATTR_HIDDEN;
3185 *((u_long *)dptr) = lattr;
3190 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3192 /* and copy out date */
3193 shortTemp = (dosTime>>16) & 0xffff;
3194 *((u_short *)dptr) = shortTemp;
3197 /* copy out creation time */
3198 shortTemp = dosTime & 0xffff;
3199 *((u_short *)dptr) = shortTemp;
3202 /* and copy out date */
3203 shortTemp = (dosTime>>16) & 0xffff;
3204 *((u_short *)dptr) = shortTemp;
3207 /* copy out access time */
3208 shortTemp = dosTime & 0xffff;
3209 *((u_short *)dptr) = shortTemp;
3212 /* and copy out date */
3213 shortTemp = (dosTime>>16) & 0xffff;
3214 *((u_short *)dptr) = shortTemp;
3217 /* copy out mod time */
3218 shortTemp = dosTime & 0xffff;
3219 *((u_short *)dptr) = shortTemp;
3222 /* copy out file length and alloc length,
3223 * using the same for both
3225 *((u_long *)dptr) = scp->length.LowPart;
3227 *((u_long *)dptr) = scp->length.LowPart;
3230 /* finally copy out attributes as short */
3231 attr = smb_Attributes(scp);
3232 /* merge in hidden (dot file) attribute */
3233 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3234 attr |= SMB_ATTR_HIDDEN;
3235 *dptr++ = attr & 0xff;
3236 *dptr++ = (attr >> 8) & 0xff;
3239 lock_ReleaseMutex(&scp->mx);
3240 cm_ReleaseSCache(scp);
3243 /* now free the patches */
3244 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3245 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3249 /* and mark the list as empty */
3250 *dirPatchespp = NULL;
3255 #ifndef USE_OLD_MATCHING
3256 // char table for case insensitive comparison
3257 char mapCaseTable[256];
3259 VOID initUpperCaseTable(VOID)
3262 for (i = 0; i < 256; ++i)
3263 mapCaseTable[i] = toupper(i);
3264 // make '"' match '.'
3265 mapCaseTable[(int)'"'] = toupper('.');
3266 // make '<' match '*'
3267 mapCaseTable[(int)'<'] = toupper('*');
3268 // make '>' match '?'
3269 mapCaseTable[(int)'>'] = toupper('?');
3272 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3274 // Note : this procedure works recursively calling itself.
3276 // PSZ pattern : string containing metacharacters.
3277 // PSZ name : file name to be compared with 'pattern'.
3279 // BOOL : TRUE/FALSE (match/mistmatch)
3282 szWildCardMatchFileName(PSZ pattern, PSZ name)
3284 PSZ pename; // points to the last 'name' character
3286 pename = name + strlen(name) - 1;
3296 if (*pattern == '\0')
3298 for (p = pename; p >= name; --p) {
3299 if ((mapCaseTable[*p] == mapCaseTable[*pattern]) &&
3300 szWildCardMatchFileName(pattern + 1, p + 1))
3305 if (mapCaseTable[*name] != mapCaseTable[*pattern])
3312 if (*pattern == '\0' || *pattern == '*' && *(pattern+1) == '\0')
3318 /* do a case-folding search of the star name mask with the name in namep.
3319 * Return 1 if we match, otherwise 0.
3321 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3324 int i, j, star, qmark, retval;
3326 /* make sure we only match 8.3 names, if requested */
3327 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3330 /* optimize the pattern:
3331 * if there is a mixture of '?' and '*',
3332 * for example the sequence "*?*?*?*"
3333 * must be turned into the form "*"
3335 newmask = (char *)malloc(strlen(maskp)+1);
3336 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3337 switch ( maskp[i] ) {
3349 } else if ( qmark ) {
3353 newmask[j++] = maskp[i];
3360 } else if ( qmark ) {
3364 newmask[j++] = '\0';
3366 retval = szWildCardMatchFileName(newmask, namep) ? 1:0;
3372 #else /* USE_OLD_MATCHING */
3373 /* do a case-folding search of the star name mask with the name in namep.
3374 * Return 1 if we match, otherwise 0.
3376 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3378 unsigned char tcp1, tcp2; /* Pattern characters */
3379 unsigned char tcn1; /* Name characters */
3380 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3381 char *starNamep, *starMaskp;
3382 static char nullCharp[] = {0};
3383 int casefold = flags & CM_FLAG_CASEFOLD;
3385 /* make sure we only match 8.3 names, if requested */
3386 req8dot3 = (flags & CM_FLAG_8DOT3);
3387 if (req8dot3 && !cm_Is8Dot3(namep))
3392 /* Next pattern character */
3395 /* Next name character */
3399 /* 0 - end of pattern */
3405 else if (tcp1 == '.' || tcp1 == '"') {
3415 * first dot in pattern;
3416 * must match dot or end of name
3421 else if (tcn1 == '.') {
3430 else if (tcp1 == '?') {
3431 if (tcn1 == 0 || tcn1 == '.')
3436 else if (tcp1 == '>') {
3437 if (tcn1 != 0 && tcn1 != '.')
3441 else if (tcp1 == '*' || tcp1 == '<') {
3445 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3446 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3461 * pattern character after '*' is not null or
3462 * period. If it is '?' or '>', we are not
3463 * going to understand it. If it is '*' or
3464 * '<', we are going to skip over it. None of
3465 * these are likely, I hope.
3467 /* skip over '*' and '<' */
3468 while (tcp2 == '*' || tcp2 == '<')
3471 /* skip over characters that don't match tcp2 */
3472 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
3473 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
3474 (!casefold && tcn1 != tcp2)))
3478 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3481 /* Remember where we are */
3491 /* tcp1 is not a wildcard */
3492 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
3493 (!casefold && tcn1 == tcp1)) {
3498 /* if trying to match a star pattern, go back */
3500 maskp = starMaskp - 2;
3501 namep = starNamep + 1;
3510 #endif /* USE_OLD_MATCHING */
3512 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3521 smb_dirListPatch_t *dirListPatchesp;
3522 smb_dirListPatch_t *curPatchp;
3525 long orbytes; /* # of bytes in this output record */
3526 long ohbytes; /* # of bytes, except file name */
3527 long onbytes; /* # of bytes in name, incl. term. null */
3528 osi_hyper_t dirLength;
3529 osi_hyper_t bufferOffset;
3530 osi_hyper_t curOffset;
3532 smb_dirSearch_t *dsp;
3536 cm_pageHeader_t *pageHeaderp;
3537 cm_user_t *userp = NULL;
3540 long nextEntryCookie;
3541 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3542 char *op; /* output data ptr */
3543 char *origOp; /* original value of op */
3544 cm_space_t *spacep; /* for pathname buffer */
3545 long maxReturnData; /* max # of return data */
3546 long maxReturnParms; /* max # of return parms */
3547 long bytesInBuffer; /* # data bytes in the output buffer */
3549 char *maskp; /* mask part of path */
3553 smb_tran2Packet_t *outp; /* response packet */
3556 char shortName[13]; /* 8.3 name if needed */
3567 if (p->opcode == 1) {
3568 /* find first; obtain basic parameters from request */
3569 attribute = p->parmsp[0];
3570 maxCount = p->parmsp[1];
3571 infoLevel = p->parmsp[3];
3572 searchFlags = p->parmsp[2];
3573 dsp = smb_NewDirSearch(1);
3574 dsp->attribute = attribute;
3575 pathp = ((char *) p->parmsp) + 12; /* points to path */
3577 maskp = strrchr(pathp, '\\');
3578 if (maskp == NULL) maskp = pathp;
3579 else maskp++; /* skip over backslash */
3580 strcpy(dsp->mask, maskp); /* and save mask */
3581 /* track if this is likely to match a lot of entries */
3582 starPattern = smb_V3IsStarMask(maskp);
3585 osi_assert(p->opcode == 2);
3586 /* find next; obtain basic parameters from request or open dir file */
3587 dsp = smb_FindDirSearch(p->parmsp[0]);
3588 if (!dsp) return CM_ERROR_BADFD;
3589 attribute = dsp->attribute;
3590 maxCount = p->parmsp[1];
3591 infoLevel = p->parmsp[2];
3592 searchFlags = p->parmsp[5];
3594 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
3596 starPattern = 1; /* assume, since required a Find Next */
3600 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
3601 attribute, infoLevel, maxCount, searchFlags);
3603 osi_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
3604 p->opcode, nextCookie);
3606 if (infoLevel >= 0x101)
3607 searchFlags &= ~4; /* no resume keys */
3609 dirListPatchesp = NULL;
3611 maxReturnData = p->maxReturnData;
3612 if (p->opcode == 1) /* find first */
3613 maxReturnParms = 10; /* bytes */
3615 maxReturnParms = 8; /* bytes */
3617 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
3618 if (maxReturnData > 6000)
3619 maxReturnData = 6000;
3620 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
3622 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
3625 osi_Log1(smb_logp, "T2 receive search dir %s",
3626 osi_LogSaveString(smb_logp, pathp));
3628 /* bail out if request looks bad */
3629 if (p->opcode == 1 && !pathp) {
3630 smb_ReleaseDirSearch(dsp);
3631 smb_FreeTran2Packet(outp);
3632 return CM_ERROR_BADSMB;
3635 osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
3636 nextCookie, dsp->cookie);
3638 userp = smb_GetTran2User(vcp, p);
3640 osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p->uid);
3641 smb_ReleaseDirSearch(dsp);
3642 smb_FreeTran2Packet(outp);
3643 return CM_ERROR_BADSMB;
3646 /* try to get the vnode for the path name next */
3647 lock_ObtainMutex(&dsp->mx);
3654 spacep = cm_GetSpace();
3655 smb_StripLastComponent(spacep->data, NULL, pathp);
3656 lock_ReleaseMutex(&dsp->mx);
3658 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3660 cm_ReleaseUser(userp);
3661 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
3662 smb_FreeTran2Packet(outp);
3663 smb_DeleteDirSearch(dsp);
3664 smb_ReleaseDirSearch(dsp);
3667 code = cm_NameI(cm_rootSCachep, spacep->data,
3668 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3669 userp, tidPathp, &req, &scp);
3670 cm_FreeSpace(spacep);
3672 lock_ObtainMutex(&dsp->mx);
3674 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
3676 /* we need one hold for the entry we just stored into,
3677 * and one for our own processing. When we're done
3678 * with this function, we'll drop the one for our own
3679 * processing. We held it once from the namei call,
3680 * and so we do another hold now.
3683 lock_ObtainMutex(&scp->mx);
3684 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
3685 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3686 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3687 dsp->flags |= SMB_DIRSEARCH_BULKST;
3689 lock_ReleaseMutex(&scp->mx);
3692 lock_ReleaseMutex(&dsp->mx);
3694 cm_ReleaseUser(userp);
3695 smb_FreeTran2Packet(outp);
3696 smb_DeleteDirSearch(dsp);
3697 smb_ReleaseDirSearch(dsp);
3701 /* get the directory size */
3702 lock_ObtainMutex(&scp->mx);
3703 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3704 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3706 lock_ReleaseMutex(&scp->mx);
3707 cm_ReleaseSCache(scp);
3708 cm_ReleaseUser(userp);
3709 smb_FreeTran2Packet(outp);
3710 smb_DeleteDirSearch(dsp);
3711 smb_ReleaseDirSearch(dsp);
3716 dirLength = scp->length;
3718 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3719 curOffset.HighPart = 0;
3720 curOffset.LowPart = nextCookie;
3721 origOp = outp->datap;
3729 if (searchFlags & 4)
3730 /* skip over resume key */
3733 /* make sure that curOffset.LowPart doesn't point to the first
3734 * 32 bytes in the 2nd through last dir page, and that it doesn't
3735 * point at the first 13 32-byte chunks in the first dir page,
3736 * since those are dir and page headers, and don't contain useful
3739 temp = curOffset.LowPart & (2048-1);
3740 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3741 /* we're in the first page */
3742 if (temp < 13*32) temp = 13*32;
3745 /* we're in a later dir page */
3746 if (temp < 32) temp = 32;
3749 /* make sure the low order 5 bits are zero */
3752 /* now put temp bits back ito curOffset.LowPart */
3753 curOffset.LowPart &= ~(2048-1);
3754 curOffset.LowPart |= temp;
3756 /* check if we've passed the dir's EOF */
3757 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
3762 /* check if we've returned all the names that will fit in the
3763 * response packet; we check return count as well as the number
3764 * of bytes requested. We check the # of bytes after we find
3765 * the dir entry, since we'll need to check its size.
3767 if (returnedNames >= maxCount) {
3771 /* see if we can use the bufferp we have now; compute in which
3772 * page the current offset would be, and check whether that's
3773 * the offset of the buffer we have. If not, get the buffer.
3775 thyper.HighPart = curOffset.HighPart;
3776 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3777 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3780 buf_Release(bufferp);
3783 lock_ReleaseMutex(&scp->mx);
3784 lock_ObtainRead(&scp->bufCreateLock);
3785 code = buf_Get(scp, &thyper, &bufferp);
3786 lock_ReleaseRead(&scp->bufCreateLock);
3788 /* now, if we're doing a star match, do bulk fetching
3789 * of all of the status info for files in the dir.
3792 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
3795 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3796 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
3797 /* Don't bulk stat if risking timeout */
3798 int now = GetCurrentTime();
3799 if (now - req.startTime > 5000) {
3800 scp->bulkStatProgress = thyper;
3801 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3802 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3804 cm_TryBulkStat(scp, &thyper, userp, &req);
3808 lock_ObtainMutex(&scp->mx);
3810 bufferOffset = thyper;
3812 /* now get the data in the cache */
3814 code = cm_SyncOp(scp, bufferp, userp, &req,
3816 CM_SCACHESYNC_NEEDCALLBACK
3817 | CM_SCACHESYNC_READ);
3820 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3822 /* otherwise, load the buffer and try again */
3823 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3828 buf_Release(bufferp);
3832 } /* if (wrong buffer) ... */
3834 /* now we have the buffer containing the entry we're interested
3835 * in; copy it out if it represents a non-deleted entry.
3837 entryInDir = curOffset.LowPart & (2048-1);
3838 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3840 /* page header will help tell us which entries are free. Page
3841 * header can change more often than once per buffer, since
3842 * AFS 3 dir page size may be less than (but not more than)
3843 * a buffer package buffer.
3845 /* only look intra-buffer */
3846 temp = curOffset.LowPart & (buf_bufferSize - 1);
3847 temp &= ~(2048 - 1); /* turn off intra-page bits */
3848 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3850 /* now determine which entry we're looking at in the page.
3851 * If it is free (there's a free bitmap at the start of the
3852 * dir), we should skip these 32 bytes.
3854 slotInPage = (entryInDir & 0x7e0) >> 5;
3855 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
3856 (1 << (slotInPage & 0x7)))) {
3857 /* this entry is free */
3858 numDirChunks = 1; /* only skip this guy */
3862 tp = bufferp->datap + entryInBuffer;
3863 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3865 /* while we're here, compute the next entry's location, too,
3866 * since we'll need it when writing out the cookie into the dir
3869 * XXXX Probably should do more sanity checking.
3871 numDirChunks = cm_NameEntries(dep->name, &onbytes);
3873 /* compute offset of cookie representing next entry */
3874 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3876 /* Need 8.3 name? */
3878 if (infoLevel == 0x104
3879 && dep->fid.vnode != 0
3880 && !cm_Is8Dot3(dep->name)) {
3881 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3885 /* When matching, we are using doing a case fold if we have a wildcard mask.
3886 * If we get a non-wildcard match, it's a lookup for a specific file.
3888 if (dep->fid.vnode != 0 &&
3889 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
3891 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
3893 /* Eliminate entries that don't match requested attributes */
3894 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
3895 smb_IsDotFile(dep->name))
3896 goto nextEntry; /* no hidden files */
3898 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3900 /* We have already done the cm_TryBulkStat above */
3901 fid.cell = scp->fid.cell;
3902 fid.volume = scp->fid.volume;
3903 fid.vnode = ntohl(dep->fid.vnode);
3904 fid.unique = ntohl(dep->fid.unique);
3905 fileType = cm_FindFileType(&fid);
3906 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
3907 "has filetype %d", dep->name,
3909 if (fileType == CM_SCACHETYPE_DIRECTORY)
3913 /* finally check if this name will fit */
3915 /* standard dir entry stuff */
3916 if (infoLevel < 0x101)
3917 ohbytes = 23; /* pre-NT */
3918 else if (infoLevel == 0x103)
3919 ohbytes = 12; /* NT names only */
3921 ohbytes = 64; /* NT */
3923 if (infoLevel == 0x104)
3924 ohbytes += 26; /* Short name & length */
3926 if (searchFlags & 4) {
3927 ohbytes += 4; /* if resume key required */
3931 && infoLevel != 0x101
3932 && infoLevel != 0x103)
3933 ohbytes += 4; /* EASIZE */
3935 /* add header to name & term. null */
3936 orbytes = onbytes + ohbytes + 1;
3938 /* now, we round up the record to a 4 byte alignment,
3939 * and we make sure that we have enough room here for
3940 * even the aligned version (so we don't have to worry
3941 * about an * overflow when we pad things out below).
3942 * That's the reason for the alignment arithmetic below.
3944 if (infoLevel >= 0x101)
3945 align = (4 - (orbytes & 3)) & 3;
3948 if (orbytes + bytesInBuffer + align > maxReturnData)
3951 /* this is one of the entries to use: it is not deleted
3952 * and it matches the star pattern we're looking for.
3953 * Put out the name, preceded by its length.
3955 /* First zero everything else */
3956 memset(origOp, 0, ohbytes);
3958 if (infoLevel <= 0x101)
3959 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
3960 else if (infoLevel == 0x103)
3961 *((u_long *)(op + 8)) = onbytes;
3963 *((u_long *)(op + 60)) = onbytes;
3964 strcpy(origOp+ohbytes, dep->name);
3966 /* Short name if requested and needed */
3967 if (infoLevel == 0x104) {
3968 if (NeedShortName) {
3969 strcpy(op + 70, shortName);
3970 *(op + 68) = shortNameEnd - shortName;
3974 /* now, adjust the # of entries copied */
3977 /* NextEntryOffset and FileIndex */
3978 if (infoLevel >= 101) {
3979 int entryOffset = orbytes + align;
3980 *((u_long *)op) = entryOffset;
3981 *((u_long *)(op+4)) = nextEntryCookie;
3984 /* now we emit the attribute. This is tricky, since
3985 * we need to really stat the file to find out what
3986 * type of entry we've got. Right now, we're copying
3987 * out data from * a buffer, while holding the scp
3988 * locked, so it isn't really convenient to stat
3989 * something now. We'll put in a place holder
3990 * now, and make a second pass before returning this
3991 * to get the real attributes. So, we just skip the
3992 * data for now, and adjust it later. We allocate a
3993 * patch record to make it easy to find this point
3994 * later. The replay will happen at a time when it is
3995 * safe to unlock the directory.
3997 if (infoLevel != 0x103) {
3998 curPatchp = malloc(sizeof(*curPatchp));
3999 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4001 curPatchp->dptr = op;
4002 if (infoLevel >= 0x101)
4003 curPatchp->dptr += 8;
4005 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4006 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4009 curPatchp->flags = 0;
4011 curPatchp->fid.cell = scp->fid.cell;
4012 curPatchp->fid.volume = scp->fid.volume;
4013 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4014 curPatchp->fid.unique = ntohl(dep->fid.unique);
4017 curPatchp->dep = dep;
4020 if (searchFlags & 4)
4021 /* put out resume key */
4022 *((u_long *)origOp) = nextEntryCookie;
4024 /* Adjust byte ptr and count */
4025 origOp += orbytes; /* skip entire record */
4026 bytesInBuffer += orbytes;
4028 /* and pad the record out */
4029 while (--align >= 0) {
4033 } /* if we're including this name */
4034 else if (!NeedShortName &&
4037 dep->fid.vnode != 0 &&
4038 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4039 /* We were looking for exact matches, but here's an inexact one*/
4044 /* and adjust curOffset to be where the new cookie is */
4045 thyper.HighPart = 0;
4046 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4047 curOffset = LargeIntegerAdd(thyper, curOffset);
4048 } /* while copying data for dir listing */
4050 /* If we didn't get a star pattern, we did an exact match during the first pass.
4051 * If there were no exact matches found, we fail over to inexact matches by
4052 * marking the query as a star pattern (matches all case permutations), and
4053 * re-running the query.
4055 if (returnedNames == 0 && !starPattern && foundInexact) {
4056 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4061 /* release the mutex */
4062 lock_ReleaseMutex(&scp->mx);
4063 if (bufferp) buf_Release(bufferp);
4065 /* apply and free last set of patches; if not doing a star match, this
4066 * will be empty, but better safe (and freeing everything) than sorry.
4068 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4071 /* now put out the final parameters */
4072 if (returnedNames == 0) eos = 1;
4073 if (p->opcode == 1) {
4075 outp->parmsp[0] = (unsigned short) dsp->cookie;
4076 outp->parmsp[1] = returnedNames;
4077 outp->parmsp[2] = eos;
4078 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4079 outp->parmsp[4] = 0;
4080 /* don't need last name to continue
4081 * search, cookie is enough. Normally,
4082 * this is the offset of the file name
4083 * of the last entry returned.
4085 outp->totalParms = 10; /* in bytes */
4089 outp->parmsp[0] = returnedNames;
4090 outp->parmsp[1] = eos;
4091 outp->parmsp[2] = 0; /* EAS error */
4092 outp->parmsp[3] = 0; /* last name, as above */
4093 outp->totalParms = 8; /* in bytes */
4096 /* return # of bytes in the buffer */
4097 outp->totalData = bytesInBuffer;
4099 osi_Log2(smb_logp, "T2 search dir done, %d names, code %d",
4100 returnedNames, code);
4102 /* Return error code if unsuccessful on first request */
4103 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4104 code = CM_ERROR_NOSUCHFILE;
4106 /* if we're supposed to close the search after this request, or if
4107 * we're supposed to close the search if we're done, and we're done,
4108 * or if something went wrong, close the search.
4110 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4111 if ((searchFlags & 1) || (returnedNames == 0) ||
4112 ((searchFlags & 2) && eos) || code != 0)
4113 smb_DeleteDirSearch(dsp);
4115 smb_SendTran2Error(vcp, p, opx, code);
4117 smb_SendTran2Packet(vcp, outp, opx);
4119 smb_FreeTran2Packet(outp);
4120 smb_ReleaseDirSearch(dsp);
4121 cm_ReleaseSCache(scp);
4122 cm_ReleaseUser(userp);
4126 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4129 smb_dirSearch_t *dsp;
4131 dirHandle = smb_GetSMBParm(inp, 0);
4133 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4135 dsp = smb_FindDirSearch(dirHandle);
4138 return CM_ERROR_BADFD;
4140 /* otherwise, we have an FD to destroy */
4141 smb_DeleteDirSearch(dsp);
4142 smb_ReleaseDirSearch(dsp);
4144 /* and return results */
4145 smb_SetSMBDataLength(outp, 0);
4150 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4152 smb_SetSMBDataLength(outp, 0);
4156 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4163 cm_scache_t *dscp; /* dir we're dealing with */
4164 cm_scache_t *scp; /* file we're creating */
4166 int initialModeBits;
4176 int parmSlot; /* which parm we're dealing with */
4184 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4185 openFun = smb_GetSMBParm(inp, 8); /* open function */
4186 excl = ((openFun & 3) == 0);
4187 trunc = ((openFun & 3) == 2); /* truncate it */
4188 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4189 openAction = 0; /* tracks what we did */
4191 attributes = smb_GetSMBParm(inp, 5);
4192 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4194 /* compute initial mode bits based on read-only flag in attributes */
4195 initialModeBits = 0666;
4196 if (attributes & 1) initialModeBits &= ~0222;
4198 pathp = smb_GetSMBData(inp, NULL);
4200 spacep = inp->spacep;
4201 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4203 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4204 /* special case magic file name for receiving IOCTL requests
4205 * (since IOCTL calls themselves aren't getting through).
4208 osi_Log0(smb_logp, "IOCTL Open");
4211 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4212 smb_SetupIoctlFid(fidp, spacep);
4214 /* set inp->fid so that later read calls in same msg can find fid */
4215 inp->fid = fidp->fid;
4217 /* copy out remainder of the parms */
4219 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4221 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4222 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4223 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4224 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4225 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4226 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4227 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4228 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4230 /* and the final "always present" stuff */
4231 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4232 /* next write out the "unique" ID */
4233 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4234 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4235 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4236 smb_SetSMBDataLength(outp, 0);
4238 /* and clean up fid reference */
4239 smb_ReleaseFID(fidp);
4243 #ifdef DEBUG_VERBOSE
4245 char *hexp, *asciip;
4246 asciip = (lastNamep ? lastNamep : pathp );
4247 hexp = osi_HexifyString(asciip);
4248 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4252 userp = smb_GetUser(vcp, inp);
4255 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4257 cm_ReleaseUser(userp);
4258 return CM_ERROR_NOSUCHPATH;
4260 code = cm_NameI(cm_rootSCachep, pathp,
4261 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4262 userp, tidPathp, &req, &scp);
4264 code = cm_NameI(cm_rootSCachep, spacep->data,
4265 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4266 userp, tidPathp, &req, &dscp);
4269 cm_ReleaseUser(userp);
4273 /* otherwise, scp points to the parent directory. Do a lookup,
4274 * and truncate the file if we find it, otherwise we create the
4277 if (!lastNamep) lastNamep = pathp;
4279 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
4281 if (code && code != CM_ERROR_NOSUCHFILE) {
4282 cm_ReleaseSCache(dscp);
4283 cm_ReleaseUser(userp);
4288 /* if we get here, if code is 0, the file exists and is represented by
4289 * scp. Otherwise, we have to create it. The dir may be represented
4290 * by dscp, or we may have found the file directly. If code is non-zero,
4294 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
4296 if (dscp) cm_ReleaseSCache(dscp);
4297 cm_ReleaseSCache(scp);
4298 cm_ReleaseUser(userp);
4303 /* oops, file shouldn't be there */
4304 if (dscp) cm_ReleaseSCache(dscp);
4305 cm_ReleaseSCache(scp);
4306 cm_ReleaseUser(userp);
4307 return CM_ERROR_EXISTS;
4311 setAttr.mask = CM_ATTRMASK_LENGTH;
4312 setAttr.length.LowPart = 0;
4313 setAttr.length.HighPart = 0;
4314 code = cm_SetAttr(scp, &setAttr, userp, &req);
4315 openAction = 3; /* truncated existing file */
4317 else openAction = 1; /* found existing file */
4319 else if (!(openFun & 0x10)) {
4320 /* don't create if not found */
4321 if (dscp) cm_ReleaseSCache(dscp);
4322 cm_ReleaseUser(userp);
4323 return CM_ERROR_NOSUCHFILE;
4326 osi_assert(dscp != NULL);
4327 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
4328 osi_LogSaveString(smb_logp, lastNamep));
4329 openAction = 2; /* created file */
4330 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4331 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
4332 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4334 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4335 smb_NotifyChange(FILE_ACTION_ADDED,
4336 FILE_NOTIFY_CHANGE_FILE_NAME,
4337 dscp, lastNamep, NULL, TRUE);
4338 if (!excl && code == CM_ERROR_EXISTS) {
4339 /* not an exclusive create, and someone else tried
4340 * creating it already, then we open it anyway. We
4341 * don't bother retrying after this, since if this next
4342 * fails, that means that the file was deleted after we
4343 * started this call.
4345 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4349 setAttr.mask = CM_ATTRMASK_LENGTH;
4350 setAttr.length.LowPart = 0;
4351 setAttr.length.HighPart = 0;
4352 code = cm_SetAttr(scp, &setAttr, userp, &req);
4354 } /* lookup succeeded */
4358 /* we don't need this any longer */
4359 if (dscp) cm_ReleaseSCache(dscp);
4362 /* something went wrong creating or truncating the file */
4363 if (scp) cm_ReleaseSCache(scp);
4364 cm_ReleaseUser(userp);
4368 /* make sure we're about to open a file */
4369 if (scp->fileType != CM_SCACHETYPE_FILE) {
4370 cm_ReleaseSCache(scp);
4371 cm_ReleaseUser(userp);
4372 return CM_ERROR_ISDIR;
4375 /* now all we have to do is open the file itself */
4376 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4379 /* save a pointer to the vnode */
4382 /* compute open mode */
4383 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
4384 if (openMode == 1 || openMode == 2)
4385 fidp->flags |= SMB_FID_OPENWRITE;
4387 smb_ReleaseFID(fidp);
4389 cm_Open(scp, 0, userp);
4391 /* set inp->fid so that later read calls in same msg can find fid */
4392 inp->fid = fidp->fid;
4394 /* copy out remainder of the parms */
4396 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4397 lock_ObtainMutex(&scp->mx);
4399 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
4400 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4401 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
4402 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
4403 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
4404 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
4405 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4406 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4407 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4409 /* and the final "always present" stuff */
4410 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
4411 /* next write out the "unique" ID */
4412 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
4413 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
4414 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4415 lock_ReleaseMutex(&scp->mx);
4416 smb_SetSMBDataLength(outp, 0);
4418 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
4420 cm_ReleaseUser(userp);
4421 /* leave scp held since we put it in fidp->scp */
4425 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4432 unsigned char LockType;
4433 unsigned short NumberOfUnlocks, NumberOfLocks;
4434 unsigned long Timeout;
4436 LARGE_INTEGER LOffset, LLength;
4437 smb_waitingLock_t *waitingLock;
4444 fid = smb_GetSMBParm(inp, 2);
4445 fid = smb_ChainFID(fid, inp);
4447 fidp = smb_FindFID(vcp, fid, 0);
4448 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4449 return CM_ERROR_BADFD;
4451 /* set inp->fid so that later read calls in same msg can find fid */
4454 userp = smb_GetUser(vcp, inp);
4458 lock_ObtainMutex(&scp->mx);
4459 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4460 CM_SCACHESYNC_NEEDCALLBACK
4461 | CM_SCACHESYNC_GETSTATUS
4462 | CM_SCACHESYNC_LOCK);
4463 if (code) goto doneSync;
4465 LockType = smb_GetSMBParm(inp, 3) & 0xff;
4466 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
4467 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
4468 NumberOfLocks = smb_GetSMBParm(inp, 7);
4470 op = smb_GetSMBData(inp, NULL);
4472 for (i=0; i<NumberOfUnlocks; i++) {
4473 if (LockType & 0x10) {
4475 LOffset.HighPart = *((LONG *)(op + 4));
4476 LOffset.LowPart = *((DWORD *)(op + 8));
4477 LLength.HighPart = *((LONG *)(op + 12));
4478 LLength.LowPart = *((DWORD *)(op + 16));
4482 /* Not Large Files */
4483 LOffset.HighPart = 0;
4484 LOffset.LowPart = *((DWORD *)(op + 2));
4485 LLength.HighPart = 0;
4486 LLength.LowPart = *((DWORD *)(op + 6));
4489 if (LargeIntegerNotEqualToZero(LOffset))
4491 /* Do not check length -- length check done in cm_Unlock */
4493 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
4494 if (code) goto done;
4497 for (i=0; i<NumberOfLocks; i++) {
4498 if (LockType & 0x10) {
4500 LOffset.HighPart = *((LONG *)(op + 4));
4501 LOffset.LowPart = *((DWORD *)(op + 8));
4502 LLength.HighPart = *((LONG *)(op + 12));
4503 LLength.LowPart = *((DWORD *)(op + 16));
4507 /* Not Large Files */
4508 LOffset.HighPart = 0;
4509 LOffset.LowPart = *((DWORD *)(op + 2));
4510 LLength.HighPart = 0;
4511 LLength.LowPart = *((DWORD *)(op + 6));
4514 if (LargeIntegerNotEqualToZero(LOffset))
4516 if (LargeIntegerLessThan(LOffset, scp->length))
4519 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
4520 userp, &req, &lockp);
4521 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
4522 /* Put on waiting list */
4523 waitingLock = malloc(sizeof(smb_waitingLock_t));
4524 waitingLock->vcp = vcp;
4525 waitingLock->inp = smb_CopyPacket(inp);
4526 waitingLock->outp = smb_CopyPacket(outp);
4527 waitingLock->timeRemaining = Timeout;
4528 waitingLock->lockp = lockp;
4529 lock_ObtainWrite(&smb_globalLock);
4530 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
4532 osi_Wakeup((long) &smb_allWaitingLocks);
4533 lock_ReleaseWrite(&smb_globalLock);
4534 /* don't send reply immediately */
4535 outp->flags |= SMB_PACKETFLAG_NOSEND;
4541 /* release any locks acquired before the failure */
4544 smb_SetSMBDataLength(outp, 0);
4546 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
4548 lock_ReleaseMutex(&scp->mx);
4549 cm_ReleaseUser(userp);
4550 smb_ReleaseFID(fidp);
4555 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4567 fid = smb_GetSMBParm(inp, 0);
4568 fid = smb_ChainFID(fid, inp);
4570 fidp = smb_FindFID(vcp, fid, 0);
4571 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4572 return CM_ERROR_BADFD;
4575 userp = smb_GetUser(vcp, inp);
4579 /* otherwise, stat the file */
4580 lock_ObtainMutex(&scp->mx);
4581 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4582 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4583 if (code) goto done;
4585 /* decode times. We need a search time, but the response to this
4586 * call provides the date first, not the time, as returned in the
4587 * searchTime variable. So we take the high-order bits first.
4589 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
4590 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
4591 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
4592 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
4593 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
4594 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
4595 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
4597 /* now handle file size and allocation size */
4598 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
4599 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
4600 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
4601 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
4603 /* file attribute */
4604 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
4606 /* and finalize stuff */
4607 smb_SetSMBDataLength(outp, 0);
4611 lock_ReleaseMutex(&scp->mx);
4612 cm_ReleaseUser(userp);
4613 smb_ReleaseFID(fidp);
4617 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4631 fid = smb_GetSMBParm(inp, 0);
4632 fid = smb_ChainFID(fid, inp);
4634 fidp = smb_FindFID(vcp, fid, 0);
4635 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4636 return CM_ERROR_BADFD;
4639 userp = smb_GetUser(vcp, inp);
4643 /* now prepare to call cm_setattr. This message only sets various times,
4644 * and AFS only implements mtime, and we'll set the mtime if that's
4645 * requested. The others we'll ignore.
4647 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
4649 if (searchTime != 0) {
4650 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
4652 if ( unixTime != -1 ) {
4653 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
4654 attrs.clientModTime = unixTime;
4655 code = cm_SetAttr(scp, &attrs, userp, &req);
4657 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
4659 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
4664 cm_ReleaseUser(userp);
4665 smb_ReleaseFID(fidp);
4670 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4673 long count, finalCount;
4680 fd = smb_GetSMBParm(inp, 2);
4681 count = smb_GetSMBParm(inp, 5);
4682 offset.HighPart = 0; /* too bad */
4683 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
4685 osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
4686 fd, offset.LowPart, count);
4688 fd = smb_ChainFID(fd, inp);
4689 fidp = smb_FindFID(vcp, fd, 0);
4691 return CM_ERROR_BADFD;
4693 /* set inp->fid so that later read calls in same msg can find fid */
4696 if (fidp->flags & SMB_FID_IOCTL) {
4697 return smb_IoctlV3Read(fidp, vcp, inp, outp);
4700 userp = smb_GetUser(vcp, inp);
4702 /* 0 and 1 are reserved for request chaining, were setup by our caller,
4703 * and will be further filled in after we return.
4705 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
4706 smb_SetSMBParm(outp, 3, 0); /* resvd */
4707 smb_SetSMBParm(outp, 4, 0); /* resvd */
4708 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
4709 /* fill in #6 when we have all the parameters' space reserved */
4710 smb_SetSMBParm(outp, 7, 0); /* resv'd */
4711 smb_SetSMBParm(outp, 8, 0); /* resv'd */
4712 smb_SetSMBParm(outp, 9, 0); /* resv'd */
4713 smb_SetSMBParm(outp, 10, 0); /* resv'd */
4714 smb_SetSMBParm(outp, 11, 0); /* reserved */
4716 /* get op ptr after putting in the parms, since otherwise we don't
4717 * know where the data really is.
4719 op = smb_GetSMBData(outp, NULL);
4721 /* now fill in offset from start of SMB header to first data byte (to op) */
4722 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
4724 /* set the packet data length the count of the # of bytes */
4725 smb_SetSMBDataLength(outp, count);
4728 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
4730 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
4733 /* fix some things up */
4734 smb_SetSMBParm(outp, 5, finalCount);
4735 smb_SetSMBDataLength(outp, finalCount);
4737 smb_ReleaseFID(fidp);
4739 cm_ReleaseUser(userp);
4744 * Values for createDisp, copied from NTDDK.H
4746 #define FILE_SUPERSEDE 0 // (???)
4747 #define FILE_OPEN 1 // (open)
4748 #define FILE_CREATE 2 // (exclusive)
4749 #define FILE_OPEN_IF 3 // (non-exclusive)
4750 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
4751 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
4753 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4755 char *pathp, *realPathp;
4759 cm_scache_t *dscp; /* parent dir */
4760 cm_scache_t *scp; /* file to create or open */
4761 cm_scache_t *targetScp; /* if scp is a symlink */
4765 unsigned short nameLength;
4767 unsigned int requestOpLock;
4768 unsigned int requestBatchOpLock;
4769 unsigned int mustBeDir;
4770 unsigned int treeCreate;
4772 unsigned int desiredAccess;
4773 unsigned int extAttributes;
4774 unsigned int createDisp;
4775 unsigned int createOptions;
4776 int initialModeBits;
4777 unsigned short baseFid;
4778 smb_fid_t *baseFidp;
4780 cm_scache_t *baseDirp;
4781 unsigned short openAction;
4796 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
4797 flags = smb_GetSMBOffsetParm(inp, 3, 1)
4798 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
4799 requestOpLock = flags & 0x02;
4800 requestBatchOpLock = flags & 0x04;
4801 mustBeDir = flags & 0x08;
4804 * Why all of a sudden 32-bit FID?
4805 * We will reject all bits higher than 16.
4807 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
4808 return CM_ERROR_INVAL;
4809 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
4810 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
4811 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
4812 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
4813 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
4814 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
4815 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
4816 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
4817 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
4819 /* mustBeDir is never set; createOptions directory bit seems to be
4822 if (createOptions & 1)
4824 else if (createOptions & 0x40)
4830 * compute initial mode bits based on read-only flag in
4831 * extended attributes
4833 initialModeBits = 0666;
4834 if (extAttributes & 1)
4835 initialModeBits &= ~0222;
4837 pathp = smb_GetSMBData(inp, NULL);
4838 /* Sometimes path is not null-terminated, so we make a copy. */
4839 realPathp = malloc(nameLength+1);
4840 memcpy(realPathp, pathp, nameLength);
4841 realPathp[nameLength] = 0;
4843 spacep = inp->spacep;
4844 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
4846 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
4847 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
4848 osi_Log2(smb_logp,"... flags=[%x] lastNamep=[%s]", flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
4850 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4851 /* special case magic file name for receiving IOCTL requests
4852 * (since IOCTL calls themselves aren't getting through).
4854 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4855 smb_SetupIoctlFid(fidp, spacep);
4856 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
4858 /* set inp->fid so that later read calls in same msg can find fid */
4859 inp->fid = fidp->fid;
4863 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
4864 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4865 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
4867 memset(&ft, 0, sizeof(ft));
4868 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4869 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4870 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4871 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4872 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
4873 sz.HighPart = 0x7fff; sz.LowPart = 0;
4874 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
4875 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
4876 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
4877 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
4878 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
4879 smb_SetSMBDataLength(outp, 0);
4881 /* clean up fid reference */
4882 smb_ReleaseFID(fidp);
4887 #ifdef DEBUG_VERBOSE
4889 char *hexp, *asciip;
4890 asciip = (lastNamep? lastNamep : realPathp);
4891 hexp = osi_HexifyString( asciip );
4892 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
4896 userp = smb_GetUser(vcp, inp);
4898 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
4900 return CM_ERROR_INVAL;
4904 baseDirp = cm_rootSCachep;
4905 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4906 if (code == CM_ERROR_TIDIPC) {
4907 /* Attempt to use a TID allocated for IPC. The client
4908 * is probably looking for DCE RPC end points which we
4910 osi_Log0(smb_logp, "NTCreateX received IPC TID");
4912 cm_ReleaseUser(userp);
4913 return CM_ERROR_NOSUCHFILE;
4917 baseFidp = smb_FindFID(vcp, baseFid, 0);
4919 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
4921 cm_ReleaseUser(userp);
4922 return CM_ERROR_INVAL;
4924 baseDirp = baseFidp->scp;
4928 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
4930 /* compute open mode */
4932 if (desiredAccess & DELETE)
4933 fidflags |= SMB_FID_OPENDELETE;
4934 if (desiredAccess & AFS_ACCESS_READ)
4935 fidflags |= SMB_FID_OPENREAD;
4936 if (desiredAccess & AFS_ACCESS_WRITE)
4937 fidflags |= SMB_FID_OPENWRITE;
4941 /* For an exclusive create, we want to do a case sensitive match for the last component. */
4942 if ( createDisp == FILE_CREATE ||
4943 createDisp == FILE_OVERWRITE ||
4944 createDisp == FILE_OVERWRITE_IF) {
4945 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4946 userp, tidPathp, &req, &dscp);
4948 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
4950 if (code == CM_ERROR_NOSUCHFILE) {
4951 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
4952 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
4953 if (code == 0 && realDirFlag == 1) {
4954 cm_ReleaseSCache(scp);
4955 cm_ReleaseSCache(dscp);
4956 cm_ReleaseUser(userp);
4958 return CM_ERROR_EXISTS;
4964 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4965 userp, tidPathp, &req, &scp);
4970 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
4971 /* look up parent directory */
4972 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
4973 * the immediate parent. We have to work our way up realPathp until we hit something that we
4981 code = cm_NameI(baseDirp, spacep->data,
4982 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4983 userp, tidPathp, &req, &dscp);
4986 (tp = strrchr(spacep->data,'\\')) &&
4987 (createDisp == FILE_CREATE) &&
4988 (realDirFlag == 1)) {
4991 treeStartp = realPathp + (tp - spacep->data);
4993 if (*tp && !smb_IsLegalFilename(tp)) {
4995 smb_ReleaseFID(baseFidp);
4996 cm_ReleaseUser(userp);
4998 return CM_ERROR_BADNTFILENAME;
5008 smb_ReleaseFID(baseFidp);
5011 osi_Log0(smb_logp,"NTCreateX parent not found");
5012 cm_ReleaseUser(userp);
5017 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
5018 /* A file exists where we want a directory. */
5019 cm_ReleaseSCache(dscp);
5020 cm_ReleaseUser(userp);
5022 return CM_ERROR_EXISTS;
5026 lastNamep = realPathp;
5030 if (!smb_IsLegalFilename(lastNamep)) {
5031 cm_ReleaseSCache(dscp);
5032 cm_ReleaseUser(userp);
5034 return CM_ERROR_BADNTFILENAME;
5037 if (!foundscp && !treeCreate) {
5038 if ( createDisp == FILE_CREATE ||
5039 createDisp == FILE_OVERWRITE ||
5040 createDisp == FILE_OVERWRITE_IF)
5042 code = cm_Lookup(dscp, lastNamep,
5043 CM_FLAG_FOLLOW, userp, &req, &scp);
5045 code = cm_Lookup(dscp, lastNamep,
5046 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5049 if (code && code != CM_ERROR_NOSUCHFILE) {
5050 cm_ReleaseSCache(dscp);
5051 cm_ReleaseUser(userp);
5059 smb_ReleaseFID(baseFidp);
5062 /* if we get here, if code is 0, the file exists and is represented by
5063 * scp. Otherwise, we have to create it. The dir may be represented
5064 * by dscp, or we may have found the file directly. If code is non-zero,
5067 if (code == 0 && !treeCreate) {
5068 if (createDisp == FILE_CREATE) {
5069 /* oops, file shouldn't be there */
5070 if (dscp) cm_ReleaseSCache(dscp);
5071 cm_ReleaseSCache(scp);
5072 cm_ReleaseUser(userp);
5074 return CM_ERROR_EXISTS;
5077 if ( createDisp == FILE_OVERWRITE ||
5078 createDisp == FILE_OVERWRITE_IF) {
5079 setAttr.mask = CM_ATTRMASK_LENGTH;
5080 setAttr.length.LowPart = 0;
5081 setAttr.length.HighPart = 0;
5082 /* now watch for a symlink */
5084 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5086 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5088 /* we have a more accurate file to use (the
5089 * target of the symbolic link). Otherwise,
5090 * we'll just use the symlink anyway.
5092 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5094 cm_ReleaseSCache(scp);
5098 code = cm_SetAttr(scp, &setAttr, userp, &req);
5099 openAction = 3; /* truncated existing file */
5102 openAction = 1; /* found existing file */
5104 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
5107 if (dscp) cm_ReleaseSCache(dscp);
5108 cm_ReleaseSCache(scp);
5109 cm_ReleaseUser(userp);
5114 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
5115 /* don't create if not found */
5116 if (dscp) cm_ReleaseSCache(dscp);
5117 cm_ReleaseUser(userp);
5119 return CM_ERROR_NOSUCHFILE;
5121 else if (realDirFlag == 0 || realDirFlag == -1) {
5122 osi_assert(dscp != NULL);
5123 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
5124 osi_LogSaveString(smb_logp, lastNamep));
5125 openAction = 2; /* created file */
5126 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5127 setAttr.clientModTime = time(NULL);
5128 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5130 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5131 smb_NotifyChange(FILE_ACTION_ADDED,
5132 FILE_NOTIFY_CHANGE_FILE_NAME,
5133 dscp, lastNamep, NULL, TRUE);
5134 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
5135 /* Not an exclusive create, and someone else tried
5136 * creating it already, then we open it anyway. We
5137 * don't bother retrying after this, since if this next
5138 * fails, that means that the file was deleted after we
5139 * started this call.
5141 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5144 if (createDisp == FILE_OVERWRITE_IF) {
5145 setAttr.mask = CM_ATTRMASK_LENGTH;
5146 setAttr.length.LowPart = 0;
5147 setAttr.length.HighPart = 0;
5149 /* now watch for a symlink */
5151 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5153 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5155 /* we have a more accurate file to use (the
5156 * target of the symbolic link). Otherwise,
5157 * we'll just use the symlink anyway.
5159 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5161 cm_ReleaseSCache(scp);
5165 code = cm_SetAttr(scp, &setAttr, userp, &req);
5167 } /* lookup succeeded */
5172 char *cp; /* This component */
5173 int clen = 0; /* length of component */
5177 /* create directory */
5179 treeStartp = lastNamep;
5180 osi_assert(dscp != NULL);
5181 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
5182 osi_LogSaveString(smb_logp, treeStartp));
5183 openAction = 2; /* created directory */
5185 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5186 setAttr.clientModTime = time(NULL);
5193 tp = strchr(pp, '\\');
5197 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
5201 strncpy(cp,pp,clen);
5208 continue; /* the supplied path can't have consecutive slashes either , but */
5210 /* cp is the next component to be created. */
5211 code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
5212 if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
5213 smb_NotifyChange(FILE_ACTION_ADDED,
5214 FILE_NOTIFY_CHANGE_DIR_NAME,
5215 tscp, cp, NULL, TRUE);
5217 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
5218 /* Not an exclusive create, and someone else tried
5219 * creating it already, then we open it anyway. We
5220 * don't bother retrying after this, since if this next
5221 * fails, that means that the file was deleted after we
5222 * started this call.
5224 code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
5229 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
5230 cm_ReleaseSCache(tscp);
5231 tscp = scp; /* Newly created directory will be next parent */
5236 * if we get here and code == 0, then scp is the last directory created, and tscp is the
5237 * parent of scp. dscp got released if dscp != tscp. both tscp and scp are held.
5243 /* something went wrong creating or truncating the file */
5244 if (scp) cm_ReleaseSCache(scp);
5245 if (dscp) cm_ReleaseSCache(dscp);
5246 cm_ReleaseUser(userp);
5251 /* make sure we have file vs. dir right (only applies for single component case) */
5252 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5253 /* now watch for a symlink */
5255 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5256 cm_scache_t * targetScp = 0;
5257 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5259 /* we have a more accurate file to use (the
5260 * target of the symbolic link). Otherwise,
5261 * we'll just use the symlink anyway.
5263 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5265 cm_ReleaseSCache(scp);
5270 if (scp->fileType != CM_SCACHETYPE_FILE) {
5271 cm_ReleaseSCache(scp);
5272 cm_ReleaseUser(userp);
5274 return CM_ERROR_ISDIR;
5278 /* (only applies to single component case) */
5279 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5280 cm_ReleaseSCache(scp);
5281 if (dscp) cm_ReleaseSCache(dscp);
5282 cm_ReleaseUser(userp);
5284 return CM_ERROR_NOTDIR;
5287 /* open the file itself */
5288 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5290 /* save a pointer to the vnode */
5293 fidp->flags = fidflags;
5295 /* save parent dir and pathname for delete or change notification */
5296 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5297 fidp->flags |= SMB_FID_NTOPEN;
5298 fidp->NTopen_dscp = dscp;
5299 cm_HoldSCache(dscp);
5300 fidp->NTopen_pathp = strdup(lastNamep);
5302 fidp->NTopen_wholepathp = realPathp;
5304 /* we don't need this any longer */
5305 if (dscp) cm_ReleaseSCache(dscp);
5306 cm_Open(scp, 0, userp);
5308 /* set inp->fid so that later read calls in same msg can find fid */
5309 inp->fid = fidp->fid;
5313 lock_ObtainMutex(&scp->mx);
5314 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5315 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5316 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
5317 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5318 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5319 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5320 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5321 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5322 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
5324 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5325 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5326 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
5327 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
5328 smb_SetSMBParmByte(outp, parmSlot,
5329 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
5330 lock_ReleaseMutex(&scp->mx);
5331 smb_SetSMBDataLength(outp, 0);
5333 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
5334 osi_LogSaveString(smb_logp, realPathp));
5336 smb_ReleaseFID(fidp);
5338 cm_ReleaseUser(userp);
5340 /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
5342 /* leave scp held since we put it in fidp->scp */
5347 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
5348 * Instead, ultimately, would like to use a subroutine for common code.
5350 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5352 char *pathp, *realPathp;
5356 cm_scache_t *dscp; /* parent dir */
5357 cm_scache_t *scp; /* file to create or open */
5358 cm_scache_t *targetScp; /* if scp is a symlink */
5361 unsigned long nameLength;
5363 unsigned int requestOpLock;
5364 unsigned int requestBatchOpLock;
5365 unsigned int mustBeDir;
5366 unsigned int extendedRespRequired;
5368 unsigned int desiredAccess;
5369 #ifdef DEBUG_VERBOSE
5370 unsigned int allocSize;
5371 unsigned int shareAccess;
5373 unsigned int extAttributes;
5374 unsigned int createDisp;
5375 #ifdef DEBUG_VERBOSE
5378 unsigned int createOptions;
5379 int initialModeBits;
5380 unsigned short baseFid;
5381 smb_fid_t *baseFidp;
5383 cm_scache_t *baseDirp;
5384 unsigned short openAction;
5390 int parmOffset, dataOffset;
5401 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
5402 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
5403 parmp = inp->data + parmOffset;
5404 lparmp = (ULONG *) parmp;
5407 requestOpLock = flags & 0x02;
5408 requestBatchOpLock = flags & 0x04;
5409 mustBeDir = flags & 0x08;
5410 extendedRespRequired = flags & 0x10;
5413 * Why all of a sudden 32-bit FID?
5414 * We will reject all bits higher than 16.
5416 if (lparmp[1] & 0xFFFF0000)
5417 return CM_ERROR_INVAL;
5418 baseFid = (unsigned short)lparmp[1];
5419 desiredAccess = lparmp[2];
5420 #ifdef DEBUG_VERBOSE
5421 allocSize = lparmp[3];
5422 #endif /* DEBUG_VERSOSE */
5423 extAttributes = lparmp[5];
5425 shareAccess = lparmp[6];
5427 createDisp = lparmp[7];
5428 createOptions = lparmp[8];
5429 #ifdef DEBUG_VERBOSE
5432 nameLength = lparmp[11];
5434 #ifdef DEBUG_VERBOSE
5435 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
5436 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
5437 osi_Log1(smb_logp,"... flags[%x]",flags);
5440 /* mustBeDir is never set; createOptions directory bit seems to be
5443 if (createOptions & 1)
5445 else if (createOptions & 0x40)
5451 * compute initial mode bits based on read-only flag in
5452 * extended attributes
5454 initialModeBits = 0666;
5455 if (extAttributes & 1)
5456 initialModeBits &= ~0222;
5458 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
5459 /* Sometimes path is not null-terminated, so we make a copy. */
5460 realPathp = malloc(nameLength+1);
5461 memcpy(realPathp, pathp, nameLength);
5462 realPathp[nameLength] = 0;
5464 spacep = cm_GetSpace();
5465 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5468 * Nothing here to handle SMB_IOCTL_FILENAME.
5469 * Will add it if necessary.
5472 #ifdef DEBUG_VERBOSE
5474 char *hexp, *asciip;
5475 asciip = (lastNamep? lastNamep : realPathp);
5476 hexp = osi_HexifyString( asciip );
5477 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
5482 userp = smb_GetUser(vcp, inp);
5484 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
5486 return CM_ERROR_INVAL;
5490 baseDirp = cm_rootSCachep;
5491 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5492 if(code == CM_ERROR_TIDIPC) {
5493 /* Attempt to use TID allocated for IPC. The client is
5494 * probably trying to locate DCE RPC endpoints, which we
5496 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
5498 cm_ReleaseUser(userp);
5499 return CM_ERROR_NOSUCHPATH;
5503 baseFidp = smb_FindFID(vcp, baseFid, 0);
5505 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
5507 cm_ReleaseUser(userp);
5508 return CM_ERROR_INVAL;
5510 baseDirp = baseFidp->scp;
5514 /* compute open mode */
5516 if (desiredAccess & DELETE)
5517 fidflags |= SMB_FID_OPENDELETE;
5518 if (desiredAccess & AFS_ACCESS_READ)
5519 fidflags |= SMB_FID_OPENREAD;
5520 if (desiredAccess & AFS_ACCESS_WRITE)
5521 fidflags |= SMB_FID_OPENWRITE;
5525 if ( createDisp == FILE_OPEN ||
5526 createDisp == FILE_OVERWRITE ||
5527 createDisp == FILE_OVERWRITE_IF) {
5528 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5529 userp, tidPathp, &req, &dscp);
5531 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5533 if (code == CM_ERROR_NOSUCHFILE) {
5534 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
5535 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
5536 if (code == 0 && realDirFlag == 1) {
5537 cm_ReleaseSCache(scp);
5538 cm_ReleaseSCache(dscp);
5539 cm_ReleaseUser(userp);
5541 return CM_ERROR_EXISTS;
5547 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5548 userp, tidPathp, &req, &scp);
5554 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
5555 /* look up parent directory */
5557 code = cm_NameI(baseDirp, spacep->data,
5558 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5559 userp, tidPathp, &req, &dscp);
5563 cm_FreeSpace(spacep);
5566 smb_ReleaseFID(baseFidp);
5571 cm_ReleaseUser(userp);
5576 if (!lastNamep) lastNamep = realPathp;
5579 if (!smb_IsLegalFilename(lastNamep))
5580 return CM_ERROR_BADNTFILENAME;
5583 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
5584 code = cm_Lookup(dscp, lastNamep,
5585 CM_FLAG_FOLLOW, userp, &req, &scp);
5587 code = cm_Lookup(dscp, lastNamep,
5588 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5591 if (code && code != CM_ERROR_NOSUCHFILE) {
5592 cm_ReleaseSCache(dscp);
5593 cm_ReleaseUser(userp);
5601 smb_ReleaseFID(baseFidp);
5604 cm_FreeSpace(spacep);
5607 /* if we get here, if code is 0, the file exists and is represented by
5608 * scp. Otherwise, we have to create it. The dir may be represented
5609 * by dscp, or we may have found the file directly. If code is non-zero,
5613 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
5616 if (dscp) cm_ReleaseSCache(dscp);
5617 cm_ReleaseSCache(scp);
5618 cm_ReleaseUser(userp);
5623 if (createDisp == FILE_CREATE) {
5624 /* oops, file shouldn't be there */
5625 if (dscp) cm_ReleaseSCache(dscp);
5626 cm_ReleaseSCache(scp);
5627 cm_ReleaseUser(userp);
5629 return CM_ERROR_EXISTS;
5632 if (createDisp == FILE_OVERWRITE ||
5633 createDisp == FILE_OVERWRITE_IF) {
5634 setAttr.mask = CM_ATTRMASK_LENGTH;
5635 setAttr.length.LowPart = 0;
5636 setAttr.length.HighPart = 0;
5638 /* now watch for a symlink */
5640 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5642 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5644 /* we have a more accurate file to use (the
5645 * target of the symbolic link). Otherwise,
5646 * we'll just use the symlink anyway.
5648 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5650 cm_ReleaseSCache(scp);
5654 code = cm_SetAttr(scp, &setAttr, userp, &req);
5655 openAction = 3; /* truncated existing file */
5657 else openAction = 1; /* found existing file */
5659 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
5660 /* don't create if not found */
5661 if (dscp) cm_ReleaseSCache(dscp);
5662 cm_ReleaseUser(userp);
5664 return CM_ERROR_NOSUCHFILE;
5666 else if (realDirFlag == 0 || realDirFlag == -1) {
5667 osi_assert(dscp != NULL);
5668 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
5669 osi_LogSaveString(smb_logp, lastNamep));
5670 openAction = 2; /* created file */
5671 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5672 setAttr.clientModTime = time(NULL);
5673 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5675 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5676 smb_NotifyChange(FILE_ACTION_ADDED,
5677 FILE_NOTIFY_CHANGE_FILE_NAME,
5678 dscp, lastNamep, NULL, TRUE);
5679 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
5680 /* Not an exclusive create, and someone else tried
5681 * creating it already, then we open it anyway. We
5682 * don't bother retrying after this, since if this next
5683 * fails, that means that the file was deleted after we
5684 * started this call.
5686 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5689 if (createDisp == FILE_OVERWRITE_IF) {
5690 setAttr.mask = CM_ATTRMASK_LENGTH;
5691 setAttr.length.LowPart = 0;
5692 setAttr.length.HighPart = 0;
5694 /* now watch for a symlink */
5696 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5698 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5700 /* we have a more accurate file to use (the
5701 * target of the symbolic link). Otherwise,
5702 * we'll just use the symlink anyway.
5704 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5706 cm_ReleaseSCache(scp);
5710 code = cm_SetAttr(scp, &setAttr, userp, &req);
5712 } /* lookup succeeded */
5716 /* create directory */
5717 osi_assert(dscp != NULL);
5719 "smb_ReceiveNTTranCreate creating directory %s",
5720 osi_LogSaveString(smb_logp, lastNamep));
5721 openAction = 2; /* created directory */
5722 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5723 setAttr.clientModTime = time(NULL);
5724 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5725 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5726 smb_NotifyChange(FILE_ACTION_ADDED,
5727 FILE_NOTIFY_CHANGE_DIR_NAME,
5728 dscp, lastNamep, NULL, TRUE);
5730 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
5731 /* Not an exclusive create, and someone else tried
5732 * creating it already, then we open it anyway. We
5733 * don't bother retrying after this, since if this next
5734 * fails, that means that the file was deleted after we
5735 * started this call.
5737 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5743 /* something went wrong creating or truncating the file */
5744 if (scp) cm_ReleaseSCache(scp);
5745 cm_ReleaseUser(userp);
5750 /* make sure we have file vs. dir right */
5751 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5752 /* now watch for a symlink */
5754 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5756 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5758 /* we have a more accurate file to use (the
5759 * target of the symbolic link). Otherwise,
5760 * we'll just use the symlink anyway.
5762 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5764 cm_ReleaseSCache(scp);
5769 if (scp->fileType != CM_SCACHETYPE_FILE) {
5770 cm_ReleaseSCache(scp);
5771 cm_ReleaseUser(userp);
5773 return CM_ERROR_ISDIR;
5777 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5778 cm_ReleaseSCache(scp);
5779 cm_ReleaseUser(userp);
5781 return CM_ERROR_NOTDIR;
5784 /* open the file itself */
5785 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5788 /* save a pointer to the vnode */
5791 fidp->flags = fidflags;
5793 /* save parent dir and pathname for deletion or change notification */
5794 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5795 fidp->flags |= SMB_FID_NTOPEN;
5796 fidp->NTopen_dscp = dscp;
5797 cm_HoldSCache(dscp);
5798 fidp->NTopen_pathp = strdup(lastNamep);
5800 fidp->NTopen_wholepathp = realPathp;
5802 /* we don't need this any longer */
5803 if (dscp) cm_ReleaseSCache(dscp);
5805 cm_Open(scp, 0, userp);
5807 /* set inp->fid so that later read calls in same msg can find fid */
5808 inp->fid = fidp->fid;
5810 /* check whether we are required to send an extended response */
5811 if (!extendedRespRequired) {
5813 parmOffset = 8*4 + 39;
5814 parmOffset += 1; /* pad to 4 */
5815 dataOffset = parmOffset + 70;
5819 /* Total Parameter Count */
5820 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
5821 /* Total Data Count */
5822 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5823 /* Parameter Count */
5824 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
5825 /* Parameter Offset */
5826 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5827 /* Parameter Displacement */
5828 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5830 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5832 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5833 /* Data Displacement */
5834 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5835 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5836 smb_SetSMBDataLength(outp, 70);
5838 lock_ObtainMutex(&scp->mx);
5839 outData = smb_GetSMBData(outp, NULL);
5840 outData++; /* round to get to parmOffset */
5841 *outData = 0; outData++; /* oplock */
5842 *outData = 0; outData++; /* reserved */
5843 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
5844 *((ULONG *)outData) = openAction; outData += 4;
5845 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
5846 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5847 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
5848 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
5849 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
5850 *((FILETIME *)outData) = ft; outData += 8; /* change time */
5851 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
5852 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
5853 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
5854 *((USHORT *)outData) = 0; outData += 2; /* filetype */
5855 *((USHORT *)outData) = 0; outData += 2; /* dev state */
5856 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
5857 outData += 2; /* is a dir? */
5858 lock_ReleaseMutex(&scp->mx);
5861 parmOffset = 8*4 + 39;
5862 parmOffset += 1; /* pad to 4 */
5863 dataOffset = parmOffset + 104;
5867 /* Total Parameter Count */
5868 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
5869 /* Total Data Count */
5870 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5871 /* Parameter Count */
5872 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
5873 /* Parameter Offset */
5874 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5875 /* Parameter Displacement */
5876 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5878 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5880 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5881 /* Data Displacement */
5882 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5883 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5884 smb_SetSMBDataLength(outp, 105);
5886 lock_ObtainMutex(&scp->mx);
5887 outData = smb_GetSMBData(outp, NULL);
5888 outData++; /* round to get to parmOffset */
5889 *outData = 0; outData++; /* oplock */
5890 *outData = 1; outData++; /* response type */
5891 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
5892 *((ULONG *)outData) = openAction; outData += 4;
5893 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
5894 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5895 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
5896 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
5897 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
5898 *((FILETIME *)outData) = ft; outData += 8; /* change time */
5899 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
5900 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
5901 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
5902 *((USHORT *)outData) = 0; outData += 2; /* filetype */
5903 *((USHORT *)outData) = 0; outData += 2; /* dev state */
5904 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
5905 outData += 1; /* is a dir? */
5906 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
5907 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
5908 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
5909 lock_ReleaseMutex(&scp->mx);
5912 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
5914 smb_ReleaseFID(fidp);
5916 cm_ReleaseUser(userp);
5918 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
5919 /* leave scp held since we put it in fidp->scp */
5923 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
5926 smb_packet_t *savedPacketp;
5927 ULONG filter; USHORT fid, watchtree;
5931 filter = smb_GetSMBParm(inp, 19) |
5932 (smb_GetSMBParm(inp, 20) << 16);
5933 fid = smb_GetSMBParm(inp, 21);
5934 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
5936 fidp = smb_FindFID(vcp, fid, 0);
5938 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
5939 return CM_ERROR_BADFD;
5942 savedPacketp = smb_CopyPacket(inp);
5944 savedPacketp->vcp = vcp;
5945 lock_ObtainMutex(&smb_Dir_Watch_Lock);
5946 savedPacketp->nextp = smb_Directory_Watches;
5947 smb_Directory_Watches = savedPacketp;
5948 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
5950 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
5951 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
5954 lock_ObtainMutex(&scp->mx);
5956 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
5958 scp->flags |= CM_SCACHEFLAG_WATCHED;
5959 lock_ReleaseMutex(&scp->mx);
5960 smb_ReleaseFID(fidp);
5962 outp->flags |= SMB_PACKETFLAG_NOSEND;
5966 unsigned char nullSecurityDesc[36] = {
5967 0x01, /* security descriptor revision */
5968 0x00, /* reserved, should be zero */
5969 0x00, 0x80, /* security descriptor control;
5970 * 0x8000 : self-relative format */
5971 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
5972 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
5973 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
5974 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
5975 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5976 /* "null SID" owner SID */
5977 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5978 /* "null SID" group SID */
5981 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5983 int parmOffset, parmCount, dataOffset, dataCount;
5991 ULONG securityInformation;
5993 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
5994 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
5995 parmp = inp->data + parmOffset;
5996 sparmp = (USHORT *) parmp;
5997 lparmp = (ULONG *) parmp;
6000 securityInformation = lparmp[1];
6002 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
6003 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6011 parmOffset = 8*4 + 39;
6012 parmOffset += 1; /* pad to 4 */
6014 dataOffset = parmOffset + parmCount;
6018 /* Total Parameter Count */
6019 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6020 /* Total Data Count */
6021 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6022 /* Parameter Count */
6023 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6024 /* Parameter Offset */
6025 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6026 /* Parameter Displacement */
6027 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6029 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6031 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6032 /* Data Displacement */
6033 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6034 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6035 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
6037 outData = smb_GetSMBData(outp, NULL);
6038 outData++; /* round to get to parmOffset */
6039 *((ULONG *)outData) = 36; outData += 4; /* length */
6041 if (maxData >= 36) {
6042 memcpy(outData, nullSecurityDesc, 36);
6046 return CM_ERROR_BUFFERTOOSMALL;
6049 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6051 unsigned short function;
6053 function = smb_GetSMBParm(inp, 18);
6055 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
6057 /* We can handle long names */
6058 if (vcp->flags & SMB_VCFLAG_USENT)
6059 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
6063 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
6065 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
6067 return smb_ReceiveNTTranCreate(vcp, inp, outp);
6069 return CM_ERROR_INVAL;
6074 * smb_NotifyChange -- find relevant change notification messages and
6077 * If we don't know the file name (i.e. a callback break), filename is
6078 * NULL, and we return a zero-length list.
6080 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
6081 cm_scache_t *dscp, char *filename, char *otherFilename,
6082 BOOL isDirectParent)
6084 smb_packet_t *watch, *lastWatch, *nextWatch;
6085 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
6086 char *outData, *oldOutData;
6090 BOOL twoEntries = FALSE;
6091 ULONG otherNameLen, oldParmCount = 0;
6096 /* Get ready for rename within directory */
6097 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
6099 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
6102 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
6103 osi_LogSaveString(smb_logp,filename),dscp);
6105 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6106 watch = smb_Directory_Watches;
6108 filter = smb_GetSMBParm(watch, 19)
6109 | (smb_GetSMBParm(watch, 20) << 16);
6110 fid = smb_GetSMBParm(watch, 21);
6111 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
6112 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
6113 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
6117 * Strange hack - bug in NT Client and NT Server that we
6120 if (filter == 3 && wtree)
6123 fidp = smb_FindFID(vcp, fid, 0);
6125 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
6127 watch = watch->nextp;
6130 if (fidp->scp != dscp
6131 || (filter & notifyFilter) == 0
6132 || (!isDirectParent && !wtree)) {
6133 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
6134 smb_ReleaseFID(fidp);
6136 watch = watch->nextp;
6139 smb_ReleaseFID(fidp);
6142 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
6143 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
6145 nextWatch = watch->nextp;
6146 if (watch == smb_Directory_Watches)
6147 smb_Directory_Watches = nextWatch;
6149 lastWatch->nextp = nextWatch;
6151 /* Turn off WATCHED flag in dscp */
6152 lock_ObtainMutex(&dscp->mx);
6154 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6156 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
6157 lock_ReleaseMutex(&dscp->mx);
6159 /* Convert to response packet */
6160 ((smb_t *) watch)->reb = 0x80;
6161 ((smb_t *) watch)->wct = 0;
6164 if (filename == NULL)
6167 nameLen = strlen(filename);
6168 parmCount = 3*4 + nameLen*2;
6169 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6171 otherNameLen = strlen(otherFilename);
6172 oldParmCount = parmCount;
6173 parmCount += 3*4 + otherNameLen*2;
6174 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6176 if (maxLen < parmCount)
6177 parmCount = 0; /* not enough room */
6179 parmOffset = 8*4 + 39;
6180 parmOffset += 1; /* pad to 4 */
6181 dataOffset = parmOffset + parmCount;
6185 /* Total Parameter Count */
6186 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6187 /* Total Data Count */
6188 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6189 /* Parameter Count */
6190 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6191 /* Parameter Offset */
6192 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
6193 /* Parameter Displacement */
6194 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6196 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6198 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
6199 /* Data Displacement */
6200 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6201 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
6202 smb_SetSMBDataLength(watch, parmCount + 1);
6204 if (parmCount != 0) {
6205 outData = smb_GetSMBData(watch, NULL);
6206 outData++; /* round to get to parmOffset */
6207 oldOutData = outData;
6208 *((DWORD *)outData) = oldParmCount; outData += 4;
6209 /* Next Entry Offset */
6210 *((DWORD *)outData) = action; outData += 4;
6212 *((DWORD *)outData) = nameLen*2; outData += 4;
6213 /* File Name Length */
6214 mbstowcs((WCHAR *)outData, filename, nameLen);
6217 outData = oldOutData + oldParmCount;
6218 *((DWORD *)outData) = 0; outData += 4;
6219 /* Next Entry Offset */
6220 *((DWORD *)outData) = otherAction; outData += 4;
6222 *((DWORD *)outData) = otherNameLen*2;
6223 outData += 4; /* File Name Length */
6224 mbstowcs((WCHAR *)outData, otherFilename,
6225 otherNameLen); /* File Name */
6230 * If filename is null, we don't know the cause of the
6231 * change notification. We return zero data (see above),
6232 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
6233 * (= 0x010C). We set the error code here by hand, without
6234 * modifying wct and bcc.
6236 if (filename == NULL) {
6237 ((smb_t *) watch)->rcls = 0x0C;
6238 ((smb_t *) watch)->reh = 0x01;
6239 ((smb_t *) watch)->errLow = 0;
6240 ((smb_t *) watch)->errHigh = 0;
6241 /* Set NT Status codes flag */
6242 ((smb_t *) watch)->flg2 |= 0x4000;
6245 smb_SendPacket(vcp, watch);
6247 smb_FreePacket(watch);
6250 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6253 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6255 unsigned char *replyWctp;
6256 smb_packet_t *watch, *lastWatch;
6257 USHORT fid, watchtree;
6261 osi_Log0(smb_logp, "SMB3 receive NT cancel");
6263 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6264 watch = smb_Directory_Watches;
6266 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
6267 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
6268 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
6269 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
6270 if (watch == smb_Directory_Watches)
6271 smb_Directory_Watches = watch->nextp;
6273 lastWatch->nextp = watch->nextp;
6274 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6276 /* Turn off WATCHED flag in scp */
6277 fid = smb_GetSMBParm(watch, 21);
6278 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
6280 if (vcp != watch->vcp)
6281 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
6284 fidp = smb_FindFID(vcp, fid, 0);
6286 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
6288 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
6291 lock_ObtainMutex(&scp->mx);
6293 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6295 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
6296 lock_ReleaseMutex(&scp->mx);
6297 smb_ReleaseFID(fidp);
6299 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
6302 /* assume STATUS32; return 0xC0000120 (CANCELED) */
6303 replyWctp = watch->wctp;
6307 ((smb_t *)watch)->rcls = 0x20;
6308 ((smb_t *)watch)->reh = 0x1;
6309 ((smb_t *)watch)->errLow = 0;
6310 ((smb_t *)watch)->errHigh = 0xC0;
6311 ((smb_t *)watch)->flg2 |= 0x4000;
6312 smb_SendPacket(vcp, watch);
6314 smb_ReleaseVC(watch->vcp);
6315 smb_FreePacket(watch);
6319 watch = watch->nextp;
6321 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6327 * NT rename also does hard links.
6330 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
6331 #define RENAME_FLAG_HARD_LINK 0x103
6332 #define RENAME_FLAG_RENAME 0x104
6333 #define RENAME_FLAG_COPY 0x105
6335 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6337 char *oldname, *newname;
6344 attrs = smb_GetSMBParm(inp, 0);
6345 rename_type = smb_GetSMBParm(inp, 1);
6347 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
6348 osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
6349 return CM_ERROR_NOACCESS;
6352 tp = smb_GetSMBData(inp, NULL);
6353 oldname = smb_ParseASCIIBlock(tp, &tp);
6354 newname = smb_ParseASCIIBlock(tp, &tp);
6356 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
6357 osi_LogSaveString(smb_logp, oldname),
6358 osi_LogSaveString(smb_logp, newname),
6359 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
6361 if (rename_type == RENAME_FLAG_RENAME) {
6362 code = smb_Rename(vcp,inp,oldname,newname,attrs);
6363 } else { /* RENAME_FLAG_HARD_LINK */
6364 code = smb_Link(vcp,inp,oldname,newname);
6371 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
6374 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
6377 smb_username_t *unp;
6379 unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
6381 lock_ObtainMutex(&unp->mx);
6382 unp->userp = cm_NewUser();
6383 lock_ReleaseMutex(&unp->mx);
6384 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6385 osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
6387 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6388 osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);