2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
15 #define SECURITY_WIN32
31 extern osi_hyper_t hzero;
33 smb_packet_t *smb_Directory_Watches = NULL;
34 osi_mutex_t smb_Dir_Watch_Lock;
36 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
38 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
40 /* protected by the smb_globalLock */
41 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
43 /* retrieve a held reference to a user structure corresponding to an incoming
45 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
50 uidp = smb_FindUID(vcp, inp->uid, 0);
51 if (!uidp) return NULL;
53 lock_ObtainMutex(&uidp->mx);
55 up = uidp->unp->userp;
58 lock_ReleaseMutex(&uidp->mx);
66 * Return extended attributes.
67 * Right now, we aren't using any of the "new" bits, so this looks exactly
68 * like smb_Attributes() (see smb.c).
70 unsigned long smb_ExtAttributes(cm_scache_t *scp)
74 if (scp->fileType == CM_SCACHETYPE_DIRECTORY
75 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
76 attrs = SMB_ATTR_DIRECTORY;
80 * We used to mark a file RO if it was in an RO volume, but that
81 * turns out to be impolitic in NT. See defect 10007.
84 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
86 if ((scp->unixModeBits & 0222) == 0)
87 attrs |= SMB_ATTR_READONLY; /* Read-only */
90 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
95 int smb_V3IsStarMask(char *maskp)
100 if (tc == '?' || tc == '*')
105 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
108 /* skip over null-terminated string */
109 *chainpp = inp + strlen(inp) + 1;
114 /*DEBUG do not checkin*/
115 void OutputDebugF(char * format, ...) {
120 va_start( args, format );
121 len = _vscprintf( format, args ) // _vscprintf doesn't count
122 + 3; // terminating '\0' + '\n'
123 buffer = malloc( len * sizeof(char) );
124 vsprintf( buffer, format, args );
125 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buffer));
126 strcat(buffer, "\n");
127 OutputDebugString(buffer);
131 void OutputDebugHexDump(unsigned char * buffer, int len) {
134 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
136 OutputDebugF("Hexdump length [%d]",len);
141 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
143 OutputDebugString(buf);
145 sprintf(buf,"%5x",i);
146 memset(buf+5,' ',80);
151 j = j*3 + 7 + ((j>7)?1:0);
154 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
157 j = j + 56 + ((j>7)?1:0);
159 buf[j] = (k>32 && k<127)?k:'.';
162 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
164 OutputDebugString(buf);
169 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
170 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength){
171 SECURITY_STATUS status, istatus;
172 CredHandle creds = {0,0};
174 SecBufferDesc secOut;
182 OutputDebugF("Negotiating Extended Security");
184 status = AcquireCredentialsHandle(
186 SMB_EXT_SEC_PACKAGE_NAME,
195 if (status != SEC_E_OK) {
196 /* Really bad. We return an empty security blob */
197 OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
202 secOut.pBuffers = &secTok;
203 secOut.ulVersion = SECBUFFER_VERSION;
205 secTok.BufferType = SECBUFFER_TOKEN;
207 secTok.pvBuffer = NULL;
209 ctx.dwLower = ctx.dwUpper = 0;
211 status = AcceptSecurityContext(
215 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
216 SECURITY_NETWORK_DREP,
223 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
224 OutputDebugF("Completing token...");
225 istatus = CompleteAuthToken(&ctx, &secOut);
226 if ( istatus != SEC_E_OK )
227 OutputDebugF("Token completion failed: %x", istatus);
230 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
231 if (secTok.pvBuffer) {
232 *secBlobLength = secTok.cbBuffer;
233 *secBlob = malloc( secTok.cbBuffer );
234 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
237 if ( status != SEC_E_OK )
238 OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
241 /* Discard partial security context */
242 DeleteSecurityContext(&ctx);
244 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
246 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
247 FreeCredentialsHandle(&creds);
253 struct smb_ext_context {
260 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
261 SECURITY_STATUS status, istatus;
265 SecBufferDesc secBufIn;
267 SecBufferDesc secBufOut;
270 struct smb_ext_context * secCtx = NULL;
271 struct smb_ext_context * newSecCtx = NULL;
272 void * assembledBlob = NULL;
273 int assembledBlobLength = 0;
276 OutputDebugF("In smb_AuthenticateUserExt");
279 *secBlobOutLength = 0;
281 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
282 secCtx = vcp->secCtx;
283 lock_ObtainMutex(&vcp->mx);
284 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
286 lock_ReleaseMutex(&vcp->mx);
290 OutputDebugF("Received incoming token:");
291 OutputDebugHexDump(secBlobIn,secBlobInLength);
295 OutputDebugF("Continuing with existing context.");
296 creds = secCtx->creds;
299 if (secCtx->partialToken) {
300 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
301 assembledBlob = malloc(assembledBlobLength);
302 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
303 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
306 status = AcquireCredentialsHandle(
308 SMB_EXT_SEC_PACKAGE_NAME,
317 if (status != SEC_E_OK) {
318 OutputDebugF("Can't acquire Credentials handle [%lX]", status);
319 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
327 secBufIn.cBuffers = 1;
328 secBufIn.pBuffers = &secTokIn;
329 secBufIn.ulVersion = SECBUFFER_VERSION;
331 secTokIn.BufferType = SECBUFFER_TOKEN;
333 secTokIn.cbBuffer = assembledBlobLength;
334 secTokIn.pvBuffer = assembledBlob;
336 secTokIn.cbBuffer = secBlobInLength;
337 secTokIn.pvBuffer = secBlobIn;
340 secBufOut.cBuffers = 1;
341 secBufOut.pBuffers = &secTokOut;
342 secBufOut.ulVersion = SECBUFFER_VERSION;
344 secTokOut.BufferType = SECBUFFER_TOKEN;
345 secTokOut.cbBuffer = 0;
346 secTokOut.pvBuffer = NULL;
348 status = AcceptSecurityContext(
350 ((secCtx)?&ctx:NULL),
352 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
353 SECURITY_NETWORK_DREP,
360 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
361 OutputDebugF("Completing token...");
362 istatus = CompleteAuthToken(&ctx, &secBufOut);
363 if ( istatus != SEC_E_OK )
364 OutputDebugF("Token completion failed: %lX", istatus);
367 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
368 OutputDebugF("Continue needed");
370 newSecCtx = malloc(sizeof(*newSecCtx));
372 newSecCtx->creds = creds;
373 newSecCtx->ctx = ctx;
374 newSecCtx->partialToken = NULL;
375 newSecCtx->partialTokenLen = 0;
377 lock_ObtainMutex( &vcp->mx );
378 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
379 vcp->secCtx = newSecCtx;
380 lock_ReleaseMutex( &vcp->mx );
382 code = CM_ERROR_GSSCONTINUE;
385 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
386 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
387 secTokOut.pvBuffer) {
388 OutputDebugF("Need to send token back to client");
390 *secBlobOutLength = secTokOut.cbBuffer;
391 *secBlobOut = malloc(secTokOut.cbBuffer);
392 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
394 OutputDebugF("Outgoing token:");
395 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
396 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
397 OutputDebugF("Incomplete message");
399 newSecCtx = malloc(sizeof(*newSecCtx));
401 newSecCtx->creds = creds;
402 newSecCtx->ctx = ctx;
403 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
404 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
405 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
407 lock_ObtainMutex( &vcp->mx );
408 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
409 vcp->secCtx = newSecCtx;
410 lock_ReleaseMutex( &vcp->mx );
412 code = CM_ERROR_GSSCONTINUE;
415 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
417 SecPkgContext_Names names;
419 OutputDebugF("Authentication completed");
420 OutputDebugF("Returned flags : [%lX]", flags);
422 if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
423 OutputDebugF("Received name [%s]", names.sUserName);
424 strcpy(usern, names.sUserName);
425 strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
426 FreeContextBuffer(names.sUserName);
428 /* Force the user to retry if the context is invalid */
429 OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
430 code = CM_ERROR_BADPASSWORD;
434 case SEC_E_INVALID_TOKEN:
435 OutputDebugF("Returning bad password :: INVALID_TOKEN");
437 case SEC_E_INVALID_HANDLE:
438 OutputDebugF("Returning bad password :: INVALID_HANDLE");
440 case SEC_E_LOGON_DENIED:
441 OutputDebugF("Returning bad password :: LOGON_DENIED");
443 case SEC_E_UNKNOWN_CREDENTIALS:
444 OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
446 case SEC_E_NO_CREDENTIALS:
447 OutputDebugF("Returning bad password :: NO_CREDENTIALS");
449 case SEC_E_CONTEXT_EXPIRED:
450 OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
452 case SEC_E_INCOMPLETE_CREDENTIALS:
453 OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
455 case SEC_E_WRONG_PRINCIPAL:
456 OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
458 case SEC_E_TIME_SKEW:
459 OutputDebugF("Returning bad password :: TIME_SKEW");
462 OutputDebugF("Returning bad password :: Status == %lX", status);
464 code = CM_ERROR_BADPASSWORD;
468 if (secCtx->partialToken) free(secCtx->partialToken);
476 if (secTokOut.pvBuffer)
477 FreeContextBuffer(secTokOut.pvBuffer);
479 if (code != CM_ERROR_GSSCONTINUE) {
480 DeleteSecurityContext(&ctx);
481 FreeCredentialsHandle(&creds);
489 #define P_RESP_LEN 128
491 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
492 So put stuff in a struct. */
493 struct Lm20AuthBlob {
494 MSV1_0_LM20_LOGON lmlogon;
495 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
496 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
497 WCHAR accountNameW[P_LEN];
498 WCHAR primaryDomainW[P_LEN];
499 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
500 TOKEN_GROUPS tgroups;
501 TOKEN_SOURCE tsource;
504 long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength) {
507 struct Lm20AuthBlob lmAuth;
508 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
509 QUOTA_LIMITS quotaLimits;
511 ULONG lmprofilepSize;
515 OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
516 OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
518 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
519 OutputDebugF("ciPwdLength or csPwdLength is too long");
520 return CM_ERROR_BADPASSWORD;
523 memset(&lmAuth,0,sizeof(lmAuth));
525 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
527 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
528 mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
529 lmAuth.lmlogon.LogonDomainName.Length = wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR);
530 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
532 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
533 mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
534 lmAuth.lmlogon.UserName.Length = wcslen(lmAuth.accountNameW) * sizeof(WCHAR);
535 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
537 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
538 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
539 size = MAX_COMPUTERNAME_LENGTH + 1;
540 GetComputerNameW(lmAuth.workstationW, &size);
541 lmAuth.lmlogon.Workstation.Length = wcslen(lmAuth.workstationW) * sizeof(WCHAR);
543 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
545 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
546 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
547 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
548 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
550 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
551 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
552 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
553 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
555 lmAuth.lmlogon.ParameterControl = 0;
557 lmAuth.tgroups.GroupCount = 0;
558 lmAuth.tgroups.Groups[0].Sid = NULL;
559 lmAuth.tgroups.Groups[0].Attributes = 0;
561 lmAuth.tsource.SourceIdentifier.HighPart = 0;
562 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD) vcp;
563 strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
581 OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
582 OutputDebugF("Extended status is 0x%lX", ntsEx);
584 if (nts == ERROR_SUCCESS) {
586 LsaFreeReturnBuffer(lmprofilep);
587 CloseHandle(lmToken);
591 if (nts == 0xC000015BL)
592 return CM_ERROR_BADLOGONTYPE;
593 else /* our catchall is a bad password though we could be more specific */
594 return CM_ERROR_BADPASSWORD;
598 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
599 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName) {
604 /* check if we have sane input */
605 if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
608 /* we could get : [accountName][domainName]
614 atsign = strchr(accountName, '@');
616 if (atsign) /* [user@domain][] -> [user@domain][domain] */
621 /* if for some reason the client doesn't know what domain to use,
622 it will either return an empty string or a '?' */
623 if (!domain[0] || domain[0] == '?')
624 /* Empty domains and empty usernames are usually sent from tokenless contexts.
625 This way such logins will get an empty username (easy to check). I don't know
626 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
627 strcpy(usern,accountName);
629 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
630 strcpy(usern,domain);
633 strncat(usern,accountName,atsign - accountName);
635 strcat(usern,accountName);
643 /* When using SMB auth, all SMB sessions have to pass through here first to
644 * authenticate the user.
645 * Caveat: If not use the SMB auth the protocol does not require sending a
646 * session setup packet, which means that we can't rely on a UID in subsequent
647 * packets. Though in practice we get one anyway.
649 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
653 unsigned short newUid;
654 unsigned long caps = 0;
659 char usern[SMB_MAX_USERNAME_LENGTH];
660 char *secBlobOut = NULL;
661 int secBlobOutLength = 0;
663 /* Check for bad conns */
664 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
665 return CM_ERROR_REMOTECONN;
667 if (vcp->flags & SMB_VCFLAG_USENT) {
668 if (smb_authType == SMB_AUTH_EXTENDED) {
669 /* extended authentication */
673 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
674 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
677 secBlobInLength = smb_GetSMBParm(inp, 7);
678 secBlobIn = smb_GetSMBData(inp, NULL);
680 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
682 if (code == CM_ERROR_GSSCONTINUE) {
683 smb_SetSMBParm(outp, 2, 0);
684 smb_SetSMBParm(outp, 3, secBlobOutLength);
685 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
686 tp = smb_GetSMBData(outp, NULL);
687 if (secBlobOutLength) {
688 memcpy(tp, secBlobOut, secBlobOutLength);
690 tp += secBlobOutLength;
692 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
693 tp += smb_ServerOSLength;
694 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
695 tp += smb_ServerLanManagerLength;
696 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
697 tp += smb_ServerDomainNameLength;
700 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
702 unsigned ciPwdLength, csPwdLength;
708 /* TODO: parse for extended auth as well */
709 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
710 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
712 tp = smb_GetSMBData(inp, &datalen);
714 OutputDebugF("Session packet data size [%d]",datalen);
721 accountName = smb_ParseString(tp, &tp);
722 primaryDomain = smb_ParseString(tp, NULL);
724 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
725 /* shouldn't happen */
726 code = CM_ERROR_BADSMB;
727 goto after_read_packet;
730 /* capabilities are only valid for first session packet */
731 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
732 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
735 if (smb_authType == SMB_AUTH_NTLM) {
736 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
740 unsigned ciPwdLength;
745 ciPwdLength = smb_GetSMBParm(inp, 7);
746 tp = smb_GetSMBData(inp, NULL);
750 accountName = smb_ParseString(tp, &tp);
751 primaryDomain = smb_ParseString(tp, NULL);
753 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
754 /* shouldn't happen */
755 code = CM_ERROR_BADSMB;
756 goto after_read_packet;
759 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
762 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
763 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
768 /* note down that we received a session setup X and set the capabilities flag */
769 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
770 lock_ObtainMutex(&vcp->mx);
771 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
772 /* for the moment we can only deal with NTSTATUS */
773 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
774 vcp->flags |= SMB_VCFLAG_STATUS32;
776 lock_ReleaseMutex(&vcp->mx);
779 /* code would be non-zero if there was an authentication failure.
780 Ideally we would like to invalidate the uid for this session or break
781 early to avoid accidently stealing someone else's tokens. */
787 OutputDebugF("Received username=[%s]", usern);
789 /* On Windows 2000, this function appears to be called more often than
790 it is expected to be called. This resulted in multiple smb_user_t
791 records existing all for the same user session which results in all
792 of the users tokens disappearing.
794 To avoid this problem, we look for an existing smb_user_t record
795 based on the users name, and use that one if we find it.
798 uidp = smb_FindUserByNameThisSession(vcp, usern);
799 if (uidp) { /* already there, so don't create a new one */
802 newUid = (unsigned short)uidp->userID; /* For some reason these are different types!*/
803 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"FindUserByName:Lana[%d],lsn[%d],userid[%d],name[%s]",vcp->lana,vcp->lsn,newUid,osi_LogSaveString(smb_logp, usern));
804 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
805 smb_ReleaseUID(uidp);
808 /* do a global search for the username/machine name pair */
809 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
811 /* Create a new UID and cm_user_t structure */
814 userp = cm_NewUser();
815 lock_ObtainMutex(&vcp->mx);
816 if (!vcp->uidCounter)
817 vcp->uidCounter++; /* handle unlikely wraparounds */
818 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
819 lock_ReleaseMutex(&vcp->mx);
821 /* Create a new smb_user_t structure and connect them up */
822 lock_ObtainMutex(&unp->mx);
824 lock_ReleaseMutex(&unp->mx);
826 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
827 lock_ObtainMutex(&uidp->mx);
829 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d],TicketKTCName[%s]",(int)vcp,vcp->lana,vcp->lsn,newUid,osi_LogSaveString(smb_logp, usern));
830 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
831 lock_ReleaseMutex(&uidp->mx);
832 smb_ReleaseUID(uidp);
835 /* Return UID to the client */
836 ((smb_t *)outp)->uid = newUid;
837 /* Also to the next chained message */
838 ((smb_t *)inp)->uid = newUid;
840 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
841 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
843 smb_SetSMBParm(outp, 2, 0);
845 if (vcp->flags & SMB_VCFLAG_USENT) {
846 if (smb_authType == SMB_AUTH_EXTENDED) {
847 smb_SetSMBParm(outp, 3, secBlobOutLength);
848 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
849 tp = smb_GetSMBData(outp, NULL);
850 if (secBlobOutLength) {
851 memcpy(tp, secBlobOut, secBlobOutLength);
853 tp += secBlobOutLength;
855 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
856 tp += smb_ServerOSLength;
857 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
858 tp += smb_ServerLanManagerLength;
859 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
860 tp += smb_ServerDomainNameLength;
862 smb_SetSMBDataLength(outp, 0);
865 if (smb_authType == SMB_AUTH_EXTENDED) {
866 smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
867 tp = smb_GetSMBData(outp, NULL);
868 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
869 tp += smb_ServerOSLength;
870 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
871 tp += smb_ServerLanManagerLength;
872 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
873 tp += smb_ServerDomainNameLength;
875 smb_SetSMBDataLength(outp, 0);
882 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
886 /* don't get tokens from this VC */
887 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
889 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
891 /* find the tree and free it */
892 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
893 /* TODO: smb_ReleaseUID() ? */
895 char *s1 = NULL, *s2 = NULL;
897 if (s2 == NULL) s2 = " ";
898 if (s1 == NULL) {s1 = s2; s2 = " ";}
900 osi_Log4(smb_logp, "SMB3 user logoffX uid %d name %s%s%s", uidp->userID,
901 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "), s1, s2);
903 lock_ObtainMutex(&uidp->mx);
904 uidp->flags |= SMB_USERFLAG_DELETE;
906 * it doesn't get deleted right away
907 * because the vcp points to it
909 lock_ReleaseMutex(&uidp->mx);
912 osi_Log0(smb_logp, "SMB3 user logoffX");
914 smb_SetSMBDataLength(outp, 0);
918 #define SMB_SUPPORT_SEARCH_BITS 0x0001
920 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
924 unsigned short newTid;
935 osi_Log0(smb_logp, "SMB3 receive tree connect");
937 /* parse input parameters */
938 tp = smb_GetSMBData(inp, NULL);
939 passwordp = smb_ParseString(tp, &tp);
940 pathp = smb_ParseString(tp, &tp);
941 servicep = smb_ParseString(tp, &tp);
943 tp = strrchr(pathp, '\\');
945 return CM_ERROR_BADSMB;
947 strcpy(shareName, tp+1);
949 osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
950 osi_LogSaveString(smb_logp, pathp),
951 osi_LogSaveString(smb_logp, shareName));
953 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
955 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
958 return CM_ERROR_NOIPC;
962 userp = smb_GetUser(vcp, inp);
964 lock_ObtainMutex(&vcp->mx);
965 newTid = vcp->tidCounter++;
966 lock_ReleaseMutex(&vcp->mx);
968 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
971 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
972 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
974 smb_ReleaseUID(uidp);
976 smb_ReleaseTID(tidp);
977 return CM_ERROR_BADSHARENAME;
980 if (vcp->flags & SMB_VCFLAG_USENT)
982 int policy = smb_FindShareCSCPolicy(shareName);
983 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS | (policy << 2));
986 smb_SetSMBParm(outp, 2, 0);
990 lock_ObtainMutex(&tidp->mx);
992 tidp->pathname = sharePath;
993 if(ipc) tidp->flags |= SMB_TIDFLAG_IPC;
994 lock_ReleaseMutex(&tidp->mx);
995 smb_ReleaseTID(tidp);
997 ((smb_t *)outp)->tid = newTid;
998 ((smb_t *)inp)->tid = newTid;
999 tp = smb_GetSMBData(outp, NULL);
1004 smb_SetSMBDataLength(outp, 3);
1007 smb_SetSMBDataLength(outp, 4);
1010 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1014 /* must be called with global tran lock held */
1015 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1017 smb_tran2Packet_t *tp;
1020 smbp = (smb_t *) inp->data;
1021 for(tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1022 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1028 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1029 int totalParms, int totalData)
1031 smb_tran2Packet_t *tp;
1034 smbp = (smb_t *) inp->data;
1035 tp = malloc(sizeof(*tp));
1036 memset(tp, 0, sizeof(*tp));
1039 tp->curData = tp->curParms = 0;
1040 tp->totalData = totalData;
1041 tp->totalParms = totalParms;
1042 tp->tid = smbp->tid;
1043 tp->mid = smbp->mid;
1044 tp->uid = smbp->uid;
1045 tp->pid = smbp->pid;
1046 tp->res[0] = smbp->res[0];
1047 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1048 if (totalParms != 0)
1049 tp->parmsp = malloc(totalParms);
1051 tp->datap = malloc(totalData);
1052 if (smbp->com == 0x25 || smbp->com == 0x26)
1055 tp->opcode = smb_GetSMBParm(inp, 14);
1058 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1062 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1063 smb_tran2Packet_t *inp, smb_packet_t *outp,
1064 int totalParms, int totalData)
1066 smb_tran2Packet_t *tp;
1067 unsigned short parmOffset;
1068 unsigned short dataOffset;
1069 unsigned short dataAlign;
1071 tp = malloc(sizeof(*tp));
1072 memset(tp, 0, sizeof(*tp));
1074 tp->curData = tp->curParms = 0;
1075 tp->totalData = totalData;
1076 tp->totalParms = totalParms;
1077 tp->oldTotalParms = totalParms;
1082 tp->res[0] = inp->res[0];
1083 tp->opcode = inp->opcode;
1087 * We calculate where the parameters and data will start.
1088 * This calculation must parallel the calculation in
1089 * smb_SendTran2Packet.
1092 parmOffset = 10*2 + 35;
1093 parmOffset++; /* round to even */
1094 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1096 dataOffset = parmOffset + totalParms;
1097 dataAlign = dataOffset & 2; /* quad-align */
1098 dataOffset += dataAlign;
1099 tp->datap = outp->data + dataOffset;
1104 /* free a tran2 packet; must be called with smb_globalLock held */
1105 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1107 if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
1108 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1117 /* called with a VC, an input packet to respond to, and an error code.
1118 * sends an error response.
1120 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1121 smb_packet_t *tp, long code)
1124 unsigned short errCode;
1125 unsigned char errClass;
1126 unsigned long NTStatus;
1128 if (vcp->flags & SMB_VCFLAG_STATUS32)
1129 smb_MapNTError(code, &NTStatus);
1131 smb_MapCoreError(code, vcp, &errCode, &errClass);
1133 smb_FormatResponsePacket(vcp, NULL, tp);
1134 smbp = (smb_t *) tp;
1136 /* We can handle long names */
1137 if (vcp->flags & SMB_VCFLAG_USENT)
1138 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
1140 /* now copy important fields from the tran 2 packet */
1141 smbp->com = t2p->com;
1142 smbp->tid = t2p->tid;
1143 smbp->mid = t2p->mid;
1144 smbp->pid = t2p->pid;
1145 smbp->uid = t2p->uid;
1146 smbp->res[0] = t2p->res[0];
1147 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1148 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1149 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1150 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1151 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1152 smbp->flg2 |= 0x4000;
1155 smbp->rcls = errClass;
1156 smbp->errLow = (unsigned char) (errCode & 0xff);
1157 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1161 smb_SendPacket(vcp, tp);
1164 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1167 unsigned short parmOffset;
1168 unsigned short dataOffset;
1169 unsigned short totalLength;
1170 unsigned short dataAlign;
1173 smb_FormatResponsePacket(vcp, NULL, tp);
1174 smbp = (smb_t *) tp;
1176 /* We can handle long names */
1177 if (vcp->flags & SMB_VCFLAG_USENT)
1178 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
1180 /* now copy important fields from the tran 2 packet */
1181 smbp->com = t2p->com;
1182 smbp->tid = t2p->tid;
1183 smbp->mid = t2p->mid;
1184 smbp->pid = t2p->pid;
1185 smbp->uid = t2p->uid;
1186 smbp->res[0] = t2p->res[0];
1188 totalLength = 1 + t2p->totalData + t2p->totalParms;
1190 /* now add the core parameters (tran2 info) to the packet */
1191 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1192 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1193 smb_SetSMBParm(tp, 2, 0); /* reserved */
1194 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1195 parmOffset = 10*2 + 35; /* parm offset in packet */
1196 parmOffset++; /* round to even */
1197 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1198 * hdr, bcc and wct */
1199 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1200 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1201 dataOffset = parmOffset + t2p->oldTotalParms;
1202 dataAlign = dataOffset & 2; /* quad-align */
1203 dataOffset += dataAlign;
1204 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1205 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1206 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1209 datap = smb_GetSMBData(tp, NULL);
1210 *datap++ = 0; /* we rounded to even */
1212 totalLength += dataAlign;
1213 smb_SetSMBDataLength(tp, totalLength);
1215 /* next, send the datagram */
1216 smb_SendPacket(vcp, tp);
1219 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1221 smb_tran2Packet_t *asp;
1234 /* We sometimes see 0 word count. What to do? */
1235 if (*inp->wctp == 0) {
1240 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1242 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1243 ptbuf[0] = "Transaction2 word count = 0";
1244 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1245 1, inp->ncb_length, ptbuf, inp);
1246 DeregisterEventSource(h);
1248 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1251 smb_SetSMBDataLength(outp, 0);
1252 smb_SendPacket(vcp, outp);
1256 totalParms = smb_GetSMBParm(inp, 0);
1257 totalData = smb_GetSMBParm(inp, 1);
1259 firstPacket = (inp->inCom == 0x25);
1261 /* find the packet we're reassembling */
1262 lock_ObtainWrite(&smb_globalLock);
1263 asp = smb_FindTran2Packet(vcp, inp);
1265 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1267 lock_ReleaseWrite(&smb_globalLock);
1269 /* now merge in this latest packet; start by looking up offsets */
1271 parmDisp = dataDisp = 0;
1272 parmOffset = smb_GetSMBParm(inp, 10);
1273 dataOffset = smb_GetSMBParm(inp, 12);
1274 parmCount = smb_GetSMBParm(inp, 9);
1275 dataCount = smb_GetSMBParm(inp, 11);
1276 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1277 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1279 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1280 totalData, dataCount, asp->maxReturnData);
1283 parmDisp = smb_GetSMBParm(inp, 4);
1284 parmOffset = smb_GetSMBParm(inp, 3);
1285 dataDisp = smb_GetSMBParm(inp, 7);
1286 dataOffset = smb_GetSMBParm(inp, 6);
1287 parmCount = smb_GetSMBParm(inp, 2);
1288 dataCount = smb_GetSMBParm(inp, 5);
1290 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1291 parmCount, dataCount);
1294 /* now copy the parms and data */
1295 if ( parmCount != 0 )
1297 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1299 if ( dataCount != 0 ) {
1300 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1303 /* account for new bytes */
1304 asp->curData += dataCount;
1305 asp->curParms += parmCount;
1307 /* finally, if we're done, remove the packet from the queue and dispatch it */
1308 if (asp->totalData <= asp->curData && asp->totalParms <= asp->curParms) {
1309 /* we've received it all */
1310 lock_ObtainWrite(&smb_globalLock);
1311 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1312 lock_ReleaseWrite(&smb_globalLock);
1314 /* now dispatch it */
1315 rapOp = asp->parmsp[0];
1317 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1318 osi_LogEvent("AFS-Dispatch-RAP[%s]",myCrt_RapDispatch(rapOp),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1319 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%x] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1320 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1323 osi_LogEvent("AFS-Dispatch-RAP [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1324 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1325 code = CM_ERROR_BADOP;
1328 /* if an error is returned, we're supposed to send an error packet,
1329 * otherwise the dispatched function already did the data sending.
1330 * We give dispatched proc the responsibility since it knows how much
1331 * space to allocate.
1334 smb_SendTran2Error(vcp, asp, outp, code);
1337 /* free the input tran 2 packet */
1338 lock_ObtainWrite(&smb_globalLock);
1339 smb_FreeTran2Packet(asp);
1340 lock_ReleaseWrite(&smb_globalLock);
1342 else if (firstPacket) {
1343 /* the first packet in a multi-packet request, we need to send an
1344 * ack to get more data.
1346 smb_SetSMBDataLength(outp, 0);
1347 smb_SendPacket(vcp, outp);
1353 /* ANSI versions. The unicode versions support arbitrary length
1354 share names, but we don't support unicode yet. */
1356 typedef struct smb_rap_share_info_0 {
1357 char shi0_netname[13];
1358 } smb_rap_share_info_0_t;
1360 typedef struct smb_rap_share_info_1 {
1361 char shi1_netname[13];
1364 DWORD shi1_remark; /* char *shi1_remark; data offset */
1365 } smb_rap_share_info_1_t;
1367 typedef struct smb_rap_share_info_2 {
1368 char shi2_netname[13];
1370 unsigned short shi2_type;
1371 DWORD shi2_remark; /* char *shi2_remark; data offset */
1372 unsigned short shi2_permissions;
1373 unsigned short shi2_max_uses;
1374 unsigned short shi2_current_uses;
1375 DWORD shi2_path; /* char *shi2_path; data offset */
1376 unsigned short shi2_passwd[9];
1377 unsigned short shi2_pad2;
1378 } smb_rap_share_info_2_t;
1380 #define SMB_RAP_MAX_SHARES 512
1382 typedef struct smb_rap_share_list {
1385 smb_rap_share_info_0_t * shares;
1386 } smb_rap_share_list_t;
1388 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1389 smb_rap_share_list_t * sp;
1394 if(name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1395 return 0; /* skip over '.' and '..' */
1397 sp = (smb_rap_share_list_t *) vrockp;
1399 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1400 sp->shares[sp->cShare].shi0_netname[12] = 0;
1404 if(sp->cShare >= sp->maxShares)
1405 return CM_ERROR_STOPNOW;
1410 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1412 smb_tran2Packet_t *outp;
1413 unsigned short * tp;
1417 int outParmsTotal; /* total parameter bytes */
1418 int outDataTotal; /* total data bytes */
1426 HKEY hkSubmount = NULL;
1427 smb_rap_share_info_1_t * shares;
1430 char thisShare[256];
1433 smb_rap_share_list_t rootShares;
1438 tp = p->parmsp + 1; /* skip over function number (always 0) */
1439 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1440 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1444 if(infoLevel != 1) {
1445 return CM_ERROR_INVAL;
1448 /* first figure out how many shares there are */
1449 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1450 KEY_QUERY_VALUE, &hkParam);
1451 if (rv == ERROR_SUCCESS) {
1452 len = sizeof(allSubmount);
1453 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1454 (BYTE *) &allSubmount, &len);
1455 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1458 RegCloseKey (hkParam);
1461 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1462 0, KEY_QUERY_VALUE, &hkSubmount);
1463 if (rv == ERROR_SUCCESS) {
1464 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1465 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1466 if (rv != ERROR_SUCCESS)
1472 /* fetch the root shares */
1473 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1474 rootShares.cShare = 0;
1475 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1479 userp = smb_GetTran2User(vcp,p);
1481 thyper.HighPart = 0;
1484 cm_HoldSCache(cm_rootSCachep);
1485 cm_ApplyDir(cm_rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1486 cm_ReleaseSCache(cm_rootSCachep);
1488 cm_ReleaseUser(userp);
1490 nShares = rootShares.cShare + nRegShares + allSubmount;
1492 #define REMARK_LEN 1
1493 outParmsTotal = 8; /* 4 dwords */
1494 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1495 if(outDataTotal > bufsize) {
1496 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1497 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1500 nSharesRet = nShares;
1503 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1505 /* now for the submounts */
1506 shares = (smb_rap_share_info_1_t *) outp->datap;
1507 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1509 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1512 strcpy( shares[cshare].shi1_netname, "all" );
1513 shares[cshare].shi1_remark = cstrp - outp->datap;
1514 /* type and pad are zero already */
1520 for(i=0; i < nRegShares && cshare < nSharesRet; i++) {
1521 len = sizeof(thisShare);
1522 rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1523 if(rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1524 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1525 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1526 shares[cshare].shi1_remark = cstrp - outp->datap;
1531 nShares--; /* uncount key */
1534 RegCloseKey(hkSubmount);
1537 nonrootShares = cshare;
1539 for(i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1540 /* in case there are collisions with submounts, submounts have higher priority */
1541 for(j=0; j < nonrootShares; j++)
1542 if(!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1545 if(j < nonrootShares) {
1546 nShares--; /* uncount */
1550 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1551 shares[cshare].shi1_remark = cstrp - outp->datap;
1556 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1557 outp->parmsp[1] = 0;
1558 outp->parmsp[2] = cshare;
1559 outp->parmsp[3] = nShares;
1561 outp->totalData = cstrp - outp->datap;
1562 outp->totalParms = outParmsTotal;
1564 smb_SendTran2Packet(vcp, outp, op);
1565 smb_FreeTran2Packet(outp);
1567 free(rootShares.shares);
1572 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1574 smb_tran2Packet_t *outp;
1575 unsigned short * tp;
1577 BOOL shareFound = FALSE;
1578 unsigned short infoLevel;
1579 unsigned short bufsize;
1589 tp = p->parmsp + 1; /* skip over function number (always 1) */
1590 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1591 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1592 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1599 totalData = sizeof(smb_rap_share_info_0_t);
1600 else if(infoLevel == 1)
1601 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1602 else if(infoLevel == 2)
1603 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1605 return CM_ERROR_INVAL;
1607 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1609 if(!stricmp(shareName,"all")) {
1610 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1611 KEY_QUERY_VALUE, &hkParam);
1612 if (rv == ERROR_SUCCESS) {
1613 len = sizeof(allSubmount);
1614 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1615 (BYTE *) &allSubmount, &len);
1616 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1619 RegCloseKey (hkParam);
1626 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts", 0,
1627 KEY_QUERY_VALUE, &hkSubmount);
1628 if(rv == ERROR_SUCCESS) {
1629 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1630 if(rv == ERROR_SUCCESS) {
1633 RegCloseKey(hkSubmount);
1638 smb_FreeTran2Packet(outp);
1639 return CM_ERROR_BADSHARENAME;
1642 memset(outp->datap, 0, totalData);
1644 outp->parmsp[0] = 0;
1645 outp->parmsp[1] = 0;
1646 outp->parmsp[2] = totalData;
1648 if(infoLevel == 0) {
1649 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1650 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1651 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1652 } else if(infoLevel == 1) {
1653 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1654 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1655 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1656 info->shi1_remark = ((unsigned char *) (info + 1)) - outp->datap;
1657 /* type and pad are already zero */
1658 } else { /* infoLevel==2 */
1659 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1660 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1661 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1662 info->shi2_remark = ((unsigned char *) (info + 1)) - outp->datap;
1663 info->shi2_permissions = ACCESS_ALL;
1664 info->shi2_max_uses = (unsigned short) -1;
1665 info->shi2_path = 1 + (((unsigned char *) (info + 1)) - outp->datap);
1668 outp->totalData = totalData;
1669 outp->totalParms = totalParam;
1671 smb_SendTran2Packet(vcp, outp, op);
1672 smb_FreeTran2Packet(outp);
1677 typedef struct smb_rap_wksta_info_10 {
1678 DWORD wki10_computername; /*char *wki10_computername;*/
1679 DWORD wki10_username; /* char *wki10_username; */
1680 DWORD wki10_langroup; /* char *wki10_langroup;*/
1681 unsigned char wki10_ver_major;
1682 unsigned char wki10_ver_minor;
1683 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1684 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1685 } smb_rap_wksta_info_10_t;
1688 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1690 smb_tran2Packet_t *outp;
1694 unsigned short * tp;
1697 smb_rap_wksta_info_10_t * info;
1701 tp = p->parmsp + 1; /* Skip over function number */
1702 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1703 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1707 if(infoLevel != 10) {
1708 return CM_ERROR_INVAL;
1714 totalData = sizeof(*info) + /* info */
1715 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1716 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1717 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1718 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1719 1; /* wki10_oth_domains (null)*/
1721 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1723 memset(outp->parmsp,0,totalParams);
1724 memset(outp->datap,0,totalData);
1726 info = (smb_rap_wksta_info_10_t *) outp->datap;
1727 cstrp = (char *) (info + 1);
1729 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1730 strcpy(cstrp, smb_localNamep);
1731 cstrp += strlen(cstrp) + 1;
1733 info->wki10_username = (DWORD) (cstrp - outp->datap);
1734 uidp = smb_FindUID(vcp, p->uid, 0);
1736 lock_ObtainMutex(&uidp->mx);
1737 if(uidp->unp && uidp->unp->name)
1738 strcpy(cstrp, uidp->unp->name);
1739 lock_ReleaseMutex(&uidp->mx);
1740 smb_ReleaseUID(uidp);
1742 cstrp += strlen(cstrp) + 1;
1744 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1745 strcpy(cstrp, "WORKGROUP");
1746 cstrp += strlen(cstrp) + 1;
1748 /* TODO: Not sure what values these should take, but these work */
1749 info->wki10_ver_major = 5;
1750 info->wki10_ver_minor = 1;
1752 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1753 strcpy(cstrp, smb_ServerDomainName);
1754 cstrp += strlen(cstrp) + 1;
1756 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1757 cstrp ++; /* no other domains */
1759 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1760 outp->parmsp[2] = outp->totalData;
1761 outp->totalParms = totalParams;
1763 smb_SendTran2Packet(vcp,outp,op);
1764 smb_FreeTran2Packet(outp);
1769 typedef struct smb_rap_server_info_0 {
1771 } smb_rap_server_info_0_t;
1773 typedef struct smb_rap_server_info_1 {
1775 char sv1_version_major;
1776 char sv1_version_minor;
1777 unsigned long sv1_type;
1778 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1779 } smb_rap_server_info_1_t;
1781 char smb_ServerComment[] = "OpenAFS Client";
1782 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1784 #define SMB_SV_TYPE_SERVER 0x00000002L
1785 #define SMB_SV_TYPE_NT 0x00001000L
1786 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1788 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1790 smb_tran2Packet_t *outp;
1794 unsigned short * tp;
1797 smb_rap_server_info_0_t * info0;
1798 smb_rap_server_info_1_t * info1;
1801 tp = p->parmsp + 1; /* Skip over function number */
1802 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1803 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1807 if(infoLevel != 0 && infoLevel != 1) {
1808 return CM_ERROR_INVAL;
1814 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1815 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1817 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1819 memset(outp->parmsp,0,totalParams);
1820 memset(outp->datap,0,totalData);
1822 if(infoLevel == 0) {
1823 info0 = (smb_rap_server_info_0_t *) outp->datap;
1824 cstrp = (char *) (info0 + 1);
1825 strcpy(info0->sv0_name, "AFS");
1826 } else { /* infoLevel == 1 */
1827 info1 = (smb_rap_server_info_1_t *) outp->datap;
1828 cstrp = (char *) (info1 + 1);
1829 strcpy(info1->sv1_name, "AFS");
1832 SMB_SV_TYPE_SERVER |
1834 SMB_SV_TYPE_SERVER_NT;
1836 info1->sv1_version_major = 5;
1837 info1->sv1_version_minor = 1;
1838 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1840 strcpy(cstrp, smb_ServerComment);
1842 cstrp += smb_ServerCommentLen;
1845 totalData = cstrp - outp->datap;
1846 outp->totalData = min(bufsize,totalData); /* actual data size */
1847 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1848 outp->parmsp[2] = totalData;
1849 outp->totalParms = totalParams;
1851 smb_SendTran2Packet(vcp,outp,op);
1852 smb_FreeTran2Packet(outp);
1857 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1859 smb_tran2Packet_t *asp;
1871 /* We sometimes see 0 word count. What to do? */
1872 if (*inp->wctp == 0) {
1877 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1879 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1880 ptbuf[0] = "Transaction2 word count = 0";
1881 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1882 1, inp->ncb_length, ptbuf, inp);
1883 DeregisterEventSource(h);
1885 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1888 smb_SetSMBDataLength(outp, 0);
1889 smb_SendPacket(vcp, outp);
1893 totalParms = smb_GetSMBParm(inp, 0);
1894 totalData = smb_GetSMBParm(inp, 1);
1896 firstPacket = (inp->inCom == 0x32);
1898 /* find the packet we're reassembling */
1899 lock_ObtainWrite(&smb_globalLock);
1900 asp = smb_FindTran2Packet(vcp, inp);
1902 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1904 lock_ReleaseWrite(&smb_globalLock);
1906 /* now merge in this latest packet; start by looking up offsets */
1908 parmDisp = dataDisp = 0;
1909 parmOffset = smb_GetSMBParm(inp, 10);
1910 dataOffset = smb_GetSMBParm(inp, 12);
1911 parmCount = smb_GetSMBParm(inp, 9);
1912 dataCount = smb_GetSMBParm(inp, 11);
1913 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1914 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1916 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1917 totalData, dataCount, asp->maxReturnData);
1920 parmDisp = smb_GetSMBParm(inp, 4);
1921 parmOffset = smb_GetSMBParm(inp, 3);
1922 dataDisp = smb_GetSMBParm(inp, 7);
1923 dataOffset = smb_GetSMBParm(inp, 6);
1924 parmCount = smb_GetSMBParm(inp, 2);
1925 dataCount = smb_GetSMBParm(inp, 5);
1927 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1928 parmCount, dataCount);
1931 /* now copy the parms and data */
1932 if ( parmCount != 0 )
1934 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1936 if ( dataCount != 0 ) {
1937 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1940 /* account for new bytes */
1941 asp->curData += dataCount;
1942 asp->curParms += parmCount;
1944 /* finally, if we're done, remove the packet from the queue and dispatch it */
1945 if (asp->totalData <= asp->curData && asp->totalParms <= asp->curParms) {
1946 /* we've received it all */
1947 lock_ObtainWrite(&smb_globalLock);
1948 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1949 lock_ReleaseWrite(&smb_globalLock);
1951 /* now dispatch it */
1952 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
1953 osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1954 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
1955 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
1958 osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1959 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1960 code = CM_ERROR_BADOP;
1963 /* if an error is returned, we're supposed to send an error packet,
1964 * otherwise the dispatched function already did the data sending.
1965 * We give dispatched proc the responsibility since it knows how much
1966 * space to allocate.
1969 smb_SendTran2Error(vcp, asp, outp, code);
1972 /* free the input tran 2 packet */
1973 lock_ObtainWrite(&smb_globalLock);
1974 smb_FreeTran2Packet(asp);
1975 lock_ReleaseWrite(&smb_globalLock);
1977 else if (firstPacket) {
1978 /* the first packet in a multi-packet request, we need to send an
1979 * ack to get more data.
1981 smb_SetSMBDataLength(outp, 0);
1982 smb_SendPacket(vcp, outp);
1988 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1991 smb_tran2Packet_t *outp;
1996 cm_scache_t *dscp; /* dir we're dealing with */
1997 cm_scache_t *scp; /* file we're creating */
1999 int initialModeBits;
2009 int parmSlot; /* which parm we're dealing with */
2010 long returnEALength;
2018 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2019 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2021 openFun = p->parmsp[6]; /* open function */
2022 excl = ((openFun & 3) == 0);
2023 trunc = ((openFun & 3) == 2); /* truncate it */
2024 openMode = (p->parmsp[1] & 0x7);
2025 openAction = 0; /* tracks what we did */
2027 attributes = p->parmsp[3];
2028 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2030 /* compute initial mode bits based on read-only flag in attributes */
2031 initialModeBits = 0666;
2032 if (attributes & 1) initialModeBits &= ~0222;
2034 pathp = (char *) (&p->parmsp[14]);
2036 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2038 spacep = cm_GetSpace();
2039 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2041 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2042 /* special case magic file name for receiving IOCTL requests
2043 * (since IOCTL calls themselves aren't getting through).
2045 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2046 smb_SetupIoctlFid(fidp, spacep);
2048 /* copy out remainder of the parms */
2050 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2052 outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
2053 outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
2054 outp->parmsp[parmSlot] = 0; parmSlot++;
2055 outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
2056 outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
2057 outp->parmsp[parmSlot] = openMode; parmSlot++;
2058 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2059 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2061 /* and the final "always present" stuff */
2062 outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
2063 /* next write out the "unique" ID */
2064 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
2065 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
2066 outp->parmsp[parmSlot] = 0; parmSlot++;
2067 if (returnEALength) {
2068 outp->parmsp[parmSlot] = 0; parmSlot++;
2069 outp->parmsp[parmSlot] = 0; parmSlot++;
2072 outp->totalData = 0;
2073 outp->totalParms = parmSlot * 2;
2075 smb_SendTran2Packet(vcp, outp, op);
2077 smb_FreeTran2Packet(outp);
2079 /* and clean up fid reference */
2080 smb_ReleaseFID(fidp);
2084 #ifdef DEBUG_VERBOSE
2086 char *hexp, *asciip;
2087 asciip = (lastNamep ? lastNamep : pathp);
2088 hexp = osi_HexifyString( asciip );
2089 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2094 userp = smb_GetTran2User(vcp, p);
2095 /* In the off chance that userp is NULL, we log and abandon */
2097 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2098 smb_FreeTran2Packet(outp);
2099 return CM_ERROR_BADSMB;
2102 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2103 if(code == CM_ERROR_TIDIPC) {
2104 /* Attempt to use TID allocated for IPC. The client is
2105 probably trying to locate DCE RPC end points, which
2106 we don't support. */
2107 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2108 cm_ReleaseUser(userp);
2109 smb_FreeTran2Packet(outp);
2110 return CM_ERROR_NOSUCHPATH;
2114 code = cm_NameI(cm_rootSCachep, pathp,
2115 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2116 userp, tidPathp, &req, &scp);
2118 code = cm_NameI(cm_rootSCachep, spacep->data,
2119 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2120 userp, tidPathp, &req, &dscp);
2121 cm_FreeSpace(spacep);
2124 cm_ReleaseUser(userp);
2125 smb_FreeTran2Packet(outp);
2129 /* otherwise, scp points to the parent directory. Do a lookup,
2130 * and truncate the file if we find it, otherwise we create the
2133 if (!lastNamep) lastNamep = pathp;
2135 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2137 if (code && code != CM_ERROR_NOSUCHFILE) {
2138 cm_ReleaseSCache(dscp);
2139 cm_ReleaseUser(userp);
2140 smb_FreeTran2Packet(outp);
2145 cm_FreeSpace(spacep);
2148 /* if we get here, if code is 0, the file exists and is represented by
2149 * scp. Otherwise, we have to create it.
2152 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2154 if (dscp) cm_ReleaseSCache(dscp);
2155 cm_ReleaseSCache(scp);
2156 cm_ReleaseUser(userp);
2157 smb_FreeTran2Packet(outp);
2162 /* oops, file shouldn't be there */
2163 if (dscp) cm_ReleaseSCache(dscp);
2164 cm_ReleaseSCache(scp);
2165 cm_ReleaseUser(userp);
2166 smb_FreeTran2Packet(outp);
2167 return CM_ERROR_EXISTS;
2171 setAttr.mask = CM_ATTRMASK_LENGTH;
2172 setAttr.length.LowPart = 0;
2173 setAttr.length.HighPart = 0;
2174 code = cm_SetAttr(scp, &setAttr, userp, &req);
2175 openAction = 3; /* truncated existing file */
2177 else openAction = 1; /* found existing file */
2179 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
2180 /* don't create if not found */
2181 if (dscp) cm_ReleaseSCache(dscp);
2182 osi_assert(scp == NULL);
2183 cm_ReleaseUser(userp);
2184 smb_FreeTran2Packet(outp);
2185 return CM_ERROR_NOSUCHFILE;
2188 osi_assert(dscp != NULL && scp == NULL);
2189 openAction = 2; /* created file */
2190 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2191 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2192 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2194 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2195 smb_NotifyChange(FILE_ACTION_ADDED,
2196 FILE_NOTIFY_CHANGE_FILE_NAME,
2197 dscp, lastNamep, NULL, TRUE);
2198 if (!excl && code == CM_ERROR_EXISTS) {
2199 /* not an exclusive create, and someone else tried
2200 * creating it already, then we open it anyway. We
2201 * don't bother retrying after this, since if this next
2202 * fails, that means that the file was deleted after we
2203 * started this call.
2205 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2209 setAttr.mask = CM_ATTRMASK_LENGTH;
2210 setAttr.length.LowPart = 0;
2211 setAttr.length.HighPart = 0;
2212 code = cm_SetAttr(scp, &setAttr, userp,
2215 } /* lookup succeeded */
2219 /* we don't need this any longer */
2220 if (dscp) cm_ReleaseSCache(dscp);
2223 /* something went wrong creating or truncating the file */
2224 if (scp) cm_ReleaseSCache(scp);
2225 cm_ReleaseUser(userp);
2226 smb_FreeTran2Packet(outp);
2230 /* make sure we're about to open a file */
2231 if (scp->fileType != CM_SCACHETYPE_FILE) {
2232 cm_ReleaseSCache(scp);
2233 cm_ReleaseUser(userp);
2234 smb_FreeTran2Packet(outp);
2235 return CM_ERROR_ISDIR;
2238 /* now all we have to do is open the file itself */
2239 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2242 /* save a pointer to the vnode */
2245 /* compute open mode */
2246 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2247 if (openMode == 1 || openMode == 2)
2248 fidp->flags |= SMB_FID_OPENWRITE;
2250 smb_ReleaseFID(fidp);
2252 cm_Open(scp, 0, userp);
2254 /* copy out remainder of the parms */
2256 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2257 lock_ObtainMutex(&scp->mx);
2259 outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
2260 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2261 outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
2262 outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
2263 outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
2265 outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2267 outp->parmsp[parmSlot] = openMode; parmSlot++;
2268 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2269 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2271 /* and the final "always present" stuff */
2272 outp->parmsp[parmSlot] = openAction; parmSlot++;
2273 /* next write out the "unique" ID */
2274 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
2275 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
2276 outp->parmsp[parmSlot] = 0; parmSlot++;
2277 if (returnEALength) {
2278 outp->parmsp[parmSlot] = 0; parmSlot++;
2279 outp->parmsp[parmSlot] = 0; parmSlot++;
2281 lock_ReleaseMutex(&scp->mx);
2282 outp->totalData = 0; /* total # of data bytes */
2283 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2285 smb_SendTran2Packet(vcp, outp, op);
2287 smb_FreeTran2Packet(outp);
2289 cm_ReleaseUser(userp);
2290 /* leave scp held since we put it in fidp->scp */
2294 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2296 return CM_ERROR_BADOP;
2299 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2301 return CM_ERROR_BADOP;
2304 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2306 smb_tran2Packet_t *outp;
2307 smb_tran2QFSInfo_t qi;
2310 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
2312 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2314 switch (p->parmsp[0]) {
2315 case 1: responseSize = sizeof(qi.u.allocInfo); break;
2316 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
2317 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
2318 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
2319 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
2320 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
2321 default: return CM_ERROR_INVAL;
2324 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2325 switch (p->parmsp[0]) {
2328 qi.u.allocInfo.FSID = 0;
2329 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2330 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2331 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2332 qi.u.allocInfo.bytesPerSector = 1024;
2337 qi.u.volumeInfo.vsn = 1234;
2338 qi.u.volumeInfo.vnCount = 4;
2339 /* we're supposed to pad it out with zeroes to the end */
2340 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2341 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2345 /* FS volume info */
2346 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
2347 qi.u.FSvolumeInfo.vsn = 1234;
2348 qi.u.FSvolumeInfo.vnCount = 8;
2349 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
2355 temp.LowPart = 0x7fffffff;
2356 qi.u.FSsizeInfo.totalAllocUnits = temp;
2357 temp.LowPart = 0x3fffffff;
2358 qi.u.FSsizeInfo.availAllocUnits = temp;
2359 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2360 qi.u.FSsizeInfo.bytesPerSector = 1024;
2364 /* FS device info */
2365 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
2366 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2370 /* FS attribute info */
2371 /* attributes, defined in WINNT.H:
2372 * FILE_CASE_SENSITIVE_SEARCH 0x1
2373 * FILE_CASE_PRESERVED_NAMES 0x2
2374 * <no name defined> 0x4000
2375 * If bit 0x4000 is not set, Windows 95 thinks
2376 * we can't handle long (non-8.3) names,
2377 * despite our protestations to the contrary.
2379 qi.u.FSattributeInfo.attributes = 0x4003;
2380 qi.u.FSattributeInfo.maxCompLength = 255;
2381 qi.u.FSattributeInfo.FSnameLength = 6;
2382 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
2386 /* copy out return data, and set corresponding sizes */
2387 outp->totalParms = 0;
2388 outp->totalData = responseSize;
2389 memcpy(outp->datap, &qi, responseSize);
2391 /* send and free the packets */
2392 smb_SendTran2Packet(vcp, outp, op);
2393 smb_FreeTran2Packet(outp);
2398 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2400 return CM_ERROR_BADOP;
2403 struct smb_ShortNameRock {
2407 size_t shortNameLen;
2410 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2413 struct smb_ShortNameRock *rockp;
2417 /* compare both names and vnodes, though probably just comparing vnodes
2418 * would be safe enough.
2420 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2422 if (ntohl(dep->fid.vnode) != rockp->vnode)
2424 /* This is the entry */
2425 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2426 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2427 return CM_ERROR_STOPNOW;
2430 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2431 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2433 struct smb_ShortNameRock rock;
2437 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2441 spacep = cm_GetSpace();
2442 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2444 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
2446 cm_FreeSpace(spacep);
2447 if (code) return code;
2449 if (!lastNamep) lastNamep = pathp;
2452 thyper.HighPart = 0;
2453 rock.shortName = shortName;
2455 rock.maskp = lastNamep;
2456 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
2459 cm_ReleaseSCache(dscp);
2462 return CM_ERROR_NOSUCHFILE;
2463 if (code == CM_ERROR_STOPNOW) {
2464 *shortNameLenp = rock.shortNameLen;
2470 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2472 smb_tran2Packet_t *outp;
2473 unsigned long dosTime;
2475 unsigned short infoLevel;
2477 unsigned short attributes;
2478 unsigned long extAttributes;
2483 cm_scache_t *scp, *dscp;
2492 infoLevel = p->parmsp[0];
2493 if (infoLevel == 6) nbytesRequired = 0;
2494 else if (infoLevel == 1) nbytesRequired = 22;
2495 else if (infoLevel == 2) nbytesRequired = 26;
2496 else if (infoLevel == 0x101) nbytesRequired = 40;
2497 else if (infoLevel == 0x102) nbytesRequired = 24;
2498 else if (infoLevel == 0x103) nbytesRequired = 4;
2499 else if (infoLevel == 0x108) nbytesRequired = 30;
2501 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2502 p->opcode, infoLevel);
2503 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2506 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2507 osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
2509 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2511 if (infoLevel > 0x100)
2512 outp->totalParms = 2;
2514 outp->totalParms = 0;
2515 outp->totalData = nbytesRequired;
2517 /* now, if we're at infoLevel 6, we're only being asked to check
2518 * the syntax, so we just OK things now. In particular, we're *not*
2519 * being asked to verify anything about the state of any parent dirs.
2521 if (infoLevel == 6) {
2522 smb_SendTran2Packet(vcp, outp, opx);
2523 smb_FreeTran2Packet(outp);
2527 userp = smb_GetTran2User(vcp, p);
2529 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2530 smb_FreeTran2Packet(outp);
2531 return CM_ERROR_BADSMB;
2534 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2536 cm_ReleaseUser(userp);
2537 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2538 smb_FreeTran2Packet(outp);
2543 * XXX Strange hack XXX
2545 * As of Patch 7 (13 January 98), we are having the following problem:
2546 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2547 * requests to look up "desktop.ini" in all the subdirectories.
2548 * This can cause zillions of timeouts looking up non-existent cells
2549 * and volumes, especially in the top-level directory.
2551 * We have not found any way to avoid this or work around it except
2552 * to explicitly ignore the requests for mount points that haven't
2553 * yet been evaluated and for directories that haven't yet been
2556 if (infoLevel == 0x101) {
2557 spacep = cm_GetSpace();
2558 smb_StripLastComponent(spacep->data, &lastComp,
2559 (char *)(&p->parmsp[3]));
2560 /* Make sure that lastComp is not NULL */
2562 if (strcmp(lastComp, "\\desktop.ini") == 0) {
2563 code = cm_NameI(cm_rootSCachep, spacep->data,
2567 userp, tidPathp, &req, &dscp);
2569 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
2570 && !dscp->mountRootFidp)
2571 code = CM_ERROR_NOSUCHFILE;
2572 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2573 cm_buf_t *bp = buf_Find(dscp, &hzero);
2577 code = CM_ERROR_NOSUCHFILE;
2579 cm_ReleaseSCache(dscp);
2581 cm_FreeSpace(spacep);
2582 cm_ReleaseUser(userp);
2583 smb_SendTran2Error(vcp, p, opx, code);
2584 smb_FreeTran2Packet(outp);
2590 cm_FreeSpace(spacep);
2593 /* now do namei and stat, and copy out the info */
2594 code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
2595 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2598 cm_ReleaseUser(userp);
2599 smb_SendTran2Error(vcp, p, opx, code);
2600 smb_FreeTran2Packet(outp);
2604 lock_ObtainMutex(&scp->mx);
2605 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2606 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2607 if (code) goto done;
2609 /* now we have the status in the cache entry, and everything is locked.
2610 * Marshall the output data.
2613 /* for info level 108, figure out short name */
2614 if (infoLevel == 0x108) {
2615 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
2616 tidPathp, scp->fid.vnode, shortName,
2623 *((u_long *)op) = len * 2; op += 4;
2624 mbstowcs((unsigned short *)op, shortName, len);
2629 if (infoLevel == 1 || infoLevel == 2) {
2630 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2631 *((u_long *)op) = dosTime; op += 4; /* creation time */
2632 *((u_long *)op) = dosTime; op += 4; /* access time */
2633 *((u_long *)op) = dosTime; op += 4; /* write time */
2634 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
2635 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
2636 attributes = smb_Attributes(scp);
2637 *((u_short *)op) = attributes; op += 2; /* attributes */
2639 else if (infoLevel == 0x101) {
2640 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2641 *((FILETIME *)op) = ft; op += 8; /* creation time */
2642 *((FILETIME *)op) = ft; op += 8; /* last access time */
2643 *((FILETIME *)op) = ft; op += 8; /* last write time */
2644 *((FILETIME *)op) = ft; op += 8; /* last change time */
2645 extAttributes = smb_ExtAttributes(scp);
2646 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
2647 *((u_long *)op) = 0; op += 4; /* don't know what this is */
2649 else if (infoLevel == 0x102) {
2650 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2651 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2652 *((u_long *)op) = scp->linkCount; op += 4;
2655 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2658 else if (infoLevel == 0x103) {
2659 memset(op, 0, 4); op += 4; /* EA size */
2662 /* now, if we are being asked about extended attrs, return a 0 size */
2663 if (infoLevel == 2) {
2664 *((u_long *)op) = 0; op += 4;
2668 /* send and free the packets */
2670 lock_ReleaseMutex(&scp->mx);
2671 cm_ReleaseSCache(scp);
2672 cm_ReleaseUser(userp);
2674 smb_SendTran2Packet(vcp, outp, opx);
2676 smb_SendTran2Error(vcp, p, opx, code);
2677 smb_FreeTran2Packet(outp);
2682 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2684 return CM_ERROR_BADOP;
2687 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2689 smb_tran2Packet_t *outp;
2691 unsigned long attributes;
2692 unsigned short infoLevel;
2705 fidp = smb_FindFID(vcp, fid, 0);
2708 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2712 infoLevel = p->parmsp[1];
2713 if (infoLevel == 0x101) nbytesRequired = 40;
2714 else if (infoLevel == 0x102) nbytesRequired = 24;
2715 else if (infoLevel == 0x103) nbytesRequired = 4;
2716 else if (infoLevel == 0x104) nbytesRequired = 6;
2718 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2719 p->opcode, infoLevel);
2720 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2721 smb_ReleaseFID(fidp);
2724 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2726 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2728 if (infoLevel > 0x100)
2729 outp->totalParms = 2;
2731 outp->totalParms = 0;
2732 outp->totalData = nbytesRequired;
2734 userp = smb_GetTran2User(vcp, p);
2736 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2737 code = CM_ERROR_BADSMB;
2742 lock_ObtainMutex(&scp->mx);
2743 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2744 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2745 if (code) goto done;
2747 /* now we have the status in the cache entry, and everything is locked.
2748 * Marshall the output data.
2751 if (infoLevel == 0x101) {
2752 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2753 *((FILETIME *)op) = ft; op += 8; /* creation time */
2754 *((FILETIME *)op) = ft; op += 8; /* last access time */
2755 *((FILETIME *)op) = ft; op += 8; /* last write time */
2756 *((FILETIME *)op) = ft; op += 8; /* last change time */
2757 attributes = smb_ExtAttributes(scp);
2758 *((u_long *)op) = attributes; op += 4;
2759 *((u_long *)op) = 0; op += 4;
2761 else if (infoLevel == 0x102) {
2762 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2763 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2764 *((u_long *)op) = scp->linkCount; op += 4;
2765 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
2766 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2770 else if (infoLevel == 0x103) {
2771 *((u_long *)op) = 0; op += 4;
2773 else if (infoLevel == 0x104) {
2777 if (fidp->NTopen_wholepathp)
2778 name = fidp->NTopen_wholepathp;
2780 name = "\\"; /* probably can't happen */
2782 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
2783 *((u_long *)op) = len * 2; op += 4;
2784 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2787 /* send and free the packets */
2789 lock_ReleaseMutex(&scp->mx);
2790 cm_ReleaseUser(userp);
2791 smb_ReleaseFID(fidp);
2792 if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
2793 else smb_SendTran2Error(vcp, p, opx, code);
2794 smb_FreeTran2Packet(outp);
2799 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2804 unsigned short infoLevel;
2805 smb_tran2Packet_t *outp;
2813 fidp = smb_FindFID(vcp, fid, 0);
2816 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
2820 infoLevel = p->parmsp[1];
2821 if (infoLevel > 0x104 || infoLevel < 0x101) {
2822 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2823 p->opcode, infoLevel);
2824 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
2825 smb_ReleaseFID(fidp);
2829 if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
2830 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2831 smb_ReleaseFID(fidp);
2834 if ((infoLevel == 0x103 || infoLevel == 0x104)
2835 && !(fidp->flags & SMB_FID_OPENWRITE)) {
2836 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2837 smb_ReleaseFID(fidp);
2841 osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
2843 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
2845 outp->totalParms = 2;
2846 outp->totalData = 0;
2848 userp = smb_GetTran2User(vcp, p);
2850 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
2851 code = CM_ERROR_BADSMB;
2857 if (infoLevel == 0x101) {
2859 unsigned int attribute;
2862 /* lock the vnode with a callback; we need the current status
2863 * to determine what the new status is, in some cases.
2865 lock_ObtainMutex(&scp->mx);
2866 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2867 CM_SCACHESYNC_GETSTATUS
2868 | CM_SCACHESYNC_NEEDCALLBACK);
2870 lock_ReleaseMutex(&scp->mx);
2874 /* prepare for setattr call */
2877 lastMod = *((FILETIME *)(p->datap + 16));
2878 /* when called as result of move a b, lastMod is (-1, -1).
2879 * If the check for -1 is not present, timestamp
2880 * of the resulting file will be 1969 (-1)
2882 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
2883 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
2884 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
2885 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
2887 fidp->flags |= SMB_FID_MTIMESETDONE;
2890 attribute = *((u_long *)(p->datap + 32));
2891 if (attribute != 0) {
2892 if ((scp->unixModeBits & 0222)
2893 && (attribute & 1) != 0) {
2894 /* make a writable file read-only */
2895 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2896 attr.unixModeBits = scp->unixModeBits & ~0222;
2898 else if ((scp->unixModeBits & 0222) == 0
2899 && (attribute & 1) == 0) {
2900 /* make a read-only file writable */
2901 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2902 attr.unixModeBits = scp->unixModeBits | 0222;
2905 lock_ReleaseMutex(&scp->mx);
2909 code = cm_SetAttr(scp, &attr, userp, &req);
2913 else if (infoLevel == 0x103 || infoLevel == 0x104) {
2914 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
2917 attr.mask = CM_ATTRMASK_LENGTH;
2918 attr.length.LowPart = size.LowPart;
2919 attr.length.HighPart = size.HighPart;
2920 code = cm_SetAttr(scp, &attr, userp, &req);
2922 else if (infoLevel == 0x102) {
2923 if (*((char *)(p->datap))) {
2924 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
2927 fidp->flags |= SMB_FID_DELONCLOSE;
2931 fidp->flags &= ~SMB_FID_DELONCLOSE;
2935 cm_ReleaseUser(userp);
2936 smb_ReleaseFID(fidp);
2937 if (code == 0) smb_SendTran2Packet(vcp, outp, op);
2938 else smb_SendTran2Error(vcp, p, op, code);
2939 smb_FreeTran2Packet(outp);
2944 long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2946 return CM_ERROR_BADOP;
2949 long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2951 return CM_ERROR_BADOP;
2954 long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2956 return CM_ERROR_BADOP;
2959 long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2961 return CM_ERROR_BADOP;
2964 long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2966 return CM_ERROR_BADOP;
2969 long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
2970 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
2975 cm_scache_t *targetScp; /* target if scp is a symlink */
2980 unsigned short attr;
2981 unsigned long lattr;
2982 smb_dirListPatch_t *patchp;
2983 smb_dirListPatch_t *npatchp;
2985 for(patchp = *dirPatchespp; patchp; patchp =
2986 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
2987 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
2989 lock_ObtainMutex(&scp->mx);
2990 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
2991 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2993 lock_ReleaseMutex(&scp->mx);
2994 cm_ReleaseSCache(scp);
2996 dptr = patchp->dptr;
2998 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
2999 errors in the client. */
3000 if (infoLevel >= 0x101) {
3001 /* 1969-12-31 23:59:59 +00 */
3002 ft.dwHighDateTime = 0x19DB200;
3003 ft.dwLowDateTime = 0x5BB78980;
3005 /* copy to Creation Time */
3006 *((FILETIME *)dptr) = ft;
3009 /* copy to Last Access Time */
3010 *((FILETIME *)dptr) = ft;
3013 /* copy to Last Write Time */
3014 *((FILETIME *)dptr) = ft;
3017 /* copy to Change Time */
3018 *((FILETIME *)dptr) = ft;
3021 /* merge in hidden attribute */
3022 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3023 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3028 /* 1969-12-31 23:59:58 +00*/
3029 dosTime = 0xEBBFBF7D;
3031 /* and copy out date */
3032 shortTemp = (dosTime>>16) & 0xffff;
3033 *((u_short *)dptr) = shortTemp;
3036 /* copy out creation time */
3037 shortTemp = dosTime & 0xffff;
3038 *((u_short *)dptr) = shortTemp;
3041 /* and copy out date */
3042 shortTemp = (dosTime>>16) & 0xffff;
3043 *((u_short *)dptr) = shortTemp;
3046 /* copy out access time */
3047 shortTemp = dosTime & 0xffff;
3048 *((u_short *)dptr) = shortTemp;
3051 /* and copy out date */
3052 shortTemp = (dosTime>>16) & 0xffff;
3053 *((u_short *)dptr) = shortTemp;
3056 /* copy out mod time */
3057 shortTemp = dosTime & 0xffff;
3058 *((u_short *)dptr) = shortTemp;
3061 /* merge in hidden (dot file) attribute */
3062 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3063 attr == SMB_ATTR_HIDDEN;
3064 *dptr++ = attr & 0xff;
3065 *dptr++ = (attr >> 8) & 0xff;
3072 /* now watch for a symlink */
3073 if (scp->fileType == CM_SCACHETYPE_SYMLINK) {
3074 lock_ReleaseMutex(&scp->mx);
3075 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3077 /* we have a more accurate file to use (the
3078 * target of the symbolic link). Otherwise,
3079 * we'll just use the symlink anyway.
3081 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3083 cm_ReleaseSCache(scp);
3086 lock_ObtainMutex(&scp->mx);
3089 dptr = patchp->dptr;
3091 if (infoLevel >= 0x101) {
3093 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3095 /* copy to Creation Time */
3096 *((FILETIME *)dptr) = ft;
3099 /* copy to Last Access Time */
3100 *((FILETIME *)dptr) = ft;
3103 /* copy to Last Write Time */
3104 *((FILETIME *)dptr) = ft;
3107 /* copy to Change Time */
3108 *((FILETIME *)dptr) = ft;
3111 /* Use length for both file length and alloc length */
3112 *((LARGE_INTEGER *)dptr) = scp->length;
3114 *((LARGE_INTEGER *)dptr) = scp->length;
3117 /* Copy attributes */
3118 lattr = smb_ExtAttributes(scp);
3119 /* merge in hidden (dot file) attribute */
3120 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3121 lattr |= SMB_ATTR_HIDDEN;
3122 *((u_long *)dptr) = lattr;
3127 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3129 /* and copy out date */
3130 shortTemp = (dosTime>>16) & 0xffff;
3131 *((u_short *)dptr) = shortTemp;
3134 /* copy out creation time */
3135 shortTemp = dosTime & 0xffff;
3136 *((u_short *)dptr) = shortTemp;
3139 /* and copy out date */
3140 shortTemp = (dosTime>>16) & 0xffff;
3141 *((u_short *)dptr) = shortTemp;
3144 /* copy out access time */
3145 shortTemp = dosTime & 0xffff;
3146 *((u_short *)dptr) = shortTemp;
3149 /* and copy out date */
3150 shortTemp = (dosTime>>16) & 0xffff;
3151 *((u_short *)dptr) = shortTemp;
3154 /* copy out mod time */
3155 shortTemp = dosTime & 0xffff;
3156 *((u_short *)dptr) = shortTemp;
3159 /* copy out file length and alloc length,
3160 * using the same for both
3162 *((u_long *)dptr) = scp->length.LowPart;
3164 *((u_long *)dptr) = scp->length.LowPart;
3167 /* finally copy out attributes as short */
3168 attr = smb_Attributes(scp);
3169 /* merge in hidden (dot file) attribute */
3170 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3171 attr |= SMB_ATTR_HIDDEN;
3172 *dptr++ = attr & 0xff;
3173 *dptr++ = (attr >> 8) & 0xff;
3176 lock_ReleaseMutex(&scp->mx);
3177 cm_ReleaseSCache(scp);
3180 /* now free the patches */
3181 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
3182 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3186 /* and mark the list as empty */
3187 *dirPatchespp = NULL;
3192 #ifndef USE_OLD_MATCHING
3193 // char table for case insensitive comparison
3194 char mapCaseTable[256];
3196 VOID initUpperCaseTable(VOID)
3199 for (i = 0; i < 256; ++i)
3200 mapCaseTable[i] = toupper(i);
3201 // make '"' match '.'
3202 mapCaseTable[(int)'"'] = toupper('.');
3203 // make '<' match '*'
3204 mapCaseTable[(int)'<'] = toupper('*');
3205 // make '>' match '?'
3206 mapCaseTable[(int)'>'] = toupper('?');
3209 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3211 // Note : this procedure works recursively calling itself.
3213 // PSZ pattern : string containing metacharacters.
3214 // PSZ name : file name to be compared with 'pattern'.
3216 // BOOL : TRUE/FALSE (match/mistmatch)
3218 BOOL szWildCardMatchFileName(PSZ pattern, PSZ name) {
3219 PSZ pename; // points to the last 'name' character
3221 pename = name + strlen(name) - 1;
3226 if (*(++pattern) != '<' || *(++pattern) != '*') {
3234 while ((*pattern == '<') || (*pattern == '*') || (*pattern == '?') || (*pattern == '>'))
3238 for (p = pename; p >= name; --p) {
3239 if ((mapCaseTable[*p] == mapCaseTable[*pattern]) &&
3240 szWildCardMatchFileName(pattern + 1, p + 1))
3245 if (mapCaseTable[*name] != mapCaseTable[*pattern])
3254 /* do a case-folding search of the star name mask with the name in namep.
3255 * Return 1 if we match, otherwise 0.
3257 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3259 /* make sure we only match 8.3 names, if requested */
3260 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3263 return szWildCardMatchFileName(maskp, namep) ? 1:0;
3266 #else /* USE_OLD_MATCHING */
3267 /* do a case-folding search of the star name mask with the name in namep.
3268 * Return 1 if we match, otherwise 0.
3270 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3272 unsigned char tcp1, tcp2; /* Pattern characters */
3273 unsigned char tcn1; /* Name characters */
3274 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3275 char *starNamep, *starMaskp;
3276 static char nullCharp[] = {0};
3277 int casefold = flags & CM_FLAG_CASEFOLD;
3279 /* make sure we only match 8.3 names, if requested */
3280 req8dot3 = (flags & CM_FLAG_8DOT3);
3281 if (req8dot3 && !cm_Is8Dot3(namep))
3286 /* Next pattern character */
3289 /* Next name character */
3293 /* 0 - end of pattern */
3299 else if (tcp1 == '.' || tcp1 == '"') {
3309 * first dot in pattern;
3310 * must match dot or end of name
3315 else if (tcn1 == '.') {
3324 else if (tcp1 == '?') {
3325 if (tcn1 == 0 || tcn1 == '.')
3330 else if (tcp1 == '>') {
3331 if (tcn1 != 0 && tcn1 != '.')
3335 else if (tcp1 == '*' || tcp1 == '<') {
3339 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3340 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3355 * pattern character after '*' is not null or
3356 * period. If it is '?' or '>', we are not
3357 * going to understand it. If it is '*' or
3358 * '<', we are going to skip over it. None of
3359 * these are likely, I hope.
3361 /* skip over '*' and '<' */
3362 while (tcp2 == '*' || tcp2 == '<')
3365 /* skip over characters that don't match tcp2 */
3366 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
3367 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
3368 (!casefold && tcn1 != tcp2)))
3372 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3375 /* Remember where we are */
3385 /* tcp1 is not a wildcard */
3386 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
3387 (!casefold && tcn1 == tcp1)) {
3392 /* if trying to match a star pattern, go back */
3394 maskp = starMaskp - 2;
3395 namep = starNamep + 1;
3404 #endif /* USE_OLD_MATCHING */
3406 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3415 smb_dirListPatch_t *dirListPatchesp;
3416 smb_dirListPatch_t *curPatchp;
3419 long orbytes; /* # of bytes in this output record */
3420 long ohbytes; /* # of bytes, except file name */
3421 long onbytes; /* # of bytes in name, incl. term. null */
3422 osi_hyper_t dirLength;
3423 osi_hyper_t bufferOffset;
3424 osi_hyper_t curOffset;
3426 smb_dirSearch_t *dsp;
3430 cm_pageHeader_t *pageHeaderp;
3431 cm_user_t *userp = NULL;
3434 long nextEntryCookie;
3435 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3436 char *op; /* output data ptr */
3437 char *origOp; /* original value of op */
3438 cm_space_t *spacep; /* for pathname buffer */
3439 long maxReturnData; /* max # of return data */
3440 long maxReturnParms; /* max # of return parms */
3441 long bytesInBuffer; /* # data bytes in the output buffer */
3443 char *maskp; /* mask part of path */
3447 smb_tran2Packet_t *outp; /* response packet */
3450 char shortName[13]; /* 8.3 name if needed */
3462 if (p->opcode == 1) {
3463 /* find first; obtain basic parameters from request */
3464 attribute = p->parmsp[0];
3465 maxCount = p->parmsp[1];
3466 infoLevel = p->parmsp[3];
3467 searchFlags = p->parmsp[2];
3468 dsp = smb_NewDirSearch(1);
3469 dsp->attribute = attribute;
3470 pathp = ((char *) p->parmsp) + 12; /* points to path */
3472 maskp = strrchr(pathp, '\\');
3473 if (maskp == NULL) maskp = pathp;
3474 else maskp++; /* skip over backslash */
3475 strcpy(dsp->mask, maskp); /* and save mask */
3476 /* track if this is likely to match a lot of entries */
3477 starPattern = smb_V3IsStarMask(maskp);
3480 osi_assert(p->opcode == 2);
3481 /* find next; obtain basic parameters from request or open dir file */
3482 dsp = smb_FindDirSearch(p->parmsp[0]);
3483 if (!dsp) return CM_ERROR_BADFD;
3484 attribute = dsp->attribute;
3485 maxCount = p->parmsp[1];
3486 infoLevel = p->parmsp[2];
3487 searchFlags = p->parmsp[5];
3489 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
3491 starPattern = 1; /* assume, since required a Find Next */
3495 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
3496 attribute, infoLevel, maxCount, searchFlags);
3498 osi_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
3499 p->opcode, nextCookie);
3501 if (infoLevel >= 0x101)
3502 searchFlags &= ~4; /* no resume keys */
3504 dirListPatchesp = NULL;
3506 maxReturnData = p->maxReturnData;
3507 if (p->opcode == 1) /* find first */
3508 maxReturnParms = 10; /* bytes */
3510 maxReturnParms = 8; /* bytes */
3512 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
3513 if (maxReturnData > 6000)
3514 maxReturnData = 6000;
3515 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
3517 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
3520 osi_Log1(smb_logp, "T2 receive search dir %s",
3521 osi_LogSaveString(smb_logp, pathp));
3523 /* bail out if request looks bad */
3524 if (p->opcode == 1 && !pathp) {
3525 smb_ReleaseDirSearch(dsp);
3526 smb_FreeTran2Packet(outp);
3527 return CM_ERROR_BADSMB;
3530 osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
3531 nextCookie, dsp->cookie);
3533 userp = smb_GetTran2User(vcp, p);
3535 osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p->uid);
3536 smb_ReleaseDirSearch(dsp);
3537 smb_FreeTran2Packet(outp);
3538 return CM_ERROR_BADSMB;
3541 /* try to get the vnode for the path name next */
3542 lock_ObtainMutex(&dsp->mx);
3549 spacep = cm_GetSpace();
3550 smb_StripLastComponent(spacep->data, NULL, pathp);
3551 lock_ReleaseMutex(&dsp->mx);
3553 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3555 cm_ReleaseUser(userp);
3556 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
3557 smb_FreeTran2Packet(outp);
3558 smb_DeleteDirSearch(dsp);
3559 smb_ReleaseDirSearch(dsp);
3562 code = cm_NameI(cm_rootSCachep, spacep->data,
3563 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3564 userp, tidPathp, &req, &scp);
3565 cm_FreeSpace(spacep);
3567 lock_ObtainMutex(&dsp->mx);
3569 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
3571 /* we need one hold for the entry we just stored into,
3572 * and one for our own processing. When we're done
3573 * with this function, we'll drop the one for our own
3574 * processing. We held it once from the namei call,
3575 * and so we do another hold now.
3578 lock_ObtainMutex(&scp->mx);
3579 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3580 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3581 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3582 dsp->flags |= SMB_DIRSEARCH_BULKST;
3584 lock_ReleaseMutex(&scp->mx);
3587 lock_ReleaseMutex(&dsp->mx);
3589 cm_ReleaseUser(userp);
3590 smb_FreeTran2Packet(outp);
3591 smb_DeleteDirSearch(dsp);
3592 smb_ReleaseDirSearch(dsp);
3596 /* get the directory size */
3597 lock_ObtainMutex(&scp->mx);
3598 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3599 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3601 lock_ReleaseMutex(&scp->mx);
3602 cm_ReleaseSCache(scp);
3603 cm_ReleaseUser(userp);
3604 smb_FreeTran2Packet(outp);
3605 smb_DeleteDirSearch(dsp);
3606 smb_ReleaseDirSearch(dsp);
3611 dirLength = scp->length;
3613 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3614 curOffset.HighPart = 0;
3615 curOffset.LowPart = nextCookie;
3616 origOp = outp->datap;
3624 if (searchFlags & 4)
3625 /* skip over resume key */
3628 /* make sure that curOffset.LowPart doesn't point to the first
3629 * 32 bytes in the 2nd through last dir page, and that it doesn't
3630 * point at the first 13 32-byte chunks in the first dir page,
3631 * since those are dir and page headers, and don't contain useful
3634 temp = curOffset.LowPart & (2048-1);
3635 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3636 /* we're in the first page */
3637 if (temp < 13*32) temp = 13*32;
3640 /* we're in a later dir page */
3641 if (temp < 32) temp = 32;
3644 /* make sure the low order 5 bits are zero */
3647 /* now put temp bits back ito curOffset.LowPart */
3648 curOffset.LowPart &= ~(2048-1);
3649 curOffset.LowPart |= temp;
3651 /* check if we've passed the dir's EOF */
3652 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
3657 /* check if we've returned all the names that will fit in the
3658 * response packet; we check return count as well as the number
3659 * of bytes requested. We check the # of bytes after we find
3660 * the dir entry, since we'll need to check its size.
3662 if (returnedNames >= maxCount) {
3666 /* see if we can use the bufferp we have now; compute in which
3667 * page the current offset would be, and check whether that's
3668 * the offset of the buffer we have. If not, get the buffer.
3670 thyper.HighPart = curOffset.HighPart;
3671 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3672 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3675 buf_Release(bufferp);
3678 lock_ReleaseMutex(&scp->mx);
3679 lock_ObtainRead(&scp->bufCreateLock);
3680 code = buf_Get(scp, &thyper, &bufferp);
3681 lock_ReleaseRead(&scp->bufCreateLock);
3683 /* now, if we're doing a star match, do bulk fetching
3684 * of all of the status info for files in the dir.
3687 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
3690 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
3691 && LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
3692 /* Don't bulk stat if risking timeout */
3693 int now = GetCurrentTime();
3694 if (now - req.startTime > 5000) {
3695 scp->bulkStatProgress = thyper;
3696 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3697 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3699 cm_TryBulkStat(scp, &thyper, userp, &req);
3703 lock_ObtainMutex(&scp->mx);
3705 bufferOffset = thyper;
3707 /* now get the data in the cache */
3709 code = cm_SyncOp(scp, bufferp, userp, &req,
3711 CM_SCACHESYNC_NEEDCALLBACK
3712 | CM_SCACHESYNC_READ);
3715 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3717 /* otherwise, load the buffer and try again */
3718 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3723 buf_Release(bufferp);
3727 } /* if (wrong buffer) ... */
3729 /* now we have the buffer containing the entry we're interested
3730 * in; copy it out if it represents a non-deleted entry.
3732 entryInDir = curOffset.LowPart & (2048-1);
3733 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3735 /* page header will help tell us which entries are free. Page
3736 * header can change more often than once per buffer, since
3737 * AFS 3 dir page size may be less than (but not more than)
3738 * a buffer package buffer.
3740 /* only look intra-buffer */
3741 temp = curOffset.LowPart & (buf_bufferSize - 1);
3742 temp &= ~(2048 - 1); /* turn off intra-page bits */
3743 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3745 /* now determine which entry we're looking at in the page.
3746 * If it is free (there's a free bitmap at the start of the
3747 * dir), we should skip these 32 bytes.
3749 slotInPage = (entryInDir & 0x7e0) >> 5;
3750 if (!(pageHeaderp->freeBitmap[slotInPage>>3]
3751 & (1 << (slotInPage & 0x7)))) {
3752 /* this entry is free */
3753 numDirChunks = 1; /* only skip this guy */
3757 tp = bufferp->datap + entryInBuffer;
3758 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3760 /* while we're here, compute the next entry's location, too,
3761 * since we'll need it when writing out the cookie into the dir
3764 * XXXX Probably should do more sanity checking.
3766 numDirChunks = cm_NameEntries(dep->name, &onbytes);
3768 /* compute offset of cookie representing next entry */
3769 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3771 /* Need 8.3 name? */
3773 if (infoLevel == 0x104
3774 && dep->fid.vnode != 0
3775 && !cm_Is8Dot3(dep->name)) {
3776 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3780 /* When matching, we are using doing a case fold if we have a wildcard mask.
3781 * If we get a non-wildcard match, it's a lookup for a specific file.
3783 if (dep->fid.vnode != 0 &&
3784 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0))
3786 && smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
3788 /* Eliminate entries that don't match requested attributes */
3789 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
3790 smb_IsDotFile(dep->name))
3791 goto nextEntry; /* no hidden files */
3793 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3795 /* We have already done the cm_TryBulkStat above */
3796 fid.cell = scp->fid.cell;
3797 fid.volume = scp->fid.volume;
3798 fid.vnode = ntohl(dep->fid.vnode);
3799 fid.unique = ntohl(dep->fid.unique);
3800 fileType = cm_FindFileType(&fid);
3801 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
3802 "has filetype %d", dep->name,
3804 if (fileType == CM_SCACHETYPE_DIRECTORY)
3808 /* finally check if this name will fit */
3810 /* standard dir entry stuff */
3811 if (infoLevel < 0x101)
3812 ohbytes = 23; /* pre-NT */
3813 else if (infoLevel == 0x103)
3814 ohbytes = 12; /* NT names only */
3816 ohbytes = 64; /* NT */
3818 if (infoLevel == 0x104)
3819 ohbytes += 26; /* Short name & length */
3821 if (searchFlags & 4) {
3822 ohbytes += 4; /* if resume key required */
3826 && infoLevel != 0x101
3827 && infoLevel != 0x103)
3828 ohbytes += 4; /* EASIZE */
3830 /* add header to name & term. null */
3831 orbytes = onbytes + ohbytes + 1;
3833 /* now, we round up the record to a 4 byte alignment,
3834 * and we make sure that we have enough room here for
3835 * even the aligned version (so we don't have to worry
3836 * about an * overflow when we pad things out below).
3837 * That's the reason for the alignment arithmetic below.
3839 if (infoLevel >= 0x101)
3840 align = (4 - (orbytes & 3)) & 3;
3843 if (orbytes + bytesInBuffer + align > maxReturnData)
3846 /* this is one of the entries to use: it is not deleted
3847 * and it matches the star pattern we're looking for.
3848 * Put out the name, preceded by its length.
3850 /* First zero everything else */
3851 memset(origOp, 0, ohbytes);
3853 if (infoLevel <= 0x101)
3854 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
3855 else if (infoLevel == 0x103)
3856 *((u_long *)(op + 8)) = onbytes;
3858 *((u_long *)(op + 60)) = onbytes;
3859 strcpy(origOp+ohbytes, dep->name);
3861 /* Short name if requested and needed */
3862 if (infoLevel == 0x104) {
3863 if (NeedShortName) {
3864 strcpy(op + 70, shortName);
3865 *(op + 68) = shortNameEnd - shortName;
3869 /* now, adjust the # of entries copied */
3872 /* NextEntryOffset and FileIndex */
3873 if (infoLevel >= 101) {
3874 int entryOffset = orbytes + align;
3875 *((u_long *)op) = entryOffset;
3876 *((u_long *)(op+4)) = nextEntryCookie;
3879 /* now we emit the attribute. This is tricky, since
3880 * we need to really stat the file to find out what
3881 * type of entry we've got. Right now, we're copying
3882 * out data from * a buffer, while holding the scp
3883 * locked, so it isn't really convenient to stat
3884 * something now. We'll put in a place holder
3885 * now, and make a second pass before returning this
3886 * to get the real attributes. So, we just skip the
3887 * data for now, and adjust it later. We allocate a
3888 * patch record to make it easy to find this point
3889 * later. The replay will happen at a time when it is
3890 * safe to unlock the directory.
3892 if (infoLevel != 0x103) {
3893 curPatchp = malloc(sizeof(*curPatchp));
3894 osi_QAdd((osi_queue_t **) &dirListPatchesp,
3896 curPatchp->dptr = op;
3897 if (infoLevel >= 0x101)
3898 curPatchp->dptr += 8;
3900 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
3901 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3904 curPatchp->flags = 0;
3906 curPatchp->fid.cell = scp->fid.cell;
3907 curPatchp->fid.volume = scp->fid.volume;
3908 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3909 curPatchp->fid.unique = ntohl(dep->fid.unique);
3912 curPatchp->dep = dep;
3915 if (searchFlags & 4)
3916 /* put out resume key */
3917 *((u_long *)origOp) = nextEntryCookie;
3919 /* Adjust byte ptr and count */
3920 origOp += orbytes; /* skip entire record */
3921 bytesInBuffer += orbytes;
3923 /* and pad the record out */
3924 while (--align >= 0) {
3929 } /* if we're including this name */
3930 else if (!NeedShortName &&
3933 dep->fid.vnode != 0 &&
3934 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
3935 /* We were looking for exact matches, but here's an inexact one*/
3940 /* and adjust curOffset to be where the new cookie is */
3941 thyper.HighPart = 0;
3942 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3943 curOffset = LargeIntegerAdd(thyper, curOffset);
3944 } /* while copying data for dir listing */
3946 /* If we didn't get a star pattern, we did an exact match during the first pass.
3947 * If there were no exact matches found, we fail over to inexact matches by
3948 * marking the query as a star pattern (matches all case permutations), and
3949 * re-running the query.
3951 if (returnedNames == 0 && !starPattern && foundInexact) {
3952 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
3957 /* release the mutex */
3958 lock_ReleaseMutex(&scp->mx);
3959 if (bufferp) buf_Release(bufferp);
3961 /* apply and free last set of patches; if not doing a star match, this
3962 * will be empty, but better safe (and freeing everything) than sorry.
3964 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
3967 /* now put out the final parameters */
3968 if (returnedNames == 0) eos = 1;
3969 if (p->opcode == 1) {
3971 outp->parmsp[0] = (unsigned short) dsp->cookie;
3972 outp->parmsp[1] = returnedNames;
3973 outp->parmsp[2] = eos;
3974 outp->parmsp[3] = 0; /* nothing wrong with EAS */
3975 outp->parmsp[4] = 0;
3976 /* don't need last name to continue
3977 * search, cookie is enough. Normally,
3978 * this is the offset of the file name
3979 * of the last entry returned.
3981 outp->totalParms = 10; /* in bytes */
3985 outp->parmsp[0] = returnedNames;
3986 outp->parmsp[1] = eos;
3987 outp->parmsp[2] = 0; /* EAS error */
3988 outp->parmsp[3] = 0; /* last name, as above */
3989 outp->totalParms = 8; /* in bytes */
3992 /* return # of bytes in the buffer */
3993 outp->totalData = bytesInBuffer;
3995 osi_Log2(smb_logp, "T2 search dir done, %d names, code %d",
3996 returnedNames, code);
3998 /* Return error code if unsuccessful on first request */
3999 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4000 code = CM_ERROR_NOSUCHFILE;
4002 /* if we're supposed to close the search after this request, or if
4003 * we're supposed to close the search if we're done, and we're done,
4004 * or if something went wrong, close the search.
4006 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4007 if ((searchFlags & 1) || (returnedNames == 0) ||
4008 ((searchFlags & 2) && eos) || code != 0)
4009 smb_DeleteDirSearch(dsp);
4011 smb_SendTran2Error(vcp, p, opx, code);
4013 smb_SendTran2Packet(vcp, outp, opx);
4015 smb_FreeTran2Packet(outp);
4016 smb_ReleaseDirSearch(dsp);
4017 cm_ReleaseSCache(scp);
4018 cm_ReleaseUser(userp);
4022 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4025 smb_dirSearch_t *dsp;
4027 dirHandle = smb_GetSMBParm(inp, 0);
4029 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4031 dsp = smb_FindDirSearch(dirHandle);
4034 return CM_ERROR_BADFD;
4036 /* otherwise, we have an FD to destroy */
4037 smb_DeleteDirSearch(dsp);
4038 smb_ReleaseDirSearch(dsp);
4040 /* and return results */
4041 smb_SetSMBDataLength(outp, 0);
4046 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4048 smb_SetSMBDataLength(outp, 0);
4052 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4059 cm_scache_t *dscp; /* dir we're dealing with */
4060 cm_scache_t *scp; /* file we're creating */
4062 int initialModeBits;
4072 int parmSlot; /* which parm we're dealing with */
4080 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4081 openFun = smb_GetSMBParm(inp, 8); /* open function */
4082 excl = ((openFun & 3) == 0);
4083 trunc = ((openFun & 3) == 2); /* truncate it */
4084 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4085 openAction = 0; /* tracks what we did */
4087 attributes = smb_GetSMBParm(inp, 5);
4088 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4090 /* compute initial mode bits based on read-only flag in attributes */
4091 initialModeBits = 0666;
4092 if (attributes & 1) initialModeBits &= ~0222;
4094 pathp = smb_GetSMBData(inp, NULL);
4096 spacep = inp->spacep;
4097 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4099 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4100 /* special case magic file name for receiving IOCTL requests
4101 * (since IOCTL calls themselves aren't getting through).
4104 osi_Log0(smb_logp, "IOCTL Open");
4107 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4108 smb_SetupIoctlFid(fidp, spacep);
4110 /* set inp->fid so that later read calls in same msg can find fid */
4111 inp->fid = fidp->fid;
4113 /* copy out remainder of the parms */
4115 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4117 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4118 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4119 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4120 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4121 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4122 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4123 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4124 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4126 /* and the final "always present" stuff */
4127 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4128 /* next write out the "unique" ID */
4129 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4130 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4131 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4132 smb_SetSMBDataLength(outp, 0);
4134 /* and clean up fid reference */
4135 smb_ReleaseFID(fidp);
4139 #ifdef DEBUG_VERBOSE
4141 char *hexp, *asciip;
4142 asciip = (lastNamep ? lastNamep : pathp );
4143 hexp = osi_HexifyString(asciip);
4144 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4148 userp = smb_GetUser(vcp, inp);
4151 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4153 cm_ReleaseUser(userp);
4154 return CM_ERROR_NOSUCHPATH;
4156 code = cm_NameI(cm_rootSCachep, pathp,
4157 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4158 userp, tidPathp, &req, &scp);
4160 code = cm_NameI(cm_rootSCachep, spacep->data,
4161 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4162 userp, tidPathp, &req, &dscp);
4165 cm_ReleaseUser(userp);
4169 /* otherwise, scp points to the parent directory. Do a lookup,
4170 * and truncate the file if we find it, otherwise we create the
4173 if (!lastNamep) lastNamep = pathp;
4175 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
4177 if (code && code != CM_ERROR_NOSUCHFILE) {
4178 cm_ReleaseSCache(dscp);
4179 cm_ReleaseUser(userp);
4184 /* if we get here, if code is 0, the file exists and is represented by
4185 * scp. Otherwise, we have to create it. The dir may be represented
4186 * by dscp, or we may have found the file directly. If code is non-zero,
4190 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
4192 if (dscp) cm_ReleaseSCache(dscp);
4193 cm_ReleaseSCache(scp);
4194 cm_ReleaseUser(userp);
4199 /* oops, file shouldn't be there */
4200 if (dscp) cm_ReleaseSCache(dscp);
4201 cm_ReleaseSCache(scp);
4202 cm_ReleaseUser(userp);
4203 return CM_ERROR_EXISTS;
4207 setAttr.mask = CM_ATTRMASK_LENGTH;
4208 setAttr.length.LowPart = 0;
4209 setAttr.length.HighPart = 0;
4210 code = cm_SetAttr(scp, &setAttr, userp, &req);
4211 openAction = 3; /* truncated existing file */
4213 else openAction = 1; /* found existing file */
4215 else if (!(openFun & 0x10)) {
4216 /* don't create if not found */
4217 if (dscp) cm_ReleaseSCache(dscp);
4218 cm_ReleaseUser(userp);
4219 return CM_ERROR_NOSUCHFILE;
4222 osi_assert(dscp != NULL);
4223 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
4224 osi_LogSaveString(smb_logp, lastNamep));
4225 openAction = 2; /* created file */
4226 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4227 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
4228 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4230 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4231 smb_NotifyChange(FILE_ACTION_ADDED,
4232 FILE_NOTIFY_CHANGE_FILE_NAME,
4233 dscp, lastNamep, NULL, TRUE);
4234 if (!excl && code == CM_ERROR_EXISTS) {
4235 /* not an exclusive create, and someone else tried
4236 * creating it already, then we open it anyway. We
4237 * don't bother retrying after this, since if this next
4238 * fails, that means that the file was deleted after we
4239 * started this call.
4241 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4245 setAttr.mask = CM_ATTRMASK_LENGTH;
4246 setAttr.length.LowPart = 0;
4247 setAttr.length.HighPart = 0;
4248 code = cm_SetAttr(scp, &setAttr, userp, &req);
4250 } /* lookup succeeded */
4254 /* we don't need this any longer */
4255 if (dscp) cm_ReleaseSCache(dscp);
4258 /* something went wrong creating or truncating the file */
4259 if (scp) cm_ReleaseSCache(scp);
4260 cm_ReleaseUser(userp);
4264 /* make sure we're about to open a file */
4265 if (scp->fileType != CM_SCACHETYPE_FILE) {
4266 cm_ReleaseSCache(scp);
4267 cm_ReleaseUser(userp);
4268 return CM_ERROR_ISDIR;
4271 /* now all we have to do is open the file itself */
4272 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4275 /* save a pointer to the vnode */
4278 /* compute open mode */
4279 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
4280 if (openMode == 1 || openMode == 2)
4281 fidp->flags |= SMB_FID_OPENWRITE;
4283 smb_ReleaseFID(fidp);
4285 cm_Open(scp, 0, userp);
4287 /* set inp->fid so that later read calls in same msg can find fid */
4288 inp->fid = fidp->fid;
4290 /* copy out remainder of the parms */
4292 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4293 lock_ObtainMutex(&scp->mx);
4295 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
4296 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4297 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
4298 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
4299 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
4300 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
4301 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4302 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4303 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4305 /* and the final "always present" stuff */
4306 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
4307 /* next write out the "unique" ID */
4308 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
4309 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
4310 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4311 lock_ReleaseMutex(&scp->mx);
4312 smb_SetSMBDataLength(outp, 0);
4314 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
4316 cm_ReleaseUser(userp);
4317 /* leave scp held since we put it in fidp->scp */
4321 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4328 unsigned char LockType;
4329 unsigned short NumberOfUnlocks, NumberOfLocks;
4330 unsigned long Timeout;
4332 LARGE_INTEGER LOffset, LLength;
4333 smb_waitingLock_t *waitingLock;
4340 fid = smb_GetSMBParm(inp, 2);
4341 fid = smb_ChainFID(fid, inp);
4343 fidp = smb_FindFID(vcp, fid, 0);
4344 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4345 return CM_ERROR_BADFD;
4347 /* set inp->fid so that later read calls in same msg can find fid */
4350 userp = smb_GetUser(vcp, inp);
4354 lock_ObtainMutex(&scp->mx);
4355 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4356 CM_SCACHESYNC_NEEDCALLBACK
4357 | CM_SCACHESYNC_GETSTATUS
4358 | CM_SCACHESYNC_LOCK);
4359 if (code) goto doneSync;
4361 LockType = smb_GetSMBParm(inp, 3) & 0xff;
4362 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
4363 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
4364 NumberOfLocks = smb_GetSMBParm(inp, 7);
4366 op = smb_GetSMBData(inp, NULL);
4368 for (i=0; i<NumberOfUnlocks; i++) {
4369 if (LockType & 0x10) {
4371 LOffset.HighPart = *((LONG *)(op + 4));
4372 LOffset.LowPart = *((DWORD *)(op + 8));
4373 LLength.HighPart = *((LONG *)(op + 12));
4374 LLength.LowPart = *((DWORD *)(op + 16));
4378 /* Not Large Files */
4379 LOffset.HighPart = 0;
4380 LOffset.LowPart = *((DWORD *)(op + 2));
4381 LLength.HighPart = 0;
4382 LLength.LowPart = *((DWORD *)(op + 6));
4385 if (LargeIntegerNotEqualToZero(LOffset))
4387 /* Do not check length -- length check done in cm_Unlock */
4389 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
4390 if (code) goto done;
4393 for (i=0; i<NumberOfLocks; i++) {
4394 if (LockType & 0x10) {
4396 LOffset.HighPart = *((LONG *)(op + 4));
4397 LOffset.LowPart = *((DWORD *)(op + 8));
4398 LLength.HighPart = *((LONG *)(op + 12));
4399 LLength.LowPart = *((DWORD *)(op + 16));
4403 /* Not Large Files */
4404 LOffset.HighPart = 0;
4405 LOffset.LowPart = *((DWORD *)(op + 2));
4406 LLength.HighPart = 0;
4407 LLength.LowPart = *((DWORD *)(op + 6));
4410 if (LargeIntegerNotEqualToZero(LOffset))
4412 if (LargeIntegerLessThan(LOffset, scp->length))
4415 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
4416 userp, &req, &lockp);
4417 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
4418 /* Put on waiting list */
4419 waitingLock = malloc(sizeof(smb_waitingLock_t));
4420 waitingLock->vcp = vcp;
4421 waitingLock->inp = smb_CopyPacket(inp);
4422 waitingLock->outp = smb_CopyPacket(outp);
4423 waitingLock->timeRemaining = Timeout;
4424 waitingLock->lockp = lockp;
4425 lock_ObtainWrite(&smb_globalLock);
4426 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
4428 osi_Wakeup((long) &smb_allWaitingLocks);
4429 lock_ReleaseWrite(&smb_globalLock);
4430 /* don't send reply immediately */
4431 outp->flags |= SMB_PACKETFLAG_NOSEND;
4437 /* release any locks acquired before the failure */
4440 smb_SetSMBDataLength(outp, 0);
4442 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
4444 lock_ReleaseMutex(&scp->mx);
4445 cm_ReleaseUser(userp);
4446 smb_ReleaseFID(fidp);
4451 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4463 fid = smb_GetSMBParm(inp, 0);
4464 fid = smb_ChainFID(fid, inp);
4466 fidp = smb_FindFID(vcp, fid, 0);
4467 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4468 return CM_ERROR_BADFD;
4471 userp = smb_GetUser(vcp, inp);
4475 /* otherwise, stat the file */
4476 lock_ObtainMutex(&scp->mx);
4477 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4478 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4479 if (code) goto done;
4481 /* decode times. We need a search time, but the response to this
4482 * call provides the date first, not the time, as returned in the
4483 * searchTime variable. So we take the high-order bits first.
4485 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
4486 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
4487 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
4488 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
4489 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
4490 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
4491 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
4493 /* now handle file size and allocation size */
4494 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
4495 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
4496 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
4497 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
4499 /* file attribute */
4500 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
4502 /* and finalize stuff */
4503 smb_SetSMBDataLength(outp, 0);
4507 lock_ReleaseMutex(&scp->mx);
4508 cm_ReleaseUser(userp);
4509 smb_ReleaseFID(fidp);
4513 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4527 fid = smb_GetSMBParm(inp, 0);
4528 fid = smb_ChainFID(fid, inp);
4530 fidp = smb_FindFID(vcp, fid, 0);
4531 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4532 return CM_ERROR_BADFD;
4535 userp = smb_GetUser(vcp, inp);
4539 /* now prepare to call cm_setattr. This message only sets various times,
4540 * and AFS only implements mtime, and we'll set the mtime if that's
4541 * requested. The others we'll ignore.
4543 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
4545 if (searchTime != 0) {
4546 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
4548 if ( unixTime != -1 ) {
4549 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
4550 attrs.clientModTime = unixTime;
4551 code = cm_SetAttr(scp, &attrs, userp, &req);
4553 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
4555 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
4560 cm_ReleaseUser(userp);
4561 smb_ReleaseFID(fidp);
4566 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4569 long count, finalCount;
4576 fd = smb_GetSMBParm(inp, 2);
4577 count = smb_GetSMBParm(inp, 5);
4578 offset.HighPart = 0; /* too bad */
4579 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
4581 osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
4582 fd, offset.LowPart, count);
4584 fd = smb_ChainFID(fd, inp);
4585 fidp = smb_FindFID(vcp, fd, 0);
4587 return CM_ERROR_BADFD;
4589 /* set inp->fid so that later read calls in same msg can find fid */
4592 if (fidp->flags & SMB_FID_IOCTL) {
4593 return smb_IoctlV3Read(fidp, vcp, inp, outp);
4596 userp = smb_GetUser(vcp, inp);
4598 /* 0 and 1 are reserved for request chaining, were setup by our caller,
4599 * and will be further filled in after we return.
4601 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
4602 smb_SetSMBParm(outp, 3, 0); /* resvd */
4603 smb_SetSMBParm(outp, 4, 0); /* resvd */
4604 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
4605 /* fill in #6 when we have all the parameters' space reserved */
4606 smb_SetSMBParm(outp, 7, 0); /* resv'd */
4607 smb_SetSMBParm(outp, 8, 0); /* resv'd */
4608 smb_SetSMBParm(outp, 9, 0); /* resv'd */
4609 smb_SetSMBParm(outp, 10, 0); /* resv'd */
4610 smb_SetSMBParm(outp, 11, 0); /* reserved */
4612 /* get op ptr after putting in the parms, since otherwise we don't
4613 * know where the data really is.
4615 op = smb_GetSMBData(outp, NULL);
4617 /* now fill in offset from start of SMB header to first data byte (to op) */
4618 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
4620 /* set the packet data length the count of the # of bytes */
4621 smb_SetSMBDataLength(outp, count);
4624 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
4626 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
4629 /* fix some things up */
4630 smb_SetSMBParm(outp, 5, finalCount);
4631 smb_SetSMBDataLength(outp, finalCount);
4633 smb_ReleaseFID(fidp);
4635 cm_ReleaseUser(userp);
4640 * Values for createDisp, copied from NTDDK.H
4642 * FILE_SUPERSEDE 0 (???)
4643 * FILE_OPEN 1 (open)
4644 * FILE_CREATE 2 (exclusive)
4645 * FILE_OPEN_IF 3 (non-exclusive)
4646 * FILE_OVERWRITE 4 (open & truncate, but do not create)
4647 * FILE_OVERWRITE_IF 5 (open & truncate, or create)
4650 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4652 char *pathp, *realPathp;
4656 cm_scache_t *dscp; /* parent dir */
4657 cm_scache_t *scp; /* file to create or open */
4661 unsigned short nameLength;
4663 unsigned int requestOpLock;
4664 unsigned int requestBatchOpLock;
4665 unsigned int mustBeDir;
4666 unsigned int treeCreate;
4668 unsigned int desiredAccess;
4669 unsigned int extAttributes;
4670 unsigned int createDisp;
4671 unsigned int createOptions;
4672 int initialModeBits;
4673 unsigned short baseFid;
4674 smb_fid_t *baseFidp;
4676 cm_scache_t *baseDirp;
4677 unsigned short openAction;
4692 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
4693 flags = smb_GetSMBOffsetParm(inp, 3, 1)
4694 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
4695 requestOpLock = flags & 0x02;
4696 requestBatchOpLock = flags & 0x04;
4697 mustBeDir = flags & 0x08;
4700 * Why all of a sudden 32-bit FID?
4701 * We will reject all bits higher than 16.
4703 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
4704 return CM_ERROR_INVAL;
4705 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
4706 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
4707 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
4708 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
4709 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
4710 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
4711 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
4712 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
4713 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
4715 /* mustBeDir is never set; createOptions directory bit seems to be
4718 if (createOptions & 1)
4720 else if (createOptions & 0x40)
4726 * compute initial mode bits based on read-only flag in
4727 * extended attributes
4729 initialModeBits = 0666;
4730 if (extAttributes & 1) initialModeBits &= ~0222;
4732 pathp = smb_GetSMBData(inp, NULL);
4733 /* Sometimes path is not null-terminated, so we make a copy. */
4734 realPathp = malloc(nameLength+1);
4735 memcpy(realPathp, pathp, nameLength);
4736 realPathp[nameLength] = 0;
4738 spacep = inp->spacep;
4739 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
4741 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
4742 osi_Log4(smb_logp,"NTCreateX da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
4743 osi_Log1(smb_logp,"NTCreateX lastNamep=[%s]",osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
4745 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4746 /* special case magic file name for receiving IOCTL requests
4747 * (since IOCTL calls themselves aren't getting through).
4749 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4750 smb_SetupIoctlFid(fidp, spacep);
4751 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
4753 /* set inp->fid so that later read calls in same msg can find fid */
4754 inp->fid = fidp->fid;
4758 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
4759 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4760 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
4762 memset(&ft, 0, sizeof(ft));
4763 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4764 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4765 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4766 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4767 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
4768 sz.HighPart = 0x7fff; sz.LowPart = 0;
4769 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
4770 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
4771 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
4772 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
4773 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
4774 smb_SetSMBDataLength(outp, 0);
4776 /* clean up fid reference */
4777 smb_ReleaseFID(fidp);
4782 #ifdef DEBUG_VERBOSE
4784 char *hexp, *asciip;
4785 asciip = (lastNamep? lastNamep : realPathp);
4786 hexp = osi_HexifyString( asciip );
4787 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
4791 userp = smb_GetUser(vcp, inp);
4793 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
4795 return CM_ERROR_INVAL;
4799 baseDirp = cm_rootSCachep;
4800 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4801 if(code == CM_ERROR_TIDIPC) {
4802 /* Attempt to use a TID allocated for IPC. The client
4803 is probably looking for DCE RPC end points which we
4805 osi_Log0(smb_logp, "NTCreateX received IPC TID");
4807 cm_ReleaseUser(userp);
4808 return CM_ERROR_NOSUCHFILE;
4812 baseFidp = smb_FindFID(vcp, baseFid, 0);
4814 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
4816 cm_ReleaseUser(userp);
4817 return CM_ERROR_INVAL;
4819 baseDirp = baseFidp->scp;
4823 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
4825 /* compute open mode */
4827 if (desiredAccess & DELETE)
4828 fidflags |= SMB_FID_OPENDELETE;
4829 if (desiredAccess & AFS_ACCESS_READ)
4830 fidflags |= SMB_FID_OPENREAD;
4831 if (desiredAccess & AFS_ACCESS_WRITE)
4832 fidflags |= SMB_FID_OPENWRITE;
4836 /* For an exclusive create, we want to do a case sensitive match for the last component. */
4837 if (createDisp == 2 || createDisp == 4 || createDisp == 5) {
4838 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4839 userp, tidPathp, &req, &dscp);
4841 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
4843 if (code == CM_ERROR_NOSUCHFILE) {
4844 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
4845 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
4846 if (code == 0 && realDirFlag == 1) {
4847 cm_ReleaseSCache(scp);
4848 cm_ReleaseSCache(dscp);
4849 cm_ReleaseUser(userp);
4851 return CM_ERROR_EXISTS;
4857 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4858 userp, tidPathp, &req, &scp);
4863 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
4864 /* look up parent directory */
4865 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
4866 * the immediate parent. We have to work our way up realPathp until we hit something that we
4874 code = cm_NameI(baseDirp, spacep->data,
4875 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4876 userp, tidPathp, &req, &dscp);
4879 (tp = strrchr(spacep->data,'\\')) &&
4880 (createDisp == 2) &&
4881 (realDirFlag == 1)) {
4884 treeStartp = realPathp + (tp - spacep->data);
4886 if (*tp && !smb_IsLegalFilename(tp)) {
4888 smb_ReleaseFID(baseFidp);
4889 cm_ReleaseUser(userp);
4891 return CM_ERROR_BADNTFILENAME;
4901 smb_ReleaseFID(baseFidp);
4904 osi_Log0(smb_logp,"NTCreateX parent not found");
4905 cm_ReleaseUser(userp);
4910 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
4911 /* A file exists where we want a directory. */
4912 cm_ReleaseSCache(dscp);
4913 cm_ReleaseUser(userp);
4915 return CM_ERROR_EXISTS;
4919 lastNamep = realPathp;
4923 if (!smb_IsLegalFilename(lastNamep)) {
4924 cm_ReleaseSCache(dscp);
4925 cm_ReleaseUser(userp);
4927 return CM_ERROR_BADNTFILENAME;
4930 if (!foundscp && !treeCreate) {
4931 if (createDisp == 2 || createDisp == 4)
4932 code = cm_Lookup(dscp, lastNamep,
4933 CM_FLAG_FOLLOW, userp, &req, &scp);
4935 code = cm_Lookup(dscp, lastNamep,
4936 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4938 if (code && code != CM_ERROR_NOSUCHFILE) {
4939 cm_ReleaseSCache(dscp);
4940 cm_ReleaseUser(userp);
4948 smb_ReleaseFID(baseFidp);
4951 /* if we get here, if code is 0, the file exists and is represented by
4952 * scp. Otherwise, we have to create it. The dir may be represented
4953 * by dscp, or we may have found the file directly. If code is non-zero,
4956 if (code == 0 && !treeCreate) {
4957 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
4960 if (dscp) cm_ReleaseSCache(dscp);
4961 cm_ReleaseSCache(scp);
4962 cm_ReleaseUser(userp);
4967 if (createDisp == 2) {
4968 /* oops, file shouldn't be there */
4969 if (dscp) cm_ReleaseSCache(dscp);
4970 cm_ReleaseSCache(scp);
4971 cm_ReleaseUser(userp);
4973 return CM_ERROR_EXISTS;
4977 || createDisp == 5) {
4978 setAttr.mask = CM_ATTRMASK_LENGTH;
4979 setAttr.length.LowPart = 0;
4980 setAttr.length.HighPart = 0;
4981 code = cm_SetAttr(scp, &setAttr, userp, &req);
4982 openAction = 3; /* truncated existing file */
4984 else openAction = 1; /* found existing file */
4986 else if (createDisp == 1 || createDisp == 4) {
4987 /* don't create if not found */
4988 if (dscp) cm_ReleaseSCache(dscp);
4989 cm_ReleaseUser(userp);
4991 return CM_ERROR_NOSUCHFILE;
4993 else if (realDirFlag == 0 || realDirFlag == -1) {
4994 osi_assert(dscp != NULL);
4995 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
4996 osi_LogSaveString(smb_logp, lastNamep));
4997 openAction = 2; /* created file */
4998 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4999 setAttr.clientModTime = time(NULL);
5000 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5002 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5003 smb_NotifyChange(FILE_ACTION_ADDED,
5004 FILE_NOTIFY_CHANGE_FILE_NAME,
5005 dscp, lastNamep, NULL, TRUE);
5006 if (code == CM_ERROR_EXISTS && createDisp != 2) {
5007 /* Not an exclusive create, and someone else tried
5008 * creating it already, then we open it anyway. We
5009 * don't bother retrying after this, since if this next
5010 * fails, that means that the file was deleted after we
5011 * started this call.
5013 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5016 if (createDisp == 5) {
5017 setAttr.mask = CM_ATTRMASK_LENGTH;
5018 setAttr.length.LowPart = 0;
5019 setAttr.length.HighPart = 0;
5020 code = cm_SetAttr(scp, &setAttr, userp,
5023 } /* lookup succeeded */
5028 char *cp; /* This component */
5029 int clen = 0; /* length of component */
5033 /* create directory */
5034 if ( !treeCreate ) treeStartp = lastNamep;
5035 osi_assert(dscp != NULL);
5036 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
5037 osi_LogSaveString(smb_logp, treeStartp));
5038 openAction = 2; /* created directory */
5040 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5041 setAttr.clientModTime = time(NULL);
5048 tp = strchr(pp, '\\');
5052 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
5056 strncpy(cp,pp,clen);
5062 if (clen == 0) continue; /* the supplied path can't have consecutive slashes either , but */
5064 /* cp is the next component to be created. */
5065 code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
5066 if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
5067 smb_NotifyChange(FILE_ACTION_ADDED,
5068 FILE_NOTIFY_CHANGE_DIR_NAME,
5069 tscp, cp, NULL, TRUE);
5071 (code == CM_ERROR_EXISTS && createDisp != 2)) {
5072 /* Not an exclusive create, and someone else tried
5073 * creating it already, then we open it anyway. We
5074 * don't bother retrying after this, since if this next
5075 * fails, that means that the file was deleted after we
5076 * started this call.
5078 code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
5083 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
5084 cm_ReleaseSCache(tscp);
5085 tscp = scp; /* Newly created directory will be next parent */
5090 if we get here and code == 0, then scp is the last directory created, and tscp is the
5091 parent of scp. dscp got released if dscp != tscp. both tscp and scp are held.
5097 /* something went wrong creating or truncating the file */
5098 if (scp) cm_ReleaseSCache(scp);
5099 if (dscp) cm_ReleaseSCache(dscp);
5100 cm_ReleaseUser(userp);
5105 /* make sure we have file vs. dir right (only applies for single component case) */
5106 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5107 cm_ReleaseSCache(scp);
5108 if (dscp) cm_ReleaseSCache(dscp);
5109 cm_ReleaseUser(userp);
5111 return CM_ERROR_ISDIR;
5113 /* (only applies to single component case) */
5114 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5115 cm_ReleaseSCache(scp);
5116 if (dscp) cm_ReleaseSCache(dscp);
5117 cm_ReleaseUser(userp);
5119 return CM_ERROR_NOTDIR;
5122 /* open the file itself */
5123 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5125 /* save a pointer to the vnode */
5128 fidp->flags = fidflags;
5130 /* save parent dir and pathname for delete or change notification */
5131 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5132 fidp->flags |= SMB_FID_NTOPEN;
5133 fidp->NTopen_dscp = dscp;
5134 cm_HoldSCache(dscp);
5135 fidp->NTopen_pathp = strdup(lastNamep);
5137 fidp->NTopen_wholepathp = realPathp;
5139 /* we don't need this any longer */
5140 if (dscp) cm_ReleaseSCache(dscp);
5141 cm_Open(scp, 0, userp);
5143 /* set inp->fid so that later read calls in same msg can find fid */
5144 inp->fid = fidp->fid;
5148 lock_ObtainMutex(&scp->mx);
5149 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5150 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5151 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
5152 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5153 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5154 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5155 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5156 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5157 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
5159 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5160 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5161 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
5162 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
5163 smb_SetSMBParmByte(outp, parmSlot,
5164 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
5165 lock_ReleaseMutex(&scp->mx);
5166 smb_SetSMBDataLength(outp, 0);
5168 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
5169 osi_LogSaveString(smb_logp, realPathp));
5171 smb_ReleaseFID(fidp);
5173 cm_ReleaseUser(userp);
5175 /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
5177 /* leave scp held since we put it in fidp->scp */
5182 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
5183 * Instead, ultimately, would like to use a subroutine for common code.
5185 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5187 char *pathp, *realPathp;
5191 cm_scache_t *dscp; /* parent dir */
5192 cm_scache_t *scp; /* file to create or open */
5195 unsigned long nameLength;
5197 unsigned int requestOpLock;
5198 unsigned int requestBatchOpLock;
5199 unsigned int mustBeDir;
5200 unsigned int extendedRespRequired;
5202 unsigned int desiredAccess;
5203 #ifdef DEBUG_VERBOSE
5204 unsigned int allocSize;
5205 unsigned int shareAccess;
5207 unsigned int extAttributes;
5208 unsigned int createDisp;
5209 #ifdef DEBUG_VERBOSE
5212 unsigned int createOptions;
5213 int initialModeBits;
5214 unsigned short baseFid;
5215 smb_fid_t *baseFidp;
5217 cm_scache_t *baseDirp;
5218 unsigned short openAction;
5224 int parmOffset, dataOffset;
5235 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
5236 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
5237 parmp = inp->data + parmOffset;
5238 lparmp = (ULONG *) parmp;
5241 requestOpLock = flags & 0x02;
5242 requestBatchOpLock = flags & 0x04;
5243 mustBeDir = flags & 0x08;
5244 extendedRespRequired = flags & 0x10;
5247 * Why all of a sudden 32-bit FID?
5248 * We will reject all bits higher than 16.
5250 if (lparmp[1] & 0xFFFF0000)
5251 return CM_ERROR_INVAL;
5252 baseFid = (unsigned short)lparmp[1];
5253 desiredAccess = lparmp[2];
5254 #ifdef DEBUG_VERBOSE
5255 allocSize = lparmp[3];
5256 #endif /* DEBUG_VERSOSE */
5257 extAttributes = lparmp[5];
5259 shareAccess = lparmp[6];
5261 createDisp = lparmp[7];
5262 createOptions = lparmp[8];
5263 #ifdef DEBUG_VERBOSE
5266 nameLength = lparmp[11];
5268 #ifdef DEBUG_VERBOSE
5269 osi_Log4(smb_logp,"NTTransCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
5270 osi_Log2(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
5271 osi_Log1(smb_logp,"... flags[%x]",flags);
5274 /* mustBeDir is never set; createOptions directory bit seems to be
5277 if (createOptions & 1)
5279 else if (createOptions & 0x40)
5285 * compute initial mode bits based on read-only flag in
5286 * extended attributes
5288 initialModeBits = 0666;
5289 if (extAttributes & 1) initialModeBits &= ~0222;
5291 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
5292 /* Sometimes path is not null-terminated, so we make a copy. */
5293 realPathp = malloc(nameLength+1);
5294 memcpy(realPathp, pathp, nameLength);
5295 realPathp[nameLength] = 0;
5297 spacep = cm_GetSpace();
5298 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5301 * Nothing here to handle SMB_IOCTL_FILENAME.
5302 * Will add it if necessary.
5305 #ifdef DEBUG_VERBOSE
5307 char *hexp, *asciip;
5308 asciip = (lastNamep? lastNamep : realPathp);
5309 hexp = osi_HexifyString( asciip );
5310 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
5315 userp = smb_GetUser(vcp, inp);
5317 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
5319 return CM_ERROR_INVAL;
5323 baseDirp = cm_rootSCachep;
5324 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5325 if(code == CM_ERROR_TIDIPC) {
5326 /* Attempt to use TID allocated for IPC. The client is
5327 probably trying to locate DCE RPC endpoints, which we
5329 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
5331 cm_ReleaseUser(userp);
5332 return CM_ERROR_NOSUCHPATH;
5336 baseFidp = smb_FindFID(vcp, baseFid, 0);
5338 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
5340 cm_ReleaseUser(userp);
5341 return CM_ERROR_INVAL;
5343 baseDirp = baseFidp->scp;
5347 /* compute open mode */
5349 if (desiredAccess & DELETE)
5350 fidflags |= SMB_FID_OPENDELETE;
5351 if (desiredAccess & AFS_ACCESS_READ)
5352 fidflags |= SMB_FID_OPENREAD;
5353 if (desiredAccess & AFS_ACCESS_WRITE)
5354 fidflags |= SMB_FID_OPENWRITE;
5358 if (createDisp == 2 || createDisp == 4 || createDisp == 5) {
5359 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5360 userp, tidPathp, &req, &dscp);
5362 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5364 if (code == CM_ERROR_NOSUCHFILE) {
5365 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
5366 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
5367 if (code == 0 && realDirFlag == 1) {
5368 cm_ReleaseSCache(scp);
5369 cm_ReleaseSCache(dscp);
5370 cm_ReleaseUser(userp);
5372 return CM_ERROR_EXISTS;
5378 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5379 userp, tidPathp, &req, &scp);
5382 if (code == 0) foundscp = TRUE;
5384 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
5385 /* look up parent directory */
5387 code = cm_NameI(baseDirp, spacep->data,
5388 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5389 userp, tidPathp, &req, &dscp);
5393 cm_FreeSpace(spacep);
5396 smb_ReleaseFID(baseFidp);
5401 cm_ReleaseUser(userp);
5406 if (!lastNamep) lastNamep = realPathp;
5409 if (!smb_IsLegalFilename(lastNamep))
5410 return CM_ERROR_BADNTFILENAME;
5413 if (createDisp == 2 || createDisp == 4)
5414 code = cm_Lookup(dscp, lastNamep,
5415 CM_FLAG_FOLLOW, userp, &req, &scp);
5417 code = cm_Lookup(dscp, lastNamep,
5418 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5420 if (code && code != CM_ERROR_NOSUCHFILE) {
5421 cm_ReleaseSCache(dscp);
5422 cm_ReleaseUser(userp);
5430 smb_ReleaseFID(baseFidp);
5433 cm_FreeSpace(spacep);
5436 /* if we get here, if code is 0, the file exists and is represented by
5437 * scp. Otherwise, we have to create it. The dir may be represented
5438 * by dscp, or we may have found the file directly. If code is non-zero,
5442 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
5445 if (dscp) cm_ReleaseSCache(dscp);
5446 cm_ReleaseSCache(scp);
5447 cm_ReleaseUser(userp);
5452 if (createDisp == 2) {
5453 /* oops, file shouldn't be there */
5454 if (dscp) cm_ReleaseSCache(dscp);
5455 cm_ReleaseSCache(scp);
5456 cm_ReleaseUser(userp);
5458 return CM_ERROR_EXISTS;
5462 || createDisp == 5) {
5463 setAttr.mask = CM_ATTRMASK_LENGTH;
5464 setAttr.length.LowPart = 0;
5465 setAttr.length.HighPart = 0;
5466 code = cm_SetAttr(scp, &setAttr, userp, &req);
5467 openAction = 3; /* truncated existing file */
5469 else openAction = 1; /* found existing file */
5471 else if (createDisp == 1 || createDisp == 4) {
5472 /* don't create if not found */
5473 if (dscp) cm_ReleaseSCache(dscp);
5474 cm_ReleaseUser(userp);
5476 return CM_ERROR_NOSUCHFILE;
5478 else if (realDirFlag == 0 || realDirFlag == -1) {
5479 osi_assert(dscp != NULL);
5480 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
5481 osi_LogSaveString(smb_logp, lastNamep));
5482 openAction = 2; /* created file */
5483 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5484 setAttr.clientModTime = time(NULL);
5485 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5487 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5488 smb_NotifyChange(FILE_ACTION_ADDED,
5489 FILE_NOTIFY_CHANGE_FILE_NAME,
5490 dscp, lastNamep, NULL, TRUE);
5491 if (code == CM_ERROR_EXISTS && createDisp != 2) {
5492 /* Not an exclusive create, and someone else tried
5493 * creating it already, then we open it anyway. We
5494 * don't bother retrying after this, since if this next
5495 * fails, that means that the file was deleted after we
5496 * started this call.
5498 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5501 if (createDisp == 5) {
5502 setAttr.mask = CM_ATTRMASK_LENGTH;
5503 setAttr.length.LowPart = 0;
5504 setAttr.length.HighPart = 0;
5505 code = cm_SetAttr(scp, &setAttr, userp,
5508 } /* lookup succeeded */
5512 /* create directory */
5513 osi_assert(dscp != NULL);
5515 "smb_ReceiveNTTranCreate creating directory %s",
5516 osi_LogSaveString(smb_logp, lastNamep));
5517 openAction = 2; /* created directory */
5518 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5519 setAttr.clientModTime = time(NULL);
5520 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5521 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5522 smb_NotifyChange(FILE_ACTION_ADDED,
5523 FILE_NOTIFY_CHANGE_DIR_NAME,
5524 dscp, lastNamep, NULL, TRUE);
5526 || (code == CM_ERROR_EXISTS && createDisp != 2)) {
5527 /* Not an exclusive create, and someone else tried
5528 * creating it already, then we open it anyway. We
5529 * don't bother retrying after this, since if this next
5530 * fails, that means that the file was deleted after we
5531 * started this call.
5533 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5539 /* something went wrong creating or truncating the file */
5540 if (scp) cm_ReleaseSCache(scp);
5541 cm_ReleaseUser(userp);
5546 /* make sure we have file vs. dir right */
5547 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5548 cm_ReleaseSCache(scp);
5549 cm_ReleaseUser(userp);
5551 return CM_ERROR_ISDIR;
5553 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5554 cm_ReleaseSCache(scp);
5555 cm_ReleaseUser(userp);
5557 return CM_ERROR_NOTDIR;
5560 /* open the file itself */
5561 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5564 /* save a pointer to the vnode */
5567 fidp->flags = fidflags;
5569 /* save parent dir and pathname for deletion or change notification */
5570 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5571 fidp->flags |= SMB_FID_NTOPEN;
5572 fidp->NTopen_dscp = dscp;
5573 cm_HoldSCache(dscp);
5574 fidp->NTopen_pathp = strdup(lastNamep);
5576 fidp->NTopen_wholepathp = realPathp;
5578 /* we don't need this any longer */
5579 if (dscp) cm_ReleaseSCache(dscp);
5581 cm_Open(scp, 0, userp);
5583 /* set inp->fid so that later read calls in same msg can find fid */
5584 inp->fid = fidp->fid;
5586 /* check whether we are required to send an extended response */
5587 if (!extendedRespRequired) {
5589 parmOffset = 8*4 + 39;
5590 parmOffset += 1; /* pad to 4 */
5591 dataOffset = parmOffset + 70;
5595 /* Total Parameter Count */
5596 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
5597 /* Total Data Count */
5598 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5599 /* Parameter Count */
5600 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
5601 /* Parameter Offset */
5602 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5603 /* Parameter Displacement */
5604 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5606 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5608 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5609 /* Data Displacement */
5610 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5611 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5612 smb_SetSMBDataLength(outp, 70);
5614 lock_ObtainMutex(&scp->mx);
5615 outData = smb_GetSMBData(outp, NULL);
5616 outData++; /* round to get to parmOffset */
5617 *outData = 0; outData++; /* oplock */
5618 *outData = 0; outData++; /* reserved */
5619 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
5620 *((ULONG *)outData) = openAction; outData += 4;
5621 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
5622 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5623 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
5624 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
5625 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
5626 *((FILETIME *)outData) = ft; outData += 8; /* change time */
5627 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
5628 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
5629 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
5630 *((USHORT *)outData) = 0; outData += 2; /* filetype */
5631 *((USHORT *)outData) = 0; outData += 2; /* dev state */
5632 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
5633 outData += 2; /* is a dir? */
5634 lock_ReleaseMutex(&scp->mx);
5637 parmOffset = 8*4 + 39;
5638 parmOffset += 1; /* pad to 4 */
5639 dataOffset = parmOffset + 104;
5643 /* Total Parameter Count */
5644 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
5645 /* Total Data Count */
5646 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5647 /* Parameter Count */
5648 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
5649 /* Parameter Offset */
5650 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5651 /* Parameter Displacement */
5652 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5654 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5656 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5657 /* Data Displacement */
5658 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5659 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5660 smb_SetSMBDataLength(outp, 105);
5662 lock_ObtainMutex(&scp->mx);
5663 outData = smb_GetSMBData(outp, NULL);
5664 outData++; /* round to get to parmOffset */
5665 *outData = 0; outData++; /* oplock */
5666 *outData = 1; outData++; /* response type */
5667 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
5668 *((ULONG *)outData) = openAction; outData += 4;
5669 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
5670 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5671 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
5672 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
5673 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
5674 *((FILETIME *)outData) = ft; outData += 8; /* change time */
5675 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
5676 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
5677 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
5678 *((USHORT *)outData) = 0; outData += 2; /* filetype */
5679 *((USHORT *)outData) = 0; outData += 2; /* dev state */
5680 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
5681 outData += 1; /* is a dir? */
5682 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
5683 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
5684 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
5685 lock_ReleaseMutex(&scp->mx);
5688 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
5690 smb_ReleaseFID(fidp);
5692 cm_ReleaseUser(userp);
5694 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
5695 /* leave scp held since we put it in fidp->scp */
5699 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
5702 smb_packet_t *savedPacketp;
5703 ULONG filter; USHORT fid, watchtree;
5707 filter = smb_GetSMBParm(inp, 19)
5708 | (smb_GetSMBParm(inp, 20) << 16);
5709 fid = smb_GetSMBParm(inp, 21);
5710 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
5712 fidp = smb_FindFID(vcp, fid, 0);
5714 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
5715 return CM_ERROR_BADFD;
5718 savedPacketp = smb_CopyPacket(inp);
5720 savedPacketp->vcp = vcp;
5721 lock_ObtainMutex(&smb_Dir_Watch_Lock);
5722 savedPacketp->nextp = smb_Directory_Watches;
5723 smb_Directory_Watches = savedPacketp;
5724 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
5726 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
5727 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
5730 lock_ObtainMutex(&scp->mx);
5732 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
5734 scp->flags |= CM_SCACHEFLAG_WATCHED;
5735 lock_ReleaseMutex(&scp->mx);
5736 smb_ReleaseFID(fidp);
5738 outp->flags |= SMB_PACKETFLAG_NOSEND;
5742 unsigned char nullSecurityDesc[36] = {
5743 0x01, /* security descriptor revision */
5744 0x00, /* reserved, should be zero */
5745 0x00, 0x80, /* security descriptor control;
5746 * 0x8000 : self-relative format */
5747 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
5748 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
5749 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
5750 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
5751 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5752 /* "null SID" owner SID */
5753 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5754 /* "null SID" group SID */
5757 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5759 int parmOffset, parmCount, dataOffset, dataCount;
5767 ULONG securityInformation;
5769 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
5770 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
5771 parmp = inp->data + parmOffset;
5772 sparmp = (USHORT *) parmp;
5773 lparmp = (ULONG *) parmp;
5776 securityInformation = lparmp[1];
5778 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
5779 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
5787 parmOffset = 8*4 + 39;
5788 parmOffset += 1; /* pad to 4 */
5790 dataOffset = parmOffset + parmCount;
5794 /* Total Parameter Count */
5795 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
5796 /* Total Data Count */
5797 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
5798 /* Parameter Count */
5799 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
5800 /* Parameter Offset */
5801 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5802 /* Parameter Displacement */
5803 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5805 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
5807 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5808 /* Data Displacement */
5809 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5810 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5811 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
5813 outData = smb_GetSMBData(outp, NULL);
5814 outData++; /* round to get to parmOffset */
5815 *((ULONG *)outData) = 36; outData += 4; /* length */
5817 if (maxData >= 36) {
5818 memcpy(outData, nullSecurityDesc, 36);
5822 return CM_ERROR_BUFFERTOOSMALL;
5825 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5827 unsigned short function;
5829 function = smb_GetSMBParm(inp, 18);
5831 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
5833 /* We can handle long names */
5834 if (vcp->flags & SMB_VCFLAG_USENT)
5835 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
5839 case 6: return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
5841 case 4: return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
5843 case 1: return smb_ReceiveNTTranCreate(vcp, inp, outp);
5845 default: return CM_ERROR_INVAL;
5850 * smb_NotifyChange -- find relevant change notification messages and
5853 * If we don't know the file name (i.e. a callback break), filename is
5854 * NULL, and we return a zero-length list.
5856 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
5857 cm_scache_t *dscp, char *filename, char *otherFilename,
5858 BOOL isDirectParent)
5860 smb_packet_t *watch, *lastWatch, *nextWatch;
5861 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
5862 char *outData, *oldOutData;
5866 BOOL twoEntries = FALSE;
5867 ULONG otherNameLen, oldParmCount = 0;
5872 /* Get ready for rename within directory */
5873 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
5875 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
5878 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
5879 osi_LogSaveString(smb_logp,filename),dscp);
5881 lock_ObtainMutex(&smb_Dir_Watch_Lock);
5882 watch = smb_Directory_Watches;
5884 filter = smb_GetSMBParm(watch, 19)
5885 | (smb_GetSMBParm(watch, 20) << 16);
5886 fid = smb_GetSMBParm(watch, 21);
5887 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
5888 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
5889 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
5893 * Strange hack - bug in NT Client and NT Server that we
5896 if (filter == 3 && wtree)
5899 fidp = smb_FindFID(vcp, fid, 0);
5901 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
5903 watch = watch->nextp;
5906 if (fidp->scp != dscp
5907 || (filter & notifyFilter) == 0
5908 || (!isDirectParent && !wtree)) {
5909 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
5910 smb_ReleaseFID(fidp);
5912 watch = watch->nextp;
5915 smb_ReleaseFID(fidp);
5918 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
5919 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
5921 nextWatch = watch->nextp;
5922 if (watch == smb_Directory_Watches)
5923 smb_Directory_Watches = nextWatch;
5925 lastWatch->nextp = nextWatch;
5927 /* Turn off WATCHED flag in dscp */
5928 lock_ObtainMutex(&dscp->mx);
5930 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
5932 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
5933 lock_ReleaseMutex(&dscp->mx);
5935 /* Convert to response packet */
5936 ((smb_t *) watch)->reb = 0x80;
5937 ((smb_t *) watch)->wct = 0;
5940 if (filename == NULL)
5943 nameLen = strlen(filename);
5944 parmCount = 3*4 + nameLen*2;
5945 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
5947 otherNameLen = strlen(otherFilename);
5948 oldParmCount = parmCount;
5949 parmCount += 3*4 + otherNameLen*2;
5950 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
5952 if (maxLen < parmCount)
5953 parmCount = 0; /* not enough room */
5955 parmOffset = 8*4 + 39;
5956 parmOffset += 1; /* pad to 4 */
5957 dataOffset = parmOffset + parmCount;
5961 /* Total Parameter Count */
5962 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
5963 /* Total Data Count */
5964 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
5965 /* Parameter Count */
5966 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
5967 /* Parameter Offset */
5968 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
5969 /* Parameter Displacement */
5970 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
5972 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
5974 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
5975 /* Data Displacement */
5976 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
5977 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
5978 smb_SetSMBDataLength(watch, parmCount + 1);
5980 if (parmCount != 0) {
5981 outData = smb_GetSMBData(watch, NULL);
5982 outData++; /* round to get to parmOffset */
5983 oldOutData = outData;
5984 *((DWORD *)outData) = oldParmCount; outData += 4;
5985 /* Next Entry Offset */
5986 *((DWORD *)outData) = action; outData += 4;
5988 *((DWORD *)outData) = nameLen*2; outData += 4;
5989 /* File Name Length */
5990 mbstowcs((WCHAR *)outData, filename, nameLen);
5993 outData = oldOutData + oldParmCount;
5994 *((DWORD *)outData) = 0; outData += 4;
5995 /* Next Entry Offset */
5996 *((DWORD *)outData) = otherAction; outData += 4;
5998 *((DWORD *)outData) = otherNameLen*2;
5999 outData += 4; /* File Name Length */
6000 mbstowcs((WCHAR *)outData, otherFilename,
6001 otherNameLen); /* File Name */
6006 * If filename is null, we don't know the cause of the
6007 * change notification. We return zero data (see above),
6008 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
6009 * (= 0x010C). We set the error code here by hand, without
6010 * modifying wct and bcc.
6012 if (filename == NULL) {
6013 ((smb_t *) watch)->rcls = 0x0C;
6014 ((smb_t *) watch)->reh = 0x01;
6015 ((smb_t *) watch)->errLow = 0;
6016 ((smb_t *) watch)->errHigh = 0;
6017 /* Set NT Status codes flag */
6018 ((smb_t *) watch)->flg2 |= 0x4000;
6021 smb_SendPacket(vcp, watch);
6023 smb_FreePacket(watch);
6026 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6029 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6031 unsigned char *replyWctp;
6032 smb_packet_t *watch, *lastWatch;
6033 USHORT fid, watchtree;
6037 osi_Log0(smb_logp, "SMB3 receive NT cancel");
6039 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6040 watch = smb_Directory_Watches;
6042 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
6043 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
6044 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
6045 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
6046 if (watch == smb_Directory_Watches)
6047 smb_Directory_Watches = watch->nextp;
6049 lastWatch->nextp = watch->nextp;
6050 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6052 /* Turn off WATCHED flag in scp */
6053 fid = smb_GetSMBParm(watch, 21);
6054 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
6056 if (vcp != watch->vcp)
6057 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
6060 fidp = smb_FindFID(vcp, fid, 0);
6062 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
6064 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
6067 lock_ObtainMutex(&scp->mx);
6069 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6071 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
6072 lock_ReleaseMutex(&scp->mx);
6073 smb_ReleaseFID(fidp);
6075 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
6078 /* assume STATUS32; return 0xC0000120 (CANCELED) */
6079 replyWctp = watch->wctp;
6083 ((smb_t *)watch)->rcls = 0x20;
6084 ((smb_t *)watch)->reh = 0x1;
6085 ((smb_t *)watch)->errLow = 0;
6086 ((smb_t *)watch)->errHigh = 0xC0;
6087 ((smb_t *)watch)->flg2 |= 0x4000;
6088 smb_SendPacket(vcp, watch);
6090 smb_ReleaseVC(watch->vcp);
6091 smb_FreePacket(watch);
6095 watch = watch->nextp;
6097 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6104 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
6107 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
6110 smb_username_t *unp;
6112 unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
6114 lock_ObtainMutex(&unp->mx);
6115 unp->userp = cm_NewUser();
6116 lock_ReleaseMutex(&unp->mx);
6117 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6118 osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
6120 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6121 osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);