2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
15 #define SECURITY_WIN32
30 extern osi_hyper_t hzero;
32 smb_packet_t *smb_Directory_Watches = NULL;
33 osi_mutex_t smb_Dir_Watch_Lock;
35 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
37 /* protected by the smb_globalLock */
38 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
40 /* retrieve a held reference to a user structure corresponding to an incoming
42 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
47 uidp = smb_FindUID(vcp, inp->uid, 0);
48 if (!uidp) return NULL;
50 lock_ObtainMutex(&uidp->mx);
52 up = uidp->unp->userp;
55 lock_ReleaseMutex(&uidp->mx);
63 * Return extended attributes.
64 * Right now, we aren't using any of the "new" bits, so this looks exactly
65 * like smb_Attributes() (see smb.c).
67 unsigned long smb_ExtAttributes(cm_scache_t *scp)
71 if (scp->fileType == CM_SCACHETYPE_DIRECTORY
72 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
73 attrs = SMB_ATTR_DIRECTORY;
77 * We used to mark a file RO if it was in an RO volume, but that
78 * turns out to be impolitic in NT. See defect 10007.
81 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
83 if ((scp->unixModeBits & 0222) == 0)
84 attrs |= SMB_ATTR_READONLY; /* Read-only */
87 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
92 int smb_V3IsStarMask(char *maskp)
97 if (tc == '?' || tc == '*')
102 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
105 /* skip over null-terminated string */
106 *chainpp = inp + strlen(inp) + 1;
111 /*DEBUG do not checkin*/
112 void OutputDebugF(char * format, ...) {
118 va_start( args, format );
119 len = _vscprintf( format, args ) // _vscprintf doesn't count
120 + 3; // terminating '\0' + '\n'
121 buffer = malloc( len * sizeof(char) );
122 vsprintf( buffer, format, args );
123 strcat(buffer, "\n");
124 OutputDebugString(buffer);
129 void OutputDebugHexDump(unsigned char * buffer, int len) {
133 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
135 OutputDebugF("Hexdump length [%d]",len);
140 OutputDebugString(buf);
141 sprintf(buf,"%5x",i);
142 memset(buf+5,' ',80);
148 j = j*3 + 7 + ((j>7)?1:0);
151 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
154 j = j + 56 + ((j>7)?1:0);
156 buf[j] = (k>32 && k<127)?k:'.';
159 OutputDebugString(buf);
164 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
165 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength){
166 SECURITY_STATUS status, istatus;
167 CredHandle creds = {0,0};
169 SecBufferDesc secOut;
177 OutputDebugF("Negotiating Extended Security");
179 status = AcquireCredentialsHandle(
181 SMB_EXT_SEC_PACKAGE_NAME,
190 if (status != SEC_E_OK) {
191 /* Really bad. We return an empty security blob */
192 OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
197 secOut.pBuffers = &secTok;
198 secOut.ulVersion = SECBUFFER_VERSION;
200 secTok.BufferType = SECBUFFER_TOKEN;
202 secTok.pvBuffer = NULL;
204 ctx.dwLower = ctx.dwUpper = 0;
206 status = AcceptSecurityContext(
210 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
211 SECURITY_NETWORK_DREP,
218 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
219 OutputDebugF("Completing token...");
220 istatus = CompleteAuthToken(&ctx, &secOut);
221 if ( istatus != SEC_E_OK )
222 OutputDebugF("Token completion failed: %x", istatus);
225 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
226 if (secTok.pvBuffer) {
227 *secBlobLength = secTok.cbBuffer;
228 *secBlob = malloc( secTok.cbBuffer );
229 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
232 if ( status != SEC_E_OK )
233 OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
236 /* Discard partial security context */
237 DeleteSecurityContext(&ctx);
239 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
241 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
242 FreeCredentialsHandle(&creds);
248 struct smb_ext_context {
255 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
256 SECURITY_STATUS status, istatus;
260 SecBufferDesc secBufIn;
262 SecBufferDesc secBufOut;
265 struct smb_ext_context * secCtx = NULL;
266 struct smb_ext_context * newSecCtx = NULL;
267 void * assembledBlob = NULL;
268 int assembledBlobLength = 0;
271 OutputDebugF("In smb_AuthenticateUserExt");
274 *secBlobOutLength = 0;
276 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
277 secCtx = vcp->secCtx;
278 lock_ObtainMutex(&vcp->mx);
279 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
281 lock_ReleaseMutex(&vcp->mx);
285 OutputDebugF("Received incoming token:");
286 OutputDebugHexDump(secBlobIn,secBlobInLength);
290 OutputDebugF("Continuing with existing context.");
291 creds = secCtx->creds;
294 if (secCtx->partialToken) {
295 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
296 assembledBlob = malloc(assembledBlobLength);
297 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
298 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
301 status = AcquireCredentialsHandle(
303 SMB_EXT_SEC_PACKAGE_NAME,
312 if (status != SEC_E_OK) {
313 OutputDebugF("Can't acquire Credentials handle [%lX]", status);
314 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
322 secBufIn.cBuffers = 1;
323 secBufIn.pBuffers = &secTokIn;
324 secBufIn.ulVersion = SECBUFFER_VERSION;
326 secTokIn.BufferType = SECBUFFER_TOKEN;
328 secTokIn.cbBuffer = assembledBlobLength;
329 secTokIn.pvBuffer = assembledBlob;
331 secTokIn.cbBuffer = secBlobInLength;
332 secTokIn.pvBuffer = secBlobIn;
335 secBufOut.cBuffers = 1;
336 secBufOut.pBuffers = &secTokOut;
337 secBufOut.ulVersion = SECBUFFER_VERSION;
339 secTokOut.BufferType = SECBUFFER_TOKEN;
340 secTokOut.cbBuffer = 0;
341 secTokOut.pvBuffer = NULL;
343 status = AcceptSecurityContext(
345 ((secCtx)?&ctx:NULL),
347 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
348 SECURITY_NETWORK_DREP,
355 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
356 OutputDebugF("Completing token...");
357 istatus = CompleteAuthToken(&ctx, &secBufOut);
358 if ( istatus != SEC_E_OK )
359 OutputDebugF("Token completion failed: %lX", istatus);
362 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
363 OutputDebugF("Continue needed");
365 newSecCtx = malloc(sizeof(*newSecCtx));
367 newSecCtx->creds = creds;
368 newSecCtx->ctx = ctx;
369 newSecCtx->partialToken = NULL;
370 newSecCtx->partialTokenLen = 0;
372 lock_ObtainMutex( &vcp->mx );
373 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
374 vcp->secCtx = newSecCtx;
375 lock_ReleaseMutex( &vcp->mx );
377 code = CM_ERROR_GSSCONTINUE;
380 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
381 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
382 secTokOut.pvBuffer) {
383 OutputDebugF("Need to send token back to client");
385 *secBlobOutLength = secTokOut.cbBuffer;
386 *secBlobOut = malloc(secTokOut.cbBuffer);
387 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
389 OutputDebugF("Outgoing token:");
390 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
391 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
392 OutputDebugF("Incomplete message");
394 newSecCtx = malloc(sizeof(*newSecCtx));
396 newSecCtx->creds = creds;
397 newSecCtx->ctx = ctx;
398 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
399 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
400 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
402 lock_ObtainMutex( &vcp->mx );
403 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
404 vcp->secCtx = newSecCtx;
405 lock_ReleaseMutex( &vcp->mx );
407 code = CM_ERROR_GSSCONTINUE;
410 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
412 SecPkgContext_Names names;
414 OutputDebugF("Authentication completed");
415 OutputDebugF("Returned flags : [%lX]", flags);
417 if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
418 OutputDebugF("Received name [%s]", names.sUserName);
419 strcpy(usern, names.sUserName);
420 strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
421 FreeContextBuffer(names.sUserName);
423 /* Force the user to retry if the context is invalid */
424 OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
425 code = CM_ERROR_BADPASSWORD;
429 case SEC_E_INVALID_TOKEN:
430 OutputDebugF("Returning bad password :: INVALID_TOKEN");
432 case SEC_E_INVALID_HANDLE:
433 OutputDebugF("Returning bad password :: INVALID_HANDLE");
435 case SEC_E_LOGON_DENIED:
436 OutputDebugF("Returning bad password :: LOGON_DENIED");
438 case SEC_E_UNKNOWN_CREDENTIALS:
439 OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
441 case SEC_E_NO_CREDENTIALS:
442 OutputDebugF("Returning bad password :: NO_CREDENTIALS");
444 case SEC_E_CONTEXT_EXPIRED:
445 OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
447 case SEC_E_INCOMPLETE_CREDENTIALS:
448 OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
450 case SEC_E_WRONG_PRINCIPAL:
451 OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
453 case SEC_E_TIME_SKEW:
454 OutputDebugF("Returning bad password :: TIME_SKEW");
457 OutputDebugF("Returning bad password :: Status == %lX", status);
459 code = CM_ERROR_BADPASSWORD;
463 if (secCtx->partialToken) free(secCtx->partialToken);
471 if (secTokOut.pvBuffer)
472 FreeContextBuffer(secTokOut.pvBuffer);
474 if (code != CM_ERROR_GSSCONTINUE) {
475 DeleteSecurityContext(&ctx);
476 FreeCredentialsHandle(&creds);
484 #define P_RESP_LEN 128
486 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
487 So put stuff in a struct. */
488 struct Lm20AuthBlob {
489 MSV1_0_LM20_LOGON lmlogon;
490 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
491 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
492 WCHAR accountNameW[P_LEN];
493 WCHAR primaryDomainW[P_LEN];
494 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
495 TOKEN_GROUPS tgroups;
496 TOKEN_SOURCE tsource;
499 long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength) {
502 struct Lm20AuthBlob lmAuth;
503 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
504 QUOTA_LIMITS quotaLimits;
506 ULONG lmprofilepSize;
510 OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
511 OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
513 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
514 OutputDebugF("ciPwdLength or csPwdLength is too long");
515 return CM_ERROR_BADPASSWORD;
518 memset(&lmAuth,0,sizeof(lmAuth));
520 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
522 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
523 mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
524 lmAuth.lmlogon.LogonDomainName.Length = wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR);
525 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
527 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
528 mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
529 lmAuth.lmlogon.UserName.Length = wcslen(lmAuth.accountNameW) * sizeof(WCHAR);
530 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
532 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
533 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
534 size = MAX_COMPUTERNAME_LENGTH + 1;
535 GetComputerNameW(lmAuth.workstationW, &size);
536 lmAuth.lmlogon.Workstation.Length = wcslen(lmAuth.workstationW) * sizeof(WCHAR);
538 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
540 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
541 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
542 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
543 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
545 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
546 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
547 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
548 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
550 lmAuth.lmlogon.ParameterControl = 0;
552 lmAuth.tgroups.GroupCount = 0;
553 lmAuth.tgroups.Groups[0].Sid = NULL;
554 lmAuth.tgroups.Groups[0].Attributes = 0;
556 lmAuth.tsource.SourceIdentifier.HighPart = 0;
557 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD) vcp;
558 strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
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,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,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;
929 osi_Log0(smb_logp, "SMB3 receive tree connect");
931 /* parse input parameters */
932 tp = smb_GetSMBData(inp, NULL);
933 passwordp = smb_ParseString(tp, &tp);
934 pathp = smb_ParseString(tp, &tp);
935 servicep = smb_ParseString(tp, &tp);
937 tp = strrchr(pathp, '\\');
939 return CM_ERROR_BADSMB;
941 strcpy(shareName, tp+1);
943 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0)
944 return CM_ERROR_NOIPC;
946 userp = smb_GetUser(vcp, inp);
948 lock_ObtainMutex(&vcp->mx);
949 newTid = vcp->tidCounter++;
950 lock_ReleaseMutex(&vcp->mx);
952 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
953 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
954 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
956 smb_ReleaseUID(uidp);
958 smb_ReleaseTID(tidp);
959 return CM_ERROR_BADSHARENAME;
961 lock_ObtainMutex(&tidp->mx);
963 tidp->pathname = sharePath;
964 lock_ReleaseMutex(&tidp->mx);
965 smb_ReleaseTID(tidp);
967 if (vcp->flags & SMB_VCFLAG_USENT)
969 int policy = smb_FindShareCSCPolicy(shareName);
970 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS | (policy << 2));
973 ((smb_t *)outp)->tid = newTid;
974 ((smb_t *)inp)->tid = newTid;
975 tp = smb_GetSMBData(outp, NULL);
979 smb_SetSMBDataLength(outp, 3);
981 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
985 /* must be called with global tran lock held */
986 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
988 smb_tran2Packet_t *tp;
991 smbp = (smb_t *) inp->data;
992 for(tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
993 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
999 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1000 int totalParms, int totalData)
1002 smb_tran2Packet_t *tp;
1005 smbp = (smb_t *) inp->data;
1006 tp = malloc(sizeof(*tp));
1007 memset(tp, 0, sizeof(*tp));
1010 tp->curData = tp->curParms = 0;
1011 tp->totalData = totalData;
1012 tp->totalParms = totalParms;
1013 tp->tid = smbp->tid;
1014 tp->mid = smbp->mid;
1015 tp->uid = smbp->uid;
1016 tp->pid = smbp->pid;
1017 tp->res[0] = smbp->res[0];
1018 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1019 tp->opcode = smb_GetSMBParm(inp, 14);
1020 if (totalParms != 0)
1021 tp->parmsp = malloc(totalParms);
1023 tp->datap = malloc(totalData);
1024 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1028 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1029 smb_tran2Packet_t *inp, smb_packet_t *outp,
1030 int totalParms, int totalData)
1032 smb_tran2Packet_t *tp;
1033 unsigned short parmOffset;
1034 unsigned short dataOffset;
1035 unsigned short dataAlign;
1037 tp = malloc(sizeof(*tp));
1038 memset(tp, 0, sizeof(*tp));
1040 tp->curData = tp->curParms = 0;
1041 tp->totalData = totalData;
1042 tp->totalParms = totalParms;
1043 tp->oldTotalParms = totalParms;
1048 tp->res[0] = inp->res[0];
1049 tp->opcode = inp->opcode;
1052 * We calculate where the parameters and data will start.
1053 * This calculation must parallel the calculation in
1054 * smb_SendTran2Packet.
1057 parmOffset = 10*2 + 35;
1058 parmOffset++; /* round to even */
1059 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1061 dataOffset = parmOffset + totalParms;
1062 dataAlign = dataOffset & 2; /* quad-align */
1063 dataOffset += dataAlign;
1064 tp->datap = outp->data + dataOffset;
1069 /* free a tran2 packet; must be called with smb_globalLock held */
1070 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1072 if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
1073 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1082 /* called with a VC, an input packet to respond to, and an error code.
1083 * sends an error response.
1085 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1086 smb_packet_t *tp, long code)
1089 unsigned short errCode;
1090 unsigned char errClass;
1091 unsigned long NTStatus;
1093 if (vcp->flags & SMB_VCFLAG_STATUS32)
1094 smb_MapNTError(code, &NTStatus);
1096 smb_MapCoreError(code, vcp, &errCode, &errClass);
1098 smb_FormatResponsePacket(vcp, NULL, tp);
1099 smbp = (smb_t *) tp;
1101 /* We can handle long names */
1102 if (vcp->flags & SMB_VCFLAG_USENT)
1103 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
1105 /* now copy important fields from the tran 2 packet */
1106 smbp->com = 0x32; /* tran 2 response */
1107 smbp->tid = t2p->tid;
1108 smbp->mid = t2p->mid;
1109 smbp->pid = t2p->pid;
1110 smbp->uid = t2p->uid;
1111 smbp->res[0] = t2p->res[0];
1112 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1113 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1114 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1115 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1116 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1117 smbp->flg2 |= 0x4000;
1120 smbp->rcls = errClass;
1121 smbp->errLow = (unsigned char) (errCode & 0xff);
1122 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1126 smb_SendPacket(vcp, tp);
1129 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1132 unsigned short parmOffset;
1133 unsigned short dataOffset;
1134 unsigned short totalLength;
1135 unsigned short dataAlign;
1138 smb_FormatResponsePacket(vcp, NULL, tp);
1139 smbp = (smb_t *) tp;
1141 /* We can handle long names */
1142 if (vcp->flags & SMB_VCFLAG_USENT)
1143 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
1145 /* now copy important fields from the tran 2 packet */
1146 smbp->com = 0x32; /* tran 2 response */
1147 smbp->tid = t2p->tid;
1148 smbp->mid = t2p->mid;
1149 smbp->pid = t2p->pid;
1150 smbp->uid = t2p->uid;
1151 smbp->res[0] = t2p->res[0];
1153 totalLength = 1 + t2p->totalData + t2p->totalParms;
1155 /* now add the core parameters (tran2 info) to the packet */
1156 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1157 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1158 smb_SetSMBParm(tp, 2, 0); /* reserved */
1159 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1160 parmOffset = 10*2 + 35; /* parm offset in packet */
1161 parmOffset++; /* round to even */
1162 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1163 * hdr, bcc and wct */
1164 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1165 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1166 dataOffset = parmOffset + t2p->oldTotalParms;
1167 dataAlign = dataOffset & 2; /* quad-align */
1168 dataOffset += dataAlign;
1169 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1170 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1171 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1174 datap = smb_GetSMBData(tp, NULL);
1175 *datap++ = 0; /* we rounded to even */
1177 totalLength += dataAlign;
1178 smb_SetSMBDataLength(tp, totalLength);
1180 /* next, send the datagram */
1181 smb_SendPacket(vcp, tp);
1184 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1186 smb_tran2Packet_t *asp;
1198 /* We sometimes see 0 word count. What to do? */
1199 if (*inp->wctp == 0) {
1204 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1206 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1207 ptbuf[0] = "Transaction2 word count = 0";
1208 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1209 1, inp->ncb_length, ptbuf, inp);
1210 DeregisterEventSource(h);
1212 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1215 smb_SetSMBDataLength(outp, 0);
1216 smb_SendPacket(vcp, outp);
1220 totalParms = smb_GetSMBParm(inp, 0);
1221 totalData = smb_GetSMBParm(inp, 1);
1223 firstPacket = (inp->inCom == 0x32);
1225 /* find the packet we're reassembling */
1226 lock_ObtainWrite(&smb_globalLock);
1227 asp = smb_FindTran2Packet(vcp, inp);
1229 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1231 lock_ReleaseWrite(&smb_globalLock);
1233 /* now merge in this latest packet; start by looking up offsets */
1235 parmDisp = dataDisp = 0;
1236 parmOffset = smb_GetSMBParm(inp, 10);
1237 dataOffset = smb_GetSMBParm(inp, 12);
1238 parmCount = smb_GetSMBParm(inp, 9);
1239 dataCount = smb_GetSMBParm(inp, 11);
1240 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1241 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1243 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1244 totalData, dataCount, asp->maxReturnData);
1247 parmDisp = smb_GetSMBParm(inp, 4);
1248 parmOffset = smb_GetSMBParm(inp, 3);
1249 dataDisp = smb_GetSMBParm(inp, 7);
1250 dataOffset = smb_GetSMBParm(inp, 6);
1251 parmCount = smb_GetSMBParm(inp, 2);
1252 dataCount = smb_GetSMBParm(inp, 5);
1254 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1255 parmCount, dataCount);
1258 /* now copy the parms and data */
1259 if ( parmCount != 0 )
1261 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1263 if ( dataCount != 0 ) {
1264 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1267 /* account for new bytes */
1268 asp->curData += dataCount;
1269 asp->curParms += parmCount;
1271 /* finally, if we're done, remove the packet from the queue and dispatch it */
1272 if (asp->totalData <= asp->curData && asp->totalParms <= asp->curParms) {
1273 /* we've received it all */
1274 lock_ObtainWrite(&smb_globalLock);
1275 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1276 lock_ReleaseWrite(&smb_globalLock);
1278 /* now dispatch it */
1279 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
1280 osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1281 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
1282 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
1285 osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1286 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1287 code = CM_ERROR_BADOP;
1290 /* if an error is returned, we're supposed to send an error packet,
1291 * otherwise the dispatched function already did the data sending.
1292 * We give dispatched proc the responsibility since it knows how much
1293 * space to allocate.
1296 smb_SendTran2Error(vcp, asp, outp, code);
1299 /* free the input tran 2 packet */
1300 lock_ObtainWrite(&smb_globalLock);
1301 smb_FreeTran2Packet(asp);
1302 lock_ReleaseWrite(&smb_globalLock);
1304 else if (firstPacket) {
1305 /* the first packet in a multi-packet request, we need to send an
1306 * ack to get more data.
1308 smb_SetSMBDataLength(outp, 0);
1309 smb_SendPacket(vcp, outp);
1315 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1318 smb_tran2Packet_t *outp;
1323 cm_scache_t *dscp; /* dir we're dealing with */
1324 cm_scache_t *scp; /* file we're creating */
1326 int initialModeBits;
1336 int parmSlot; /* which parm we're dealing with */
1337 long returnEALength;
1345 extraInfo = (p->parmsp[0] & 1); /* return extra info */
1346 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
1348 openFun = p->parmsp[6]; /* open function */
1349 excl = ((openFun & 3) == 0);
1350 trunc = ((openFun & 3) == 2); /* truncate it */
1351 openMode = (p->parmsp[1] & 0x7);
1352 openAction = 0; /* tracks what we did */
1354 attributes = p->parmsp[3];
1355 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
1357 /* compute initial mode bits based on read-only flag in attributes */
1358 initialModeBits = 0666;
1359 if (attributes & 1) initialModeBits &= ~0222;
1361 pathp = (char *) (&p->parmsp[14]);
1363 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
1365 spacep = cm_GetSpace();
1366 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
1368 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
1369 /* special case magic file name for receiving IOCTL requests
1370 * (since IOCTL calls themselves aren't getting through).
1372 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
1373 smb_SetupIoctlFid(fidp, spacep);
1375 /* copy out remainder of the parms */
1377 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
1379 outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
1380 outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
1381 outp->parmsp[parmSlot] = 0; parmSlot++;
1382 outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
1383 outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
1384 outp->parmsp[parmSlot] = openMode; parmSlot++;
1385 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
1386 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
1388 /* and the final "always present" stuff */
1389 outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
1390 /* next write out the "unique" ID */
1391 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
1392 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
1393 outp->parmsp[parmSlot] = 0; parmSlot++;
1394 if (returnEALength) {
1395 outp->parmsp[parmSlot] = 0; parmSlot++;
1396 outp->parmsp[parmSlot] = 0; parmSlot++;
1399 outp->totalData = 0;
1400 outp->totalParms = parmSlot * 2;
1402 smb_SendTran2Packet(vcp, outp, op);
1404 smb_FreeTran2Packet(outp);
1406 /* and clean up fid reference */
1407 smb_ReleaseFID(fidp);
1411 #ifdef DEBUG_VERBOSE
1413 char *hexp, *asciip;
1414 asciip = (lastNamep ? lastNamep : pathp);
1415 hexp = osi_HexifyString( asciip );
1416 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
1421 userp = smb_GetTran2User(vcp, p);
1422 /* In the off chance that userp is NULL, we log and abandon */
1424 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
1425 smb_FreeTran2Packet(outp);
1426 return CM_ERROR_BADSMB;
1429 tidPathp = smb_GetTIDPath(vcp, p->tid);
1432 code = cm_NameI(cm_rootSCachep, pathp,
1433 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
1434 userp, tidPathp, &req, &scp);
1436 code = cm_NameI(cm_rootSCachep, spacep->data,
1437 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
1438 userp, tidPathp, &req, &dscp);
1439 cm_FreeSpace(spacep);
1442 cm_ReleaseUser(userp);
1443 smb_FreeTran2Packet(outp);
1447 /* otherwise, scp points to the parent directory. Do a lookup,
1448 * and truncate the file if we find it, otherwise we create the
1451 if (!lastNamep) lastNamep = pathp;
1453 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
1455 if (code && code != CM_ERROR_NOSUCHFILE) {
1456 cm_ReleaseSCache(dscp);
1457 cm_ReleaseUser(userp);
1458 smb_FreeTran2Packet(outp);
1463 cm_FreeSpace(spacep);
1466 /* if we get here, if code is 0, the file exists and is represented by
1467 * scp. Otherwise, we have to create it.
1470 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
1472 if (dscp) cm_ReleaseSCache(dscp);
1473 cm_ReleaseSCache(scp);
1474 cm_ReleaseUser(userp);
1475 smb_FreeTran2Packet(outp);
1480 /* oops, file shouldn't be there */
1481 if (dscp) cm_ReleaseSCache(dscp);
1482 cm_ReleaseSCache(scp);
1483 cm_ReleaseUser(userp);
1484 smb_FreeTran2Packet(outp);
1485 return CM_ERROR_EXISTS;
1489 setAttr.mask = CM_ATTRMASK_LENGTH;
1490 setAttr.length.LowPart = 0;
1491 setAttr.length.HighPart = 0;
1492 code = cm_SetAttr(scp, &setAttr, userp, &req);
1493 openAction = 3; /* truncated existing file */
1495 else openAction = 1; /* found existing file */
1497 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
1498 /* don't create if not found */
1499 if (dscp) cm_ReleaseSCache(dscp);
1500 osi_assert(scp == NULL);
1501 cm_ReleaseUser(userp);
1502 smb_FreeTran2Packet(outp);
1503 return CM_ERROR_NOSUCHFILE;
1506 osi_assert(dscp != NULL && scp == NULL);
1507 openAction = 2; /* created file */
1508 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
1509 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
1510 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
1512 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
1513 smb_NotifyChange(FILE_ACTION_ADDED,
1514 FILE_NOTIFY_CHANGE_FILE_NAME,
1515 dscp, lastNamep, NULL, TRUE);
1516 if (!excl && code == CM_ERROR_EXISTS) {
1517 /* not an exclusive create, and someone else tried
1518 * creating it already, then we open it anyway. We
1519 * don't bother retrying after this, since if this next
1520 * fails, that means that the file was deleted after we
1521 * started this call.
1523 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
1527 setAttr.mask = CM_ATTRMASK_LENGTH;
1528 setAttr.length.LowPart = 0;
1529 setAttr.length.HighPart = 0;
1530 code = cm_SetAttr(scp, &setAttr, userp,
1533 } /* lookup succeeded */
1537 /* we don't need this any longer */
1538 if (dscp) cm_ReleaseSCache(dscp);
1541 /* something went wrong creating or truncating the file */
1542 if (scp) cm_ReleaseSCache(scp);
1543 cm_ReleaseUser(userp);
1544 smb_FreeTran2Packet(outp);
1548 /* make sure we're about to open a file */
1549 if (scp->fileType != CM_SCACHETYPE_FILE) {
1550 cm_ReleaseSCache(scp);
1551 cm_ReleaseUser(userp);
1552 smb_FreeTran2Packet(outp);
1553 return CM_ERROR_ISDIR;
1556 /* now all we have to do is open the file itself */
1557 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
1560 /* save a pointer to the vnode */
1563 /* compute open mode */
1564 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
1565 if (openMode == 1 || openMode == 2)
1566 fidp->flags |= SMB_FID_OPENWRITE;
1568 smb_ReleaseFID(fidp);
1570 cm_Open(scp, 0, userp);
1572 /* copy out remainder of the parms */
1574 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
1575 lock_ObtainMutex(&scp->mx);
1577 outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
1578 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1579 outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
1580 outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
1581 outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
1583 outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
1585 outp->parmsp[parmSlot] = openMode; parmSlot++;
1586 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
1587 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
1589 /* and the final "always present" stuff */
1590 outp->parmsp[parmSlot] = openAction; parmSlot++;
1591 /* next write out the "unique" ID */
1592 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
1593 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
1594 outp->parmsp[parmSlot] = 0; parmSlot++;
1595 if (returnEALength) {
1596 outp->parmsp[parmSlot] = 0; parmSlot++;
1597 outp->parmsp[parmSlot] = 0; parmSlot++;
1599 lock_ReleaseMutex(&scp->mx);
1600 outp->totalData = 0; /* total # of data bytes */
1601 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
1603 smb_SendTran2Packet(vcp, outp, op);
1605 smb_FreeTran2Packet(outp);
1607 cm_ReleaseUser(userp);
1608 /* leave scp held since we put it in fidp->scp */
1612 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1614 return CM_ERROR_BADOP;
1617 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1619 return CM_ERROR_BADOP;
1622 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1624 smb_tran2Packet_t *outp;
1625 smb_tran2QFSInfo_t qi;
1628 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
1630 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
1632 switch (p->parmsp[0]) {
1633 case 1: responseSize = sizeof(qi.u.allocInfo); break;
1634 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
1635 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
1636 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
1637 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
1638 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
1639 default: return CM_ERROR_INVAL;
1642 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
1643 switch (p->parmsp[0]) {
1646 qi.u.allocInfo.FSID = 0;
1647 qi.u.allocInfo.sectorsPerAllocUnit = 1;
1648 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
1649 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
1650 qi.u.allocInfo.bytesPerSector = 1024;
1655 qi.u.volumeInfo.vsn = 1234;
1656 qi.u.volumeInfo.vnCount = 4;
1657 /* we're supposed to pad it out with zeroes to the end */
1658 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
1659 memcpy(qi.u.volumeInfo.label, "AFS", 4);
1663 /* FS volume info */
1664 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
1665 qi.u.FSvolumeInfo.vsn = 1234;
1666 qi.u.FSvolumeInfo.vnCount = 8;
1667 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
1673 temp.LowPart = 0x7fffffff;
1674 qi.u.FSsizeInfo.totalAllocUnits = temp;
1675 temp.LowPart = 0x3fffffff;
1676 qi.u.FSsizeInfo.availAllocUnits = temp;
1677 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
1678 qi.u.FSsizeInfo.bytesPerSector = 1024;
1682 /* FS device info */
1683 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
1684 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
1688 /* FS attribute info */
1689 /* attributes, defined in WINNT.H:
1690 * FILE_CASE_SENSITIVE_SEARCH 0x1
1691 * FILE_CASE_PRESERVED_NAMES 0x2
1692 * <no name defined> 0x4000
1693 * If bit 0x4000 is not set, Windows 95 thinks
1694 * we can't handle long (non-8.3) names,
1695 * despite our protestations to the contrary.
1697 qi.u.FSattributeInfo.attributes = 0x4003;
1698 qi.u.FSattributeInfo.maxCompLength = 255;
1699 qi.u.FSattributeInfo.FSnameLength = 6;
1700 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
1704 /* copy out return data, and set corresponding sizes */
1705 outp->totalParms = 0;
1706 outp->totalData = responseSize;
1707 memcpy(outp->datap, &qi, responseSize);
1709 /* send and free the packets */
1710 smb_SendTran2Packet(vcp, outp, op);
1711 smb_FreeTran2Packet(outp);
1716 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1718 return CM_ERROR_BADOP;
1721 struct smb_ShortNameRock {
1725 size_t shortNameLen;
1728 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
1731 struct smb_ShortNameRock *rockp;
1735 /* compare both names and vnodes, though probably just comparing vnodes
1736 * would be safe enough.
1738 if (cm_stricmp(dep->name, rockp->maskp) != 0)
1740 if (ntohl(dep->fid.vnode) != rockp->vnode)
1742 /* This is the entry */
1743 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
1744 rockp->shortNameLen = shortNameEnd - rockp->shortName;
1745 return CM_ERROR_STOPNOW;
1748 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
1749 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
1751 struct smb_ShortNameRock rock;
1755 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
1759 spacep = cm_GetSpace();
1760 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
1762 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
1764 cm_FreeSpace(spacep);
1765 if (code) return code;
1767 if (!lastNamep) lastNamep = pathp;
1770 thyper.HighPart = 0;
1771 rock.shortName = shortName;
1773 rock.maskp = lastNamep;
1774 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
1777 cm_ReleaseSCache(dscp);
1780 return CM_ERROR_NOSUCHFILE;
1781 if (code == CM_ERROR_STOPNOW) {
1782 *shortNameLenp = rock.shortNameLen;
1788 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1790 smb_tran2Packet_t *outp;
1791 unsigned long dosTime;
1793 unsigned short infoLevel;
1795 unsigned short attributes;
1796 unsigned long extAttributes;
1801 cm_scache_t *scp, *dscp;
1810 infoLevel = p->parmsp[0];
1811 if (infoLevel == 6) nbytesRequired = 0;
1812 else if (infoLevel == 1) nbytesRequired = 22;
1813 else if (infoLevel == 2) nbytesRequired = 26;
1814 else if (infoLevel == 0x101) nbytesRequired = 40;
1815 else if (infoLevel == 0x102) nbytesRequired = 24;
1816 else if (infoLevel == 0x103) nbytesRequired = 4;
1817 else if (infoLevel == 0x108) nbytesRequired = 30;
1819 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1820 p->opcode, infoLevel);
1821 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1824 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
1825 osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
1827 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1829 if (infoLevel > 0x100)
1830 outp->totalParms = 2;
1832 outp->totalParms = 0;
1833 outp->totalData = nbytesRequired;
1835 /* now, if we're at infoLevel 6, we're only being asked to check
1836 * the syntax, so we just OK things now. In particular, we're *not*
1837 * being asked to verify anything about the state of any parent dirs.
1839 if (infoLevel == 6) {
1840 smb_SendTran2Packet(vcp, outp, opx);
1841 smb_FreeTran2Packet(outp);
1845 userp = smb_GetTran2User(vcp, p);
1847 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
1848 smb_FreeTran2Packet(outp);
1849 return CM_ERROR_BADSMB;
1852 tidPathp = smb_GetTIDPath(vcp, p->tid);
1855 * XXX Strange hack XXX
1857 * As of Patch 7 (13 January 98), we are having the following problem:
1858 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
1859 * requests to look up "desktop.ini" in all the subdirectories.
1860 * This can cause zillions of timeouts looking up non-existent cells
1861 * and volumes, especially in the top-level directory.
1863 * We have not found any way to avoid this or work around it except
1864 * to explicitly ignore the requests for mount points that haven't
1865 * yet been evaluated and for directories that haven't yet been
1868 if (infoLevel == 0x101) {
1869 spacep = cm_GetSpace();
1870 smb_StripLastComponent(spacep->data, &lastComp,
1871 (char *)(&p->parmsp[3]));
1872 /* Make sure that lastComp is not NULL */
1874 if (strcmp(lastComp, "\\desktop.ini") == 0) {
1875 code = cm_NameI(cm_rootSCachep, spacep->data,
1879 userp, tidPathp, &req, &dscp);
1881 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
1882 && !dscp->mountRootFidp)
1883 code = CM_ERROR_NOSUCHFILE;
1884 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
1885 cm_buf_t *bp = buf_Find(dscp, &hzero);
1889 code = CM_ERROR_NOSUCHFILE;
1891 cm_ReleaseSCache(dscp);
1893 cm_FreeSpace(spacep);
1894 cm_ReleaseUser(userp);
1895 smb_SendTran2Error(vcp, p, opx, code);
1896 smb_FreeTran2Packet(outp);
1902 cm_FreeSpace(spacep);
1905 /* now do namei and stat, and copy out the info */
1906 code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
1907 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
1910 cm_ReleaseUser(userp);
1911 smb_SendTran2Error(vcp, p, opx, code);
1912 smb_FreeTran2Packet(outp);
1916 lock_ObtainMutex(&scp->mx);
1917 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1918 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1919 if (code) goto done;
1921 /* now we have the status in the cache entry, and everything is locked.
1922 * Marshall the output data.
1925 /* for info level 108, figure out short name */
1926 if (infoLevel == 0x108) {
1927 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
1928 tidPathp, scp->fid.vnode, shortName,
1935 *((u_long *)op) = len * 2; op += 4;
1936 mbstowcs((unsigned short *)op, shortName, len);
1941 if (infoLevel == 1 || infoLevel == 2) {
1942 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1943 *((u_long *)op) = dosTime; op += 4; /* creation time */
1944 *((u_long *)op) = dosTime; op += 4; /* access time */
1945 *((u_long *)op) = dosTime; op += 4; /* write time */
1946 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
1947 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
1948 attributes = smb_Attributes(scp);
1949 *((u_short *)op) = attributes; op += 2; /* attributes */
1951 else if (infoLevel == 0x101) {
1952 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1953 *((FILETIME *)op) = ft; op += 8; /* creation time */
1954 *((FILETIME *)op) = ft; op += 8; /* last access time */
1955 *((FILETIME *)op) = ft; op += 8; /* last write time */
1956 *((FILETIME *)op) = ft; op += 8; /* last change time */
1957 extAttributes = smb_ExtAttributes(scp);
1958 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
1959 *((u_long *)op) = 0; op += 4; /* don't know what this is */
1961 else if (infoLevel == 0x102) {
1962 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
1963 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
1964 *((u_long *)op) = scp->linkCount; op += 4;
1967 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1970 else if (infoLevel == 0x103) {
1971 memset(op, 0, 4); op += 4; /* EA size */
1974 /* now, if we are being asked about extended attrs, return a 0 size */
1975 if (infoLevel == 2) {
1976 *((u_long *)op) = 0; op += 4;
1980 /* send and free the packets */
1982 lock_ReleaseMutex(&scp->mx);
1983 cm_ReleaseSCache(scp);
1984 cm_ReleaseUser(userp);
1986 smb_SendTran2Packet(vcp, outp, opx);
1988 smb_SendTran2Error(vcp, p, opx, code);
1989 smb_FreeTran2Packet(outp);
1994 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1996 return CM_ERROR_BADOP;
1999 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2001 smb_tran2Packet_t *outp;
2003 unsigned long attributes;
2004 unsigned short infoLevel;
2017 fidp = smb_FindFID(vcp, fid, 0);
2020 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2024 infoLevel = p->parmsp[1];
2025 if (infoLevel == 0x101) nbytesRequired = 40;
2026 else if (infoLevel == 0x102) nbytesRequired = 24;
2027 else if (infoLevel == 0x103) nbytesRequired = 4;
2028 else if (infoLevel == 0x104) nbytesRequired = 6;
2030 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2031 p->opcode, infoLevel);
2032 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2033 smb_ReleaseFID(fidp);
2036 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2038 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2040 if (infoLevel > 0x100)
2041 outp->totalParms = 2;
2043 outp->totalParms = 0;
2044 outp->totalData = nbytesRequired;
2046 userp = smb_GetTran2User(vcp, p);
2048 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2049 code = CM_ERROR_BADSMB;
2054 lock_ObtainMutex(&scp->mx);
2055 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2056 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2057 if (code) goto done;
2059 /* now we have the status in the cache entry, and everything is locked.
2060 * Marshall the output data.
2063 if (infoLevel == 0x101) {
2064 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2065 *((FILETIME *)op) = ft; op += 8; /* creation time */
2066 *((FILETIME *)op) = ft; op += 8; /* last access time */
2067 *((FILETIME *)op) = ft; op += 8; /* last write time */
2068 *((FILETIME *)op) = ft; op += 8; /* last change time */
2069 attributes = smb_ExtAttributes(scp);
2070 *((u_long *)op) = attributes; op += 4;
2071 *((u_long *)op) = 0; op += 4;
2073 else if (infoLevel == 0x102) {
2074 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2075 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2076 *((u_long *)op) = scp->linkCount; op += 4;
2077 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
2078 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2082 else if (infoLevel == 0x103) {
2083 *((u_long *)op) = 0; op += 4;
2085 else if (infoLevel == 0x104) {
2089 if (fidp->NTopen_wholepathp)
2090 name = fidp->NTopen_wholepathp;
2092 name = "\\"; /* probably can't happen */
2094 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
2095 *((u_long *)op) = len * 2; op += 4;
2096 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2099 /* send and free the packets */
2101 lock_ReleaseMutex(&scp->mx);
2102 cm_ReleaseUser(userp);
2103 smb_ReleaseFID(fidp);
2104 if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
2105 else smb_SendTran2Error(vcp, p, opx, code);
2106 smb_FreeTran2Packet(outp);
2111 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2116 unsigned short infoLevel;
2117 smb_tran2Packet_t *outp;
2125 fidp = smb_FindFID(vcp, fid, 0);
2128 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
2132 infoLevel = p->parmsp[1];
2133 if (infoLevel > 0x104 || infoLevel < 0x101) {
2134 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2135 p->opcode, infoLevel);
2136 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
2137 smb_ReleaseFID(fidp);
2141 if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
2142 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2143 smb_ReleaseFID(fidp);
2146 if ((infoLevel == 0x103 || infoLevel == 0x104)
2147 && !(fidp->flags & SMB_FID_OPENWRITE)) {
2148 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2149 smb_ReleaseFID(fidp);
2153 osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
2155 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
2157 outp->totalParms = 2;
2158 outp->totalData = 0;
2160 userp = smb_GetTran2User(vcp, p);
2162 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
2163 code = CM_ERROR_BADSMB;
2169 if (infoLevel == 0x101) {
2171 unsigned int attribute;
2174 /* lock the vnode with a callback; we need the current status
2175 * to determine what the new status is, in some cases.
2177 lock_ObtainMutex(&scp->mx);
2178 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2179 CM_SCACHESYNC_GETSTATUS
2180 | CM_SCACHESYNC_NEEDCALLBACK);
2182 lock_ReleaseMutex(&scp->mx);
2186 /* prepare for setattr call */
2189 lastMod = *((FILETIME *)(p->datap + 16));
2190 /* when called as result of move a b, lastMod is (-1, -1).
2191 * If the check for -1 is not present, timestamp
2192 * of the resulting file will be 1969 (-1)
2194 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
2195 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
2196 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
2197 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
2199 fidp->flags |= SMB_FID_MTIMESETDONE;
2202 attribute = *((u_long *)(p->datap + 32));
2203 if (attribute != 0) {
2204 if ((scp->unixModeBits & 0222)
2205 && (attribute & 1) != 0) {
2206 /* make a writable file read-only */
2207 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2208 attr.unixModeBits = scp->unixModeBits & ~0222;
2210 else if ((scp->unixModeBits & 0222) == 0
2211 && (attribute & 1) == 0) {
2212 /* make a read-only file writable */
2213 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2214 attr.unixModeBits = scp->unixModeBits | 0222;
2217 lock_ReleaseMutex(&scp->mx);
2221 code = cm_SetAttr(scp, &attr, userp, &req);
2225 else if (infoLevel == 0x103 || infoLevel == 0x104) {
2226 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
2229 attr.mask = CM_ATTRMASK_LENGTH;
2230 attr.length.LowPart = size.LowPart;
2231 attr.length.HighPart = size.HighPart;
2232 code = cm_SetAttr(scp, &attr, userp, &req);
2234 else if (infoLevel == 0x102) {
2235 if (*((char *)(p->datap))) {
2236 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
2239 fidp->flags |= SMB_FID_DELONCLOSE;
2243 fidp->flags &= ~SMB_FID_DELONCLOSE;
2247 cm_ReleaseUser(userp);
2248 smb_ReleaseFID(fidp);
2249 if (code == 0) smb_SendTran2Packet(vcp, outp, op);
2250 else smb_SendTran2Error(vcp, p, op, code);
2251 smb_FreeTran2Packet(outp);
2256 long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2258 return CM_ERROR_BADOP;
2261 long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2263 return CM_ERROR_BADOP;
2266 long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2268 return CM_ERROR_BADOP;
2271 long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2273 return CM_ERROR_BADOP;
2276 long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2278 return CM_ERROR_BADOP;
2281 long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
2282 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
2287 cm_scache_t *targetScp; /* target if scp is a symlink */
2292 unsigned short attr;
2293 unsigned long lattr;
2294 smb_dirListPatch_t *patchp;
2295 smb_dirListPatch_t *npatchp;
2297 for(patchp = *dirPatchespp; patchp; patchp =
2298 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
2299 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
2301 lock_ObtainMutex(&scp->mx);
2302 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
2303 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2305 lock_ReleaseMutex(&scp->mx);
2306 cm_ReleaseSCache(scp);
2310 /* now watch for a symlink */
2311 if (scp->fileType == CM_SCACHETYPE_SYMLINK) {
2312 lock_ReleaseMutex(&scp->mx);
2313 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
2315 /* we have a more accurate file to use (the
2316 * target of the symbolic link). Otherwise,
2317 * we'll just use the symlink anyway.
2319 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2321 cm_ReleaseSCache(scp);
2324 lock_ObtainMutex(&scp->mx);
2327 dptr = patchp->dptr;
2329 if (infoLevel >= 0x101) {
2331 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2333 /* copy to Creation Time */
2334 *((FILETIME *)dptr) = ft;
2337 /* copy to Last Access Time */
2338 *((FILETIME *)dptr) = ft;
2341 /* copy to Last Write Time */
2342 *((FILETIME *)dptr) = ft;
2345 /* copy to Change Time */
2346 *((FILETIME *)dptr) = ft;
2349 /* Use length for both file length and alloc length */
2350 *((LARGE_INTEGER *)dptr) = scp->length;
2352 *((LARGE_INTEGER *)dptr) = scp->length;
2355 /* Copy attributes */
2356 lattr = smb_ExtAttributes(scp);
2357 /* merge in hidden (dot file) attribute */
2358 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
2359 lattr |= SMB_ATTR_HIDDEN;
2360 *((u_long *)dptr) = lattr;
2365 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2367 /* and copy out date */
2368 shortTemp = (dosTime>>16) & 0xffff;
2369 *((u_short *)dptr) = shortTemp;
2372 /* copy out creation time */
2373 shortTemp = dosTime & 0xffff;
2374 *((u_short *)dptr) = shortTemp;
2377 /* and copy out date */
2378 shortTemp = (dosTime>>16) & 0xffff;
2379 *((u_short *)dptr) = shortTemp;
2382 /* copy out access time */
2383 shortTemp = dosTime & 0xffff;
2384 *((u_short *)dptr) = shortTemp;
2387 /* and copy out date */
2388 shortTemp = (dosTime>>16) & 0xffff;
2389 *((u_short *)dptr) = shortTemp;
2392 /* copy out mod time */
2393 shortTemp = dosTime & 0xffff;
2394 *((u_short *)dptr) = shortTemp;
2397 /* copy out file length and alloc length,
2398 * using the same for both
2400 *((u_long *)dptr) = scp->length.LowPart;
2402 *((u_long *)dptr) = scp->length.LowPart;
2405 /* finally copy out attributes as short */
2406 attr = smb_Attributes(scp);
2407 /* merge in hidden (dot file) attribute */
2408 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
2409 attr |= SMB_ATTR_HIDDEN;
2410 *dptr++ = attr & 0xff;
2411 *dptr++ = (attr >> 8) & 0xff;
2414 lock_ReleaseMutex(&scp->mx);
2415 cm_ReleaseSCache(scp);
2418 /* now free the patches */
2419 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
2420 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
2424 /* and mark the list as empty */
2425 *dirPatchespp = NULL;
2430 #ifndef USE_OLD_MATCHING
2431 // char table for case insensitive comparison
2432 char mapCaseTable[256];
2434 VOID initUpperCaseTable(VOID)
2437 for (i = 0; i < 256; ++i)
2438 mapCaseTable[i] = toupper(i);
2439 // make '"' match '.'
2440 mapCaseTable[(int)'"'] = toupper('.');
2441 // make '<' match '*'
2442 mapCaseTable[(int)'<'] = toupper('*');
2443 // make '>' match '?'
2444 mapCaseTable[(int)'>'] = toupper('?');
2447 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
2449 // Note : this procedure works recursively calling itself.
2451 // PSZ pattern : string containing metacharacters.
2452 // PSZ name : file name to be compared with 'pattern'.
2454 // BOOL : TRUE/FALSE (match/mistmatch)
2456 BOOL szWildCardMatchFileName(PSZ pattern, PSZ name) {
2457 PSZ pename; // points to the last 'name' character
2459 pename = name + strlen(name) - 1;
2464 if (*(++pattern) != '<' || *(++pattern) != '*') {
2472 while ((*pattern == '<') || (*pattern == '*') || (*pattern == '?') || (*pattern == '>'))
2476 for (p = pename; p >= name; --p) {
2477 if ((mapCaseTable[*p] == mapCaseTable[*pattern]) &&
2478 szWildCardMatchFileName(pattern + 1, p + 1))
2483 if (mapCaseTable[*name] != mapCaseTable[*pattern])
2492 /* do a case-folding search of the star name mask with the name in namep.
2493 * Return 1 if we match, otherwise 0.
2495 int smb_V3MatchMask(char *namep, char *maskp, int flags)
2497 /* make sure we only match 8.3 names, if requested */
2498 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
2501 return szWildCardMatchFileName(maskp, namep) ? 1:0;
2504 #else /* USE_OLD_MATCHING */
2505 /* do a case-folding search of the star name mask with the name in namep.
2506 * Return 1 if we match, otherwise 0.
2508 int smb_V3MatchMask(char *namep, char *maskp, int flags)
2510 unsigned char tcp1, tcp2; /* Pattern characters */
2511 unsigned char tcn1; /* Name characters */
2512 int sawDot = 0, sawStar = 0, req8dot3 = 0;
2513 char *starNamep, *starMaskp;
2514 static char nullCharp[] = {0};
2515 int casefold = flags & CM_FLAG_CASEFOLD;
2517 /* make sure we only match 8.3 names, if requested */
2518 req8dot3 = (flags & CM_FLAG_8DOT3);
2519 if (req8dot3 && !cm_Is8Dot3(namep))
2524 /* Next pattern character */
2527 /* Next name character */
2531 /* 0 - end of pattern */
2537 else if (tcp1 == '.' || tcp1 == '"') {
2547 * first dot in pattern;
2548 * must match dot or end of name
2553 else if (tcn1 == '.') {
2562 else if (tcp1 == '?') {
2563 if (tcn1 == 0 || tcn1 == '.')
2568 else if (tcp1 == '>') {
2569 if (tcn1 != 0 && tcn1 != '.')
2573 else if (tcp1 == '*' || tcp1 == '<') {
2577 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
2578 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
2593 * pattern character after '*' is not null or
2594 * period. If it is '?' or '>', we are not
2595 * going to understand it. If it is '*' or
2596 * '<', we are going to skip over it. None of
2597 * these are likely, I hope.
2599 /* skip over '*' and '<' */
2600 while (tcp2 == '*' || tcp2 == '<')
2603 /* skip over characters that don't match tcp2 */
2604 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
2605 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
2606 (!casefold && tcn1 != tcp2)))
2610 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
2613 /* Remember where we are */
2623 /* tcp1 is not a wildcard */
2624 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
2625 (!casefold && tcn1 == tcp1)) {
2630 /* if trying to match a star pattern, go back */
2632 maskp = starMaskp - 2;
2633 namep = starNamep + 1;
2642 #endif /* USE_OLD_MATCHING */
2644 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2653 smb_dirListPatch_t *dirListPatchesp;
2654 smb_dirListPatch_t *curPatchp;
2657 long orbytes; /* # of bytes in this output record */
2658 long ohbytes; /* # of bytes, except file name */
2659 long onbytes; /* # of bytes in name, incl. term. null */
2660 osi_hyper_t dirLength;
2661 osi_hyper_t bufferOffset;
2662 osi_hyper_t curOffset;
2664 smb_dirSearch_t *dsp;
2668 cm_pageHeader_t *pageHeaderp;
2669 cm_user_t *userp = NULL;
2672 long nextEntryCookie;
2673 int numDirChunks; /* # of 32 byte dir chunks in this entry */
2674 char *op; /* output data ptr */
2675 char *origOp; /* original value of op */
2676 cm_space_t *spacep; /* for pathname buffer */
2677 long maxReturnData; /* max # of return data */
2678 long maxReturnParms; /* max # of return parms */
2679 long bytesInBuffer; /* # data bytes in the output buffer */
2681 char *maskp; /* mask part of path */
2685 smb_tran2Packet_t *outp; /* response packet */
2688 char shortName[13]; /* 8.3 name if needed */
2700 if (p->opcode == 1) {
2701 /* find first; obtain basic parameters from request */
2702 attribute = p->parmsp[0];
2703 maxCount = p->parmsp[1];
2704 infoLevel = p->parmsp[3];
2705 searchFlags = p->parmsp[2];
2706 dsp = smb_NewDirSearch(1);
2707 dsp->attribute = attribute;
2708 pathp = ((char *) p->parmsp) + 12; /* points to path */
2710 maskp = strrchr(pathp, '\\');
2711 if (maskp == NULL) maskp = pathp;
2712 else maskp++; /* skip over backslash */
2713 strcpy(dsp->mask, maskp); /* and save mask */
2714 /* track if this is likely to match a lot of entries */
2715 starPattern = smb_V3IsStarMask(maskp);
2718 osi_assert(p->opcode == 2);
2719 /* find next; obtain basic parameters from request or open dir file */
2720 dsp = smb_FindDirSearch(p->parmsp[0]);
2721 if (!dsp) return CM_ERROR_BADFD;
2722 attribute = dsp->attribute;
2723 maxCount = p->parmsp[1];
2724 infoLevel = p->parmsp[2];
2725 searchFlags = p->parmsp[5];
2727 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
2729 starPattern = 1; /* assume, since required a Find Next */
2733 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
2734 attribute, infoLevel, maxCount, searchFlags);
2736 osi_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
2737 p->opcode, nextCookie);
2739 if (infoLevel >= 0x101)
2740 searchFlags &= ~4; /* no resume keys */
2742 dirListPatchesp = NULL;
2744 maxReturnData = p->maxReturnData;
2745 if (p->opcode == 1) /* find first */
2746 maxReturnParms = 10; /* bytes */
2748 maxReturnParms = 8; /* bytes */
2750 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
2751 if (maxReturnData > 6000)
2752 maxReturnData = 6000;
2753 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
2755 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
2758 osi_Log1(smb_logp, "T2 receive search dir %s",
2759 osi_LogSaveString(smb_logp, pathp));
2761 /* bail out if request looks bad */
2762 if (p->opcode == 1 && !pathp) {
2763 smb_ReleaseDirSearch(dsp);
2764 smb_FreeTran2Packet(outp);
2765 return CM_ERROR_BADSMB;
2768 osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
2769 nextCookie, dsp->cookie);
2771 userp = smb_GetTran2User(vcp, p);
2773 osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p->uid);
2774 smb_ReleaseDirSearch(dsp);
2775 smb_FreeTran2Packet(outp);
2776 return CM_ERROR_BADSMB;
2779 /* try to get the vnode for the path name next */
2780 lock_ObtainMutex(&dsp->mx);
2787 spacep = cm_GetSpace();
2788 smb_StripLastComponent(spacep->data, NULL, pathp);
2789 lock_ReleaseMutex(&dsp->mx);
2791 tidPathp = smb_GetTIDPath(vcp, p->tid);
2792 code = cm_NameI(cm_rootSCachep, spacep->data,
2793 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2794 userp, tidPathp, &req, &scp);
2795 cm_FreeSpace(spacep);
2797 lock_ObtainMutex(&dsp->mx);
2799 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
2801 /* we need one hold for the entry we just stored into,
2802 * and one for our own processing. When we're done
2803 * with this function, we'll drop the one for our own
2804 * processing. We held it once from the namei call,
2805 * and so we do another hold now.
2808 lock_ObtainMutex(&scp->mx);
2809 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
2810 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
2811 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
2812 dsp->flags |= SMB_DIRSEARCH_BULKST;
2814 lock_ReleaseMutex(&scp->mx);
2817 lock_ReleaseMutex(&dsp->mx);
2819 cm_ReleaseUser(userp);
2820 smb_FreeTran2Packet(outp);
2821 smb_DeleteDirSearch(dsp);
2822 smb_ReleaseDirSearch(dsp);
2826 /* get the directory size */
2827 lock_ObtainMutex(&scp->mx);
2828 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2829 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2831 lock_ReleaseMutex(&scp->mx);
2832 cm_ReleaseSCache(scp);
2833 cm_ReleaseUser(userp);
2834 smb_FreeTran2Packet(outp);
2835 smb_DeleteDirSearch(dsp);
2836 smb_ReleaseDirSearch(dsp);
2841 dirLength = scp->length;
2843 bufferOffset.LowPart = bufferOffset.HighPart = 0;
2844 curOffset.HighPart = 0;
2845 curOffset.LowPart = nextCookie;
2846 origOp = outp->datap;
2854 if (searchFlags & 4)
2855 /* skip over resume key */
2858 /* make sure that curOffset.LowPart doesn't point to the first
2859 * 32 bytes in the 2nd through last dir page, and that it doesn't
2860 * point at the first 13 32-byte chunks in the first dir page,
2861 * since those are dir and page headers, and don't contain useful
2864 temp = curOffset.LowPart & (2048-1);
2865 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
2866 /* we're in the first page */
2867 if (temp < 13*32) temp = 13*32;
2870 /* we're in a later dir page */
2871 if (temp < 32) temp = 32;
2874 /* make sure the low order 5 bits are zero */
2877 /* now put temp bits back ito curOffset.LowPart */
2878 curOffset.LowPart &= ~(2048-1);
2879 curOffset.LowPart |= temp;
2881 /* check if we've passed the dir's EOF */
2882 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
2887 /* check if we've returned all the names that will fit in the
2888 * response packet; we check return count as well as the number
2889 * of bytes requested. We check the # of bytes after we find
2890 * the dir entry, since we'll need to check its size.
2892 if (returnedNames >= maxCount) {
2896 /* see if we can use the bufferp we have now; compute in which
2897 * page the current offset would be, and check whether that's
2898 * the offset of the buffer we have. If not, get the buffer.
2900 thyper.HighPart = curOffset.HighPart;
2901 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
2902 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
2905 buf_Release(bufferp);
2908 lock_ReleaseMutex(&scp->mx);
2909 lock_ObtainRead(&scp->bufCreateLock);
2910 code = buf_Get(scp, &thyper, &bufferp);
2911 lock_ReleaseRead(&scp->bufCreateLock);
2913 /* now, if we're doing a star match, do bulk fetching
2914 * of all of the status info for files in the dir.
2917 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
2920 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
2921 && LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
2922 /* Don't bulk stat if risking timeout */
2923 int now = GetCurrentTime();
2924 if (now - req.startTime > 5000) {
2925 scp->bulkStatProgress = thyper;
2926 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2927 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2929 cm_TryBulkStat(scp, &thyper, userp, &req);
2933 lock_ObtainMutex(&scp->mx);
2935 bufferOffset = thyper;
2937 /* now get the data in the cache */
2939 code = cm_SyncOp(scp, bufferp, userp, &req,
2941 CM_SCACHESYNC_NEEDCALLBACK
2942 | CM_SCACHESYNC_READ);
2945 if (cm_HaveBuffer(scp, bufferp, 0)) break;
2947 /* otherwise, load the buffer and try again */
2948 code = cm_GetBuffer(scp, bufferp, NULL, userp,
2953 buf_Release(bufferp);
2957 } /* if (wrong buffer) ... */
2959 /* now we have the buffer containing the entry we're interested
2960 * in; copy it out if it represents a non-deleted entry.
2962 entryInDir = curOffset.LowPart & (2048-1);
2963 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
2965 /* page header will help tell us which entries are free. Page
2966 * header can change more often than once per buffer, since
2967 * AFS 3 dir page size may be less than (but not more than)
2968 * a buffer package buffer.
2970 /* only look intra-buffer */
2971 temp = curOffset.LowPart & (buf_bufferSize - 1);
2972 temp &= ~(2048 - 1); /* turn off intra-page bits */
2973 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
2975 /* now determine which entry we're looking at in the page.
2976 * If it is free (there's a free bitmap at the start of the
2977 * dir), we should skip these 32 bytes.
2979 slotInPage = (entryInDir & 0x7e0) >> 5;
2980 if (!(pageHeaderp->freeBitmap[slotInPage>>3]
2981 & (1 << (slotInPage & 0x7)))) {
2982 /* this entry is free */
2983 numDirChunks = 1; /* only skip this guy */
2987 tp = bufferp->datap + entryInBuffer;
2988 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
2990 /* while we're here, compute the next entry's location, too,
2991 * since we'll need it when writing out the cookie into the dir
2994 * XXXX Probably should do more sanity checking.
2996 numDirChunks = cm_NameEntries(dep->name, &onbytes);
2998 /* compute offset of cookie representing next entry */
2999 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3001 /* Need 8.3 name? */
3003 if (infoLevel == 0x104
3004 && dep->fid.vnode != 0
3005 && !cm_Is8Dot3(dep->name)) {
3006 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3010 /* When matching, we are using doing a case fold if we have a wildcard mask.
3011 * If we get a non-wildcard match, it's a lookup for a specific file.
3013 if (dep->fid.vnode != 0 &&
3014 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0))
3016 && smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
3018 /* Eliminate entries that don't match requested attributes */
3019 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
3020 smb_IsDotFile(dep->name))
3021 goto nextEntry; /* no hidden files */
3023 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3025 /* We have already done the cm_TryBulkStat above */
3026 fid.cell = scp->fid.cell;
3027 fid.volume = scp->fid.volume;
3028 fid.vnode = ntohl(dep->fid.vnode);
3029 fid.unique = ntohl(dep->fid.unique);
3030 fileType = cm_FindFileType(&fid);
3031 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
3032 "has filetype %d", dep->name,
3034 if (fileType == CM_SCACHETYPE_DIRECTORY)
3038 /* finally check if this name will fit */
3040 /* standard dir entry stuff */
3041 if (infoLevel < 0x101)
3042 ohbytes = 23; /* pre-NT */
3043 else if (infoLevel == 0x103)
3044 ohbytes = 12; /* NT names only */
3046 ohbytes = 64; /* NT */
3048 if (infoLevel == 0x104)
3049 ohbytes += 26; /* Short name & length */
3051 if (searchFlags & 4) {
3052 ohbytes += 4; /* if resume key required */
3056 && infoLevel != 0x101
3057 && infoLevel != 0x103)
3058 ohbytes += 4; /* EASIZE */
3060 /* add header to name & term. null */
3061 orbytes = onbytes + ohbytes + 1;
3063 /* now, we round up the record to a 4 byte alignment,
3064 * and we make sure that we have enough room here for
3065 * even the aligned version (so we don't have to worry
3066 * about an * overflow when we pad things out below).
3067 * That's the reason for the alignment arithmetic below.
3069 if (infoLevel >= 0x101)
3070 align = (4 - (orbytes & 3)) & 3;
3073 if (orbytes + bytesInBuffer + align > maxReturnData)
3076 /* this is one of the entries to use: it is not deleted
3077 * and it matches the star pattern we're looking for.
3078 * Put out the name, preceded by its length.
3080 /* First zero everything else */
3081 memset(origOp, 0, ohbytes);
3083 if (infoLevel <= 0x101)
3084 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
3085 else if (infoLevel == 0x103)
3086 *((u_long *)(op + 8)) = onbytes;
3088 *((u_long *)(op + 60)) = onbytes;
3089 strcpy(origOp+ohbytes, dep->name);
3091 /* Short name if requested and needed */
3092 if (infoLevel == 0x104) {
3093 if (NeedShortName) {
3094 strcpy(op + 70, shortName);
3095 *(op + 68) = shortNameEnd - shortName;
3099 /* now, adjust the # of entries copied */
3102 /* NextEntryOffset and FileIndex */
3103 if (infoLevel >= 101) {
3104 int entryOffset = orbytes + align;
3105 *((u_long *)op) = entryOffset;
3106 *((u_long *)(op+4)) = nextEntryCookie;
3109 /* now we emit the attribute. This is tricky, since
3110 * we need to really stat the file to find out what
3111 * type of entry we've got. Right now, we're copying
3112 * out data from * a buffer, while holding the scp
3113 * locked, so it isn't really convenient to stat
3114 * something now. We'll put in a place holder
3115 * now, and make a second pass before returning this
3116 * to get the real attributes. So, we just skip the
3117 * data for now, and adjust it later. We allocate a
3118 * patch record to make it easy to find this point
3119 * later. The replay will happen at a time when it is
3120 * safe to unlock the directory.
3122 if (infoLevel != 0x103) {
3123 curPatchp = malloc(sizeof(*curPatchp));
3124 osi_QAdd((osi_queue_t **) &dirListPatchesp,
3126 curPatchp->dptr = op;
3127 if (infoLevel >= 0x101)
3128 curPatchp->dptr += 8;
3130 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
3131 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3134 curPatchp->flags = 0;
3136 curPatchp->fid.cell = scp->fid.cell;
3137 curPatchp->fid.volume = scp->fid.volume;
3138 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3139 curPatchp->fid.unique = ntohl(dep->fid.unique);
3142 curPatchp->dep = dep;
3145 if (searchFlags & 4)
3146 /* put out resume key */
3147 *((u_long *)origOp) = nextEntryCookie;
3149 /* Adjust byte ptr and count */
3150 origOp += orbytes; /* skip entire record */
3151 bytesInBuffer += orbytes;
3153 /* and pad the record out */
3154 while (--align >= 0) {
3159 } /* if we're including this name */
3160 else if (!NeedShortName &&
3163 dep->fid.vnode != 0 &&
3164 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
3165 /* We were looking for exact matches, but here's an inexact one*/
3170 /* and adjust curOffset to be where the new cookie is */
3171 thyper.HighPart = 0;
3172 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3173 curOffset = LargeIntegerAdd(thyper, curOffset);
3174 } /* while copying data for dir listing */
3176 /* If we didn't get a star pattern, we did an exact match during the first pass.
3177 * If there were no exact matches found, we fail over to inexact matches by
3178 * marking the query as a star pattern (matches all case permutations), and
3179 * re-running the query.
3181 if (returnedNames == 0 && !starPattern && foundInexact) {
3182 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
3187 /* release the mutex */
3188 lock_ReleaseMutex(&scp->mx);
3189 if (bufferp) buf_Release(bufferp);
3191 /* apply and free last set of patches; if not doing a star match, this
3192 * will be empty, but better safe (and freeing everything) than sorry.
3194 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
3197 /* now put out the final parameters */
3198 if (returnedNames == 0) eos = 1;
3199 if (p->opcode == 1) {
3201 outp->parmsp[0] = (unsigned short) dsp->cookie;
3202 outp->parmsp[1] = returnedNames;
3203 outp->parmsp[2] = eos;
3204 outp->parmsp[3] = 0; /* nothing wrong with EAS */
3205 outp->parmsp[4] = 0;
3206 /* don't need last name to continue
3207 * search, cookie is enough. Normally,
3208 * this is the offset of the file name
3209 * of the last entry returned.
3211 outp->totalParms = 10; /* in bytes */
3215 outp->parmsp[0] = returnedNames;
3216 outp->parmsp[1] = eos;
3217 outp->parmsp[2] = 0; /* EAS error */
3218 outp->parmsp[3] = 0; /* last name, as above */
3219 outp->totalParms = 8; /* in bytes */
3222 /* return # of bytes in the buffer */
3223 outp->totalData = bytesInBuffer;
3225 osi_Log2(smb_logp, "T2 search dir done, %d names, code %d",
3226 returnedNames, code);
3228 /* Return error code if unsuccessful on first request */
3229 if (code == 0 && p->opcode == 1 && returnedNames == 0)
3230 code = CM_ERROR_NOSUCHFILE;
3232 /* if we're supposed to close the search after this request, or if
3233 * we're supposed to close the search if we're done, and we're done,
3234 * or if something went wrong, close the search.
3236 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
3237 if ((searchFlags & 1) || (returnedNames == 0) ||
3238 ((searchFlags & 2) && eos) || code != 0)
3239 smb_DeleteDirSearch(dsp);
3241 smb_SendTran2Error(vcp, p, opx, code);
3243 smb_SendTran2Packet(vcp, outp, opx);
3245 smb_FreeTran2Packet(outp);
3246 smb_ReleaseDirSearch(dsp);
3247 cm_ReleaseSCache(scp);
3248 cm_ReleaseUser(userp);
3252 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3255 smb_dirSearch_t *dsp;
3257 dirHandle = smb_GetSMBParm(inp, 0);
3259 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
3261 dsp = smb_FindDirSearch(dirHandle);
3264 return CM_ERROR_BADFD;
3266 /* otherwise, we have an FD to destroy */
3267 smb_DeleteDirSearch(dsp);
3268 smb_ReleaseDirSearch(dsp);
3270 /* and return results */
3271 smb_SetSMBDataLength(outp, 0);
3276 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3278 smb_SetSMBDataLength(outp, 0);
3282 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3289 cm_scache_t *dscp; /* dir we're dealing with */
3290 cm_scache_t *scp; /* file we're creating */
3292 int initialModeBits;
3302 int parmSlot; /* which parm we're dealing with */
3310 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
3311 openFun = smb_GetSMBParm(inp, 8); /* open function */
3312 excl = ((openFun & 3) == 0);
3313 trunc = ((openFun & 3) == 2); /* truncate it */
3314 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
3315 openAction = 0; /* tracks what we did */
3317 attributes = smb_GetSMBParm(inp, 5);
3318 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
3320 /* compute initial mode bits based on read-only flag in attributes */
3321 initialModeBits = 0666;
3322 if (attributes & 1) initialModeBits &= ~0222;
3324 pathp = smb_GetSMBData(inp, NULL);
3326 spacep = inp->spacep;
3327 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
3329 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3330 /* special case magic file name for receiving IOCTL requests
3331 * (since IOCTL calls themselves aren't getting through).
3334 osi_Log0(smb_logp, "IOCTL Open");
3337 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3338 smb_SetupIoctlFid(fidp, spacep);
3340 /* set inp->fid so that later read calls in same msg can find fid */
3341 inp->fid = fidp->fid;
3343 /* copy out remainder of the parms */
3345 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3347 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
3348 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
3349 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
3350 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
3351 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
3352 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
3353 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
3354 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
3356 /* and the final "always present" stuff */
3357 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
3358 /* next write out the "unique" ID */
3359 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
3360 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
3361 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
3362 smb_SetSMBDataLength(outp, 0);
3364 /* and clean up fid reference */
3365 smb_ReleaseFID(fidp);
3369 #ifdef DEBUG_VERBOSE
3371 char *hexp, *asciip;
3372 asciip = (lastNamep ? lastNamep : pathp );
3373 hexp = osi_HexifyString(asciip);
3374 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
3378 userp = smb_GetUser(vcp, inp);
3381 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3382 code = cm_NameI(cm_rootSCachep, pathp,
3383 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3384 userp, tidPathp, &req, &scp);
3386 code = cm_NameI(cm_rootSCachep, spacep->data,
3387 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3388 userp, tidPathp, &req, &dscp);
3391 cm_ReleaseUser(userp);
3395 /* otherwise, scp points to the parent directory. Do a lookup,
3396 * and truncate the file if we find it, otherwise we create the
3399 if (!lastNamep) lastNamep = pathp;
3401 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
3403 if (code && code != CM_ERROR_NOSUCHFILE) {
3404 cm_ReleaseSCache(dscp);
3405 cm_ReleaseUser(userp);
3410 /* if we get here, if code is 0, the file exists and is represented by
3411 * scp. Otherwise, we have to create it. The dir may be represented
3412 * by dscp, or we may have found the file directly. If code is non-zero,
3416 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
3418 if (dscp) cm_ReleaseSCache(dscp);
3419 cm_ReleaseSCache(scp);
3420 cm_ReleaseUser(userp);
3425 /* oops, file shouldn't be there */
3426 if (dscp) cm_ReleaseSCache(dscp);
3427 cm_ReleaseSCache(scp);
3428 cm_ReleaseUser(userp);
3429 return CM_ERROR_EXISTS;
3433 setAttr.mask = CM_ATTRMASK_LENGTH;
3434 setAttr.length.LowPart = 0;
3435 setAttr.length.HighPart = 0;
3436 code = cm_SetAttr(scp, &setAttr, userp, &req);
3437 openAction = 3; /* truncated existing file */
3439 else openAction = 1; /* found existing file */
3441 else if (!(openFun & 0x10)) {
3442 /* don't create if not found */
3443 if (dscp) cm_ReleaseSCache(dscp);
3444 cm_ReleaseUser(userp);
3445 return CM_ERROR_NOSUCHFILE;
3448 osi_assert(dscp != NULL);
3449 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
3450 osi_LogSaveString(smb_logp, lastNamep));
3451 openAction = 2; /* created file */
3452 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3453 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
3454 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3456 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3457 smb_NotifyChange(FILE_ACTION_ADDED,
3458 FILE_NOTIFY_CHANGE_FILE_NAME,
3459 dscp, lastNamep, NULL, TRUE);
3460 if (!excl && code == CM_ERROR_EXISTS) {
3461 /* not an exclusive create, and someone else tried
3462 * creating it already, then we open it anyway. We
3463 * don't bother retrying after this, since if this next
3464 * fails, that means that the file was deleted after we
3465 * started this call.
3467 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3471 setAttr.mask = CM_ATTRMASK_LENGTH;
3472 setAttr.length.LowPart = 0;
3473 setAttr.length.HighPart = 0;
3474 code = cm_SetAttr(scp, &setAttr, userp, &req);
3476 } /* lookup succeeded */
3480 /* we don't need this any longer */
3481 if (dscp) cm_ReleaseSCache(dscp);
3484 /* something went wrong creating or truncating the file */
3485 if (scp) cm_ReleaseSCache(scp);
3486 cm_ReleaseUser(userp);
3490 /* make sure we're about to open a file */
3491 if (scp->fileType != CM_SCACHETYPE_FILE) {
3492 cm_ReleaseSCache(scp);
3493 cm_ReleaseUser(userp);
3494 return CM_ERROR_ISDIR;
3497 /* now all we have to do is open the file itself */
3498 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3501 /* save a pointer to the vnode */
3504 /* compute open mode */
3505 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
3506 if (openMode == 1 || openMode == 2)
3507 fidp->flags |= SMB_FID_OPENWRITE;
3509 smb_ReleaseFID(fidp);
3511 cm_Open(scp, 0, userp);
3513 /* set inp->fid so that later read calls in same msg can find fid */
3514 inp->fid = fidp->fid;
3516 /* copy out remainder of the parms */
3518 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3519 lock_ObtainMutex(&scp->mx);
3521 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
3522 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
3523 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
3524 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
3525 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
3526 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
3527 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
3528 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
3529 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
3531 /* and the final "always present" stuff */
3532 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
3533 /* next write out the "unique" ID */
3534 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
3535 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
3536 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
3537 lock_ReleaseMutex(&scp->mx);
3538 smb_SetSMBDataLength(outp, 0);
3540 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
3542 cm_ReleaseUser(userp);
3543 /* leave scp held since we put it in fidp->scp */
3547 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3554 unsigned char LockType;
3555 unsigned short NumberOfUnlocks, NumberOfLocks;
3556 unsigned long Timeout;
3558 LARGE_INTEGER LOffset, LLength;
3559 smb_waitingLock_t *waitingLock;
3566 fid = smb_GetSMBParm(inp, 2);
3567 fid = smb_ChainFID(fid, inp);
3569 fidp = smb_FindFID(vcp, fid, 0);
3570 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
3571 return CM_ERROR_BADFD;
3573 /* set inp->fid so that later read calls in same msg can find fid */
3576 userp = smb_GetUser(vcp, inp);
3580 lock_ObtainMutex(&scp->mx);
3581 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3582 CM_SCACHESYNC_NEEDCALLBACK
3583 | CM_SCACHESYNC_GETSTATUS
3584 | CM_SCACHESYNC_LOCK);
3585 if (code) goto doneSync;
3587 LockType = smb_GetSMBParm(inp, 3) & 0xff;
3588 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
3589 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
3590 NumberOfLocks = smb_GetSMBParm(inp, 7);
3592 op = smb_GetSMBData(inp, NULL);
3594 for (i=0; i<NumberOfUnlocks; i++) {
3595 if (LockType & 0x10) {
3597 LOffset.HighPart = *((LONG *)(op + 4));
3598 LOffset.LowPart = *((DWORD *)(op + 8));
3599 LLength.HighPart = *((LONG *)(op + 12));
3600 LLength.LowPart = *((DWORD *)(op + 16));
3604 /* Not Large Files */
3605 LOffset.HighPart = 0;
3606 LOffset.LowPart = *((DWORD *)(op + 2));
3607 LLength.HighPart = 0;
3608 LLength.LowPart = *((DWORD *)(op + 6));
3611 if (LargeIntegerNotEqualToZero(LOffset))
3613 /* Do not check length -- length check done in cm_Unlock */
3615 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
3616 if (code) goto done;
3619 for (i=0; i<NumberOfLocks; i++) {
3620 if (LockType & 0x10) {
3622 LOffset.HighPart = *((LONG *)(op + 4));
3623 LOffset.LowPart = *((DWORD *)(op + 8));
3624 LLength.HighPart = *((LONG *)(op + 12));
3625 LLength.LowPart = *((DWORD *)(op + 16));
3629 /* Not Large Files */
3630 LOffset.HighPart = 0;
3631 LOffset.LowPart = *((DWORD *)(op + 2));
3632 LLength.HighPart = 0;
3633 LLength.LowPart = *((DWORD *)(op + 6));
3636 if (LargeIntegerNotEqualToZero(LOffset))
3638 if (LargeIntegerLessThan(LOffset, scp->length))
3641 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
3642 userp, &req, &lockp);
3643 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
3644 /* Put on waiting list */
3645 waitingLock = malloc(sizeof(smb_waitingLock_t));
3646 waitingLock->vcp = vcp;
3647 waitingLock->inp = smb_CopyPacket(inp);
3648 waitingLock->outp = smb_CopyPacket(outp);
3649 waitingLock->timeRemaining = Timeout;
3650 waitingLock->lockp = lockp;
3651 lock_ObtainWrite(&smb_globalLock);
3652 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
3654 osi_Wakeup((long) &smb_allWaitingLocks);
3655 lock_ReleaseWrite(&smb_globalLock);
3656 /* don't send reply immediately */
3657 outp->flags |= SMB_PACKETFLAG_NOSEND;
3663 /* release any locks acquired before the failure */
3666 smb_SetSMBDataLength(outp, 0);
3668 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
3670 lock_ReleaseMutex(&scp->mx);
3671 cm_ReleaseUser(userp);
3672 smb_ReleaseFID(fidp);
3677 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3689 fid = smb_GetSMBParm(inp, 0);
3690 fid = smb_ChainFID(fid, inp);
3692 fidp = smb_FindFID(vcp, fid, 0);
3693 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
3694 return CM_ERROR_BADFD;
3697 userp = smb_GetUser(vcp, inp);
3701 /* otherwise, stat the file */
3702 lock_ObtainMutex(&scp->mx);
3703 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3704 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3705 if (code) goto done;
3707 /* decode times. We need a search time, but the response to this
3708 * call provides the date first, not the time, as returned in the
3709 * searchTime variable. So we take the high-order bits first.
3711 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
3712 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
3713 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
3714 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
3715 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
3716 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
3717 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
3719 /* now handle file size and allocation size */
3720 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
3721 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
3722 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
3723 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
3725 /* file attribute */
3726 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
3728 /* and finalize stuff */
3729 smb_SetSMBDataLength(outp, 0);
3733 lock_ReleaseMutex(&scp->mx);
3734 cm_ReleaseUser(userp);
3735 smb_ReleaseFID(fidp);
3739 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3753 fid = smb_GetSMBParm(inp, 0);
3754 fid = smb_ChainFID(fid, inp);
3756 fidp = smb_FindFID(vcp, fid, 0);
3757 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
3758 return CM_ERROR_BADFD;
3761 userp = smb_GetUser(vcp, inp);
3765 /* now prepare to call cm_setattr. This message only sets various times,
3766 * and AFS only implements mtime, and we'll set the mtime if that's
3767 * requested. The others we'll ignore.
3769 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
3771 if (searchTime != 0) {
3772 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
3774 if ( unixTime != -1 ) {
3775 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
3776 attrs.clientModTime = unixTime;
3777 code = cm_SetAttr(scp, &attrs, userp, &req);
3779 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
3781 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
3786 cm_ReleaseUser(userp);
3787 smb_ReleaseFID(fidp);
3792 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3795 long count, finalCount;
3802 fd = smb_GetSMBParm(inp, 2);
3803 count = smb_GetSMBParm(inp, 5);
3804 offset.HighPart = 0; /* too bad */
3805 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
3807 osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
3808 fd, offset.LowPart, count);
3810 fd = smb_ChainFID(fd, inp);
3811 fidp = smb_FindFID(vcp, fd, 0);
3813 return CM_ERROR_BADFD;
3815 /* set inp->fid so that later read calls in same msg can find fid */
3818 if (fidp->flags & SMB_FID_IOCTL) {
3819 return smb_IoctlV3Read(fidp, vcp, inp, outp);
3822 userp = smb_GetUser(vcp, inp);
3824 /* 0 and 1 are reserved for request chaining, were setup by our caller,
3825 * and will be further filled in after we return.
3827 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
3828 smb_SetSMBParm(outp, 3, 0); /* resvd */
3829 smb_SetSMBParm(outp, 4, 0); /* resvd */
3830 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
3831 /* fill in #6 when we have all the parameters' space reserved */
3832 smb_SetSMBParm(outp, 7, 0); /* resv'd */
3833 smb_SetSMBParm(outp, 8, 0); /* resv'd */
3834 smb_SetSMBParm(outp, 9, 0); /* resv'd */
3835 smb_SetSMBParm(outp, 10, 0); /* resv'd */
3836 smb_SetSMBParm(outp, 11, 0); /* reserved */
3838 /* get op ptr after putting in the parms, since otherwise we don't
3839 * know where the data really is.
3841 op = smb_GetSMBData(outp, NULL);
3843 /* now fill in offset from start of SMB header to first data byte (to op) */
3844 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
3846 /* set the packet data length the count of the # of bytes */
3847 smb_SetSMBDataLength(outp, count);
3850 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
3852 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
3855 /* fix some things up */
3856 smb_SetSMBParm(outp, 5, finalCount);
3857 smb_SetSMBDataLength(outp, finalCount);
3859 smb_ReleaseFID(fidp);
3861 cm_ReleaseUser(userp);
3866 * Values for createDisp, copied from NTDDK.H
3868 * FILE_SUPERSEDE 0 (???)
3869 * FILE_OPEN 1 (open)
3870 * FILE_CREATE 2 (exclusive)
3871 * FILE_OPEN_IF 3 (non-exclusive)
3872 * FILE_OVERWRITE 4 (open & truncate, but do not create)
3873 * FILE_OVERWRITE_IF 5 (open & truncate, or create)
3876 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3878 char *pathp, *realPathp;
3882 cm_scache_t *dscp; /* parent dir */
3883 cm_scache_t *scp; /* file to create or open */
3887 unsigned short nameLength;
3889 unsigned int requestOpLock;
3890 unsigned int requestBatchOpLock;
3891 unsigned int mustBeDir;
3892 unsigned int treeCreate;
3894 unsigned int desiredAccess;
3895 unsigned int extAttributes;
3896 unsigned int createDisp;
3897 unsigned int createOptions;
3898 int initialModeBits;
3899 unsigned short baseFid;
3900 smb_fid_t *baseFidp;
3902 cm_scache_t *baseDirp;
3903 unsigned short openAction;
3918 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
3919 flags = smb_GetSMBOffsetParm(inp, 3, 1)
3920 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
3921 requestOpLock = flags & 0x02;
3922 requestBatchOpLock = flags & 0x04;
3923 mustBeDir = flags & 0x08;
3926 * Why all of a sudden 32-bit FID?
3927 * We will reject all bits higher than 16.
3929 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
3930 return CM_ERROR_INVAL;
3931 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
3932 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
3933 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3934 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
3935 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
3936 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
3937 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
3938 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
3939 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
3941 /* mustBeDir is never set; createOptions directory bit seems to be
3944 if (createOptions & 1)
3946 else if (createOptions & 0x40)
3952 * compute initial mode bits based on read-only flag in
3953 * extended attributes
3955 initialModeBits = 0666;
3956 if (extAttributes & 1) initialModeBits &= ~0222;
3958 pathp = smb_GetSMBData(inp, NULL);
3959 /* Sometimes path is not null-terminated, so we make a copy. */
3960 realPathp = malloc(nameLength+1);
3961 memcpy(realPathp, pathp, nameLength);
3962 realPathp[nameLength] = 0;
3964 spacep = inp->spacep;
3965 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3967 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
3968 osi_Log4(smb_logp,"NTCreateX da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
3969 osi_Log1(smb_logp,"NTCreateX lastNamep=[%s]",osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
3971 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3972 /* special case magic file name for receiving IOCTL requests
3973 * (since IOCTL calls themselves aren't getting through).
3975 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3976 smb_SetupIoctlFid(fidp, spacep);
3977 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
3979 /* set inp->fid so that later read calls in same msg can find fid */
3980 inp->fid = fidp->fid;
3984 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3985 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3986 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
3988 memset(&ft, 0, sizeof(ft));
3989 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3990 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3991 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3992 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3993 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
3994 sz.HighPart = 0x7fff; sz.LowPart = 0;
3995 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
3996 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
3997 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3998 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3999 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
4000 smb_SetSMBDataLength(outp, 0);
4002 /* clean up fid reference */
4003 smb_ReleaseFID(fidp);
4008 #ifdef DEBUG_VERBOSE
4010 char *hexp, *asciip;
4011 asciip = (lastNamep? lastNamep : realPathp);
4012 hexp = osi_HexifyString( asciip );
4013 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
4017 userp = smb_GetUser(vcp, inp);
4019 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
4021 return CM_ERROR_INVAL;
4025 baseDirp = cm_rootSCachep;
4026 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
4029 baseFidp = smb_FindFID(vcp, baseFid, 0);
4031 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
4033 cm_ReleaseUser(userp);
4034 return CM_ERROR_INVAL;
4036 baseDirp = baseFidp->scp;
4040 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
4042 /* compute open mode */
4044 if (desiredAccess & DELETE)
4045 fidflags |= SMB_FID_OPENDELETE;
4046 if (desiredAccess & AFS_ACCESS_READ)
4047 fidflags |= SMB_FID_OPENREAD;
4048 if (desiredAccess & AFS_ACCESS_WRITE)
4049 fidflags |= SMB_FID_OPENWRITE;
4053 /* For an exclusive create, we want to do a case sensitive match for the last component. */
4054 if (createDisp == 2 || createDisp == 4 || createDisp == 5) {
4055 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4056 userp, tidPathp, &req, &dscp);
4058 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
4060 if (code == CM_ERROR_NOSUCHFILE) {
4061 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
4062 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
4063 if (code == 0 && realDirFlag == 1) {
4064 cm_ReleaseSCache(scp);
4065 cm_ReleaseSCache(dscp);
4066 cm_ReleaseUser(userp);
4068 return CM_ERROR_EXISTS;
4074 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4075 userp, tidPathp, &req, &scp);
4080 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
4081 /* look up parent directory */
4082 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
4083 * the immediate parent. We have to work our way up realPathp until we hit something that we
4091 code = cm_NameI(baseDirp, spacep->data,
4092 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4093 userp, tidPathp, &req, &dscp);
4096 (tp = strrchr(spacep->data,'\\')) &&
4097 (createDisp == 2) &&
4098 (realDirFlag == 1)) {
4101 treeStartp = realPathp + (tp - spacep->data);
4103 if (*tp && !smb_IsLegalFilename(tp)) {
4105 smb_ReleaseFID(baseFidp);
4106 cm_ReleaseUser(userp);
4108 return CM_ERROR_BADNTFILENAME;
4118 smb_ReleaseFID(baseFidp);
4121 osi_Log0(smb_logp,"NTCreateX parent not found");
4122 cm_ReleaseUser(userp);
4127 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
4128 /* A file exists where we want a directory. */
4129 cm_ReleaseSCache(dscp);
4130 cm_ReleaseUser(userp);
4132 return CM_ERROR_EXISTS;
4136 lastNamep = realPathp;
4140 if (!smb_IsLegalFilename(lastNamep)) {
4141 cm_ReleaseSCache(dscp);
4142 cm_ReleaseUser(userp);
4144 return CM_ERROR_BADNTFILENAME;
4147 if (!foundscp && !treeCreate) {
4148 if (createDisp == 2 || createDisp == 4)
4149 code = cm_Lookup(dscp, lastNamep,
4150 CM_FLAG_FOLLOW, userp, &req, &scp);
4152 code = cm_Lookup(dscp, lastNamep,
4153 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4155 if (code && code != CM_ERROR_NOSUCHFILE) {
4156 cm_ReleaseSCache(dscp);
4157 cm_ReleaseUser(userp);
4165 smb_ReleaseFID(baseFidp);
4168 /* if we get here, if code is 0, the file exists and is represented by
4169 * scp. Otherwise, we have to create it. The dir may be represented
4170 * by dscp, or we may have found the file directly. If code is non-zero,
4173 if (code == 0 && !treeCreate) {
4174 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
4177 if (dscp) cm_ReleaseSCache(dscp);
4178 cm_ReleaseSCache(scp);
4179 cm_ReleaseUser(userp);
4184 if (createDisp == 2) {
4185 /* oops, file shouldn't be there */
4186 if (dscp) cm_ReleaseSCache(dscp);
4187 cm_ReleaseSCache(scp);
4188 cm_ReleaseUser(userp);
4190 return CM_ERROR_EXISTS;
4194 || createDisp == 5) {
4195 setAttr.mask = CM_ATTRMASK_LENGTH;
4196 setAttr.length.LowPart = 0;
4197 setAttr.length.HighPart = 0;
4198 code = cm_SetAttr(scp, &setAttr, userp, &req);
4199 openAction = 3; /* truncated existing file */
4201 else openAction = 1; /* found existing file */
4203 else if (createDisp == 1 || createDisp == 4) {
4204 /* don't create if not found */
4205 if (dscp) cm_ReleaseSCache(dscp);
4206 cm_ReleaseUser(userp);
4208 return CM_ERROR_NOSUCHFILE;
4210 else if (realDirFlag == 0 || realDirFlag == -1) {
4211 osi_assert(dscp != NULL);
4212 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
4213 osi_LogSaveString(smb_logp, lastNamep));
4214 openAction = 2; /* created file */
4215 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4216 setAttr.clientModTime = time(NULL);
4217 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4219 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4220 smb_NotifyChange(FILE_ACTION_ADDED,
4221 FILE_NOTIFY_CHANGE_FILE_NAME,
4222 dscp, lastNamep, NULL, TRUE);
4223 if (code == CM_ERROR_EXISTS && createDisp != 2) {
4224 /* Not an exclusive create, and someone else tried
4225 * creating it already, then we open it anyway. We
4226 * don't bother retrying after this, since if this next
4227 * fails, that means that the file was deleted after we
4228 * started this call.
4230 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4233 if (createDisp == 5) {
4234 setAttr.mask = CM_ATTRMASK_LENGTH;
4235 setAttr.length.LowPart = 0;
4236 setAttr.length.HighPart = 0;
4237 code = cm_SetAttr(scp, &setAttr, userp,
4240 } /* lookup succeeded */
4245 char *cp; /* This component */
4246 int clen = 0; /* length of component */
4250 /* create directory */
4251 if ( !treeCreate ) treeStartp = lastNamep;
4252 osi_assert(dscp != NULL);
4253 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
4254 osi_LogSaveString(smb_logp, treeStartp));
4255 openAction = 2; /* created directory */
4257 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4258 setAttr.clientModTime = time(NULL);
4265 tp = strchr(pp, '\\');
4269 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
4273 strncpy(cp,pp,clen);
4279 if (clen == 0) continue; /* the supplied path can't have consecutive slashes either , but */
4281 /* cp is the next component to be created. */
4282 code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
4283 if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
4284 smb_NotifyChange(FILE_ACTION_ADDED,
4285 FILE_NOTIFY_CHANGE_DIR_NAME,
4286 tscp, cp, NULL, TRUE);
4288 (code == CM_ERROR_EXISTS && createDisp != 2)) {
4289 /* Not an exclusive create, and someone else tried
4290 * creating it already, then we open it anyway. We
4291 * don't bother retrying after this, since if this next
4292 * fails, that means that the file was deleted after we
4293 * started this call.
4295 code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
4300 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
4301 cm_ReleaseSCache(tscp);
4302 tscp = scp; /* Newly created directory will be next parent */
4307 if we get here and code == 0, then scp is the last directory created, and tscp is the
4308 parent of scp. dscp got released if dscp != tscp. both tscp and scp are held.
4314 /* something went wrong creating or truncating the file */
4315 if (scp) cm_ReleaseSCache(scp);
4316 if (dscp) cm_ReleaseSCache(dscp);
4317 cm_ReleaseUser(userp);
4322 /* make sure we have file vs. dir right (only applies for single component case) */
4323 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
4324 cm_ReleaseSCache(scp);
4325 if (dscp) cm_ReleaseSCache(dscp);
4326 cm_ReleaseUser(userp);
4328 return CM_ERROR_ISDIR;
4330 /* (only applies to single component case) */
4331 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
4332 cm_ReleaseSCache(scp);
4333 if (dscp) cm_ReleaseSCache(dscp);
4334 cm_ReleaseUser(userp);
4336 return CM_ERROR_NOTDIR;
4339 /* open the file itself */
4340 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4342 /* save a pointer to the vnode */
4345 fidp->flags = fidflags;
4347 /* save parent dir and pathname for delete or change notification */
4348 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
4349 fidp->flags |= SMB_FID_NTOPEN;
4350 fidp->NTopen_dscp = dscp;
4351 cm_HoldSCache(dscp);
4352 fidp->NTopen_pathp = strdup(lastNamep);
4354 fidp->NTopen_wholepathp = realPathp;
4356 /* we don't need this any longer */
4357 if (dscp) cm_ReleaseSCache(dscp);
4358 cm_Open(scp, 0, userp);
4360 /* set inp->fid so that later read calls in same msg can find fid */
4361 inp->fid = fidp->fid;
4365 lock_ObtainMutex(&scp->mx);
4366 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
4367 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4368 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
4369 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4370 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4371 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4372 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4373 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4374 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
4376 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
4377 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
4378 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
4379 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
4380 smb_SetSMBParmByte(outp, parmSlot,
4381 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
4382 lock_ReleaseMutex(&scp->mx);
4383 smb_SetSMBDataLength(outp, 0);
4385 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
4386 osi_LogSaveString(smb_logp, realPathp));
4388 smb_ReleaseFID(fidp);
4390 cm_ReleaseUser(userp);
4392 /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
4394 /* leave scp held since we put it in fidp->scp */
4399 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
4400 * Instead, ultimately, would like to use a subroutine for common code.
4402 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4404 char *pathp, *realPathp;
4408 cm_scache_t *dscp; /* parent dir */
4409 cm_scache_t *scp; /* file to create or open */
4412 unsigned long nameLength;
4414 unsigned int requestOpLock;
4415 unsigned int requestBatchOpLock;
4416 unsigned int mustBeDir;
4417 unsigned int extendedRespRequired;
4419 unsigned int desiredAccess;
4420 #ifdef DEBUG_VERBOSE
4421 unsigned int allocSize;
4422 unsigned int shareAccess;
4424 unsigned int extAttributes;
4425 unsigned int createDisp;
4426 #ifdef DEBUG_VERBOSE
4429 unsigned int createOptions;
4430 int initialModeBits;
4431 unsigned short baseFid;
4432 smb_fid_t *baseFidp;
4434 cm_scache_t *baseDirp;
4435 unsigned short openAction;
4441 int parmOffset, dataOffset;
4452 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
4453 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
4454 parmp = inp->data + parmOffset;
4455 lparmp = (ULONG *) parmp;
4458 requestOpLock = flags & 0x02;
4459 requestBatchOpLock = flags & 0x04;
4460 mustBeDir = flags & 0x08;
4461 extendedRespRequired = flags & 0x10;
4464 * Why all of a sudden 32-bit FID?
4465 * We will reject all bits higher than 16.
4467 if (lparmp[1] & 0xFFFF0000)
4468 return CM_ERROR_INVAL;
4469 baseFid = (unsigned short)lparmp[1];
4470 desiredAccess = lparmp[2];
4471 #ifdef DEBUG_VERBOSE
4472 allocSize = lparmp[3];
4473 #endif /* DEBUG_VERSOSE */
4474 extAttributes = lparmp[5];
4476 shareAccess = lparmp[6];
4478 createDisp = lparmp[7];
4479 createOptions = lparmp[8];
4480 #ifdef DEBUG_VERBOSE
4483 nameLength = lparmp[11];
4485 #ifdef DEBUG_VERBOSE
4486 osi_Log4(smb_logp,"NTTransCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
4487 osi_Log2(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
4488 osi_Log1(smb_logp,"... flags[%x]",flags);
4491 /* mustBeDir is never set; createOptions directory bit seems to be
4494 if (createOptions & 1)
4496 else if (createOptions & 0x40)
4502 * compute initial mode bits based on read-only flag in
4503 * extended attributes
4505 initialModeBits = 0666;
4506 if (extAttributes & 1) initialModeBits &= ~0222;
4508 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
4509 /* Sometimes path is not null-terminated, so we make a copy. */
4510 realPathp = malloc(nameLength+1);
4511 memcpy(realPathp, pathp, nameLength);
4512 realPathp[nameLength] = 0;
4514 spacep = cm_GetSpace();
4515 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
4518 * Nothing here to handle SMB_IOCTL_FILENAME.
4519 * Will add it if necessary.
4522 #ifdef DEBUG_VERBOSE
4524 char *hexp, *asciip;
4525 asciip = (lastNamep? lastNamep : realPathp);
4526 hexp = osi_HexifyString( asciip );
4527 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
4532 userp = smb_GetUser(vcp, inp);
4534 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
4536 return CM_ERROR_INVAL;
4540 baseDirp = cm_rootSCachep;
4541 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
4544 baseFidp = smb_FindFID(vcp, baseFid, 0);
4546 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
4548 cm_ReleaseUser(userp);
4549 return CM_ERROR_INVAL;
4551 baseDirp = baseFidp->scp;
4555 /* compute open mode */
4557 if (desiredAccess & DELETE)
4558 fidflags |= SMB_FID_OPENDELETE;
4559 if (desiredAccess & AFS_ACCESS_READ)
4560 fidflags |= SMB_FID_OPENREAD;
4561 if (desiredAccess & AFS_ACCESS_WRITE)
4562 fidflags |= SMB_FID_OPENWRITE;
4566 if (createDisp == 2 || createDisp == 4 || createDisp == 5) {
4567 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4568 userp, tidPathp, &req, &dscp);
4570 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
4572 if (code == CM_ERROR_NOSUCHFILE) {
4573 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
4574 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
4575 if (code == 0 && realDirFlag == 1) {
4576 cm_ReleaseSCache(scp);
4577 cm_ReleaseSCache(dscp);
4578 cm_ReleaseUser(userp);
4580 return CM_ERROR_EXISTS;
4586 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4587 userp, tidPathp, &req, &scp);
4590 if (code == 0) foundscp = TRUE;
4592 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
4593 /* look up parent directory */
4595 code = cm_NameI(baseDirp, spacep->data,
4596 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4597 userp, tidPathp, &req, &dscp);
4601 cm_FreeSpace(spacep);
4604 smb_ReleaseFID(baseFidp);
4609 cm_ReleaseUser(userp);
4614 if (!lastNamep) lastNamep = realPathp;
4617 if (!smb_IsLegalFilename(lastNamep))
4618 return CM_ERROR_BADNTFILENAME;
4621 if (createDisp == 2 || createDisp == 4)
4622 code = cm_Lookup(dscp, lastNamep,
4623 CM_FLAG_FOLLOW, userp, &req, &scp);
4625 code = cm_Lookup(dscp, lastNamep,
4626 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4628 if (code && code != CM_ERROR_NOSUCHFILE) {
4629 cm_ReleaseSCache(dscp);
4630 cm_ReleaseUser(userp);
4638 smb_ReleaseFID(baseFidp);
4641 cm_FreeSpace(spacep);
4644 /* if we get here, if code is 0, the file exists and is represented by
4645 * scp. Otherwise, we have to create it. The dir may be represented
4646 * by dscp, or we may have found the file directly. If code is non-zero,
4650 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
4653 if (dscp) cm_ReleaseSCache(dscp);
4654 cm_ReleaseSCache(scp);
4655 cm_ReleaseUser(userp);
4660 if (createDisp == 2) {
4661 /* oops, file shouldn't be there */
4662 if (dscp) cm_ReleaseSCache(dscp);
4663 cm_ReleaseSCache(scp);
4664 cm_ReleaseUser(userp);
4666 return CM_ERROR_EXISTS;
4670 || createDisp == 5) {
4671 setAttr.mask = CM_ATTRMASK_LENGTH;
4672 setAttr.length.LowPart = 0;
4673 setAttr.length.HighPart = 0;
4674 code = cm_SetAttr(scp, &setAttr, userp, &req);
4675 openAction = 3; /* truncated existing file */
4677 else openAction = 1; /* found existing file */
4679 else if (createDisp == 1 || createDisp == 4) {
4680 /* don't create if not found */
4681 if (dscp) cm_ReleaseSCache(dscp);
4682 cm_ReleaseUser(userp);
4684 return CM_ERROR_NOSUCHFILE;
4686 else if (realDirFlag == 0 || realDirFlag == -1) {
4687 osi_assert(dscp != NULL);
4688 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
4689 osi_LogSaveString(smb_logp, lastNamep));
4690 openAction = 2; /* created file */
4691 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4692 setAttr.clientModTime = time(NULL);
4693 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4695 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4696 smb_NotifyChange(FILE_ACTION_ADDED,
4697 FILE_NOTIFY_CHANGE_FILE_NAME,
4698 dscp, lastNamep, NULL, TRUE);
4699 if (code == CM_ERROR_EXISTS && createDisp != 2) {
4700 /* Not an exclusive create, and someone else tried
4701 * creating it already, then we open it anyway. We
4702 * don't bother retrying after this, since if this next
4703 * fails, that means that the file was deleted after we
4704 * started this call.
4706 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4709 if (createDisp == 5) {
4710 setAttr.mask = CM_ATTRMASK_LENGTH;
4711 setAttr.length.LowPart = 0;
4712 setAttr.length.HighPart = 0;
4713 code = cm_SetAttr(scp, &setAttr, userp,
4716 } /* lookup succeeded */
4720 /* create directory */
4721 osi_assert(dscp != NULL);
4723 "smb_ReceiveNTTranCreate creating directory %s",
4724 osi_LogSaveString(smb_logp, lastNamep));
4725 openAction = 2; /* created directory */
4726 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4727 setAttr.clientModTime = time(NULL);
4728 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
4729 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4730 smb_NotifyChange(FILE_ACTION_ADDED,
4731 FILE_NOTIFY_CHANGE_DIR_NAME,
4732 dscp, lastNamep, NULL, TRUE);
4734 || (code == CM_ERROR_EXISTS && createDisp != 2)) {
4735 /* Not an exclusive create, and someone else tried
4736 * creating it already, then we open it anyway. We
4737 * don't bother retrying after this, since if this next
4738 * fails, that means that the file was deleted after we
4739 * started this call.
4741 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4747 /* something went wrong creating or truncating the file */
4748 if (scp) cm_ReleaseSCache(scp);
4749 cm_ReleaseUser(userp);
4754 /* make sure we have file vs. dir right */
4755 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
4756 cm_ReleaseSCache(scp);
4757 cm_ReleaseUser(userp);
4759 return CM_ERROR_ISDIR;
4761 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
4762 cm_ReleaseSCache(scp);
4763 cm_ReleaseUser(userp);
4765 return CM_ERROR_NOTDIR;
4768 /* open the file itself */
4769 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4772 /* save a pointer to the vnode */
4775 fidp->flags = fidflags;
4777 /* save parent dir and pathname for deletion or change notification */
4778 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
4779 fidp->flags |= SMB_FID_NTOPEN;
4780 fidp->NTopen_dscp = dscp;
4781 cm_HoldSCache(dscp);
4782 fidp->NTopen_pathp = strdup(lastNamep);
4784 fidp->NTopen_wholepathp = realPathp;
4786 /* we don't need this any longer */
4787 if (dscp) cm_ReleaseSCache(dscp);
4789 cm_Open(scp, 0, userp);
4791 /* set inp->fid so that later read calls in same msg can find fid */
4792 inp->fid = fidp->fid;
4794 /* check whether we are required to send an extended response */
4795 if (!extendedRespRequired) {
4797 parmOffset = 8*4 + 39;
4798 parmOffset += 1; /* pad to 4 */
4799 dataOffset = parmOffset + 70;
4803 /* Total Parameter Count */
4804 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
4805 /* Total Data Count */
4806 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4807 /* Parameter Count */
4808 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
4809 /* Parameter Offset */
4810 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
4811 /* Parameter Displacement */
4812 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4814 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4816 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
4817 /* Data Displacement */
4818 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4819 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
4820 smb_SetSMBDataLength(outp, 70);
4822 lock_ObtainMutex(&scp->mx);
4823 outData = smb_GetSMBData(outp, NULL);
4824 outData++; /* round to get to parmOffset */
4825 *outData = 0; outData++; /* oplock */
4826 *outData = 0; outData++; /* reserved */
4827 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
4828 *((ULONG *)outData) = openAction; outData += 4;
4829 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
4830 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4831 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
4832 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
4833 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
4834 *((FILETIME *)outData) = ft; outData += 8; /* change time */
4835 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
4836 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
4837 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
4838 *((USHORT *)outData) = 0; outData += 2; /* filetype */
4839 *((USHORT *)outData) = 0; outData += 2; /* dev state */
4840 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
4841 outData += 2; /* is a dir? */
4842 lock_ReleaseMutex(&scp->mx);
4845 parmOffset = 8*4 + 39;
4846 parmOffset += 1; /* pad to 4 */
4847 dataOffset = parmOffset + 104;
4851 /* Total Parameter Count */
4852 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
4853 /* Total Data Count */
4854 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4855 /* Parameter Count */
4856 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
4857 /* Parameter Offset */
4858 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
4859 /* Parameter Displacement */
4860 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4862 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4864 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
4865 /* Data Displacement */
4866 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4867 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
4868 smb_SetSMBDataLength(outp, 105);
4870 lock_ObtainMutex(&scp->mx);
4871 outData = smb_GetSMBData(outp, NULL);
4872 outData++; /* round to get to parmOffset */
4873 *outData = 0; outData++; /* oplock */
4874 *outData = 1; outData++; /* response type */
4875 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
4876 *((ULONG *)outData) = openAction; outData += 4;
4877 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
4878 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4879 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
4880 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
4881 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
4882 *((FILETIME *)outData) = ft; outData += 8; /* change time */
4883 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
4884 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
4885 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
4886 *((USHORT *)outData) = 0; outData += 2; /* filetype */
4887 *((USHORT *)outData) = 0; outData += 2; /* dev state */
4888 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
4889 outData += 1; /* is a dir? */
4890 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
4891 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
4892 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
4893 lock_ReleaseMutex(&scp->mx);
4896 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
4898 smb_ReleaseFID(fidp);
4900 cm_ReleaseUser(userp);
4902 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
4903 /* leave scp held since we put it in fidp->scp */
4907 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
4910 smb_packet_t *savedPacketp;
4911 ULONG filter; USHORT fid, watchtree;
4915 filter = smb_GetSMBParm(inp, 19)
4916 | (smb_GetSMBParm(inp, 20) << 16);
4917 fid = smb_GetSMBParm(inp, 21);
4918 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
4920 fidp = smb_FindFID(vcp, fid, 0);
4922 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
4923 return CM_ERROR_BADFD;
4926 savedPacketp = smb_CopyPacket(inp);
4928 savedPacketp->vcp = vcp;
4929 lock_ObtainMutex(&smb_Dir_Watch_Lock);
4930 savedPacketp->nextp = smb_Directory_Watches;
4931 smb_Directory_Watches = savedPacketp;
4932 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4934 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
4935 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
4938 lock_ObtainMutex(&scp->mx);
4940 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
4942 scp->flags |= CM_SCACHEFLAG_WATCHED;
4943 lock_ReleaseMutex(&scp->mx);
4944 smb_ReleaseFID(fidp);
4946 outp->flags |= SMB_PACKETFLAG_NOSEND;
4950 unsigned char nullSecurityDesc[36] = {
4951 0x01, /* security descriptor revision */
4952 0x00, /* reserved, should be zero */
4953 0x00, 0x80, /* security descriptor control;
4954 * 0x8000 : self-relative format */
4955 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
4956 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
4957 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
4958 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
4959 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4960 /* "null SID" owner SID */
4961 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4962 /* "null SID" group SID */
4965 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4967 int parmOffset, parmCount, dataOffset, dataCount;
4975 ULONG securityInformation;
4977 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
4978 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
4979 parmp = inp->data + parmOffset;
4980 sparmp = (USHORT *) parmp;
4981 lparmp = (ULONG *) parmp;
4984 securityInformation = lparmp[1];
4986 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
4987 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
4995 parmOffset = 8*4 + 39;
4996 parmOffset += 1; /* pad to 4 */
4998 dataOffset = parmOffset + parmCount;
5002 /* Total Parameter Count */
5003 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
5004 /* Total Data Count */
5005 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
5006 /* Parameter Count */
5007 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
5008 /* Parameter Offset */
5009 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5010 /* Parameter Displacement */
5011 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5013 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
5015 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5016 /* Data Displacement */
5017 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5018 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5019 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
5021 outData = smb_GetSMBData(outp, NULL);
5022 outData++; /* round to get to parmOffset */
5023 *((ULONG *)outData) = 36; outData += 4; /* length */
5025 if (maxData >= 36) {
5026 memcpy(outData, nullSecurityDesc, 36);
5030 return CM_ERROR_BUFFERTOOSMALL;
5033 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5035 unsigned short function;
5037 function = smb_GetSMBParm(inp, 18);
5039 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
5041 /* We can handle long names */
5042 if (vcp->flags & SMB_VCFLAG_USENT)
5043 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
5047 case 6: return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
5049 case 4: return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
5051 case 1: return smb_ReceiveNTTranCreate(vcp, inp, outp);
5053 default: return CM_ERROR_INVAL;
5058 * smb_NotifyChange -- find relevant change notification messages and
5061 * If we don't know the file name (i.e. a callback break), filename is
5062 * NULL, and we return a zero-length list.
5064 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
5065 cm_scache_t *dscp, char *filename, char *otherFilename,
5066 BOOL isDirectParent)
5068 smb_packet_t *watch, *lastWatch, *nextWatch;
5069 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
5070 char *outData, *oldOutData;
5074 BOOL twoEntries = FALSE;
5075 ULONG otherNameLen, oldParmCount = 0;
5080 /* Get ready for rename within directory */
5081 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
5083 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
5086 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
5087 osi_LogSaveString(smb_logp,filename),dscp);
5089 lock_ObtainMutex(&smb_Dir_Watch_Lock);
5090 watch = smb_Directory_Watches;
5092 filter = smb_GetSMBParm(watch, 19)
5093 | (smb_GetSMBParm(watch, 20) << 16);
5094 fid = smb_GetSMBParm(watch, 21);
5095 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
5096 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
5097 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
5101 * Strange hack - bug in NT Client and NT Server that we
5104 if (filter == 3 && wtree)
5107 fidp = smb_FindFID(vcp, fid, 0);
5109 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
5111 watch = watch->nextp;
5114 if (fidp->scp != dscp
5115 || (filter & notifyFilter) == 0
5116 || (!isDirectParent && !wtree)) {
5117 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
5118 smb_ReleaseFID(fidp);
5120 watch = watch->nextp;
5123 smb_ReleaseFID(fidp);
5126 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
5127 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
5129 nextWatch = watch->nextp;
5130 if (watch == smb_Directory_Watches)
5131 smb_Directory_Watches = nextWatch;
5133 lastWatch->nextp = nextWatch;
5135 /* Turn off WATCHED flag in dscp */
5136 lock_ObtainMutex(&dscp->mx);
5138 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
5140 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
5141 lock_ReleaseMutex(&dscp->mx);
5143 /* Convert to response packet */
5144 ((smb_t *) watch)->reb = 0x80;
5145 ((smb_t *) watch)->wct = 0;
5148 if (filename == NULL)
5151 nameLen = strlen(filename);
5152 parmCount = 3*4 + nameLen*2;
5153 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
5155 otherNameLen = strlen(otherFilename);
5156 oldParmCount = parmCount;
5157 parmCount += 3*4 + otherNameLen*2;
5158 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
5160 if (maxLen < parmCount)
5161 parmCount = 0; /* not enough room */
5163 parmOffset = 8*4 + 39;
5164 parmOffset += 1; /* pad to 4 */
5165 dataOffset = parmOffset + parmCount;
5169 /* Total Parameter Count */
5170 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
5171 /* Total Data Count */
5172 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
5173 /* Parameter Count */
5174 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
5175 /* Parameter Offset */
5176 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
5177 /* Parameter Displacement */
5178 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
5180 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
5182 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
5183 /* Data Displacement */
5184 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
5185 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
5186 smb_SetSMBDataLength(watch, parmCount + 1);
5188 if (parmCount != 0) {
5189 outData = smb_GetSMBData(watch, NULL);
5190 outData++; /* round to get to parmOffset */
5191 oldOutData = outData;
5192 *((DWORD *)outData) = oldParmCount; outData += 4;
5193 /* Next Entry Offset */
5194 *((DWORD *)outData) = action; outData += 4;
5196 *((DWORD *)outData) = nameLen*2; outData += 4;
5197 /* File Name Length */
5198 mbstowcs((WCHAR *)outData, filename, nameLen);
5201 outData = oldOutData + oldParmCount;
5202 *((DWORD *)outData) = 0; outData += 4;
5203 /* Next Entry Offset */
5204 *((DWORD *)outData) = otherAction; outData += 4;
5206 *((DWORD *)outData) = otherNameLen*2;
5207 outData += 4; /* File Name Length */
5208 mbstowcs((WCHAR *)outData, otherFilename,
5209 otherNameLen); /* File Name */
5214 * If filename is null, we don't know the cause of the
5215 * change notification. We return zero data (see above),
5216 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
5217 * (= 0x010C). We set the error code here by hand, without
5218 * modifying wct and bcc.
5220 if (filename == NULL) {
5221 ((smb_t *) watch)->rcls = 0x0C;
5222 ((smb_t *) watch)->reh = 0x01;
5223 ((smb_t *) watch)->errLow = 0;
5224 ((smb_t *) watch)->errHigh = 0;
5225 /* Set NT Status codes flag */
5226 ((smb_t *) watch)->flg2 |= 0x4000;
5229 smb_SendPacket(vcp, watch);
5231 smb_FreePacket(watch);
5234 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
5237 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5239 unsigned char *replyWctp;
5240 smb_packet_t *watch, *lastWatch;
5241 USHORT fid, watchtree;
5245 osi_Log0(smb_logp, "SMB3 receive NT cancel");
5247 lock_ObtainMutex(&smb_Dir_Watch_Lock);
5248 watch = smb_Directory_Watches;
5250 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
5251 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
5252 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
5253 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
5254 if (watch == smb_Directory_Watches)
5255 smb_Directory_Watches = watch->nextp;
5257 lastWatch->nextp = watch->nextp;
5258 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
5260 /* Turn off WATCHED flag in scp */
5261 fid = smb_GetSMBParm(watch, 21);
5262 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
5264 if (vcp != watch->vcp)
5265 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
5268 fidp = smb_FindFID(vcp, fid, 0);
5270 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
5272 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
5275 lock_ObtainMutex(&scp->mx);
5277 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
5279 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
5280 lock_ReleaseMutex(&scp->mx);
5281 smb_ReleaseFID(fidp);
5283 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
5286 /* assume STATUS32; return 0xC0000120 (CANCELED) */
5287 replyWctp = watch->wctp;
5291 ((smb_t *)watch)->rcls = 0x20;
5292 ((smb_t *)watch)->reh = 0x1;
5293 ((smb_t *)watch)->errLow = 0;
5294 ((smb_t *)watch)->errHigh = 0xC0;
5295 ((smb_t *)watch)->flg2 |= 0x4000;
5296 smb_SendPacket(vcp, watch);
5298 smb_ReleaseVC(watch->vcp);
5299 smb_FreePacket(watch);
5303 watch = watch->nextp;
5305 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
5312 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
5315 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
5318 smb_username_t *unp;
5320 unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
5322 lock_ObtainMutex(&unp->mx);
5323 unp->userp = cm_NewUser();
5324 lock_ReleaseMutex(&unp->mx);
5325 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
5326 osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
5328 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
5329 osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);