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 ( asp->totalParms > 0 && parmCount != 0 )
1297 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1299 if ( asp->totalData > 0 && 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->totalParms > 0 &&
1309 asp->curParms > 0 &&
1310 asp->totalData <= asp->curData &&
1311 asp->totalParms <= asp->curParms) {
1312 /* we've received it all */
1313 lock_ObtainWrite(&smb_globalLock);
1314 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1315 lock_ReleaseWrite(&smb_globalLock);
1317 /* now dispatch it */
1318 rapOp = asp->parmsp[0];
1320 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1321 osi_LogEvent("AFS-Dispatch-RAP[%s]",myCrt_RapDispatch(rapOp),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1322 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%x] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1323 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1326 osi_LogEvent("AFS-Dispatch-RAP [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1327 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1328 code = CM_ERROR_BADOP;
1331 /* if an error is returned, we're supposed to send an error packet,
1332 * otherwise the dispatched function already did the data sending.
1333 * We give dispatched proc the responsibility since it knows how much
1334 * space to allocate.
1337 smb_SendTran2Error(vcp, asp, outp, code);
1340 /* free the input tran 2 packet */
1341 lock_ObtainWrite(&smb_globalLock);
1342 smb_FreeTran2Packet(asp);
1343 lock_ReleaseWrite(&smb_globalLock);
1345 else if (firstPacket) {
1346 /* the first packet in a multi-packet request, we need to send an
1347 * ack to get more data.
1349 smb_SetSMBDataLength(outp, 0);
1350 smb_SendPacket(vcp, outp);
1356 /* ANSI versions. The unicode versions support arbitrary length
1357 share names, but we don't support unicode yet. */
1359 typedef struct smb_rap_share_info_0 {
1360 char shi0_netname[13];
1361 } smb_rap_share_info_0_t;
1363 typedef struct smb_rap_share_info_1 {
1364 char shi1_netname[13];
1367 DWORD shi1_remark; /* char *shi1_remark; data offset */
1368 } smb_rap_share_info_1_t;
1370 typedef struct smb_rap_share_info_2 {
1371 char shi2_netname[13];
1373 unsigned short shi2_type;
1374 DWORD shi2_remark; /* char *shi2_remark; data offset */
1375 unsigned short shi2_permissions;
1376 unsigned short shi2_max_uses;
1377 unsigned short shi2_current_uses;
1378 DWORD shi2_path; /* char *shi2_path; data offset */
1379 unsigned short shi2_passwd[9];
1380 unsigned short shi2_pad2;
1381 } smb_rap_share_info_2_t;
1383 #define SMB_RAP_MAX_SHARES 512
1385 typedef struct smb_rap_share_list {
1388 smb_rap_share_info_0_t * shares;
1389 } smb_rap_share_list_t;
1391 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1392 smb_rap_share_list_t * sp;
1397 if(name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1398 return 0; /* skip over '.' and '..' */
1400 sp = (smb_rap_share_list_t *) vrockp;
1402 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1403 sp->shares[sp->cShare].shi0_netname[12] = 0;
1407 if(sp->cShare >= sp->maxShares)
1408 return CM_ERROR_STOPNOW;
1413 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1415 smb_tran2Packet_t *outp;
1416 unsigned short * tp;
1420 int outParmsTotal; /* total parameter bytes */
1421 int outDataTotal; /* total data bytes */
1429 HKEY hkSubmount = NULL;
1430 smb_rap_share_info_1_t * shares;
1433 char thisShare[256];
1436 smb_rap_share_list_t rootShares;
1441 tp = p->parmsp + 1; /* skip over function number (always 0) */
1442 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1443 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1447 if(infoLevel != 1) {
1448 return CM_ERROR_INVAL;
1451 /* first figure out how many shares there are */
1452 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1453 KEY_QUERY_VALUE, &hkParam);
1454 if (rv == ERROR_SUCCESS) {
1455 len = sizeof(allSubmount);
1456 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1457 (BYTE *) &allSubmount, &len);
1458 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1461 RegCloseKey (hkParam);
1464 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1465 0, KEY_QUERY_VALUE, &hkSubmount);
1466 if (rv == ERROR_SUCCESS) {
1467 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1468 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1469 if (rv != ERROR_SUCCESS)
1475 /* fetch the root shares */
1476 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1477 rootShares.cShare = 0;
1478 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1482 userp = smb_GetTran2User(vcp,p);
1484 thyper.HighPart = 0;
1487 cm_HoldSCache(cm_rootSCachep);
1488 cm_ApplyDir(cm_rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1489 cm_ReleaseSCache(cm_rootSCachep);
1491 cm_ReleaseUser(userp);
1493 nShares = rootShares.cShare + nRegShares + allSubmount;
1495 #define REMARK_LEN 1
1496 outParmsTotal = 8; /* 4 dwords */
1497 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1498 if(outDataTotal > bufsize) {
1499 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1500 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1503 nSharesRet = nShares;
1506 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1508 /* now for the submounts */
1509 shares = (smb_rap_share_info_1_t *) outp->datap;
1510 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1512 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1515 strcpy( shares[cshare].shi1_netname, "all" );
1516 shares[cshare].shi1_remark = cstrp - outp->datap;
1517 /* type and pad are zero already */
1523 for(i=0; i < nRegShares && cshare < nSharesRet; i++) {
1524 len = sizeof(thisShare);
1525 rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1526 if(rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1527 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1528 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1529 shares[cshare].shi1_remark = cstrp - outp->datap;
1534 nShares--; /* uncount key */
1537 RegCloseKey(hkSubmount);
1540 nonrootShares = cshare;
1542 for(i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1543 /* in case there are collisions with submounts, submounts have higher priority */
1544 for(j=0; j < nonrootShares; j++)
1545 if(!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1548 if(j < nonrootShares) {
1549 nShares--; /* uncount */
1553 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1554 shares[cshare].shi1_remark = cstrp - outp->datap;
1559 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1560 outp->parmsp[1] = 0;
1561 outp->parmsp[2] = cshare;
1562 outp->parmsp[3] = nShares;
1564 outp->totalData = cstrp - outp->datap;
1565 outp->totalParms = outParmsTotal;
1567 smb_SendTran2Packet(vcp, outp, op);
1568 smb_FreeTran2Packet(outp);
1570 free(rootShares.shares);
1575 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1577 smb_tran2Packet_t *outp;
1578 unsigned short * tp;
1580 BOOL shareFound = FALSE;
1581 unsigned short infoLevel;
1582 unsigned short bufsize;
1592 tp = p->parmsp + 1; /* skip over function number (always 1) */
1593 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1594 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1595 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1602 totalData = sizeof(smb_rap_share_info_0_t);
1603 else if(infoLevel == 1)
1604 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1605 else if(infoLevel == 2)
1606 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1608 return CM_ERROR_INVAL;
1610 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1612 if(!stricmp(shareName,"all")) {
1613 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1614 KEY_QUERY_VALUE, &hkParam);
1615 if (rv == ERROR_SUCCESS) {
1616 len = sizeof(allSubmount);
1617 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1618 (BYTE *) &allSubmount, &len);
1619 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1622 RegCloseKey (hkParam);
1629 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts", 0,
1630 KEY_QUERY_VALUE, &hkSubmount);
1631 if(rv == ERROR_SUCCESS) {
1632 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1633 if(rv == ERROR_SUCCESS) {
1636 RegCloseKey(hkSubmount);
1641 smb_FreeTran2Packet(outp);
1642 return CM_ERROR_BADSHARENAME;
1645 memset(outp->datap, 0, totalData);
1647 outp->parmsp[0] = 0;
1648 outp->parmsp[1] = 0;
1649 outp->parmsp[2] = totalData;
1651 if(infoLevel == 0) {
1652 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1653 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1654 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1655 } else if(infoLevel == 1) {
1656 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1657 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1658 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1659 info->shi1_remark = ((unsigned char *) (info + 1)) - outp->datap;
1660 /* type and pad are already zero */
1661 } else { /* infoLevel==2 */
1662 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1663 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1664 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1665 info->shi2_remark = ((unsigned char *) (info + 1)) - outp->datap;
1666 info->shi2_permissions = ACCESS_ALL;
1667 info->shi2_max_uses = (unsigned short) -1;
1668 info->shi2_path = 1 + (((unsigned char *) (info + 1)) - outp->datap);
1671 outp->totalData = totalData;
1672 outp->totalParms = totalParam;
1674 smb_SendTran2Packet(vcp, outp, op);
1675 smb_FreeTran2Packet(outp);
1680 typedef struct smb_rap_wksta_info_10 {
1681 DWORD wki10_computername; /*char *wki10_computername;*/
1682 DWORD wki10_username; /* char *wki10_username; */
1683 DWORD wki10_langroup; /* char *wki10_langroup;*/
1684 unsigned char wki10_ver_major;
1685 unsigned char wki10_ver_minor;
1686 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1687 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1688 } smb_rap_wksta_info_10_t;
1691 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1693 smb_tran2Packet_t *outp;
1697 unsigned short * tp;
1700 smb_rap_wksta_info_10_t * info;
1704 tp = p->parmsp + 1; /* Skip over function number */
1705 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1706 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1710 if(infoLevel != 10) {
1711 return CM_ERROR_INVAL;
1717 totalData = sizeof(*info) + /* info */
1718 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1719 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1720 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1721 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1722 1; /* wki10_oth_domains (null)*/
1724 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1726 memset(outp->parmsp,0,totalParams);
1727 memset(outp->datap,0,totalData);
1729 info = (smb_rap_wksta_info_10_t *) outp->datap;
1730 cstrp = (char *) (info + 1);
1732 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1733 strcpy(cstrp, smb_localNamep);
1734 cstrp += strlen(cstrp) + 1;
1736 info->wki10_username = (DWORD) (cstrp - outp->datap);
1737 uidp = smb_FindUID(vcp, p->uid, 0);
1739 lock_ObtainMutex(&uidp->mx);
1740 if(uidp->unp && uidp->unp->name)
1741 strcpy(cstrp, uidp->unp->name);
1742 lock_ReleaseMutex(&uidp->mx);
1743 smb_ReleaseUID(uidp);
1745 cstrp += strlen(cstrp) + 1;
1747 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1748 strcpy(cstrp, "WORKGROUP");
1749 cstrp += strlen(cstrp) + 1;
1751 /* TODO: Not sure what values these should take, but these work */
1752 info->wki10_ver_major = 5;
1753 info->wki10_ver_minor = 1;
1755 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1756 strcpy(cstrp, smb_ServerDomainName);
1757 cstrp += strlen(cstrp) + 1;
1759 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1760 cstrp ++; /* no other domains */
1762 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1763 outp->parmsp[2] = outp->totalData;
1764 outp->totalParms = totalParams;
1766 smb_SendTran2Packet(vcp,outp,op);
1767 smb_FreeTran2Packet(outp);
1772 typedef struct smb_rap_server_info_0 {
1774 } smb_rap_server_info_0_t;
1776 typedef struct smb_rap_server_info_1 {
1778 char sv1_version_major;
1779 char sv1_version_minor;
1780 unsigned long sv1_type;
1781 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1782 } smb_rap_server_info_1_t;
1784 char smb_ServerComment[] = "OpenAFS Client";
1785 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1787 #define SMB_SV_TYPE_SERVER 0x00000002L
1788 #define SMB_SV_TYPE_NT 0x00001000L
1789 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1791 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1793 smb_tran2Packet_t *outp;
1797 unsigned short * tp;
1800 smb_rap_server_info_0_t * info0;
1801 smb_rap_server_info_1_t * info1;
1804 tp = p->parmsp + 1; /* Skip over function number */
1805 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1806 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1810 if(infoLevel != 0 && infoLevel != 1) {
1811 return CM_ERROR_INVAL;
1817 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1818 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1820 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1822 memset(outp->parmsp,0,totalParams);
1823 memset(outp->datap,0,totalData);
1825 if(infoLevel == 0) {
1826 info0 = (smb_rap_server_info_0_t *) outp->datap;
1827 cstrp = (char *) (info0 + 1);
1828 strcpy(info0->sv0_name, "AFS");
1829 } else { /* infoLevel == 1 */
1830 info1 = (smb_rap_server_info_1_t *) outp->datap;
1831 cstrp = (char *) (info1 + 1);
1832 strcpy(info1->sv1_name, "AFS");
1835 SMB_SV_TYPE_SERVER |
1837 SMB_SV_TYPE_SERVER_NT;
1839 info1->sv1_version_major = 5;
1840 info1->sv1_version_minor = 1;
1841 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1843 strcpy(cstrp, smb_ServerComment);
1845 cstrp += smb_ServerCommentLen;
1848 totalData = cstrp - outp->datap;
1849 outp->totalData = min(bufsize,totalData); /* actual data size */
1850 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1851 outp->parmsp[2] = totalData;
1852 outp->totalParms = totalParams;
1854 smb_SendTran2Packet(vcp,outp,op);
1855 smb_FreeTran2Packet(outp);
1860 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1862 smb_tran2Packet_t *asp;
1874 /* We sometimes see 0 word count. What to do? */
1875 if (*inp->wctp == 0) {
1880 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1882 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1883 ptbuf[0] = "Transaction2 word count = 0";
1884 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1885 1, inp->ncb_length, ptbuf, inp);
1886 DeregisterEventSource(h);
1888 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1891 smb_SetSMBDataLength(outp, 0);
1892 smb_SendPacket(vcp, outp);
1896 totalParms = smb_GetSMBParm(inp, 0);
1897 totalData = smb_GetSMBParm(inp, 1);
1899 firstPacket = (inp->inCom == 0x32);
1901 /* find the packet we're reassembling */
1902 lock_ObtainWrite(&smb_globalLock);
1903 asp = smb_FindTran2Packet(vcp, inp);
1905 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1907 lock_ReleaseWrite(&smb_globalLock);
1909 /* now merge in this latest packet; start by looking up offsets */
1911 parmDisp = dataDisp = 0;
1912 parmOffset = smb_GetSMBParm(inp, 10);
1913 dataOffset = smb_GetSMBParm(inp, 12);
1914 parmCount = smb_GetSMBParm(inp, 9);
1915 dataCount = smb_GetSMBParm(inp, 11);
1916 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1917 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1919 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1920 totalData, dataCount, asp->maxReturnData);
1923 parmDisp = smb_GetSMBParm(inp, 4);
1924 parmOffset = smb_GetSMBParm(inp, 3);
1925 dataDisp = smb_GetSMBParm(inp, 7);
1926 dataOffset = smb_GetSMBParm(inp, 6);
1927 parmCount = smb_GetSMBParm(inp, 2);
1928 dataCount = smb_GetSMBParm(inp, 5);
1930 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1931 parmCount, dataCount);
1934 /* now copy the parms and data */
1935 if ( asp->totalParms > 0 && parmCount != 0 )
1937 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1939 if ( asp->totalData > 0 && dataCount != 0 ) {
1940 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1943 /* account for new bytes */
1944 asp->curData += dataCount;
1945 asp->curParms += parmCount;
1947 /* finally, if we're done, remove the packet from the queue and dispatch it */
1948 if (asp->totalParms > 0 &&
1949 asp->curParms > 0 &&
1950 asp->totalData <= asp->curData &&
1951 asp->totalParms <= asp->curParms) {
1952 /* we've received it all */
1953 lock_ObtainWrite(&smb_globalLock);
1954 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1955 lock_ReleaseWrite(&smb_globalLock);
1957 /* now dispatch it */
1958 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
1959 osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1960 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
1961 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
1964 osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1965 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1966 code = CM_ERROR_BADOP;
1969 /* if an error is returned, we're supposed to send an error packet,
1970 * otherwise the dispatched function already did the data sending.
1971 * We give dispatched proc the responsibility since it knows how much
1972 * space to allocate.
1975 smb_SendTran2Error(vcp, asp, outp, code);
1978 /* free the input tran 2 packet */
1979 lock_ObtainWrite(&smb_globalLock);
1980 smb_FreeTran2Packet(asp);
1981 lock_ReleaseWrite(&smb_globalLock);
1983 else if (firstPacket) {
1984 /* the first packet in a multi-packet request, we need to send an
1985 * ack to get more data.
1987 smb_SetSMBDataLength(outp, 0);
1988 smb_SendPacket(vcp, outp);
1994 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1997 smb_tran2Packet_t *outp;
2002 cm_scache_t *dscp; /* dir we're dealing with */
2003 cm_scache_t *scp; /* file we're creating */
2005 int initialModeBits;
2015 int parmSlot; /* which parm we're dealing with */
2016 long returnEALength;
2024 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2025 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2027 openFun = p->parmsp[6]; /* open function */
2028 excl = ((openFun & 3) == 0);
2029 trunc = ((openFun & 3) == 2); /* truncate it */
2030 openMode = (p->parmsp[1] & 0x7);
2031 openAction = 0; /* tracks what we did */
2033 attributes = p->parmsp[3];
2034 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2036 /* compute initial mode bits based on read-only flag in attributes */
2037 initialModeBits = 0666;
2038 if (attributes & 1) initialModeBits &= ~0222;
2040 pathp = (char *) (&p->parmsp[14]);
2042 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2044 spacep = cm_GetSpace();
2045 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2047 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2048 /* special case magic file name for receiving IOCTL requests
2049 * (since IOCTL calls themselves aren't getting through).
2051 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2052 smb_SetupIoctlFid(fidp, spacep);
2054 /* copy out remainder of the parms */
2056 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2058 outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
2059 outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
2060 outp->parmsp[parmSlot] = 0; parmSlot++;
2061 outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
2062 outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
2063 outp->parmsp[parmSlot] = openMode; parmSlot++;
2064 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2065 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2067 /* and the final "always present" stuff */
2068 outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
2069 /* next write out the "unique" ID */
2070 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
2071 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
2072 outp->parmsp[parmSlot] = 0; parmSlot++;
2073 if (returnEALength) {
2074 outp->parmsp[parmSlot] = 0; parmSlot++;
2075 outp->parmsp[parmSlot] = 0; parmSlot++;
2078 outp->totalData = 0;
2079 outp->totalParms = parmSlot * 2;
2081 smb_SendTran2Packet(vcp, outp, op);
2083 smb_FreeTran2Packet(outp);
2085 /* and clean up fid reference */
2086 smb_ReleaseFID(fidp);
2090 #ifdef DEBUG_VERBOSE
2092 char *hexp, *asciip;
2093 asciip = (lastNamep ? lastNamep : pathp);
2094 hexp = osi_HexifyString( asciip );
2095 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2100 userp = smb_GetTran2User(vcp, p);
2101 /* In the off chance that userp is NULL, we log and abandon */
2103 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2104 smb_FreeTran2Packet(outp);
2105 return CM_ERROR_BADSMB;
2108 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2109 if(code == CM_ERROR_TIDIPC) {
2110 /* Attempt to use TID allocated for IPC. The client is
2111 probably trying to locate DCE RPC end points, which
2112 we don't support. */
2113 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2114 cm_ReleaseUser(userp);
2115 smb_FreeTran2Packet(outp);
2116 return CM_ERROR_NOSUCHPATH;
2120 code = cm_NameI(cm_rootSCachep, pathp,
2121 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2122 userp, tidPathp, &req, &scp);
2124 code = cm_NameI(cm_rootSCachep, spacep->data,
2125 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2126 userp, tidPathp, &req, &dscp);
2127 cm_FreeSpace(spacep);
2130 cm_ReleaseUser(userp);
2131 smb_FreeTran2Packet(outp);
2135 /* otherwise, scp points to the parent directory. Do a lookup,
2136 * and truncate the file if we find it, otherwise we create the
2139 if (!lastNamep) lastNamep = pathp;
2141 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2143 if (code && code != CM_ERROR_NOSUCHFILE) {
2144 cm_ReleaseSCache(dscp);
2145 cm_ReleaseUser(userp);
2146 smb_FreeTran2Packet(outp);
2151 cm_FreeSpace(spacep);
2154 /* if we get here, if code is 0, the file exists and is represented by
2155 * scp. Otherwise, we have to create it.
2158 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2160 if (dscp) cm_ReleaseSCache(dscp);
2161 cm_ReleaseSCache(scp);
2162 cm_ReleaseUser(userp);
2163 smb_FreeTran2Packet(outp);
2168 /* oops, file shouldn't be there */
2169 if (dscp) cm_ReleaseSCache(dscp);
2170 cm_ReleaseSCache(scp);
2171 cm_ReleaseUser(userp);
2172 smb_FreeTran2Packet(outp);
2173 return CM_ERROR_EXISTS;
2177 setAttr.mask = CM_ATTRMASK_LENGTH;
2178 setAttr.length.LowPart = 0;
2179 setAttr.length.HighPart = 0;
2180 code = cm_SetAttr(scp, &setAttr, userp, &req);
2181 openAction = 3; /* truncated existing file */
2183 else openAction = 1; /* found existing file */
2185 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
2186 /* don't create if not found */
2187 if (dscp) cm_ReleaseSCache(dscp);
2188 osi_assert(scp == NULL);
2189 cm_ReleaseUser(userp);
2190 smb_FreeTran2Packet(outp);
2191 return CM_ERROR_NOSUCHFILE;
2194 osi_assert(dscp != NULL && scp == NULL);
2195 openAction = 2; /* created file */
2196 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2197 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2198 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2200 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2201 smb_NotifyChange(FILE_ACTION_ADDED,
2202 FILE_NOTIFY_CHANGE_FILE_NAME,
2203 dscp, lastNamep, NULL, TRUE);
2204 if (!excl && code == CM_ERROR_EXISTS) {
2205 /* not an exclusive create, and someone else tried
2206 * creating it already, then we open it anyway. We
2207 * don't bother retrying after this, since if this next
2208 * fails, that means that the file was deleted after we
2209 * started this call.
2211 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2215 setAttr.mask = CM_ATTRMASK_LENGTH;
2216 setAttr.length.LowPart = 0;
2217 setAttr.length.HighPart = 0;
2218 code = cm_SetAttr(scp, &setAttr, userp,
2221 } /* lookup succeeded */
2225 /* we don't need this any longer */
2226 if (dscp) cm_ReleaseSCache(dscp);
2229 /* something went wrong creating or truncating the file */
2230 if (scp) cm_ReleaseSCache(scp);
2231 cm_ReleaseUser(userp);
2232 smb_FreeTran2Packet(outp);
2236 /* make sure we're about to open a file */
2237 if (scp->fileType != CM_SCACHETYPE_FILE) {
2238 cm_ReleaseSCache(scp);
2239 cm_ReleaseUser(userp);
2240 smb_FreeTran2Packet(outp);
2241 return CM_ERROR_ISDIR;
2244 /* now all we have to do is open the file itself */
2245 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2248 /* save a pointer to the vnode */
2251 /* compute open mode */
2252 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2253 if (openMode == 1 || openMode == 2)
2254 fidp->flags |= SMB_FID_OPENWRITE;
2256 smb_ReleaseFID(fidp);
2258 cm_Open(scp, 0, userp);
2260 /* copy out remainder of the parms */
2262 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2263 lock_ObtainMutex(&scp->mx);
2265 outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
2266 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2267 outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
2268 outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
2269 outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
2271 outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2273 outp->parmsp[parmSlot] = openMode; parmSlot++;
2274 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2275 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2277 /* and the final "always present" stuff */
2278 outp->parmsp[parmSlot] = openAction; parmSlot++;
2279 /* next write out the "unique" ID */
2280 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
2281 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
2282 outp->parmsp[parmSlot] = 0; parmSlot++;
2283 if (returnEALength) {
2284 outp->parmsp[parmSlot] = 0; parmSlot++;
2285 outp->parmsp[parmSlot] = 0; parmSlot++;
2287 lock_ReleaseMutex(&scp->mx);
2288 outp->totalData = 0; /* total # of data bytes */
2289 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2291 smb_SendTran2Packet(vcp, outp, op);
2293 smb_FreeTran2Packet(outp);
2295 cm_ReleaseUser(userp);
2296 /* leave scp held since we put it in fidp->scp */
2300 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2302 return CM_ERROR_BADOP;
2305 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2307 return CM_ERROR_BADOP;
2310 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2312 smb_tran2Packet_t *outp;
2313 smb_tran2QFSInfo_t qi;
2316 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
2318 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2320 switch (p->parmsp[0]) {
2321 case 1: responseSize = sizeof(qi.u.allocInfo); break;
2322 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
2323 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
2324 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
2325 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
2326 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
2327 default: return CM_ERROR_INVAL;
2330 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2331 switch (p->parmsp[0]) {
2334 qi.u.allocInfo.FSID = 0;
2335 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2336 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2337 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2338 qi.u.allocInfo.bytesPerSector = 1024;
2343 qi.u.volumeInfo.vsn = 1234;
2344 qi.u.volumeInfo.vnCount = 4;
2345 /* we're supposed to pad it out with zeroes to the end */
2346 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2347 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2351 /* FS volume info */
2352 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
2353 qi.u.FSvolumeInfo.vsn = 1234;
2354 qi.u.FSvolumeInfo.vnCount = 8;
2355 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
2361 temp.LowPart = 0x7fffffff;
2362 qi.u.FSsizeInfo.totalAllocUnits = temp;
2363 temp.LowPart = 0x3fffffff;
2364 qi.u.FSsizeInfo.availAllocUnits = temp;
2365 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2366 qi.u.FSsizeInfo.bytesPerSector = 1024;
2370 /* FS device info */
2371 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
2372 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2376 /* FS attribute info */
2377 /* attributes, defined in WINNT.H:
2378 * FILE_CASE_SENSITIVE_SEARCH 0x1
2379 * FILE_CASE_PRESERVED_NAMES 0x2
2380 * <no name defined> 0x4000
2381 * If bit 0x4000 is not set, Windows 95 thinks
2382 * we can't handle long (non-8.3) names,
2383 * despite our protestations to the contrary.
2385 qi.u.FSattributeInfo.attributes = 0x4003;
2386 qi.u.FSattributeInfo.maxCompLength = 255;
2387 qi.u.FSattributeInfo.FSnameLength = 6;
2388 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
2392 /* copy out return data, and set corresponding sizes */
2393 outp->totalParms = 0;
2394 outp->totalData = responseSize;
2395 memcpy(outp->datap, &qi, responseSize);
2397 /* send and free the packets */
2398 smb_SendTran2Packet(vcp, outp, op);
2399 smb_FreeTran2Packet(outp);
2404 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2406 return CM_ERROR_BADOP;
2409 struct smb_ShortNameRock {
2413 size_t shortNameLen;
2416 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2419 struct smb_ShortNameRock *rockp;
2423 /* compare both names and vnodes, though probably just comparing vnodes
2424 * would be safe enough.
2426 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2428 if (ntohl(dep->fid.vnode) != rockp->vnode)
2430 /* This is the entry */
2431 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2432 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2433 return CM_ERROR_STOPNOW;
2436 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2437 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2439 struct smb_ShortNameRock rock;
2443 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2447 spacep = cm_GetSpace();
2448 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2450 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
2452 cm_FreeSpace(spacep);
2453 if (code) return code;
2455 if (!lastNamep) lastNamep = pathp;
2458 thyper.HighPart = 0;
2459 rock.shortName = shortName;
2461 rock.maskp = lastNamep;
2462 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
2465 cm_ReleaseSCache(dscp);
2468 return CM_ERROR_NOSUCHFILE;
2469 if (code == CM_ERROR_STOPNOW) {
2470 *shortNameLenp = rock.shortNameLen;
2476 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2478 smb_tran2Packet_t *outp;
2479 unsigned long dosTime;
2481 unsigned short infoLevel;
2483 unsigned short attributes;
2484 unsigned long extAttributes;
2489 cm_scache_t *scp, *dscp;
2498 infoLevel = p->parmsp[0];
2499 if (infoLevel == 6) nbytesRequired = 0;
2500 else if (infoLevel == 1) nbytesRequired = 22;
2501 else if (infoLevel == 2) nbytesRequired = 26;
2502 else if (infoLevel == 0x101) nbytesRequired = 40;
2503 else if (infoLevel == 0x102) nbytesRequired = 24;
2504 else if (infoLevel == 0x103) nbytesRequired = 4;
2505 else if (infoLevel == 0x108) nbytesRequired = 30;
2507 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2508 p->opcode, infoLevel);
2509 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2512 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2513 osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
2515 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2517 if (infoLevel > 0x100)
2518 outp->totalParms = 2;
2520 outp->totalParms = 0;
2521 outp->totalData = nbytesRequired;
2523 /* now, if we're at infoLevel 6, we're only being asked to check
2524 * the syntax, so we just OK things now. In particular, we're *not*
2525 * being asked to verify anything about the state of any parent dirs.
2527 if (infoLevel == 6) {
2528 smb_SendTran2Packet(vcp, outp, opx);
2529 smb_FreeTran2Packet(outp);
2533 userp = smb_GetTran2User(vcp, p);
2535 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2536 smb_FreeTran2Packet(outp);
2537 return CM_ERROR_BADSMB;
2540 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2542 cm_ReleaseUser(userp);
2543 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2544 smb_FreeTran2Packet(outp);
2549 * XXX Strange hack XXX
2551 * As of Patch 7 (13 January 98), we are having the following problem:
2552 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2553 * requests to look up "desktop.ini" in all the subdirectories.
2554 * This can cause zillions of timeouts looking up non-existent cells
2555 * and volumes, especially in the top-level directory.
2557 * We have not found any way to avoid this or work around it except
2558 * to explicitly ignore the requests for mount points that haven't
2559 * yet been evaluated and for directories that haven't yet been
2562 if (infoLevel == 0x101) {
2563 spacep = cm_GetSpace();
2564 smb_StripLastComponent(spacep->data, &lastComp,
2565 (char *)(&p->parmsp[3]));
2566 /* Make sure that lastComp is not NULL */
2568 if (strcmp(lastComp, "\\desktop.ini") == 0) {
2569 code = cm_NameI(cm_rootSCachep, spacep->data,
2573 userp, tidPathp, &req, &dscp);
2575 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
2576 && !dscp->mountRootFidp)
2577 code = CM_ERROR_NOSUCHFILE;
2578 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2579 cm_buf_t *bp = buf_Find(dscp, &hzero);
2583 code = CM_ERROR_NOSUCHFILE;
2585 cm_ReleaseSCache(dscp);
2587 cm_FreeSpace(spacep);
2588 cm_ReleaseUser(userp);
2589 smb_SendTran2Error(vcp, p, opx, code);
2590 smb_FreeTran2Packet(outp);
2596 cm_FreeSpace(spacep);
2599 /* now do namei and stat, and copy out the info */
2600 code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
2601 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2604 cm_ReleaseUser(userp);
2605 smb_SendTran2Error(vcp, p, opx, code);
2606 smb_FreeTran2Packet(outp);
2610 lock_ObtainMutex(&scp->mx);
2611 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2612 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2613 if (code) goto done;
2615 /* now we have the status in the cache entry, and everything is locked.
2616 * Marshall the output data.
2619 /* for info level 108, figure out short name */
2620 if (infoLevel == 0x108) {
2621 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
2622 tidPathp, scp->fid.vnode, shortName,
2629 *((u_long *)op) = len * 2; op += 4;
2630 mbstowcs((unsigned short *)op, shortName, len);
2635 if (infoLevel == 1 || infoLevel == 2) {
2636 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2637 *((u_long *)op) = dosTime; op += 4; /* creation time */
2638 *((u_long *)op) = dosTime; op += 4; /* access time */
2639 *((u_long *)op) = dosTime; op += 4; /* write time */
2640 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
2641 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
2642 attributes = smb_Attributes(scp);
2643 *((u_short *)op) = attributes; op += 2; /* attributes */
2645 else if (infoLevel == 0x101) {
2646 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2647 *((FILETIME *)op) = ft; op += 8; /* creation time */
2648 *((FILETIME *)op) = ft; op += 8; /* last access time */
2649 *((FILETIME *)op) = ft; op += 8; /* last write time */
2650 *((FILETIME *)op) = ft; op += 8; /* last change time */
2651 extAttributes = smb_ExtAttributes(scp);
2652 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
2653 *((u_long *)op) = 0; op += 4; /* don't know what this is */
2655 else if (infoLevel == 0x102) {
2656 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2657 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2658 *((u_long *)op) = scp->linkCount; op += 4;
2661 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2664 else if (infoLevel == 0x103) {
2665 memset(op, 0, 4); op += 4; /* EA size */
2668 /* now, if we are being asked about extended attrs, return a 0 size */
2669 if (infoLevel == 2) {
2670 *((u_long *)op) = 0; op += 4;
2674 /* send and free the packets */
2676 lock_ReleaseMutex(&scp->mx);
2677 cm_ReleaseSCache(scp);
2678 cm_ReleaseUser(userp);
2680 smb_SendTran2Packet(vcp, outp, opx);
2682 smb_SendTran2Error(vcp, p, opx, code);
2683 smb_FreeTran2Packet(outp);
2688 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2690 return CM_ERROR_BADOP;
2693 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2695 smb_tran2Packet_t *outp;
2697 unsigned long attributes;
2698 unsigned short infoLevel;
2711 fidp = smb_FindFID(vcp, fid, 0);
2714 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2718 infoLevel = p->parmsp[1];
2719 if (infoLevel == 0x101) nbytesRequired = 40;
2720 else if (infoLevel == 0x102) nbytesRequired = 24;
2721 else if (infoLevel == 0x103) nbytesRequired = 4;
2722 else if (infoLevel == 0x104) nbytesRequired = 6;
2724 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2725 p->opcode, infoLevel);
2726 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2727 smb_ReleaseFID(fidp);
2730 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2732 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2734 if (infoLevel > 0x100)
2735 outp->totalParms = 2;
2737 outp->totalParms = 0;
2738 outp->totalData = nbytesRequired;
2740 userp = smb_GetTran2User(vcp, p);
2742 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2743 code = CM_ERROR_BADSMB;
2748 lock_ObtainMutex(&scp->mx);
2749 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2750 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2751 if (code) goto done;
2753 /* now we have the status in the cache entry, and everything is locked.
2754 * Marshall the output data.
2757 if (infoLevel == 0x101) {
2758 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2759 *((FILETIME *)op) = ft; op += 8; /* creation time */
2760 *((FILETIME *)op) = ft; op += 8; /* last access time */
2761 *((FILETIME *)op) = ft; op += 8; /* last write time */
2762 *((FILETIME *)op) = ft; op += 8; /* last change time */
2763 attributes = smb_ExtAttributes(scp);
2764 *((u_long *)op) = attributes; op += 4;
2765 *((u_long *)op) = 0; op += 4;
2767 else if (infoLevel == 0x102) {
2768 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2769 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2770 *((u_long *)op) = scp->linkCount; op += 4;
2771 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
2772 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2776 else if (infoLevel == 0x103) {
2777 *((u_long *)op) = 0; op += 4;
2779 else if (infoLevel == 0x104) {
2783 if (fidp->NTopen_wholepathp)
2784 name = fidp->NTopen_wholepathp;
2786 name = "\\"; /* probably can't happen */
2788 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
2789 *((u_long *)op) = len * 2; op += 4;
2790 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2793 /* send and free the packets */
2795 lock_ReleaseMutex(&scp->mx);
2796 cm_ReleaseUser(userp);
2797 smb_ReleaseFID(fidp);
2798 if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
2799 else smb_SendTran2Error(vcp, p, opx, code);
2800 smb_FreeTran2Packet(outp);
2805 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2810 unsigned short infoLevel;
2811 smb_tran2Packet_t *outp;
2819 fidp = smb_FindFID(vcp, fid, 0);
2822 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
2826 infoLevel = p->parmsp[1];
2827 if (infoLevel > 0x104 || infoLevel < 0x101) {
2828 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2829 p->opcode, infoLevel);
2830 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
2831 smb_ReleaseFID(fidp);
2835 if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
2836 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2837 smb_ReleaseFID(fidp);
2840 if ((infoLevel == 0x103 || infoLevel == 0x104)
2841 && !(fidp->flags & SMB_FID_OPENWRITE)) {
2842 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2843 smb_ReleaseFID(fidp);
2847 osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
2849 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
2851 outp->totalParms = 2;
2852 outp->totalData = 0;
2854 userp = smb_GetTran2User(vcp, p);
2856 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
2857 code = CM_ERROR_BADSMB;
2863 if (infoLevel == 0x101) {
2865 unsigned int attribute;
2868 /* lock the vnode with a callback; we need the current status
2869 * to determine what the new status is, in some cases.
2871 lock_ObtainMutex(&scp->mx);
2872 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2873 CM_SCACHESYNC_GETSTATUS
2874 | CM_SCACHESYNC_NEEDCALLBACK);
2876 lock_ReleaseMutex(&scp->mx);
2880 /* prepare for setattr call */
2883 lastMod = *((FILETIME *)(p->datap + 16));
2884 /* when called as result of move a b, lastMod is (-1, -1).
2885 * If the check for -1 is not present, timestamp
2886 * of the resulting file will be 1969 (-1)
2888 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
2889 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
2890 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
2891 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
2893 fidp->flags |= SMB_FID_MTIMESETDONE;
2896 attribute = *((u_long *)(p->datap + 32));
2897 if (attribute != 0) {
2898 if ((scp->unixModeBits & 0222)
2899 && (attribute & 1) != 0) {
2900 /* make a writable file read-only */
2901 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2902 attr.unixModeBits = scp->unixModeBits & ~0222;
2904 else if ((scp->unixModeBits & 0222) == 0
2905 && (attribute & 1) == 0) {
2906 /* make a read-only file writable */
2907 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2908 attr.unixModeBits = scp->unixModeBits | 0222;
2911 lock_ReleaseMutex(&scp->mx);
2915 code = cm_SetAttr(scp, &attr, userp, &req);
2919 else if (infoLevel == 0x103 || infoLevel == 0x104) {
2920 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
2923 attr.mask = CM_ATTRMASK_LENGTH;
2924 attr.length.LowPart = size.LowPart;
2925 attr.length.HighPart = size.HighPart;
2926 code = cm_SetAttr(scp, &attr, userp, &req);
2928 else if (infoLevel == 0x102) {
2929 if (*((char *)(p->datap))) {
2930 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
2933 fidp->flags |= SMB_FID_DELONCLOSE;
2937 fidp->flags &= ~SMB_FID_DELONCLOSE;
2941 cm_ReleaseUser(userp);
2942 smb_ReleaseFID(fidp);
2943 if (code == 0) smb_SendTran2Packet(vcp, outp, op);
2944 else smb_SendTran2Error(vcp, p, op, code);
2945 smb_FreeTran2Packet(outp);
2950 long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2952 return CM_ERROR_BADOP;
2955 long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2957 return CM_ERROR_BADOP;
2960 long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2962 return CM_ERROR_BADOP;
2965 long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2967 return CM_ERROR_BADOP;
2970 long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2972 return CM_ERROR_BADOP;
2975 long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
2976 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
2981 cm_scache_t *targetScp; /* target if scp is a symlink */
2986 unsigned short attr;
2987 unsigned long lattr;
2988 smb_dirListPatch_t *patchp;
2989 smb_dirListPatch_t *npatchp;
2991 for(patchp = *dirPatchespp; patchp; patchp =
2992 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
2993 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
2995 lock_ObtainMutex(&scp->mx);
2996 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
2997 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2999 lock_ReleaseMutex(&scp->mx);
3000 cm_ReleaseSCache(scp);
3002 dptr = patchp->dptr;
3004 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3005 errors in the client. */
3006 if (infoLevel >= 0x101) {
3007 /* 1969-12-31 23:59:59 +00 */
3008 ft.dwHighDateTime = 0x19DB200;
3009 ft.dwLowDateTime = 0x5BB78980;
3011 /* copy to Creation Time */
3012 *((FILETIME *)dptr) = ft;
3015 /* copy to Last Access Time */
3016 *((FILETIME *)dptr) = ft;
3019 /* copy to Last Write Time */
3020 *((FILETIME *)dptr) = ft;
3023 /* copy to Change Time */
3024 *((FILETIME *)dptr) = ft;
3027 /* merge in hidden attribute */
3028 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3029 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3033 /* 1969-12-31 23:59:58 +00*/
3034 dosTime = 0xEBBFBF7D;
3036 /* and copy out date */
3037 shortTemp = (dosTime>>16) & 0xffff;
3038 *((u_short *)dptr) = shortTemp;
3041 /* copy out creation time */
3042 shortTemp = dosTime & 0xffff;
3043 *((u_short *)dptr) = shortTemp;
3046 /* and copy out date */
3047 shortTemp = (dosTime>>16) & 0xffff;
3048 *((u_short *)dptr) = shortTemp;
3051 /* copy out access time */
3052 shortTemp = dosTime & 0xffff;
3053 *((u_short *)dptr) = shortTemp;
3056 /* and copy out date */
3057 shortTemp = (dosTime>>16) & 0xffff;
3058 *((u_short *)dptr) = shortTemp;
3061 /* copy out mod time */
3062 shortTemp = dosTime & 0xffff;
3063 *((u_short *)dptr) = shortTemp;
3066 /* merge in hidden (dot file) attribute */
3067 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3068 attr = SMB_ATTR_HIDDEN;
3069 *dptr++ = attr & 0xff;
3070 *dptr++ = (attr >> 8) & 0xff;
3076 /* now watch for a symlink */
3077 if (scp->fileType == CM_SCACHETYPE_SYMLINK) {
3078 lock_ReleaseMutex(&scp->mx);
3079 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3081 /* we have a more accurate file to use (the
3082 * target of the symbolic link). Otherwise,
3083 * we'll just use the symlink anyway.
3085 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3087 cm_ReleaseSCache(scp);
3090 lock_ObtainMutex(&scp->mx);
3093 dptr = patchp->dptr;
3095 if (infoLevel >= 0x101) {
3097 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3099 /* copy to Creation Time */
3100 *((FILETIME *)dptr) = ft;
3103 /* copy to Last Access Time */
3104 *((FILETIME *)dptr) = ft;
3107 /* copy to Last Write Time */
3108 *((FILETIME *)dptr) = ft;
3111 /* copy to Change Time */
3112 *((FILETIME *)dptr) = ft;
3115 /* Use length for both file length and alloc length */
3116 *((LARGE_INTEGER *)dptr) = scp->length;
3118 *((LARGE_INTEGER *)dptr) = scp->length;
3121 /* Copy attributes */
3122 lattr = smb_ExtAttributes(scp);
3123 /* merge in hidden (dot file) attribute */
3124 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3125 lattr |= SMB_ATTR_HIDDEN;
3126 *((u_long *)dptr) = lattr;
3131 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3133 /* and copy out date */
3134 shortTemp = (dosTime>>16) & 0xffff;
3135 *((u_short *)dptr) = shortTemp;
3138 /* copy out creation time */
3139 shortTemp = dosTime & 0xffff;
3140 *((u_short *)dptr) = shortTemp;
3143 /* and copy out date */
3144 shortTemp = (dosTime>>16) & 0xffff;
3145 *((u_short *)dptr) = shortTemp;
3148 /* copy out access time */
3149 shortTemp = dosTime & 0xffff;
3150 *((u_short *)dptr) = shortTemp;
3153 /* and copy out date */
3154 shortTemp = (dosTime>>16) & 0xffff;
3155 *((u_short *)dptr) = shortTemp;
3158 /* copy out mod time */
3159 shortTemp = dosTime & 0xffff;
3160 *((u_short *)dptr) = shortTemp;
3163 /* copy out file length and alloc length,
3164 * using the same for both
3166 *((u_long *)dptr) = scp->length.LowPart;
3168 *((u_long *)dptr) = scp->length.LowPart;
3171 /* finally copy out attributes as short */
3172 attr = smb_Attributes(scp);
3173 /* merge in hidden (dot file) attribute */
3174 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3175 attr |= SMB_ATTR_HIDDEN;
3176 *dptr++ = attr & 0xff;
3177 *dptr++ = (attr >> 8) & 0xff;
3180 lock_ReleaseMutex(&scp->mx);
3181 cm_ReleaseSCache(scp);
3184 /* now free the patches */
3185 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
3186 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3190 /* and mark the list as empty */
3191 *dirPatchespp = NULL;
3196 #ifndef USE_OLD_MATCHING
3197 // char table for case insensitive comparison
3198 char mapCaseTable[256];
3200 VOID initUpperCaseTable(VOID)
3203 for (i = 0; i < 256; ++i)
3204 mapCaseTable[i] = toupper(i);
3205 // make '"' match '.'
3206 mapCaseTable[(int)'"'] = toupper('.');
3207 // make '<' match '*'
3208 mapCaseTable[(int)'<'] = toupper('*');
3209 // make '>' match '?'
3210 mapCaseTable[(int)'>'] = toupper('?');
3213 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3215 // Note : this procedure works recursively calling itself.
3217 // PSZ pattern : string containing metacharacters.
3218 // PSZ name : file name to be compared with 'pattern'.
3220 // BOOL : TRUE/FALSE (match/mistmatch)
3222 BOOL szWildCardMatchFileName(PSZ pattern, PSZ name) {
3223 PSZ pename; // points to the last 'name' character
3225 pename = name + strlen(name) - 1;
3230 if (*(++pattern) != '<' || *(++pattern) != '*') {
3238 while ((*pattern == '<') || (*pattern == '*') || (*pattern == '?') || (*pattern == '>'))
3242 for (p = pename; p >= name; --p) {
3243 if ((mapCaseTable[*p] == mapCaseTable[*pattern]) &&
3244 szWildCardMatchFileName(pattern + 1, p + 1))
3249 if (mapCaseTable[*name] != mapCaseTable[*pattern])
3258 /* do a case-folding search of the star name mask with the name in namep.
3259 * Return 1 if we match, otherwise 0.
3261 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3263 /* make sure we only match 8.3 names, if requested */
3264 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3267 return szWildCardMatchFileName(maskp, namep) ? 1:0;
3270 #else /* USE_OLD_MATCHING */
3271 /* do a case-folding search of the star name mask with the name in namep.
3272 * Return 1 if we match, otherwise 0.
3274 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3276 unsigned char tcp1, tcp2; /* Pattern characters */
3277 unsigned char tcn1; /* Name characters */
3278 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3279 char *starNamep, *starMaskp;
3280 static char nullCharp[] = {0};
3281 int casefold = flags & CM_FLAG_CASEFOLD;
3283 /* make sure we only match 8.3 names, if requested */
3284 req8dot3 = (flags & CM_FLAG_8DOT3);
3285 if (req8dot3 && !cm_Is8Dot3(namep))
3290 /* Next pattern character */
3293 /* Next name character */
3297 /* 0 - end of pattern */
3303 else if (tcp1 == '.' || tcp1 == '"') {
3313 * first dot in pattern;
3314 * must match dot or end of name
3319 else if (tcn1 == '.') {
3328 else if (tcp1 == '?') {
3329 if (tcn1 == 0 || tcn1 == '.')
3334 else if (tcp1 == '>') {
3335 if (tcn1 != 0 && tcn1 != '.')
3339 else if (tcp1 == '*' || tcp1 == '<') {
3343 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3344 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3359 * pattern character after '*' is not null or
3360 * period. If it is '?' or '>', we are not
3361 * going to understand it. If it is '*' or
3362 * '<', we are going to skip over it. None of
3363 * these are likely, I hope.
3365 /* skip over '*' and '<' */
3366 while (tcp2 == '*' || tcp2 == '<')
3369 /* skip over characters that don't match tcp2 */
3370 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
3371 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
3372 (!casefold && tcn1 != tcp2)))
3376 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3379 /* Remember where we are */
3389 /* tcp1 is not a wildcard */
3390 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
3391 (!casefold && tcn1 == tcp1)) {
3396 /* if trying to match a star pattern, go back */
3398 maskp = starMaskp - 2;
3399 namep = starNamep + 1;
3408 #endif /* USE_OLD_MATCHING */
3410 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3419 smb_dirListPatch_t *dirListPatchesp;
3420 smb_dirListPatch_t *curPatchp;
3423 long orbytes; /* # of bytes in this output record */
3424 long ohbytes; /* # of bytes, except file name */
3425 long onbytes; /* # of bytes in name, incl. term. null */
3426 osi_hyper_t dirLength;
3427 osi_hyper_t bufferOffset;
3428 osi_hyper_t curOffset;
3430 smb_dirSearch_t *dsp;
3434 cm_pageHeader_t *pageHeaderp;
3435 cm_user_t *userp = NULL;
3438 long nextEntryCookie;
3439 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3440 char *op; /* output data ptr */
3441 char *origOp; /* original value of op */
3442 cm_space_t *spacep; /* for pathname buffer */
3443 long maxReturnData; /* max # of return data */
3444 long maxReturnParms; /* max # of return parms */
3445 long bytesInBuffer; /* # data bytes in the output buffer */
3447 char *maskp; /* mask part of path */
3451 smb_tran2Packet_t *outp; /* response packet */
3454 char shortName[13]; /* 8.3 name if needed */
3466 if (p->opcode == 1) {
3467 /* find first; obtain basic parameters from request */
3468 attribute = p->parmsp[0];
3469 maxCount = p->parmsp[1];
3470 infoLevel = p->parmsp[3];
3471 searchFlags = p->parmsp[2];
3472 dsp = smb_NewDirSearch(1);
3473 dsp->attribute = attribute;
3474 pathp = ((char *) p->parmsp) + 12; /* points to path */
3476 maskp = strrchr(pathp, '\\');
3477 if (maskp == NULL) maskp = pathp;
3478 else maskp++; /* skip over backslash */
3479 strcpy(dsp->mask, maskp); /* and save mask */
3480 /* track if this is likely to match a lot of entries */
3481 starPattern = smb_V3IsStarMask(maskp);
3484 osi_assert(p->opcode == 2);
3485 /* find next; obtain basic parameters from request or open dir file */
3486 dsp = smb_FindDirSearch(p->parmsp[0]);
3487 if (!dsp) return CM_ERROR_BADFD;
3488 attribute = dsp->attribute;
3489 maxCount = p->parmsp[1];
3490 infoLevel = p->parmsp[2];
3491 searchFlags = p->parmsp[5];
3493 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
3495 starPattern = 1; /* assume, since required a Find Next */
3499 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
3500 attribute, infoLevel, maxCount, searchFlags);
3502 osi_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
3503 p->opcode, nextCookie);
3505 if (infoLevel >= 0x101)
3506 searchFlags &= ~4; /* no resume keys */
3508 dirListPatchesp = NULL;
3510 maxReturnData = p->maxReturnData;
3511 if (p->opcode == 1) /* find first */
3512 maxReturnParms = 10; /* bytes */
3514 maxReturnParms = 8; /* bytes */
3516 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
3517 if (maxReturnData > 6000)
3518 maxReturnData = 6000;
3519 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
3521 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
3524 osi_Log1(smb_logp, "T2 receive search dir %s",
3525 osi_LogSaveString(smb_logp, pathp));
3527 /* bail out if request looks bad */
3528 if (p->opcode == 1 && !pathp) {
3529 smb_ReleaseDirSearch(dsp);
3530 smb_FreeTran2Packet(outp);
3531 return CM_ERROR_BADSMB;
3534 osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
3535 nextCookie, dsp->cookie);
3537 userp = smb_GetTran2User(vcp, p);
3539 osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p->uid);
3540 smb_ReleaseDirSearch(dsp);
3541 smb_FreeTran2Packet(outp);
3542 return CM_ERROR_BADSMB;
3545 /* try to get the vnode for the path name next */
3546 lock_ObtainMutex(&dsp->mx);
3553 spacep = cm_GetSpace();
3554 smb_StripLastComponent(spacep->data, NULL, pathp);
3555 lock_ReleaseMutex(&dsp->mx);
3557 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3559 cm_ReleaseUser(userp);
3560 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
3561 smb_FreeTran2Packet(outp);
3562 smb_DeleteDirSearch(dsp);
3563 smb_ReleaseDirSearch(dsp);
3566 code = cm_NameI(cm_rootSCachep, spacep->data,
3567 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3568 userp, tidPathp, &req, &scp);
3569 cm_FreeSpace(spacep);
3571 lock_ObtainMutex(&dsp->mx);
3573 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
3575 /* we need one hold for the entry we just stored into,
3576 * and one for our own processing. When we're done
3577 * with this function, we'll drop the one for our own
3578 * processing. We held it once from the namei call,
3579 * and so we do another hold now.
3582 lock_ObtainMutex(&scp->mx);
3583 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3584 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3585 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3586 dsp->flags |= SMB_DIRSEARCH_BULKST;
3588 lock_ReleaseMutex(&scp->mx);
3591 lock_ReleaseMutex(&dsp->mx);
3593 cm_ReleaseUser(userp);
3594 smb_FreeTran2Packet(outp);
3595 smb_DeleteDirSearch(dsp);
3596 smb_ReleaseDirSearch(dsp);
3600 /* get the directory size */
3601 lock_ObtainMutex(&scp->mx);
3602 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3603 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3605 lock_ReleaseMutex(&scp->mx);
3606 cm_ReleaseSCache(scp);
3607 cm_ReleaseUser(userp);
3608 smb_FreeTran2Packet(outp);
3609 smb_DeleteDirSearch(dsp);
3610 smb_ReleaseDirSearch(dsp);
3615 dirLength = scp->length;
3617 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3618 curOffset.HighPart = 0;
3619 curOffset.LowPart = nextCookie;
3620 origOp = outp->datap;
3628 if (searchFlags & 4)
3629 /* skip over resume key */
3632 /* make sure that curOffset.LowPart doesn't point to the first
3633 * 32 bytes in the 2nd through last dir page, and that it doesn't
3634 * point at the first 13 32-byte chunks in the first dir page,
3635 * since those are dir and page headers, and don't contain useful
3638 temp = curOffset.LowPart & (2048-1);
3639 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3640 /* we're in the first page */
3641 if (temp < 13*32) temp = 13*32;
3644 /* we're in a later dir page */
3645 if (temp < 32) temp = 32;
3648 /* make sure the low order 5 bits are zero */
3651 /* now put temp bits back ito curOffset.LowPart */
3652 curOffset.LowPart &= ~(2048-1);
3653 curOffset.LowPart |= temp;
3655 /* check if we've passed the dir's EOF */
3656 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
3661 /* check if we've returned all the names that will fit in the
3662 * response packet; we check return count as well as the number
3663 * of bytes requested. We check the # of bytes after we find
3664 * the dir entry, since we'll need to check its size.
3666 if (returnedNames >= maxCount) {
3670 /* see if we can use the bufferp we have now; compute in which
3671 * page the current offset would be, and check whether that's
3672 * the offset of the buffer we have. If not, get the buffer.
3674 thyper.HighPart = curOffset.HighPart;
3675 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3676 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3679 buf_Release(bufferp);
3682 lock_ReleaseMutex(&scp->mx);
3683 lock_ObtainRead(&scp->bufCreateLock);
3684 code = buf_Get(scp, &thyper, &bufferp);
3685 lock_ReleaseRead(&scp->bufCreateLock);
3687 /* now, if we're doing a star match, do bulk fetching
3688 * of all of the status info for files in the dir.
3691 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
3694 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
3695 && LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
3696 /* Don't bulk stat if risking timeout */
3697 int now = GetCurrentTime();
3698 if (now - req.startTime > 5000) {
3699 scp->bulkStatProgress = thyper;
3700 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3701 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3703 cm_TryBulkStat(scp, &thyper, userp, &req);
3707 lock_ObtainMutex(&scp->mx);
3709 bufferOffset = thyper;
3711 /* now get the data in the cache */
3713 code = cm_SyncOp(scp, bufferp, userp, &req,
3715 CM_SCACHESYNC_NEEDCALLBACK
3716 | CM_SCACHESYNC_READ);
3719 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3721 /* otherwise, load the buffer and try again */
3722 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3727 buf_Release(bufferp);
3731 } /* if (wrong buffer) ... */
3733 /* now we have the buffer containing the entry we're interested
3734 * in; copy it out if it represents a non-deleted entry.
3736 entryInDir = curOffset.LowPart & (2048-1);
3737 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3739 /* page header will help tell us which entries are free. Page
3740 * header can change more often than once per buffer, since
3741 * AFS 3 dir page size may be less than (but not more than)
3742 * a buffer package buffer.
3744 /* only look intra-buffer */
3745 temp = curOffset.LowPart & (buf_bufferSize - 1);
3746 temp &= ~(2048 - 1); /* turn off intra-page bits */
3747 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3749 /* now determine which entry we're looking at in the page.
3750 * If it is free (there's a free bitmap at the start of the
3751 * dir), we should skip these 32 bytes.
3753 slotInPage = (entryInDir & 0x7e0) >> 5;
3754 if (!(pageHeaderp->freeBitmap[slotInPage>>3]
3755 & (1 << (slotInPage & 0x7)))) {
3756 /* this entry is free */
3757 numDirChunks = 1; /* only skip this guy */
3761 tp = bufferp->datap + entryInBuffer;
3762 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3764 /* while we're here, compute the next entry's location, too,
3765 * since we'll need it when writing out the cookie into the dir
3768 * XXXX Probably should do more sanity checking.
3770 numDirChunks = cm_NameEntries(dep->name, &onbytes);
3772 /* compute offset of cookie representing next entry */
3773 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3775 /* Need 8.3 name? */
3777 if (infoLevel == 0x104
3778 && dep->fid.vnode != 0
3779 && !cm_Is8Dot3(dep->name)) {
3780 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3784 /* When matching, we are using doing a case fold if we have a wildcard mask.
3785 * If we get a non-wildcard match, it's a lookup for a specific file.
3787 if (dep->fid.vnode != 0 &&
3788 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0))
3790 && smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
3792 /* Eliminate entries that don't match requested attributes */
3793 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
3794 smb_IsDotFile(dep->name))
3795 goto nextEntry; /* no hidden files */
3797 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3799 /* We have already done the cm_TryBulkStat above */
3800 fid.cell = scp->fid.cell;
3801 fid.volume = scp->fid.volume;
3802 fid.vnode = ntohl(dep->fid.vnode);
3803 fid.unique = ntohl(dep->fid.unique);
3804 fileType = cm_FindFileType(&fid);
3805 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
3806 "has filetype %d", dep->name,
3808 if (fileType == CM_SCACHETYPE_DIRECTORY)
3812 /* finally check if this name will fit */
3814 /* standard dir entry stuff */
3815 if (infoLevel < 0x101)
3816 ohbytes = 23; /* pre-NT */
3817 else if (infoLevel == 0x103)
3818 ohbytes = 12; /* NT names only */
3820 ohbytes = 64; /* NT */
3822 if (infoLevel == 0x104)
3823 ohbytes += 26; /* Short name & length */
3825 if (searchFlags & 4) {
3826 ohbytes += 4; /* if resume key required */
3830 && infoLevel != 0x101
3831 && infoLevel != 0x103)
3832 ohbytes += 4; /* EASIZE */
3834 /* add header to name & term. null */
3835 orbytes = onbytes + ohbytes + 1;
3837 /* now, we round up the record to a 4 byte alignment,
3838 * and we make sure that we have enough room here for
3839 * even the aligned version (so we don't have to worry
3840 * about an * overflow when we pad things out below).
3841 * That's the reason for the alignment arithmetic below.
3843 if (infoLevel >= 0x101)
3844 align = (4 - (orbytes & 3)) & 3;
3847 if (orbytes + bytesInBuffer + align > maxReturnData)
3850 /* this is one of the entries to use: it is not deleted
3851 * and it matches the star pattern we're looking for.
3852 * Put out the name, preceded by its length.
3854 /* First zero everything else */
3855 memset(origOp, 0, ohbytes);
3857 if (infoLevel <= 0x101)
3858 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
3859 else if (infoLevel == 0x103)
3860 *((u_long *)(op + 8)) = onbytes;
3862 *((u_long *)(op + 60)) = onbytes;
3863 strcpy(origOp+ohbytes, dep->name);
3865 /* Short name if requested and needed */
3866 if (infoLevel == 0x104) {
3867 if (NeedShortName) {
3868 strcpy(op + 70, shortName);
3869 *(op + 68) = shortNameEnd - shortName;
3873 /* now, adjust the # of entries copied */
3876 /* NextEntryOffset and FileIndex */
3877 if (infoLevel >= 101) {
3878 int entryOffset = orbytes + align;
3879 *((u_long *)op) = entryOffset;
3880 *((u_long *)(op+4)) = nextEntryCookie;
3883 /* now we emit the attribute. This is tricky, since
3884 * we need to really stat the file to find out what
3885 * type of entry we've got. Right now, we're copying
3886 * out data from * a buffer, while holding the scp
3887 * locked, so it isn't really convenient to stat
3888 * something now. We'll put in a place holder
3889 * now, and make a second pass before returning this
3890 * to get the real attributes. So, we just skip the
3891 * data for now, and adjust it later. We allocate a
3892 * patch record to make it easy to find this point
3893 * later. The replay will happen at a time when it is
3894 * safe to unlock the directory.
3896 if (infoLevel != 0x103) {
3897 curPatchp = malloc(sizeof(*curPatchp));
3898 osi_QAdd((osi_queue_t **) &dirListPatchesp,
3900 curPatchp->dptr = op;
3901 if (infoLevel >= 0x101)
3902 curPatchp->dptr += 8;
3904 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
3905 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3908 curPatchp->flags = 0;
3910 curPatchp->fid.cell = scp->fid.cell;
3911 curPatchp->fid.volume = scp->fid.volume;
3912 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3913 curPatchp->fid.unique = ntohl(dep->fid.unique);
3916 curPatchp->dep = dep;
3919 if (searchFlags & 4)
3920 /* put out resume key */
3921 *((u_long *)origOp) = nextEntryCookie;
3923 /* Adjust byte ptr and count */
3924 origOp += orbytes; /* skip entire record */
3925 bytesInBuffer += orbytes;
3927 /* and pad the record out */
3928 while (--align >= 0) {
3933 } /* if we're including this name */
3934 else if (!NeedShortName &&
3937 dep->fid.vnode != 0 &&
3938 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
3939 /* We were looking for exact matches, but here's an inexact one*/
3944 /* and adjust curOffset to be where the new cookie is */
3945 thyper.HighPart = 0;
3946 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3947 curOffset = LargeIntegerAdd(thyper, curOffset);
3948 } /* while copying data for dir listing */
3950 /* If we didn't get a star pattern, we did an exact match during the first pass.
3951 * If there were no exact matches found, we fail over to inexact matches by
3952 * marking the query as a star pattern (matches all case permutations), and
3953 * re-running the query.
3955 if (returnedNames == 0 && !starPattern && foundInexact) {
3956 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
3961 /* release the mutex */
3962 lock_ReleaseMutex(&scp->mx);
3963 if (bufferp) buf_Release(bufferp);
3965 /* apply and free last set of patches; if not doing a star match, this
3966 * will be empty, but better safe (and freeing everything) than sorry.
3968 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
3971 /* now put out the final parameters */
3972 if (returnedNames == 0) eos = 1;
3973 if (p->opcode == 1) {
3975 outp->parmsp[0] = (unsigned short) dsp->cookie;
3976 outp->parmsp[1] = returnedNames;
3977 outp->parmsp[2] = eos;
3978 outp->parmsp[3] = 0; /* nothing wrong with EAS */
3979 outp->parmsp[4] = 0;
3980 /* don't need last name to continue
3981 * search, cookie is enough. Normally,
3982 * this is the offset of the file name
3983 * of the last entry returned.
3985 outp->totalParms = 10; /* in bytes */
3989 outp->parmsp[0] = returnedNames;
3990 outp->parmsp[1] = eos;
3991 outp->parmsp[2] = 0; /* EAS error */
3992 outp->parmsp[3] = 0; /* last name, as above */
3993 outp->totalParms = 8; /* in bytes */
3996 /* return # of bytes in the buffer */
3997 outp->totalData = bytesInBuffer;
3999 osi_Log2(smb_logp, "T2 search dir done, %d names, code %d",
4000 returnedNames, code);
4002 /* Return error code if unsuccessful on first request */
4003 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4004 code = CM_ERROR_NOSUCHFILE;
4006 /* if we're supposed to close the search after this request, or if
4007 * we're supposed to close the search if we're done, and we're done,
4008 * or if something went wrong, close the search.
4010 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4011 if ((searchFlags & 1) || (returnedNames == 0) ||
4012 ((searchFlags & 2) && eos) || code != 0)
4013 smb_DeleteDirSearch(dsp);
4015 smb_SendTran2Error(vcp, p, opx, code);
4017 smb_SendTran2Packet(vcp, outp, opx);
4019 smb_FreeTran2Packet(outp);
4020 smb_ReleaseDirSearch(dsp);
4021 cm_ReleaseSCache(scp);
4022 cm_ReleaseUser(userp);
4026 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4029 smb_dirSearch_t *dsp;
4031 dirHandle = smb_GetSMBParm(inp, 0);
4033 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4035 dsp = smb_FindDirSearch(dirHandle);
4038 return CM_ERROR_BADFD;
4040 /* otherwise, we have an FD to destroy */
4041 smb_DeleteDirSearch(dsp);
4042 smb_ReleaseDirSearch(dsp);
4044 /* and return results */
4045 smb_SetSMBDataLength(outp, 0);
4050 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4052 smb_SetSMBDataLength(outp, 0);
4056 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4063 cm_scache_t *dscp; /* dir we're dealing with */
4064 cm_scache_t *scp; /* file we're creating */
4066 int initialModeBits;
4076 int parmSlot; /* which parm we're dealing with */
4084 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4085 openFun = smb_GetSMBParm(inp, 8); /* open function */
4086 excl = ((openFun & 3) == 0);
4087 trunc = ((openFun & 3) == 2); /* truncate it */
4088 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4089 openAction = 0; /* tracks what we did */
4091 attributes = smb_GetSMBParm(inp, 5);
4092 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4094 /* compute initial mode bits based on read-only flag in attributes */
4095 initialModeBits = 0666;
4096 if (attributes & 1) initialModeBits &= ~0222;
4098 pathp = smb_GetSMBData(inp, NULL);
4100 spacep = inp->spacep;
4101 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4103 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4104 /* special case magic file name for receiving IOCTL requests
4105 * (since IOCTL calls themselves aren't getting through).
4108 osi_Log0(smb_logp, "IOCTL Open");
4111 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4112 smb_SetupIoctlFid(fidp, spacep);
4114 /* set inp->fid so that later read calls in same msg can find fid */
4115 inp->fid = fidp->fid;
4117 /* copy out remainder of the parms */
4119 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4121 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4122 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4123 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4124 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4125 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4126 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4127 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4128 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4130 /* and the final "always present" stuff */
4131 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4132 /* next write out the "unique" ID */
4133 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4134 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4135 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4136 smb_SetSMBDataLength(outp, 0);
4138 /* and clean up fid reference */
4139 smb_ReleaseFID(fidp);
4143 #ifdef DEBUG_VERBOSE
4145 char *hexp, *asciip;
4146 asciip = (lastNamep ? lastNamep : pathp );
4147 hexp = osi_HexifyString(asciip);
4148 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4152 userp = smb_GetUser(vcp, inp);
4155 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4157 cm_ReleaseUser(userp);
4158 return CM_ERROR_NOSUCHPATH;
4160 code = cm_NameI(cm_rootSCachep, pathp,
4161 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4162 userp, tidPathp, &req, &scp);
4164 code = cm_NameI(cm_rootSCachep, spacep->data,
4165 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4166 userp, tidPathp, &req, &dscp);
4169 cm_ReleaseUser(userp);
4173 /* otherwise, scp points to the parent directory. Do a lookup,
4174 * and truncate the file if we find it, otherwise we create the
4177 if (!lastNamep) lastNamep = pathp;
4179 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
4181 if (code && code != CM_ERROR_NOSUCHFILE) {
4182 cm_ReleaseSCache(dscp);
4183 cm_ReleaseUser(userp);
4188 /* if we get here, if code is 0, the file exists and is represented by
4189 * scp. Otherwise, we have to create it. The dir may be represented
4190 * by dscp, or we may have found the file directly. If code is non-zero,
4194 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
4196 if (dscp) cm_ReleaseSCache(dscp);
4197 cm_ReleaseSCache(scp);
4198 cm_ReleaseUser(userp);
4203 /* oops, file shouldn't be there */
4204 if (dscp) cm_ReleaseSCache(dscp);
4205 cm_ReleaseSCache(scp);
4206 cm_ReleaseUser(userp);
4207 return CM_ERROR_EXISTS;
4211 setAttr.mask = CM_ATTRMASK_LENGTH;
4212 setAttr.length.LowPart = 0;
4213 setAttr.length.HighPart = 0;
4214 code = cm_SetAttr(scp, &setAttr, userp, &req);
4215 openAction = 3; /* truncated existing file */
4217 else openAction = 1; /* found existing file */
4219 else if (!(openFun & 0x10)) {
4220 /* don't create if not found */
4221 if (dscp) cm_ReleaseSCache(dscp);
4222 cm_ReleaseUser(userp);
4223 return CM_ERROR_NOSUCHFILE;
4226 osi_assert(dscp != NULL);
4227 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
4228 osi_LogSaveString(smb_logp, lastNamep));
4229 openAction = 2; /* created file */
4230 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4231 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
4232 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4234 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4235 smb_NotifyChange(FILE_ACTION_ADDED,
4236 FILE_NOTIFY_CHANGE_FILE_NAME,
4237 dscp, lastNamep, NULL, TRUE);
4238 if (!excl && code == CM_ERROR_EXISTS) {
4239 /* not an exclusive create, and someone else tried
4240 * creating it already, then we open it anyway. We
4241 * don't bother retrying after this, since if this next
4242 * fails, that means that the file was deleted after we
4243 * started this call.
4245 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4249 setAttr.mask = CM_ATTRMASK_LENGTH;
4250 setAttr.length.LowPart = 0;
4251 setAttr.length.HighPart = 0;
4252 code = cm_SetAttr(scp, &setAttr, userp, &req);
4254 } /* lookup succeeded */
4258 /* we don't need this any longer */
4259 if (dscp) cm_ReleaseSCache(dscp);
4262 /* something went wrong creating or truncating the file */
4263 if (scp) cm_ReleaseSCache(scp);
4264 cm_ReleaseUser(userp);
4268 /* make sure we're about to open a file */
4269 if (scp->fileType != CM_SCACHETYPE_FILE) {
4270 cm_ReleaseSCache(scp);
4271 cm_ReleaseUser(userp);
4272 return CM_ERROR_ISDIR;
4275 /* now all we have to do is open the file itself */
4276 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4279 /* save a pointer to the vnode */
4282 /* compute open mode */
4283 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
4284 if (openMode == 1 || openMode == 2)
4285 fidp->flags |= SMB_FID_OPENWRITE;
4287 smb_ReleaseFID(fidp);
4289 cm_Open(scp, 0, userp);
4291 /* set inp->fid so that later read calls in same msg can find fid */
4292 inp->fid = fidp->fid;
4294 /* copy out remainder of the parms */
4296 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4297 lock_ObtainMutex(&scp->mx);
4299 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
4300 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4301 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
4302 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
4303 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
4304 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
4305 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4306 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4307 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4309 /* and the final "always present" stuff */
4310 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
4311 /* next write out the "unique" ID */
4312 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
4313 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
4314 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4315 lock_ReleaseMutex(&scp->mx);
4316 smb_SetSMBDataLength(outp, 0);
4318 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
4320 cm_ReleaseUser(userp);
4321 /* leave scp held since we put it in fidp->scp */
4325 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4332 unsigned char LockType;
4333 unsigned short NumberOfUnlocks, NumberOfLocks;
4334 unsigned long Timeout;
4336 LARGE_INTEGER LOffset, LLength;
4337 smb_waitingLock_t *waitingLock;
4344 fid = smb_GetSMBParm(inp, 2);
4345 fid = smb_ChainFID(fid, inp);
4347 fidp = smb_FindFID(vcp, fid, 0);
4348 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4349 return CM_ERROR_BADFD;
4351 /* set inp->fid so that later read calls in same msg can find fid */
4354 userp = smb_GetUser(vcp, inp);
4358 lock_ObtainMutex(&scp->mx);
4359 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4360 CM_SCACHESYNC_NEEDCALLBACK
4361 | CM_SCACHESYNC_GETSTATUS
4362 | CM_SCACHESYNC_LOCK);
4363 if (code) goto doneSync;
4365 LockType = smb_GetSMBParm(inp, 3) & 0xff;
4366 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
4367 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
4368 NumberOfLocks = smb_GetSMBParm(inp, 7);
4370 op = smb_GetSMBData(inp, NULL);
4372 for (i=0; i<NumberOfUnlocks; i++) {
4373 if (LockType & 0x10) {
4375 LOffset.HighPart = *((LONG *)(op + 4));
4376 LOffset.LowPart = *((DWORD *)(op + 8));
4377 LLength.HighPart = *((LONG *)(op + 12));
4378 LLength.LowPart = *((DWORD *)(op + 16));
4382 /* Not Large Files */
4383 LOffset.HighPart = 0;
4384 LOffset.LowPart = *((DWORD *)(op + 2));
4385 LLength.HighPart = 0;
4386 LLength.LowPart = *((DWORD *)(op + 6));
4389 if (LargeIntegerNotEqualToZero(LOffset))
4391 /* Do not check length -- length check done in cm_Unlock */
4393 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
4394 if (code) goto done;
4397 for (i=0; i<NumberOfLocks; i++) {
4398 if (LockType & 0x10) {
4400 LOffset.HighPart = *((LONG *)(op + 4));
4401 LOffset.LowPart = *((DWORD *)(op + 8));
4402 LLength.HighPart = *((LONG *)(op + 12));
4403 LLength.LowPart = *((DWORD *)(op + 16));
4407 /* Not Large Files */
4408 LOffset.HighPart = 0;
4409 LOffset.LowPart = *((DWORD *)(op + 2));
4410 LLength.HighPart = 0;
4411 LLength.LowPart = *((DWORD *)(op + 6));
4414 if (LargeIntegerNotEqualToZero(LOffset))
4416 if (LargeIntegerLessThan(LOffset, scp->length))
4419 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
4420 userp, &req, &lockp);
4421 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
4422 /* Put on waiting list */
4423 waitingLock = malloc(sizeof(smb_waitingLock_t));
4424 waitingLock->vcp = vcp;
4425 waitingLock->inp = smb_CopyPacket(inp);
4426 waitingLock->outp = smb_CopyPacket(outp);
4427 waitingLock->timeRemaining = Timeout;
4428 waitingLock->lockp = lockp;
4429 lock_ObtainWrite(&smb_globalLock);
4430 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
4432 osi_Wakeup((long) &smb_allWaitingLocks);
4433 lock_ReleaseWrite(&smb_globalLock);
4434 /* don't send reply immediately */
4435 outp->flags |= SMB_PACKETFLAG_NOSEND;
4441 /* release any locks acquired before the failure */
4444 smb_SetSMBDataLength(outp, 0);
4446 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
4448 lock_ReleaseMutex(&scp->mx);
4449 cm_ReleaseUser(userp);
4450 smb_ReleaseFID(fidp);
4455 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4467 fid = smb_GetSMBParm(inp, 0);
4468 fid = smb_ChainFID(fid, inp);
4470 fidp = smb_FindFID(vcp, fid, 0);
4471 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4472 return CM_ERROR_BADFD;
4475 userp = smb_GetUser(vcp, inp);
4479 /* otherwise, stat the file */
4480 lock_ObtainMutex(&scp->mx);
4481 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4482 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4483 if (code) goto done;
4485 /* decode times. We need a search time, but the response to this
4486 * call provides the date first, not the time, as returned in the
4487 * searchTime variable. So we take the high-order bits first.
4489 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
4490 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
4491 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
4492 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
4493 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
4494 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
4495 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
4497 /* now handle file size and allocation size */
4498 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
4499 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
4500 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
4501 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
4503 /* file attribute */
4504 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
4506 /* and finalize stuff */
4507 smb_SetSMBDataLength(outp, 0);
4511 lock_ReleaseMutex(&scp->mx);
4512 cm_ReleaseUser(userp);
4513 smb_ReleaseFID(fidp);
4517 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4531 fid = smb_GetSMBParm(inp, 0);
4532 fid = smb_ChainFID(fid, inp);
4534 fidp = smb_FindFID(vcp, fid, 0);
4535 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4536 return CM_ERROR_BADFD;
4539 userp = smb_GetUser(vcp, inp);
4543 /* now prepare to call cm_setattr. This message only sets various times,
4544 * and AFS only implements mtime, and we'll set the mtime if that's
4545 * requested. The others we'll ignore.
4547 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
4549 if (searchTime != 0) {
4550 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
4552 if ( unixTime != -1 ) {
4553 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
4554 attrs.clientModTime = unixTime;
4555 code = cm_SetAttr(scp, &attrs, userp, &req);
4557 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
4559 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
4564 cm_ReleaseUser(userp);
4565 smb_ReleaseFID(fidp);
4570 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4573 long count, finalCount;
4580 fd = smb_GetSMBParm(inp, 2);
4581 count = smb_GetSMBParm(inp, 5);
4582 offset.HighPart = 0; /* too bad */
4583 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
4585 osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
4586 fd, offset.LowPart, count);
4588 fd = smb_ChainFID(fd, inp);
4589 fidp = smb_FindFID(vcp, fd, 0);
4591 return CM_ERROR_BADFD;
4593 /* set inp->fid so that later read calls in same msg can find fid */
4596 if (fidp->flags & SMB_FID_IOCTL) {
4597 return smb_IoctlV3Read(fidp, vcp, inp, outp);
4600 userp = smb_GetUser(vcp, inp);
4602 /* 0 and 1 are reserved for request chaining, were setup by our caller,
4603 * and will be further filled in after we return.
4605 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
4606 smb_SetSMBParm(outp, 3, 0); /* resvd */
4607 smb_SetSMBParm(outp, 4, 0); /* resvd */
4608 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
4609 /* fill in #6 when we have all the parameters' space reserved */
4610 smb_SetSMBParm(outp, 7, 0); /* resv'd */
4611 smb_SetSMBParm(outp, 8, 0); /* resv'd */
4612 smb_SetSMBParm(outp, 9, 0); /* resv'd */
4613 smb_SetSMBParm(outp, 10, 0); /* resv'd */
4614 smb_SetSMBParm(outp, 11, 0); /* reserved */
4616 /* get op ptr after putting in the parms, since otherwise we don't
4617 * know where the data really is.
4619 op = smb_GetSMBData(outp, NULL);
4621 /* now fill in offset from start of SMB header to first data byte (to op) */
4622 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
4624 /* set the packet data length the count of the # of bytes */
4625 smb_SetSMBDataLength(outp, count);
4628 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
4630 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
4633 /* fix some things up */
4634 smb_SetSMBParm(outp, 5, finalCount);
4635 smb_SetSMBDataLength(outp, finalCount);
4637 smb_ReleaseFID(fidp);
4639 cm_ReleaseUser(userp);
4644 * Values for createDisp, copied from NTDDK.H
4646 * FILE_SUPERSEDE 0 (???)
4647 * FILE_OPEN 1 (open)
4648 * FILE_CREATE 2 (exclusive)
4649 * FILE_OPEN_IF 3 (non-exclusive)
4650 * FILE_OVERWRITE 4 (open & truncate, but do not create)
4651 * FILE_OVERWRITE_IF 5 (open & truncate, or create)
4654 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4656 char *pathp, *realPathp;
4660 cm_scache_t *dscp; /* parent dir */
4661 cm_scache_t *scp; /* file to create or open */
4665 unsigned short nameLength;
4667 unsigned int requestOpLock;
4668 unsigned int requestBatchOpLock;
4669 unsigned int mustBeDir;
4670 unsigned int treeCreate;
4672 unsigned int desiredAccess;
4673 unsigned int extAttributes;
4674 unsigned int createDisp;
4675 unsigned int createOptions;
4676 int initialModeBits;
4677 unsigned short baseFid;
4678 smb_fid_t *baseFidp;
4680 cm_scache_t *baseDirp;
4681 unsigned short openAction;
4696 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
4697 flags = smb_GetSMBOffsetParm(inp, 3, 1)
4698 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
4699 requestOpLock = flags & 0x02;
4700 requestBatchOpLock = flags & 0x04;
4701 mustBeDir = flags & 0x08;
4704 * Why all of a sudden 32-bit FID?
4705 * We will reject all bits higher than 16.
4707 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
4708 return CM_ERROR_INVAL;
4709 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
4710 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
4711 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
4712 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
4713 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
4714 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
4715 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
4716 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
4717 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
4719 /* mustBeDir is never set; createOptions directory bit seems to be
4722 if (createOptions & 1)
4724 else if (createOptions & 0x40)
4730 * compute initial mode bits based on read-only flag in
4731 * extended attributes
4733 initialModeBits = 0666;
4734 if (extAttributes & 1) initialModeBits &= ~0222;
4736 pathp = smb_GetSMBData(inp, NULL);
4737 /* Sometimes path is not null-terminated, so we make a copy. */
4738 realPathp = malloc(nameLength+1);
4739 memcpy(realPathp, pathp, nameLength);
4740 realPathp[nameLength] = 0;
4742 spacep = inp->spacep;
4743 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
4745 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
4746 osi_Log4(smb_logp,"NTCreateX da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
4747 osi_Log1(smb_logp,"NTCreateX lastNamep=[%s]",osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
4749 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4750 /* special case magic file name for receiving IOCTL requests
4751 * (since IOCTL calls themselves aren't getting through).
4753 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4754 smb_SetupIoctlFid(fidp, spacep);
4755 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
4757 /* set inp->fid so that later read calls in same msg can find fid */
4758 inp->fid = fidp->fid;
4762 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
4763 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4764 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
4766 memset(&ft, 0, sizeof(ft));
4767 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4768 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4769 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4770 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4771 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
4772 sz.HighPart = 0x7fff; sz.LowPart = 0;
4773 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
4774 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
4775 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
4776 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
4777 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
4778 smb_SetSMBDataLength(outp, 0);
4780 /* clean up fid reference */
4781 smb_ReleaseFID(fidp);
4786 #ifdef DEBUG_VERBOSE
4788 char *hexp, *asciip;
4789 asciip = (lastNamep? lastNamep : realPathp);
4790 hexp = osi_HexifyString( asciip );
4791 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
4795 userp = smb_GetUser(vcp, inp);
4797 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
4799 return CM_ERROR_INVAL;
4803 baseDirp = cm_rootSCachep;
4804 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4805 if(code == CM_ERROR_TIDIPC) {
4806 /* Attempt to use a TID allocated for IPC. The client
4807 is probably looking for DCE RPC end points which we
4809 osi_Log0(smb_logp, "NTCreateX received IPC TID");
4811 cm_ReleaseUser(userp);
4812 return CM_ERROR_NOSUCHFILE;
4816 baseFidp = smb_FindFID(vcp, baseFid, 0);
4818 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
4820 cm_ReleaseUser(userp);
4821 return CM_ERROR_INVAL;
4823 baseDirp = baseFidp->scp;
4827 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
4829 /* compute open mode */
4831 if (desiredAccess & DELETE)
4832 fidflags |= SMB_FID_OPENDELETE;
4833 if (desiredAccess & AFS_ACCESS_READ)
4834 fidflags |= SMB_FID_OPENREAD;
4835 if (desiredAccess & AFS_ACCESS_WRITE)
4836 fidflags |= SMB_FID_OPENWRITE;
4840 /* For an exclusive create, we want to do a case sensitive match for the last component. */
4841 if (createDisp == 2 || createDisp == 4 || createDisp == 5) {
4842 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4843 userp, tidPathp, &req, &dscp);
4845 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
4847 if (code == CM_ERROR_NOSUCHFILE) {
4848 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
4849 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
4850 if (code == 0 && realDirFlag == 1) {
4851 cm_ReleaseSCache(scp);
4852 cm_ReleaseSCache(dscp);
4853 cm_ReleaseUser(userp);
4855 return CM_ERROR_EXISTS;
4861 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4862 userp, tidPathp, &req, &scp);
4867 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
4868 /* look up parent directory */
4869 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
4870 * the immediate parent. We have to work our way up realPathp until we hit something that we
4878 code = cm_NameI(baseDirp, spacep->data,
4879 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4880 userp, tidPathp, &req, &dscp);
4883 (tp = strrchr(spacep->data,'\\')) &&
4884 (createDisp == 2) &&
4885 (realDirFlag == 1)) {
4888 treeStartp = realPathp + (tp - spacep->data);
4890 if (*tp && !smb_IsLegalFilename(tp)) {
4892 smb_ReleaseFID(baseFidp);
4893 cm_ReleaseUser(userp);
4895 return CM_ERROR_BADNTFILENAME;
4905 smb_ReleaseFID(baseFidp);
4908 osi_Log0(smb_logp,"NTCreateX parent not found");
4909 cm_ReleaseUser(userp);
4914 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
4915 /* A file exists where we want a directory. */
4916 cm_ReleaseSCache(dscp);
4917 cm_ReleaseUser(userp);
4919 return CM_ERROR_EXISTS;
4923 lastNamep = realPathp;
4927 if (!smb_IsLegalFilename(lastNamep)) {
4928 cm_ReleaseSCache(dscp);
4929 cm_ReleaseUser(userp);
4931 return CM_ERROR_BADNTFILENAME;
4934 if (!foundscp && !treeCreate) {
4935 if (createDisp == 2 || createDisp == 4)
4936 code = cm_Lookup(dscp, lastNamep,
4937 CM_FLAG_FOLLOW, userp, &req, &scp);
4939 code = cm_Lookup(dscp, lastNamep,
4940 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4942 if (code && code != CM_ERROR_NOSUCHFILE) {
4943 cm_ReleaseSCache(dscp);
4944 cm_ReleaseUser(userp);
4952 smb_ReleaseFID(baseFidp);
4955 /* if we get here, if code is 0, the file exists and is represented by
4956 * scp. Otherwise, we have to create it. The dir may be represented
4957 * by dscp, or we may have found the file directly. If code is non-zero,
4960 if (code == 0 && !treeCreate) {
4961 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
4964 if (dscp) cm_ReleaseSCache(dscp);
4965 cm_ReleaseSCache(scp);
4966 cm_ReleaseUser(userp);
4971 if (createDisp == 2) {
4972 /* oops, file shouldn't be there */
4973 if (dscp) cm_ReleaseSCache(dscp);
4974 cm_ReleaseSCache(scp);
4975 cm_ReleaseUser(userp);
4977 return CM_ERROR_EXISTS;
4981 || createDisp == 5) {
4982 setAttr.mask = CM_ATTRMASK_LENGTH;
4983 setAttr.length.LowPart = 0;
4984 setAttr.length.HighPart = 0;
4985 code = cm_SetAttr(scp, &setAttr, userp, &req);
4986 openAction = 3; /* truncated existing file */
4988 else openAction = 1; /* found existing file */
4990 else if (createDisp == 1 || createDisp == 4) {
4991 /* don't create if not found */
4992 if (dscp) cm_ReleaseSCache(dscp);
4993 cm_ReleaseUser(userp);
4995 return CM_ERROR_NOSUCHFILE;
4997 else if (realDirFlag == 0 || realDirFlag == -1) {
4998 osi_assert(dscp != NULL);
4999 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
5000 osi_LogSaveString(smb_logp, lastNamep));
5001 openAction = 2; /* created file */
5002 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5003 setAttr.clientModTime = time(NULL);
5004 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5006 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5007 smb_NotifyChange(FILE_ACTION_ADDED,
5008 FILE_NOTIFY_CHANGE_FILE_NAME,
5009 dscp, lastNamep, NULL, TRUE);
5010 if (code == CM_ERROR_EXISTS && createDisp != 2) {
5011 /* Not an exclusive create, and someone else tried
5012 * creating it already, then we open it anyway. We
5013 * don't bother retrying after this, since if this next
5014 * fails, that means that the file was deleted after we
5015 * started this call.
5017 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5020 if (createDisp == 5) {
5021 setAttr.mask = CM_ATTRMASK_LENGTH;
5022 setAttr.length.LowPart = 0;
5023 setAttr.length.HighPart = 0;
5024 code = cm_SetAttr(scp, &setAttr, userp,
5027 } /* lookup succeeded */
5032 char *cp; /* This component */
5033 int clen = 0; /* length of component */
5037 /* create directory */
5038 if ( !treeCreate ) treeStartp = lastNamep;
5039 osi_assert(dscp != NULL);
5040 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
5041 osi_LogSaveString(smb_logp, treeStartp));
5042 openAction = 2; /* created directory */
5044 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5045 setAttr.clientModTime = time(NULL);
5052 tp = strchr(pp, '\\');
5056 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
5060 strncpy(cp,pp,clen);
5066 if (clen == 0) continue; /* the supplied path can't have consecutive slashes either , but */
5068 /* cp is the next component to be created. */
5069 code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
5070 if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
5071 smb_NotifyChange(FILE_ACTION_ADDED,
5072 FILE_NOTIFY_CHANGE_DIR_NAME,
5073 tscp, cp, NULL, TRUE);
5075 (code == CM_ERROR_EXISTS && createDisp != 2)) {
5076 /* Not an exclusive create, and someone else tried
5077 * creating it already, then we open it anyway. We
5078 * don't bother retrying after this, since if this next
5079 * fails, that means that the file was deleted after we
5080 * started this call.
5082 code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
5087 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
5088 cm_ReleaseSCache(tscp);
5089 tscp = scp; /* Newly created directory will be next parent */
5094 if we get here and code == 0, then scp is the last directory created, and tscp is the
5095 parent of scp. dscp got released if dscp != tscp. both tscp and scp are held.
5101 /* something went wrong creating or truncating the file */
5102 if (scp) cm_ReleaseSCache(scp);
5103 if (dscp) cm_ReleaseSCache(dscp);
5104 cm_ReleaseUser(userp);
5109 /* make sure we have file vs. dir right (only applies for single component case) */
5110 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5111 cm_ReleaseSCache(scp);
5112 if (dscp) cm_ReleaseSCache(dscp);
5113 cm_ReleaseUser(userp);
5115 return CM_ERROR_ISDIR;
5117 /* (only applies to single component case) */
5118 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5119 cm_ReleaseSCache(scp);
5120 if (dscp) cm_ReleaseSCache(dscp);
5121 cm_ReleaseUser(userp);
5123 return CM_ERROR_NOTDIR;
5126 /* open the file itself */
5127 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5129 /* save a pointer to the vnode */
5132 fidp->flags = fidflags;
5134 /* save parent dir and pathname for delete or change notification */
5135 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5136 fidp->flags |= SMB_FID_NTOPEN;
5137 fidp->NTopen_dscp = dscp;
5138 cm_HoldSCache(dscp);
5139 fidp->NTopen_pathp = strdup(lastNamep);
5141 fidp->NTopen_wholepathp = realPathp;
5143 /* we don't need this any longer */
5144 if (dscp) cm_ReleaseSCache(dscp);
5145 cm_Open(scp, 0, userp);
5147 /* set inp->fid so that later read calls in same msg can find fid */
5148 inp->fid = fidp->fid;
5152 lock_ObtainMutex(&scp->mx);
5153 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5154 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5155 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
5156 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5157 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5158 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5159 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5160 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5161 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
5163 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5164 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5165 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
5166 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
5167 smb_SetSMBParmByte(outp, parmSlot,
5168 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
5169 lock_ReleaseMutex(&scp->mx);
5170 smb_SetSMBDataLength(outp, 0);
5172 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
5173 osi_LogSaveString(smb_logp, realPathp));
5175 smb_ReleaseFID(fidp);
5177 cm_ReleaseUser(userp);
5179 /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
5181 /* leave scp held since we put it in fidp->scp */
5186 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
5187 * Instead, ultimately, would like to use a subroutine for common code.
5189 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5191 char *pathp, *realPathp;
5195 cm_scache_t *dscp; /* parent dir */
5196 cm_scache_t *scp; /* file to create or open */
5199 unsigned long nameLength;
5201 unsigned int requestOpLock;
5202 unsigned int requestBatchOpLock;
5203 unsigned int mustBeDir;
5204 unsigned int extendedRespRequired;
5206 unsigned int desiredAccess;
5207 #ifdef DEBUG_VERBOSE
5208 unsigned int allocSize;
5209 unsigned int shareAccess;
5211 unsigned int extAttributes;
5212 unsigned int createDisp;
5213 #ifdef DEBUG_VERBOSE
5216 unsigned int createOptions;
5217 int initialModeBits;
5218 unsigned short baseFid;
5219 smb_fid_t *baseFidp;
5221 cm_scache_t *baseDirp;
5222 unsigned short openAction;
5228 int parmOffset, dataOffset;
5239 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
5240 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
5241 parmp = inp->data + parmOffset;
5242 lparmp = (ULONG *) parmp;
5245 requestOpLock = flags & 0x02;
5246 requestBatchOpLock = flags & 0x04;
5247 mustBeDir = flags & 0x08;
5248 extendedRespRequired = flags & 0x10;
5251 * Why all of a sudden 32-bit FID?
5252 * We will reject all bits higher than 16.
5254 if (lparmp[1] & 0xFFFF0000)
5255 return CM_ERROR_INVAL;
5256 baseFid = (unsigned short)lparmp[1];
5257 desiredAccess = lparmp[2];
5258 #ifdef DEBUG_VERBOSE
5259 allocSize = lparmp[3];
5260 #endif /* DEBUG_VERSOSE */
5261 extAttributes = lparmp[5];
5263 shareAccess = lparmp[6];
5265 createDisp = lparmp[7];
5266 createOptions = lparmp[8];
5267 #ifdef DEBUG_VERBOSE
5270 nameLength = lparmp[11];
5272 #ifdef DEBUG_VERBOSE
5273 osi_Log4(smb_logp,"NTTransCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
5274 osi_Log2(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
5275 osi_Log1(smb_logp,"... flags[%x]",flags);
5278 /* mustBeDir is never set; createOptions directory bit seems to be
5281 if (createOptions & 1)
5283 else if (createOptions & 0x40)
5289 * compute initial mode bits based on read-only flag in
5290 * extended attributes
5292 initialModeBits = 0666;
5293 if (extAttributes & 1) initialModeBits &= ~0222;
5295 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
5296 /* Sometimes path is not null-terminated, so we make a copy. */
5297 realPathp = malloc(nameLength+1);
5298 memcpy(realPathp, pathp, nameLength);
5299 realPathp[nameLength] = 0;
5301 spacep = cm_GetSpace();
5302 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5305 * Nothing here to handle SMB_IOCTL_FILENAME.
5306 * Will add it if necessary.
5309 #ifdef DEBUG_VERBOSE
5311 char *hexp, *asciip;
5312 asciip = (lastNamep? lastNamep : realPathp);
5313 hexp = osi_HexifyString( asciip );
5314 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
5319 userp = smb_GetUser(vcp, inp);
5321 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
5323 return CM_ERROR_INVAL;
5327 baseDirp = cm_rootSCachep;
5328 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5329 if(code == CM_ERROR_TIDIPC) {
5330 /* Attempt to use TID allocated for IPC. The client is
5331 probably trying to locate DCE RPC endpoints, which we
5333 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
5335 cm_ReleaseUser(userp);
5336 return CM_ERROR_NOSUCHPATH;
5340 baseFidp = smb_FindFID(vcp, baseFid, 0);
5342 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
5344 cm_ReleaseUser(userp);
5345 return CM_ERROR_INVAL;
5347 baseDirp = baseFidp->scp;
5351 /* compute open mode */
5353 if (desiredAccess & DELETE)
5354 fidflags |= SMB_FID_OPENDELETE;
5355 if (desiredAccess & AFS_ACCESS_READ)
5356 fidflags |= SMB_FID_OPENREAD;
5357 if (desiredAccess & AFS_ACCESS_WRITE)
5358 fidflags |= SMB_FID_OPENWRITE;
5362 if (createDisp == 2 || createDisp == 4 || createDisp == 5) {
5363 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5364 userp, tidPathp, &req, &dscp);
5366 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5368 if (code == CM_ERROR_NOSUCHFILE) {
5369 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
5370 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
5371 if (code == 0 && realDirFlag == 1) {
5372 cm_ReleaseSCache(scp);
5373 cm_ReleaseSCache(dscp);
5374 cm_ReleaseUser(userp);
5376 return CM_ERROR_EXISTS;
5382 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5383 userp, tidPathp, &req, &scp);
5386 if (code == 0) foundscp = TRUE;
5388 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
5389 /* look up parent directory */
5391 code = cm_NameI(baseDirp, spacep->data,
5392 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5393 userp, tidPathp, &req, &dscp);
5397 cm_FreeSpace(spacep);
5400 smb_ReleaseFID(baseFidp);
5405 cm_ReleaseUser(userp);
5410 if (!lastNamep) lastNamep = realPathp;
5413 if (!smb_IsLegalFilename(lastNamep))
5414 return CM_ERROR_BADNTFILENAME;
5417 if (createDisp == 2 || createDisp == 4)
5418 code = cm_Lookup(dscp, lastNamep,
5419 CM_FLAG_FOLLOW, userp, &req, &scp);
5421 code = cm_Lookup(dscp, lastNamep,
5422 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5424 if (code && code != CM_ERROR_NOSUCHFILE) {
5425 cm_ReleaseSCache(dscp);
5426 cm_ReleaseUser(userp);
5434 smb_ReleaseFID(baseFidp);
5437 cm_FreeSpace(spacep);
5440 /* if we get here, if code is 0, the file exists and is represented by
5441 * scp. Otherwise, we have to create it. The dir may be represented
5442 * by dscp, or we may have found the file directly. If code is non-zero,
5446 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
5449 if (dscp) cm_ReleaseSCache(dscp);
5450 cm_ReleaseSCache(scp);
5451 cm_ReleaseUser(userp);
5456 if (createDisp == 2) {
5457 /* oops, file shouldn't be there */
5458 if (dscp) cm_ReleaseSCache(dscp);
5459 cm_ReleaseSCache(scp);
5460 cm_ReleaseUser(userp);
5462 return CM_ERROR_EXISTS;
5466 || createDisp == 5) {
5467 setAttr.mask = CM_ATTRMASK_LENGTH;
5468 setAttr.length.LowPart = 0;
5469 setAttr.length.HighPart = 0;
5470 code = cm_SetAttr(scp, &setAttr, userp, &req);
5471 openAction = 3; /* truncated existing file */
5473 else openAction = 1; /* found existing file */
5475 else if (createDisp == 1 || createDisp == 4) {
5476 /* don't create if not found */
5477 if (dscp) cm_ReleaseSCache(dscp);
5478 cm_ReleaseUser(userp);
5480 return CM_ERROR_NOSUCHFILE;
5482 else if (realDirFlag == 0 || realDirFlag == -1) {
5483 osi_assert(dscp != NULL);
5484 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
5485 osi_LogSaveString(smb_logp, lastNamep));
5486 openAction = 2; /* created file */
5487 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5488 setAttr.clientModTime = time(NULL);
5489 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5491 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5492 smb_NotifyChange(FILE_ACTION_ADDED,
5493 FILE_NOTIFY_CHANGE_FILE_NAME,
5494 dscp, lastNamep, NULL, TRUE);
5495 if (code == CM_ERROR_EXISTS && createDisp != 2) {
5496 /* Not an exclusive create, and someone else tried
5497 * creating it already, then we open it anyway. We
5498 * don't bother retrying after this, since if this next
5499 * fails, that means that the file was deleted after we
5500 * started this call.
5502 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5505 if (createDisp == 5) {
5506 setAttr.mask = CM_ATTRMASK_LENGTH;
5507 setAttr.length.LowPart = 0;
5508 setAttr.length.HighPart = 0;
5509 code = cm_SetAttr(scp, &setAttr, userp,
5512 } /* lookup succeeded */
5516 /* create directory */
5517 osi_assert(dscp != NULL);
5519 "smb_ReceiveNTTranCreate creating directory %s",
5520 osi_LogSaveString(smb_logp, lastNamep));
5521 openAction = 2; /* created directory */
5522 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5523 setAttr.clientModTime = time(NULL);
5524 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5525 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5526 smb_NotifyChange(FILE_ACTION_ADDED,
5527 FILE_NOTIFY_CHANGE_DIR_NAME,
5528 dscp, lastNamep, NULL, TRUE);
5530 || (code == CM_ERROR_EXISTS && createDisp != 2)) {
5531 /* Not an exclusive create, and someone else tried
5532 * creating it already, then we open it anyway. We
5533 * don't bother retrying after this, since if this next
5534 * fails, that means that the file was deleted after we
5535 * started this call.
5537 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5543 /* something went wrong creating or truncating the file */
5544 if (scp) cm_ReleaseSCache(scp);
5545 cm_ReleaseUser(userp);
5550 /* make sure we have file vs. dir right */
5551 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5552 cm_ReleaseSCache(scp);
5553 cm_ReleaseUser(userp);
5555 return CM_ERROR_ISDIR;
5557 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5558 cm_ReleaseSCache(scp);
5559 cm_ReleaseUser(userp);
5561 return CM_ERROR_NOTDIR;
5564 /* open the file itself */
5565 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5568 /* save a pointer to the vnode */
5571 fidp->flags = fidflags;
5573 /* save parent dir and pathname for deletion or change notification */
5574 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5575 fidp->flags |= SMB_FID_NTOPEN;
5576 fidp->NTopen_dscp = dscp;
5577 cm_HoldSCache(dscp);
5578 fidp->NTopen_pathp = strdup(lastNamep);
5580 fidp->NTopen_wholepathp = realPathp;
5582 /* we don't need this any longer */
5583 if (dscp) cm_ReleaseSCache(dscp);
5585 cm_Open(scp, 0, userp);
5587 /* set inp->fid so that later read calls in same msg can find fid */
5588 inp->fid = fidp->fid;
5590 /* check whether we are required to send an extended response */
5591 if (!extendedRespRequired) {
5593 parmOffset = 8*4 + 39;
5594 parmOffset += 1; /* pad to 4 */
5595 dataOffset = parmOffset + 70;
5599 /* Total Parameter Count */
5600 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
5601 /* Total Data Count */
5602 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5603 /* Parameter Count */
5604 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
5605 /* Parameter Offset */
5606 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5607 /* Parameter Displacement */
5608 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5610 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5612 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5613 /* Data Displacement */
5614 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5615 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5616 smb_SetSMBDataLength(outp, 70);
5618 lock_ObtainMutex(&scp->mx);
5619 outData = smb_GetSMBData(outp, NULL);
5620 outData++; /* round to get to parmOffset */
5621 *outData = 0; outData++; /* oplock */
5622 *outData = 0; outData++; /* reserved */
5623 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
5624 *((ULONG *)outData) = openAction; outData += 4;
5625 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
5626 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5627 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
5628 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
5629 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
5630 *((FILETIME *)outData) = ft; outData += 8; /* change time */
5631 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
5632 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
5633 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
5634 *((USHORT *)outData) = 0; outData += 2; /* filetype */
5635 *((USHORT *)outData) = 0; outData += 2; /* dev state */
5636 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
5637 outData += 2; /* is a dir? */
5638 lock_ReleaseMutex(&scp->mx);
5641 parmOffset = 8*4 + 39;
5642 parmOffset += 1; /* pad to 4 */
5643 dataOffset = parmOffset + 104;
5647 /* Total Parameter Count */
5648 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
5649 /* Total Data Count */
5650 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5651 /* Parameter Count */
5652 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
5653 /* Parameter Offset */
5654 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5655 /* Parameter Displacement */
5656 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5658 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5660 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5661 /* Data Displacement */
5662 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5663 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5664 smb_SetSMBDataLength(outp, 105);
5666 lock_ObtainMutex(&scp->mx);
5667 outData = smb_GetSMBData(outp, NULL);
5668 outData++; /* round to get to parmOffset */
5669 *outData = 0; outData++; /* oplock */
5670 *outData = 1; outData++; /* response type */
5671 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
5672 *((ULONG *)outData) = openAction; outData += 4;
5673 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
5674 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5675 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
5676 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
5677 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
5678 *((FILETIME *)outData) = ft; outData += 8; /* change time */
5679 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
5680 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
5681 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
5682 *((USHORT *)outData) = 0; outData += 2; /* filetype */
5683 *((USHORT *)outData) = 0; outData += 2; /* dev state */
5684 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
5685 outData += 1; /* is a dir? */
5686 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
5687 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
5688 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
5689 lock_ReleaseMutex(&scp->mx);
5692 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
5694 smb_ReleaseFID(fidp);
5696 cm_ReleaseUser(userp);
5698 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
5699 /* leave scp held since we put it in fidp->scp */
5703 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
5706 smb_packet_t *savedPacketp;
5707 ULONG filter; USHORT fid, watchtree;
5711 filter = smb_GetSMBParm(inp, 19)
5712 | (smb_GetSMBParm(inp, 20) << 16);
5713 fid = smb_GetSMBParm(inp, 21);
5714 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
5716 fidp = smb_FindFID(vcp, fid, 0);
5718 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
5719 return CM_ERROR_BADFD;
5722 savedPacketp = smb_CopyPacket(inp);
5724 savedPacketp->vcp = vcp;
5725 lock_ObtainMutex(&smb_Dir_Watch_Lock);
5726 savedPacketp->nextp = smb_Directory_Watches;
5727 smb_Directory_Watches = savedPacketp;
5728 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
5730 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
5731 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
5734 lock_ObtainMutex(&scp->mx);
5736 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
5738 scp->flags |= CM_SCACHEFLAG_WATCHED;
5739 lock_ReleaseMutex(&scp->mx);
5740 smb_ReleaseFID(fidp);
5742 outp->flags |= SMB_PACKETFLAG_NOSEND;
5746 unsigned char nullSecurityDesc[36] = {
5747 0x01, /* security descriptor revision */
5748 0x00, /* reserved, should be zero */
5749 0x00, 0x80, /* security descriptor control;
5750 * 0x8000 : self-relative format */
5751 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
5752 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
5753 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
5754 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
5755 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5756 /* "null SID" owner SID */
5757 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5758 /* "null SID" group SID */
5761 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5763 int parmOffset, parmCount, dataOffset, dataCount;
5771 ULONG securityInformation;
5773 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
5774 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
5775 parmp = inp->data + parmOffset;
5776 sparmp = (USHORT *) parmp;
5777 lparmp = (ULONG *) parmp;
5780 securityInformation = lparmp[1];
5782 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
5783 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
5791 parmOffset = 8*4 + 39;
5792 parmOffset += 1; /* pad to 4 */
5794 dataOffset = parmOffset + parmCount;
5798 /* Total Parameter Count */
5799 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
5800 /* Total Data Count */
5801 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
5802 /* Parameter Count */
5803 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
5804 /* Parameter Offset */
5805 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5806 /* Parameter Displacement */
5807 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5809 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
5811 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5812 /* Data Displacement */
5813 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5814 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5815 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
5817 outData = smb_GetSMBData(outp, NULL);
5818 outData++; /* round to get to parmOffset */
5819 *((ULONG *)outData) = 36; outData += 4; /* length */
5821 if (maxData >= 36) {
5822 memcpy(outData, nullSecurityDesc, 36);
5826 return CM_ERROR_BUFFERTOOSMALL;
5829 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5831 unsigned short function;
5833 function = smb_GetSMBParm(inp, 18);
5835 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
5837 /* We can handle long names */
5838 if (vcp->flags & SMB_VCFLAG_USENT)
5839 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
5843 case 6: return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
5845 case 4: return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
5847 case 1: return smb_ReceiveNTTranCreate(vcp, inp, outp);
5849 default: return CM_ERROR_INVAL;
5854 * smb_NotifyChange -- find relevant change notification messages and
5857 * If we don't know the file name (i.e. a callback break), filename is
5858 * NULL, and we return a zero-length list.
5860 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
5861 cm_scache_t *dscp, char *filename, char *otherFilename,
5862 BOOL isDirectParent)
5864 smb_packet_t *watch, *lastWatch, *nextWatch;
5865 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
5866 char *outData, *oldOutData;
5870 BOOL twoEntries = FALSE;
5871 ULONG otherNameLen, oldParmCount = 0;
5876 /* Get ready for rename within directory */
5877 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
5879 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
5882 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
5883 osi_LogSaveString(smb_logp,filename),dscp);
5885 lock_ObtainMutex(&smb_Dir_Watch_Lock);
5886 watch = smb_Directory_Watches;
5888 filter = smb_GetSMBParm(watch, 19)
5889 | (smb_GetSMBParm(watch, 20) << 16);
5890 fid = smb_GetSMBParm(watch, 21);
5891 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
5892 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
5893 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
5897 * Strange hack - bug in NT Client and NT Server that we
5900 if (filter == 3 && wtree)
5903 fidp = smb_FindFID(vcp, fid, 0);
5905 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
5907 watch = watch->nextp;
5910 if (fidp->scp != dscp
5911 || (filter & notifyFilter) == 0
5912 || (!isDirectParent && !wtree)) {
5913 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
5914 smb_ReleaseFID(fidp);
5916 watch = watch->nextp;
5919 smb_ReleaseFID(fidp);
5922 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
5923 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
5925 nextWatch = watch->nextp;
5926 if (watch == smb_Directory_Watches)
5927 smb_Directory_Watches = nextWatch;
5929 lastWatch->nextp = nextWatch;
5931 /* Turn off WATCHED flag in dscp */
5932 lock_ObtainMutex(&dscp->mx);
5934 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
5936 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
5937 lock_ReleaseMutex(&dscp->mx);
5939 /* Convert to response packet */
5940 ((smb_t *) watch)->reb = 0x80;
5941 ((smb_t *) watch)->wct = 0;
5944 if (filename == NULL)
5947 nameLen = strlen(filename);
5948 parmCount = 3*4 + nameLen*2;
5949 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
5951 otherNameLen = strlen(otherFilename);
5952 oldParmCount = parmCount;
5953 parmCount += 3*4 + otherNameLen*2;
5954 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
5956 if (maxLen < parmCount)
5957 parmCount = 0; /* not enough room */
5959 parmOffset = 8*4 + 39;
5960 parmOffset += 1; /* pad to 4 */
5961 dataOffset = parmOffset + parmCount;
5965 /* Total Parameter Count */
5966 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
5967 /* Total Data Count */
5968 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
5969 /* Parameter Count */
5970 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
5971 /* Parameter Offset */
5972 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
5973 /* Parameter Displacement */
5974 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
5976 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
5978 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
5979 /* Data Displacement */
5980 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
5981 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
5982 smb_SetSMBDataLength(watch, parmCount + 1);
5984 if (parmCount != 0) {
5985 outData = smb_GetSMBData(watch, NULL);
5986 outData++; /* round to get to parmOffset */
5987 oldOutData = outData;
5988 *((DWORD *)outData) = oldParmCount; outData += 4;
5989 /* Next Entry Offset */
5990 *((DWORD *)outData) = action; outData += 4;
5992 *((DWORD *)outData) = nameLen*2; outData += 4;
5993 /* File Name Length */
5994 mbstowcs((WCHAR *)outData, filename, nameLen);
5997 outData = oldOutData + oldParmCount;
5998 *((DWORD *)outData) = 0; outData += 4;
5999 /* Next Entry Offset */
6000 *((DWORD *)outData) = otherAction; outData += 4;
6002 *((DWORD *)outData) = otherNameLen*2;
6003 outData += 4; /* File Name Length */
6004 mbstowcs((WCHAR *)outData, otherFilename,
6005 otherNameLen); /* File Name */
6010 * If filename is null, we don't know the cause of the
6011 * change notification. We return zero data (see above),
6012 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
6013 * (= 0x010C). We set the error code here by hand, without
6014 * modifying wct and bcc.
6016 if (filename == NULL) {
6017 ((smb_t *) watch)->rcls = 0x0C;
6018 ((smb_t *) watch)->reh = 0x01;
6019 ((smb_t *) watch)->errLow = 0;
6020 ((smb_t *) watch)->errHigh = 0;
6021 /* Set NT Status codes flag */
6022 ((smb_t *) watch)->flg2 |= 0x4000;
6025 smb_SendPacket(vcp, watch);
6027 smb_FreePacket(watch);
6030 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6033 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6035 unsigned char *replyWctp;
6036 smb_packet_t *watch, *lastWatch;
6037 USHORT fid, watchtree;
6041 osi_Log0(smb_logp, "SMB3 receive NT cancel");
6043 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6044 watch = smb_Directory_Watches;
6046 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
6047 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
6048 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
6049 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
6050 if (watch == smb_Directory_Watches)
6051 smb_Directory_Watches = watch->nextp;
6053 lastWatch->nextp = watch->nextp;
6054 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6056 /* Turn off WATCHED flag in scp */
6057 fid = smb_GetSMBParm(watch, 21);
6058 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
6060 if (vcp != watch->vcp)
6061 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
6064 fidp = smb_FindFID(vcp, fid, 0);
6066 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
6068 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
6071 lock_ObtainMutex(&scp->mx);
6073 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6075 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
6076 lock_ReleaseMutex(&scp->mx);
6077 smb_ReleaseFID(fidp);
6079 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
6082 /* assume STATUS32; return 0xC0000120 (CANCELED) */
6083 replyWctp = watch->wctp;
6087 ((smb_t *)watch)->rcls = 0x20;
6088 ((smb_t *)watch)->reh = 0x1;
6089 ((smb_t *)watch)->errLow = 0;
6090 ((smb_t *)watch)->errHigh = 0xC0;
6091 ((smb_t *)watch)->flg2 |= 0x4000;
6092 smb_SendPacket(vcp, watch);
6094 smb_ReleaseVC(watch->vcp);
6095 smb_FreePacket(watch);
6099 watch = watch->nextp;
6101 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6108 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
6111 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
6114 smb_username_t *unp;
6116 unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
6118 lock_ObtainMutex(&unp->mx);
6119 unp->userp = cm_NewUser();
6120 lock_ReleaseMutex(&unp->mx);
6121 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6122 osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
6124 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6125 osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);