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->curData > 0 && asp->curParms > 0 &&
1309 asp->totalData <= asp->curData &&
1310 asp->totalParms <= asp->curParms) {
1311 /* we've received it all */
1312 lock_ObtainWrite(&smb_globalLock);
1313 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1314 lock_ReleaseWrite(&smb_globalLock);
1316 /* now dispatch it */
1317 rapOp = asp->parmsp[0];
1319 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1320 osi_LogEvent("AFS-Dispatch-RAP[%s]",myCrt_RapDispatch(rapOp),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1321 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%x] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1322 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1325 osi_LogEvent("AFS-Dispatch-RAP [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1326 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1327 code = CM_ERROR_BADOP;
1330 /* if an error is returned, we're supposed to send an error packet,
1331 * otherwise the dispatched function already did the data sending.
1332 * We give dispatched proc the responsibility since it knows how much
1333 * space to allocate.
1336 smb_SendTran2Error(vcp, asp, outp, code);
1339 /* free the input tran 2 packet */
1340 lock_ObtainWrite(&smb_globalLock);
1341 smb_FreeTran2Packet(asp);
1342 lock_ReleaseWrite(&smb_globalLock);
1344 else if (firstPacket) {
1345 /* the first packet in a multi-packet request, we need to send an
1346 * ack to get more data.
1348 smb_SetSMBDataLength(outp, 0);
1349 smb_SendPacket(vcp, outp);
1355 /* ANSI versions. The unicode versions support arbitrary length
1356 share names, but we don't support unicode yet. */
1358 typedef struct smb_rap_share_info_0 {
1359 char shi0_netname[13];
1360 } smb_rap_share_info_0_t;
1362 typedef struct smb_rap_share_info_1 {
1363 char shi1_netname[13];
1366 DWORD shi1_remark; /* char *shi1_remark; data offset */
1367 } smb_rap_share_info_1_t;
1369 typedef struct smb_rap_share_info_2 {
1370 char shi2_netname[13];
1372 unsigned short shi2_type;
1373 DWORD shi2_remark; /* char *shi2_remark; data offset */
1374 unsigned short shi2_permissions;
1375 unsigned short shi2_max_uses;
1376 unsigned short shi2_current_uses;
1377 DWORD shi2_path; /* char *shi2_path; data offset */
1378 unsigned short shi2_passwd[9];
1379 unsigned short shi2_pad2;
1380 } smb_rap_share_info_2_t;
1382 #define SMB_RAP_MAX_SHARES 512
1384 typedef struct smb_rap_share_list {
1387 smb_rap_share_info_0_t * shares;
1388 } smb_rap_share_list_t;
1390 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1391 smb_rap_share_list_t * sp;
1396 if(name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1397 return 0; /* skip over '.' and '..' */
1399 sp = (smb_rap_share_list_t *) vrockp;
1401 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1402 sp->shares[sp->cShare].shi0_netname[12] = 0;
1406 if(sp->cShare >= sp->maxShares)
1407 return CM_ERROR_STOPNOW;
1412 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1414 smb_tran2Packet_t *outp;
1415 unsigned short * tp;
1419 int outParmsTotal; /* total parameter bytes */
1420 int outDataTotal; /* total data bytes */
1428 HKEY hkSubmount = NULL;
1429 smb_rap_share_info_1_t * shares;
1432 char thisShare[256];
1435 smb_rap_share_list_t rootShares;
1440 tp = p->parmsp + 1; /* skip over function number (always 0) */
1441 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1442 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1446 if(infoLevel != 1) {
1447 return CM_ERROR_INVAL;
1450 /* first figure out how many shares there are */
1451 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1452 KEY_QUERY_VALUE, &hkParam);
1453 if (rv == ERROR_SUCCESS) {
1454 len = sizeof(allSubmount);
1455 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1456 (BYTE *) &allSubmount, &len);
1457 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1460 RegCloseKey (hkParam);
1463 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1464 0, KEY_QUERY_VALUE, &hkSubmount);
1465 if (rv == ERROR_SUCCESS) {
1466 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1467 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1468 if (rv != ERROR_SUCCESS)
1474 /* fetch the root shares */
1475 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1476 rootShares.cShare = 0;
1477 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1481 userp = smb_GetTran2User(vcp,p);
1483 thyper.HighPart = 0;
1486 cm_HoldSCache(cm_rootSCachep);
1487 cm_ApplyDir(cm_rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1488 cm_ReleaseSCache(cm_rootSCachep);
1490 cm_ReleaseUser(userp);
1492 nShares = rootShares.cShare + nRegShares + allSubmount;
1494 #define REMARK_LEN 1
1495 outParmsTotal = 8; /* 4 dwords */
1496 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1497 if(outDataTotal > bufsize) {
1498 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1499 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1502 nSharesRet = nShares;
1505 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1507 /* now for the submounts */
1508 shares = (smb_rap_share_info_1_t *) outp->datap;
1509 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1511 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1514 strcpy( shares[cshare].shi1_netname, "all" );
1515 shares[cshare].shi1_remark = cstrp - outp->datap;
1516 /* type and pad are zero already */
1522 for(i=0; i < nRegShares && cshare < nSharesRet; i++) {
1523 len = sizeof(thisShare);
1524 rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1525 if(rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1526 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1527 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1528 shares[cshare].shi1_remark = cstrp - outp->datap;
1533 nShares--; /* uncount key */
1536 RegCloseKey(hkSubmount);
1539 nonrootShares = cshare;
1541 for(i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1542 /* in case there are collisions with submounts, submounts have higher priority */
1543 for(j=0; j < nonrootShares; j++)
1544 if(!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1547 if(j < nonrootShares) {
1548 nShares--; /* uncount */
1552 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1553 shares[cshare].shi1_remark = cstrp - outp->datap;
1558 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1559 outp->parmsp[1] = 0;
1560 outp->parmsp[2] = cshare;
1561 outp->parmsp[3] = nShares;
1563 outp->totalData = cstrp - outp->datap;
1564 outp->totalParms = outParmsTotal;
1566 smb_SendTran2Packet(vcp, outp, op);
1567 smb_FreeTran2Packet(outp);
1569 free(rootShares.shares);
1574 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1576 smb_tran2Packet_t *outp;
1577 unsigned short * tp;
1579 BOOL shareFound = FALSE;
1580 unsigned short infoLevel;
1581 unsigned short bufsize;
1591 tp = p->parmsp + 1; /* skip over function number (always 1) */
1592 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1593 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1594 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1601 totalData = sizeof(smb_rap_share_info_0_t);
1602 else if(infoLevel == 1)
1603 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1604 else if(infoLevel == 2)
1605 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1607 return CM_ERROR_INVAL;
1609 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1611 if(!stricmp(shareName,"all")) {
1612 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1613 KEY_QUERY_VALUE, &hkParam);
1614 if (rv == ERROR_SUCCESS) {
1615 len = sizeof(allSubmount);
1616 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1617 (BYTE *) &allSubmount, &len);
1618 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1621 RegCloseKey (hkParam);
1628 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts", 0,
1629 KEY_QUERY_VALUE, &hkSubmount);
1630 if(rv == ERROR_SUCCESS) {
1631 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1632 if(rv == ERROR_SUCCESS) {
1635 RegCloseKey(hkSubmount);
1640 smb_FreeTran2Packet(outp);
1641 return CM_ERROR_BADSHARENAME;
1644 memset(outp->datap, 0, totalData);
1646 outp->parmsp[0] = 0;
1647 outp->parmsp[1] = 0;
1648 outp->parmsp[2] = totalData;
1650 if(infoLevel == 0) {
1651 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1652 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1653 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1654 } else if(infoLevel == 1) {
1655 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1656 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1657 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1658 info->shi1_remark = ((unsigned char *) (info + 1)) - outp->datap;
1659 /* type and pad are already zero */
1660 } else { /* infoLevel==2 */
1661 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1662 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1663 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1664 info->shi2_remark = ((unsigned char *) (info + 1)) - outp->datap;
1665 info->shi2_permissions = ACCESS_ALL;
1666 info->shi2_max_uses = (unsigned short) -1;
1667 info->shi2_path = 1 + (((unsigned char *) (info + 1)) - outp->datap);
1670 outp->totalData = totalData;
1671 outp->totalParms = totalParam;
1673 smb_SendTran2Packet(vcp, outp, op);
1674 smb_FreeTran2Packet(outp);
1679 typedef struct smb_rap_wksta_info_10 {
1680 DWORD wki10_computername; /*char *wki10_computername;*/
1681 DWORD wki10_username; /* char *wki10_username; */
1682 DWORD wki10_langroup; /* char *wki10_langroup;*/
1683 unsigned char wki10_ver_major;
1684 unsigned char wki10_ver_minor;
1685 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1686 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1687 } smb_rap_wksta_info_10_t;
1690 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1692 smb_tran2Packet_t *outp;
1696 unsigned short * tp;
1699 smb_rap_wksta_info_10_t * info;
1703 tp = p->parmsp + 1; /* Skip over function number */
1704 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1705 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1709 if(infoLevel != 10) {
1710 return CM_ERROR_INVAL;
1716 totalData = sizeof(*info) + /* info */
1717 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1718 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1719 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1720 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1721 1; /* wki10_oth_domains (null)*/
1723 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1725 memset(outp->parmsp,0,totalParams);
1726 memset(outp->datap,0,totalData);
1728 info = (smb_rap_wksta_info_10_t *) outp->datap;
1729 cstrp = (char *) (info + 1);
1731 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1732 strcpy(cstrp, smb_localNamep);
1733 cstrp += strlen(cstrp) + 1;
1735 info->wki10_username = (DWORD) (cstrp - outp->datap);
1736 uidp = smb_FindUID(vcp, p->uid, 0);
1738 lock_ObtainMutex(&uidp->mx);
1739 if(uidp->unp && uidp->unp->name)
1740 strcpy(cstrp, uidp->unp->name);
1741 lock_ReleaseMutex(&uidp->mx);
1742 smb_ReleaseUID(uidp);
1744 cstrp += strlen(cstrp) + 1;
1746 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1747 strcpy(cstrp, "WORKGROUP");
1748 cstrp += strlen(cstrp) + 1;
1750 /* TODO: Not sure what values these should take, but these work */
1751 info->wki10_ver_major = 5;
1752 info->wki10_ver_minor = 1;
1754 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1755 strcpy(cstrp, smb_ServerDomainName);
1756 cstrp += strlen(cstrp) + 1;
1758 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1759 cstrp ++; /* no other domains */
1761 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1762 outp->parmsp[2] = outp->totalData;
1763 outp->totalParms = totalParams;
1765 smb_SendTran2Packet(vcp,outp,op);
1766 smb_FreeTran2Packet(outp);
1771 typedef struct smb_rap_server_info_0 {
1773 } smb_rap_server_info_0_t;
1775 typedef struct smb_rap_server_info_1 {
1777 char sv1_version_major;
1778 char sv1_version_minor;
1779 unsigned long sv1_type;
1780 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1781 } smb_rap_server_info_1_t;
1783 char smb_ServerComment[] = "OpenAFS Client";
1784 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1786 #define SMB_SV_TYPE_SERVER 0x00000002L
1787 #define SMB_SV_TYPE_NT 0x00001000L
1788 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1790 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1792 smb_tran2Packet_t *outp;
1796 unsigned short * tp;
1799 smb_rap_server_info_0_t * info0;
1800 smb_rap_server_info_1_t * info1;
1803 tp = p->parmsp + 1; /* Skip over function number */
1804 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1805 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1809 if(infoLevel != 0 && infoLevel != 1) {
1810 return CM_ERROR_INVAL;
1816 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1817 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1819 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1821 memset(outp->parmsp,0,totalParams);
1822 memset(outp->datap,0,totalData);
1824 if(infoLevel == 0) {
1825 info0 = (smb_rap_server_info_0_t *) outp->datap;
1826 cstrp = (char *) (info0 + 1);
1827 strcpy(info0->sv0_name, "AFS");
1828 } else { /* infoLevel == 1 */
1829 info1 = (smb_rap_server_info_1_t *) outp->datap;
1830 cstrp = (char *) (info1 + 1);
1831 strcpy(info1->sv1_name, "AFS");
1834 SMB_SV_TYPE_SERVER |
1836 SMB_SV_TYPE_SERVER_NT;
1838 info1->sv1_version_major = 5;
1839 info1->sv1_version_minor = 1;
1840 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1842 strcpy(cstrp, smb_ServerComment);
1844 cstrp += smb_ServerCommentLen;
1847 totalData = cstrp - outp->datap;
1848 outp->totalData = min(bufsize,totalData); /* actual data size */
1849 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1850 outp->parmsp[2] = totalData;
1851 outp->totalParms = totalParams;
1853 smb_SendTran2Packet(vcp,outp,op);
1854 smb_FreeTran2Packet(outp);
1859 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1861 smb_tran2Packet_t *asp;
1873 /* We sometimes see 0 word count. What to do? */
1874 if (*inp->wctp == 0) {
1879 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1881 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1882 ptbuf[0] = "Transaction2 word count = 0";
1883 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1884 1, inp->ncb_length, ptbuf, inp);
1885 DeregisterEventSource(h);
1887 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1890 smb_SetSMBDataLength(outp, 0);
1891 smb_SendPacket(vcp, outp);
1895 totalParms = smb_GetSMBParm(inp, 0);
1896 totalData = smb_GetSMBParm(inp, 1);
1898 firstPacket = (inp->inCom == 0x32);
1900 /* find the packet we're reassembling */
1901 lock_ObtainWrite(&smb_globalLock);
1902 asp = smb_FindTran2Packet(vcp, inp);
1904 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1906 lock_ReleaseWrite(&smb_globalLock);
1908 /* now merge in this latest packet; start by looking up offsets */
1910 parmDisp = dataDisp = 0;
1911 parmOffset = smb_GetSMBParm(inp, 10);
1912 dataOffset = smb_GetSMBParm(inp, 12);
1913 parmCount = smb_GetSMBParm(inp, 9);
1914 dataCount = smb_GetSMBParm(inp, 11);
1915 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1916 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1918 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1919 totalData, dataCount, asp->maxReturnData);
1922 parmDisp = smb_GetSMBParm(inp, 4);
1923 parmOffset = smb_GetSMBParm(inp, 3);
1924 dataDisp = smb_GetSMBParm(inp, 7);
1925 dataOffset = smb_GetSMBParm(inp, 6);
1926 parmCount = smb_GetSMBParm(inp, 2);
1927 dataCount = smb_GetSMBParm(inp, 5);
1929 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1930 parmCount, dataCount);
1933 /* now copy the parms and data */
1934 if ( parmCount != 0 )
1936 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1938 if ( dataCount != 0 ) {
1939 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1942 /* account for new bytes */
1943 asp->curData += dataCount;
1944 asp->curParms += parmCount;
1946 /* finally, if we're done, remove the packet from the queue and dispatch it */
1947 if (asp->totalData <= asp->curData && asp->totalParms <= asp->curParms) {
1948 /* we've received it all */
1949 lock_ObtainWrite(&smb_globalLock);
1950 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1951 lock_ReleaseWrite(&smb_globalLock);
1953 /* now dispatch it */
1954 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
1955 osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1956 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
1957 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
1960 osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1961 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1962 code = CM_ERROR_BADOP;
1965 /* if an error is returned, we're supposed to send an error packet,
1966 * otherwise the dispatched function already did the data sending.
1967 * We give dispatched proc the responsibility since it knows how much
1968 * space to allocate.
1971 smb_SendTran2Error(vcp, asp, outp, code);
1974 /* free the input tran 2 packet */
1975 lock_ObtainWrite(&smb_globalLock);
1976 smb_FreeTran2Packet(asp);
1977 lock_ReleaseWrite(&smb_globalLock);
1979 else if (firstPacket) {
1980 /* the first packet in a multi-packet request, we need to send an
1981 * ack to get more data.
1983 smb_SetSMBDataLength(outp, 0);
1984 smb_SendPacket(vcp, outp);
1990 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1993 smb_tran2Packet_t *outp;
1998 cm_scache_t *dscp; /* dir we're dealing with */
1999 cm_scache_t *scp; /* file we're creating */
2001 int initialModeBits;
2011 int parmSlot; /* which parm we're dealing with */
2012 long returnEALength;
2020 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2021 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2023 openFun = p->parmsp[6]; /* open function */
2024 excl = ((openFun & 3) == 0);
2025 trunc = ((openFun & 3) == 2); /* truncate it */
2026 openMode = (p->parmsp[1] & 0x7);
2027 openAction = 0; /* tracks what we did */
2029 attributes = p->parmsp[3];
2030 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2032 /* compute initial mode bits based on read-only flag in attributes */
2033 initialModeBits = 0666;
2034 if (attributes & 1) initialModeBits &= ~0222;
2036 pathp = (char *) (&p->parmsp[14]);
2038 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2040 spacep = cm_GetSpace();
2041 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2043 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2044 /* special case magic file name for receiving IOCTL requests
2045 * (since IOCTL calls themselves aren't getting through).
2047 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2048 smb_SetupIoctlFid(fidp, spacep);
2050 /* copy out remainder of the parms */
2052 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2054 outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
2055 outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
2056 outp->parmsp[parmSlot] = 0; parmSlot++;
2057 outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
2058 outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
2059 outp->parmsp[parmSlot] = openMode; parmSlot++;
2060 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2061 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2063 /* and the final "always present" stuff */
2064 outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
2065 /* next write out the "unique" ID */
2066 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
2067 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
2068 outp->parmsp[parmSlot] = 0; parmSlot++;
2069 if (returnEALength) {
2070 outp->parmsp[parmSlot] = 0; parmSlot++;
2071 outp->parmsp[parmSlot] = 0; parmSlot++;
2074 outp->totalData = 0;
2075 outp->totalParms = parmSlot * 2;
2077 smb_SendTran2Packet(vcp, outp, op);
2079 smb_FreeTran2Packet(outp);
2081 /* and clean up fid reference */
2082 smb_ReleaseFID(fidp);
2086 #ifdef DEBUG_VERBOSE
2088 char *hexp, *asciip;
2089 asciip = (lastNamep ? lastNamep : pathp);
2090 hexp = osi_HexifyString( asciip );
2091 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2096 userp = smb_GetTran2User(vcp, p);
2097 /* In the off chance that userp is NULL, we log and abandon */
2099 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2100 smb_FreeTran2Packet(outp);
2101 return CM_ERROR_BADSMB;
2104 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2105 if(code == CM_ERROR_TIDIPC) {
2106 /* Attempt to use TID allocated for IPC. The client is
2107 probably trying to locate DCE RPC end points, which
2108 we don't support. */
2109 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2110 cm_ReleaseUser(userp);
2111 smb_FreeTran2Packet(outp);
2112 return CM_ERROR_NOSUCHPATH;
2116 code = cm_NameI(cm_rootSCachep, pathp,
2117 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2118 userp, tidPathp, &req, &scp);
2120 code = cm_NameI(cm_rootSCachep, spacep->data,
2121 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2122 userp, tidPathp, &req, &dscp);
2123 cm_FreeSpace(spacep);
2126 cm_ReleaseUser(userp);
2127 smb_FreeTran2Packet(outp);
2131 /* otherwise, scp points to the parent directory. Do a lookup,
2132 * and truncate the file if we find it, otherwise we create the
2135 if (!lastNamep) lastNamep = pathp;
2137 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2139 if (code && code != CM_ERROR_NOSUCHFILE) {
2140 cm_ReleaseSCache(dscp);
2141 cm_ReleaseUser(userp);
2142 smb_FreeTran2Packet(outp);
2147 cm_FreeSpace(spacep);
2150 /* if we get here, if code is 0, the file exists and is represented by
2151 * scp. Otherwise, we have to create it.
2154 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2156 if (dscp) cm_ReleaseSCache(dscp);
2157 cm_ReleaseSCache(scp);
2158 cm_ReleaseUser(userp);
2159 smb_FreeTran2Packet(outp);
2164 /* oops, file shouldn't be there */
2165 if (dscp) cm_ReleaseSCache(dscp);
2166 cm_ReleaseSCache(scp);
2167 cm_ReleaseUser(userp);
2168 smb_FreeTran2Packet(outp);
2169 return CM_ERROR_EXISTS;
2173 setAttr.mask = CM_ATTRMASK_LENGTH;
2174 setAttr.length.LowPart = 0;
2175 setAttr.length.HighPart = 0;
2176 code = cm_SetAttr(scp, &setAttr, userp, &req);
2177 openAction = 3; /* truncated existing file */
2179 else openAction = 1; /* found existing file */
2181 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
2182 /* don't create if not found */
2183 if (dscp) cm_ReleaseSCache(dscp);
2184 osi_assert(scp == NULL);
2185 cm_ReleaseUser(userp);
2186 smb_FreeTran2Packet(outp);
2187 return CM_ERROR_NOSUCHFILE;
2190 osi_assert(dscp != NULL && scp == NULL);
2191 openAction = 2; /* created file */
2192 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2193 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2194 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2196 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2197 smb_NotifyChange(FILE_ACTION_ADDED,
2198 FILE_NOTIFY_CHANGE_FILE_NAME,
2199 dscp, lastNamep, NULL, TRUE);
2200 if (!excl && code == CM_ERROR_EXISTS) {
2201 /* not an exclusive create, and someone else tried
2202 * creating it already, then we open it anyway. We
2203 * don't bother retrying after this, since if this next
2204 * fails, that means that the file was deleted after we
2205 * started this call.
2207 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2211 setAttr.mask = CM_ATTRMASK_LENGTH;
2212 setAttr.length.LowPart = 0;
2213 setAttr.length.HighPart = 0;
2214 code = cm_SetAttr(scp, &setAttr, userp,
2217 } /* lookup succeeded */
2221 /* we don't need this any longer */
2222 if (dscp) cm_ReleaseSCache(dscp);
2225 /* something went wrong creating or truncating the file */
2226 if (scp) cm_ReleaseSCache(scp);
2227 cm_ReleaseUser(userp);
2228 smb_FreeTran2Packet(outp);
2232 /* make sure we're about to open a file */
2233 if (scp->fileType != CM_SCACHETYPE_FILE) {
2234 cm_ReleaseSCache(scp);
2235 cm_ReleaseUser(userp);
2236 smb_FreeTran2Packet(outp);
2237 return CM_ERROR_ISDIR;
2240 /* now all we have to do is open the file itself */
2241 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2244 /* save a pointer to the vnode */
2247 /* compute open mode */
2248 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2249 if (openMode == 1 || openMode == 2)
2250 fidp->flags |= SMB_FID_OPENWRITE;
2252 smb_ReleaseFID(fidp);
2254 cm_Open(scp, 0, userp);
2256 /* copy out remainder of the parms */
2258 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2259 lock_ObtainMutex(&scp->mx);
2261 outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
2262 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2263 outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
2264 outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
2265 outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
2267 outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2269 outp->parmsp[parmSlot] = openMode; parmSlot++;
2270 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2271 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2273 /* and the final "always present" stuff */
2274 outp->parmsp[parmSlot] = openAction; parmSlot++;
2275 /* next write out the "unique" ID */
2276 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
2277 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
2278 outp->parmsp[parmSlot] = 0; parmSlot++;
2279 if (returnEALength) {
2280 outp->parmsp[parmSlot] = 0; parmSlot++;
2281 outp->parmsp[parmSlot] = 0; parmSlot++;
2283 lock_ReleaseMutex(&scp->mx);
2284 outp->totalData = 0; /* total # of data bytes */
2285 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2287 smb_SendTran2Packet(vcp, outp, op);
2289 smb_FreeTran2Packet(outp);
2291 cm_ReleaseUser(userp);
2292 /* leave scp held since we put it in fidp->scp */
2296 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2298 return CM_ERROR_BADOP;
2301 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2303 return CM_ERROR_BADOP;
2306 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2308 smb_tran2Packet_t *outp;
2309 smb_tran2QFSInfo_t qi;
2312 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
2314 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2316 switch (p->parmsp[0]) {
2317 case 1: responseSize = sizeof(qi.u.allocInfo); break;
2318 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
2319 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
2320 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
2321 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
2322 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
2323 default: return CM_ERROR_INVAL;
2326 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2327 switch (p->parmsp[0]) {
2330 qi.u.allocInfo.FSID = 0;
2331 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2332 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2333 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2334 qi.u.allocInfo.bytesPerSector = 1024;
2339 qi.u.volumeInfo.vsn = 1234;
2340 qi.u.volumeInfo.vnCount = 4;
2341 /* we're supposed to pad it out with zeroes to the end */
2342 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2343 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2347 /* FS volume info */
2348 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
2349 qi.u.FSvolumeInfo.vsn = 1234;
2350 qi.u.FSvolumeInfo.vnCount = 8;
2351 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
2357 temp.LowPart = 0x7fffffff;
2358 qi.u.FSsizeInfo.totalAllocUnits = temp;
2359 temp.LowPart = 0x3fffffff;
2360 qi.u.FSsizeInfo.availAllocUnits = temp;
2361 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2362 qi.u.FSsizeInfo.bytesPerSector = 1024;
2366 /* FS device info */
2367 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
2368 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2372 /* FS attribute info */
2373 /* attributes, defined in WINNT.H:
2374 * FILE_CASE_SENSITIVE_SEARCH 0x1
2375 * FILE_CASE_PRESERVED_NAMES 0x2
2376 * <no name defined> 0x4000
2377 * If bit 0x4000 is not set, Windows 95 thinks
2378 * we can't handle long (non-8.3) names,
2379 * despite our protestations to the contrary.
2381 qi.u.FSattributeInfo.attributes = 0x4003;
2382 qi.u.FSattributeInfo.maxCompLength = 255;
2383 qi.u.FSattributeInfo.FSnameLength = 6;
2384 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
2388 /* copy out return data, and set corresponding sizes */
2389 outp->totalParms = 0;
2390 outp->totalData = responseSize;
2391 memcpy(outp->datap, &qi, responseSize);
2393 /* send and free the packets */
2394 smb_SendTran2Packet(vcp, outp, op);
2395 smb_FreeTran2Packet(outp);
2400 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2402 return CM_ERROR_BADOP;
2405 struct smb_ShortNameRock {
2409 size_t shortNameLen;
2412 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2415 struct smb_ShortNameRock *rockp;
2419 /* compare both names and vnodes, though probably just comparing vnodes
2420 * would be safe enough.
2422 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2424 if (ntohl(dep->fid.vnode) != rockp->vnode)
2426 /* This is the entry */
2427 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2428 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2429 return CM_ERROR_STOPNOW;
2432 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2433 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2435 struct smb_ShortNameRock rock;
2439 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2443 spacep = cm_GetSpace();
2444 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2446 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
2448 cm_FreeSpace(spacep);
2449 if (code) return code;
2451 if (!lastNamep) lastNamep = pathp;
2454 thyper.HighPart = 0;
2455 rock.shortName = shortName;
2457 rock.maskp = lastNamep;
2458 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
2461 cm_ReleaseSCache(dscp);
2464 return CM_ERROR_NOSUCHFILE;
2465 if (code == CM_ERROR_STOPNOW) {
2466 *shortNameLenp = rock.shortNameLen;
2472 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2474 smb_tran2Packet_t *outp;
2475 unsigned long dosTime;
2477 unsigned short infoLevel;
2479 unsigned short attributes;
2480 unsigned long extAttributes;
2485 cm_scache_t *scp, *dscp;
2494 infoLevel = p->parmsp[0];
2495 if (infoLevel == 6) nbytesRequired = 0;
2496 else if (infoLevel == 1) nbytesRequired = 22;
2497 else if (infoLevel == 2) nbytesRequired = 26;
2498 else if (infoLevel == 0x101) nbytesRequired = 40;
2499 else if (infoLevel == 0x102) nbytesRequired = 24;
2500 else if (infoLevel == 0x103) nbytesRequired = 4;
2501 else if (infoLevel == 0x108) nbytesRequired = 30;
2503 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2504 p->opcode, infoLevel);
2505 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2508 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2509 osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
2511 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2513 if (infoLevel > 0x100)
2514 outp->totalParms = 2;
2516 outp->totalParms = 0;
2517 outp->totalData = nbytesRequired;
2519 /* now, if we're at infoLevel 6, we're only being asked to check
2520 * the syntax, so we just OK things now. In particular, we're *not*
2521 * being asked to verify anything about the state of any parent dirs.
2523 if (infoLevel == 6) {
2524 smb_SendTran2Packet(vcp, outp, opx);
2525 smb_FreeTran2Packet(outp);
2529 userp = smb_GetTran2User(vcp, p);
2531 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2532 smb_FreeTran2Packet(outp);
2533 return CM_ERROR_BADSMB;
2536 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2538 cm_ReleaseUser(userp);
2539 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2540 smb_FreeTran2Packet(outp);
2545 * XXX Strange hack XXX
2547 * As of Patch 7 (13 January 98), we are having the following problem:
2548 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2549 * requests to look up "desktop.ini" in all the subdirectories.
2550 * This can cause zillions of timeouts looking up non-existent cells
2551 * and volumes, especially in the top-level directory.
2553 * We have not found any way to avoid this or work around it except
2554 * to explicitly ignore the requests for mount points that haven't
2555 * yet been evaluated and for directories that haven't yet been
2558 if (infoLevel == 0x101) {
2559 spacep = cm_GetSpace();
2560 smb_StripLastComponent(spacep->data, &lastComp,
2561 (char *)(&p->parmsp[3]));
2562 /* Make sure that lastComp is not NULL */
2564 if (strcmp(lastComp, "\\desktop.ini") == 0) {
2565 code = cm_NameI(cm_rootSCachep, spacep->data,
2569 userp, tidPathp, &req, &dscp);
2571 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
2572 && !dscp->mountRootFidp)
2573 code = CM_ERROR_NOSUCHFILE;
2574 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2575 cm_buf_t *bp = buf_Find(dscp, &hzero);
2579 code = CM_ERROR_NOSUCHFILE;
2581 cm_ReleaseSCache(dscp);
2583 cm_FreeSpace(spacep);
2584 cm_ReleaseUser(userp);
2585 smb_SendTran2Error(vcp, p, opx, code);
2586 smb_FreeTran2Packet(outp);
2592 cm_FreeSpace(spacep);
2595 /* now do namei and stat, and copy out the info */
2596 code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
2597 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2600 cm_ReleaseUser(userp);
2601 smb_SendTran2Error(vcp, p, opx, code);
2602 smb_FreeTran2Packet(outp);
2606 lock_ObtainMutex(&scp->mx);
2607 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2608 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2609 if (code) goto done;
2611 /* now we have the status in the cache entry, and everything is locked.
2612 * Marshall the output data.
2615 /* for info level 108, figure out short name */
2616 if (infoLevel == 0x108) {
2617 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
2618 tidPathp, scp->fid.vnode, shortName,
2625 *((u_long *)op) = len * 2; op += 4;
2626 mbstowcs((unsigned short *)op, shortName, len);
2631 if (infoLevel == 1 || infoLevel == 2) {
2632 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2633 *((u_long *)op) = dosTime; op += 4; /* creation time */
2634 *((u_long *)op) = dosTime; op += 4; /* access time */
2635 *((u_long *)op) = dosTime; op += 4; /* write time */
2636 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
2637 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
2638 attributes = smb_Attributes(scp);
2639 *((u_short *)op) = attributes; op += 2; /* attributes */
2641 else if (infoLevel == 0x101) {
2642 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2643 *((FILETIME *)op) = ft; op += 8; /* creation time */
2644 *((FILETIME *)op) = ft; op += 8; /* last access time */
2645 *((FILETIME *)op) = ft; op += 8; /* last write time */
2646 *((FILETIME *)op) = ft; op += 8; /* last change time */
2647 extAttributes = smb_ExtAttributes(scp);
2648 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
2649 *((u_long *)op) = 0; op += 4; /* don't know what this is */
2651 else if (infoLevel == 0x102) {
2652 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2653 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2654 *((u_long *)op) = scp->linkCount; op += 4;
2657 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2660 else if (infoLevel == 0x103) {
2661 memset(op, 0, 4); op += 4; /* EA size */
2664 /* now, if we are being asked about extended attrs, return a 0 size */
2665 if (infoLevel == 2) {
2666 *((u_long *)op) = 0; op += 4;
2670 /* send and free the packets */
2672 lock_ReleaseMutex(&scp->mx);
2673 cm_ReleaseSCache(scp);
2674 cm_ReleaseUser(userp);
2676 smb_SendTran2Packet(vcp, outp, opx);
2678 smb_SendTran2Error(vcp, p, opx, code);
2679 smb_FreeTran2Packet(outp);
2684 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2686 return CM_ERROR_BADOP;
2689 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2691 smb_tran2Packet_t *outp;
2693 unsigned long attributes;
2694 unsigned short infoLevel;
2707 fidp = smb_FindFID(vcp, fid, 0);
2710 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2714 infoLevel = p->parmsp[1];
2715 if (infoLevel == 0x101) nbytesRequired = 40;
2716 else if (infoLevel == 0x102) nbytesRequired = 24;
2717 else if (infoLevel == 0x103) nbytesRequired = 4;
2718 else if (infoLevel == 0x104) nbytesRequired = 6;
2720 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2721 p->opcode, infoLevel);
2722 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2723 smb_ReleaseFID(fidp);
2726 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2728 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2730 if (infoLevel > 0x100)
2731 outp->totalParms = 2;
2733 outp->totalParms = 0;
2734 outp->totalData = nbytesRequired;
2736 userp = smb_GetTran2User(vcp, p);
2738 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2739 code = CM_ERROR_BADSMB;
2744 lock_ObtainMutex(&scp->mx);
2745 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2746 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2747 if (code) goto done;
2749 /* now we have the status in the cache entry, and everything is locked.
2750 * Marshall the output data.
2753 if (infoLevel == 0x101) {
2754 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2755 *((FILETIME *)op) = ft; op += 8; /* creation time */
2756 *((FILETIME *)op) = ft; op += 8; /* last access time */
2757 *((FILETIME *)op) = ft; op += 8; /* last write time */
2758 *((FILETIME *)op) = ft; op += 8; /* last change time */
2759 attributes = smb_ExtAttributes(scp);
2760 *((u_long *)op) = attributes; op += 4;
2761 *((u_long *)op) = 0; op += 4;
2763 else if (infoLevel == 0x102) {
2764 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2765 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2766 *((u_long *)op) = scp->linkCount; op += 4;
2767 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
2768 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2772 else if (infoLevel == 0x103) {
2773 *((u_long *)op) = 0; op += 4;
2775 else if (infoLevel == 0x104) {
2779 if (fidp->NTopen_wholepathp)
2780 name = fidp->NTopen_wholepathp;
2782 name = "\\"; /* probably can't happen */
2784 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
2785 *((u_long *)op) = len * 2; op += 4;
2786 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2789 /* send and free the packets */
2791 lock_ReleaseMutex(&scp->mx);
2792 cm_ReleaseUser(userp);
2793 smb_ReleaseFID(fidp);
2794 if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
2795 else smb_SendTran2Error(vcp, p, opx, code);
2796 smb_FreeTran2Packet(outp);
2801 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2806 unsigned short infoLevel;
2807 smb_tran2Packet_t *outp;
2815 fidp = smb_FindFID(vcp, fid, 0);
2818 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
2822 infoLevel = p->parmsp[1];
2823 if (infoLevel > 0x104 || infoLevel < 0x101) {
2824 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2825 p->opcode, infoLevel);
2826 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
2827 smb_ReleaseFID(fidp);
2831 if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
2832 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2833 smb_ReleaseFID(fidp);
2836 if ((infoLevel == 0x103 || infoLevel == 0x104)
2837 && !(fidp->flags & SMB_FID_OPENWRITE)) {
2838 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2839 smb_ReleaseFID(fidp);
2843 osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
2845 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
2847 outp->totalParms = 2;
2848 outp->totalData = 0;
2850 userp = smb_GetTran2User(vcp, p);
2852 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
2853 code = CM_ERROR_BADSMB;
2859 if (infoLevel == 0x101) {
2861 unsigned int attribute;
2864 /* lock the vnode with a callback; we need the current status
2865 * to determine what the new status is, in some cases.
2867 lock_ObtainMutex(&scp->mx);
2868 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2869 CM_SCACHESYNC_GETSTATUS
2870 | CM_SCACHESYNC_NEEDCALLBACK);
2872 lock_ReleaseMutex(&scp->mx);
2876 /* prepare for setattr call */
2879 lastMod = *((FILETIME *)(p->datap + 16));
2880 /* when called as result of move a b, lastMod is (-1, -1).
2881 * If the check for -1 is not present, timestamp
2882 * of the resulting file will be 1969 (-1)
2884 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
2885 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
2886 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
2887 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
2889 fidp->flags |= SMB_FID_MTIMESETDONE;
2892 attribute = *((u_long *)(p->datap + 32));
2893 if (attribute != 0) {
2894 if ((scp->unixModeBits & 0222)
2895 && (attribute & 1) != 0) {
2896 /* make a writable file read-only */
2897 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2898 attr.unixModeBits = scp->unixModeBits & ~0222;
2900 else if ((scp->unixModeBits & 0222) == 0
2901 && (attribute & 1) == 0) {
2902 /* make a read-only file writable */
2903 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2904 attr.unixModeBits = scp->unixModeBits | 0222;
2907 lock_ReleaseMutex(&scp->mx);
2911 code = cm_SetAttr(scp, &attr, userp, &req);
2915 else if (infoLevel == 0x103 || infoLevel == 0x104) {
2916 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
2919 attr.mask = CM_ATTRMASK_LENGTH;
2920 attr.length.LowPart = size.LowPart;
2921 attr.length.HighPart = size.HighPart;
2922 code = cm_SetAttr(scp, &attr, userp, &req);
2924 else if (infoLevel == 0x102) {
2925 if (*((char *)(p->datap))) {
2926 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
2929 fidp->flags |= SMB_FID_DELONCLOSE;
2933 fidp->flags &= ~SMB_FID_DELONCLOSE;
2937 cm_ReleaseUser(userp);
2938 smb_ReleaseFID(fidp);
2939 if (code == 0) smb_SendTran2Packet(vcp, outp, op);
2940 else smb_SendTran2Error(vcp, p, op, code);
2941 smb_FreeTran2Packet(outp);
2946 long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2948 return CM_ERROR_BADOP;
2951 long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2953 return CM_ERROR_BADOP;
2956 long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2958 return CM_ERROR_BADOP;
2961 long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2963 return CM_ERROR_BADOP;
2966 long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2968 return CM_ERROR_BADOP;
2971 long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
2972 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
2977 cm_scache_t *targetScp; /* target if scp is a symlink */
2982 unsigned short attr;
2983 unsigned long lattr;
2984 smb_dirListPatch_t *patchp;
2985 smb_dirListPatch_t *npatchp;
2987 for(patchp = *dirPatchespp; patchp; patchp =
2988 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
2989 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
2991 lock_ObtainMutex(&scp->mx);
2992 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
2993 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2995 lock_ReleaseMutex(&scp->mx);
2996 cm_ReleaseSCache(scp);
2998 dptr = patchp->dptr;
3000 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3001 errors in the client. */
3002 if (infoLevel >= 0x101) {
3003 /* 1969-12-31 23:59:59 +00 */
3004 ft.dwHighDateTime = 0x19DB200;
3005 ft.dwLowDateTime = 0x5BB78980;
3007 /* copy to Creation Time */
3008 *((FILETIME *)dptr) = ft;
3011 /* copy to Last Access Time */
3012 *((FILETIME *)dptr) = ft;
3015 /* copy to Last Write Time */
3016 *((FILETIME *)dptr) = ft;
3019 /* copy to Change Time */
3020 *((FILETIME *)dptr) = ft;
3023 /* merge in hidden attribute */
3024 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3025 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3030 /* 1969-12-31 23:59:58 +00*/
3031 dosTime = 0xEBBFBF7D;
3033 /* and copy out date */
3034 shortTemp = (dosTime>>16) & 0xffff;
3035 *((u_short *)dptr) = shortTemp;
3038 /* copy out creation time */
3039 shortTemp = dosTime & 0xffff;
3040 *((u_short *)dptr) = shortTemp;
3043 /* and copy out date */
3044 shortTemp = (dosTime>>16) & 0xffff;
3045 *((u_short *)dptr) = shortTemp;
3048 /* copy out access time */
3049 shortTemp = dosTime & 0xffff;
3050 *((u_short *)dptr) = shortTemp;
3053 /* and copy out date */
3054 shortTemp = (dosTime>>16) & 0xffff;
3055 *((u_short *)dptr) = shortTemp;
3058 /* copy out mod time */
3059 shortTemp = dosTime & 0xffff;
3060 *((u_short *)dptr) = shortTemp;
3063 /* merge in hidden (dot file) attribute */
3064 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3065 attr == SMB_ATTR_HIDDEN;
3066 *dptr++ = attr & 0xff;
3067 *dptr++ = (attr >> 8) & 0xff;
3074 /* now watch for a symlink */
3075 if (scp->fileType == CM_SCACHETYPE_SYMLINK) {
3076 lock_ReleaseMutex(&scp->mx);
3077 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3079 /* we have a more accurate file to use (the
3080 * target of the symbolic link). Otherwise,
3081 * we'll just use the symlink anyway.
3083 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3085 cm_ReleaseSCache(scp);
3088 lock_ObtainMutex(&scp->mx);
3091 dptr = patchp->dptr;
3093 if (infoLevel >= 0x101) {
3095 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3097 /* copy to Creation Time */
3098 *((FILETIME *)dptr) = ft;
3101 /* copy to Last Access Time */
3102 *((FILETIME *)dptr) = ft;
3105 /* copy to Last Write Time */
3106 *((FILETIME *)dptr) = ft;
3109 /* copy to Change Time */
3110 *((FILETIME *)dptr) = ft;
3113 /* Use length for both file length and alloc length */
3114 *((LARGE_INTEGER *)dptr) = scp->length;
3116 *((LARGE_INTEGER *)dptr) = scp->length;
3119 /* Copy attributes */
3120 lattr = smb_ExtAttributes(scp);
3121 /* merge in hidden (dot file) attribute */
3122 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3123 lattr |= SMB_ATTR_HIDDEN;
3124 *((u_long *)dptr) = lattr;
3129 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3131 /* and copy out date */
3132 shortTemp = (dosTime>>16) & 0xffff;
3133 *((u_short *)dptr) = shortTemp;
3136 /* copy out creation time */
3137 shortTemp = dosTime & 0xffff;
3138 *((u_short *)dptr) = shortTemp;
3141 /* and copy out date */
3142 shortTemp = (dosTime>>16) & 0xffff;
3143 *((u_short *)dptr) = shortTemp;
3146 /* copy out access time */
3147 shortTemp = dosTime & 0xffff;
3148 *((u_short *)dptr) = shortTemp;
3151 /* and copy out date */
3152 shortTemp = (dosTime>>16) & 0xffff;
3153 *((u_short *)dptr) = shortTemp;
3156 /* copy out mod time */
3157 shortTemp = dosTime & 0xffff;
3158 *((u_short *)dptr) = shortTemp;
3161 /* copy out file length and alloc length,
3162 * using the same for both
3164 *((u_long *)dptr) = scp->length.LowPart;
3166 *((u_long *)dptr) = scp->length.LowPart;
3169 /* finally copy out attributes as short */
3170 attr = smb_Attributes(scp);
3171 /* merge in hidden (dot file) attribute */
3172 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3173 attr |= SMB_ATTR_HIDDEN;
3174 *dptr++ = attr & 0xff;
3175 *dptr++ = (attr >> 8) & 0xff;
3178 lock_ReleaseMutex(&scp->mx);
3179 cm_ReleaseSCache(scp);
3182 /* now free the patches */
3183 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
3184 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3188 /* and mark the list as empty */
3189 *dirPatchespp = NULL;
3194 #ifndef USE_OLD_MATCHING
3195 // char table for case insensitive comparison
3196 char mapCaseTable[256];
3198 VOID initUpperCaseTable(VOID)
3201 for (i = 0; i < 256; ++i)
3202 mapCaseTable[i] = toupper(i);
3203 // make '"' match '.'
3204 mapCaseTable[(int)'"'] = toupper('.');
3205 // make '<' match '*'
3206 mapCaseTable[(int)'<'] = toupper('*');
3207 // make '>' match '?'
3208 mapCaseTable[(int)'>'] = toupper('?');
3211 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3213 // Note : this procedure works recursively calling itself.
3215 // PSZ pattern : string containing metacharacters.
3216 // PSZ name : file name to be compared with 'pattern'.
3218 // BOOL : TRUE/FALSE (match/mistmatch)
3220 BOOL szWildCardMatchFileName(PSZ pattern, PSZ name) {
3221 PSZ pename; // points to the last 'name' character
3223 pename = name + strlen(name) - 1;
3228 if (*(++pattern) != '<' || *(++pattern) != '*') {
3236 while ((*pattern == '<') || (*pattern == '*') || (*pattern == '?') || (*pattern == '>'))
3240 for (p = pename; p >= name; --p) {
3241 if ((mapCaseTable[*p] == mapCaseTable[*pattern]) &&
3242 szWildCardMatchFileName(pattern + 1, p + 1))
3247 if (mapCaseTable[*name] != mapCaseTable[*pattern])
3256 /* do a case-folding search of the star name mask with the name in namep.
3257 * Return 1 if we match, otherwise 0.
3259 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3261 /* make sure we only match 8.3 names, if requested */
3262 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3265 return szWildCardMatchFileName(maskp, namep) ? 1:0;
3268 #else /* USE_OLD_MATCHING */
3269 /* do a case-folding search of the star name mask with the name in namep.
3270 * Return 1 if we match, otherwise 0.
3272 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3274 unsigned char tcp1, tcp2; /* Pattern characters */
3275 unsigned char tcn1; /* Name characters */
3276 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3277 char *starNamep, *starMaskp;
3278 static char nullCharp[] = {0};
3279 int casefold = flags & CM_FLAG_CASEFOLD;
3281 /* make sure we only match 8.3 names, if requested */
3282 req8dot3 = (flags & CM_FLAG_8DOT3);
3283 if (req8dot3 && !cm_Is8Dot3(namep))
3288 /* Next pattern character */
3291 /* Next name character */
3295 /* 0 - end of pattern */
3301 else if (tcp1 == '.' || tcp1 == '"') {
3311 * first dot in pattern;
3312 * must match dot or end of name
3317 else if (tcn1 == '.') {
3326 else if (tcp1 == '?') {
3327 if (tcn1 == 0 || tcn1 == '.')
3332 else if (tcp1 == '>') {
3333 if (tcn1 != 0 && tcn1 != '.')
3337 else if (tcp1 == '*' || tcp1 == '<') {
3341 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3342 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3357 * pattern character after '*' is not null or
3358 * period. If it is '?' or '>', we are not
3359 * going to understand it. If it is '*' or
3360 * '<', we are going to skip over it. None of
3361 * these are likely, I hope.
3363 /* skip over '*' and '<' */
3364 while (tcp2 == '*' || tcp2 == '<')
3367 /* skip over characters that don't match tcp2 */
3368 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
3369 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
3370 (!casefold && tcn1 != tcp2)))
3374 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3377 /* Remember where we are */
3387 /* tcp1 is not a wildcard */
3388 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
3389 (!casefold && tcn1 == tcp1)) {
3394 /* if trying to match a star pattern, go back */
3396 maskp = starMaskp - 2;
3397 namep = starNamep + 1;
3406 #endif /* USE_OLD_MATCHING */
3408 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3417 smb_dirListPatch_t *dirListPatchesp;
3418 smb_dirListPatch_t *curPatchp;
3421 long orbytes; /* # of bytes in this output record */
3422 long ohbytes; /* # of bytes, except file name */
3423 long onbytes; /* # of bytes in name, incl. term. null */
3424 osi_hyper_t dirLength;
3425 osi_hyper_t bufferOffset;
3426 osi_hyper_t curOffset;
3428 smb_dirSearch_t *dsp;
3432 cm_pageHeader_t *pageHeaderp;
3433 cm_user_t *userp = NULL;
3436 long nextEntryCookie;
3437 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3438 char *op; /* output data ptr */
3439 char *origOp; /* original value of op */
3440 cm_space_t *spacep; /* for pathname buffer */
3441 long maxReturnData; /* max # of return data */
3442 long maxReturnParms; /* max # of return parms */
3443 long bytesInBuffer; /* # data bytes in the output buffer */
3445 char *maskp; /* mask part of path */
3449 smb_tran2Packet_t *outp; /* response packet */
3452 char shortName[13]; /* 8.3 name if needed */
3464 if (p->opcode == 1) {
3465 /* find first; obtain basic parameters from request */
3466 attribute = p->parmsp[0];
3467 maxCount = p->parmsp[1];
3468 infoLevel = p->parmsp[3];
3469 searchFlags = p->parmsp[2];
3470 dsp = smb_NewDirSearch(1);
3471 dsp->attribute = attribute;
3472 pathp = ((char *) p->parmsp) + 12; /* points to path */
3474 maskp = strrchr(pathp, '\\');
3475 if (maskp == NULL) maskp = pathp;
3476 else maskp++; /* skip over backslash */
3477 strcpy(dsp->mask, maskp); /* and save mask */
3478 /* track if this is likely to match a lot of entries */
3479 starPattern = smb_V3IsStarMask(maskp);
3482 osi_assert(p->opcode == 2);
3483 /* find next; obtain basic parameters from request or open dir file */
3484 dsp = smb_FindDirSearch(p->parmsp[0]);
3485 if (!dsp) return CM_ERROR_BADFD;
3486 attribute = dsp->attribute;
3487 maxCount = p->parmsp[1];
3488 infoLevel = p->parmsp[2];
3489 searchFlags = p->parmsp[5];
3491 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
3493 starPattern = 1; /* assume, since required a Find Next */
3497 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
3498 attribute, infoLevel, maxCount, searchFlags);
3500 osi_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
3501 p->opcode, nextCookie);
3503 if (infoLevel >= 0x101)
3504 searchFlags &= ~4; /* no resume keys */
3506 dirListPatchesp = NULL;
3508 maxReturnData = p->maxReturnData;
3509 if (p->opcode == 1) /* find first */
3510 maxReturnParms = 10; /* bytes */
3512 maxReturnParms = 8; /* bytes */
3514 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
3515 if (maxReturnData > 6000)
3516 maxReturnData = 6000;
3517 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
3519 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
3522 osi_Log1(smb_logp, "T2 receive search dir %s",
3523 osi_LogSaveString(smb_logp, pathp));
3525 /* bail out if request looks bad */
3526 if (p->opcode == 1 && !pathp) {
3527 smb_ReleaseDirSearch(dsp);
3528 smb_FreeTran2Packet(outp);
3529 return CM_ERROR_BADSMB;
3532 osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
3533 nextCookie, dsp->cookie);
3535 userp = smb_GetTran2User(vcp, p);
3537 osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p->uid);
3538 smb_ReleaseDirSearch(dsp);
3539 smb_FreeTran2Packet(outp);
3540 return CM_ERROR_BADSMB;
3543 /* try to get the vnode for the path name next */
3544 lock_ObtainMutex(&dsp->mx);
3551 spacep = cm_GetSpace();
3552 smb_StripLastComponent(spacep->data, NULL, pathp);
3553 lock_ReleaseMutex(&dsp->mx);
3555 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3557 cm_ReleaseUser(userp);
3558 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
3559 smb_FreeTran2Packet(outp);
3560 smb_DeleteDirSearch(dsp);
3561 smb_ReleaseDirSearch(dsp);
3564 code = cm_NameI(cm_rootSCachep, spacep->data,
3565 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3566 userp, tidPathp, &req, &scp);
3567 cm_FreeSpace(spacep);
3569 lock_ObtainMutex(&dsp->mx);
3571 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
3573 /* we need one hold for the entry we just stored into,
3574 * and one for our own processing. When we're done
3575 * with this function, we'll drop the one for our own
3576 * processing. We held it once from the namei call,
3577 * and so we do another hold now.
3580 lock_ObtainMutex(&scp->mx);
3581 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3582 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3583 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3584 dsp->flags |= SMB_DIRSEARCH_BULKST;
3586 lock_ReleaseMutex(&scp->mx);
3589 lock_ReleaseMutex(&dsp->mx);
3591 cm_ReleaseUser(userp);
3592 smb_FreeTran2Packet(outp);
3593 smb_DeleteDirSearch(dsp);
3594 smb_ReleaseDirSearch(dsp);
3598 /* get the directory size */
3599 lock_ObtainMutex(&scp->mx);
3600 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3601 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3603 lock_ReleaseMutex(&scp->mx);
3604 cm_ReleaseSCache(scp);
3605 cm_ReleaseUser(userp);
3606 smb_FreeTran2Packet(outp);
3607 smb_DeleteDirSearch(dsp);
3608 smb_ReleaseDirSearch(dsp);
3613 dirLength = scp->length;
3615 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3616 curOffset.HighPart = 0;
3617 curOffset.LowPart = nextCookie;
3618 origOp = outp->datap;
3626 if (searchFlags & 4)
3627 /* skip over resume key */
3630 /* make sure that curOffset.LowPart doesn't point to the first
3631 * 32 bytes in the 2nd through last dir page, and that it doesn't
3632 * point at the first 13 32-byte chunks in the first dir page,
3633 * since those are dir and page headers, and don't contain useful
3636 temp = curOffset.LowPart & (2048-1);
3637 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3638 /* we're in the first page */
3639 if (temp < 13*32) temp = 13*32;
3642 /* we're in a later dir page */
3643 if (temp < 32) temp = 32;
3646 /* make sure the low order 5 bits are zero */
3649 /* now put temp bits back ito curOffset.LowPart */
3650 curOffset.LowPart &= ~(2048-1);
3651 curOffset.LowPart |= temp;
3653 /* check if we've passed the dir's EOF */
3654 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
3659 /* check if we've returned all the names that will fit in the
3660 * response packet; we check return count as well as the number
3661 * of bytes requested. We check the # of bytes after we find
3662 * the dir entry, since we'll need to check its size.
3664 if (returnedNames >= maxCount) {
3668 /* see if we can use the bufferp we have now; compute in which
3669 * page the current offset would be, and check whether that's
3670 * the offset of the buffer we have. If not, get the buffer.
3672 thyper.HighPart = curOffset.HighPart;
3673 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3674 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3677 buf_Release(bufferp);
3680 lock_ReleaseMutex(&scp->mx);
3681 lock_ObtainRead(&scp->bufCreateLock);
3682 code = buf_Get(scp, &thyper, &bufferp);
3683 lock_ReleaseRead(&scp->bufCreateLock);
3685 /* now, if we're doing a star match, do bulk fetching
3686 * of all of the status info for files in the dir.
3689 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
3692 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
3693 && LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
3694 /* Don't bulk stat if risking timeout */
3695 int now = GetCurrentTime();
3696 if (now - req.startTime > 5000) {
3697 scp->bulkStatProgress = thyper;
3698 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3699 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3701 cm_TryBulkStat(scp, &thyper, userp, &req);
3705 lock_ObtainMutex(&scp->mx);
3707 bufferOffset = thyper;
3709 /* now get the data in the cache */
3711 code = cm_SyncOp(scp, bufferp, userp, &req,
3713 CM_SCACHESYNC_NEEDCALLBACK
3714 | CM_SCACHESYNC_READ);
3717 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3719 /* otherwise, load the buffer and try again */
3720 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3725 buf_Release(bufferp);
3729 } /* if (wrong buffer) ... */
3731 /* now we have the buffer containing the entry we're interested
3732 * in; copy it out if it represents a non-deleted entry.
3734 entryInDir = curOffset.LowPart & (2048-1);
3735 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3737 /* page header will help tell us which entries are free. Page
3738 * header can change more often than once per buffer, since
3739 * AFS 3 dir page size may be less than (but not more than)
3740 * a buffer package buffer.
3742 /* only look intra-buffer */
3743 temp = curOffset.LowPart & (buf_bufferSize - 1);
3744 temp &= ~(2048 - 1); /* turn off intra-page bits */
3745 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3747 /* now determine which entry we're looking at in the page.
3748 * If it is free (there's a free bitmap at the start of the
3749 * dir), we should skip these 32 bytes.
3751 slotInPage = (entryInDir & 0x7e0) >> 5;
3752 if (!(pageHeaderp->freeBitmap[slotInPage>>3]
3753 & (1 << (slotInPage & 0x7)))) {
3754 /* this entry is free */
3755 numDirChunks = 1; /* only skip this guy */
3759 tp = bufferp->datap + entryInBuffer;
3760 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3762 /* while we're here, compute the next entry's location, too,
3763 * since we'll need it when writing out the cookie into the dir
3766 * XXXX Probably should do more sanity checking.
3768 numDirChunks = cm_NameEntries(dep->name, &onbytes);
3770 /* compute offset of cookie representing next entry */
3771 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3773 /* Need 8.3 name? */
3775 if (infoLevel == 0x104
3776 && dep->fid.vnode != 0
3777 && !cm_Is8Dot3(dep->name)) {
3778 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3782 /* When matching, we are using doing a case fold if we have a wildcard mask.
3783 * If we get a non-wildcard match, it's a lookup for a specific file.
3785 if (dep->fid.vnode != 0 &&
3786 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0))
3788 && smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
3790 /* Eliminate entries that don't match requested attributes */
3791 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
3792 smb_IsDotFile(dep->name))
3793 goto nextEntry; /* no hidden files */
3795 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3797 /* We have already done the cm_TryBulkStat above */
3798 fid.cell = scp->fid.cell;
3799 fid.volume = scp->fid.volume;
3800 fid.vnode = ntohl(dep->fid.vnode);
3801 fid.unique = ntohl(dep->fid.unique);
3802 fileType = cm_FindFileType(&fid);
3803 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
3804 "has filetype %d", dep->name,
3806 if (fileType == CM_SCACHETYPE_DIRECTORY)
3810 /* finally check if this name will fit */
3812 /* standard dir entry stuff */
3813 if (infoLevel < 0x101)
3814 ohbytes = 23; /* pre-NT */
3815 else if (infoLevel == 0x103)
3816 ohbytes = 12; /* NT names only */
3818 ohbytes = 64; /* NT */
3820 if (infoLevel == 0x104)
3821 ohbytes += 26; /* Short name & length */
3823 if (searchFlags & 4) {
3824 ohbytes += 4; /* if resume key required */
3828 && infoLevel != 0x101
3829 && infoLevel != 0x103)
3830 ohbytes += 4; /* EASIZE */
3832 /* add header to name & term. null */
3833 orbytes = onbytes + ohbytes + 1;
3835 /* now, we round up the record to a 4 byte alignment,
3836 * and we make sure that we have enough room here for
3837 * even the aligned version (so we don't have to worry
3838 * about an * overflow when we pad things out below).
3839 * That's the reason for the alignment arithmetic below.
3841 if (infoLevel >= 0x101)
3842 align = (4 - (orbytes & 3)) & 3;
3845 if (orbytes + bytesInBuffer + align > maxReturnData)
3848 /* this is one of the entries to use: it is not deleted
3849 * and it matches the star pattern we're looking for.
3850 * Put out the name, preceded by its length.
3852 /* First zero everything else */
3853 memset(origOp, 0, ohbytes);
3855 if (infoLevel <= 0x101)
3856 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
3857 else if (infoLevel == 0x103)
3858 *((u_long *)(op + 8)) = onbytes;
3860 *((u_long *)(op + 60)) = onbytes;
3861 strcpy(origOp+ohbytes, dep->name);
3863 /* Short name if requested and needed */
3864 if (infoLevel == 0x104) {
3865 if (NeedShortName) {
3866 strcpy(op + 70, shortName);
3867 *(op + 68) = shortNameEnd - shortName;
3871 /* now, adjust the # of entries copied */
3874 /* NextEntryOffset and FileIndex */
3875 if (infoLevel >= 101) {
3876 int entryOffset = orbytes + align;
3877 *((u_long *)op) = entryOffset;
3878 *((u_long *)(op+4)) = nextEntryCookie;
3881 /* now we emit the attribute. This is tricky, since
3882 * we need to really stat the file to find out what
3883 * type of entry we've got. Right now, we're copying
3884 * out data from * a buffer, while holding the scp
3885 * locked, so it isn't really convenient to stat
3886 * something now. We'll put in a place holder
3887 * now, and make a second pass before returning this
3888 * to get the real attributes. So, we just skip the
3889 * data for now, and adjust it later. We allocate a
3890 * patch record to make it easy to find this point
3891 * later. The replay will happen at a time when it is
3892 * safe to unlock the directory.
3894 if (infoLevel != 0x103) {
3895 curPatchp = malloc(sizeof(*curPatchp));
3896 osi_QAdd((osi_queue_t **) &dirListPatchesp,
3898 curPatchp->dptr = op;
3899 if (infoLevel >= 0x101)
3900 curPatchp->dptr += 8;
3902 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
3903 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3906 curPatchp->flags = 0;
3908 curPatchp->fid.cell = scp->fid.cell;
3909 curPatchp->fid.volume = scp->fid.volume;
3910 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3911 curPatchp->fid.unique = ntohl(dep->fid.unique);
3914 curPatchp->dep = dep;
3917 if (searchFlags & 4)
3918 /* put out resume key */
3919 *((u_long *)origOp) = nextEntryCookie;
3921 /* Adjust byte ptr and count */
3922 origOp += orbytes; /* skip entire record */
3923 bytesInBuffer += orbytes;
3925 /* and pad the record out */
3926 while (--align >= 0) {
3931 } /* if we're including this name */
3932 else if (!NeedShortName &&
3935 dep->fid.vnode != 0 &&
3936 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
3937 /* We were looking for exact matches, but here's an inexact one*/
3942 /* and adjust curOffset to be where the new cookie is */
3943 thyper.HighPart = 0;
3944 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3945 curOffset = LargeIntegerAdd(thyper, curOffset);
3946 } /* while copying data for dir listing */
3948 /* If we didn't get a star pattern, we did an exact match during the first pass.
3949 * If there were no exact matches found, we fail over to inexact matches by
3950 * marking the query as a star pattern (matches all case permutations), and
3951 * re-running the query.
3953 if (returnedNames == 0 && !starPattern && foundInexact) {
3954 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
3959 /* release the mutex */
3960 lock_ReleaseMutex(&scp->mx);
3961 if (bufferp) buf_Release(bufferp);
3963 /* apply and free last set of patches; if not doing a star match, this
3964 * will be empty, but better safe (and freeing everything) than sorry.
3966 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
3969 /* now put out the final parameters */
3970 if (returnedNames == 0) eos = 1;
3971 if (p->opcode == 1) {
3973 outp->parmsp[0] = (unsigned short) dsp->cookie;
3974 outp->parmsp[1] = returnedNames;
3975 outp->parmsp[2] = eos;
3976 outp->parmsp[3] = 0; /* nothing wrong with EAS */
3977 outp->parmsp[4] = 0;
3978 /* don't need last name to continue
3979 * search, cookie is enough. Normally,
3980 * this is the offset of the file name
3981 * of the last entry returned.
3983 outp->totalParms = 10; /* in bytes */
3987 outp->parmsp[0] = returnedNames;
3988 outp->parmsp[1] = eos;
3989 outp->parmsp[2] = 0; /* EAS error */
3990 outp->parmsp[3] = 0; /* last name, as above */
3991 outp->totalParms = 8; /* in bytes */
3994 /* return # of bytes in the buffer */
3995 outp->totalData = bytesInBuffer;
3997 osi_Log2(smb_logp, "T2 search dir done, %d names, code %d",
3998 returnedNames, code);
4000 /* Return error code if unsuccessful on first request */
4001 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4002 code = CM_ERROR_NOSUCHFILE;
4004 /* if we're supposed to close the search after this request, or if
4005 * we're supposed to close the search if we're done, and we're done,
4006 * or if something went wrong, close the search.
4008 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4009 if ((searchFlags & 1) || (returnedNames == 0) ||
4010 ((searchFlags & 2) && eos) || code != 0)
4011 smb_DeleteDirSearch(dsp);
4013 smb_SendTran2Error(vcp, p, opx, code);
4015 smb_SendTran2Packet(vcp, outp, opx);
4017 smb_FreeTran2Packet(outp);
4018 smb_ReleaseDirSearch(dsp);
4019 cm_ReleaseSCache(scp);
4020 cm_ReleaseUser(userp);
4024 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4027 smb_dirSearch_t *dsp;
4029 dirHandle = smb_GetSMBParm(inp, 0);
4031 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4033 dsp = smb_FindDirSearch(dirHandle);
4036 return CM_ERROR_BADFD;
4038 /* otherwise, we have an FD to destroy */
4039 smb_DeleteDirSearch(dsp);
4040 smb_ReleaseDirSearch(dsp);
4042 /* and return results */
4043 smb_SetSMBDataLength(outp, 0);
4048 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4050 smb_SetSMBDataLength(outp, 0);
4054 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4061 cm_scache_t *dscp; /* dir we're dealing with */
4062 cm_scache_t *scp; /* file we're creating */
4064 int initialModeBits;
4074 int parmSlot; /* which parm we're dealing with */
4082 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4083 openFun = smb_GetSMBParm(inp, 8); /* open function */
4084 excl = ((openFun & 3) == 0);
4085 trunc = ((openFun & 3) == 2); /* truncate it */
4086 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4087 openAction = 0; /* tracks what we did */
4089 attributes = smb_GetSMBParm(inp, 5);
4090 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4092 /* compute initial mode bits based on read-only flag in attributes */
4093 initialModeBits = 0666;
4094 if (attributes & 1) initialModeBits &= ~0222;
4096 pathp = smb_GetSMBData(inp, NULL);
4098 spacep = inp->spacep;
4099 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4101 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4102 /* special case magic file name for receiving IOCTL requests
4103 * (since IOCTL calls themselves aren't getting through).
4106 osi_Log0(smb_logp, "IOCTL Open");
4109 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4110 smb_SetupIoctlFid(fidp, spacep);
4112 /* set inp->fid so that later read calls in same msg can find fid */
4113 inp->fid = fidp->fid;
4115 /* copy out remainder of the parms */
4117 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4119 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4120 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4121 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4122 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4123 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4124 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4125 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4126 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4128 /* and the final "always present" stuff */
4129 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4130 /* next write out the "unique" ID */
4131 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4132 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4133 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4134 smb_SetSMBDataLength(outp, 0);
4136 /* and clean up fid reference */
4137 smb_ReleaseFID(fidp);
4141 #ifdef DEBUG_VERBOSE
4143 char *hexp, *asciip;
4144 asciip = (lastNamep ? lastNamep : pathp );
4145 hexp = osi_HexifyString(asciip);
4146 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4150 userp = smb_GetUser(vcp, inp);
4153 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4155 cm_ReleaseUser(userp);
4156 return CM_ERROR_NOSUCHPATH;
4158 code = cm_NameI(cm_rootSCachep, pathp,
4159 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4160 userp, tidPathp, &req, &scp);
4162 code = cm_NameI(cm_rootSCachep, spacep->data,
4163 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4164 userp, tidPathp, &req, &dscp);
4167 cm_ReleaseUser(userp);
4171 /* otherwise, scp points to the parent directory. Do a lookup,
4172 * and truncate the file if we find it, otherwise we create the
4175 if (!lastNamep) lastNamep = pathp;
4177 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
4179 if (code && code != CM_ERROR_NOSUCHFILE) {
4180 cm_ReleaseSCache(dscp);
4181 cm_ReleaseUser(userp);
4186 /* if we get here, if code is 0, the file exists and is represented by
4187 * scp. Otherwise, we have to create it. The dir may be represented
4188 * by dscp, or we may have found the file directly. If code is non-zero,
4192 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
4194 if (dscp) cm_ReleaseSCache(dscp);
4195 cm_ReleaseSCache(scp);
4196 cm_ReleaseUser(userp);
4201 /* oops, file shouldn't be there */
4202 if (dscp) cm_ReleaseSCache(dscp);
4203 cm_ReleaseSCache(scp);
4204 cm_ReleaseUser(userp);
4205 return CM_ERROR_EXISTS;
4209 setAttr.mask = CM_ATTRMASK_LENGTH;
4210 setAttr.length.LowPart = 0;
4211 setAttr.length.HighPart = 0;
4212 code = cm_SetAttr(scp, &setAttr, userp, &req);
4213 openAction = 3; /* truncated existing file */
4215 else openAction = 1; /* found existing file */
4217 else if (!(openFun & 0x10)) {
4218 /* don't create if not found */
4219 if (dscp) cm_ReleaseSCache(dscp);
4220 cm_ReleaseUser(userp);
4221 return CM_ERROR_NOSUCHFILE;
4224 osi_assert(dscp != NULL);
4225 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
4226 osi_LogSaveString(smb_logp, lastNamep));
4227 openAction = 2; /* created file */
4228 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4229 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
4230 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4232 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4233 smb_NotifyChange(FILE_ACTION_ADDED,
4234 FILE_NOTIFY_CHANGE_FILE_NAME,
4235 dscp, lastNamep, NULL, TRUE);
4236 if (!excl && code == CM_ERROR_EXISTS) {
4237 /* not an exclusive create, and someone else tried
4238 * creating it already, then we open it anyway. We
4239 * don't bother retrying after this, since if this next
4240 * fails, that means that the file was deleted after we
4241 * started this call.
4243 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4247 setAttr.mask = CM_ATTRMASK_LENGTH;
4248 setAttr.length.LowPart = 0;
4249 setAttr.length.HighPart = 0;
4250 code = cm_SetAttr(scp, &setAttr, userp, &req);
4252 } /* lookup succeeded */
4256 /* we don't need this any longer */
4257 if (dscp) cm_ReleaseSCache(dscp);
4260 /* something went wrong creating or truncating the file */
4261 if (scp) cm_ReleaseSCache(scp);
4262 cm_ReleaseUser(userp);
4266 /* make sure we're about to open a file */
4267 if (scp->fileType != CM_SCACHETYPE_FILE) {
4268 cm_ReleaseSCache(scp);
4269 cm_ReleaseUser(userp);
4270 return CM_ERROR_ISDIR;
4273 /* now all we have to do is open the file itself */
4274 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4277 /* save a pointer to the vnode */
4280 /* compute open mode */
4281 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
4282 if (openMode == 1 || openMode == 2)
4283 fidp->flags |= SMB_FID_OPENWRITE;
4285 smb_ReleaseFID(fidp);
4287 cm_Open(scp, 0, userp);
4289 /* set inp->fid so that later read calls in same msg can find fid */
4290 inp->fid = fidp->fid;
4292 /* copy out remainder of the parms */
4294 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4295 lock_ObtainMutex(&scp->mx);
4297 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
4298 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4299 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
4300 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
4301 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
4302 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
4303 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4304 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4305 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4307 /* and the final "always present" stuff */
4308 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
4309 /* next write out the "unique" ID */
4310 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
4311 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
4312 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4313 lock_ReleaseMutex(&scp->mx);
4314 smb_SetSMBDataLength(outp, 0);
4316 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
4318 cm_ReleaseUser(userp);
4319 /* leave scp held since we put it in fidp->scp */
4323 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4330 unsigned char LockType;
4331 unsigned short NumberOfUnlocks, NumberOfLocks;
4332 unsigned long Timeout;
4334 LARGE_INTEGER LOffset, LLength;
4335 smb_waitingLock_t *waitingLock;
4342 fid = smb_GetSMBParm(inp, 2);
4343 fid = smb_ChainFID(fid, inp);
4345 fidp = smb_FindFID(vcp, fid, 0);
4346 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4347 return CM_ERROR_BADFD;
4349 /* set inp->fid so that later read calls in same msg can find fid */
4352 userp = smb_GetUser(vcp, inp);
4356 lock_ObtainMutex(&scp->mx);
4357 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4358 CM_SCACHESYNC_NEEDCALLBACK
4359 | CM_SCACHESYNC_GETSTATUS
4360 | CM_SCACHESYNC_LOCK);
4361 if (code) goto doneSync;
4363 LockType = smb_GetSMBParm(inp, 3) & 0xff;
4364 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
4365 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
4366 NumberOfLocks = smb_GetSMBParm(inp, 7);
4368 op = smb_GetSMBData(inp, NULL);
4370 for (i=0; i<NumberOfUnlocks; i++) {
4371 if (LockType & 0x10) {
4373 LOffset.HighPart = *((LONG *)(op + 4));
4374 LOffset.LowPart = *((DWORD *)(op + 8));
4375 LLength.HighPart = *((LONG *)(op + 12));
4376 LLength.LowPart = *((DWORD *)(op + 16));
4380 /* Not Large Files */
4381 LOffset.HighPart = 0;
4382 LOffset.LowPart = *((DWORD *)(op + 2));
4383 LLength.HighPart = 0;
4384 LLength.LowPart = *((DWORD *)(op + 6));
4387 if (LargeIntegerNotEqualToZero(LOffset))
4389 /* Do not check length -- length check done in cm_Unlock */
4391 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
4392 if (code) goto done;
4395 for (i=0; i<NumberOfLocks; i++) {
4396 if (LockType & 0x10) {
4398 LOffset.HighPart = *((LONG *)(op + 4));
4399 LOffset.LowPart = *((DWORD *)(op + 8));
4400 LLength.HighPart = *((LONG *)(op + 12));
4401 LLength.LowPart = *((DWORD *)(op + 16));
4405 /* Not Large Files */
4406 LOffset.HighPart = 0;
4407 LOffset.LowPart = *((DWORD *)(op + 2));
4408 LLength.HighPart = 0;
4409 LLength.LowPart = *((DWORD *)(op + 6));
4412 if (LargeIntegerNotEqualToZero(LOffset))
4414 if (LargeIntegerLessThan(LOffset, scp->length))
4417 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
4418 userp, &req, &lockp);
4419 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
4420 /* Put on waiting list */
4421 waitingLock = malloc(sizeof(smb_waitingLock_t));
4422 waitingLock->vcp = vcp;
4423 waitingLock->inp = smb_CopyPacket(inp);
4424 waitingLock->outp = smb_CopyPacket(outp);
4425 waitingLock->timeRemaining = Timeout;
4426 waitingLock->lockp = lockp;
4427 lock_ObtainWrite(&smb_globalLock);
4428 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
4430 osi_Wakeup((long) &smb_allWaitingLocks);
4431 lock_ReleaseWrite(&smb_globalLock);
4432 /* don't send reply immediately */
4433 outp->flags |= SMB_PACKETFLAG_NOSEND;
4439 /* release any locks acquired before the failure */
4442 smb_SetSMBDataLength(outp, 0);
4444 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
4446 lock_ReleaseMutex(&scp->mx);
4447 cm_ReleaseUser(userp);
4448 smb_ReleaseFID(fidp);
4453 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4465 fid = smb_GetSMBParm(inp, 0);
4466 fid = smb_ChainFID(fid, inp);
4468 fidp = smb_FindFID(vcp, fid, 0);
4469 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4470 return CM_ERROR_BADFD;
4473 userp = smb_GetUser(vcp, inp);
4477 /* otherwise, stat the file */
4478 lock_ObtainMutex(&scp->mx);
4479 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4480 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4481 if (code) goto done;
4483 /* decode times. We need a search time, but the response to this
4484 * call provides the date first, not the time, as returned in the
4485 * searchTime variable. So we take the high-order bits first.
4487 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
4488 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
4489 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
4490 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
4491 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
4492 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
4493 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
4495 /* now handle file size and allocation size */
4496 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
4497 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
4498 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
4499 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
4501 /* file attribute */
4502 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
4504 /* and finalize stuff */
4505 smb_SetSMBDataLength(outp, 0);
4509 lock_ReleaseMutex(&scp->mx);
4510 cm_ReleaseUser(userp);
4511 smb_ReleaseFID(fidp);
4515 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4529 fid = smb_GetSMBParm(inp, 0);
4530 fid = smb_ChainFID(fid, inp);
4532 fidp = smb_FindFID(vcp, fid, 0);
4533 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4534 return CM_ERROR_BADFD;
4537 userp = smb_GetUser(vcp, inp);
4541 /* now prepare to call cm_setattr. This message only sets various times,
4542 * and AFS only implements mtime, and we'll set the mtime if that's
4543 * requested. The others we'll ignore.
4545 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
4547 if (searchTime != 0) {
4548 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
4550 if ( unixTime != -1 ) {
4551 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
4552 attrs.clientModTime = unixTime;
4553 code = cm_SetAttr(scp, &attrs, userp, &req);
4555 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
4557 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
4562 cm_ReleaseUser(userp);
4563 smb_ReleaseFID(fidp);
4568 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4571 long count, finalCount;
4578 fd = smb_GetSMBParm(inp, 2);
4579 count = smb_GetSMBParm(inp, 5);
4580 offset.HighPart = 0; /* too bad */
4581 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
4583 osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
4584 fd, offset.LowPart, count);
4586 fd = smb_ChainFID(fd, inp);
4587 fidp = smb_FindFID(vcp, fd, 0);
4589 return CM_ERROR_BADFD;
4591 /* set inp->fid so that later read calls in same msg can find fid */
4594 if (fidp->flags & SMB_FID_IOCTL) {
4595 return smb_IoctlV3Read(fidp, vcp, inp, outp);
4598 userp = smb_GetUser(vcp, inp);
4600 /* 0 and 1 are reserved for request chaining, were setup by our caller,
4601 * and will be further filled in after we return.
4603 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
4604 smb_SetSMBParm(outp, 3, 0); /* resvd */
4605 smb_SetSMBParm(outp, 4, 0); /* resvd */
4606 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
4607 /* fill in #6 when we have all the parameters' space reserved */
4608 smb_SetSMBParm(outp, 7, 0); /* resv'd */
4609 smb_SetSMBParm(outp, 8, 0); /* resv'd */
4610 smb_SetSMBParm(outp, 9, 0); /* resv'd */
4611 smb_SetSMBParm(outp, 10, 0); /* resv'd */
4612 smb_SetSMBParm(outp, 11, 0); /* reserved */
4614 /* get op ptr after putting in the parms, since otherwise we don't
4615 * know where the data really is.
4617 op = smb_GetSMBData(outp, NULL);
4619 /* now fill in offset from start of SMB header to first data byte (to op) */
4620 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
4622 /* set the packet data length the count of the # of bytes */
4623 smb_SetSMBDataLength(outp, count);
4626 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
4628 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
4631 /* fix some things up */
4632 smb_SetSMBParm(outp, 5, finalCount);
4633 smb_SetSMBDataLength(outp, finalCount);
4635 smb_ReleaseFID(fidp);
4637 cm_ReleaseUser(userp);
4642 * Values for createDisp, copied from NTDDK.H
4644 * FILE_SUPERSEDE 0 (???)
4645 * FILE_OPEN 1 (open)
4646 * FILE_CREATE 2 (exclusive)
4647 * FILE_OPEN_IF 3 (non-exclusive)
4648 * FILE_OVERWRITE 4 (open & truncate, but do not create)
4649 * FILE_OVERWRITE_IF 5 (open & truncate, or create)
4652 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4654 char *pathp, *realPathp;
4658 cm_scache_t *dscp; /* parent dir */
4659 cm_scache_t *scp; /* file to create or open */
4663 unsigned short nameLength;
4665 unsigned int requestOpLock;
4666 unsigned int requestBatchOpLock;
4667 unsigned int mustBeDir;
4668 unsigned int treeCreate;
4670 unsigned int desiredAccess;
4671 unsigned int extAttributes;
4672 unsigned int createDisp;
4673 unsigned int createOptions;
4674 int initialModeBits;
4675 unsigned short baseFid;
4676 smb_fid_t *baseFidp;
4678 cm_scache_t *baseDirp;
4679 unsigned short openAction;
4694 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
4695 flags = smb_GetSMBOffsetParm(inp, 3, 1)
4696 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
4697 requestOpLock = flags & 0x02;
4698 requestBatchOpLock = flags & 0x04;
4699 mustBeDir = flags & 0x08;
4702 * Why all of a sudden 32-bit FID?
4703 * We will reject all bits higher than 16.
4705 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
4706 return CM_ERROR_INVAL;
4707 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
4708 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
4709 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
4710 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
4711 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
4712 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
4713 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
4714 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
4715 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
4717 /* mustBeDir is never set; createOptions directory bit seems to be
4720 if (createOptions & 1)
4722 else if (createOptions & 0x40)
4728 * compute initial mode bits based on read-only flag in
4729 * extended attributes
4731 initialModeBits = 0666;
4732 if (extAttributes & 1) initialModeBits &= ~0222;
4734 pathp = smb_GetSMBData(inp, NULL);
4735 /* Sometimes path is not null-terminated, so we make a copy. */
4736 realPathp = malloc(nameLength+1);
4737 memcpy(realPathp, pathp, nameLength);
4738 realPathp[nameLength] = 0;
4740 spacep = inp->spacep;
4741 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
4743 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
4744 osi_Log4(smb_logp,"NTCreateX da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
4745 osi_Log1(smb_logp,"NTCreateX lastNamep=[%s]",osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
4747 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4748 /* special case magic file name for receiving IOCTL requests
4749 * (since IOCTL calls themselves aren't getting through).
4751 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4752 smb_SetupIoctlFid(fidp, spacep);
4753 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
4755 /* set inp->fid so that later read calls in same msg can find fid */
4756 inp->fid = fidp->fid;
4760 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
4761 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4762 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
4764 memset(&ft, 0, sizeof(ft));
4765 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4766 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4767 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4768 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4769 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
4770 sz.HighPart = 0x7fff; sz.LowPart = 0;
4771 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
4772 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
4773 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
4774 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
4775 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
4776 smb_SetSMBDataLength(outp, 0);
4778 /* clean up fid reference */
4779 smb_ReleaseFID(fidp);
4784 #ifdef DEBUG_VERBOSE
4786 char *hexp, *asciip;
4787 asciip = (lastNamep? lastNamep : realPathp);
4788 hexp = osi_HexifyString( asciip );
4789 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
4793 userp = smb_GetUser(vcp, inp);
4795 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
4797 return CM_ERROR_INVAL;
4801 baseDirp = cm_rootSCachep;
4802 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4803 if(code == CM_ERROR_TIDIPC) {
4804 /* Attempt to use a TID allocated for IPC. The client
4805 is probably looking for DCE RPC end points which we
4807 osi_Log0(smb_logp, "NTCreateX received IPC TID");
4809 cm_ReleaseUser(userp);
4810 return CM_ERROR_NOSUCHFILE;
4814 baseFidp = smb_FindFID(vcp, baseFid, 0);
4816 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
4818 cm_ReleaseUser(userp);
4819 return CM_ERROR_INVAL;
4821 baseDirp = baseFidp->scp;
4825 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
4827 /* compute open mode */
4829 if (desiredAccess & DELETE)
4830 fidflags |= SMB_FID_OPENDELETE;
4831 if (desiredAccess & AFS_ACCESS_READ)
4832 fidflags |= SMB_FID_OPENREAD;
4833 if (desiredAccess & AFS_ACCESS_WRITE)
4834 fidflags |= SMB_FID_OPENWRITE;
4838 /* For an exclusive create, we want to do a case sensitive match for the last component. */
4839 if (createDisp == 2 || createDisp == 4 || createDisp == 5) {
4840 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4841 userp, tidPathp, &req, &dscp);
4843 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
4845 if (code == CM_ERROR_NOSUCHFILE) {
4846 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
4847 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
4848 if (code == 0 && realDirFlag == 1) {
4849 cm_ReleaseSCache(scp);
4850 cm_ReleaseSCache(dscp);
4851 cm_ReleaseUser(userp);
4853 return CM_ERROR_EXISTS;
4859 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4860 userp, tidPathp, &req, &scp);
4865 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
4866 /* look up parent directory */
4867 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
4868 * the immediate parent. We have to work our way up realPathp until we hit something that we
4876 code = cm_NameI(baseDirp, spacep->data,
4877 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4878 userp, tidPathp, &req, &dscp);
4881 (tp = strrchr(spacep->data,'\\')) &&
4882 (createDisp == 2) &&
4883 (realDirFlag == 1)) {
4886 treeStartp = realPathp + (tp - spacep->data);
4888 if (*tp && !smb_IsLegalFilename(tp)) {
4890 smb_ReleaseFID(baseFidp);
4891 cm_ReleaseUser(userp);
4893 return CM_ERROR_BADNTFILENAME;
4903 smb_ReleaseFID(baseFidp);
4906 osi_Log0(smb_logp,"NTCreateX parent not found");
4907 cm_ReleaseUser(userp);
4912 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
4913 /* A file exists where we want a directory. */
4914 cm_ReleaseSCache(dscp);
4915 cm_ReleaseUser(userp);
4917 return CM_ERROR_EXISTS;
4921 lastNamep = realPathp;
4925 if (!smb_IsLegalFilename(lastNamep)) {
4926 cm_ReleaseSCache(dscp);
4927 cm_ReleaseUser(userp);
4929 return CM_ERROR_BADNTFILENAME;
4932 if (!foundscp && !treeCreate) {
4933 if (createDisp == 2 || createDisp == 4)
4934 code = cm_Lookup(dscp, lastNamep,
4935 CM_FLAG_FOLLOW, userp, &req, &scp);
4937 code = cm_Lookup(dscp, lastNamep,
4938 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4940 if (code && code != CM_ERROR_NOSUCHFILE) {
4941 cm_ReleaseSCache(dscp);
4942 cm_ReleaseUser(userp);
4950 smb_ReleaseFID(baseFidp);
4953 /* if we get here, if code is 0, the file exists and is represented by
4954 * scp. Otherwise, we have to create it. The dir may be represented
4955 * by dscp, or we may have found the file directly. If code is non-zero,
4958 if (code == 0 && !treeCreate) {
4959 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
4962 if (dscp) cm_ReleaseSCache(dscp);
4963 cm_ReleaseSCache(scp);
4964 cm_ReleaseUser(userp);
4969 if (createDisp == 2) {
4970 /* oops, file shouldn't be there */
4971 if (dscp) cm_ReleaseSCache(dscp);
4972 cm_ReleaseSCache(scp);
4973 cm_ReleaseUser(userp);
4975 return CM_ERROR_EXISTS;
4979 || createDisp == 5) {
4980 setAttr.mask = CM_ATTRMASK_LENGTH;
4981 setAttr.length.LowPart = 0;
4982 setAttr.length.HighPart = 0;
4983 code = cm_SetAttr(scp, &setAttr, userp, &req);
4984 openAction = 3; /* truncated existing file */
4986 else openAction = 1; /* found existing file */
4988 else if (createDisp == 1 || createDisp == 4) {
4989 /* don't create if not found */
4990 if (dscp) cm_ReleaseSCache(dscp);
4991 cm_ReleaseUser(userp);
4993 return CM_ERROR_NOSUCHFILE;
4995 else if (realDirFlag == 0 || realDirFlag == -1) {
4996 osi_assert(dscp != NULL);
4997 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
4998 osi_LogSaveString(smb_logp, lastNamep));
4999 openAction = 2; /* created file */
5000 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5001 setAttr.clientModTime = time(NULL);
5002 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5004 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5005 smb_NotifyChange(FILE_ACTION_ADDED,
5006 FILE_NOTIFY_CHANGE_FILE_NAME,
5007 dscp, lastNamep, NULL, TRUE);
5008 if (code == CM_ERROR_EXISTS && createDisp != 2) {
5009 /* Not an exclusive create, and someone else tried
5010 * creating it already, then we open it anyway. We
5011 * don't bother retrying after this, since if this next
5012 * fails, that means that the file was deleted after we
5013 * started this call.
5015 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5018 if (createDisp == 5) {
5019 setAttr.mask = CM_ATTRMASK_LENGTH;
5020 setAttr.length.LowPart = 0;
5021 setAttr.length.HighPart = 0;
5022 code = cm_SetAttr(scp, &setAttr, userp,
5025 } /* lookup succeeded */
5030 char *cp; /* This component */
5031 int clen = 0; /* length of component */
5035 /* create directory */
5036 if ( !treeCreate ) treeStartp = lastNamep;
5037 osi_assert(dscp != NULL);
5038 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
5039 osi_LogSaveString(smb_logp, treeStartp));
5040 openAction = 2; /* created directory */
5042 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5043 setAttr.clientModTime = time(NULL);
5050 tp = strchr(pp, '\\');
5054 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
5058 strncpy(cp,pp,clen);
5064 if (clen == 0) continue; /* the supplied path can't have consecutive slashes either , but */
5066 /* cp is the next component to be created. */
5067 code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
5068 if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
5069 smb_NotifyChange(FILE_ACTION_ADDED,
5070 FILE_NOTIFY_CHANGE_DIR_NAME,
5071 tscp, cp, NULL, TRUE);
5073 (code == CM_ERROR_EXISTS && createDisp != 2)) {
5074 /* Not an exclusive create, and someone else tried
5075 * creating it already, then we open it anyway. We
5076 * don't bother retrying after this, since if this next
5077 * fails, that means that the file was deleted after we
5078 * started this call.
5080 code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
5085 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
5086 cm_ReleaseSCache(tscp);
5087 tscp = scp; /* Newly created directory will be next parent */
5092 if we get here and code == 0, then scp is the last directory created, and tscp is the
5093 parent of scp. dscp got released if dscp != tscp. both tscp and scp are held.
5099 /* something went wrong creating or truncating the file */
5100 if (scp) cm_ReleaseSCache(scp);
5101 if (dscp) cm_ReleaseSCache(dscp);
5102 cm_ReleaseUser(userp);
5107 /* make sure we have file vs. dir right (only applies for single component case) */
5108 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5109 cm_ReleaseSCache(scp);
5110 if (dscp) cm_ReleaseSCache(dscp);
5111 cm_ReleaseUser(userp);
5113 return CM_ERROR_ISDIR;
5115 /* (only applies to single component case) */
5116 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5117 cm_ReleaseSCache(scp);
5118 if (dscp) cm_ReleaseSCache(dscp);
5119 cm_ReleaseUser(userp);
5121 return CM_ERROR_NOTDIR;
5124 /* open the file itself */
5125 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5127 /* save a pointer to the vnode */
5130 fidp->flags = fidflags;
5132 /* save parent dir and pathname for delete or change notification */
5133 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5134 fidp->flags |= SMB_FID_NTOPEN;
5135 fidp->NTopen_dscp = dscp;
5136 cm_HoldSCache(dscp);
5137 fidp->NTopen_pathp = strdup(lastNamep);
5139 fidp->NTopen_wholepathp = realPathp;
5141 /* we don't need this any longer */
5142 if (dscp) cm_ReleaseSCache(dscp);
5143 cm_Open(scp, 0, userp);
5145 /* set inp->fid so that later read calls in same msg can find fid */
5146 inp->fid = fidp->fid;
5150 lock_ObtainMutex(&scp->mx);
5151 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5152 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5153 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
5154 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5155 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5156 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5157 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5158 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5159 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
5161 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5162 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5163 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
5164 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
5165 smb_SetSMBParmByte(outp, parmSlot,
5166 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
5167 lock_ReleaseMutex(&scp->mx);
5168 smb_SetSMBDataLength(outp, 0);
5170 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
5171 osi_LogSaveString(smb_logp, realPathp));
5173 smb_ReleaseFID(fidp);
5175 cm_ReleaseUser(userp);
5177 /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
5179 /* leave scp held since we put it in fidp->scp */
5184 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
5185 * Instead, ultimately, would like to use a subroutine for common code.
5187 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5189 char *pathp, *realPathp;
5193 cm_scache_t *dscp; /* parent dir */
5194 cm_scache_t *scp; /* file to create or open */
5197 unsigned long nameLength;
5199 unsigned int requestOpLock;
5200 unsigned int requestBatchOpLock;
5201 unsigned int mustBeDir;
5202 unsigned int extendedRespRequired;
5204 unsigned int desiredAccess;
5205 #ifdef DEBUG_VERBOSE
5206 unsigned int allocSize;
5207 unsigned int shareAccess;
5209 unsigned int extAttributes;
5210 unsigned int createDisp;
5211 #ifdef DEBUG_VERBOSE
5214 unsigned int createOptions;
5215 int initialModeBits;
5216 unsigned short baseFid;
5217 smb_fid_t *baseFidp;
5219 cm_scache_t *baseDirp;
5220 unsigned short openAction;
5226 int parmOffset, dataOffset;
5237 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
5238 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
5239 parmp = inp->data + parmOffset;
5240 lparmp = (ULONG *) parmp;
5243 requestOpLock = flags & 0x02;
5244 requestBatchOpLock = flags & 0x04;
5245 mustBeDir = flags & 0x08;
5246 extendedRespRequired = flags & 0x10;
5249 * Why all of a sudden 32-bit FID?
5250 * We will reject all bits higher than 16.
5252 if (lparmp[1] & 0xFFFF0000)
5253 return CM_ERROR_INVAL;
5254 baseFid = (unsigned short)lparmp[1];
5255 desiredAccess = lparmp[2];
5256 #ifdef DEBUG_VERBOSE
5257 allocSize = lparmp[3];
5258 #endif /* DEBUG_VERSOSE */
5259 extAttributes = lparmp[5];
5261 shareAccess = lparmp[6];
5263 createDisp = lparmp[7];
5264 createOptions = lparmp[8];
5265 #ifdef DEBUG_VERBOSE
5268 nameLength = lparmp[11];
5270 #ifdef DEBUG_VERBOSE
5271 osi_Log4(smb_logp,"NTTransCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
5272 osi_Log2(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
5273 osi_Log1(smb_logp,"... flags[%x]",flags);
5276 /* mustBeDir is never set; createOptions directory bit seems to be
5279 if (createOptions & 1)
5281 else if (createOptions & 0x40)
5287 * compute initial mode bits based on read-only flag in
5288 * extended attributes
5290 initialModeBits = 0666;
5291 if (extAttributes & 1) initialModeBits &= ~0222;
5293 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
5294 /* Sometimes path is not null-terminated, so we make a copy. */
5295 realPathp = malloc(nameLength+1);
5296 memcpy(realPathp, pathp, nameLength);
5297 realPathp[nameLength] = 0;
5299 spacep = cm_GetSpace();
5300 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5303 * Nothing here to handle SMB_IOCTL_FILENAME.
5304 * Will add it if necessary.
5307 #ifdef DEBUG_VERBOSE
5309 char *hexp, *asciip;
5310 asciip = (lastNamep? lastNamep : realPathp);
5311 hexp = osi_HexifyString( asciip );
5312 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
5317 userp = smb_GetUser(vcp, inp);
5319 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
5321 return CM_ERROR_INVAL;
5325 baseDirp = cm_rootSCachep;
5326 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5327 if(code == CM_ERROR_TIDIPC) {
5328 /* Attempt to use TID allocated for IPC. The client is
5329 probably trying to locate DCE RPC endpoints, which we
5331 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
5333 cm_ReleaseUser(userp);
5334 return CM_ERROR_NOSUCHPATH;
5338 baseFidp = smb_FindFID(vcp, baseFid, 0);
5340 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
5342 cm_ReleaseUser(userp);
5343 return CM_ERROR_INVAL;
5345 baseDirp = baseFidp->scp;
5349 /* compute open mode */
5351 if (desiredAccess & DELETE)
5352 fidflags |= SMB_FID_OPENDELETE;
5353 if (desiredAccess & AFS_ACCESS_READ)
5354 fidflags |= SMB_FID_OPENREAD;
5355 if (desiredAccess & AFS_ACCESS_WRITE)
5356 fidflags |= SMB_FID_OPENWRITE;
5360 if (createDisp == 2 || createDisp == 4 || createDisp == 5) {
5361 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5362 userp, tidPathp, &req, &dscp);
5364 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5366 if (code == CM_ERROR_NOSUCHFILE) {
5367 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
5368 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
5369 if (code == 0 && realDirFlag == 1) {
5370 cm_ReleaseSCache(scp);
5371 cm_ReleaseSCache(dscp);
5372 cm_ReleaseUser(userp);
5374 return CM_ERROR_EXISTS;
5380 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5381 userp, tidPathp, &req, &scp);
5384 if (code == 0) foundscp = TRUE;
5386 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
5387 /* look up parent directory */
5389 code = cm_NameI(baseDirp, spacep->data,
5390 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5391 userp, tidPathp, &req, &dscp);
5395 cm_FreeSpace(spacep);
5398 smb_ReleaseFID(baseFidp);
5403 cm_ReleaseUser(userp);
5408 if (!lastNamep) lastNamep = realPathp;
5411 if (!smb_IsLegalFilename(lastNamep))
5412 return CM_ERROR_BADNTFILENAME;
5415 if (createDisp == 2 || createDisp == 4)
5416 code = cm_Lookup(dscp, lastNamep,
5417 CM_FLAG_FOLLOW, userp, &req, &scp);
5419 code = cm_Lookup(dscp, lastNamep,
5420 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5422 if (code && code != CM_ERROR_NOSUCHFILE) {
5423 cm_ReleaseSCache(dscp);
5424 cm_ReleaseUser(userp);
5432 smb_ReleaseFID(baseFidp);
5435 cm_FreeSpace(spacep);
5438 /* if we get here, if code is 0, the file exists and is represented by
5439 * scp. Otherwise, we have to create it. The dir may be represented
5440 * by dscp, or we may have found the file directly. If code is non-zero,
5444 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
5447 if (dscp) cm_ReleaseSCache(dscp);
5448 cm_ReleaseSCache(scp);
5449 cm_ReleaseUser(userp);
5454 if (createDisp == 2) {
5455 /* oops, file shouldn't be there */
5456 if (dscp) cm_ReleaseSCache(dscp);
5457 cm_ReleaseSCache(scp);
5458 cm_ReleaseUser(userp);
5460 return CM_ERROR_EXISTS;
5464 || createDisp == 5) {
5465 setAttr.mask = CM_ATTRMASK_LENGTH;
5466 setAttr.length.LowPart = 0;
5467 setAttr.length.HighPart = 0;
5468 code = cm_SetAttr(scp, &setAttr, userp, &req);
5469 openAction = 3; /* truncated existing file */
5471 else openAction = 1; /* found existing file */
5473 else if (createDisp == 1 || createDisp == 4) {
5474 /* don't create if not found */
5475 if (dscp) cm_ReleaseSCache(dscp);
5476 cm_ReleaseUser(userp);
5478 return CM_ERROR_NOSUCHFILE;
5480 else if (realDirFlag == 0 || realDirFlag == -1) {
5481 osi_assert(dscp != NULL);
5482 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
5483 osi_LogSaveString(smb_logp, lastNamep));
5484 openAction = 2; /* created file */
5485 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5486 setAttr.clientModTime = time(NULL);
5487 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5489 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5490 smb_NotifyChange(FILE_ACTION_ADDED,
5491 FILE_NOTIFY_CHANGE_FILE_NAME,
5492 dscp, lastNamep, NULL, TRUE);
5493 if (code == CM_ERROR_EXISTS && createDisp != 2) {
5494 /* Not an exclusive create, and someone else tried
5495 * creating it already, then we open it anyway. We
5496 * don't bother retrying after this, since if this next
5497 * fails, that means that the file was deleted after we
5498 * started this call.
5500 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5503 if (createDisp == 5) {
5504 setAttr.mask = CM_ATTRMASK_LENGTH;
5505 setAttr.length.LowPart = 0;
5506 setAttr.length.HighPart = 0;
5507 code = cm_SetAttr(scp, &setAttr, userp,
5510 } /* lookup succeeded */
5514 /* create directory */
5515 osi_assert(dscp != NULL);
5517 "smb_ReceiveNTTranCreate creating directory %s",
5518 osi_LogSaveString(smb_logp, lastNamep));
5519 openAction = 2; /* created directory */
5520 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5521 setAttr.clientModTime = time(NULL);
5522 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5523 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5524 smb_NotifyChange(FILE_ACTION_ADDED,
5525 FILE_NOTIFY_CHANGE_DIR_NAME,
5526 dscp, lastNamep, NULL, TRUE);
5528 || (code == CM_ERROR_EXISTS && createDisp != 2)) {
5529 /* Not an exclusive create, and someone else tried
5530 * creating it already, then we open it anyway. We
5531 * don't bother retrying after this, since if this next
5532 * fails, that means that the file was deleted after we
5533 * started this call.
5535 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5541 /* something went wrong creating or truncating the file */
5542 if (scp) cm_ReleaseSCache(scp);
5543 cm_ReleaseUser(userp);
5548 /* make sure we have file vs. dir right */
5549 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5550 cm_ReleaseSCache(scp);
5551 cm_ReleaseUser(userp);
5553 return CM_ERROR_ISDIR;
5555 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5556 cm_ReleaseSCache(scp);
5557 cm_ReleaseUser(userp);
5559 return CM_ERROR_NOTDIR;
5562 /* open the file itself */
5563 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5566 /* save a pointer to the vnode */
5569 fidp->flags = fidflags;
5571 /* save parent dir and pathname for deletion or change notification */
5572 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5573 fidp->flags |= SMB_FID_NTOPEN;
5574 fidp->NTopen_dscp = dscp;
5575 cm_HoldSCache(dscp);
5576 fidp->NTopen_pathp = strdup(lastNamep);
5578 fidp->NTopen_wholepathp = realPathp;
5580 /* we don't need this any longer */
5581 if (dscp) cm_ReleaseSCache(dscp);
5583 cm_Open(scp, 0, userp);
5585 /* set inp->fid so that later read calls in same msg can find fid */
5586 inp->fid = fidp->fid;
5588 /* check whether we are required to send an extended response */
5589 if (!extendedRespRequired) {
5591 parmOffset = 8*4 + 39;
5592 parmOffset += 1; /* pad to 4 */
5593 dataOffset = parmOffset + 70;
5597 /* Total Parameter Count */
5598 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
5599 /* Total Data Count */
5600 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5601 /* Parameter Count */
5602 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
5603 /* Parameter Offset */
5604 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5605 /* Parameter Displacement */
5606 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5608 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5610 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5611 /* Data Displacement */
5612 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5613 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5614 smb_SetSMBDataLength(outp, 70);
5616 lock_ObtainMutex(&scp->mx);
5617 outData = smb_GetSMBData(outp, NULL);
5618 outData++; /* round to get to parmOffset */
5619 *outData = 0; outData++; /* oplock */
5620 *outData = 0; outData++; /* reserved */
5621 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
5622 *((ULONG *)outData) = openAction; outData += 4;
5623 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
5624 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5625 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
5626 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
5627 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
5628 *((FILETIME *)outData) = ft; outData += 8; /* change time */
5629 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
5630 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
5631 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
5632 *((USHORT *)outData) = 0; outData += 2; /* filetype */
5633 *((USHORT *)outData) = 0; outData += 2; /* dev state */
5634 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
5635 outData += 2; /* is a dir? */
5636 lock_ReleaseMutex(&scp->mx);
5639 parmOffset = 8*4 + 39;
5640 parmOffset += 1; /* pad to 4 */
5641 dataOffset = parmOffset + 104;
5645 /* Total Parameter Count */
5646 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
5647 /* Total Data Count */
5648 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5649 /* Parameter Count */
5650 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
5651 /* Parameter Offset */
5652 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5653 /* Parameter Displacement */
5654 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5656 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5658 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5659 /* Data Displacement */
5660 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5661 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5662 smb_SetSMBDataLength(outp, 105);
5664 lock_ObtainMutex(&scp->mx);
5665 outData = smb_GetSMBData(outp, NULL);
5666 outData++; /* round to get to parmOffset */
5667 *outData = 0; outData++; /* oplock */
5668 *outData = 1; outData++; /* response type */
5669 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
5670 *((ULONG *)outData) = openAction; outData += 4;
5671 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
5672 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5673 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
5674 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
5675 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
5676 *((FILETIME *)outData) = ft; outData += 8; /* change time */
5677 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
5678 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
5679 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
5680 *((USHORT *)outData) = 0; outData += 2; /* filetype */
5681 *((USHORT *)outData) = 0; outData += 2; /* dev state */
5682 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
5683 outData += 1; /* is a dir? */
5684 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
5685 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
5686 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
5687 lock_ReleaseMutex(&scp->mx);
5690 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
5692 smb_ReleaseFID(fidp);
5694 cm_ReleaseUser(userp);
5696 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
5697 /* leave scp held since we put it in fidp->scp */
5701 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
5704 smb_packet_t *savedPacketp;
5705 ULONG filter; USHORT fid, watchtree;
5709 filter = smb_GetSMBParm(inp, 19)
5710 | (smb_GetSMBParm(inp, 20) << 16);
5711 fid = smb_GetSMBParm(inp, 21);
5712 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
5714 fidp = smb_FindFID(vcp, fid, 0);
5716 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
5717 return CM_ERROR_BADFD;
5720 savedPacketp = smb_CopyPacket(inp);
5722 savedPacketp->vcp = vcp;
5723 lock_ObtainMutex(&smb_Dir_Watch_Lock);
5724 savedPacketp->nextp = smb_Directory_Watches;
5725 smb_Directory_Watches = savedPacketp;
5726 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
5728 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
5729 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
5732 lock_ObtainMutex(&scp->mx);
5734 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
5736 scp->flags |= CM_SCACHEFLAG_WATCHED;
5737 lock_ReleaseMutex(&scp->mx);
5738 smb_ReleaseFID(fidp);
5740 outp->flags |= SMB_PACKETFLAG_NOSEND;
5744 unsigned char nullSecurityDesc[36] = {
5745 0x01, /* security descriptor revision */
5746 0x00, /* reserved, should be zero */
5747 0x00, 0x80, /* security descriptor control;
5748 * 0x8000 : self-relative format */
5749 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
5750 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
5751 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
5752 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
5753 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5754 /* "null SID" owner SID */
5755 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5756 /* "null SID" group SID */
5759 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5761 int parmOffset, parmCount, dataOffset, dataCount;
5769 ULONG securityInformation;
5771 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
5772 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
5773 parmp = inp->data + parmOffset;
5774 sparmp = (USHORT *) parmp;
5775 lparmp = (ULONG *) parmp;
5778 securityInformation = lparmp[1];
5780 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
5781 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
5789 parmOffset = 8*4 + 39;
5790 parmOffset += 1; /* pad to 4 */
5792 dataOffset = parmOffset + parmCount;
5796 /* Total Parameter Count */
5797 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
5798 /* Total Data Count */
5799 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
5800 /* Parameter Count */
5801 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
5802 /* Parameter Offset */
5803 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5804 /* Parameter Displacement */
5805 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5807 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
5809 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5810 /* Data Displacement */
5811 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5812 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5813 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
5815 outData = smb_GetSMBData(outp, NULL);
5816 outData++; /* round to get to parmOffset */
5817 *((ULONG *)outData) = 36; outData += 4; /* length */
5819 if (maxData >= 36) {
5820 memcpy(outData, nullSecurityDesc, 36);
5824 return CM_ERROR_BUFFERTOOSMALL;
5827 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5829 unsigned short function;
5831 function = smb_GetSMBParm(inp, 18);
5833 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
5835 /* We can handle long names */
5836 if (vcp->flags & SMB_VCFLAG_USENT)
5837 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
5841 case 6: return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
5843 case 4: return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
5845 case 1: return smb_ReceiveNTTranCreate(vcp, inp, outp);
5847 default: return CM_ERROR_INVAL;
5852 * smb_NotifyChange -- find relevant change notification messages and
5855 * If we don't know the file name (i.e. a callback break), filename is
5856 * NULL, and we return a zero-length list.
5858 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
5859 cm_scache_t *dscp, char *filename, char *otherFilename,
5860 BOOL isDirectParent)
5862 smb_packet_t *watch, *lastWatch, *nextWatch;
5863 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
5864 char *outData, *oldOutData;
5868 BOOL twoEntries = FALSE;
5869 ULONG otherNameLen, oldParmCount = 0;
5874 /* Get ready for rename within directory */
5875 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
5877 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
5880 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
5881 osi_LogSaveString(smb_logp,filename),dscp);
5883 lock_ObtainMutex(&smb_Dir_Watch_Lock);
5884 watch = smb_Directory_Watches;
5886 filter = smb_GetSMBParm(watch, 19)
5887 | (smb_GetSMBParm(watch, 20) << 16);
5888 fid = smb_GetSMBParm(watch, 21);
5889 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
5890 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
5891 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
5895 * Strange hack - bug in NT Client and NT Server that we
5898 if (filter == 3 && wtree)
5901 fidp = smb_FindFID(vcp, fid, 0);
5903 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
5905 watch = watch->nextp;
5908 if (fidp->scp != dscp
5909 || (filter & notifyFilter) == 0
5910 || (!isDirectParent && !wtree)) {
5911 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
5912 smb_ReleaseFID(fidp);
5914 watch = watch->nextp;
5917 smb_ReleaseFID(fidp);
5920 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
5921 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
5923 nextWatch = watch->nextp;
5924 if (watch == smb_Directory_Watches)
5925 smb_Directory_Watches = nextWatch;
5927 lastWatch->nextp = nextWatch;
5929 /* Turn off WATCHED flag in dscp */
5930 lock_ObtainMutex(&dscp->mx);
5932 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
5934 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
5935 lock_ReleaseMutex(&dscp->mx);
5937 /* Convert to response packet */
5938 ((smb_t *) watch)->reb = 0x80;
5939 ((smb_t *) watch)->wct = 0;
5942 if (filename == NULL)
5945 nameLen = strlen(filename);
5946 parmCount = 3*4 + nameLen*2;
5947 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
5949 otherNameLen = strlen(otherFilename);
5950 oldParmCount = parmCount;
5951 parmCount += 3*4 + otherNameLen*2;
5952 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
5954 if (maxLen < parmCount)
5955 parmCount = 0; /* not enough room */
5957 parmOffset = 8*4 + 39;
5958 parmOffset += 1; /* pad to 4 */
5959 dataOffset = parmOffset + parmCount;
5963 /* Total Parameter Count */
5964 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
5965 /* Total Data Count */
5966 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
5967 /* Parameter Count */
5968 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
5969 /* Parameter Offset */
5970 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
5971 /* Parameter Displacement */
5972 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
5974 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
5976 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
5977 /* Data Displacement */
5978 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
5979 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
5980 smb_SetSMBDataLength(watch, parmCount + 1);
5982 if (parmCount != 0) {
5983 outData = smb_GetSMBData(watch, NULL);
5984 outData++; /* round to get to parmOffset */
5985 oldOutData = outData;
5986 *((DWORD *)outData) = oldParmCount; outData += 4;
5987 /* Next Entry Offset */
5988 *((DWORD *)outData) = action; outData += 4;
5990 *((DWORD *)outData) = nameLen*2; outData += 4;
5991 /* File Name Length */
5992 mbstowcs((WCHAR *)outData, filename, nameLen);
5995 outData = oldOutData + oldParmCount;
5996 *((DWORD *)outData) = 0; outData += 4;
5997 /* Next Entry Offset */
5998 *((DWORD *)outData) = otherAction; outData += 4;
6000 *((DWORD *)outData) = otherNameLen*2;
6001 outData += 4; /* File Name Length */
6002 mbstowcs((WCHAR *)outData, otherFilename,
6003 otherNameLen); /* File Name */
6008 * If filename is null, we don't know the cause of the
6009 * change notification. We return zero data (see above),
6010 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
6011 * (= 0x010C). We set the error code here by hand, without
6012 * modifying wct and bcc.
6014 if (filename == NULL) {
6015 ((smb_t *) watch)->rcls = 0x0C;
6016 ((smb_t *) watch)->reh = 0x01;
6017 ((smb_t *) watch)->errLow = 0;
6018 ((smb_t *) watch)->errHigh = 0;
6019 /* Set NT Status codes flag */
6020 ((smb_t *) watch)->flg2 |= 0x4000;
6023 smb_SendPacket(vcp, watch);
6025 smb_FreePacket(watch);
6028 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6031 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6033 unsigned char *replyWctp;
6034 smb_packet_t *watch, *lastWatch;
6035 USHORT fid, watchtree;
6039 osi_Log0(smb_logp, "SMB3 receive NT cancel");
6041 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6042 watch = smb_Directory_Watches;
6044 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
6045 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
6046 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
6047 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
6048 if (watch == smb_Directory_Watches)
6049 smb_Directory_Watches = watch->nextp;
6051 lastWatch->nextp = watch->nextp;
6052 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6054 /* Turn off WATCHED flag in scp */
6055 fid = smb_GetSMBParm(watch, 21);
6056 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
6058 if (vcp != watch->vcp)
6059 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
6062 fidp = smb_FindFID(vcp, fid, 0);
6064 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
6066 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
6069 lock_ObtainMutex(&scp->mx);
6071 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6073 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
6074 lock_ReleaseMutex(&scp->mx);
6075 smb_ReleaseFID(fidp);
6077 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
6080 /* assume STATUS32; return 0xC0000120 (CANCELED) */
6081 replyWctp = watch->wctp;
6085 ((smb_t *)watch)->rcls = 0x20;
6086 ((smb_t *)watch)->reh = 0x1;
6087 ((smb_t *)watch)->errLow = 0;
6088 ((smb_t *)watch)->errHigh = 0xC0;
6089 ((smb_t *)watch)->flg2 |= 0x4000;
6090 smb_SendPacket(vcp, watch);
6092 smb_ReleaseVC(watch->vcp);
6093 smb_FreePacket(watch);
6097 watch = watch->nextp;
6099 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6106 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
6109 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
6112 smb_username_t *unp;
6114 unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
6116 lock_ObtainMutex(&unp->mx);
6117 unp->userp = cm_NewUser();
6118 lock_ReleaseMutex(&unp->mx);
6119 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6120 osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
6122 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6123 osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);