2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
15 #define SECURITY_WIN32
31 extern osi_hyper_t hzero;
33 smb_packet_t *smb_Directory_Watches = NULL;
34 osi_mutex_t smb_Dir_Watch_Lock;
36 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
38 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
40 /* protected by the smb_globalLock */
41 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
43 /* retrieve a held reference to a user structure corresponding to an incoming
45 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
50 uidp = smb_FindUID(vcp, inp->uid, 0);
51 if (!uidp) return NULL;
53 lock_ObtainMutex(&uidp->mx);
55 up = uidp->unp->userp;
58 lock_ReleaseMutex(&uidp->mx);
66 * Return extended attributes.
67 * Right now, we aren't using any of the "new" bits, so this looks exactly
68 * like smb_Attributes() (see smb.c).
70 unsigned long smb_ExtAttributes(cm_scache_t *scp)
74 if (scp->fileType == CM_SCACHETYPE_DIRECTORY
75 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
76 attrs = SMB_ATTR_DIRECTORY;
80 * We used to mark a file RO if it was in an RO volume, but that
81 * turns out to be impolitic in NT. See defect 10007.
84 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
86 if ((scp->unixModeBits & 0222) == 0)
87 attrs |= SMB_ATTR_READONLY; /* Read-only */
90 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
95 int smb_V3IsStarMask(char *maskp)
100 if (tc == '?' || tc == '*')
105 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
108 /* skip over null-terminated string */
109 *chainpp = inp + strlen(inp) + 1;
114 /*DEBUG do not checkin*/
115 void OutputDebugF(char * format, ...) {
120 va_start( args, format );
121 len = _vscprintf( format, args ) // _vscprintf doesn't count
122 + 3; // terminating '\0' + '\n'
123 buffer = malloc( len * sizeof(char) );
124 vsprintf( buffer, format, args );
125 strcat(buffer, "\n");
126 OutputDebugString(buffer);
130 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);
163 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
164 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength){
165 SECURITY_STATUS status, istatus;
166 CredHandle creds = {0,0};
168 SecBufferDesc secOut;
176 OutputDebugF("Negotiating Extended Security");
178 status = AcquireCredentialsHandle(
180 SMB_EXT_SEC_PACKAGE_NAME,
189 if (status != SEC_E_OK) {
190 /* Really bad. We return an empty security blob */
191 OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
196 secOut.pBuffers = &secTok;
197 secOut.ulVersion = SECBUFFER_VERSION;
199 secTok.BufferType = SECBUFFER_TOKEN;
201 secTok.pvBuffer = NULL;
203 ctx.dwLower = ctx.dwUpper = 0;
205 status = AcceptSecurityContext(
209 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
210 SECURITY_NETWORK_DREP,
217 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
218 OutputDebugF("Completing token...");
219 istatus = CompleteAuthToken(&ctx, &secOut);
220 if ( istatus != SEC_E_OK )
221 OutputDebugF("Token completion failed: %x", istatus);
224 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
225 if (secTok.pvBuffer) {
226 *secBlobLength = secTok.cbBuffer;
227 *secBlob = malloc( secTok.cbBuffer );
228 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
231 if ( status != SEC_E_OK )
232 OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
235 /* Discard partial security context */
236 DeleteSecurityContext(&ctx);
238 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
240 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
241 FreeCredentialsHandle(&creds);
247 struct smb_ext_context {
254 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
255 SECURITY_STATUS status, istatus;
259 SecBufferDesc secBufIn;
261 SecBufferDesc secBufOut;
264 struct smb_ext_context * secCtx = NULL;
265 struct smb_ext_context * newSecCtx = NULL;
266 void * assembledBlob = NULL;
267 int assembledBlobLength = 0;
270 OutputDebugF("In smb_AuthenticateUserExt");
273 *secBlobOutLength = 0;
275 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
276 secCtx = vcp->secCtx;
277 lock_ObtainMutex(&vcp->mx);
278 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
280 lock_ReleaseMutex(&vcp->mx);
284 OutputDebugF("Received incoming token:");
285 OutputDebugHexDump(secBlobIn,secBlobInLength);
289 OutputDebugF("Continuing with existing context.");
290 creds = secCtx->creds;
293 if (secCtx->partialToken) {
294 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
295 assembledBlob = malloc(assembledBlobLength);
296 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
297 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
300 status = AcquireCredentialsHandle(
302 SMB_EXT_SEC_PACKAGE_NAME,
311 if (status != SEC_E_OK) {
312 OutputDebugF("Can't acquire Credentials handle [%lX]", status);
313 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
321 secBufIn.cBuffers = 1;
322 secBufIn.pBuffers = &secTokIn;
323 secBufIn.ulVersion = SECBUFFER_VERSION;
325 secTokIn.BufferType = SECBUFFER_TOKEN;
327 secTokIn.cbBuffer = assembledBlobLength;
328 secTokIn.pvBuffer = assembledBlob;
330 secTokIn.cbBuffer = secBlobInLength;
331 secTokIn.pvBuffer = secBlobIn;
334 secBufOut.cBuffers = 1;
335 secBufOut.pBuffers = &secTokOut;
336 secBufOut.ulVersion = SECBUFFER_VERSION;
338 secTokOut.BufferType = SECBUFFER_TOKEN;
339 secTokOut.cbBuffer = 0;
340 secTokOut.pvBuffer = NULL;
342 status = AcceptSecurityContext(
344 ((secCtx)?&ctx:NULL),
346 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
347 SECURITY_NETWORK_DREP,
354 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
355 OutputDebugF("Completing token...");
356 istatus = CompleteAuthToken(&ctx, &secBufOut);
357 if ( istatus != SEC_E_OK )
358 OutputDebugF("Token completion failed: %lX", istatus);
361 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
362 OutputDebugF("Continue needed");
364 newSecCtx = malloc(sizeof(*newSecCtx));
366 newSecCtx->creds = creds;
367 newSecCtx->ctx = ctx;
368 newSecCtx->partialToken = NULL;
369 newSecCtx->partialTokenLen = 0;
371 lock_ObtainMutex( &vcp->mx );
372 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
373 vcp->secCtx = newSecCtx;
374 lock_ReleaseMutex( &vcp->mx );
376 code = CM_ERROR_GSSCONTINUE;
379 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
380 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
381 secTokOut.pvBuffer) {
382 OutputDebugF("Need to send token back to client");
384 *secBlobOutLength = secTokOut.cbBuffer;
385 *secBlobOut = malloc(secTokOut.cbBuffer);
386 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
388 OutputDebugF("Outgoing token:");
389 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
390 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
391 OutputDebugF("Incomplete message");
393 newSecCtx = malloc(sizeof(*newSecCtx));
395 newSecCtx->creds = creds;
396 newSecCtx->ctx = ctx;
397 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
398 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
399 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
401 lock_ObtainMutex( &vcp->mx );
402 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
403 vcp->secCtx = newSecCtx;
404 lock_ReleaseMutex( &vcp->mx );
406 code = CM_ERROR_GSSCONTINUE;
409 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
411 SecPkgContext_Names names;
413 OutputDebugF("Authentication completed");
414 OutputDebugF("Returned flags : [%lX]", flags);
416 if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
417 OutputDebugF("Received name [%s]", names.sUserName);
418 strcpy(usern, names.sUserName);
419 strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
420 FreeContextBuffer(names.sUserName);
422 /* Force the user to retry if the context is invalid */
423 OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
424 code = CM_ERROR_BADPASSWORD;
428 case SEC_E_INVALID_TOKEN:
429 OutputDebugF("Returning bad password :: INVALID_TOKEN");
431 case SEC_E_INVALID_HANDLE:
432 OutputDebugF("Returning bad password :: INVALID_HANDLE");
434 case SEC_E_LOGON_DENIED:
435 OutputDebugF("Returning bad password :: LOGON_DENIED");
437 case SEC_E_UNKNOWN_CREDENTIALS:
438 OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
440 case SEC_E_NO_CREDENTIALS:
441 OutputDebugF("Returning bad password :: NO_CREDENTIALS");
443 case SEC_E_CONTEXT_EXPIRED:
444 OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
446 case SEC_E_INCOMPLETE_CREDENTIALS:
447 OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
449 case SEC_E_WRONG_PRINCIPAL:
450 OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
452 case SEC_E_TIME_SKEW:
453 OutputDebugF("Returning bad password :: TIME_SKEW");
456 OutputDebugF("Returning bad password :: Status == %lX", status);
458 code = CM_ERROR_BADPASSWORD;
462 if (secCtx->partialToken) free(secCtx->partialToken);
470 if (secTokOut.pvBuffer)
471 FreeContextBuffer(secTokOut.pvBuffer);
473 if (code != CM_ERROR_GSSCONTINUE) {
474 DeleteSecurityContext(&ctx);
475 FreeCredentialsHandle(&creds);
483 #define P_RESP_LEN 128
485 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
486 So put stuff in a struct. */
487 struct Lm20AuthBlob {
488 MSV1_0_LM20_LOGON lmlogon;
489 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
490 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
491 WCHAR accountNameW[P_LEN];
492 WCHAR primaryDomainW[P_LEN];
493 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
494 TOKEN_GROUPS tgroups;
495 TOKEN_SOURCE tsource;
498 long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength) {
501 struct Lm20AuthBlob lmAuth;
502 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
503 QUOTA_LIMITS quotaLimits;
505 ULONG lmprofilepSize;
509 OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
510 OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
512 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
513 OutputDebugF("ciPwdLength or csPwdLength is too long");
514 return CM_ERROR_BADPASSWORD;
517 memset(&lmAuth,0,sizeof(lmAuth));
519 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
521 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
522 mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
523 lmAuth.lmlogon.LogonDomainName.Length = wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR);
524 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
526 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
527 mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
528 lmAuth.lmlogon.UserName.Length = wcslen(lmAuth.accountNameW) * sizeof(WCHAR);
529 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
531 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
532 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
533 size = MAX_COMPUTERNAME_LENGTH + 1;
534 GetComputerNameW(lmAuth.workstationW, &size);
535 lmAuth.lmlogon.Workstation.Length = wcslen(lmAuth.workstationW) * sizeof(WCHAR);
537 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
539 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
540 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
541 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
542 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
544 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
545 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
546 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
547 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
549 lmAuth.lmlogon.ParameterControl = 0;
551 lmAuth.tgroups.GroupCount = 0;
552 lmAuth.tgroups.Groups[0].Sid = NULL;
553 lmAuth.tgroups.Groups[0].Attributes = 0;
555 lmAuth.tsource.SourceIdentifier.HighPart = 0;
556 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD) vcp;
557 strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
575 OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
576 OutputDebugF("Extended status is 0x%lX", ntsEx);
578 if (nts == ERROR_SUCCESS) {
580 LsaFreeReturnBuffer(lmprofilep);
581 CloseHandle(lmToken);
585 if (nts == 0xC000015BL)
586 return CM_ERROR_BADLOGONTYPE;
587 else /* our catchall is a bad password though we could be more specific */
588 return CM_ERROR_BADPASSWORD;
592 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
593 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName) {
598 /* check if we have sane input */
599 if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
602 /* we could get : [accountName][domainName]
608 atsign = strchr(accountName, '@');
610 if (atsign) /* [user@domain][] -> [user@domain][domain] */
615 /* if for some reason the client doesn't know what domain to use,
616 it will either return an empty string or a '?' */
617 if (!domain[0] || domain[0] == '?')
618 /* Empty domains and empty usernames are usually sent from tokenless contexts.
619 This way such logins will get an empty username (easy to check). I don't know
620 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
621 strcpy(usern,accountName);
623 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
624 strcpy(usern,domain);
627 strncat(usern,accountName,atsign - accountName);
629 strcat(usern,accountName);
637 /* When using SMB auth, all SMB sessions have to pass through here first to
638 * authenticate the user.
639 * Caveat: If not use the SMB auth the protocol does not require sending a
640 * session setup packet, which means that we can't rely on a UID in subsequent
641 * packets. Though in practice we get one anyway.
643 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
647 unsigned short newUid;
648 unsigned long caps = 0;
653 char usern[SMB_MAX_USERNAME_LENGTH];
654 char *secBlobOut = NULL;
655 int secBlobOutLength = 0;
657 /* Check for bad conns */
658 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
659 return CM_ERROR_REMOTECONN;
661 if (vcp->flags & SMB_VCFLAG_USENT) {
662 if (smb_authType == SMB_AUTH_EXTENDED) {
663 /* extended authentication */
667 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
668 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
671 secBlobInLength = smb_GetSMBParm(inp, 7);
672 secBlobIn = smb_GetSMBData(inp, NULL);
674 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
676 if (code == CM_ERROR_GSSCONTINUE) {
677 smb_SetSMBParm(outp, 2, 0);
678 smb_SetSMBParm(outp, 3, secBlobOutLength);
679 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
680 tp = smb_GetSMBData(outp, NULL);
681 if (secBlobOutLength) {
682 memcpy(tp, secBlobOut, secBlobOutLength);
684 tp += secBlobOutLength;
686 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
687 tp += smb_ServerOSLength;
688 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
689 tp += smb_ServerLanManagerLength;
690 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
691 tp += smb_ServerDomainNameLength;
694 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
696 unsigned ciPwdLength, csPwdLength;
702 /* TODO: parse for extended auth as well */
703 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
704 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
706 tp = smb_GetSMBData(inp, &datalen);
708 OutputDebugF("Session packet data size [%d]",datalen);
715 accountName = smb_ParseString(tp, &tp);
716 primaryDomain = smb_ParseString(tp, NULL);
718 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
719 /* shouldn't happen */
720 code = CM_ERROR_BADSMB;
721 goto after_read_packet;
724 /* capabilities are only valid for first session packet */
725 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
726 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
729 if (smb_authType == SMB_AUTH_NTLM) {
730 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
734 unsigned ciPwdLength;
739 ciPwdLength = smb_GetSMBParm(inp, 7);
740 tp = smb_GetSMBData(inp, NULL);
744 accountName = smb_ParseString(tp, &tp);
745 primaryDomain = smb_ParseString(tp, NULL);
747 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
748 /* shouldn't happen */
749 code = CM_ERROR_BADSMB;
750 goto after_read_packet;
753 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
756 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
757 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
762 /* note down that we received a session setup X and set the capabilities flag */
763 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
764 lock_ObtainMutex(&vcp->mx);
765 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
766 /* for the moment we can only deal with NTSTATUS */
767 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
768 vcp->flags |= SMB_VCFLAG_STATUS32;
770 lock_ReleaseMutex(&vcp->mx);
773 /* code would be non-zero if there was an authentication failure.
774 Ideally we would like to invalidate the uid for this session or break
775 early to avoid accidently stealing someone else's tokens. */
781 OutputDebugF("Received username=[%s]", usern);
783 /* On Windows 2000, this function appears to be called more often than
784 it is expected to be called. This resulted in multiple smb_user_t
785 records existing all for the same user session which results in all
786 of the users tokens disappearing.
788 To avoid this problem, we look for an existing smb_user_t record
789 based on the users name, and use that one if we find it.
792 uidp = smb_FindUserByNameThisSession(vcp, usern);
793 if (uidp) { /* already there, so don't create a new one */
796 newUid = (unsigned short)uidp->userID; /* For some reason these are different types!*/
797 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"FindUserByName:Lana[%d],lsn[%d],userid[%d],name[%s]",vcp->lana,vcp->lsn,newUid,usern);
798 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
799 smb_ReleaseUID(uidp);
802 /* do a global search for the username/machine name pair */
803 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
805 /* Create a new UID and cm_user_t structure */
808 userp = cm_NewUser();
809 lock_ObtainMutex(&vcp->mx);
810 if (!vcp->uidCounter)
811 vcp->uidCounter++; /* handle unlikely wraparounds */
812 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
813 lock_ReleaseMutex(&vcp->mx);
815 /* Create a new smb_user_t structure and connect them up */
816 lock_ObtainMutex(&unp->mx);
818 lock_ReleaseMutex(&unp->mx);
820 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
821 lock_ObtainMutex(&uidp->mx);
823 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);
824 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
825 lock_ReleaseMutex(&uidp->mx);
826 smb_ReleaseUID(uidp);
829 /* Return UID to the client */
830 ((smb_t *)outp)->uid = newUid;
831 /* Also to the next chained message */
832 ((smb_t *)inp)->uid = newUid;
834 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
835 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
837 smb_SetSMBParm(outp, 2, 0);
839 if (vcp->flags & SMB_VCFLAG_USENT) {
840 if (smb_authType == SMB_AUTH_EXTENDED) {
841 smb_SetSMBParm(outp, 3, secBlobOutLength);
842 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
843 tp = smb_GetSMBData(outp, NULL);
844 if (secBlobOutLength) {
845 memcpy(tp, secBlobOut, secBlobOutLength);
847 tp += secBlobOutLength;
849 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
850 tp += smb_ServerOSLength;
851 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
852 tp += smb_ServerLanManagerLength;
853 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
854 tp += smb_ServerDomainNameLength;
856 smb_SetSMBDataLength(outp, 0);
859 if (smb_authType == SMB_AUTH_EXTENDED) {
860 smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
861 tp = smb_GetSMBData(outp, NULL);
862 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
863 tp += smb_ServerOSLength;
864 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
865 tp += smb_ServerLanManagerLength;
866 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
867 tp += smb_ServerDomainNameLength;
869 smb_SetSMBDataLength(outp, 0);
876 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
880 /* don't get tokens from this VC */
881 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
883 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
885 /* find the tree and free it */
886 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
887 /* TODO: smb_ReleaseUID() ? */
889 char *s1 = NULL, *s2 = NULL;
891 if (s2 == NULL) s2 = " ";
892 if (s1 == NULL) {s1 = s2; s2 = " ";}
894 osi_Log4(smb_logp, "SMB3 user logoffX uid %d name %s%s%s", uidp->userID,
895 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "), s1, s2);
897 lock_ObtainMutex(&uidp->mx);
898 uidp->flags |= SMB_USERFLAG_DELETE;
900 * it doesn't get deleted right away
901 * because the vcp points to it
903 lock_ReleaseMutex(&uidp->mx);
906 osi_Log0(smb_logp, "SMB3 user logoffX");
908 smb_SetSMBDataLength(outp, 0);
912 #define SMB_SUPPORT_SEARCH_BITS 0x0001
914 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
918 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) {
945 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
948 return CM_ERROR_NOIPC;
952 userp = smb_GetUser(vcp, inp);
954 lock_ObtainMutex(&vcp->mx);
955 newTid = vcp->tidCounter++;
956 lock_ReleaseMutex(&vcp->mx);
958 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
961 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
962 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
964 smb_ReleaseUID(uidp);
966 smb_ReleaseTID(tidp);
967 return CM_ERROR_BADSHARENAME;
970 if (vcp->flags & SMB_VCFLAG_USENT)
972 int policy = smb_FindShareCSCPolicy(shareName);
973 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS | (policy << 2));
976 smb_SetSMBParm(outp, 2, 0);
980 lock_ObtainMutex(&tidp->mx);
982 tidp->pathname = sharePath;
983 if(ipc) tidp->flags |= SMB_TIDFLAG_IPC;
984 lock_ReleaseMutex(&tidp->mx);
985 smb_ReleaseTID(tidp);
987 ((smb_t *)outp)->tid = newTid;
988 ((smb_t *)inp)->tid = newTid;
989 tp = smb_GetSMBData(outp, NULL);
994 smb_SetSMBDataLength(outp, 3);
997 smb_SetSMBDataLength(outp, 4);
1000 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1004 /* must be called with global tran lock held */
1005 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1007 smb_tran2Packet_t *tp;
1010 smbp = (smb_t *) inp->data;
1011 for(tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1012 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1018 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1019 int totalParms, int totalData)
1021 smb_tran2Packet_t *tp;
1024 smbp = (smb_t *) inp->data;
1025 tp = malloc(sizeof(*tp));
1026 memset(tp, 0, sizeof(*tp));
1029 tp->curData = tp->curParms = 0;
1030 tp->totalData = totalData;
1031 tp->totalParms = totalParms;
1032 tp->tid = smbp->tid;
1033 tp->mid = smbp->mid;
1034 tp->uid = smbp->uid;
1035 tp->pid = smbp->pid;
1036 tp->res[0] = smbp->res[0];
1037 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1038 if (totalParms != 0)
1039 tp->parmsp = malloc(totalParms);
1041 tp->datap = malloc(totalData);
1042 if (smbp->com == 0x25 || smbp->com == 0x26)
1045 tp->opcode = smb_GetSMBParm(inp, 14);
1048 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1052 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1053 smb_tran2Packet_t *inp, smb_packet_t *outp,
1054 int totalParms, int totalData)
1056 smb_tran2Packet_t *tp;
1057 unsigned short parmOffset;
1058 unsigned short dataOffset;
1059 unsigned short dataAlign;
1061 tp = malloc(sizeof(*tp));
1062 memset(tp, 0, sizeof(*tp));
1064 tp->curData = tp->curParms = 0;
1065 tp->totalData = totalData;
1066 tp->totalParms = totalParms;
1067 tp->oldTotalParms = totalParms;
1072 tp->res[0] = inp->res[0];
1073 tp->opcode = inp->opcode;
1077 * We calculate where the parameters and data will start.
1078 * This calculation must parallel the calculation in
1079 * smb_SendTran2Packet.
1082 parmOffset = 10*2 + 35;
1083 parmOffset++; /* round to even */
1084 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1086 dataOffset = parmOffset + totalParms;
1087 dataAlign = dataOffset & 2; /* quad-align */
1088 dataOffset += dataAlign;
1089 tp->datap = outp->data + dataOffset;
1094 /* free a tran2 packet; must be called with smb_globalLock held */
1095 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1097 if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
1098 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1107 /* called with a VC, an input packet to respond to, and an error code.
1108 * sends an error response.
1110 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1111 smb_packet_t *tp, long code)
1114 unsigned short errCode;
1115 unsigned char errClass;
1116 unsigned long NTStatus;
1118 if (vcp->flags & SMB_VCFLAG_STATUS32)
1119 smb_MapNTError(code, &NTStatus);
1121 smb_MapCoreError(code, vcp, &errCode, &errClass);
1123 smb_FormatResponsePacket(vcp, NULL, tp);
1124 smbp = (smb_t *) tp;
1126 /* We can handle long names */
1127 if (vcp->flags & SMB_VCFLAG_USENT)
1128 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
1130 /* now copy important fields from the tran 2 packet */
1131 smbp->com = t2p->com;
1132 smbp->tid = t2p->tid;
1133 smbp->mid = t2p->mid;
1134 smbp->pid = t2p->pid;
1135 smbp->uid = t2p->uid;
1136 smbp->res[0] = t2p->res[0];
1137 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1138 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1139 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1140 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1141 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1142 smbp->flg2 |= 0x4000;
1145 smbp->rcls = errClass;
1146 smbp->errLow = (unsigned char) (errCode & 0xff);
1147 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1151 smb_SendPacket(vcp, tp);
1154 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1157 unsigned short parmOffset;
1158 unsigned short dataOffset;
1159 unsigned short totalLength;
1160 unsigned short dataAlign;
1163 smb_FormatResponsePacket(vcp, NULL, tp);
1164 smbp = (smb_t *) tp;
1166 /* We can handle long names */
1167 if (vcp->flags & SMB_VCFLAG_USENT)
1168 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
1170 /* now copy important fields from the tran 2 packet */
1171 smbp->com = t2p->com;
1172 smbp->tid = t2p->tid;
1173 smbp->mid = t2p->mid;
1174 smbp->pid = t2p->pid;
1175 smbp->uid = t2p->uid;
1176 smbp->res[0] = t2p->res[0];
1178 totalLength = 1 + t2p->totalData + t2p->totalParms;
1180 /* now add the core parameters (tran2 info) to the packet */
1181 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1182 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1183 smb_SetSMBParm(tp, 2, 0); /* reserved */
1184 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1185 parmOffset = 10*2 + 35; /* parm offset in packet */
1186 parmOffset++; /* round to even */
1187 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1188 * hdr, bcc and wct */
1189 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1190 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1191 dataOffset = parmOffset + t2p->oldTotalParms;
1192 dataAlign = dataOffset & 2; /* quad-align */
1193 dataOffset += dataAlign;
1194 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1195 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1196 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1199 datap = smb_GetSMBData(tp, NULL);
1200 *datap++ = 0; /* we rounded to even */
1202 totalLength += dataAlign;
1203 smb_SetSMBDataLength(tp, totalLength);
1205 /* next, send the datagram */
1206 smb_SendPacket(vcp, tp);
1209 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1211 smb_tran2Packet_t *asp;
1224 /* We sometimes see 0 word count. What to do? */
1225 if (*inp->wctp == 0) {
1230 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1232 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1233 ptbuf[0] = "Transaction2 word count = 0";
1234 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1235 1, inp->ncb_length, ptbuf, inp);
1236 DeregisterEventSource(h);
1238 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1241 smb_SetSMBDataLength(outp, 0);
1242 smb_SendPacket(vcp, outp);
1246 totalParms = smb_GetSMBParm(inp, 0);
1247 totalData = smb_GetSMBParm(inp, 1);
1249 firstPacket = (inp->inCom == 0x25);
1251 /* find the packet we're reassembling */
1252 lock_ObtainWrite(&smb_globalLock);
1253 asp = smb_FindTran2Packet(vcp, inp);
1255 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1257 lock_ReleaseWrite(&smb_globalLock);
1259 /* now merge in this latest packet; start by looking up offsets */
1261 parmDisp = dataDisp = 0;
1262 parmOffset = smb_GetSMBParm(inp, 10);
1263 dataOffset = smb_GetSMBParm(inp, 12);
1264 parmCount = smb_GetSMBParm(inp, 9);
1265 dataCount = smb_GetSMBParm(inp, 11);
1266 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1267 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1269 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1270 totalData, dataCount, asp->maxReturnData);
1273 parmDisp = smb_GetSMBParm(inp, 4);
1274 parmOffset = smb_GetSMBParm(inp, 3);
1275 dataDisp = smb_GetSMBParm(inp, 7);
1276 dataOffset = smb_GetSMBParm(inp, 6);
1277 parmCount = smb_GetSMBParm(inp, 2);
1278 dataCount = smb_GetSMBParm(inp, 5);
1280 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1281 parmCount, dataCount);
1284 /* now copy the parms and data */
1285 if ( parmCount != 0 )
1287 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1289 if ( dataCount != 0 ) {
1290 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1293 /* account for new bytes */
1294 asp->curData += dataCount;
1295 asp->curParms += parmCount;
1297 /* finally, if we're done, remove the packet from the queue and dispatch it */
1298 if (asp->totalData <= asp->curData && asp->totalParms <= asp->curParms) {
1299 /* we've received it all */
1300 lock_ObtainWrite(&smb_globalLock);
1301 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1302 lock_ReleaseWrite(&smb_globalLock);
1304 /* now dispatch it */
1305 rapOp = asp->parmsp[0];
1307 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1308 osi_LogEvent("AFS-Dispatch-RAP[%s]",myCrt_RapDispatch(rapOp),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1309 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%x] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1310 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1313 osi_LogEvent("AFS-Dispatch-RAP [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1314 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1315 code = CM_ERROR_BADOP;
1318 /* if an error is returned, we're supposed to send an error packet,
1319 * otherwise the dispatched function already did the data sending.
1320 * We give dispatched proc the responsibility since it knows how much
1321 * space to allocate.
1324 smb_SendTran2Error(vcp, asp, outp, code);
1327 /* free the input tran 2 packet */
1328 lock_ObtainWrite(&smb_globalLock);
1329 smb_FreeTran2Packet(asp);
1330 lock_ReleaseWrite(&smb_globalLock);
1332 else if (firstPacket) {
1333 /* the first packet in a multi-packet request, we need to send an
1334 * ack to get more data.
1336 smb_SetSMBDataLength(outp, 0);
1337 smb_SendPacket(vcp, outp);
1343 /* ANSI versions. The unicode versions support arbitrary length
1344 share names, but we don't support unicode yet. */
1346 typedef struct smb_rap_share_info_0 {
1347 char shi0_netname[13];
1348 } smb_rap_share_info_0_t;
1350 typedef struct smb_rap_share_info_1 {
1351 char shi1_netname[13];
1354 DWORD shi1_remark; /* char *shi1_remark; data offset */
1355 } smb_rap_share_info_1_t;
1357 typedef struct smb_rap_share_info_2 {
1358 char shi2_netname[13];
1360 unsigned short shi2_type;
1361 DWORD shi2_remark; /* char *shi2_remark; data offset */
1362 unsigned short shi2_permissions;
1363 unsigned short shi2_max_uses;
1364 unsigned short shi2_current_uses;
1365 DWORD shi2_path; /* char *shi2_path; data offset */
1366 unsigned short shi2_passwd[9];
1367 unsigned short shi2_pad2;
1368 } smb_rap_share_info_2_t;
1370 #define SMB_RAP_MAX_SHARES 512
1372 typedef struct smb_rap_share_list {
1375 smb_rap_share_info_0_t * shares;
1376 } smb_rap_share_list_t;
1378 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1379 smb_rap_share_list_t * sp;
1384 if(name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1385 return 0; /* skip over '.' and '..' */
1387 sp = (smb_rap_share_list_t *) vrockp;
1389 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1390 sp->shares[sp->cShare].shi0_netname[12] = 0;
1394 if(sp->cShare >= sp->maxShares)
1395 return CM_ERROR_STOPNOW;
1400 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1402 smb_tran2Packet_t *outp;
1403 unsigned short * tp;
1407 int outParmsTotal; /* total parameter bytes */
1408 int outDataTotal; /* total data bytes */
1416 HKEY hkSubmount = NULL;
1417 smb_rap_share_info_1_t * shares;
1420 char thisShare[256];
1423 smb_rap_share_list_t rootShares;
1428 tp = p->parmsp + 1; /* skip over function number (always 0) */
1429 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1430 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1434 if(infoLevel != 1) {
1435 return CM_ERROR_INVAL;
1438 /* first figure out how many shares there are */
1439 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1440 KEY_QUERY_VALUE, &hkParam);
1441 if (rv == ERROR_SUCCESS) {
1442 len = sizeof(allSubmount);
1443 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1444 (BYTE *) &allSubmount, &len);
1445 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1448 RegCloseKey (hkParam);
1451 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1452 0, KEY_QUERY_VALUE, &hkSubmount);
1453 if (rv == ERROR_SUCCESS) {
1454 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1455 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1456 if (rv != ERROR_SUCCESS)
1462 /* fetch the root shares */
1463 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1464 rootShares.cShare = 0;
1465 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1469 userp = smb_GetTran2User(vcp,p);
1471 thyper.HighPart = 0;
1474 cm_HoldSCache(cm_rootSCachep);
1475 cm_ApplyDir(cm_rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1476 cm_ReleaseSCache(cm_rootSCachep);
1478 cm_ReleaseUser(userp);
1480 nShares = rootShares.cShare + nRegShares + allSubmount;
1482 outParmsTotal = 8; /* 4 dwords */
1483 outDataTotal = (sizeof(smb_rap_share_info_1_t) + 1) * nShares ;
1484 if(outDataTotal > bufsize) {
1485 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + 1);
1486 outDataTotal = (sizeof(smb_rap_share_info_1_t) + 1) * nSharesRet;
1489 nSharesRet = nShares;
1492 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1494 /* now for the submounts */
1495 shares = (smb_rap_share_info_1_t *) outp->datap;
1496 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1498 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + 1) * nSharesRet);
1501 strcpy( shares[cshare].shi1_netname, "all" );
1502 shares[cshare].shi1_remark = cstrp - outp->datap;
1503 /* type and pad are zero already */
1509 for(i=0; i < nRegShares && cshare < nSharesRet; i++) {
1510 len = sizeof(thisShare);
1511 rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1512 if(rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1513 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1514 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1515 shares[cshare].shi1_remark = cstrp - outp->datap;
1520 nShares--; /* uncount key */
1523 RegCloseKey(hkSubmount);
1526 nonrootShares = cshare;
1528 for(i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1529 /* in case there are collisions with submounts, submounts have higher priority */
1530 for(j=0; j < nonrootShares; j++)
1531 if(!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1534 if(j < nonrootShares) {
1535 nShares--; /* uncount */
1539 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1540 shares[cshare].shi1_remark = cstrp - outp->datap;
1545 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1546 outp->parmsp[1] = 0;
1547 outp->parmsp[2] = cshare;
1548 outp->parmsp[3] = nShares;
1550 outp->totalData = (sizeof(smb_rap_share_info_1_t) + 1) * cshare;
1551 outp->totalParms = outParmsTotal;
1553 smb_SendTran2Packet(vcp, outp, op);
1554 smb_FreeTran2Packet(outp);
1556 free(rootShares.shares);
1561 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1563 smb_tran2Packet_t *outp;
1564 unsigned short * tp;
1566 BOOL shareFound = FALSE;
1567 unsigned short infoLevel;
1568 unsigned short bufsize;
1578 tp = p->parmsp + 1; /* skip over function number (always 1) */
1579 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1580 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1581 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1588 totalData = sizeof(smb_rap_share_info_0_t);
1589 else if(infoLevel == 1)
1590 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1591 else if(infoLevel == 2)
1592 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1594 return CM_ERROR_INVAL;
1596 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1598 if(!stricmp(shareName,"all")) {
1599 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1600 KEY_QUERY_VALUE, &hkParam);
1601 if (rv == ERROR_SUCCESS) {
1602 len = sizeof(allSubmount);
1603 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1604 (BYTE *) &allSubmount, &len);
1605 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1608 RegCloseKey (hkParam);
1615 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts", 0,
1616 KEY_QUERY_VALUE, &hkSubmount);
1617 if(rv == ERROR_SUCCESS) {
1618 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1619 if(rv == ERROR_SUCCESS) {
1622 RegCloseKey(hkSubmount);
1627 smb_FreeTran2Packet(outp);
1628 return CM_ERROR_BADSHARENAME;
1631 memset(outp->datap, 0, totalData);
1633 outp->parmsp[0] = 0;
1634 outp->parmsp[1] = 0;
1635 outp->parmsp[2] = totalData;
1637 if(infoLevel == 0) {
1638 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1639 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1640 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1641 } else if(infoLevel == 1) {
1642 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1643 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1644 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1645 info->shi1_remark = ((unsigned char *) (info + 1)) - outp->datap;
1646 /* type and pad are already zero */
1647 } else { /* infoLevel==2 */
1648 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1649 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1650 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1651 info->shi2_remark = ((unsigned char *) (info + 1)) - outp->datap;
1652 info->shi2_permissions = ACCESS_ALL;
1653 info->shi2_max_uses = (unsigned short) -1;
1654 info->shi2_path = 1 + (((unsigned char *) (info + 1)) - outp->datap);
1657 outp->totalData = totalData;
1658 outp->totalParms = totalParam;
1660 smb_SendTran2Packet(vcp, outp, op);
1661 smb_FreeTran2Packet(outp);
1666 typedef struct smb_rap_wksta_info_10 {
1667 DWORD wki10_computername; /*char *wki10_computername;*/
1668 DWORD wki10_username; /* char *wki10_username; */
1669 DWORD wki10_langroup; /* char *wki10_langroup;*/
1670 unsigned char wki10_ver_major;
1671 unsigned char wki10_ver_minor;
1672 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1673 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1674 } smb_rap_wksta_info_10_t;
1677 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1679 smb_tran2Packet_t *outp;
1683 unsigned short * tp;
1686 smb_rap_wksta_info_10_t * info;
1690 tp = p->parmsp + 1; /* Skip over function number */
1691 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1692 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1696 if(infoLevel != 10) {
1697 return CM_ERROR_INVAL;
1703 totalData = sizeof(*info) + /* info */
1704 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1705 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1706 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1707 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1708 1; /* wki10_oth_domains (null)*/
1710 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1712 memset(outp->parmsp,0,totalParams);
1713 memset(outp->datap,0,totalData);
1715 info = (smb_rap_wksta_info_10_t *) outp->datap;
1716 cstrp = (char *) (info + 1);
1718 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1719 strcpy(cstrp, smb_localNamep);
1720 cstrp += strlen(cstrp) + 1;
1722 info->wki10_username = (DWORD) (cstrp - outp->datap);
1723 uidp = smb_FindUID(vcp, p->uid, 0);
1725 lock_ObtainMutex(&uidp->mx);
1726 if(uidp->unp && uidp->unp->name)
1727 strcpy(cstrp, uidp->unp->name);
1728 lock_ReleaseMutex(&uidp->mx);
1729 smb_ReleaseUID(uidp);
1731 cstrp += strlen(cstrp) + 1;
1733 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1734 strcpy(cstrp, "WORKGROUP");
1735 cstrp += strlen(cstrp) + 1;
1737 /* TODO: Not sure what values these should take, but these work */
1738 info->wki10_ver_major = 5;
1739 info->wki10_ver_minor = 1;
1741 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1742 strcpy(cstrp, smb_ServerDomainName);
1743 cstrp += strlen(cstrp) + 1;
1745 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1746 cstrp ++; /* no other domains */
1748 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1749 outp->parmsp[2] = outp->totalData;
1750 outp->totalParms = totalParams;
1752 smb_SendTran2Packet(vcp,outp,op);
1753 smb_FreeTran2Packet(outp);
1758 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1760 return CM_ERROR_BADOP;
1763 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1765 smb_tran2Packet_t *asp;
1777 /* We sometimes see 0 word count. What to do? */
1778 if (*inp->wctp == 0) {
1783 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1785 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1786 ptbuf[0] = "Transaction2 word count = 0";
1787 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1788 1, inp->ncb_length, ptbuf, inp);
1789 DeregisterEventSource(h);
1791 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1794 smb_SetSMBDataLength(outp, 0);
1795 smb_SendPacket(vcp, outp);
1799 totalParms = smb_GetSMBParm(inp, 0);
1800 totalData = smb_GetSMBParm(inp, 1);
1802 firstPacket = (inp->inCom == 0x32);
1804 /* find the packet we're reassembling */
1805 lock_ObtainWrite(&smb_globalLock);
1806 asp = smb_FindTran2Packet(vcp, inp);
1808 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1810 lock_ReleaseWrite(&smb_globalLock);
1812 /* now merge in this latest packet; start by looking up offsets */
1814 parmDisp = dataDisp = 0;
1815 parmOffset = smb_GetSMBParm(inp, 10);
1816 dataOffset = smb_GetSMBParm(inp, 12);
1817 parmCount = smb_GetSMBParm(inp, 9);
1818 dataCount = smb_GetSMBParm(inp, 11);
1819 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1820 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1822 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1823 totalData, dataCount, asp->maxReturnData);
1826 parmDisp = smb_GetSMBParm(inp, 4);
1827 parmOffset = smb_GetSMBParm(inp, 3);
1828 dataDisp = smb_GetSMBParm(inp, 7);
1829 dataOffset = smb_GetSMBParm(inp, 6);
1830 parmCount = smb_GetSMBParm(inp, 2);
1831 dataCount = smb_GetSMBParm(inp, 5);
1833 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1834 parmCount, dataCount);
1837 /* now copy the parms and data */
1838 if ( parmCount != 0 )
1840 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1842 if ( dataCount != 0 ) {
1843 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1846 /* account for new bytes */
1847 asp->curData += dataCount;
1848 asp->curParms += parmCount;
1850 /* finally, if we're done, remove the packet from the queue and dispatch it */
1851 if (asp->totalData <= asp->curData && asp->totalParms <= asp->curParms) {
1852 /* we've received it all */
1853 lock_ObtainWrite(&smb_globalLock);
1854 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1855 lock_ReleaseWrite(&smb_globalLock);
1857 /* now dispatch it */
1858 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
1859 osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1860 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
1861 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
1864 osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1865 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1866 code = CM_ERROR_BADOP;
1869 /* if an error is returned, we're supposed to send an error packet,
1870 * otherwise the dispatched function already did the data sending.
1871 * We give dispatched proc the responsibility since it knows how much
1872 * space to allocate.
1875 smb_SendTran2Error(vcp, asp, outp, code);
1878 /* free the input tran 2 packet */
1879 lock_ObtainWrite(&smb_globalLock);
1880 smb_FreeTran2Packet(asp);
1881 lock_ReleaseWrite(&smb_globalLock);
1883 else if (firstPacket) {
1884 /* the first packet in a multi-packet request, we need to send an
1885 * ack to get more data.
1887 smb_SetSMBDataLength(outp, 0);
1888 smb_SendPacket(vcp, outp);
1894 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1897 smb_tran2Packet_t *outp;
1902 cm_scache_t *dscp; /* dir we're dealing with */
1903 cm_scache_t *scp; /* file we're creating */
1905 int initialModeBits;
1915 int parmSlot; /* which parm we're dealing with */
1916 long returnEALength;
1924 extraInfo = (p->parmsp[0] & 1); /* return extra info */
1925 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
1927 openFun = p->parmsp[6]; /* open function */
1928 excl = ((openFun & 3) == 0);
1929 trunc = ((openFun & 3) == 2); /* truncate it */
1930 openMode = (p->parmsp[1] & 0x7);
1931 openAction = 0; /* tracks what we did */
1933 attributes = p->parmsp[3];
1934 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
1936 /* compute initial mode bits based on read-only flag in attributes */
1937 initialModeBits = 0666;
1938 if (attributes & 1) initialModeBits &= ~0222;
1940 pathp = (char *) (&p->parmsp[14]);
1942 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
1944 spacep = cm_GetSpace();
1945 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
1947 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
1948 /* special case magic file name for receiving IOCTL requests
1949 * (since IOCTL calls themselves aren't getting through).
1951 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
1952 smb_SetupIoctlFid(fidp, spacep);
1954 /* copy out remainder of the parms */
1956 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
1958 outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
1959 outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
1960 outp->parmsp[parmSlot] = 0; parmSlot++;
1961 outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
1962 outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
1963 outp->parmsp[parmSlot] = openMode; parmSlot++;
1964 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
1965 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
1967 /* and the final "always present" stuff */
1968 outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
1969 /* next write out the "unique" ID */
1970 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
1971 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
1972 outp->parmsp[parmSlot] = 0; parmSlot++;
1973 if (returnEALength) {
1974 outp->parmsp[parmSlot] = 0; parmSlot++;
1975 outp->parmsp[parmSlot] = 0; parmSlot++;
1978 outp->totalData = 0;
1979 outp->totalParms = parmSlot * 2;
1981 smb_SendTran2Packet(vcp, outp, op);
1983 smb_FreeTran2Packet(outp);
1985 /* and clean up fid reference */
1986 smb_ReleaseFID(fidp);
1990 #ifdef DEBUG_VERBOSE
1992 char *hexp, *asciip;
1993 asciip = (lastNamep ? lastNamep : pathp);
1994 hexp = osi_HexifyString( asciip );
1995 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2000 userp = smb_GetTran2User(vcp, p);
2001 /* In the off chance that userp is NULL, we log and abandon */
2003 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2004 smb_FreeTran2Packet(outp);
2005 return CM_ERROR_BADSMB;
2008 tidPathp = smb_GetTIDPath(vcp, p->tid);
2011 code = cm_NameI(cm_rootSCachep, pathp,
2012 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2013 userp, tidPathp, &req, &scp);
2015 code = cm_NameI(cm_rootSCachep, spacep->data,
2016 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2017 userp, tidPathp, &req, &dscp);
2018 cm_FreeSpace(spacep);
2021 cm_ReleaseUser(userp);
2022 smb_FreeTran2Packet(outp);
2026 /* otherwise, scp points to the parent directory. Do a lookup,
2027 * and truncate the file if we find it, otherwise we create the
2030 if (!lastNamep) lastNamep = pathp;
2032 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2034 if (code && code != CM_ERROR_NOSUCHFILE) {
2035 cm_ReleaseSCache(dscp);
2036 cm_ReleaseUser(userp);
2037 smb_FreeTran2Packet(outp);
2042 cm_FreeSpace(spacep);
2045 /* if we get here, if code is 0, the file exists and is represented by
2046 * scp. Otherwise, we have to create it.
2049 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2051 if (dscp) cm_ReleaseSCache(dscp);
2052 cm_ReleaseSCache(scp);
2053 cm_ReleaseUser(userp);
2054 smb_FreeTran2Packet(outp);
2059 /* oops, file shouldn't be there */
2060 if (dscp) cm_ReleaseSCache(dscp);
2061 cm_ReleaseSCache(scp);
2062 cm_ReleaseUser(userp);
2063 smb_FreeTran2Packet(outp);
2064 return CM_ERROR_EXISTS;
2068 setAttr.mask = CM_ATTRMASK_LENGTH;
2069 setAttr.length.LowPart = 0;
2070 setAttr.length.HighPart = 0;
2071 code = cm_SetAttr(scp, &setAttr, userp, &req);
2072 openAction = 3; /* truncated existing file */
2074 else openAction = 1; /* found existing file */
2076 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
2077 /* don't create if not found */
2078 if (dscp) cm_ReleaseSCache(dscp);
2079 osi_assert(scp == NULL);
2080 cm_ReleaseUser(userp);
2081 smb_FreeTran2Packet(outp);
2082 return CM_ERROR_NOSUCHFILE;
2085 osi_assert(dscp != NULL && scp == NULL);
2086 openAction = 2; /* created file */
2087 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2088 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2089 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2091 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2092 smb_NotifyChange(FILE_ACTION_ADDED,
2093 FILE_NOTIFY_CHANGE_FILE_NAME,
2094 dscp, lastNamep, NULL, TRUE);
2095 if (!excl && code == CM_ERROR_EXISTS) {
2096 /* not an exclusive create, and someone else tried
2097 * creating it already, then we open it anyway. We
2098 * don't bother retrying after this, since if this next
2099 * fails, that means that the file was deleted after we
2100 * started this call.
2102 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2106 setAttr.mask = CM_ATTRMASK_LENGTH;
2107 setAttr.length.LowPart = 0;
2108 setAttr.length.HighPart = 0;
2109 code = cm_SetAttr(scp, &setAttr, userp,
2112 } /* lookup succeeded */
2116 /* we don't need this any longer */
2117 if (dscp) cm_ReleaseSCache(dscp);
2120 /* something went wrong creating or truncating the file */
2121 if (scp) cm_ReleaseSCache(scp);
2122 cm_ReleaseUser(userp);
2123 smb_FreeTran2Packet(outp);
2127 /* make sure we're about to open a file */
2128 if (scp->fileType != CM_SCACHETYPE_FILE) {
2129 cm_ReleaseSCache(scp);
2130 cm_ReleaseUser(userp);
2131 smb_FreeTran2Packet(outp);
2132 return CM_ERROR_ISDIR;
2135 /* now all we have to do is open the file itself */
2136 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2139 /* save a pointer to the vnode */
2142 /* compute open mode */
2143 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2144 if (openMode == 1 || openMode == 2)
2145 fidp->flags |= SMB_FID_OPENWRITE;
2147 smb_ReleaseFID(fidp);
2149 cm_Open(scp, 0, userp);
2151 /* copy out remainder of the parms */
2153 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2154 lock_ObtainMutex(&scp->mx);
2156 outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
2157 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2158 outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
2159 outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
2160 outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
2162 outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2164 outp->parmsp[parmSlot] = openMode; parmSlot++;
2165 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2166 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2168 /* and the final "always present" stuff */
2169 outp->parmsp[parmSlot] = openAction; parmSlot++;
2170 /* next write out the "unique" ID */
2171 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
2172 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
2173 outp->parmsp[parmSlot] = 0; parmSlot++;
2174 if (returnEALength) {
2175 outp->parmsp[parmSlot] = 0; parmSlot++;
2176 outp->parmsp[parmSlot] = 0; parmSlot++;
2178 lock_ReleaseMutex(&scp->mx);
2179 outp->totalData = 0; /* total # of data bytes */
2180 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2182 smb_SendTran2Packet(vcp, outp, op);
2184 smb_FreeTran2Packet(outp);
2186 cm_ReleaseUser(userp);
2187 /* leave scp held since we put it in fidp->scp */
2191 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2193 return CM_ERROR_BADOP;
2196 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2198 return CM_ERROR_BADOP;
2201 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2203 smb_tran2Packet_t *outp;
2204 smb_tran2QFSInfo_t qi;
2207 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
2209 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2211 switch (p->parmsp[0]) {
2212 case 1: responseSize = sizeof(qi.u.allocInfo); break;
2213 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
2214 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
2215 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
2216 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
2217 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
2218 default: return CM_ERROR_INVAL;
2221 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2222 switch (p->parmsp[0]) {
2225 qi.u.allocInfo.FSID = 0;
2226 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2227 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2228 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2229 qi.u.allocInfo.bytesPerSector = 1024;
2234 qi.u.volumeInfo.vsn = 1234;
2235 qi.u.volumeInfo.vnCount = 4;
2236 /* we're supposed to pad it out with zeroes to the end */
2237 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2238 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2242 /* FS volume info */
2243 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
2244 qi.u.FSvolumeInfo.vsn = 1234;
2245 qi.u.FSvolumeInfo.vnCount = 8;
2246 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
2252 temp.LowPart = 0x7fffffff;
2253 qi.u.FSsizeInfo.totalAllocUnits = temp;
2254 temp.LowPart = 0x3fffffff;
2255 qi.u.FSsizeInfo.availAllocUnits = temp;
2256 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2257 qi.u.FSsizeInfo.bytesPerSector = 1024;
2261 /* FS device info */
2262 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
2263 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2267 /* FS attribute info */
2268 /* attributes, defined in WINNT.H:
2269 * FILE_CASE_SENSITIVE_SEARCH 0x1
2270 * FILE_CASE_PRESERVED_NAMES 0x2
2271 * <no name defined> 0x4000
2272 * If bit 0x4000 is not set, Windows 95 thinks
2273 * we can't handle long (non-8.3) names,
2274 * despite our protestations to the contrary.
2276 qi.u.FSattributeInfo.attributes = 0x4003;
2277 qi.u.FSattributeInfo.maxCompLength = 255;
2278 qi.u.FSattributeInfo.FSnameLength = 6;
2279 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
2283 /* copy out return data, and set corresponding sizes */
2284 outp->totalParms = 0;
2285 outp->totalData = responseSize;
2286 memcpy(outp->datap, &qi, responseSize);
2288 /* send and free the packets */
2289 smb_SendTran2Packet(vcp, outp, op);
2290 smb_FreeTran2Packet(outp);
2295 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2297 return CM_ERROR_BADOP;
2300 struct smb_ShortNameRock {
2304 size_t shortNameLen;
2307 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2310 struct smb_ShortNameRock *rockp;
2314 /* compare both names and vnodes, though probably just comparing vnodes
2315 * would be safe enough.
2317 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2319 if (ntohl(dep->fid.vnode) != rockp->vnode)
2321 /* This is the entry */
2322 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2323 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2324 return CM_ERROR_STOPNOW;
2327 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2328 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2330 struct smb_ShortNameRock rock;
2334 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2338 spacep = cm_GetSpace();
2339 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2341 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
2343 cm_FreeSpace(spacep);
2344 if (code) return code;
2346 if (!lastNamep) lastNamep = pathp;
2349 thyper.HighPart = 0;
2350 rock.shortName = shortName;
2352 rock.maskp = lastNamep;
2353 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
2356 cm_ReleaseSCache(dscp);
2359 return CM_ERROR_NOSUCHFILE;
2360 if (code == CM_ERROR_STOPNOW) {
2361 *shortNameLenp = rock.shortNameLen;
2367 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2369 smb_tran2Packet_t *outp;
2370 unsigned long dosTime;
2372 unsigned short infoLevel;
2374 unsigned short attributes;
2375 unsigned long extAttributes;
2380 cm_scache_t *scp, *dscp;
2389 infoLevel = p->parmsp[0];
2390 if (infoLevel == 6) nbytesRequired = 0;
2391 else if (infoLevel == 1) nbytesRequired = 22;
2392 else if (infoLevel == 2) nbytesRequired = 26;
2393 else if (infoLevel == 0x101) nbytesRequired = 40;
2394 else if (infoLevel == 0x102) nbytesRequired = 24;
2395 else if (infoLevel == 0x103) nbytesRequired = 4;
2396 else if (infoLevel == 0x108) nbytesRequired = 30;
2398 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2399 p->opcode, infoLevel);
2400 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2403 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2404 osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
2406 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2408 if (infoLevel > 0x100)
2409 outp->totalParms = 2;
2411 outp->totalParms = 0;
2412 outp->totalData = nbytesRequired;
2414 /* now, if we're at infoLevel 6, we're only being asked to check
2415 * the syntax, so we just OK things now. In particular, we're *not*
2416 * being asked to verify anything about the state of any parent dirs.
2418 if (infoLevel == 6) {
2419 smb_SendTran2Packet(vcp, outp, opx);
2420 smb_FreeTran2Packet(outp);
2424 userp = smb_GetTran2User(vcp, p);
2426 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2427 smb_FreeTran2Packet(outp);
2428 return CM_ERROR_BADSMB;
2431 tidPathp = smb_GetTIDPath(vcp, p->tid);
2434 * XXX Strange hack XXX
2436 * As of Patch 7 (13 January 98), we are having the following problem:
2437 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2438 * requests to look up "desktop.ini" in all the subdirectories.
2439 * This can cause zillions of timeouts looking up non-existent cells
2440 * and volumes, especially in the top-level directory.
2442 * We have not found any way to avoid this or work around it except
2443 * to explicitly ignore the requests for mount points that haven't
2444 * yet been evaluated and for directories that haven't yet been
2447 if (infoLevel == 0x101) {
2448 spacep = cm_GetSpace();
2449 smb_StripLastComponent(spacep->data, &lastComp,
2450 (char *)(&p->parmsp[3]));
2451 /* Make sure that lastComp is not NULL */
2453 if (strcmp(lastComp, "\\desktop.ini") == 0) {
2454 code = cm_NameI(cm_rootSCachep, spacep->data,
2458 userp, tidPathp, &req, &dscp);
2460 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
2461 && !dscp->mountRootFidp)
2462 code = CM_ERROR_NOSUCHFILE;
2463 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2464 cm_buf_t *bp = buf_Find(dscp, &hzero);
2468 code = CM_ERROR_NOSUCHFILE;
2470 cm_ReleaseSCache(dscp);
2472 cm_FreeSpace(spacep);
2473 cm_ReleaseUser(userp);
2474 smb_SendTran2Error(vcp, p, opx, code);
2475 smb_FreeTran2Packet(outp);
2481 cm_FreeSpace(spacep);
2484 /* now do namei and stat, and copy out the info */
2485 code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
2486 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2489 cm_ReleaseUser(userp);
2490 smb_SendTran2Error(vcp, p, opx, code);
2491 smb_FreeTran2Packet(outp);
2495 lock_ObtainMutex(&scp->mx);
2496 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2497 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2498 if (code) goto done;
2500 /* now we have the status in the cache entry, and everything is locked.
2501 * Marshall the output data.
2504 /* for info level 108, figure out short name */
2505 if (infoLevel == 0x108) {
2506 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
2507 tidPathp, scp->fid.vnode, shortName,
2514 *((u_long *)op) = len * 2; op += 4;
2515 mbstowcs((unsigned short *)op, shortName, len);
2520 if (infoLevel == 1 || infoLevel == 2) {
2521 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2522 *((u_long *)op) = dosTime; op += 4; /* creation time */
2523 *((u_long *)op) = dosTime; op += 4; /* access time */
2524 *((u_long *)op) = dosTime; op += 4; /* write time */
2525 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
2526 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
2527 attributes = smb_Attributes(scp);
2528 *((u_short *)op) = attributes; op += 2; /* attributes */
2530 else if (infoLevel == 0x101) {
2531 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2532 *((FILETIME *)op) = ft; op += 8; /* creation time */
2533 *((FILETIME *)op) = ft; op += 8; /* last access time */
2534 *((FILETIME *)op) = ft; op += 8; /* last write time */
2535 *((FILETIME *)op) = ft; op += 8; /* last change time */
2536 extAttributes = smb_ExtAttributes(scp);
2537 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
2538 *((u_long *)op) = 0; op += 4; /* don't know what this is */
2540 else if (infoLevel == 0x102) {
2541 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2542 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2543 *((u_long *)op) = scp->linkCount; op += 4;
2546 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2549 else if (infoLevel == 0x103) {
2550 memset(op, 0, 4); op += 4; /* EA size */
2553 /* now, if we are being asked about extended attrs, return a 0 size */
2554 if (infoLevel == 2) {
2555 *((u_long *)op) = 0; op += 4;
2559 /* send and free the packets */
2561 lock_ReleaseMutex(&scp->mx);
2562 cm_ReleaseSCache(scp);
2563 cm_ReleaseUser(userp);
2565 smb_SendTran2Packet(vcp, outp, opx);
2567 smb_SendTran2Error(vcp, p, opx, code);
2568 smb_FreeTran2Packet(outp);
2573 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2575 return CM_ERROR_BADOP;
2578 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2580 smb_tran2Packet_t *outp;
2582 unsigned long attributes;
2583 unsigned short infoLevel;
2596 fidp = smb_FindFID(vcp, fid, 0);
2599 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2603 infoLevel = p->parmsp[1];
2604 if (infoLevel == 0x101) nbytesRequired = 40;
2605 else if (infoLevel == 0x102) nbytesRequired = 24;
2606 else if (infoLevel == 0x103) nbytesRequired = 4;
2607 else if (infoLevel == 0x104) nbytesRequired = 6;
2609 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2610 p->opcode, infoLevel);
2611 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2612 smb_ReleaseFID(fidp);
2615 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2617 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2619 if (infoLevel > 0x100)
2620 outp->totalParms = 2;
2622 outp->totalParms = 0;
2623 outp->totalData = nbytesRequired;
2625 userp = smb_GetTran2User(vcp, p);
2627 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2628 code = CM_ERROR_BADSMB;
2633 lock_ObtainMutex(&scp->mx);
2634 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2635 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2636 if (code) goto done;
2638 /* now we have the status in the cache entry, and everything is locked.
2639 * Marshall the output data.
2642 if (infoLevel == 0x101) {
2643 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2644 *((FILETIME *)op) = ft; op += 8; /* creation time */
2645 *((FILETIME *)op) = ft; op += 8; /* last access time */
2646 *((FILETIME *)op) = ft; op += 8; /* last write time */
2647 *((FILETIME *)op) = ft; op += 8; /* last change time */
2648 attributes = smb_ExtAttributes(scp);
2649 *((u_long *)op) = attributes; op += 4;
2650 *((u_long *)op) = 0; op += 4;
2652 else if (infoLevel == 0x102) {
2653 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2654 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2655 *((u_long *)op) = scp->linkCount; op += 4;
2656 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
2657 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2661 else if (infoLevel == 0x103) {
2662 *((u_long *)op) = 0; op += 4;
2664 else if (infoLevel == 0x104) {
2668 if (fidp->NTopen_wholepathp)
2669 name = fidp->NTopen_wholepathp;
2671 name = "\\"; /* probably can't happen */
2673 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
2674 *((u_long *)op) = len * 2; op += 4;
2675 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2678 /* send and free the packets */
2680 lock_ReleaseMutex(&scp->mx);
2681 cm_ReleaseUser(userp);
2682 smb_ReleaseFID(fidp);
2683 if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
2684 else smb_SendTran2Error(vcp, p, opx, code);
2685 smb_FreeTran2Packet(outp);
2690 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2695 unsigned short infoLevel;
2696 smb_tran2Packet_t *outp;
2704 fidp = smb_FindFID(vcp, fid, 0);
2707 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
2711 infoLevel = p->parmsp[1];
2712 if (infoLevel > 0x104 || infoLevel < 0x101) {
2713 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2714 p->opcode, infoLevel);
2715 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
2716 smb_ReleaseFID(fidp);
2720 if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
2721 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2722 smb_ReleaseFID(fidp);
2725 if ((infoLevel == 0x103 || infoLevel == 0x104)
2726 && !(fidp->flags & SMB_FID_OPENWRITE)) {
2727 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2728 smb_ReleaseFID(fidp);
2732 osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
2734 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
2736 outp->totalParms = 2;
2737 outp->totalData = 0;
2739 userp = smb_GetTran2User(vcp, p);
2741 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
2742 code = CM_ERROR_BADSMB;
2748 if (infoLevel == 0x101) {
2750 unsigned int attribute;
2753 /* lock the vnode with a callback; we need the current status
2754 * to determine what the new status is, in some cases.
2756 lock_ObtainMutex(&scp->mx);
2757 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2758 CM_SCACHESYNC_GETSTATUS
2759 | CM_SCACHESYNC_NEEDCALLBACK);
2761 lock_ReleaseMutex(&scp->mx);
2765 /* prepare for setattr call */
2768 lastMod = *((FILETIME *)(p->datap + 16));
2769 /* when called as result of move a b, lastMod is (-1, -1).
2770 * If the check for -1 is not present, timestamp
2771 * of the resulting file will be 1969 (-1)
2773 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
2774 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
2775 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
2776 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
2778 fidp->flags |= SMB_FID_MTIMESETDONE;
2781 attribute = *((u_long *)(p->datap + 32));
2782 if (attribute != 0) {
2783 if ((scp->unixModeBits & 0222)
2784 && (attribute & 1) != 0) {
2785 /* make a writable file read-only */
2786 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2787 attr.unixModeBits = scp->unixModeBits & ~0222;
2789 else if ((scp->unixModeBits & 0222) == 0
2790 && (attribute & 1) == 0) {
2791 /* make a read-only file writable */
2792 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2793 attr.unixModeBits = scp->unixModeBits | 0222;
2796 lock_ReleaseMutex(&scp->mx);
2800 code = cm_SetAttr(scp, &attr, userp, &req);
2804 else if (infoLevel == 0x103 || infoLevel == 0x104) {
2805 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
2808 attr.mask = CM_ATTRMASK_LENGTH;
2809 attr.length.LowPart = size.LowPart;
2810 attr.length.HighPart = size.HighPart;
2811 code = cm_SetAttr(scp, &attr, userp, &req);
2813 else if (infoLevel == 0x102) {
2814 if (*((char *)(p->datap))) {
2815 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
2818 fidp->flags |= SMB_FID_DELONCLOSE;
2822 fidp->flags &= ~SMB_FID_DELONCLOSE;
2826 cm_ReleaseUser(userp);
2827 smb_ReleaseFID(fidp);
2828 if (code == 0) smb_SendTran2Packet(vcp, outp, op);
2829 else smb_SendTran2Error(vcp, p, op, code);
2830 smb_FreeTran2Packet(outp);
2835 long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2837 return CM_ERROR_BADOP;
2840 long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2842 return CM_ERROR_BADOP;
2845 long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2847 return CM_ERROR_BADOP;
2850 long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2852 return CM_ERROR_BADOP;
2855 long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2857 return CM_ERROR_BADOP;
2860 long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
2861 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
2866 cm_scache_t *targetScp; /* target if scp is a symlink */
2871 unsigned short attr;
2872 unsigned long lattr;
2873 smb_dirListPatch_t *patchp;
2874 smb_dirListPatch_t *npatchp;
2876 for(patchp = *dirPatchespp; patchp; patchp =
2877 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
2878 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
2880 lock_ObtainMutex(&scp->mx);
2881 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
2882 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2884 lock_ReleaseMutex(&scp->mx);
2885 cm_ReleaseSCache(scp);
2889 /* now watch for a symlink */
2890 if (scp->fileType == CM_SCACHETYPE_SYMLINK) {
2891 lock_ReleaseMutex(&scp->mx);
2892 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
2894 /* we have a more accurate file to use (the
2895 * target of the symbolic link). Otherwise,
2896 * we'll just use the symlink anyway.
2898 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2900 cm_ReleaseSCache(scp);
2903 lock_ObtainMutex(&scp->mx);
2906 dptr = patchp->dptr;
2908 if (infoLevel >= 0x101) {
2910 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2912 /* copy to Creation Time */
2913 *((FILETIME *)dptr) = ft;
2916 /* copy to Last Access Time */
2917 *((FILETIME *)dptr) = ft;
2920 /* copy to Last Write Time */
2921 *((FILETIME *)dptr) = ft;
2924 /* copy to Change Time */
2925 *((FILETIME *)dptr) = ft;
2928 /* Use length for both file length and alloc length */
2929 *((LARGE_INTEGER *)dptr) = scp->length;
2931 *((LARGE_INTEGER *)dptr) = scp->length;
2934 /* Copy attributes */
2935 lattr = smb_ExtAttributes(scp);
2936 /* merge in hidden (dot file) attribute */
2937 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
2938 lattr |= SMB_ATTR_HIDDEN;
2939 *((u_long *)dptr) = lattr;
2944 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2946 /* and copy out date */
2947 shortTemp = (dosTime>>16) & 0xffff;
2948 *((u_short *)dptr) = shortTemp;
2951 /* copy out creation time */
2952 shortTemp = dosTime & 0xffff;
2953 *((u_short *)dptr) = shortTemp;
2956 /* and copy out date */
2957 shortTemp = (dosTime>>16) & 0xffff;
2958 *((u_short *)dptr) = shortTemp;
2961 /* copy out access time */
2962 shortTemp = dosTime & 0xffff;
2963 *((u_short *)dptr) = shortTemp;
2966 /* and copy out date */
2967 shortTemp = (dosTime>>16) & 0xffff;
2968 *((u_short *)dptr) = shortTemp;
2971 /* copy out mod time */
2972 shortTemp = dosTime & 0xffff;
2973 *((u_short *)dptr) = shortTemp;
2976 /* copy out file length and alloc length,
2977 * using the same for both
2979 *((u_long *)dptr) = scp->length.LowPart;
2981 *((u_long *)dptr) = scp->length.LowPart;
2984 /* finally copy out attributes as short */
2985 attr = smb_Attributes(scp);
2986 /* merge in hidden (dot file) attribute */
2987 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
2988 attr |= SMB_ATTR_HIDDEN;
2989 *dptr++ = attr & 0xff;
2990 *dptr++ = (attr >> 8) & 0xff;
2993 lock_ReleaseMutex(&scp->mx);
2994 cm_ReleaseSCache(scp);
2997 /* now free the patches */
2998 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
2999 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3003 /* and mark the list as empty */
3004 *dirPatchespp = NULL;
3009 #ifndef USE_OLD_MATCHING
3010 // char table for case insensitive comparison
3011 char mapCaseTable[256];
3013 VOID initUpperCaseTable(VOID)
3016 for (i = 0; i < 256; ++i)
3017 mapCaseTable[i] = toupper(i);
3018 // make '"' match '.'
3019 mapCaseTable[(int)'"'] = toupper('.');
3020 // make '<' match '*'
3021 mapCaseTable[(int)'<'] = toupper('*');
3022 // make '>' match '?'
3023 mapCaseTable[(int)'>'] = toupper('?');
3026 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3028 // Note : this procedure works recursively calling itself.
3030 // PSZ pattern : string containing metacharacters.
3031 // PSZ name : file name to be compared with 'pattern'.
3033 // BOOL : TRUE/FALSE (match/mistmatch)
3035 BOOL szWildCardMatchFileName(PSZ pattern, PSZ name) {
3036 PSZ pename; // points to the last 'name' character
3038 pename = name + strlen(name) - 1;
3043 if (*(++pattern) != '<' || *(++pattern) != '*') {
3051 while ((*pattern == '<') || (*pattern == '*') || (*pattern == '?') || (*pattern == '>'))
3055 for (p = pename; p >= name; --p) {
3056 if ((mapCaseTable[*p] == mapCaseTable[*pattern]) &&
3057 szWildCardMatchFileName(pattern + 1, p + 1))
3062 if (mapCaseTable[*name] != mapCaseTable[*pattern])
3071 /* do a case-folding search of the star name mask with the name in namep.
3072 * Return 1 if we match, otherwise 0.
3074 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3076 /* make sure we only match 8.3 names, if requested */
3077 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3080 return szWildCardMatchFileName(maskp, namep) ? 1:0;
3083 #else /* USE_OLD_MATCHING */
3084 /* do a case-folding search of the star name mask with the name in namep.
3085 * Return 1 if we match, otherwise 0.
3087 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3089 unsigned char tcp1, tcp2; /* Pattern characters */
3090 unsigned char tcn1; /* Name characters */
3091 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3092 char *starNamep, *starMaskp;
3093 static char nullCharp[] = {0};
3094 int casefold = flags & CM_FLAG_CASEFOLD;
3096 /* make sure we only match 8.3 names, if requested */
3097 req8dot3 = (flags & CM_FLAG_8DOT3);
3098 if (req8dot3 && !cm_Is8Dot3(namep))
3103 /* Next pattern character */
3106 /* Next name character */
3110 /* 0 - end of pattern */
3116 else if (tcp1 == '.' || tcp1 == '"') {
3126 * first dot in pattern;
3127 * must match dot or end of name
3132 else if (tcn1 == '.') {
3141 else if (tcp1 == '?') {
3142 if (tcn1 == 0 || tcn1 == '.')
3147 else if (tcp1 == '>') {
3148 if (tcn1 != 0 && tcn1 != '.')
3152 else if (tcp1 == '*' || tcp1 == '<') {
3156 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3157 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3172 * pattern character after '*' is not null or
3173 * period. If it is '?' or '>', we are not
3174 * going to understand it. If it is '*' or
3175 * '<', we are going to skip over it. None of
3176 * these are likely, I hope.
3178 /* skip over '*' and '<' */
3179 while (tcp2 == '*' || tcp2 == '<')
3182 /* skip over characters that don't match tcp2 */
3183 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
3184 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
3185 (!casefold && tcn1 != tcp2)))
3189 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3192 /* Remember where we are */
3202 /* tcp1 is not a wildcard */
3203 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
3204 (!casefold && tcn1 == tcp1)) {
3209 /* if trying to match a star pattern, go back */
3211 maskp = starMaskp - 2;
3212 namep = starNamep + 1;
3221 #endif /* USE_OLD_MATCHING */
3223 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3232 smb_dirListPatch_t *dirListPatchesp;
3233 smb_dirListPatch_t *curPatchp;
3236 long orbytes; /* # of bytes in this output record */
3237 long ohbytes; /* # of bytes, except file name */
3238 long onbytes; /* # of bytes in name, incl. term. null */
3239 osi_hyper_t dirLength;
3240 osi_hyper_t bufferOffset;
3241 osi_hyper_t curOffset;
3243 smb_dirSearch_t *dsp;
3247 cm_pageHeader_t *pageHeaderp;
3248 cm_user_t *userp = NULL;
3251 long nextEntryCookie;
3252 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3253 char *op; /* output data ptr */
3254 char *origOp; /* original value of op */
3255 cm_space_t *spacep; /* for pathname buffer */
3256 long maxReturnData; /* max # of return data */
3257 long maxReturnParms; /* max # of return parms */
3258 long bytesInBuffer; /* # data bytes in the output buffer */
3260 char *maskp; /* mask part of path */
3264 smb_tran2Packet_t *outp; /* response packet */
3267 char shortName[13]; /* 8.3 name if needed */
3279 if (p->opcode == 1) {
3280 /* find first; obtain basic parameters from request */
3281 attribute = p->parmsp[0];
3282 maxCount = p->parmsp[1];
3283 infoLevel = p->parmsp[3];
3284 searchFlags = p->parmsp[2];
3285 dsp = smb_NewDirSearch(1);
3286 dsp->attribute = attribute;
3287 pathp = ((char *) p->parmsp) + 12; /* points to path */
3289 maskp = strrchr(pathp, '\\');
3290 if (maskp == NULL) maskp = pathp;
3291 else maskp++; /* skip over backslash */
3292 strcpy(dsp->mask, maskp); /* and save mask */
3293 /* track if this is likely to match a lot of entries */
3294 starPattern = smb_V3IsStarMask(maskp);
3297 osi_assert(p->opcode == 2);
3298 /* find next; obtain basic parameters from request or open dir file */
3299 dsp = smb_FindDirSearch(p->parmsp[0]);
3300 if (!dsp) return CM_ERROR_BADFD;
3301 attribute = dsp->attribute;
3302 maxCount = p->parmsp[1];
3303 infoLevel = p->parmsp[2];
3304 searchFlags = p->parmsp[5];
3306 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
3308 starPattern = 1; /* assume, since required a Find Next */
3312 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
3313 attribute, infoLevel, maxCount, searchFlags);
3315 osi_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
3316 p->opcode, nextCookie);
3318 if (infoLevel >= 0x101)
3319 searchFlags &= ~4; /* no resume keys */
3321 dirListPatchesp = NULL;
3323 maxReturnData = p->maxReturnData;
3324 if (p->opcode == 1) /* find first */
3325 maxReturnParms = 10; /* bytes */
3327 maxReturnParms = 8; /* bytes */
3329 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
3330 if (maxReturnData > 6000)
3331 maxReturnData = 6000;
3332 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
3334 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
3337 osi_Log1(smb_logp, "T2 receive search dir %s",
3338 osi_LogSaveString(smb_logp, pathp));
3340 /* bail out if request looks bad */
3341 if (p->opcode == 1 && !pathp) {
3342 smb_ReleaseDirSearch(dsp);
3343 smb_FreeTran2Packet(outp);
3344 return CM_ERROR_BADSMB;
3347 osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
3348 nextCookie, dsp->cookie);
3350 userp = smb_GetTran2User(vcp, p);
3352 osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p->uid);
3353 smb_ReleaseDirSearch(dsp);
3354 smb_FreeTran2Packet(outp);
3355 return CM_ERROR_BADSMB;
3358 /* try to get the vnode for the path name next */
3359 lock_ObtainMutex(&dsp->mx);
3366 spacep = cm_GetSpace();
3367 smb_StripLastComponent(spacep->data, NULL, pathp);
3368 lock_ReleaseMutex(&dsp->mx);
3370 tidPathp = smb_GetTIDPath(vcp, p->tid);
3371 code = cm_NameI(cm_rootSCachep, spacep->data,
3372 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3373 userp, tidPathp, &req, &scp);
3374 cm_FreeSpace(spacep);
3376 lock_ObtainMutex(&dsp->mx);
3378 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
3380 /* we need one hold for the entry we just stored into,
3381 * and one for our own processing. When we're done
3382 * with this function, we'll drop the one for our own
3383 * processing. We held it once from the namei call,
3384 * and so we do another hold now.
3387 lock_ObtainMutex(&scp->mx);
3388 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3389 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3390 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3391 dsp->flags |= SMB_DIRSEARCH_BULKST;
3393 lock_ReleaseMutex(&scp->mx);
3396 lock_ReleaseMutex(&dsp->mx);
3398 cm_ReleaseUser(userp);
3399 smb_FreeTran2Packet(outp);
3400 smb_DeleteDirSearch(dsp);
3401 smb_ReleaseDirSearch(dsp);
3405 /* get the directory size */
3406 lock_ObtainMutex(&scp->mx);
3407 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3408 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3410 lock_ReleaseMutex(&scp->mx);
3411 cm_ReleaseSCache(scp);
3412 cm_ReleaseUser(userp);
3413 smb_FreeTran2Packet(outp);
3414 smb_DeleteDirSearch(dsp);
3415 smb_ReleaseDirSearch(dsp);
3420 dirLength = scp->length;
3422 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3423 curOffset.HighPart = 0;
3424 curOffset.LowPart = nextCookie;
3425 origOp = outp->datap;
3433 if (searchFlags & 4)
3434 /* skip over resume key */
3437 /* make sure that curOffset.LowPart doesn't point to the first
3438 * 32 bytes in the 2nd through last dir page, and that it doesn't
3439 * point at the first 13 32-byte chunks in the first dir page,
3440 * since those are dir and page headers, and don't contain useful
3443 temp = curOffset.LowPart & (2048-1);
3444 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3445 /* we're in the first page */
3446 if (temp < 13*32) temp = 13*32;
3449 /* we're in a later dir page */
3450 if (temp < 32) temp = 32;
3453 /* make sure the low order 5 bits are zero */
3456 /* now put temp bits back ito curOffset.LowPart */
3457 curOffset.LowPart &= ~(2048-1);
3458 curOffset.LowPart |= temp;
3460 /* check if we've passed the dir's EOF */
3461 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
3466 /* check if we've returned all the names that will fit in the
3467 * response packet; we check return count as well as the number
3468 * of bytes requested. We check the # of bytes after we find
3469 * the dir entry, since we'll need to check its size.
3471 if (returnedNames >= maxCount) {
3475 /* see if we can use the bufferp we have now; compute in which
3476 * page the current offset would be, and check whether that's
3477 * the offset of the buffer we have. If not, get the buffer.
3479 thyper.HighPart = curOffset.HighPart;
3480 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3481 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3484 buf_Release(bufferp);
3487 lock_ReleaseMutex(&scp->mx);
3488 lock_ObtainRead(&scp->bufCreateLock);
3489 code = buf_Get(scp, &thyper, &bufferp);
3490 lock_ReleaseRead(&scp->bufCreateLock);
3492 /* now, if we're doing a star match, do bulk fetching
3493 * of all of the status info for files in the dir.
3496 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
3499 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
3500 && LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
3501 /* Don't bulk stat if risking timeout */
3502 int now = GetCurrentTime();
3503 if (now - req.startTime > 5000) {
3504 scp->bulkStatProgress = thyper;
3505 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3506 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3508 cm_TryBulkStat(scp, &thyper, userp, &req);
3512 lock_ObtainMutex(&scp->mx);
3514 bufferOffset = thyper;
3516 /* now get the data in the cache */
3518 code = cm_SyncOp(scp, bufferp, userp, &req,
3520 CM_SCACHESYNC_NEEDCALLBACK
3521 | CM_SCACHESYNC_READ);
3524 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3526 /* otherwise, load the buffer and try again */
3527 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3532 buf_Release(bufferp);
3536 } /* if (wrong buffer) ... */
3538 /* now we have the buffer containing the entry we're interested
3539 * in; copy it out if it represents a non-deleted entry.
3541 entryInDir = curOffset.LowPart & (2048-1);
3542 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3544 /* page header will help tell us which entries are free. Page
3545 * header can change more often than once per buffer, since
3546 * AFS 3 dir page size may be less than (but not more than)
3547 * a buffer package buffer.
3549 /* only look intra-buffer */
3550 temp = curOffset.LowPart & (buf_bufferSize - 1);
3551 temp &= ~(2048 - 1); /* turn off intra-page bits */
3552 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3554 /* now determine which entry we're looking at in the page.
3555 * If it is free (there's a free bitmap at the start of the
3556 * dir), we should skip these 32 bytes.
3558 slotInPage = (entryInDir & 0x7e0) >> 5;
3559 if (!(pageHeaderp->freeBitmap[slotInPage>>3]
3560 & (1 << (slotInPage & 0x7)))) {
3561 /* this entry is free */
3562 numDirChunks = 1; /* only skip this guy */
3566 tp = bufferp->datap + entryInBuffer;
3567 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3569 /* while we're here, compute the next entry's location, too,
3570 * since we'll need it when writing out the cookie into the dir
3573 * XXXX Probably should do more sanity checking.
3575 numDirChunks = cm_NameEntries(dep->name, &onbytes);
3577 /* compute offset of cookie representing next entry */
3578 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3580 /* Need 8.3 name? */
3582 if (infoLevel == 0x104
3583 && dep->fid.vnode != 0
3584 && !cm_Is8Dot3(dep->name)) {
3585 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3589 /* When matching, we are using doing a case fold if we have a wildcard mask.
3590 * If we get a non-wildcard match, it's a lookup for a specific file.
3592 if (dep->fid.vnode != 0 &&
3593 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0))
3595 && smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
3597 /* Eliminate entries that don't match requested attributes */
3598 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
3599 smb_IsDotFile(dep->name))
3600 goto nextEntry; /* no hidden files */
3602 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3604 /* We have already done the cm_TryBulkStat above */
3605 fid.cell = scp->fid.cell;
3606 fid.volume = scp->fid.volume;
3607 fid.vnode = ntohl(dep->fid.vnode);
3608 fid.unique = ntohl(dep->fid.unique);
3609 fileType = cm_FindFileType(&fid);
3610 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
3611 "has filetype %d", dep->name,
3613 if (fileType == CM_SCACHETYPE_DIRECTORY)
3617 /* finally check if this name will fit */
3619 /* standard dir entry stuff */
3620 if (infoLevel < 0x101)
3621 ohbytes = 23; /* pre-NT */
3622 else if (infoLevel == 0x103)
3623 ohbytes = 12; /* NT names only */
3625 ohbytes = 64; /* NT */
3627 if (infoLevel == 0x104)
3628 ohbytes += 26; /* Short name & length */
3630 if (searchFlags & 4) {
3631 ohbytes += 4; /* if resume key required */
3635 && infoLevel != 0x101
3636 && infoLevel != 0x103)
3637 ohbytes += 4; /* EASIZE */
3639 /* add header to name & term. null */
3640 orbytes = onbytes + ohbytes + 1;
3642 /* now, we round up the record to a 4 byte alignment,
3643 * and we make sure that we have enough room here for
3644 * even the aligned version (so we don't have to worry
3645 * about an * overflow when we pad things out below).
3646 * That's the reason for the alignment arithmetic below.
3648 if (infoLevel >= 0x101)
3649 align = (4 - (orbytes & 3)) & 3;
3652 if (orbytes + bytesInBuffer + align > maxReturnData)
3655 /* this is one of the entries to use: it is not deleted
3656 * and it matches the star pattern we're looking for.
3657 * Put out the name, preceded by its length.
3659 /* First zero everything else */
3660 memset(origOp, 0, ohbytes);
3662 if (infoLevel <= 0x101)
3663 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
3664 else if (infoLevel == 0x103)
3665 *((u_long *)(op + 8)) = onbytes;
3667 *((u_long *)(op + 60)) = onbytes;
3668 strcpy(origOp+ohbytes, dep->name);
3670 /* Short name if requested and needed */
3671 if (infoLevel == 0x104) {
3672 if (NeedShortName) {
3673 strcpy(op + 70, shortName);
3674 *(op + 68) = shortNameEnd - shortName;
3678 /* now, adjust the # of entries copied */
3681 /* NextEntryOffset and FileIndex */
3682 if (infoLevel >= 101) {
3683 int entryOffset = orbytes + align;
3684 *((u_long *)op) = entryOffset;
3685 *((u_long *)(op+4)) = nextEntryCookie;
3688 /* now we emit the attribute. This is tricky, since
3689 * we need to really stat the file to find out what
3690 * type of entry we've got. Right now, we're copying
3691 * out data from * a buffer, while holding the scp
3692 * locked, so it isn't really convenient to stat
3693 * something now. We'll put in a place holder
3694 * now, and make a second pass before returning this
3695 * to get the real attributes. So, we just skip the
3696 * data for now, and adjust it later. We allocate a
3697 * patch record to make it easy to find this point
3698 * later. The replay will happen at a time when it is
3699 * safe to unlock the directory.
3701 if (infoLevel != 0x103) {
3702 curPatchp = malloc(sizeof(*curPatchp));
3703 osi_QAdd((osi_queue_t **) &dirListPatchesp,
3705 curPatchp->dptr = op;
3706 if (infoLevel >= 0x101)
3707 curPatchp->dptr += 8;
3709 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
3710 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3713 curPatchp->flags = 0;
3715 curPatchp->fid.cell = scp->fid.cell;
3716 curPatchp->fid.volume = scp->fid.volume;
3717 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3718 curPatchp->fid.unique = ntohl(dep->fid.unique);
3721 curPatchp->dep = dep;
3724 if (searchFlags & 4)
3725 /* put out resume key */
3726 *((u_long *)origOp) = nextEntryCookie;
3728 /* Adjust byte ptr and count */
3729 origOp += orbytes; /* skip entire record */
3730 bytesInBuffer += orbytes;
3732 /* and pad the record out */
3733 while (--align >= 0) {
3738 } /* if we're including this name */
3739 else if (!NeedShortName &&
3742 dep->fid.vnode != 0 &&
3743 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
3744 /* We were looking for exact matches, but here's an inexact one*/
3749 /* and adjust curOffset to be where the new cookie is */
3750 thyper.HighPart = 0;
3751 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3752 curOffset = LargeIntegerAdd(thyper, curOffset);
3753 } /* while copying data for dir listing */
3755 /* If we didn't get a star pattern, we did an exact match during the first pass.
3756 * If there were no exact matches found, we fail over to inexact matches by
3757 * marking the query as a star pattern (matches all case permutations), and
3758 * re-running the query.
3760 if (returnedNames == 0 && !starPattern && foundInexact) {
3761 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
3766 /* release the mutex */
3767 lock_ReleaseMutex(&scp->mx);
3768 if (bufferp) buf_Release(bufferp);
3770 /* apply and free last set of patches; if not doing a star match, this
3771 * will be empty, but better safe (and freeing everything) than sorry.
3773 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
3776 /* now put out the final parameters */
3777 if (returnedNames == 0) eos = 1;
3778 if (p->opcode == 1) {
3780 outp->parmsp[0] = (unsigned short) dsp->cookie;
3781 outp->parmsp[1] = returnedNames;
3782 outp->parmsp[2] = eos;
3783 outp->parmsp[3] = 0; /* nothing wrong with EAS */
3784 outp->parmsp[4] = 0;
3785 /* don't need last name to continue
3786 * search, cookie is enough. Normally,
3787 * this is the offset of the file name
3788 * of the last entry returned.
3790 outp->totalParms = 10; /* in bytes */
3794 outp->parmsp[0] = returnedNames;
3795 outp->parmsp[1] = eos;
3796 outp->parmsp[2] = 0; /* EAS error */
3797 outp->parmsp[3] = 0; /* last name, as above */
3798 outp->totalParms = 8; /* in bytes */
3801 /* return # of bytes in the buffer */
3802 outp->totalData = bytesInBuffer;
3804 osi_Log2(smb_logp, "T2 search dir done, %d names, code %d",
3805 returnedNames, code);
3807 /* Return error code if unsuccessful on first request */
3808 if (code == 0 && p->opcode == 1 && returnedNames == 0)
3809 code = CM_ERROR_NOSUCHFILE;
3811 /* if we're supposed to close the search after this request, or if
3812 * we're supposed to close the search if we're done, and we're done,
3813 * or if something went wrong, close the search.
3815 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
3816 if ((searchFlags & 1) || (returnedNames == 0) ||
3817 ((searchFlags & 2) && eos) || code != 0)
3818 smb_DeleteDirSearch(dsp);
3820 smb_SendTran2Error(vcp, p, opx, code);
3822 smb_SendTran2Packet(vcp, outp, opx);
3824 smb_FreeTran2Packet(outp);
3825 smb_ReleaseDirSearch(dsp);
3826 cm_ReleaseSCache(scp);
3827 cm_ReleaseUser(userp);
3831 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3834 smb_dirSearch_t *dsp;
3836 dirHandle = smb_GetSMBParm(inp, 0);
3838 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
3840 dsp = smb_FindDirSearch(dirHandle);
3843 return CM_ERROR_BADFD;
3845 /* otherwise, we have an FD to destroy */
3846 smb_DeleteDirSearch(dsp);
3847 smb_ReleaseDirSearch(dsp);
3849 /* and return results */
3850 smb_SetSMBDataLength(outp, 0);
3855 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3857 smb_SetSMBDataLength(outp, 0);
3861 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3868 cm_scache_t *dscp; /* dir we're dealing with */
3869 cm_scache_t *scp; /* file we're creating */
3871 int initialModeBits;
3881 int parmSlot; /* which parm we're dealing with */
3889 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
3890 openFun = smb_GetSMBParm(inp, 8); /* open function */
3891 excl = ((openFun & 3) == 0);
3892 trunc = ((openFun & 3) == 2); /* truncate it */
3893 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
3894 openAction = 0; /* tracks what we did */
3896 attributes = smb_GetSMBParm(inp, 5);
3897 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
3899 /* compute initial mode bits based on read-only flag in attributes */
3900 initialModeBits = 0666;
3901 if (attributes & 1) initialModeBits &= ~0222;
3903 pathp = smb_GetSMBData(inp, NULL);
3905 spacep = inp->spacep;
3906 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
3908 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3909 /* special case magic file name for receiving IOCTL requests
3910 * (since IOCTL calls themselves aren't getting through).
3913 osi_Log0(smb_logp, "IOCTL Open");
3916 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3917 smb_SetupIoctlFid(fidp, spacep);
3919 /* set inp->fid so that later read calls in same msg can find fid */
3920 inp->fid = fidp->fid;
3922 /* copy out remainder of the parms */
3924 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3926 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
3927 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
3928 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
3929 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
3930 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
3931 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
3932 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
3933 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
3935 /* and the final "always present" stuff */
3936 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
3937 /* next write out the "unique" ID */
3938 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
3939 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
3940 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
3941 smb_SetSMBDataLength(outp, 0);
3943 /* and clean up fid reference */
3944 smb_ReleaseFID(fidp);
3948 #ifdef DEBUG_VERBOSE
3950 char *hexp, *asciip;
3951 asciip = (lastNamep ? lastNamep : pathp );
3952 hexp = osi_HexifyString(asciip);
3953 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
3957 userp = smb_GetUser(vcp, inp);
3960 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3961 code = cm_NameI(cm_rootSCachep, pathp,
3962 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3963 userp, tidPathp, &req, &scp);
3965 code = cm_NameI(cm_rootSCachep, spacep->data,
3966 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3967 userp, tidPathp, &req, &dscp);
3970 cm_ReleaseUser(userp);
3974 /* otherwise, scp points to the parent directory. Do a lookup,
3975 * and truncate the file if we find it, otherwise we create the
3978 if (!lastNamep) lastNamep = pathp;
3980 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
3982 if (code && code != CM_ERROR_NOSUCHFILE) {
3983 cm_ReleaseSCache(dscp);
3984 cm_ReleaseUser(userp);
3989 /* if we get here, if code is 0, the file exists and is represented by
3990 * scp. Otherwise, we have to create it. The dir may be represented
3991 * by dscp, or we may have found the file directly. If code is non-zero,
3995 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
3997 if (dscp) cm_ReleaseSCache(dscp);
3998 cm_ReleaseSCache(scp);
3999 cm_ReleaseUser(userp);
4004 /* oops, file shouldn't be there */
4005 if (dscp) cm_ReleaseSCache(dscp);
4006 cm_ReleaseSCache(scp);
4007 cm_ReleaseUser(userp);
4008 return CM_ERROR_EXISTS;
4012 setAttr.mask = CM_ATTRMASK_LENGTH;
4013 setAttr.length.LowPart = 0;
4014 setAttr.length.HighPart = 0;
4015 code = cm_SetAttr(scp, &setAttr, userp, &req);
4016 openAction = 3; /* truncated existing file */
4018 else openAction = 1; /* found existing file */
4020 else if (!(openFun & 0x10)) {
4021 /* don't create if not found */
4022 if (dscp) cm_ReleaseSCache(dscp);
4023 cm_ReleaseUser(userp);
4024 return CM_ERROR_NOSUCHFILE;
4027 osi_assert(dscp != NULL);
4028 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
4029 osi_LogSaveString(smb_logp, lastNamep));
4030 openAction = 2; /* created file */
4031 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4032 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
4033 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4035 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4036 smb_NotifyChange(FILE_ACTION_ADDED,
4037 FILE_NOTIFY_CHANGE_FILE_NAME,
4038 dscp, lastNamep, NULL, TRUE);
4039 if (!excl && code == CM_ERROR_EXISTS) {
4040 /* not an exclusive create, and someone else tried
4041 * creating it already, then we open it anyway. We
4042 * don't bother retrying after this, since if this next
4043 * fails, that means that the file was deleted after we
4044 * started this call.
4046 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4050 setAttr.mask = CM_ATTRMASK_LENGTH;
4051 setAttr.length.LowPart = 0;
4052 setAttr.length.HighPart = 0;
4053 code = cm_SetAttr(scp, &setAttr, userp, &req);
4055 } /* lookup succeeded */
4059 /* we don't need this any longer */
4060 if (dscp) cm_ReleaseSCache(dscp);
4063 /* something went wrong creating or truncating the file */
4064 if (scp) cm_ReleaseSCache(scp);
4065 cm_ReleaseUser(userp);
4069 /* make sure we're about to open a file */
4070 if (scp->fileType != CM_SCACHETYPE_FILE) {
4071 cm_ReleaseSCache(scp);
4072 cm_ReleaseUser(userp);
4073 return CM_ERROR_ISDIR;
4076 /* now all we have to do is open the file itself */
4077 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4080 /* save a pointer to the vnode */
4083 /* compute open mode */
4084 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
4085 if (openMode == 1 || openMode == 2)
4086 fidp->flags |= SMB_FID_OPENWRITE;
4088 smb_ReleaseFID(fidp);
4090 cm_Open(scp, 0, userp);
4092 /* set inp->fid so that later read calls in same msg can find fid */
4093 inp->fid = fidp->fid;
4095 /* copy out remainder of the parms */
4097 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4098 lock_ObtainMutex(&scp->mx);
4100 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
4101 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4102 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
4103 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
4104 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
4105 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
4106 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4107 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4108 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4110 /* and the final "always present" stuff */
4111 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
4112 /* next write out the "unique" ID */
4113 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
4114 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
4115 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4116 lock_ReleaseMutex(&scp->mx);
4117 smb_SetSMBDataLength(outp, 0);
4119 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
4121 cm_ReleaseUser(userp);
4122 /* leave scp held since we put it in fidp->scp */
4126 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4133 unsigned char LockType;
4134 unsigned short NumberOfUnlocks, NumberOfLocks;
4135 unsigned long Timeout;
4137 LARGE_INTEGER LOffset, LLength;
4138 smb_waitingLock_t *waitingLock;
4145 fid = smb_GetSMBParm(inp, 2);
4146 fid = smb_ChainFID(fid, inp);
4148 fidp = smb_FindFID(vcp, fid, 0);
4149 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4150 return CM_ERROR_BADFD;
4152 /* set inp->fid so that later read calls in same msg can find fid */
4155 userp = smb_GetUser(vcp, inp);
4159 lock_ObtainMutex(&scp->mx);
4160 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4161 CM_SCACHESYNC_NEEDCALLBACK
4162 | CM_SCACHESYNC_GETSTATUS
4163 | CM_SCACHESYNC_LOCK);
4164 if (code) goto doneSync;
4166 LockType = smb_GetSMBParm(inp, 3) & 0xff;
4167 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
4168 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
4169 NumberOfLocks = smb_GetSMBParm(inp, 7);
4171 op = smb_GetSMBData(inp, NULL);
4173 for (i=0; i<NumberOfUnlocks; i++) {
4174 if (LockType & 0x10) {
4176 LOffset.HighPart = *((LONG *)(op + 4));
4177 LOffset.LowPart = *((DWORD *)(op + 8));
4178 LLength.HighPart = *((LONG *)(op + 12));
4179 LLength.LowPart = *((DWORD *)(op + 16));
4183 /* Not Large Files */
4184 LOffset.HighPart = 0;
4185 LOffset.LowPart = *((DWORD *)(op + 2));
4186 LLength.HighPart = 0;
4187 LLength.LowPart = *((DWORD *)(op + 6));
4190 if (LargeIntegerNotEqualToZero(LOffset))
4192 /* Do not check length -- length check done in cm_Unlock */
4194 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
4195 if (code) goto done;
4198 for (i=0; i<NumberOfLocks; i++) {
4199 if (LockType & 0x10) {
4201 LOffset.HighPart = *((LONG *)(op + 4));
4202 LOffset.LowPart = *((DWORD *)(op + 8));
4203 LLength.HighPart = *((LONG *)(op + 12));
4204 LLength.LowPart = *((DWORD *)(op + 16));
4208 /* Not Large Files */
4209 LOffset.HighPart = 0;
4210 LOffset.LowPart = *((DWORD *)(op + 2));
4211 LLength.HighPart = 0;
4212 LLength.LowPart = *((DWORD *)(op + 6));
4215 if (LargeIntegerNotEqualToZero(LOffset))
4217 if (LargeIntegerLessThan(LOffset, scp->length))
4220 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
4221 userp, &req, &lockp);
4222 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
4223 /* Put on waiting list */
4224 waitingLock = malloc(sizeof(smb_waitingLock_t));
4225 waitingLock->vcp = vcp;
4226 waitingLock->inp = smb_CopyPacket(inp);
4227 waitingLock->outp = smb_CopyPacket(outp);
4228 waitingLock->timeRemaining = Timeout;
4229 waitingLock->lockp = lockp;
4230 lock_ObtainWrite(&smb_globalLock);
4231 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
4233 osi_Wakeup((long) &smb_allWaitingLocks);
4234 lock_ReleaseWrite(&smb_globalLock);
4235 /* don't send reply immediately */
4236 outp->flags |= SMB_PACKETFLAG_NOSEND;
4242 /* release any locks acquired before the failure */
4245 smb_SetSMBDataLength(outp, 0);
4247 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
4249 lock_ReleaseMutex(&scp->mx);
4250 cm_ReleaseUser(userp);
4251 smb_ReleaseFID(fidp);
4256 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4268 fid = smb_GetSMBParm(inp, 0);
4269 fid = smb_ChainFID(fid, inp);
4271 fidp = smb_FindFID(vcp, fid, 0);
4272 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4273 return CM_ERROR_BADFD;
4276 userp = smb_GetUser(vcp, inp);
4280 /* otherwise, stat the file */
4281 lock_ObtainMutex(&scp->mx);
4282 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4283 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4284 if (code) goto done;
4286 /* decode times. We need a search time, but the response to this
4287 * call provides the date first, not the time, as returned in the
4288 * searchTime variable. So we take the high-order bits first.
4290 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
4291 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
4292 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
4293 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
4294 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
4295 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
4296 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
4298 /* now handle file size and allocation size */
4299 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
4300 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
4301 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
4302 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
4304 /* file attribute */
4305 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
4307 /* and finalize stuff */
4308 smb_SetSMBDataLength(outp, 0);
4312 lock_ReleaseMutex(&scp->mx);
4313 cm_ReleaseUser(userp);
4314 smb_ReleaseFID(fidp);
4318 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4332 fid = smb_GetSMBParm(inp, 0);
4333 fid = smb_ChainFID(fid, inp);
4335 fidp = smb_FindFID(vcp, fid, 0);
4336 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4337 return CM_ERROR_BADFD;
4340 userp = smb_GetUser(vcp, inp);
4344 /* now prepare to call cm_setattr. This message only sets various times,
4345 * and AFS only implements mtime, and we'll set the mtime if that's
4346 * requested. The others we'll ignore.
4348 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
4350 if (searchTime != 0) {
4351 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
4353 if ( unixTime != -1 ) {
4354 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
4355 attrs.clientModTime = unixTime;
4356 code = cm_SetAttr(scp, &attrs, userp, &req);
4358 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
4360 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
4365 cm_ReleaseUser(userp);
4366 smb_ReleaseFID(fidp);
4371 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4374 long count, finalCount;
4381 fd = smb_GetSMBParm(inp, 2);
4382 count = smb_GetSMBParm(inp, 5);
4383 offset.HighPart = 0; /* too bad */
4384 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
4386 osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
4387 fd, offset.LowPart, count);
4389 fd = smb_ChainFID(fd, inp);
4390 fidp = smb_FindFID(vcp, fd, 0);
4392 return CM_ERROR_BADFD;
4394 /* set inp->fid so that later read calls in same msg can find fid */
4397 if (fidp->flags & SMB_FID_IOCTL) {
4398 return smb_IoctlV3Read(fidp, vcp, inp, outp);
4401 userp = smb_GetUser(vcp, inp);
4403 /* 0 and 1 are reserved for request chaining, were setup by our caller,
4404 * and will be further filled in after we return.
4406 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
4407 smb_SetSMBParm(outp, 3, 0); /* resvd */
4408 smb_SetSMBParm(outp, 4, 0); /* resvd */
4409 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
4410 /* fill in #6 when we have all the parameters' space reserved */
4411 smb_SetSMBParm(outp, 7, 0); /* resv'd */
4412 smb_SetSMBParm(outp, 8, 0); /* resv'd */
4413 smb_SetSMBParm(outp, 9, 0); /* resv'd */
4414 smb_SetSMBParm(outp, 10, 0); /* resv'd */
4415 smb_SetSMBParm(outp, 11, 0); /* reserved */
4417 /* get op ptr after putting in the parms, since otherwise we don't
4418 * know where the data really is.
4420 op = smb_GetSMBData(outp, NULL);
4422 /* now fill in offset from start of SMB header to first data byte (to op) */
4423 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
4425 /* set the packet data length the count of the # of bytes */
4426 smb_SetSMBDataLength(outp, count);
4429 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
4431 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
4434 /* fix some things up */
4435 smb_SetSMBParm(outp, 5, finalCount);
4436 smb_SetSMBDataLength(outp, finalCount);
4438 smb_ReleaseFID(fidp);
4440 cm_ReleaseUser(userp);
4445 * Values for createDisp, copied from NTDDK.H
4447 * FILE_SUPERSEDE 0 (???)
4448 * FILE_OPEN 1 (open)
4449 * FILE_CREATE 2 (exclusive)
4450 * FILE_OPEN_IF 3 (non-exclusive)
4451 * FILE_OVERWRITE 4 (open & truncate, but do not create)
4452 * FILE_OVERWRITE_IF 5 (open & truncate, or create)
4455 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4457 char *pathp, *realPathp;
4461 cm_scache_t *dscp; /* parent dir */
4462 cm_scache_t *scp; /* file to create or open */
4466 unsigned short nameLength;
4468 unsigned int requestOpLock;
4469 unsigned int requestBatchOpLock;
4470 unsigned int mustBeDir;
4471 unsigned int treeCreate;
4473 unsigned int desiredAccess;
4474 unsigned int extAttributes;
4475 unsigned int createDisp;
4476 unsigned int createOptions;
4477 int initialModeBits;
4478 unsigned short baseFid;
4479 smb_fid_t *baseFidp;
4481 cm_scache_t *baseDirp;
4482 unsigned short openAction;
4497 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
4498 flags = smb_GetSMBOffsetParm(inp, 3, 1)
4499 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
4500 requestOpLock = flags & 0x02;
4501 requestBatchOpLock = flags & 0x04;
4502 mustBeDir = flags & 0x08;
4505 * Why all of a sudden 32-bit FID?
4506 * We will reject all bits higher than 16.
4508 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
4509 return CM_ERROR_INVAL;
4510 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
4511 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
4512 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
4513 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
4514 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
4515 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
4516 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
4517 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
4518 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
4520 /* mustBeDir is never set; createOptions directory bit seems to be
4523 if (createOptions & 1)
4525 else if (createOptions & 0x40)
4531 * compute initial mode bits based on read-only flag in
4532 * extended attributes
4534 initialModeBits = 0666;
4535 if (extAttributes & 1) initialModeBits &= ~0222;
4537 pathp = smb_GetSMBData(inp, NULL);
4538 /* Sometimes path is not null-terminated, so we make a copy. */
4539 realPathp = malloc(nameLength+1);
4540 memcpy(realPathp, pathp, nameLength);
4541 realPathp[nameLength] = 0;
4543 spacep = inp->spacep;
4544 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
4546 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
4547 osi_Log4(smb_logp,"NTCreateX da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
4548 osi_Log1(smb_logp,"NTCreateX lastNamep=[%s]",osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
4550 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4551 /* special case magic file name for receiving IOCTL requests
4552 * (since IOCTL calls themselves aren't getting through).
4554 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4555 smb_SetupIoctlFid(fidp, spacep);
4556 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
4558 /* set inp->fid so that later read calls in same msg can find fid */
4559 inp->fid = fidp->fid;
4563 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
4564 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4565 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
4567 memset(&ft, 0, sizeof(ft));
4568 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4569 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4570 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4571 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4572 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
4573 sz.HighPart = 0x7fff; sz.LowPart = 0;
4574 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
4575 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
4576 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
4577 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
4578 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
4579 smb_SetSMBDataLength(outp, 0);
4581 /* clean up fid reference */
4582 smb_ReleaseFID(fidp);
4587 #ifdef DEBUG_VERBOSE
4589 char *hexp, *asciip;
4590 asciip = (lastNamep? lastNamep : realPathp);
4591 hexp = osi_HexifyString( asciip );
4592 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
4596 userp = smb_GetUser(vcp, inp);
4598 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
4600 return CM_ERROR_INVAL;
4604 baseDirp = cm_rootSCachep;
4605 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
4608 baseFidp = smb_FindFID(vcp, baseFid, 0);
4610 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
4612 cm_ReleaseUser(userp);
4613 return CM_ERROR_INVAL;
4615 baseDirp = baseFidp->scp;
4619 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
4621 /* compute open mode */
4623 if (desiredAccess & DELETE)
4624 fidflags |= SMB_FID_OPENDELETE;
4625 if (desiredAccess & AFS_ACCESS_READ)
4626 fidflags |= SMB_FID_OPENREAD;
4627 if (desiredAccess & AFS_ACCESS_WRITE)
4628 fidflags |= SMB_FID_OPENWRITE;
4632 /* For an exclusive create, we want to do a case sensitive match for the last component. */
4633 if (createDisp == 2 || createDisp == 4 || createDisp == 5) {
4634 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4635 userp, tidPathp, &req, &dscp);
4637 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
4639 if (code == CM_ERROR_NOSUCHFILE) {
4640 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
4641 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
4642 if (code == 0 && realDirFlag == 1) {
4643 cm_ReleaseSCache(scp);
4644 cm_ReleaseSCache(dscp);
4645 cm_ReleaseUser(userp);
4647 return CM_ERROR_EXISTS;
4653 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4654 userp, tidPathp, &req, &scp);
4659 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
4660 /* look up parent directory */
4661 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
4662 * the immediate parent. We have to work our way up realPathp until we hit something that we
4670 code = cm_NameI(baseDirp, spacep->data,
4671 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4672 userp, tidPathp, &req, &dscp);
4675 (tp = strrchr(spacep->data,'\\')) &&
4676 (createDisp == 2) &&
4677 (realDirFlag == 1)) {
4680 treeStartp = realPathp + (tp - spacep->data);
4682 if (*tp && !smb_IsLegalFilename(tp)) {
4684 smb_ReleaseFID(baseFidp);
4685 cm_ReleaseUser(userp);
4687 return CM_ERROR_BADNTFILENAME;
4697 smb_ReleaseFID(baseFidp);
4700 osi_Log0(smb_logp,"NTCreateX parent not found");
4701 cm_ReleaseUser(userp);
4706 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
4707 /* A file exists where we want a directory. */
4708 cm_ReleaseSCache(dscp);
4709 cm_ReleaseUser(userp);
4711 return CM_ERROR_EXISTS;
4715 lastNamep = realPathp;
4719 if (!smb_IsLegalFilename(lastNamep)) {
4720 cm_ReleaseSCache(dscp);
4721 cm_ReleaseUser(userp);
4723 return CM_ERROR_BADNTFILENAME;
4726 if (!foundscp && !treeCreate) {
4727 if (createDisp == 2 || createDisp == 4)
4728 code = cm_Lookup(dscp, lastNamep,
4729 CM_FLAG_FOLLOW, userp, &req, &scp);
4731 code = cm_Lookup(dscp, lastNamep,
4732 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4734 if (code && code != CM_ERROR_NOSUCHFILE) {
4735 cm_ReleaseSCache(dscp);
4736 cm_ReleaseUser(userp);
4744 smb_ReleaseFID(baseFidp);
4747 /* if we get here, if code is 0, the file exists and is represented by
4748 * scp. Otherwise, we have to create it. The dir may be represented
4749 * by dscp, or we may have found the file directly. If code is non-zero,
4752 if (code == 0 && !treeCreate) {
4753 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
4756 if (dscp) cm_ReleaseSCache(dscp);
4757 cm_ReleaseSCache(scp);
4758 cm_ReleaseUser(userp);
4763 if (createDisp == 2) {
4764 /* oops, file shouldn't be there */
4765 if (dscp) cm_ReleaseSCache(dscp);
4766 cm_ReleaseSCache(scp);
4767 cm_ReleaseUser(userp);
4769 return CM_ERROR_EXISTS;
4773 || createDisp == 5) {
4774 setAttr.mask = CM_ATTRMASK_LENGTH;
4775 setAttr.length.LowPart = 0;
4776 setAttr.length.HighPart = 0;
4777 code = cm_SetAttr(scp, &setAttr, userp, &req);
4778 openAction = 3; /* truncated existing file */
4780 else openAction = 1; /* found existing file */
4782 else if (createDisp == 1 || createDisp == 4) {
4783 /* don't create if not found */
4784 if (dscp) cm_ReleaseSCache(dscp);
4785 cm_ReleaseUser(userp);
4787 return CM_ERROR_NOSUCHFILE;
4789 else if (realDirFlag == 0 || realDirFlag == -1) {
4790 osi_assert(dscp != NULL);
4791 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
4792 osi_LogSaveString(smb_logp, lastNamep));
4793 openAction = 2; /* created file */
4794 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4795 setAttr.clientModTime = time(NULL);
4796 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4798 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4799 smb_NotifyChange(FILE_ACTION_ADDED,
4800 FILE_NOTIFY_CHANGE_FILE_NAME,
4801 dscp, lastNamep, NULL, TRUE);
4802 if (code == CM_ERROR_EXISTS && createDisp != 2) {
4803 /* Not an exclusive create, and someone else tried
4804 * creating it already, then we open it anyway. We
4805 * don't bother retrying after this, since if this next
4806 * fails, that means that the file was deleted after we
4807 * started this call.
4809 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4812 if (createDisp == 5) {
4813 setAttr.mask = CM_ATTRMASK_LENGTH;
4814 setAttr.length.LowPart = 0;
4815 setAttr.length.HighPart = 0;
4816 code = cm_SetAttr(scp, &setAttr, userp,
4819 } /* lookup succeeded */
4824 char *cp; /* This component */
4825 int clen = 0; /* length of component */
4829 /* create directory */
4830 if ( !treeCreate ) treeStartp = lastNamep;
4831 osi_assert(dscp != NULL);
4832 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
4833 osi_LogSaveString(smb_logp, treeStartp));
4834 openAction = 2; /* created directory */
4836 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4837 setAttr.clientModTime = time(NULL);
4844 tp = strchr(pp, '\\');
4848 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
4852 strncpy(cp,pp,clen);
4858 if (clen == 0) continue; /* the supplied path can't have consecutive slashes either , but */
4860 /* cp is the next component to be created. */
4861 code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
4862 if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
4863 smb_NotifyChange(FILE_ACTION_ADDED,
4864 FILE_NOTIFY_CHANGE_DIR_NAME,
4865 tscp, cp, NULL, TRUE);
4867 (code == CM_ERROR_EXISTS && createDisp != 2)) {
4868 /* Not an exclusive create, and someone else tried
4869 * creating it already, then we open it anyway. We
4870 * don't bother retrying after this, since if this next
4871 * fails, that means that the file was deleted after we
4872 * started this call.
4874 code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
4879 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
4880 cm_ReleaseSCache(tscp);
4881 tscp = scp; /* Newly created directory will be next parent */
4886 if we get here and code == 0, then scp is the last directory created, and tscp is the
4887 parent of scp. dscp got released if dscp != tscp. both tscp and scp are held.
4893 /* something went wrong creating or truncating the file */
4894 if (scp) cm_ReleaseSCache(scp);
4895 if (dscp) cm_ReleaseSCache(dscp);
4896 cm_ReleaseUser(userp);
4901 /* make sure we have file vs. dir right (only applies for single component case) */
4902 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
4903 cm_ReleaseSCache(scp);
4904 if (dscp) cm_ReleaseSCache(dscp);
4905 cm_ReleaseUser(userp);
4907 return CM_ERROR_ISDIR;
4909 /* (only applies to single component case) */
4910 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
4911 cm_ReleaseSCache(scp);
4912 if (dscp) cm_ReleaseSCache(dscp);
4913 cm_ReleaseUser(userp);
4915 return CM_ERROR_NOTDIR;
4918 /* open the file itself */
4919 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4921 /* save a pointer to the vnode */
4924 fidp->flags = fidflags;
4926 /* save parent dir and pathname for delete or change notification */
4927 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
4928 fidp->flags |= SMB_FID_NTOPEN;
4929 fidp->NTopen_dscp = dscp;
4930 cm_HoldSCache(dscp);
4931 fidp->NTopen_pathp = strdup(lastNamep);
4933 fidp->NTopen_wholepathp = realPathp;
4935 /* we don't need this any longer */
4936 if (dscp) cm_ReleaseSCache(dscp);
4937 cm_Open(scp, 0, userp);
4939 /* set inp->fid so that later read calls in same msg can find fid */
4940 inp->fid = fidp->fid;
4944 lock_ObtainMutex(&scp->mx);
4945 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
4946 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4947 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
4948 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4949 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4950 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4951 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4952 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4953 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
4955 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
4956 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
4957 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
4958 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
4959 smb_SetSMBParmByte(outp, parmSlot,
4960 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
4961 lock_ReleaseMutex(&scp->mx);
4962 smb_SetSMBDataLength(outp, 0);
4964 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
4965 osi_LogSaveString(smb_logp, realPathp));
4967 smb_ReleaseFID(fidp);
4969 cm_ReleaseUser(userp);
4971 /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
4973 /* leave scp held since we put it in fidp->scp */
4978 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
4979 * Instead, ultimately, would like to use a subroutine for common code.
4981 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4983 char *pathp, *realPathp;
4987 cm_scache_t *dscp; /* parent dir */
4988 cm_scache_t *scp; /* file to create or open */
4991 unsigned long nameLength;
4993 unsigned int requestOpLock;
4994 unsigned int requestBatchOpLock;
4995 unsigned int mustBeDir;
4996 unsigned int extendedRespRequired;
4998 unsigned int desiredAccess;
4999 #ifdef DEBUG_VERBOSE
5000 unsigned int allocSize;
5001 unsigned int shareAccess;
5003 unsigned int extAttributes;
5004 unsigned int createDisp;
5005 #ifdef DEBUG_VERBOSE
5008 unsigned int createOptions;
5009 int initialModeBits;
5010 unsigned short baseFid;
5011 smb_fid_t *baseFidp;
5013 cm_scache_t *baseDirp;
5014 unsigned short openAction;
5020 int parmOffset, dataOffset;
5031 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
5032 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
5033 parmp = inp->data + parmOffset;
5034 lparmp = (ULONG *) parmp;
5037 requestOpLock = flags & 0x02;
5038 requestBatchOpLock = flags & 0x04;
5039 mustBeDir = flags & 0x08;
5040 extendedRespRequired = flags & 0x10;
5043 * Why all of a sudden 32-bit FID?
5044 * We will reject all bits higher than 16.
5046 if (lparmp[1] & 0xFFFF0000)
5047 return CM_ERROR_INVAL;
5048 baseFid = (unsigned short)lparmp[1];
5049 desiredAccess = lparmp[2];
5050 #ifdef DEBUG_VERBOSE
5051 allocSize = lparmp[3];
5052 #endif /* DEBUG_VERSOSE */
5053 extAttributes = lparmp[5];
5055 shareAccess = lparmp[6];
5057 createDisp = lparmp[7];
5058 createOptions = lparmp[8];
5059 #ifdef DEBUG_VERBOSE
5062 nameLength = lparmp[11];
5064 #ifdef DEBUG_VERBOSE
5065 osi_Log4(smb_logp,"NTTransCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
5066 osi_Log2(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
5067 osi_Log1(smb_logp,"... flags[%x]",flags);
5070 /* mustBeDir is never set; createOptions directory bit seems to be
5073 if (createOptions & 1)
5075 else if (createOptions & 0x40)
5081 * compute initial mode bits based on read-only flag in
5082 * extended attributes
5084 initialModeBits = 0666;
5085 if (extAttributes & 1) initialModeBits &= ~0222;
5087 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
5088 /* Sometimes path is not null-terminated, so we make a copy. */
5089 realPathp = malloc(nameLength+1);
5090 memcpy(realPathp, pathp, nameLength);
5091 realPathp[nameLength] = 0;
5093 spacep = cm_GetSpace();
5094 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5097 * Nothing here to handle SMB_IOCTL_FILENAME.
5098 * Will add it if necessary.
5101 #ifdef DEBUG_VERBOSE
5103 char *hexp, *asciip;
5104 asciip = (lastNamep? lastNamep : realPathp);
5105 hexp = osi_HexifyString( asciip );
5106 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
5111 userp = smb_GetUser(vcp, inp);
5113 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
5115 return CM_ERROR_INVAL;
5119 baseDirp = cm_rootSCachep;
5120 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
5123 baseFidp = smb_FindFID(vcp, baseFid, 0);
5125 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
5127 cm_ReleaseUser(userp);
5128 return CM_ERROR_INVAL;
5130 baseDirp = baseFidp->scp;
5134 /* compute open mode */
5136 if (desiredAccess & DELETE)
5137 fidflags |= SMB_FID_OPENDELETE;
5138 if (desiredAccess & AFS_ACCESS_READ)
5139 fidflags |= SMB_FID_OPENREAD;
5140 if (desiredAccess & AFS_ACCESS_WRITE)
5141 fidflags |= SMB_FID_OPENWRITE;
5145 if (createDisp == 2 || createDisp == 4 || createDisp == 5) {
5146 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5147 userp, tidPathp, &req, &dscp);
5149 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5151 if (code == CM_ERROR_NOSUCHFILE) {
5152 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
5153 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
5154 if (code == 0 && realDirFlag == 1) {
5155 cm_ReleaseSCache(scp);
5156 cm_ReleaseSCache(dscp);
5157 cm_ReleaseUser(userp);
5159 return CM_ERROR_EXISTS;
5165 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5166 userp, tidPathp, &req, &scp);
5169 if (code == 0) foundscp = TRUE;
5171 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
5172 /* look up parent directory */
5174 code = cm_NameI(baseDirp, spacep->data,
5175 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5176 userp, tidPathp, &req, &dscp);
5180 cm_FreeSpace(spacep);
5183 smb_ReleaseFID(baseFidp);
5188 cm_ReleaseUser(userp);
5193 if (!lastNamep) lastNamep = realPathp;
5196 if (!smb_IsLegalFilename(lastNamep))
5197 return CM_ERROR_BADNTFILENAME;
5200 if (createDisp == 2 || createDisp == 4)
5201 code = cm_Lookup(dscp, lastNamep,
5202 CM_FLAG_FOLLOW, userp, &req, &scp);
5204 code = cm_Lookup(dscp, lastNamep,
5205 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5207 if (code && code != CM_ERROR_NOSUCHFILE) {
5208 cm_ReleaseSCache(dscp);
5209 cm_ReleaseUser(userp);
5217 smb_ReleaseFID(baseFidp);
5220 cm_FreeSpace(spacep);
5223 /* if we get here, if code is 0, the file exists and is represented by
5224 * scp. Otherwise, we have to create it. The dir may be represented
5225 * by dscp, or we may have found the file directly. If code is non-zero,
5229 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
5232 if (dscp) cm_ReleaseSCache(dscp);
5233 cm_ReleaseSCache(scp);
5234 cm_ReleaseUser(userp);
5239 if (createDisp == 2) {
5240 /* oops, file shouldn't be there */
5241 if (dscp) cm_ReleaseSCache(dscp);
5242 cm_ReleaseSCache(scp);
5243 cm_ReleaseUser(userp);
5245 return CM_ERROR_EXISTS;
5249 || createDisp == 5) {
5250 setAttr.mask = CM_ATTRMASK_LENGTH;
5251 setAttr.length.LowPart = 0;
5252 setAttr.length.HighPart = 0;
5253 code = cm_SetAttr(scp, &setAttr, userp, &req);
5254 openAction = 3; /* truncated existing file */
5256 else openAction = 1; /* found existing file */
5258 else if (createDisp == 1 || createDisp == 4) {
5259 /* don't create if not found */
5260 if (dscp) cm_ReleaseSCache(dscp);
5261 cm_ReleaseUser(userp);
5263 return CM_ERROR_NOSUCHFILE;
5265 else if (realDirFlag == 0 || realDirFlag == -1) {
5266 osi_assert(dscp != NULL);
5267 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
5268 osi_LogSaveString(smb_logp, lastNamep));
5269 openAction = 2; /* created file */
5270 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5271 setAttr.clientModTime = time(NULL);
5272 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5274 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5275 smb_NotifyChange(FILE_ACTION_ADDED,
5276 FILE_NOTIFY_CHANGE_FILE_NAME,
5277 dscp, lastNamep, NULL, TRUE);
5278 if (code == CM_ERROR_EXISTS && createDisp != 2) {
5279 /* Not an exclusive create, and someone else tried
5280 * creating it already, then we open it anyway. We
5281 * don't bother retrying after this, since if this next
5282 * fails, that means that the file was deleted after we
5283 * started this call.
5285 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5288 if (createDisp == 5) {
5289 setAttr.mask = CM_ATTRMASK_LENGTH;
5290 setAttr.length.LowPart = 0;
5291 setAttr.length.HighPart = 0;
5292 code = cm_SetAttr(scp, &setAttr, userp,
5295 } /* lookup succeeded */
5299 /* create directory */
5300 osi_assert(dscp != NULL);
5302 "smb_ReceiveNTTranCreate creating directory %s",
5303 osi_LogSaveString(smb_logp, lastNamep));
5304 openAction = 2; /* created directory */
5305 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5306 setAttr.clientModTime = time(NULL);
5307 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5308 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5309 smb_NotifyChange(FILE_ACTION_ADDED,
5310 FILE_NOTIFY_CHANGE_DIR_NAME,
5311 dscp, lastNamep, NULL, TRUE);
5313 || (code == CM_ERROR_EXISTS && createDisp != 2)) {
5314 /* Not an exclusive create, and someone else tried
5315 * creating it already, then we open it anyway. We
5316 * don't bother retrying after this, since if this next
5317 * fails, that means that the file was deleted after we
5318 * started this call.
5320 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5326 /* something went wrong creating or truncating the file */
5327 if (scp) cm_ReleaseSCache(scp);
5328 cm_ReleaseUser(userp);
5333 /* make sure we have file vs. dir right */
5334 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5335 cm_ReleaseSCache(scp);
5336 cm_ReleaseUser(userp);
5338 return CM_ERROR_ISDIR;
5340 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5341 cm_ReleaseSCache(scp);
5342 cm_ReleaseUser(userp);
5344 return CM_ERROR_NOTDIR;
5347 /* open the file itself */
5348 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5351 /* save a pointer to the vnode */
5354 fidp->flags = fidflags;
5356 /* save parent dir and pathname for deletion or change notification */
5357 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5358 fidp->flags |= SMB_FID_NTOPEN;
5359 fidp->NTopen_dscp = dscp;
5360 cm_HoldSCache(dscp);
5361 fidp->NTopen_pathp = strdup(lastNamep);
5363 fidp->NTopen_wholepathp = realPathp;
5365 /* we don't need this any longer */
5366 if (dscp) cm_ReleaseSCache(dscp);
5368 cm_Open(scp, 0, userp);
5370 /* set inp->fid so that later read calls in same msg can find fid */
5371 inp->fid = fidp->fid;
5373 /* check whether we are required to send an extended response */
5374 if (!extendedRespRequired) {
5376 parmOffset = 8*4 + 39;
5377 parmOffset += 1; /* pad to 4 */
5378 dataOffset = parmOffset + 70;
5382 /* Total Parameter Count */
5383 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
5384 /* Total Data Count */
5385 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5386 /* Parameter Count */
5387 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
5388 /* Parameter Offset */
5389 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5390 /* Parameter Displacement */
5391 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5393 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5395 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5396 /* Data Displacement */
5397 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5398 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5399 smb_SetSMBDataLength(outp, 70);
5401 lock_ObtainMutex(&scp->mx);
5402 outData = smb_GetSMBData(outp, NULL);
5403 outData++; /* round to get to parmOffset */
5404 *outData = 0; outData++; /* oplock */
5405 *outData = 0; outData++; /* reserved */
5406 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
5407 *((ULONG *)outData) = openAction; outData += 4;
5408 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
5409 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5410 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
5411 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
5412 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
5413 *((FILETIME *)outData) = ft; outData += 8; /* change time */
5414 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
5415 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
5416 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
5417 *((USHORT *)outData) = 0; outData += 2; /* filetype */
5418 *((USHORT *)outData) = 0; outData += 2; /* dev state */
5419 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
5420 outData += 2; /* is a dir? */
5421 lock_ReleaseMutex(&scp->mx);
5424 parmOffset = 8*4 + 39;
5425 parmOffset += 1; /* pad to 4 */
5426 dataOffset = parmOffset + 104;
5430 /* Total Parameter Count */
5431 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
5432 /* Total Data Count */
5433 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5434 /* Parameter Count */
5435 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
5436 /* Parameter Offset */
5437 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5438 /* Parameter Displacement */
5439 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5441 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5443 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5444 /* Data Displacement */
5445 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5446 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5447 smb_SetSMBDataLength(outp, 105);
5449 lock_ObtainMutex(&scp->mx);
5450 outData = smb_GetSMBData(outp, NULL);
5451 outData++; /* round to get to parmOffset */
5452 *outData = 0; outData++; /* oplock */
5453 *outData = 1; outData++; /* response type */
5454 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
5455 *((ULONG *)outData) = openAction; outData += 4;
5456 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
5457 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5458 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
5459 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
5460 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
5461 *((FILETIME *)outData) = ft; outData += 8; /* change time */
5462 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
5463 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
5464 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
5465 *((USHORT *)outData) = 0; outData += 2; /* filetype */
5466 *((USHORT *)outData) = 0; outData += 2; /* dev state */
5467 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
5468 outData += 1; /* is a dir? */
5469 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
5470 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
5471 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
5472 lock_ReleaseMutex(&scp->mx);
5475 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
5477 smb_ReleaseFID(fidp);
5479 cm_ReleaseUser(userp);
5481 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
5482 /* leave scp held since we put it in fidp->scp */
5486 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
5489 smb_packet_t *savedPacketp;
5490 ULONG filter; USHORT fid, watchtree;
5494 filter = smb_GetSMBParm(inp, 19)
5495 | (smb_GetSMBParm(inp, 20) << 16);
5496 fid = smb_GetSMBParm(inp, 21);
5497 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
5499 fidp = smb_FindFID(vcp, fid, 0);
5501 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
5502 return CM_ERROR_BADFD;
5505 savedPacketp = smb_CopyPacket(inp);
5507 savedPacketp->vcp = vcp;
5508 lock_ObtainMutex(&smb_Dir_Watch_Lock);
5509 savedPacketp->nextp = smb_Directory_Watches;
5510 smb_Directory_Watches = savedPacketp;
5511 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
5513 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
5514 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
5517 lock_ObtainMutex(&scp->mx);
5519 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
5521 scp->flags |= CM_SCACHEFLAG_WATCHED;
5522 lock_ReleaseMutex(&scp->mx);
5523 smb_ReleaseFID(fidp);
5525 outp->flags |= SMB_PACKETFLAG_NOSEND;
5529 unsigned char nullSecurityDesc[36] = {
5530 0x01, /* security descriptor revision */
5531 0x00, /* reserved, should be zero */
5532 0x00, 0x80, /* security descriptor control;
5533 * 0x8000 : self-relative format */
5534 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
5535 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
5536 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
5537 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
5538 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5539 /* "null SID" owner SID */
5540 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5541 /* "null SID" group SID */
5544 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5546 int parmOffset, parmCount, dataOffset, dataCount;
5554 ULONG securityInformation;
5556 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
5557 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
5558 parmp = inp->data + parmOffset;
5559 sparmp = (USHORT *) parmp;
5560 lparmp = (ULONG *) parmp;
5563 securityInformation = lparmp[1];
5565 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
5566 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
5574 parmOffset = 8*4 + 39;
5575 parmOffset += 1; /* pad to 4 */
5577 dataOffset = parmOffset + parmCount;
5581 /* Total Parameter Count */
5582 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
5583 /* Total Data Count */
5584 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
5585 /* Parameter Count */
5586 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
5587 /* Parameter Offset */
5588 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5589 /* Parameter Displacement */
5590 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5592 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
5594 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5595 /* Data Displacement */
5596 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5597 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5598 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
5600 outData = smb_GetSMBData(outp, NULL);
5601 outData++; /* round to get to parmOffset */
5602 *((ULONG *)outData) = 36; outData += 4; /* length */
5604 if (maxData >= 36) {
5605 memcpy(outData, nullSecurityDesc, 36);
5609 return CM_ERROR_BUFFERTOOSMALL;
5612 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5614 unsigned short function;
5616 function = smb_GetSMBParm(inp, 18);
5618 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
5620 /* We can handle long names */
5621 if (vcp->flags & SMB_VCFLAG_USENT)
5622 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
5626 case 6: return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
5628 case 4: return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
5630 case 1: return smb_ReceiveNTTranCreate(vcp, inp, outp);
5632 default: return CM_ERROR_INVAL;
5637 * smb_NotifyChange -- find relevant change notification messages and
5640 * If we don't know the file name (i.e. a callback break), filename is
5641 * NULL, and we return a zero-length list.
5643 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
5644 cm_scache_t *dscp, char *filename, char *otherFilename,
5645 BOOL isDirectParent)
5647 smb_packet_t *watch, *lastWatch, *nextWatch;
5648 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
5649 char *outData, *oldOutData;
5653 BOOL twoEntries = FALSE;
5654 ULONG otherNameLen, oldParmCount = 0;
5659 /* Get ready for rename within directory */
5660 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
5662 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
5665 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
5666 osi_LogSaveString(smb_logp,filename),dscp);
5668 lock_ObtainMutex(&smb_Dir_Watch_Lock);
5669 watch = smb_Directory_Watches;
5671 filter = smb_GetSMBParm(watch, 19)
5672 | (smb_GetSMBParm(watch, 20) << 16);
5673 fid = smb_GetSMBParm(watch, 21);
5674 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
5675 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
5676 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
5680 * Strange hack - bug in NT Client and NT Server that we
5683 if (filter == 3 && wtree)
5686 fidp = smb_FindFID(vcp, fid, 0);
5688 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
5690 watch = watch->nextp;
5693 if (fidp->scp != dscp
5694 || (filter & notifyFilter) == 0
5695 || (!isDirectParent && !wtree)) {
5696 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
5697 smb_ReleaseFID(fidp);
5699 watch = watch->nextp;
5702 smb_ReleaseFID(fidp);
5705 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
5706 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
5708 nextWatch = watch->nextp;
5709 if (watch == smb_Directory_Watches)
5710 smb_Directory_Watches = nextWatch;
5712 lastWatch->nextp = nextWatch;
5714 /* Turn off WATCHED flag in dscp */
5715 lock_ObtainMutex(&dscp->mx);
5717 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
5719 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
5720 lock_ReleaseMutex(&dscp->mx);
5722 /* Convert to response packet */
5723 ((smb_t *) watch)->reb = 0x80;
5724 ((smb_t *) watch)->wct = 0;
5727 if (filename == NULL)
5730 nameLen = strlen(filename);
5731 parmCount = 3*4 + nameLen*2;
5732 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
5734 otherNameLen = strlen(otherFilename);
5735 oldParmCount = parmCount;
5736 parmCount += 3*4 + otherNameLen*2;
5737 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
5739 if (maxLen < parmCount)
5740 parmCount = 0; /* not enough room */
5742 parmOffset = 8*4 + 39;
5743 parmOffset += 1; /* pad to 4 */
5744 dataOffset = parmOffset + parmCount;
5748 /* Total Parameter Count */
5749 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
5750 /* Total Data Count */
5751 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
5752 /* Parameter Count */
5753 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
5754 /* Parameter Offset */
5755 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
5756 /* Parameter Displacement */
5757 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
5759 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
5761 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
5762 /* Data Displacement */
5763 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
5764 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
5765 smb_SetSMBDataLength(watch, parmCount + 1);
5767 if (parmCount != 0) {
5768 outData = smb_GetSMBData(watch, NULL);
5769 outData++; /* round to get to parmOffset */
5770 oldOutData = outData;
5771 *((DWORD *)outData) = oldParmCount; outData += 4;
5772 /* Next Entry Offset */
5773 *((DWORD *)outData) = action; outData += 4;
5775 *((DWORD *)outData) = nameLen*2; outData += 4;
5776 /* File Name Length */
5777 mbstowcs((WCHAR *)outData, filename, nameLen);
5780 outData = oldOutData + oldParmCount;
5781 *((DWORD *)outData) = 0; outData += 4;
5782 /* Next Entry Offset */
5783 *((DWORD *)outData) = otherAction; outData += 4;
5785 *((DWORD *)outData) = otherNameLen*2;
5786 outData += 4; /* File Name Length */
5787 mbstowcs((WCHAR *)outData, otherFilename,
5788 otherNameLen); /* File Name */
5793 * If filename is null, we don't know the cause of the
5794 * change notification. We return zero data (see above),
5795 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
5796 * (= 0x010C). We set the error code here by hand, without
5797 * modifying wct and bcc.
5799 if (filename == NULL) {
5800 ((smb_t *) watch)->rcls = 0x0C;
5801 ((smb_t *) watch)->reh = 0x01;
5802 ((smb_t *) watch)->errLow = 0;
5803 ((smb_t *) watch)->errHigh = 0;
5804 /* Set NT Status codes flag */
5805 ((smb_t *) watch)->flg2 |= 0x4000;
5808 smb_SendPacket(vcp, watch);
5810 smb_FreePacket(watch);
5813 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
5816 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5818 unsigned char *replyWctp;
5819 smb_packet_t *watch, *lastWatch;
5820 USHORT fid, watchtree;
5824 osi_Log0(smb_logp, "SMB3 receive NT cancel");
5826 lock_ObtainMutex(&smb_Dir_Watch_Lock);
5827 watch = smb_Directory_Watches;
5829 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
5830 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
5831 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
5832 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
5833 if (watch == smb_Directory_Watches)
5834 smb_Directory_Watches = watch->nextp;
5836 lastWatch->nextp = watch->nextp;
5837 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
5839 /* Turn off WATCHED flag in scp */
5840 fid = smb_GetSMBParm(watch, 21);
5841 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
5843 if (vcp != watch->vcp)
5844 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
5847 fidp = smb_FindFID(vcp, fid, 0);
5849 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
5851 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
5854 lock_ObtainMutex(&scp->mx);
5856 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
5858 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
5859 lock_ReleaseMutex(&scp->mx);
5860 smb_ReleaseFID(fidp);
5862 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
5865 /* assume STATUS32; return 0xC0000120 (CANCELED) */
5866 replyWctp = watch->wctp;
5870 ((smb_t *)watch)->rcls = 0x20;
5871 ((smb_t *)watch)->reh = 0x1;
5872 ((smb_t *)watch)->errLow = 0;
5873 ((smb_t *)watch)->errHigh = 0xC0;
5874 ((smb_t *)watch)->flg2 |= 0x4000;
5875 smb_SendPacket(vcp, watch);
5877 smb_ReleaseVC(watch->vcp);
5878 smb_FreePacket(watch);
5882 watch = watch->nextp;
5884 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
5891 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
5894 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
5897 smb_username_t *unp;
5899 unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
5901 lock_ObtainMutex(&unp->mx);
5902 unp->userp = cm_NewUser();
5903 lock_ReleaseMutex(&unp->mx);
5904 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
5905 osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
5907 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
5908 osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);