2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
15 #define SECURITY_WIN32
30 extern osi_hyper_t hzero;
32 smb_packet_t *smb_Directory_Watches = NULL;
33 osi_mutex_t smb_Dir_Watch_Lock;
35 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
37 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
39 /* protected by the smb_globalLock */
40 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
42 /* retrieve a held reference to a user structure corresponding to an incoming
44 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
49 uidp = smb_FindUID(vcp, inp->uid, 0);
50 if (!uidp) return NULL;
52 lock_ObtainMutex(&uidp->mx);
54 up = uidp->unp->userp;
57 lock_ReleaseMutex(&uidp->mx);
65 * Return extended attributes.
66 * Right now, we aren't using any of the "new" bits, so this looks exactly
67 * like smb_Attributes() (see smb.c).
69 unsigned long smb_ExtAttributes(cm_scache_t *scp)
73 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
74 scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
76 attrs = SMB_ATTR_DIRECTORY;
77 #ifdef SPECIAL_FOLDERS
78 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
79 #endif /* SPECIAL_FOLDERS */
83 * We used to mark a file RO if it was in an RO volume, but that
84 * turns out to be impolitic in NT. See defect 10007.
87 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
89 if ((scp->unixModeBits & 0222) == 0)
90 attrs |= SMB_ATTR_READONLY; /* Read-only */
93 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
98 int smb_V3IsStarMask(char *maskp)
102 while (tc = *maskp++)
103 if (tc == '?' || tc == '*')
108 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
111 /* skip over null-terminated string */
112 *chainpp = inp + strlen(inp) + 1;
117 /*DEBUG do not checkin*/
118 void OutputDebugF(char * format, ...) {
123 va_start( args, format );
124 len = _vscprintf( format, args ) // _vscprintf doesn't count
125 + 3; // terminating '\0' + '\n'
126 buffer = malloc( len * sizeof(char) );
127 vsprintf( buffer, format, args );
128 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buffer));
129 strcat(buffer, "\n");
130 OutputDebugString(buffer);
134 void OutputDebugHexDump(unsigned char * buffer, int len) {
137 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
139 OutputDebugF("Hexdump length [%d]",len);
141 for (i=0;i<len;i++) {
144 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
146 OutputDebugString(buf);
148 sprintf(buf,"%5x",i);
149 memset(buf+5,' ',80);
154 j = j*3 + 7 + ((j>7)?1:0);
157 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
160 j = j + 56 + ((j>7)?1:0);
162 buf[j] = (k>32 && k<127)?k:'.';
165 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
167 OutputDebugString(buf);
172 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
173 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
174 SECURITY_STATUS status, istatus;
175 CredHandle creds = {0,0};
177 SecBufferDesc secOut;
185 OutputDebugF("Negotiating Extended Security");
187 status = AcquireCredentialsHandle( NULL,
188 SMB_EXT_SEC_PACKAGE_NAME,
197 if (status != SEC_E_OK) {
198 /* Really bad. We return an empty security blob */
199 OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
204 secOut.pBuffers = &secTok;
205 secOut.ulVersion = SECBUFFER_VERSION;
207 secTok.BufferType = SECBUFFER_TOKEN;
209 secTok.pvBuffer = NULL;
211 ctx.dwLower = ctx.dwUpper = 0;
213 status = AcceptSecurityContext( &creds,
216 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
217 SECURITY_NETWORK_DREP,
224 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
225 OutputDebugF("Completing token...");
226 istatus = CompleteAuthToken(&ctx, &secOut);
227 if ( istatus != SEC_E_OK )
228 OutputDebugF("Token completion failed: %x", istatus);
231 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
232 if (secTok.pvBuffer) {
233 *secBlobLength = secTok.cbBuffer;
234 *secBlob = malloc( secTok.cbBuffer );
235 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
238 if ( status != SEC_E_OK )
239 OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
242 /* Discard partial security context */
243 DeleteSecurityContext(&ctx);
245 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
247 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
248 FreeCredentialsHandle(&creds);
254 struct smb_ext_context {
261 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
262 SECURITY_STATUS status, istatus;
266 SecBufferDesc secBufIn;
268 SecBufferDesc secBufOut;
271 struct smb_ext_context * secCtx = NULL;
272 struct smb_ext_context * newSecCtx = NULL;
273 void * assembledBlob = NULL;
274 int assembledBlobLength = 0;
277 OutputDebugF("In smb_AuthenticateUserExt");
280 *secBlobOutLength = 0;
282 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
283 secCtx = vcp->secCtx;
284 lock_ObtainMutex(&vcp->mx);
285 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
287 lock_ReleaseMutex(&vcp->mx);
291 OutputDebugF("Received incoming token:");
292 OutputDebugHexDump(secBlobIn,secBlobInLength);
296 OutputDebugF("Continuing with existing context.");
297 creds = secCtx->creds;
300 if (secCtx->partialToken) {
301 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
302 assembledBlob = malloc(assembledBlobLength);
303 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
304 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
307 status = AcquireCredentialsHandle( NULL,
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( &creds,
349 ((secCtx)?&ctx:NULL),
351 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
352 SECURITY_NETWORK_DREP,
359 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
360 OutputDebugF("Completing token...");
361 istatus = CompleteAuthToken(&ctx, &secBufOut);
362 if ( istatus != SEC_E_OK )
363 OutputDebugF("Token completion failed: %lX", istatus);
366 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
367 OutputDebugF("Continue needed");
369 newSecCtx = malloc(sizeof(*newSecCtx));
371 newSecCtx->creds = creds;
372 newSecCtx->ctx = ctx;
373 newSecCtx->partialToken = NULL;
374 newSecCtx->partialTokenLen = 0;
376 lock_ObtainMutex( &vcp->mx );
377 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
378 vcp->secCtx = newSecCtx;
379 lock_ReleaseMutex( &vcp->mx );
381 code = CM_ERROR_GSSCONTINUE;
384 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
385 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
386 secTokOut.pvBuffer) {
387 OutputDebugF("Need to send token back to client");
389 *secBlobOutLength = secTokOut.cbBuffer;
390 *secBlobOut = malloc(secTokOut.cbBuffer);
391 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
393 OutputDebugF("Outgoing token:");
394 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
395 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
396 OutputDebugF("Incomplete message");
398 newSecCtx = malloc(sizeof(*newSecCtx));
400 newSecCtx->creds = creds;
401 newSecCtx->ctx = ctx;
402 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
403 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
404 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
406 lock_ObtainMutex( &vcp->mx );
407 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
408 vcp->secCtx = newSecCtx;
409 lock_ReleaseMutex( &vcp->mx );
411 code = CM_ERROR_GSSCONTINUE;
414 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
416 SecPkgContext_Names names;
418 OutputDebugF("Authentication completed");
419 OutputDebugF("Returned flags : [%lX]", flags);
421 if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
422 OutputDebugF("Received name [%s]", names.sUserName);
423 strcpy(usern, names.sUserName);
424 strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
425 FreeContextBuffer(names.sUserName);
427 /* Force the user to retry if the context is invalid */
428 OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
429 code = CM_ERROR_BADPASSWORD;
433 case SEC_E_INVALID_TOKEN:
434 OutputDebugF("Returning bad password :: INVALID_TOKEN");
436 case SEC_E_INVALID_HANDLE:
437 OutputDebugF("Returning bad password :: INVALID_HANDLE");
439 case SEC_E_LOGON_DENIED:
440 OutputDebugF("Returning bad password :: LOGON_DENIED");
442 case SEC_E_UNKNOWN_CREDENTIALS:
443 OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
445 case SEC_E_NO_CREDENTIALS:
446 OutputDebugF("Returning bad password :: NO_CREDENTIALS");
448 case SEC_E_CONTEXT_EXPIRED:
449 OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
451 case SEC_E_INCOMPLETE_CREDENTIALS:
452 OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
454 case SEC_E_WRONG_PRINCIPAL:
455 OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
457 case SEC_E_TIME_SKEW:
458 OutputDebugF("Returning bad password :: TIME_SKEW");
461 OutputDebugF("Returning bad password :: Status == %lX", status);
463 code = CM_ERROR_BADPASSWORD;
467 if (secCtx->partialToken) free(secCtx->partialToken);
475 if (secTokOut.pvBuffer)
476 FreeContextBuffer(secTokOut.pvBuffer);
478 if (code != CM_ERROR_GSSCONTINUE) {
479 DeleteSecurityContext(&ctx);
480 FreeCredentialsHandle(&creds);
488 #define P_RESP_LEN 128
490 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
491 So put stuff in a struct. */
492 struct Lm20AuthBlob {
493 MSV1_0_LM20_LOGON lmlogon;
494 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
495 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
496 WCHAR accountNameW[P_LEN];
497 WCHAR primaryDomainW[P_LEN];
498 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
499 TOKEN_GROUPS tgroups;
500 TOKEN_SOURCE tsource;
503 long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
506 struct Lm20AuthBlob lmAuth;
507 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
508 QUOTA_LIMITS quotaLimits;
510 ULONG lmprofilepSize;
514 OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
515 OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
517 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
518 OutputDebugF("ciPwdLength or csPwdLength is too long");
519 return CM_ERROR_BADPASSWORD;
522 memset(&lmAuth,0,sizeof(lmAuth));
524 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
526 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
527 mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
528 lmAuth.lmlogon.LogonDomainName.Length = wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR);
529 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
531 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
532 mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
533 lmAuth.lmlogon.UserName.Length = wcslen(lmAuth.accountNameW) * sizeof(WCHAR);
534 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
536 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
537 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
538 size = MAX_COMPUTERNAME_LENGTH + 1;
539 GetComputerNameW(lmAuth.workstationW, &size);
540 lmAuth.lmlogon.Workstation.Length = wcslen(lmAuth.workstationW) * sizeof(WCHAR);
542 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
544 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
545 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
546 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
547 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
549 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
550 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
551 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
552 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
554 lmAuth.lmlogon.ParameterControl = 0;
556 lmAuth.tgroups.GroupCount = 0;
557 lmAuth.tgroups.Groups[0].Sid = NULL;
558 lmAuth.tgroups.Groups[0].Attributes = 0;
560 lmAuth.tsource.SourceIdentifier.HighPart = 0;
561 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD) vcp;
562 strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
564 nts = LsaLogonUser( smb_lsaHandle,
579 OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
580 OutputDebugF("Extended status is 0x%lX", ntsEx);
582 if (nts == ERROR_SUCCESS) {
584 LsaFreeReturnBuffer(lmprofilep);
585 CloseHandle(lmToken);
589 if (nts == 0xC000015BL)
590 return CM_ERROR_BADLOGONTYPE;
591 else /* our catchall is a bad password though we could be more specific */
592 return CM_ERROR_BADPASSWORD;
596 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
597 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName)
602 /* check if we have sane input */
603 if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
606 /* we could get : [accountName][domainName]
612 atsign = strchr(accountName, '@');
614 if (atsign) /* [user@domain][] -> [user@domain][domain] */
619 /* if for some reason the client doesn't know what domain to use,
620 it will either return an empty string or a '?' */
621 if (!domain[0] || domain[0] == '?')
622 /* Empty domains and empty usernames are usually sent from tokenless contexts.
623 This way such logins will get an empty username (easy to check). I don't know
624 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
625 strcpy(usern,accountName);
627 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
628 strcpy(usern,domain);
631 strncat(usern,accountName,atsign - accountName);
633 strcat(usern,accountName);
641 /* When using SMB auth, all SMB sessions have to pass through here first to
642 * authenticate the user.
643 * Caveat: If not use the SMB auth the protocol does not require sending a
644 * session setup packet, which means that we can't rely on a UID in subsequent
645 * packets. Though in practice we get one anyway.
647 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
651 unsigned short newUid;
652 unsigned long caps = 0;
657 char usern[SMB_MAX_USERNAME_LENGTH];
658 char *secBlobOut = NULL;
659 int secBlobOutLength = 0;
661 /* Check for bad conns */
662 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
663 return CM_ERROR_REMOTECONN;
665 if (vcp->flags & SMB_VCFLAG_USENT) {
666 if (smb_authType == SMB_AUTH_EXTENDED) {
667 /* extended authentication */
671 OutputDebugF("NT Session Setup: Extended");
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 if (smb_authType == SMB_AUTH_NTLM)
709 OutputDebugF("NT Session Setup: NTLM");
711 OutputDebugF("NT Session Setup: None");
713 /* TODO: parse for extended auth as well */
714 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
715 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
717 tp = smb_GetSMBData(inp, &datalen);
719 OutputDebugF("Session packet data size [%d]",datalen);
726 accountName = smb_ParseString(tp, &tp);
727 primaryDomain = smb_ParseString(tp, NULL);
729 OutputDebugF("Account Name: %s",accountName);
730 OutputDebugF("Primary Domain: %s", primaryDomain);
731 OutputDebugF("Case Sensitive Password: %s", csPwd && csPwd[0] ? "yes" : "no");
732 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
734 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
735 /* shouldn't happen */
736 code = CM_ERROR_BADSMB;
737 goto after_read_packet;
740 /* capabilities are only valid for first session packet */
741 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
742 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
745 if (smb_authType == SMB_AUTH_NTLM) {
746 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
748 OutputDebugF("LM authentication failed [%d]", code);
750 OutputDebugF("LM authentication succeeded");
754 unsigned ciPwdLength;
759 switch ( smb_authType ) {
760 case SMB_AUTH_EXTENDED:
761 OutputDebugF("V3 Session Setup: Extended");
764 OutputDebugF("V3 Session Setup: NTLM");
767 OutputDebugF("V3 Session Setup: None");
769 ciPwdLength = smb_GetSMBParm(inp, 7);
770 tp = smb_GetSMBData(inp, NULL);
774 accountName = smb_ParseString(tp, &tp);
775 primaryDomain = smb_ParseString(tp, NULL);
777 OutputDebugF("Account Name: %s",accountName);
778 OutputDebugF("Primary Domain: %s", primaryDomain);
779 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
781 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
782 /* shouldn't happen */
783 code = CM_ERROR_BADSMB;
784 goto after_read_packet;
787 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
790 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
791 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
793 OutputDebugF("LM authentication failed [%d]", code);
795 OutputDebugF("LM authentication succeeded");
800 /* note down that we received a session setup X and set the capabilities flag */
801 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
802 lock_ObtainMutex(&vcp->mx);
803 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
804 /* for the moment we can only deal with NTSTATUS */
805 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
806 vcp->flags |= SMB_VCFLAG_STATUS32;
808 lock_ReleaseMutex(&vcp->mx);
811 /* code would be non-zero if there was an authentication failure.
812 Ideally we would like to invalidate the uid for this session or break
813 early to avoid accidently stealing someone else's tokens. */
819 OutputDebugF("Received username=[%s]", usern);
821 /* On Windows 2000, this function appears to be called more often than
822 it is expected to be called. This resulted in multiple smb_user_t
823 records existing all for the same user session which results in all
824 of the users tokens disappearing.
826 To avoid this problem, we look for an existing smb_user_t record
827 based on the users name, and use that one if we find it.
830 uidp = smb_FindUserByNameThisSession(vcp, usern);
831 if (uidp) { /* already there, so don't create a new one */
834 newUid = (unsigned short)uidp->userID; /* For some reason these are different types!*/
835 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));
836 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
837 smb_ReleaseUID(uidp);
840 /* do a global search for the username/machine name pair */
841 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
843 /* Create a new UID and cm_user_t structure */
846 userp = cm_NewUser();
847 lock_ObtainMutex(&vcp->mx);
848 if (!vcp->uidCounter)
849 vcp->uidCounter++; /* handle unlikely wraparounds */
850 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
851 lock_ReleaseMutex(&vcp->mx);
853 /* Create a new smb_user_t structure and connect them up */
854 lock_ObtainMutex(&unp->mx);
856 lock_ReleaseMutex(&unp->mx);
858 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
859 lock_ObtainMutex(&uidp->mx);
861 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));
862 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
863 lock_ReleaseMutex(&uidp->mx);
864 smb_ReleaseUID(uidp);
867 /* Return UID to the client */
868 ((smb_t *)outp)->uid = newUid;
869 /* Also to the next chained message */
870 ((smb_t *)inp)->uid = newUid;
872 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
873 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
875 smb_SetSMBParm(outp, 2, 0);
877 if (vcp->flags & SMB_VCFLAG_USENT) {
878 if (smb_authType == SMB_AUTH_EXTENDED) {
879 smb_SetSMBParm(outp, 3, secBlobOutLength);
880 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
881 tp = smb_GetSMBData(outp, NULL);
882 if (secBlobOutLength) {
883 memcpy(tp, secBlobOut, secBlobOutLength);
885 tp += secBlobOutLength;
887 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
888 tp += smb_ServerOSLength;
889 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
890 tp += smb_ServerLanManagerLength;
891 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
892 tp += smb_ServerDomainNameLength;
894 smb_SetSMBDataLength(outp, 0);
897 if (smb_authType == SMB_AUTH_EXTENDED) {
898 smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
899 tp = smb_GetSMBData(outp, NULL);
900 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
901 tp += smb_ServerOSLength;
902 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
903 tp += smb_ServerLanManagerLength;
904 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
905 tp += smb_ServerDomainNameLength;
907 smb_SetSMBDataLength(outp, 0);
914 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
918 /* don't get tokens from this VC */
919 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
921 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
923 /* find the tree and free it */
924 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
925 /* TODO: smb_ReleaseUID() ? */
927 char *s1 = NULL, *s2 = NULL;
929 if (s2 == NULL) s2 = " ";
930 if (s1 == NULL) {s1 = s2; s2 = " ";}
932 osi_Log4(smb_logp, "SMB3 user logoffX uid %d name %s%s%s", uidp->userID,
933 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "), s1, s2);
935 lock_ObtainMutex(&uidp->mx);
936 uidp->flags |= SMB_USERFLAG_DELETE;
938 * it doesn't get deleted right away
939 * because the vcp points to it
941 lock_ReleaseMutex(&uidp->mx);
944 osi_Log0(smb_logp, "SMB3 user logoffX");
946 smb_SetSMBDataLength(outp, 0);
950 #define SMB_SUPPORT_SEARCH_BITS 0x0001
951 #define SMB_SHARE_IS_IN_DFS 0x0002
953 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
957 unsigned short newTid;
968 osi_Log0(smb_logp, "SMB3 receive tree connect");
970 /* parse input parameters */
971 tp = smb_GetSMBData(inp, NULL);
972 passwordp = smb_ParseString(tp, &tp);
973 pathp = smb_ParseString(tp, &tp);
974 if (smb_StoreAnsiFilenames)
975 OemToChar(pathp,pathp);
976 servicep = smb_ParseString(tp, &tp);
978 tp = strrchr(pathp, '\\');
980 return CM_ERROR_BADSMB;
982 strcpy(shareName, tp+1);
984 osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
985 osi_LogSaveString(smb_logp, pathp),
986 osi_LogSaveString(smb_logp, shareName));
988 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
990 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
993 return CM_ERROR_NOIPC;
997 userp = smb_GetUser(vcp, inp);
999 lock_ObtainMutex(&vcp->mx);
1000 newTid = vcp->tidCounter++;
1001 lock_ReleaseMutex(&vcp->mx);
1003 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1006 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1007 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1009 smb_ReleaseUID(uidp);
1011 smb_ReleaseTID(tidp);
1012 return CM_ERROR_BADSHARENAME;
1015 if (vcp->flags & SMB_VCFLAG_USENT)
1017 int policy = smb_FindShareCSCPolicy(shareName);
1018 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1020 SMB_SHARE_IS_IN_DFS |
1025 smb_SetSMBParm(outp, 2, 0);
1029 lock_ObtainMutex(&tidp->mx);
1030 tidp->userp = userp;
1031 tidp->pathname = sharePath;
1033 tidp->flags |= SMB_TIDFLAG_IPC;
1034 lock_ReleaseMutex(&tidp->mx);
1035 smb_ReleaseTID(tidp);
1037 ((smb_t *)outp)->tid = newTid;
1038 ((smb_t *)inp)->tid = newTid;
1039 tp = smb_GetSMBData(outp, NULL);
1041 /* XXX - why is this a drive letter? - jaltman */
1045 smb_SetSMBDataLength(outp, 3);
1048 smb_SetSMBDataLength(outp, 4);
1051 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1055 /* must be called with global tran lock held */
1056 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1058 smb_tran2Packet_t *tp;
1061 smbp = (smb_t *) inp->data;
1062 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1063 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1069 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1070 int totalParms, int totalData)
1072 smb_tran2Packet_t *tp;
1075 smbp = (smb_t *) inp->data;
1076 tp = malloc(sizeof(*tp));
1077 memset(tp, 0, sizeof(*tp));
1080 tp->curData = tp->curParms = 0;
1081 tp->totalData = totalData;
1082 tp->totalParms = totalParms;
1083 tp->tid = smbp->tid;
1084 tp->mid = smbp->mid;
1085 tp->uid = smbp->uid;
1086 tp->pid = smbp->pid;
1087 tp->res[0] = smbp->res[0];
1088 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1089 if (totalParms != 0)
1090 tp->parmsp = malloc(totalParms);
1092 tp->datap = malloc(totalData);
1093 if (smbp->com == 0x25 || smbp->com == 0x26)
1096 tp->opcode = smb_GetSMBParm(inp, 14);
1099 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1103 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1104 smb_tran2Packet_t *inp, smb_packet_t *outp,
1105 int totalParms, int totalData)
1107 smb_tran2Packet_t *tp;
1108 unsigned short parmOffset;
1109 unsigned short dataOffset;
1110 unsigned short dataAlign;
1112 tp = malloc(sizeof(*tp));
1113 memset(tp, 0, sizeof(*tp));
1115 tp->curData = tp->curParms = 0;
1116 tp->totalData = totalData;
1117 tp->totalParms = totalParms;
1118 tp->oldTotalParms = totalParms;
1123 tp->res[0] = inp->res[0];
1124 tp->opcode = inp->opcode;
1128 * We calculate where the parameters and data will start.
1129 * This calculation must parallel the calculation in
1130 * smb_SendTran2Packet.
1133 parmOffset = 10*2 + 35;
1134 parmOffset++; /* round to even */
1135 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1137 dataOffset = parmOffset + totalParms;
1138 dataAlign = dataOffset & 2; /* quad-align */
1139 dataOffset += dataAlign;
1140 tp->datap = outp->data + dataOffset;
1145 /* free a tran2 packet; must be called with smb_globalLock held */
1146 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1149 smb_ReleaseVC(t2p->vcp);
1150 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1159 /* called with a VC, an input packet to respond to, and an error code.
1160 * sends an error response.
1162 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1163 smb_packet_t *tp, long code)
1166 unsigned short errCode;
1167 unsigned char errClass;
1168 unsigned long NTStatus;
1170 if (vcp->flags & SMB_VCFLAG_STATUS32)
1171 smb_MapNTError(code, &NTStatus);
1173 smb_MapCoreError(code, vcp, &errCode, &errClass);
1175 smb_FormatResponsePacket(vcp, NULL, tp);
1176 smbp = (smb_t *) tp;
1178 /* We can handle long names */
1179 if (vcp->flags & SMB_VCFLAG_USENT)
1180 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1182 /* now copy important fields from the tran 2 packet */
1183 smbp->com = t2p->com;
1184 smbp->tid = t2p->tid;
1185 smbp->mid = t2p->mid;
1186 smbp->pid = t2p->pid;
1187 smbp->uid = t2p->uid;
1188 smbp->res[0] = t2p->res[0];
1189 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1190 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1191 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1192 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1193 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1194 smbp->flg2 |= SMB_FLAGS2_ERR_STATUS;
1197 smbp->rcls = errClass;
1198 smbp->errLow = (unsigned char) (errCode & 0xff);
1199 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1203 smb_SendPacket(vcp, tp);
1206 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1209 unsigned short parmOffset;
1210 unsigned short dataOffset;
1211 unsigned short totalLength;
1212 unsigned short dataAlign;
1215 smb_FormatResponsePacket(vcp, NULL, tp);
1216 smbp = (smb_t *) tp;
1218 /* We can handle long names */
1219 if (vcp->flags & SMB_VCFLAG_USENT)
1220 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1222 /* now copy important fields from the tran 2 packet */
1223 smbp->com = t2p->com;
1224 smbp->tid = t2p->tid;
1225 smbp->mid = t2p->mid;
1226 smbp->pid = t2p->pid;
1227 smbp->uid = t2p->uid;
1228 smbp->res[0] = t2p->res[0];
1230 totalLength = 1 + t2p->totalData + t2p->totalParms;
1232 /* now add the core parameters (tran2 info) to the packet */
1233 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1234 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1235 smb_SetSMBParm(tp, 2, 0); /* reserved */
1236 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1237 parmOffset = 10*2 + 35; /* parm offset in packet */
1238 parmOffset++; /* round to even */
1239 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1240 * hdr, bcc and wct */
1241 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1242 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1243 dataOffset = parmOffset + t2p->oldTotalParms;
1244 dataAlign = dataOffset & 2; /* quad-align */
1245 dataOffset += dataAlign;
1246 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1247 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1248 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1251 datap = smb_GetSMBData(tp, NULL);
1252 *datap++ = 0; /* we rounded to even */
1254 totalLength += dataAlign;
1255 smb_SetSMBDataLength(tp, totalLength);
1257 /* next, send the datagram */
1258 smb_SendPacket(vcp, tp);
1261 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1263 smb_tran2Packet_t *asp;
1276 /* We sometimes see 0 word count. What to do? */
1277 if (*inp->wctp == 0) {
1282 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1284 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1285 ptbuf[0] = "Transaction2 word count = 0";
1286 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1287 1, inp->ncb_length, ptbuf, inp);
1288 DeregisterEventSource(h);
1290 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1293 smb_SetSMBDataLength(outp, 0);
1294 smb_SendPacket(vcp, outp);
1298 totalParms = smb_GetSMBParm(inp, 0);
1299 totalData = smb_GetSMBParm(inp, 1);
1301 firstPacket = (inp->inCom == 0x25);
1303 /* find the packet we're reassembling */
1304 lock_ObtainWrite(&smb_globalLock);
1305 asp = smb_FindTran2Packet(vcp, inp);
1307 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1309 lock_ReleaseWrite(&smb_globalLock);
1311 /* now merge in this latest packet; start by looking up offsets */
1313 parmDisp = dataDisp = 0;
1314 parmOffset = smb_GetSMBParm(inp, 10);
1315 dataOffset = smb_GetSMBParm(inp, 12);
1316 parmCount = smb_GetSMBParm(inp, 9);
1317 dataCount = smb_GetSMBParm(inp, 11);
1318 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1319 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1321 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1322 totalData, dataCount, asp->maxReturnData);
1325 parmDisp = smb_GetSMBParm(inp, 4);
1326 parmOffset = smb_GetSMBParm(inp, 3);
1327 dataDisp = smb_GetSMBParm(inp, 7);
1328 dataOffset = smb_GetSMBParm(inp, 6);
1329 parmCount = smb_GetSMBParm(inp, 2);
1330 dataCount = smb_GetSMBParm(inp, 5);
1332 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1333 parmCount, dataCount);
1336 /* now copy the parms and data */
1337 if ( asp->totalParms > 0 && parmCount != 0 )
1339 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1341 if ( asp->totalData > 0 && dataCount != 0 ) {
1342 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1345 /* account for new bytes */
1346 asp->curData += dataCount;
1347 asp->curParms += parmCount;
1349 /* finally, if we're done, remove the packet from the queue and dispatch it */
1350 if (asp->totalParms > 0 &&
1351 asp->curParms > 0 &&
1352 asp->totalData <= asp->curData &&
1353 asp->totalParms <= asp->curParms) {
1354 /* we've received it all */
1355 lock_ObtainWrite(&smb_globalLock);
1356 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1357 lock_ReleaseWrite(&smb_globalLock);
1359 /* now dispatch it */
1360 rapOp = asp->parmsp[0];
1362 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1363 osi_LogEvent("AFS-Dispatch-RAP[%s]",myCrt_RapDispatch(rapOp),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1364 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%x] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1365 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1368 osi_LogEvent("AFS-Dispatch-RAP [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1369 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1370 code = CM_ERROR_BADOP;
1373 /* if an error is returned, we're supposed to send an error packet,
1374 * otherwise the dispatched function already did the data sending.
1375 * We give dispatched proc the responsibility since it knows how much
1376 * space to allocate.
1379 smb_SendTran2Error(vcp, asp, outp, code);
1382 /* free the input tran 2 packet */
1383 lock_ObtainWrite(&smb_globalLock);
1384 smb_FreeTran2Packet(asp);
1385 lock_ReleaseWrite(&smb_globalLock);
1387 else if (firstPacket) {
1388 /* the first packet in a multi-packet request, we need to send an
1389 * ack to get more data.
1391 smb_SetSMBDataLength(outp, 0);
1392 smb_SendPacket(vcp, outp);
1398 /* ANSI versions. The unicode versions support arbitrary length
1399 share names, but we don't support unicode yet. */
1401 typedef struct smb_rap_share_info_0 {
1402 char shi0_netname[13];
1403 } smb_rap_share_info_0_t;
1405 typedef struct smb_rap_share_info_1 {
1406 char shi1_netname[13];
1409 DWORD shi1_remark; /* char *shi1_remark; data offset */
1410 } smb_rap_share_info_1_t;
1412 typedef struct smb_rap_share_info_2 {
1413 char shi2_netname[13];
1415 unsigned short shi2_type;
1416 DWORD shi2_remark; /* char *shi2_remark; data offset */
1417 unsigned short shi2_permissions;
1418 unsigned short shi2_max_uses;
1419 unsigned short shi2_current_uses;
1420 DWORD shi2_path; /* char *shi2_path; data offset */
1421 unsigned short shi2_passwd[9];
1422 unsigned short shi2_pad2;
1423 } smb_rap_share_info_2_t;
1425 #define SMB_RAP_MAX_SHARES 512
1427 typedef struct smb_rap_share_list {
1430 smb_rap_share_info_0_t * shares;
1431 } smb_rap_share_list_t;
1433 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1434 smb_rap_share_list_t * sp;
1439 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1440 return 0; /* skip over '.' and '..' */
1442 sp = (smb_rap_share_list_t *) vrockp;
1444 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1445 sp->shares[sp->cShare].shi0_netname[12] = 0;
1449 if (sp->cShare >= sp->maxShares)
1450 return CM_ERROR_STOPNOW;
1455 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1457 smb_tran2Packet_t *outp;
1458 unsigned short * tp;
1462 int outParmsTotal; /* total parameter bytes */
1463 int outDataTotal; /* total data bytes */
1471 HKEY hkSubmount = NULL;
1472 smb_rap_share_info_1_t * shares;
1475 char thisShare[256];
1478 smb_rap_share_list_t rootShares;
1483 tp = p->parmsp + 1; /* skip over function number (always 0) */
1484 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1485 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1489 if (infoLevel != 1) {
1490 return CM_ERROR_INVAL;
1493 /* first figure out how many shares there are */
1494 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1495 KEY_QUERY_VALUE, &hkParam);
1496 if (rv == ERROR_SUCCESS) {
1497 len = sizeof(allSubmount);
1498 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1499 (BYTE *) &allSubmount, &len);
1500 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1503 RegCloseKey (hkParam);
1506 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1507 0, KEY_QUERY_VALUE, &hkSubmount);
1508 if (rv == ERROR_SUCCESS) {
1509 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1510 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1511 if (rv != ERROR_SUCCESS)
1517 /* fetch the root shares */
1518 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1519 rootShares.cShare = 0;
1520 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1524 userp = smb_GetTran2User(vcp,p);
1526 thyper.HighPart = 0;
1529 cm_HoldSCache(cm_rootSCachep);
1530 cm_ApplyDir(cm_rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1531 cm_ReleaseSCache(cm_rootSCachep);
1533 cm_ReleaseUser(userp);
1535 nShares = rootShares.cShare + nRegShares + allSubmount;
1537 #define REMARK_LEN 1
1538 outParmsTotal = 8; /* 4 dwords */
1539 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1540 if(outDataTotal > bufsize) {
1541 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1542 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1545 nSharesRet = nShares;
1548 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1550 /* now for the submounts */
1551 shares = (smb_rap_share_info_1_t *) outp->datap;
1552 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1554 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1557 strcpy( shares[cshare].shi1_netname, "all" );
1558 shares[cshare].shi1_remark = cstrp - outp->datap;
1559 /* type and pad are zero already */
1565 for (i=0; i < nRegShares && cshare < nSharesRet; i++) {
1566 len = sizeof(thisShare);
1567 rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1568 if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1569 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1570 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1571 shares[cshare].shi1_remark = cstrp - outp->datap;
1576 nShares--; /* uncount key */
1579 RegCloseKey(hkSubmount);
1582 nonrootShares = cshare;
1584 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1585 /* in case there are collisions with submounts, submounts have higher priority */
1586 for (j=0; j < nonrootShares; j++)
1587 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1590 if (j < nonrootShares) {
1591 nShares--; /* uncount */
1595 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1596 shares[cshare].shi1_remark = cstrp - outp->datap;
1601 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1602 outp->parmsp[1] = 0;
1603 outp->parmsp[2] = cshare;
1604 outp->parmsp[3] = nShares;
1606 outp->totalData = cstrp - outp->datap;
1607 outp->totalParms = outParmsTotal;
1609 smb_SendTran2Packet(vcp, outp, op);
1610 smb_FreeTran2Packet(outp);
1612 free(rootShares.shares);
1617 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1619 smb_tran2Packet_t *outp;
1620 unsigned short * tp;
1622 BOOL shareFound = FALSE;
1623 unsigned short infoLevel;
1624 unsigned short bufsize;
1634 tp = p->parmsp + 1; /* skip over function number (always 1) */
1635 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1636 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1637 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1644 totalData = sizeof(smb_rap_share_info_0_t);
1645 else if(infoLevel == SMB_INFO_STANDARD)
1646 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1647 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1648 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1650 return CM_ERROR_INVAL;
1652 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1654 if(!stricmp(shareName,"all")) {
1655 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1656 KEY_QUERY_VALUE, &hkParam);
1657 if (rv == ERROR_SUCCESS) {
1658 len = sizeof(allSubmount);
1659 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1660 (BYTE *) &allSubmount, &len);
1661 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1664 RegCloseKey (hkParam);
1671 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts", 0,
1672 KEY_QUERY_VALUE, &hkSubmount);
1673 if (rv == ERROR_SUCCESS) {
1674 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1675 if (rv == ERROR_SUCCESS) {
1678 RegCloseKey(hkSubmount);
1683 smb_FreeTran2Packet(outp);
1684 return CM_ERROR_BADSHARENAME;
1687 memset(outp->datap, 0, totalData);
1689 outp->parmsp[0] = 0;
1690 outp->parmsp[1] = 0;
1691 outp->parmsp[2] = totalData;
1693 if (infoLevel == 0) {
1694 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1695 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1696 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1697 } else if(infoLevel == SMB_INFO_STANDARD) {
1698 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1699 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1700 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1701 info->shi1_remark = ((unsigned char *) (info + 1)) - outp->datap;
1702 /* type and pad are already zero */
1703 } else { /* infoLevel==2 */
1704 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1705 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1706 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1707 info->shi2_remark = ((unsigned char *) (info + 1)) - outp->datap;
1708 info->shi2_permissions = ACCESS_ALL;
1709 info->shi2_max_uses = (unsigned short) -1;
1710 info->shi2_path = 1 + (((unsigned char *) (info + 1)) - outp->datap);
1713 outp->totalData = totalData;
1714 outp->totalParms = totalParam;
1716 smb_SendTran2Packet(vcp, outp, op);
1717 smb_FreeTran2Packet(outp);
1722 typedef struct smb_rap_wksta_info_10 {
1723 DWORD wki10_computername; /*char *wki10_computername;*/
1724 DWORD wki10_username; /* char *wki10_username; */
1725 DWORD wki10_langroup; /* char *wki10_langroup;*/
1726 unsigned char wki10_ver_major;
1727 unsigned char wki10_ver_minor;
1728 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1729 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1730 } smb_rap_wksta_info_10_t;
1733 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1735 smb_tran2Packet_t *outp;
1739 unsigned short * tp;
1742 smb_rap_wksta_info_10_t * info;
1746 tp = p->parmsp + 1; /* Skip over function number */
1747 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1748 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1752 if (infoLevel != 10) {
1753 return CM_ERROR_INVAL;
1759 totalData = sizeof(*info) + /* info */
1760 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1761 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1762 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1763 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1764 1; /* wki10_oth_domains (null)*/
1766 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1768 memset(outp->parmsp,0,totalParams);
1769 memset(outp->datap,0,totalData);
1771 info = (smb_rap_wksta_info_10_t *) outp->datap;
1772 cstrp = (char *) (info + 1);
1774 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1775 strcpy(cstrp, smb_localNamep);
1776 cstrp += strlen(cstrp) + 1;
1778 info->wki10_username = (DWORD) (cstrp - outp->datap);
1779 uidp = smb_FindUID(vcp, p->uid, 0);
1781 lock_ObtainMutex(&uidp->mx);
1782 if(uidp->unp && uidp->unp->name)
1783 strcpy(cstrp, uidp->unp->name);
1784 lock_ReleaseMutex(&uidp->mx);
1785 smb_ReleaseUID(uidp);
1787 cstrp += strlen(cstrp) + 1;
1789 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1790 strcpy(cstrp, "WORKGROUP");
1791 cstrp += strlen(cstrp) + 1;
1793 /* TODO: Not sure what values these should take, but these work */
1794 info->wki10_ver_major = 5;
1795 info->wki10_ver_minor = 1;
1797 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1798 strcpy(cstrp, smb_ServerDomainName);
1799 cstrp += strlen(cstrp) + 1;
1801 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1802 cstrp ++; /* no other domains */
1804 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1805 outp->parmsp[2] = outp->totalData;
1806 outp->totalParms = totalParams;
1808 smb_SendTran2Packet(vcp,outp,op);
1809 smb_FreeTran2Packet(outp);
1814 typedef struct smb_rap_server_info_0 {
1816 } smb_rap_server_info_0_t;
1818 typedef struct smb_rap_server_info_1 {
1820 char sv1_version_major;
1821 char sv1_version_minor;
1822 unsigned long sv1_type;
1823 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1824 } smb_rap_server_info_1_t;
1826 char smb_ServerComment[] = "OpenAFS Client";
1827 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1829 #define SMB_SV_TYPE_SERVER 0x00000002L
1830 #define SMB_SV_TYPE_NT 0x00001000L
1831 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1833 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1835 smb_tran2Packet_t *outp;
1839 unsigned short * tp;
1842 smb_rap_server_info_0_t * info0;
1843 smb_rap_server_info_1_t * info1;
1846 tp = p->parmsp + 1; /* Skip over function number */
1847 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1848 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1852 if (infoLevel != 0 && infoLevel != 1) {
1853 return CM_ERROR_INVAL;
1859 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1860 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1862 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1864 memset(outp->parmsp,0,totalParams);
1865 memset(outp->datap,0,totalData);
1867 if (infoLevel == 0) {
1868 info0 = (smb_rap_server_info_0_t *) outp->datap;
1869 cstrp = (char *) (info0 + 1);
1870 strcpy(info0->sv0_name, "AFS");
1871 } else { /* infoLevel == SMB_INFO_STANDARD */
1872 info1 = (smb_rap_server_info_1_t *) outp->datap;
1873 cstrp = (char *) (info1 + 1);
1874 strcpy(info1->sv1_name, "AFS");
1877 SMB_SV_TYPE_SERVER |
1879 SMB_SV_TYPE_SERVER_NT;
1881 info1->sv1_version_major = 5;
1882 info1->sv1_version_minor = 1;
1883 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1885 strcpy(cstrp, smb_ServerComment);
1887 cstrp += smb_ServerCommentLen;
1890 totalData = cstrp - outp->datap;
1891 outp->totalData = min(bufsize,totalData); /* actual data size */
1892 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1893 outp->parmsp[2] = totalData;
1894 outp->totalParms = totalParams;
1896 smb_SendTran2Packet(vcp,outp,op);
1897 smb_FreeTran2Packet(outp);
1902 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1904 smb_tran2Packet_t *asp;
1916 /* We sometimes see 0 word count. What to do? */
1917 if (*inp->wctp == 0) {
1922 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1924 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1925 ptbuf[0] = "Transaction2 word count = 0";
1926 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1927 1, inp->ncb_length, ptbuf, inp);
1928 DeregisterEventSource(h);
1930 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1933 smb_SetSMBDataLength(outp, 0);
1934 smb_SendPacket(vcp, outp);
1938 totalParms = smb_GetSMBParm(inp, 0);
1939 totalData = smb_GetSMBParm(inp, 1);
1941 firstPacket = (inp->inCom == 0x32);
1943 /* find the packet we're reassembling */
1944 lock_ObtainWrite(&smb_globalLock);
1945 asp = smb_FindTran2Packet(vcp, inp);
1947 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1949 lock_ReleaseWrite(&smb_globalLock);
1951 /* now merge in this latest packet; start by looking up offsets */
1953 parmDisp = dataDisp = 0;
1954 parmOffset = smb_GetSMBParm(inp, 10);
1955 dataOffset = smb_GetSMBParm(inp, 12);
1956 parmCount = smb_GetSMBParm(inp, 9);
1957 dataCount = smb_GetSMBParm(inp, 11);
1958 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1959 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1961 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1962 totalData, dataCount, asp->maxReturnData);
1965 parmDisp = smb_GetSMBParm(inp, 4);
1966 parmOffset = smb_GetSMBParm(inp, 3);
1967 dataDisp = smb_GetSMBParm(inp, 7);
1968 dataOffset = smb_GetSMBParm(inp, 6);
1969 parmCount = smb_GetSMBParm(inp, 2);
1970 dataCount = smb_GetSMBParm(inp, 5);
1972 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1973 parmCount, dataCount);
1976 /* now copy the parms and data */
1977 if ( asp->totalParms > 0 && parmCount != 0 )
1979 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1981 if ( asp->totalData > 0 && dataCount != 0 ) {
1982 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1985 /* account for new bytes */
1986 asp->curData += dataCount;
1987 asp->curParms += parmCount;
1989 /* finally, if we're done, remove the packet from the queue and dispatch it */
1990 if (asp->totalParms > 0 &&
1991 asp->curParms > 0 &&
1992 asp->totalData <= asp->curData &&
1993 asp->totalParms <= asp->curParms) {
1994 /* we've received it all */
1995 lock_ObtainWrite(&smb_globalLock);
1996 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1997 lock_ReleaseWrite(&smb_globalLock);
1999 /* now dispatch it */
2000 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2001 osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
2002 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2003 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2006 osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2007 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2008 code = CM_ERROR_BADOP;
2011 /* if an error is returned, we're supposed to send an error packet,
2012 * otherwise the dispatched function already did the data sending.
2013 * We give dispatched proc the responsibility since it knows how much
2014 * space to allocate.
2017 smb_SendTran2Error(vcp, asp, outp, code);
2020 /* free the input tran 2 packet */
2021 lock_ObtainWrite(&smb_globalLock);
2022 smb_FreeTran2Packet(asp);
2023 lock_ReleaseWrite(&smb_globalLock);
2025 else if (firstPacket) {
2026 /* the first packet in a multi-packet request, we need to send an
2027 * ack to get more data.
2029 smb_SetSMBDataLength(outp, 0);
2030 smb_SendPacket(vcp, outp);
2036 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2039 smb_tran2Packet_t *outp;
2044 cm_scache_t *dscp; /* dir we're dealing with */
2045 cm_scache_t *scp; /* file we're creating */
2047 int initialModeBits;
2057 int parmSlot; /* which parm we're dealing with */
2058 long returnEALength;
2066 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2067 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2069 openFun = p->parmsp[6]; /* open function */
2070 excl = ((openFun & 3) == 0);
2071 trunc = ((openFun & 3) == 2); /* truncate it */
2072 openMode = (p->parmsp[1] & 0x7);
2073 openAction = 0; /* tracks what we did */
2075 attributes = p->parmsp[3];
2076 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2078 /* compute initial mode bits based on read-only flag in attributes */
2079 initialModeBits = 0666;
2080 if (attributes & 1) initialModeBits &= ~0222;
2082 pathp = (char *) (&p->parmsp[14]);
2083 if (smb_StoreAnsiFilenames)
2084 OemToChar(pathp,pathp);
2086 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2088 spacep = cm_GetSpace();
2089 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2091 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2092 /* special case magic file name for receiving IOCTL requests
2093 * (since IOCTL calls themselves aren't getting through).
2095 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2096 smb_SetupIoctlFid(fidp, spacep);
2098 /* copy out remainder of the parms */
2100 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2102 outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
2103 outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
2104 outp->parmsp[parmSlot] = 0; parmSlot++;
2105 outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
2106 outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
2107 outp->parmsp[parmSlot] = openMode; parmSlot++;
2108 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2109 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2111 /* and the final "always present" stuff */
2112 outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
2113 /* next write out the "unique" ID */
2114 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
2115 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
2116 outp->parmsp[parmSlot] = 0; parmSlot++;
2117 if (returnEALength) {
2118 outp->parmsp[parmSlot] = 0; parmSlot++;
2119 outp->parmsp[parmSlot] = 0; parmSlot++;
2122 outp->totalData = 0;
2123 outp->totalParms = parmSlot * 2;
2125 smb_SendTran2Packet(vcp, outp, op);
2127 smb_FreeTran2Packet(outp);
2129 /* and clean up fid reference */
2130 smb_ReleaseFID(fidp);
2134 #ifdef DEBUG_VERBOSE
2136 char *hexp, *asciip;
2137 asciip = (lastNamep ? lastNamep : pathp);
2138 hexp = osi_HexifyString( asciip );
2139 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2144 userp = smb_GetTran2User(vcp, p);
2145 /* In the off chance that userp is NULL, we log and abandon */
2147 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2148 smb_FreeTran2Packet(outp);
2149 return CM_ERROR_BADSMB;
2152 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2153 if (code == CM_ERROR_TIDIPC) {
2154 /* Attempt to use TID allocated for IPC. The client is
2155 probably trying to locate DCE RPC end points, which
2156 we don't support. */
2157 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2158 cm_ReleaseUser(userp);
2159 smb_FreeTran2Packet(outp);
2160 return CM_ERROR_NOSUCHPATH;
2164 code = cm_NameI(cm_rootSCachep, pathp,
2165 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2166 userp, tidPathp, &req, &scp);
2168 code = cm_NameI(cm_rootSCachep, spacep->data,
2169 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2170 userp, tidPathp, &req, &dscp);
2171 cm_FreeSpace(spacep);
2174 cm_ReleaseUser(userp);
2175 smb_FreeTran2Packet(outp);
2179 /* otherwise, scp points to the parent directory. Do a lookup,
2180 * and truncate the file if we find it, otherwise we create the
2187 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2189 if (code && code != CM_ERROR_NOSUCHFILE) {
2190 cm_ReleaseSCache(dscp);
2191 cm_ReleaseUser(userp);
2192 smb_FreeTran2Packet(outp);
2197 cm_FreeSpace(spacep);
2200 /* if we get here, if code is 0, the file exists and is represented by
2201 * scp. Otherwise, we have to create it.
2204 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2206 if (dscp) cm_ReleaseSCache(dscp);
2207 cm_ReleaseSCache(scp);
2208 cm_ReleaseUser(userp);
2209 smb_FreeTran2Packet(outp);
2214 /* oops, file shouldn't be there */
2215 if (dscp) cm_ReleaseSCache(dscp);
2216 cm_ReleaseSCache(scp);
2217 cm_ReleaseUser(userp);
2218 smb_FreeTran2Packet(outp);
2219 return CM_ERROR_EXISTS;
2223 setAttr.mask = CM_ATTRMASK_LENGTH;
2224 setAttr.length.LowPart = 0;
2225 setAttr.length.HighPart = 0;
2226 code = cm_SetAttr(scp, &setAttr, userp, &req);
2227 openAction = 3; /* truncated existing file */
2230 openAction = 1; /* found existing file */
2232 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
2233 /* don't create if not found */
2234 if (dscp) cm_ReleaseSCache(dscp);
2235 osi_assert(scp == NULL);
2236 cm_ReleaseUser(userp);
2237 smb_FreeTran2Packet(outp);
2238 return CM_ERROR_NOSUCHFILE;
2241 osi_assert(dscp != NULL && scp == NULL);
2242 openAction = 2; /* created file */
2243 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2244 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2245 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2247 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2248 smb_NotifyChange(FILE_ACTION_ADDED,
2249 FILE_NOTIFY_CHANGE_FILE_NAME,
2250 dscp, lastNamep, NULL, TRUE);
2251 if (!excl && code == CM_ERROR_EXISTS) {
2252 /* not an exclusive create, and someone else tried
2253 * creating it already, then we open it anyway. We
2254 * don't bother retrying after this, since if this next
2255 * fails, that means that the file was deleted after we
2256 * started this call.
2258 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2262 setAttr.mask = CM_ATTRMASK_LENGTH;
2263 setAttr.length.LowPart = 0;
2264 setAttr.length.HighPart = 0;
2265 code = cm_SetAttr(scp, &setAttr, userp,
2268 } /* lookup succeeded */
2272 /* we don't need this any longer */
2273 if (dscp) cm_ReleaseSCache(dscp);
2276 /* something went wrong creating or truncating the file */
2277 if (scp) cm_ReleaseSCache(scp);
2278 cm_ReleaseUser(userp);
2279 smb_FreeTran2Packet(outp);
2283 /* make sure we're about to open a file */
2284 if (scp->fileType != CM_SCACHETYPE_FILE) {
2286 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2287 cm_scache_t * targetScp = 0;
2288 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2290 /* we have a more accurate file to use (the
2291 * target of the symbolic link). Otherwise,
2292 * we'll just use the symlink anyway.
2294 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2296 cm_ReleaseSCache(scp);
2300 if (scp->fileType != CM_SCACHETYPE_FILE) {
2301 cm_ReleaseSCache(scp);
2302 cm_ReleaseUser(userp);
2303 smb_FreeTran2Packet(outp);
2304 return CM_ERROR_ISDIR;
2308 /* now all we have to do is open the file itself */
2309 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2312 /* save a pointer to the vnode */
2315 /* compute open mode */
2316 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2317 if (openMode == 1 || openMode == 2)
2318 fidp->flags |= SMB_FID_OPENWRITE;
2320 smb_ReleaseFID(fidp);
2322 cm_Open(scp, 0, userp);
2324 /* copy out remainder of the parms */
2326 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2327 lock_ObtainMutex(&scp->mx);
2329 outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
2330 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2331 outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
2332 outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
2333 outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
2335 outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2337 outp->parmsp[parmSlot] = openMode; parmSlot++;
2338 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2339 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2341 /* and the final "always present" stuff */
2342 outp->parmsp[parmSlot] = openAction; parmSlot++;
2343 /* next write out the "unique" ID */
2344 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
2345 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
2346 outp->parmsp[parmSlot] = 0; parmSlot++;
2347 if (returnEALength) {
2348 outp->parmsp[parmSlot] = 0; parmSlot++;
2349 outp->parmsp[parmSlot] = 0; parmSlot++;
2351 lock_ReleaseMutex(&scp->mx);
2352 outp->totalData = 0; /* total # of data bytes */
2353 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2355 smb_SendTran2Packet(vcp, outp, op);
2357 smb_FreeTran2Packet(outp);
2359 cm_ReleaseUser(userp);
2360 /* leave scp held since we put it in fidp->scp */
2364 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2366 osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2367 return CM_ERROR_BADOP;
2370 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2372 osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2373 return CM_ERROR_BADOP;
2376 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2378 smb_tran2Packet_t *outp;
2379 smb_tran2QFSInfo_t qi;
2382 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
2384 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2386 switch (p->parmsp[0]) {
2387 case 1: responseSize = sizeof(qi.u.allocInfo); break;
2388 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
2389 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
2390 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
2391 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
2392 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
2393 case 0x200: /* CIFS Unix Info */
2394 case 0x301: /* Mac FS Info */
2395 default: return CM_ERROR_INVAL;
2398 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2399 switch (p->parmsp[0]) {
2402 qi.u.allocInfo.FSID = 0;
2403 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2404 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2405 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2406 qi.u.allocInfo.bytesPerSector = 1024;
2411 qi.u.volumeInfo.vsn = 1234;
2412 qi.u.volumeInfo.vnCount = 4;
2413 /* we're supposed to pad it out with zeroes to the end */
2414 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2415 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2419 /* FS volume info */
2420 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
2421 qi.u.FSvolumeInfo.vsn = 1234;
2422 qi.u.FSvolumeInfo.vnCount = 8;
2423 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
2429 temp.LowPart = 0x7fffffff;
2430 qi.u.FSsizeInfo.totalAllocUnits = temp;
2431 temp.LowPart = 0x3fffffff;
2432 qi.u.FSsizeInfo.availAllocUnits = temp;
2433 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2434 qi.u.FSsizeInfo.bytesPerSector = 1024;
2438 /* FS device info */
2439 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
2440 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2444 /* FS attribute info */
2445 /* attributes, defined in WINNT.H:
2446 * FILE_CASE_SENSITIVE_SEARCH 0x1
2447 * FILE_CASE_PRESERVED_NAMES 0x2
2448 * <no name defined> 0x4000
2449 * If bit 0x4000 is not set, Windows 95 thinks
2450 * we can't handle long (non-8.3) names,
2451 * despite our protestations to the contrary.
2453 qi.u.FSattributeInfo.attributes = 0x4003;
2454 qi.u.FSattributeInfo.maxCompLength = 255;
2455 qi.u.FSattributeInfo.FSnameLength = 6;
2456 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
2460 /* copy out return data, and set corresponding sizes */
2461 outp->totalParms = 0;
2462 outp->totalData = responseSize;
2463 memcpy(outp->datap, &qi, responseSize);
2465 /* send and free the packets */
2466 smb_SendTran2Packet(vcp, outp, op);
2467 smb_FreeTran2Packet(outp);
2472 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2474 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2475 return CM_ERROR_BADOP;
2478 struct smb_ShortNameRock {
2482 size_t shortNameLen;
2485 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2488 struct smb_ShortNameRock *rockp;
2492 /* compare both names and vnodes, though probably just comparing vnodes
2493 * would be safe enough.
2495 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2497 if (ntohl(dep->fid.vnode) != rockp->vnode)
2499 /* This is the entry */
2500 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2501 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2502 return CM_ERROR_STOPNOW;
2505 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2506 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2508 struct smb_ShortNameRock rock;
2512 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2516 spacep = cm_GetSpace();
2517 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2519 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
2521 cm_FreeSpace(spacep);
2522 if (code) return code;
2524 if (!lastNamep) lastNamep = pathp;
2527 thyper.HighPart = 0;
2528 rock.shortName = shortName;
2530 rock.maskp = lastNamep;
2531 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2533 cm_ReleaseSCache(dscp);
2536 return CM_ERROR_NOSUCHFILE;
2537 if (code == CM_ERROR_STOPNOW) {
2538 *shortNameLenp = rock.shortNameLen;
2544 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2546 smb_tran2Packet_t *outp;
2549 unsigned short infoLevel;
2551 unsigned short attributes;
2552 unsigned long extAttributes;
2557 cm_scache_t *scp, *dscp;
2566 infoLevel = p->parmsp[0];
2567 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2569 else if (infoLevel == SMB_INFO_STANDARD)
2570 nbytesRequired = 22;
2571 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2572 nbytesRequired = 26;
2573 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2574 nbytesRequired = 40;
2575 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2576 nbytesRequired = 24;
2577 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2579 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2580 nbytesRequired = 30;
2582 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2583 p->opcode, infoLevel);
2584 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2587 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2588 osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
2590 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2592 if (infoLevel > 0x100)
2593 outp->totalParms = 2;
2595 outp->totalParms = 0;
2596 outp->totalData = nbytesRequired;
2598 /* now, if we're at infoLevel 6, we're only being asked to check
2599 * the syntax, so we just OK things now. In particular, we're *not*
2600 * being asked to verify anything about the state of any parent dirs.
2602 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2603 smb_SendTran2Packet(vcp, outp, opx);
2604 smb_FreeTran2Packet(outp);
2608 userp = smb_GetTran2User(vcp, p);
2610 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2611 smb_FreeTran2Packet(outp);
2612 return CM_ERROR_BADSMB;
2615 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2617 cm_ReleaseUser(userp);
2618 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2619 smb_FreeTran2Packet(outp);
2624 * XXX Strange hack XXX
2626 * As of Patch 7 (13 January 98), we are having the following problem:
2627 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2628 * requests to look up "desktop.ini" in all the subdirectories.
2629 * This can cause zillions of timeouts looking up non-existent cells
2630 * and volumes, especially in the top-level directory.
2632 * We have not found any way to avoid this or work around it except
2633 * to explicitly ignore the requests for mount points that haven't
2634 * yet been evaluated and for directories that haven't yet been
2637 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2638 spacep = cm_GetSpace();
2639 smb_StripLastComponent(spacep->data, &lastComp,
2640 (char *)(&p->parmsp[3]));
2641 #ifndef SPECIAL_FOLDERS
2642 /* Make sure that lastComp is not NULL */
2644 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2645 code = cm_NameI(cm_rootSCachep, spacep->data,
2649 userp, tidPathp, &req, &dscp);
2651 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
2652 && !dscp->mountRootFidp)
2653 code = CM_ERROR_NOSUCHFILE;
2654 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2655 cm_buf_t *bp = buf_Find(dscp, &hzero);
2659 code = CM_ERROR_NOSUCHFILE;
2661 cm_ReleaseSCache(dscp);
2663 cm_FreeSpace(spacep);
2664 cm_ReleaseUser(userp);
2665 smb_SendTran2Error(vcp, p, opx, code);
2666 smb_FreeTran2Packet(outp);
2672 #endif /* SPECIAL_FOLDERS */
2674 cm_FreeSpace(spacep);
2677 /* now do namei and stat, and copy out the info */
2678 code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
2679 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2682 cm_ReleaseUser(userp);
2683 smb_SendTran2Error(vcp, p, opx, code);
2684 smb_FreeTran2Packet(outp);
2688 lock_ObtainMutex(&scp->mx);
2689 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2690 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2691 if (code) goto done;
2693 /* now we have the status in the cache entry, and everything is locked.
2694 * Marshall the output data.
2697 /* for info level 108, figure out short name */
2698 if (infoLevel == 0x108) {
2699 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
2700 tidPathp, scp->fid.vnode, shortName,
2707 *((u_long *)op) = len * 2; op += 4;
2708 mbstowcs((unsigned short *)op, shortName, len);
2713 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2714 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2715 *((u_long *)op) = dosTime; op += 4; /* creation time */
2716 *((u_long *)op) = dosTime; op += 4; /* access time */
2717 *((u_long *)op) = dosTime; op += 4; /* write time */
2718 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
2719 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
2720 attributes = smb_Attributes(scp);
2721 *((u_short *)op) = attributes; op += 2; /* attributes */
2723 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2724 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2725 *((FILETIME *)op) = ft; op += 8; /* creation time */
2726 *((FILETIME *)op) = ft; op += 8; /* last access time */
2727 *((FILETIME *)op) = ft; op += 8; /* last write time */
2728 *((FILETIME *)op) = ft; op += 8; /* last change time */
2729 extAttributes = smb_ExtAttributes(scp);
2730 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
2731 *((u_long *)op) = 0; op += 4; /* don't know what this is */
2733 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2734 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2735 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2736 *((u_long *)op) = scp->linkCount; op += 4;
2739 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2742 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2743 memset(op, 0, 4); op += 4; /* EA size */
2746 /* now, if we are being asked about extended attrs, return a 0 size */
2747 if (infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2748 *((u_long *)op) = 0; op += 4;
2752 /* send and free the packets */
2754 lock_ReleaseMutex(&scp->mx);
2755 cm_ReleaseSCache(scp);
2756 cm_ReleaseUser(userp);
2758 smb_SendTran2Packet(vcp, outp, opx);
2760 smb_SendTran2Error(vcp, p, opx, code);
2761 smb_FreeTran2Packet(outp);
2766 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2768 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2769 return CM_ERROR_BADOP;
2772 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2774 smb_tran2Packet_t *outp;
2776 unsigned long attributes;
2777 unsigned short infoLevel;
2790 fidp = smb_FindFID(vcp, fid, 0);
2793 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2797 infoLevel = p->parmsp[1];
2798 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2799 nbytesRequired = 40;
2800 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2801 nbytesRequired = 24;
2802 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2804 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2807 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2808 p->opcode, infoLevel);
2809 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2810 smb_ReleaseFID(fidp);
2813 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2815 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2817 if (infoLevel > 0x100)
2818 outp->totalParms = 2;
2820 outp->totalParms = 0;
2821 outp->totalData = nbytesRequired;
2823 userp = smb_GetTran2User(vcp, p);
2825 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2826 code = CM_ERROR_BADSMB;
2831 lock_ObtainMutex(&scp->mx);
2832 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2833 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2837 /* now we have the status in the cache entry, and everything is locked.
2838 * Marshall the output data.
2841 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2842 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2843 *((FILETIME *)op) = ft; op += 8; /* creation time */
2844 *((FILETIME *)op) = ft; op += 8; /* last access time */
2845 *((FILETIME *)op) = ft; op += 8; /* last write time */
2846 *((FILETIME *)op) = ft; op += 8; /* last change time */
2847 attributes = smb_ExtAttributes(scp);
2848 *((u_long *)op) = attributes; op += 4;
2849 *((u_long *)op) = 0; op += 4;
2851 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2852 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2853 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2854 *((u_long *)op) = scp->linkCount; op += 4;
2855 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
2856 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2860 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2861 *((u_long *)op) = 0; op += 4;
2863 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2867 if (fidp->NTopen_wholepathp)
2868 name = fidp->NTopen_wholepathp;
2870 name = "\\"; /* probably can't happen */
2872 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
2873 *((u_long *)op) = len * 2; op += 4;
2874 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2877 /* send and free the packets */
2879 lock_ReleaseMutex(&scp->mx);
2880 cm_ReleaseUser(userp);
2881 smb_ReleaseFID(fidp);
2883 smb_SendTran2Packet(vcp, outp, opx);
2885 smb_SendTran2Error(vcp, p, opx, code);
2886 smb_FreeTran2Packet(outp);
2891 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2896 unsigned short infoLevel;
2897 smb_tran2Packet_t *outp;
2905 fidp = smb_FindFID(vcp, fid, 0);
2908 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
2912 infoLevel = p->parmsp[1];
2913 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type=[%x] fid=[%x]", infoLevel, fid);
2914 if (infoLevel > 0x104 || infoLevel < 0x101) {
2915 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2916 p->opcode, infoLevel);
2917 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
2918 smb_ReleaseFID(fidp);
2922 if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) {
2923 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2924 smb_ReleaseFID(fidp);
2927 if ((infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO)
2928 && !(fidp->flags & SMB_FID_OPENWRITE)) {
2929 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2930 smb_ReleaseFID(fidp);
2934 osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
2936 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
2938 outp->totalParms = 2;
2939 outp->totalData = 0;
2941 userp = smb_GetTran2User(vcp, p);
2943 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
2944 code = CM_ERROR_BADSMB;
2950 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2952 unsigned int attribute;
2955 /* lock the vnode with a callback; we need the current status
2956 * to determine what the new status is, in some cases.
2958 lock_ObtainMutex(&scp->mx);
2959 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2960 CM_SCACHESYNC_GETSTATUS
2961 | CM_SCACHESYNC_NEEDCALLBACK);
2963 lock_ReleaseMutex(&scp->mx);
2967 /* prepare for setattr call */
2970 lastMod = *((FILETIME *)(p->datap + 16));
2971 /* when called as result of move a b, lastMod is (-1, -1).
2972 * If the check for -1 is not present, timestamp
2973 * of the resulting file will be 1969 (-1)
2975 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
2976 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
2977 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
2978 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
2980 fidp->flags |= SMB_FID_MTIMESETDONE;
2983 attribute = *((u_long *)(p->datap + 32));
2984 if (attribute != 0) {
2985 if ((scp->unixModeBits & 0222)
2986 && (attribute & 1) != 0) {
2987 /* make a writable file read-only */
2988 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2989 attr.unixModeBits = scp->unixModeBits & ~0222;
2991 else if ((scp->unixModeBits & 0222) == 0
2992 && (attribute & 1) == 0) {
2993 /* make a read-only file writable */
2994 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2995 attr.unixModeBits = scp->unixModeBits | 0222;
2998 lock_ReleaseMutex(&scp->mx);
3002 code = cm_SetAttr(scp, &attr, userp, &req);
3006 else if (infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3007 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3010 attr.mask = CM_ATTRMASK_LENGTH;
3011 attr.length.LowPart = size.LowPart;
3012 attr.length.HighPart = size.HighPart;
3013 code = cm_SetAttr(scp, &attr, userp, &req);
3015 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3016 if (*((char *)(p->datap))) {
3017 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3020 fidp->flags |= SMB_FID_DELONCLOSE;
3024 fidp->flags &= ~SMB_FID_DELONCLOSE;
3029 cm_ReleaseUser(userp);
3030 smb_ReleaseFID(fidp);
3032 smb_SendTran2Packet(vcp, outp, op);
3034 smb_SendTran2Error(vcp, p, op, code);
3035 smb_FreeTran2Packet(outp);
3041 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3043 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3044 return CM_ERROR_BADOP;
3048 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3050 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3051 return CM_ERROR_BADOP;
3055 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3057 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3058 return CM_ERROR_BADOP;
3062 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3064 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3065 return CM_ERROR_BADOP;
3069 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3071 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3072 return CM_ERROR_BADOP;
3076 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3078 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3079 return CM_ERROR_BADOP;
3083 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3085 /* This is a UNICODE only request (bit15 of Flags2) */
3086 /* The TID must be IPC$ */
3088 /* The documentation for the Flags response field is contradictory */
3090 /* Use Version 1 Referral Element Format */
3091 /* ServerType = 0; indicates the next server should be queried for the file */
3092 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3093 /* Node = UnicodeString of UNC path of the next share name */
3095 osi_Log0(smb_logp,"ReceiveTran2GetDFSReferral - NOT_SUPPORTED");
3096 return CM_ERROR_BADOP;
3100 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3102 /* This is a UNICODE only request (bit15 of Flags2) */
3104 /* There is nothing we can do about this operation. The client is going to
3105 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3106 * Unfortunately, there is really nothing we can do about it other then log it
3107 * somewhere. Even then I don't think there is anything for us to do.
3108 * So let's return an error value.
3111 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3112 return CM_ERROR_BADOP;
3116 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3117 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3122 cm_scache_t *targetScp; /* target if scp is a symlink */
3127 unsigned short attr;
3128 unsigned long lattr;
3129 smb_dirListPatch_t *patchp;
3130 smb_dirListPatch_t *npatchp;
3132 for(patchp = *dirPatchespp; patchp; patchp =
3133 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3134 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3136 lock_ObtainMutex(&scp->mx);
3137 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3138 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3140 lock_ReleaseMutex(&scp->mx);
3141 cm_ReleaseSCache(scp);
3143 dptr = patchp->dptr;
3145 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3146 errors in the client. */
3147 if (infoLevel >= 0x101) {
3148 /* 1969-12-31 23:59:59 +00 */
3149 ft.dwHighDateTime = 0x19DB200;
3150 ft.dwLowDateTime = 0x5BB78980;
3152 /* copy to Creation Time */
3153 *((FILETIME *)dptr) = ft;
3156 /* copy to Last Access Time */
3157 *((FILETIME *)dptr) = ft;
3160 /* copy to Last Write Time */
3161 *((FILETIME *)dptr) = ft;
3164 /* copy to Change Time */
3165 *((FILETIME *)dptr) = ft;
3168 /* merge in hidden attribute */
3169 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3170 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3174 /* 1969-12-31 23:59:58 +00*/
3175 dosTime = 0xEBBFBF7D;
3177 /* and copy out date */
3178 shortTemp = (dosTime>>16) & 0xffff;
3179 *((u_short *)dptr) = shortTemp;
3182 /* copy out creation time */
3183 shortTemp = dosTime & 0xffff;
3184 *((u_short *)dptr) = shortTemp;
3187 /* and copy out date */
3188 shortTemp = (dosTime>>16) & 0xffff;
3189 *((u_short *)dptr) = shortTemp;
3192 /* copy out access time */
3193 shortTemp = dosTime & 0xffff;
3194 *((u_short *)dptr) = shortTemp;
3197 /* and copy out date */
3198 shortTemp = (dosTime>>16) & 0xffff;
3199 *((u_short *)dptr) = shortTemp;
3202 /* copy out mod time */
3203 shortTemp = dosTime & 0xffff;
3204 *((u_short *)dptr) = shortTemp;
3207 /* merge in hidden (dot file) attribute */
3208 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3209 attr = SMB_ATTR_HIDDEN;
3210 *dptr++ = attr & 0xff;
3211 *dptr++ = (attr >> 8) & 0xff;
3217 /* now watch for a symlink */
3219 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3220 lock_ReleaseMutex(&scp->mx);
3221 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3223 /* we have a more accurate file to use (the
3224 * target of the symbolic link). Otherwise,
3225 * we'll just use the symlink anyway.
3227 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3229 cm_ReleaseSCache(scp);
3232 lock_ObtainMutex(&scp->mx);
3235 dptr = patchp->dptr;
3237 if (infoLevel >= 0x101) {
3239 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3241 /* copy to Creation Time */
3242 *((FILETIME *)dptr) = ft;
3245 /* copy to Last Access Time */
3246 *((FILETIME *)dptr) = ft;
3249 /* copy to Last Write Time */
3250 *((FILETIME *)dptr) = ft;
3253 /* copy to Change Time */
3254 *((FILETIME *)dptr) = ft;
3257 /* Use length for both file length and alloc length */
3258 *((LARGE_INTEGER *)dptr) = scp->length;
3260 *((LARGE_INTEGER *)dptr) = scp->length;
3263 /* Copy attributes */
3264 lattr = smb_ExtAttributes(scp);
3265 /* merge in hidden (dot file) attribute */
3266 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3267 lattr |= SMB_ATTR_HIDDEN;
3268 *((u_long *)dptr) = lattr;
3273 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3275 /* and copy out date */
3276 shortTemp = (dosTime>>16) & 0xffff;
3277 *((u_short *)dptr) = shortTemp;
3280 /* copy out creation time */
3281 shortTemp = dosTime & 0xffff;
3282 *((u_short *)dptr) = shortTemp;
3285 /* and copy out date */
3286 shortTemp = (dosTime>>16) & 0xffff;
3287 *((u_short *)dptr) = shortTemp;
3290 /* copy out access time */
3291 shortTemp = dosTime & 0xffff;
3292 *((u_short *)dptr) = shortTemp;
3295 /* and copy out date */
3296 shortTemp = (dosTime>>16) & 0xffff;
3297 *((u_short *)dptr) = shortTemp;
3300 /* copy out mod time */
3301 shortTemp = dosTime & 0xffff;
3302 *((u_short *)dptr) = shortTemp;
3305 /* copy out file length and alloc length,
3306 * using the same for both
3308 *((u_long *)dptr) = scp->length.LowPart;
3310 *((u_long *)dptr) = scp->length.LowPart;
3313 /* finally copy out attributes as short */
3314 attr = smb_Attributes(scp);
3315 /* merge in hidden (dot file) attribute */
3316 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3317 attr |= SMB_ATTR_HIDDEN;
3318 *dptr++ = attr & 0xff;
3319 *dptr++ = (attr >> 8) & 0xff;
3322 lock_ReleaseMutex(&scp->mx);
3323 cm_ReleaseSCache(scp);
3326 /* now free the patches */
3327 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3328 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3332 /* and mark the list as empty */
3333 *dirPatchespp = NULL;
3338 #ifndef USE_OLD_MATCHING
3339 // char table for case insensitive comparison
3340 char mapCaseTable[256];
3342 VOID initUpperCaseTable(VOID)
3345 for (i = 0; i < 256; ++i)
3346 mapCaseTable[i] = toupper(i);
3347 // make '"' match '.'
3348 mapCaseTable[(int)'"'] = toupper('.');
3349 // make '<' match '*'
3350 mapCaseTable[(int)'<'] = toupper('*');
3351 // make '>' match '?'
3352 mapCaseTable[(int)'>'] = toupper('?');
3355 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3357 // Note : this procedure works recursively calling itself.
3359 // PSZ pattern : string containing metacharacters.
3360 // PSZ name : file name to be compared with 'pattern'.
3362 // BOOL : TRUE/FALSE (match/mistmatch)
3365 szWildCardMatchFileName(PSZ pattern, PSZ name)
3367 PSZ pename; // points to the last 'name' character
3369 pename = name + strlen(name) - 1;
3379 if (*pattern == '\0')
3381 for (p = pename; p >= name; --p) {
3382 if ((mapCaseTable[*p] == mapCaseTable[*pattern]) &&
3383 szWildCardMatchFileName(pattern + 1, p + 1))
3388 if (mapCaseTable[*name] != mapCaseTable[*pattern])
3395 if (*pattern == '\0' || *pattern == '*' && *(pattern+1) == '\0')
3401 /* do a case-folding search of the star name mask with the name in namep.
3402 * Return 1 if we match, otherwise 0.
3404 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3407 int i, j, star, qmark, retval;
3409 /* make sure we only match 8.3 names, if requested */
3410 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3413 /* optimize the pattern:
3414 * if there is a mixture of '?' and '*',
3415 * for example the sequence "*?*?*?*"
3416 * must be turned into the form "*"
3418 newmask = (char *)malloc(strlen(maskp)+1);
3419 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3420 switch ( maskp[i] ) {
3432 } else if ( qmark ) {
3436 newmask[j++] = maskp[i];
3443 } else if ( qmark ) {
3447 newmask[j++] = '\0';
3449 retval = szWildCardMatchFileName(newmask, namep) ? 1:0;
3455 #else /* USE_OLD_MATCHING */
3456 /* do a case-folding search of the star name mask with the name in namep.
3457 * Return 1 if we match, otherwise 0.
3459 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3461 unsigned char tcp1, tcp2; /* Pattern characters */
3462 unsigned char tcn1; /* Name characters */
3463 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3464 char *starNamep, *starMaskp;
3465 static char nullCharp[] = {0};
3466 int casefold = flags & CM_FLAG_CASEFOLD;
3468 /* make sure we only match 8.3 names, if requested */
3469 req8dot3 = (flags & CM_FLAG_8DOT3);
3470 if (req8dot3 && !cm_Is8Dot3(namep))
3475 /* Next pattern character */
3478 /* Next name character */
3482 /* 0 - end of pattern */
3488 else if (tcp1 == '.' || tcp1 == '"') {
3498 * first dot in pattern;
3499 * must match dot or end of name
3504 else if (tcn1 == '.') {
3513 else if (tcp1 == '?') {
3514 if (tcn1 == 0 || tcn1 == '.')
3519 else if (tcp1 == '>') {
3520 if (tcn1 != 0 && tcn1 != '.')
3524 else if (tcp1 == '*' || tcp1 == '<') {
3528 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3529 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3544 * pattern character after '*' is not null or
3545 * period. If it is '?' or '>', we are not
3546 * going to understand it. If it is '*' or
3547 * '<', we are going to skip over it. None of
3548 * these are likely, I hope.
3550 /* skip over '*' and '<' */
3551 while (tcp2 == '*' || tcp2 == '<')
3554 /* skip over characters that don't match tcp2 */
3555 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
3556 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
3557 (!casefold && tcn1 != tcp2)))
3561 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3564 /* Remember where we are */
3574 /* tcp1 is not a wildcard */
3575 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
3576 (!casefold && tcn1 == tcp1)) {
3581 /* if trying to match a star pattern, go back */
3583 maskp = starMaskp - 2;
3584 namep = starNamep + 1;
3593 #endif /* USE_OLD_MATCHING */
3595 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3604 smb_dirListPatch_t *dirListPatchesp;
3605 smb_dirListPatch_t *curPatchp;
3608 long orbytes; /* # of bytes in this output record */
3609 long ohbytes; /* # of bytes, except file name */
3610 long onbytes; /* # of bytes in name, incl. term. null */
3611 osi_hyper_t dirLength;
3612 osi_hyper_t bufferOffset;
3613 osi_hyper_t curOffset;
3615 smb_dirSearch_t *dsp;
3619 cm_pageHeader_t *pageHeaderp;
3620 cm_user_t *userp = NULL;
3623 long nextEntryCookie;
3624 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3625 char *op; /* output data ptr */
3626 char *origOp; /* original value of op */
3627 cm_space_t *spacep; /* for pathname buffer */
3628 long maxReturnData; /* max # of return data */
3629 long maxReturnParms; /* max # of return parms */
3630 long bytesInBuffer; /* # data bytes in the output buffer */
3632 char *maskp; /* mask part of path */
3636 smb_tran2Packet_t *outp; /* response packet */
3639 char shortName[13]; /* 8.3 name if needed */
3650 if (p->opcode == 1) {
3651 /* find first; obtain basic parameters from request */
3652 attribute = p->parmsp[0];
3653 maxCount = p->parmsp[1];
3654 infoLevel = p->parmsp[3];
3655 searchFlags = p->parmsp[2];
3656 dsp = smb_NewDirSearch(1);
3657 dsp->attribute = attribute;
3658 pathp = ((char *) p->parmsp) + 12; /* points to path */
3659 if (smb_StoreAnsiFilenames)
3660 OemToChar(pathp,pathp);
3662 maskp = strrchr(pathp, '\\');
3666 maskp++; /* skip over backslash */
3667 strcpy(dsp->mask, maskp); /* and save mask */
3668 /* track if this is likely to match a lot of entries */
3669 starPattern = smb_V3IsStarMask(maskp);
3672 osi_assert(p->opcode == 2);
3673 /* find next; obtain basic parameters from request or open dir file */
3674 dsp = smb_FindDirSearch(p->parmsp[0]);
3676 return CM_ERROR_BADFD;
3677 attribute = dsp->attribute;
3678 maxCount = p->parmsp[1];
3679 infoLevel = p->parmsp[2];
3680 searchFlags = p->parmsp[5];
3682 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
3684 starPattern = 1; /* assume, since required a Find Next */
3688 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
3689 attribute, infoLevel, maxCount, searchFlags);
3691 osi_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
3692 p->opcode, nextCookie);
3694 if (infoLevel >= 0x101)
3695 searchFlags &= ~4; /* no resume keys */
3697 dirListPatchesp = NULL;
3699 maxReturnData = p->maxReturnData;
3700 if (p->opcode == 1) /* find first */
3701 maxReturnParms = 10; /* bytes */
3703 maxReturnParms = 8; /* bytes */
3705 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
3706 if (maxReturnData > 6000)
3707 maxReturnData = 6000;
3708 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
3710 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
3713 osi_Log1(smb_logp, "T2 receive search dir %s",
3714 osi_LogSaveString(smb_logp, pathp));
3716 /* bail out if request looks bad */
3717 if (p->opcode == 1 && !pathp) {
3718 smb_ReleaseDirSearch(dsp);
3719 smb_FreeTran2Packet(outp);
3720 return CM_ERROR_BADSMB;
3723 osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
3724 nextCookie, dsp->cookie);
3726 userp = smb_GetTran2User(vcp, p);
3728 osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p->uid);
3729 smb_ReleaseDirSearch(dsp);
3730 smb_FreeTran2Packet(outp);
3731 return CM_ERROR_BADSMB;
3734 /* try to get the vnode for the path name next */
3735 lock_ObtainMutex(&dsp->mx);
3742 spacep = cm_GetSpace();
3743 smb_StripLastComponent(spacep->data, NULL, pathp);
3744 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3746 cm_ReleaseUser(userp);
3747 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
3748 smb_FreeTran2Packet(outp);
3749 lock_ReleaseMutex(&dsp->mx);
3750 smb_DeleteDirSearch(dsp);
3751 smb_ReleaseDirSearch(dsp);
3754 code = cm_NameI(cm_rootSCachep, spacep->data,
3755 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3756 userp, tidPathp, &req, &scp);
3757 cm_FreeSpace(spacep);
3761 cm_ReleaseSCache(dsp->scp);
3763 /* we need one hold for the entry we just stored into,
3764 * and one for our own processing. When we're done
3765 * with this function, we'll drop the one for our own
3766 * processing. We held it once from the namei call,
3767 * and so we do another hold now.
3770 lock_ObtainMutex(&scp->mx);
3771 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
3772 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3773 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3774 dsp->flags |= SMB_DIRSEARCH_BULKST;
3776 lock_ReleaseMutex(&scp->mx);
3779 lock_ReleaseMutex(&dsp->mx);
3781 cm_ReleaseUser(userp);
3782 smb_FreeTran2Packet(outp);
3783 smb_DeleteDirSearch(dsp);
3784 smb_ReleaseDirSearch(dsp);
3788 /* get the directory size */
3789 lock_ObtainMutex(&scp->mx);
3790 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3791 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3793 lock_ReleaseMutex(&scp->mx);
3794 cm_ReleaseSCache(scp);
3795 cm_ReleaseUser(userp);
3796 smb_FreeTran2Packet(outp);
3797 smb_DeleteDirSearch(dsp);
3798 smb_ReleaseDirSearch(dsp);
3803 dirLength = scp->length;
3805 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3806 curOffset.HighPart = 0;
3807 curOffset.LowPart = nextCookie;
3808 origOp = outp->datap;
3816 if (searchFlags & 4)
3817 /* skip over resume key */
3820 /* make sure that curOffset.LowPart doesn't point to the first
3821 * 32 bytes in the 2nd through last dir page, and that it doesn't
3822 * point at the first 13 32-byte chunks in the first dir page,
3823 * since those are dir and page headers, and don't contain useful
3826 temp = curOffset.LowPart & (2048-1);
3827 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3828 /* we're in the first page */
3829 if (temp < 13*32) temp = 13*32;
3832 /* we're in a later dir page */
3833 if (temp < 32) temp = 32;
3836 /* make sure the low order 5 bits are zero */
3839 /* now put temp bits back ito curOffset.LowPart */
3840 curOffset.LowPart &= ~(2048-1);
3841 curOffset.LowPart |= temp;
3843 /* check if we've passed the dir's EOF */
3844 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
3849 /* check if we've returned all the names that will fit in the
3850 * response packet; we check return count as well as the number
3851 * of bytes requested. We check the # of bytes after we find
3852 * the dir entry, since we'll need to check its size.
3854 if (returnedNames >= maxCount) {
3858 /* see if we can use the bufferp we have now; compute in which
3859 * page the current offset would be, and check whether that's
3860 * the offset of the buffer we have. If not, get the buffer.
3862 thyper.HighPart = curOffset.HighPart;
3863 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3864 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3867 buf_Release(bufferp);
3870 lock_ReleaseMutex(&scp->mx);
3871 lock_ObtainRead(&scp->bufCreateLock);
3872 code = buf_Get(scp, &thyper, &bufferp);
3873 lock_ReleaseRead(&scp->bufCreateLock);
3874 lock_ObtainMutex(&dsp->mx);
3876 /* now, if we're doing a star match, do bulk fetching
3877 * of all of the status info for files in the dir.
3880 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
3883 lock_ObtainMutex(&scp->mx);
3884 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3885 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
3886 /* Don't bulk stat if risking timeout */
3887 int now = GetCurrentTime();
3888 if (now - req.startTime > 5000) {
3889 scp->bulkStatProgress = thyper;
3890 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3891 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3893 cm_TryBulkStat(scp, &thyper, userp, &req);
3896 lock_ObtainMutex(&scp->mx);
3898 lock_ReleaseMutex(&dsp->mx);
3902 bufferOffset = thyper;
3904 /* now get the data in the cache */
3906 code = cm_SyncOp(scp, bufferp, userp, &req,
3908 CM_SCACHESYNC_NEEDCALLBACK
3909 | CM_SCACHESYNC_READ);
3912 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3914 /* otherwise, load the buffer and try again */
3915 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3920 buf_Release(bufferp);
3924 } /* if (wrong buffer) ... */
3926 /* now we have the buffer containing the entry we're interested
3927 * in; copy it out if it represents a non-deleted entry.
3929 entryInDir = curOffset.LowPart & (2048-1);
3930 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3932 /* page header will help tell us which entries are free. Page
3933 * header can change more often than once per buffer, since
3934 * AFS 3 dir page size may be less than (but not more than)
3935 * a buffer package buffer.
3937 /* only look intra-buffer */
3938 temp = curOffset.LowPart & (buf_bufferSize - 1);
3939 temp &= ~(2048 - 1); /* turn off intra-page bits */
3940 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3942 /* now determine which entry we're looking at in the page.
3943 * If it is free (there's a free bitmap at the start of the
3944 * dir), we should skip these 32 bytes.
3946 slotInPage = (entryInDir & 0x7e0) >> 5;
3947 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
3948 (1 << (slotInPage & 0x7)))) {
3949 /* this entry is free */
3950 numDirChunks = 1; /* only skip this guy */
3954 tp = bufferp->datap + entryInBuffer;
3955 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3957 /* while we're here, compute the next entry's location, too,
3958 * since we'll need it when writing out the cookie into the dir
3961 * XXXX Probably should do more sanity checking.
3963 numDirChunks = cm_NameEntries(dep->name, &onbytes);
3965 /* compute offset of cookie representing next entry */
3966 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3968 /* Need 8.3 name? */
3970 if (infoLevel == SMB_QUERY_FILE_NAME_INFO
3971 && dep->fid.vnode != 0
3972 && !cm_Is8Dot3(dep->name)) {
3973 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3977 /* When matching, we are using doing a case fold if we have a wildcard mask.
3978 * If we get a non-wildcard match, it's a lookup for a specific file.
3980 if (dep->fid.vnode != 0 &&
3981 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
3983 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
3985 /* Eliminate entries that don't match requested attributes */
3986 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
3987 smb_IsDotFile(dep->name))
3988 goto nextEntry; /* no hidden files */
3990 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3992 /* We have already done the cm_TryBulkStat above */
3993 fid.cell = scp->fid.cell;
3994 fid.volume = scp->fid.volume;
3995 fid.vnode = ntohl(dep->fid.vnode);
3996 fid.unique = ntohl(dep->fid.unique);
3997 fileType = cm_FindFileType(&fid);
3998 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
3999 "has filetype %d", dep->name,
4001 if (fileType == CM_SCACHETYPE_DIRECTORY)
4005 /* finally check if this name will fit */
4007 /* standard dir entry stuff */
4008 if (infoLevel < 0x101)
4009 ohbytes = 23; /* pre-NT */
4010 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
4011 ohbytes = 12; /* NT names only */
4013 ohbytes = 64; /* NT */
4015 if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
4016 ohbytes += 26; /* Short name & length */
4018 if (searchFlags & 4) {
4019 ohbytes += 4; /* if resume key required */
4023 && infoLevel != 0x101
4024 && infoLevel != 0x103)
4025 ohbytes += 4; /* EASIZE */
4027 /* add header to name & term. null */
4028 orbytes = onbytes + ohbytes + 1;
4030 /* now, we round up the record to a 4 byte alignment,
4031 * and we make sure that we have enough room here for
4032 * even the aligned version (so we don't have to worry
4033 * about an * overflow when we pad things out below).
4034 * That's the reason for the alignment arithmetic below.
4036 if (infoLevel >= 0x101)
4037 align = (4 - (orbytes & 3)) & 3;
4040 if (orbytes + bytesInBuffer + align > maxReturnData)
4043 /* this is one of the entries to use: it is not deleted
4044 * and it matches the star pattern we're looking for.
4045 * Put out the name, preceded by its length.
4047 /* First zero everything else */
4048 memset(origOp, 0, ohbytes);
4050 if (infoLevel <= 0x101)
4051 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4052 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
4053 *((u_long *)(op + 8)) = onbytes;
4055 *((u_long *)(op + 60)) = onbytes;
4056 strcpy(origOp+ohbytes, dep->name);
4057 if (smb_StoreAnsiFilenames)
4058 CharToOem(origOp+ohbytes, origOp+ohbytes);
4060 /* Short name if requested and needed */
4061 if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
4062 if (NeedShortName) {
4063 strcpy(op + 70, shortName);
4064 if (smb_StoreAnsiFilenames)
4065 CharToOem(op + 70, op + 70);
4066 *(op + 68) = shortNameEnd - shortName;
4070 /* now, adjust the # of entries copied */
4073 /* NextEntryOffset and FileIndex */
4074 if (infoLevel >= 101) {
4075 int entryOffset = orbytes + align;
4076 *((u_long *)op) = entryOffset;
4077 *((u_long *)(op+4)) = nextEntryCookie;
4080 /* now we emit the attribute. This is tricky, since
4081 * we need to really stat the file to find out what
4082 * type of entry we've got. Right now, we're copying
4083 * out data from a buffer, while holding the scp
4084 * locked, so it isn't really convenient to stat
4085 * something now. We'll put in a place holder
4086 * now, and make a second pass before returning this
4087 * to get the real attributes. So, we just skip the
4088 * data for now, and adjust it later. We allocate a
4089 * patch record to make it easy to find this point
4090 * later. The replay will happen at a time when it is
4091 * safe to unlock the directory.
4093 if (infoLevel != 0x103) {
4094 curPatchp = malloc(sizeof(*curPatchp));
4095 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4097 curPatchp->dptr = op;
4098 if (infoLevel >= 0x101)
4099 curPatchp->dptr += 8;
4101 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4102 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4105 curPatchp->flags = 0;
4107 curPatchp->fid.cell = scp->fid.cell;
4108 curPatchp->fid.volume = scp->fid.volume;
4109 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4110 curPatchp->fid.unique = ntohl(dep->fid.unique);
4113 curPatchp->dep = dep;
4116 if (searchFlags & 4)
4117 /* put out resume key */
4118 *((u_long *)origOp) = nextEntryCookie;
4120 /* Adjust byte ptr and count */
4121 origOp += orbytes; /* skip entire record */
4122 bytesInBuffer += orbytes;
4124 /* and pad the record out */
4125 while (--align >= 0) {
4129 } /* if we're including this name */
4130 else if (!NeedShortName &&
4133 dep->fid.vnode != 0 &&
4134 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4135 /* We were looking for exact matches, but here's an inexact one*/
4140 /* and adjust curOffset to be where the new cookie is */
4141 thyper.HighPart = 0;
4142 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4143 curOffset = LargeIntegerAdd(thyper, curOffset);
4144 } /* while copying data for dir listing */
4146 /* If we didn't get a star pattern, we did an exact match during the first pass.
4147 * If there were no exact matches found, we fail over to inexact matches by
4148 * marking the query as a star pattern (matches all case permutations), and
4149 * re-running the query.
4151 if (returnedNames == 0 && !starPattern && foundInexact) {
4152 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4157 /* release the mutex */
4158 lock_ReleaseMutex(&scp->mx);
4159 if (bufferp) buf_Release(bufferp);
4161 /* apply and free last set of patches; if not doing a star match, this
4162 * will be empty, but better safe (and freeing everything) than sorry.
4164 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4167 /* now put out the final parameters */
4168 if (returnedNames == 0) eos = 1;
4169 if (p->opcode == 1) {
4171 outp->parmsp[0] = (unsigned short) dsp->cookie;
4172 outp->parmsp[1] = returnedNames;
4173 outp->parmsp[2] = eos;
4174 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4175 outp->parmsp[4] = 0;
4176 /* don't need last name to continue
4177 * search, cookie is enough. Normally,
4178 * this is the offset of the file name
4179 * of the last entry returned.
4181 outp->totalParms = 10; /* in bytes */
4185 outp->parmsp[0] = returnedNames;
4186 outp->parmsp[1] = eos;
4187 outp->parmsp[2] = 0; /* EAS error */
4188 outp->parmsp[3] = 0; /* last name, as above */
4189 outp->totalParms = 8; /* in bytes */
4192 /* return # of bytes in the buffer */
4193 outp->totalData = bytesInBuffer;
4195 osi_Log2(smb_logp, "T2 search dir done, %d names, code %d",
4196 returnedNames, code);
4198 /* Return error code if unsuccessful on first request */
4199 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4200 code = CM_ERROR_NOSUCHFILE;
4202 /* if we're supposed to close the search after this request, or if
4203 * we're supposed to close the search if we're done, and we're done,
4204 * or if something went wrong, close the search.
4206 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4207 if ((searchFlags & 1) || (returnedNames == 0) ||
4208 ((searchFlags & 2) && eos) || code != 0)
4209 smb_DeleteDirSearch(dsp);
4211 smb_SendTran2Error(vcp, p, opx, code);
4213 smb_SendTran2Packet(vcp, outp, opx);
4215 smb_FreeTran2Packet(outp);
4216 smb_ReleaseDirSearch(dsp);
4217 cm_ReleaseSCache(scp);
4218 cm_ReleaseUser(userp);
4222 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4225 smb_dirSearch_t *dsp;
4227 dirHandle = smb_GetSMBParm(inp, 0);
4229 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4231 dsp = smb_FindDirSearch(dirHandle);
4234 return CM_ERROR_BADFD;
4236 /* otherwise, we have an FD to destroy */
4237 smb_DeleteDirSearch(dsp);
4238 smb_ReleaseDirSearch(dsp);
4240 /* and return results */
4241 smb_SetSMBDataLength(outp, 0);
4246 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4248 smb_SetSMBDataLength(outp, 0);
4252 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4259 cm_scache_t *dscp; /* dir we're dealing with */
4260 cm_scache_t *scp; /* file we're creating */
4262 int initialModeBits;
4272 int parmSlot; /* which parm we're dealing with */
4280 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4281 openFun = smb_GetSMBParm(inp, 8); /* open function */
4282 excl = ((openFun & 3) == 0);
4283 trunc = ((openFun & 3) == 2); /* truncate it */
4284 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4285 openAction = 0; /* tracks what we did */
4287 attributes = smb_GetSMBParm(inp, 5);
4288 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4290 /* compute initial mode bits based on read-only flag in attributes */
4291 initialModeBits = 0666;
4292 if (attributes & 1) initialModeBits &= ~0222;
4294 pathp = smb_GetSMBData(inp, NULL);
4295 if (smb_StoreAnsiFilenames)
4296 OemToChar(pathp,pathp);
4298 spacep = inp->spacep;
4299 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4301 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4302 /* special case magic file name for receiving IOCTL requests
4303 * (since IOCTL calls themselves aren't getting through).
4306 osi_Log0(smb_logp, "IOCTL Open");
4309 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4310 smb_SetupIoctlFid(fidp, spacep);
4312 /* set inp->fid so that later read calls in same msg can find fid */
4313 inp->fid = fidp->fid;
4315 /* copy out remainder of the parms */
4317 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4319 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4320 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4321 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4322 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4323 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4324 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4325 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4326 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4328 /* and the final "always present" stuff */
4329 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4330 /* next write out the "unique" ID */
4331 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4332 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4333 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4334 smb_SetSMBDataLength(outp, 0);
4336 /* and clean up fid reference */
4337 smb_ReleaseFID(fidp);
4341 #ifdef DEBUG_VERBOSE
4343 char *hexp, *asciip;
4344 asciip = (lastNamep ? lastNamep : pathp );
4345 hexp = osi_HexifyString(asciip);
4346 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4350 userp = smb_GetUser(vcp, inp);
4353 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4355 cm_ReleaseUser(userp);
4356 return CM_ERROR_NOSUCHPATH;
4358 code = cm_NameI(cm_rootSCachep, pathp,
4359 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4360 userp, tidPathp, &req, &scp);
4362 code = cm_NameI(cm_rootSCachep, spacep->data,
4363 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4364 userp, tidPathp, &req, &dscp);
4367 cm_ReleaseUser(userp);
4371 /* otherwise, scp points to the parent directory. Do a lookup,
4372 * and truncate the file if we find it, otherwise we create the
4379 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
4381 if (code && code != CM_ERROR_NOSUCHFILE) {
4382 cm_ReleaseSCache(dscp);
4383 cm_ReleaseUser(userp);
4388 /* if we get here, if code is 0, the file exists and is represented by
4389 * scp. Otherwise, we have to create it. The dir may be represented
4390 * by dscp, or we may have found the file directly. If code is non-zero,
4394 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
4397 cm_ReleaseSCache(dscp);
4398 cm_ReleaseSCache(scp);
4399 cm_ReleaseUser(userp);
4404 /* oops, file shouldn't be there */
4406 cm_ReleaseSCache(dscp);
4407 cm_ReleaseSCache(scp);
4408 cm_ReleaseUser(userp);
4409 return CM_ERROR_EXISTS;
4413 setAttr.mask = CM_ATTRMASK_LENGTH;
4414 setAttr.length.LowPart = 0;
4415 setAttr.length.HighPart = 0;
4416 code = cm_SetAttr(scp, &setAttr, userp, &req);
4417 openAction = 3; /* truncated existing file */
4419 else openAction = 1; /* found existing file */
4421 else if (!(openFun & 0x10)) {
4422 /* don't create if not found */
4423 if (dscp) cm_ReleaseSCache(dscp);
4424 cm_ReleaseUser(userp);
4425 return CM_ERROR_NOSUCHFILE;
4428 osi_assert(dscp != NULL);
4429 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
4430 osi_LogSaveString(smb_logp, lastNamep));
4431 openAction = 2; /* created file */
4432 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4433 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
4434 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4436 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4437 smb_NotifyChange(FILE_ACTION_ADDED,
4438 FILE_NOTIFY_CHANGE_FILE_NAME,
4439 dscp, lastNamep, NULL, TRUE);
4440 if (!excl && code == CM_ERROR_EXISTS) {
4441 /* not an exclusive create, and someone else tried
4442 * creating it already, then we open it anyway. We
4443 * don't bother retrying after this, since if this next
4444 * fails, that means that the file was deleted after we
4445 * started this call.
4447 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4451 setAttr.mask = CM_ATTRMASK_LENGTH;
4452 setAttr.length.LowPart = 0;
4453 setAttr.length.HighPart = 0;
4454 code = cm_SetAttr(scp, &setAttr, userp, &req);
4456 } /* lookup succeeded */
4460 /* we don't need this any longer */
4461 if (dscp) cm_ReleaseSCache(dscp);
4464 /* something went wrong creating or truncating the file */
4465 if (scp) cm_ReleaseSCache(scp);
4466 cm_ReleaseUser(userp);
4470 /* make sure we're about to open a file */
4471 if (scp->fileType != CM_SCACHETYPE_FILE) {
4472 cm_ReleaseSCache(scp);
4473 cm_ReleaseUser(userp);
4474 return CM_ERROR_ISDIR;
4477 /* now all we have to do is open the file itself */
4478 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4481 /* save a pointer to the vnode */
4484 /* compute open mode */
4485 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
4486 if (openMode == 1 || openMode == 2)
4487 fidp->flags |= SMB_FID_OPENWRITE;
4489 smb_ReleaseFID(fidp);
4491 cm_Open(scp, 0, userp);
4493 /* set inp->fid so that later read calls in same msg can find fid */
4494 inp->fid = fidp->fid;
4496 /* copy out remainder of the parms */
4498 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4499 lock_ObtainMutex(&scp->mx);
4501 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
4502 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4503 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
4504 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
4505 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
4506 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
4507 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4508 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4509 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4511 /* and the final "always present" stuff */
4512 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
4513 /* next write out the "unique" ID */
4514 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
4515 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
4516 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4517 lock_ReleaseMutex(&scp->mx);
4518 smb_SetSMBDataLength(outp, 0);
4520 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
4522 cm_ReleaseUser(userp);
4523 /* leave scp held since we put it in fidp->scp */
4527 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4534 unsigned char LockType;
4535 unsigned short NumberOfUnlocks, NumberOfLocks;
4536 unsigned long Timeout;
4538 LARGE_INTEGER LOffset, LLength;
4539 smb_waitingLock_t *waitingLock;
4546 fid = smb_GetSMBParm(inp, 2);
4547 fid = smb_ChainFID(fid, inp);
4549 fidp = smb_FindFID(vcp, fid, 0);
4550 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4551 return CM_ERROR_BADFD;
4553 /* set inp->fid so that later read calls in same msg can find fid */
4556 userp = smb_GetUser(vcp, inp);
4560 lock_ObtainMutex(&scp->mx);
4561 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4562 CM_SCACHESYNC_NEEDCALLBACK
4563 | CM_SCACHESYNC_GETSTATUS
4564 | CM_SCACHESYNC_LOCK);
4568 LockType = smb_GetSMBParm(inp, 3) & 0xff;
4569 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
4570 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
4571 NumberOfLocks = smb_GetSMBParm(inp, 7);
4573 op = smb_GetSMBData(inp, NULL);
4575 for (i=0; i<NumberOfUnlocks; i++) {
4576 if (LockType & 0x10) {
4578 LOffset.HighPart = *((LONG *)(op + 4));
4579 LOffset.LowPart = *((DWORD *)(op + 8));
4580 LLength.HighPart = *((LONG *)(op + 12));
4581 LLength.LowPart = *((DWORD *)(op + 16));
4585 /* Not Large Files */
4586 LOffset.HighPart = 0;
4587 LOffset.LowPart = *((DWORD *)(op + 2));
4588 LLength.HighPart = 0;
4589 LLength.LowPart = *((DWORD *)(op + 6));
4592 if (LargeIntegerNotEqualToZero(LOffset))
4594 /* Do not check length -- length check done in cm_Unlock */
4596 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
4597 if (code) goto done;
4600 for (i=0; i<NumberOfLocks; i++) {
4601 if (LockType & 0x10) {
4603 LOffset.HighPart = *((LONG *)(op + 4));
4604 LOffset.LowPart = *((DWORD *)(op + 8));
4605 LLength.HighPart = *((LONG *)(op + 12));
4606 LLength.LowPart = *((DWORD *)(op + 16));
4610 /* Not Large Files */
4611 LOffset.HighPart = 0;
4612 LOffset.LowPart = *((DWORD *)(op + 2));
4613 LLength.HighPart = 0;
4614 LLength.LowPart = *((DWORD *)(op + 6));
4617 if (LargeIntegerNotEqualToZero(LOffset))
4619 if (LargeIntegerLessThan(LOffset, scp->length))
4622 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
4623 userp, &req, &lockp);
4624 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
4625 /* Put on waiting list */
4626 waitingLock = malloc(sizeof(smb_waitingLock_t));
4627 waitingLock->vcp = vcp;
4629 waitingLock->inp = smb_CopyPacket(inp);
4630 waitingLock->outp = smb_CopyPacket(outp);
4631 waitingLock->timeRemaining = Timeout;
4632 waitingLock->lockp = lockp;
4633 lock_ObtainWrite(&smb_globalLock);
4634 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
4636 osi_Wakeup((long) &smb_allWaitingLocks);
4637 lock_ReleaseWrite(&smb_globalLock);
4638 /* don't send reply immediately */
4639 outp->flags |= SMB_PACKETFLAG_NOSEND;
4646 /* release any locks acquired before the failure */
4649 smb_SetSMBDataLength(outp, 0);
4651 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
4653 lock_ReleaseMutex(&scp->mx);
4654 cm_ReleaseUser(userp);
4655 smb_ReleaseFID(fidp);
4660 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4672 fid = smb_GetSMBParm(inp, 0);
4673 fid = smb_ChainFID(fid, inp);
4675 fidp = smb_FindFID(vcp, fid, 0);
4676 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4677 return CM_ERROR_BADFD;
4680 userp = smb_GetUser(vcp, inp);
4684 /* otherwise, stat the file */
4685 lock_ObtainMutex(&scp->mx);
4686 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4687 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4688 if (code) goto done;
4690 /* decode times. We need a search time, but the response to this
4691 * call provides the date first, not the time, as returned in the
4692 * searchTime variable. So we take the high-order bits first.
4694 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
4695 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
4696 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
4697 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
4698 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
4699 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
4700 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
4702 /* now handle file size and allocation size */
4703 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
4704 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
4705 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
4706 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
4708 /* file attribute */
4709 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
4711 /* and finalize stuff */
4712 smb_SetSMBDataLength(outp, 0);
4716 lock_ReleaseMutex(&scp->mx);
4717 cm_ReleaseUser(userp);
4718 smb_ReleaseFID(fidp);
4722 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4736 fid = smb_GetSMBParm(inp, 0);
4737 fid = smb_ChainFID(fid, inp);
4739 fidp = smb_FindFID(vcp, fid, 0);
4740 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4741 return CM_ERROR_BADFD;
4744 userp = smb_GetUser(vcp, inp);
4748 /* now prepare to call cm_setattr. This message only sets various times,
4749 * and AFS only implements mtime, and we'll set the mtime if that's
4750 * requested. The others we'll ignore.
4752 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
4754 if (searchTime != 0) {
4755 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
4757 if ( unixTime != -1 ) {
4758 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
4759 attrs.clientModTime = unixTime;
4760 code = cm_SetAttr(scp, &attrs, userp, &req);
4762 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
4764 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
4769 cm_ReleaseUser(userp);
4770 smb_ReleaseFID(fidp);
4775 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4778 long count, finalCount;
4785 fd = smb_GetSMBParm(inp, 2);
4786 count = smb_GetSMBParm(inp, 5);
4787 offset.HighPart = 0; /* too bad */
4788 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
4790 osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
4791 fd, offset.LowPart, count);
4793 fd = smb_ChainFID(fd, inp);
4794 fidp = smb_FindFID(vcp, fd, 0);
4796 return CM_ERROR_BADFD;
4798 /* set inp->fid so that later read calls in same msg can find fid */
4801 if (fidp->flags & SMB_FID_IOCTL) {
4802 return smb_IoctlV3Read(fidp, vcp, inp, outp);
4805 userp = smb_GetUser(vcp, inp);
4807 /* 0 and 1 are reserved for request chaining, were setup by our caller,
4808 * and will be further filled in after we return.
4810 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
4811 smb_SetSMBParm(outp, 3, 0); /* resvd */
4812 smb_SetSMBParm(outp, 4, 0); /* resvd */
4813 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
4814 /* fill in #6 when we have all the parameters' space reserved */
4815 smb_SetSMBParm(outp, 7, 0); /* resv'd */
4816 smb_SetSMBParm(outp, 8, 0); /* resv'd */
4817 smb_SetSMBParm(outp, 9, 0); /* resv'd */
4818 smb_SetSMBParm(outp, 10, 0); /* resv'd */
4819 smb_SetSMBParm(outp, 11, 0); /* reserved */
4821 /* get op ptr after putting in the parms, since otherwise we don't
4822 * know where the data really is.
4824 op = smb_GetSMBData(outp, NULL);
4826 /* now fill in offset from start of SMB header to first data byte (to op) */
4827 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
4829 /* set the packet data length the count of the # of bytes */
4830 smb_SetSMBDataLength(outp, count);
4833 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
4835 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
4838 /* fix some things up */
4839 smb_SetSMBParm(outp, 5, finalCount);
4840 smb_SetSMBDataLength(outp, finalCount);
4842 smb_ReleaseFID(fidp);
4844 cm_ReleaseUser(userp);
4849 * Values for createDisp, copied from NTDDK.H
4851 #define FILE_SUPERSEDE 0 // (???)
4852 #define FILE_OPEN 1 // (open)
4853 #define FILE_CREATE 2 // (exclusive)
4854 #define FILE_OPEN_IF 3 // (non-exclusive)
4855 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
4856 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
4858 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4860 char *pathp, *realPathp;
4864 cm_scache_t *dscp; /* parent dir */
4865 cm_scache_t *scp; /* file to create or open */
4866 cm_scache_t *targetScp; /* if scp is a symlink */
4870 unsigned short nameLength;
4872 unsigned int requestOpLock;
4873 unsigned int requestBatchOpLock;
4874 unsigned int mustBeDir;
4875 unsigned int treeCreate;
4877 unsigned int desiredAccess;
4878 unsigned int extAttributes;
4879 unsigned int createDisp;
4880 unsigned int createOptions;
4881 int initialModeBits;
4882 unsigned short baseFid;
4883 smb_fid_t *baseFidp;
4885 cm_scache_t *baseDirp;
4886 unsigned short openAction;
4897 /* This code is very long and has a lot of if-then-else clauses
4898 * scp and dscp get reused frequently and we need to ensure that
4899 * we don't lose a reference. Start by ensuring that they are NULL.
4906 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
4907 flags = smb_GetSMBOffsetParm(inp, 3, 1)
4908 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
4909 requestOpLock = flags & 0x02;
4910 requestBatchOpLock = flags & 0x04;
4911 mustBeDir = flags & 0x08;
4914 * Why all of a sudden 32-bit FID?
4915 * We will reject all bits higher than 16.
4917 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
4918 return CM_ERROR_INVAL;
4919 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
4920 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
4921 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
4922 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
4923 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
4924 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
4925 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
4926 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
4927 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
4929 /* mustBeDir is never set; createOptions directory bit seems to be
4932 if (createOptions & 1)
4934 else if (createOptions & 0x40)
4940 * compute initial mode bits based on read-only flag in
4941 * extended attributes
4943 initialModeBits = 0666;
4944 if (extAttributes & 1)
4945 initialModeBits &= ~0222;
4947 pathp = smb_GetSMBData(inp, NULL);
4948 /* Sometimes path is not null-terminated, so we make a copy. */
4949 realPathp = malloc(nameLength+1);
4950 memcpy(realPathp, pathp, nameLength);
4951 realPathp[nameLength] = 0;
4952 if (smb_StoreAnsiFilenames)
4953 OemToChar(realPathp,realPathp);
4955 spacep = inp->spacep;
4956 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
4958 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
4959 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
4960 osi_Log2(smb_logp,"... flags=[%x] lastNamep=[%s]", flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
4962 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4963 /* special case magic file name for receiving IOCTL requests
4964 * (since IOCTL calls themselves aren't getting through).
4966 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4967 smb_SetupIoctlFid(fidp, spacep);
4968 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
4970 /* set inp->fid so that later read calls in same msg can find fid */
4971 inp->fid = fidp->fid;
4975 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
4976 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4977 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
4979 memset(&ft, 0, sizeof(ft));
4980 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4981 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4982 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4983 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4984 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
4985 sz.HighPart = 0x7fff; sz.LowPart = 0;
4986 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
4987 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
4988 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
4989 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
4990 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
4991 smb_SetSMBDataLength(outp, 0);
4993 /* clean up fid reference */
4994 smb_ReleaseFID(fidp);
4999 #ifdef DEBUG_VERBOSE
5001 char *hexp, *asciip;
5002 asciip = (lastNamep? lastNamep : realPathp);
5003 hexp = osi_HexifyString( asciip );
5004 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
5008 userp = smb_GetUser(vcp, inp);
5010 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
5012 return CM_ERROR_INVAL;
5016 baseDirp = cm_rootSCachep;
5017 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5018 if (code == CM_ERROR_TIDIPC) {
5019 /* Attempt to use a TID allocated for IPC. The client
5020 * is probably looking for DCE RPC end points which we
5022 osi_Log0(smb_logp, "NTCreateX received IPC TID");
5024 cm_ReleaseUser(userp);
5025 return CM_ERROR_NOSUCHFILE;
5029 baseFidp = smb_FindFID(vcp, baseFid, 0);
5031 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
5033 cm_ReleaseUser(userp);
5034 return CM_ERROR_INVAL;
5036 baseDirp = baseFidp->scp;
5040 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
5042 /* compute open mode */
5044 if (desiredAccess & DELETE)
5045 fidflags |= SMB_FID_OPENDELETE;
5046 if (desiredAccess & AFS_ACCESS_READ)
5047 fidflags |= SMB_FID_OPENREAD;
5048 if (desiredAccess & AFS_ACCESS_WRITE)
5049 fidflags |= SMB_FID_OPENWRITE;
5053 /* For an exclusive create, we want to do a case sensitive match for the last component. */
5054 if ( createDisp == FILE_CREATE ||
5055 createDisp == FILE_OVERWRITE ||
5056 createDisp == FILE_OVERWRITE_IF) {
5057 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5058 userp, tidPathp, &req, &dscp);
5060 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5062 if (code == CM_ERROR_NOSUCHFILE) {
5063 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
5064 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
5065 if (code == 0 && realDirFlag == 1) {
5066 cm_ReleaseSCache(scp);
5067 cm_ReleaseSCache(dscp);
5068 cm_ReleaseUser(userp);
5070 return CM_ERROR_EXISTS;
5074 /* we have both scp and dscp */
5076 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5077 userp, tidPathp, &req, &scp);
5078 /* we might have scp but not dscp */
5084 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
5085 /* look up parent directory */
5086 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
5087 * the immediate parent. We have to work our way up realPathp until we hit something that we
5091 /* we might or might not have scp */
5097 code = cm_NameI(baseDirp, spacep->data,
5098 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5099 userp, tidPathp, &req, &dscp);
5102 (tp = strrchr(spacep->data,'\\')) &&
5103 (createDisp == FILE_CREATE) &&
5104 (realDirFlag == 1)) {
5107 treeStartp = realPathp + (tp - spacep->data);
5109 if (*tp && !smb_IsLegalFilename(tp)) {
5111 smb_ReleaseFID(baseFidp);
5112 cm_ReleaseUser(userp);
5115 cm_ReleaseSCache(scp);
5116 return CM_ERROR_BADNTFILENAME;
5120 } while (dscp == NULL && code == 0);
5124 /* we might have scp and we might have dscp */
5127 smb_ReleaseFID(baseFidp);
5130 osi_Log0(smb_logp,"NTCreateX parent not found");
5132 cm_ReleaseSCache(scp);
5134 cm_ReleaseSCache(dscp);
5135 cm_ReleaseUser(userp);
5140 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
5141 /* A file exists where we want a directory. */
5143 cm_ReleaseSCache(scp);
5144 cm_ReleaseSCache(dscp);
5145 cm_ReleaseUser(userp);
5147 return CM_ERROR_EXISTS;
5151 lastNamep = realPathp;
5155 if (!smb_IsLegalFilename(lastNamep)) {
5157 cm_ReleaseSCache(scp);
5159 cm_ReleaseSCache(dscp);
5160 cm_ReleaseUser(userp);
5162 return CM_ERROR_BADNTFILENAME;
5165 if (!foundscp && !treeCreate) {
5166 if ( createDisp == FILE_CREATE ||
5167 createDisp == FILE_OVERWRITE ||
5168 createDisp == FILE_OVERWRITE_IF)
5170 code = cm_Lookup(dscp, lastNamep,
5171 CM_FLAG_FOLLOW, userp, &req, &scp);
5173 code = cm_Lookup(dscp, lastNamep,
5174 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5177 if (code && code != CM_ERROR_NOSUCHFILE) {
5178 cm_ReleaseSCache(dscp);
5179 cm_ReleaseUser(userp);
5184 /* we have scp and dscp */
5186 /* we have scp but not dscp */
5188 smb_ReleaseFID(baseFidp);
5191 /* if we get here, if code is 0, the file exists and is represented by
5192 * scp. Otherwise, we have to create it. The dir may be represented
5193 * by dscp, or we may have found the file directly. If code is non-zero,
5196 if (code == 0 && !treeCreate) {
5197 if (createDisp == FILE_CREATE) {
5198 /* oops, file shouldn't be there */
5200 cm_ReleaseSCache(dscp);
5201 cm_ReleaseSCache(scp);
5202 cm_ReleaseUser(userp);
5204 return CM_ERROR_EXISTS;
5207 if ( createDisp == FILE_OVERWRITE ||
5208 createDisp == FILE_OVERWRITE_IF) {
5209 setAttr.mask = CM_ATTRMASK_LENGTH;
5210 setAttr.length.LowPart = 0;
5211 setAttr.length.HighPart = 0;
5212 /* now watch for a symlink */
5214 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5216 osi_assert(dscp != NULL);
5217 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5219 /* we have a more accurate file to use (the
5220 * target of the symbolic link). Otherwise,
5221 * we'll just use the symlink anyway.
5223 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5225 cm_ReleaseSCache(scp);
5229 code = cm_SetAttr(scp, &setAttr, userp, &req);
5230 openAction = 3; /* truncated existing file */
5233 openAction = 1; /* found existing file */
5235 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req);
5238 cm_ReleaseSCache(dscp);
5239 cm_ReleaseSCache(scp);
5240 cm_ReleaseUser(userp);
5244 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
5245 /* don't create if not found */
5247 cm_ReleaseSCache(dscp);
5249 cm_ReleaseSCache(scp);
5250 cm_ReleaseUser(userp);
5252 return CM_ERROR_NOSUCHFILE;
5253 } else if (realDirFlag == 0 || realDirFlag == -1) {
5254 osi_assert(dscp != NULL);
5255 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
5256 osi_LogSaveString(smb_logp, lastNamep));
5257 openAction = 2; /* created file */
5258 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5259 setAttr.clientModTime = time(NULL);
5260 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
5261 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5262 smb_NotifyChange(FILE_ACTION_ADDED,
5263 FILE_NOTIFY_CHANGE_FILE_NAME,
5264 dscp, lastNamep, NULL, TRUE);
5265 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
5266 /* Not an exclusive create, and someone else tried
5267 * creating it already, then we open it anyway. We
5268 * don't bother retrying after this, since if this next
5269 * fails, that means that the file was deleted after we
5270 * started this call.
5272 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5275 if (createDisp == FILE_OVERWRITE_IF) {
5276 setAttr.mask = CM_ATTRMASK_LENGTH;
5277 setAttr.length.LowPart = 0;
5278 setAttr.length.HighPart = 0;
5280 /* now watch for a symlink */
5282 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5284 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5286 /* we have a more accurate file to use (the
5287 * target of the symbolic link). Otherwise,
5288 * we'll just use the symlink anyway.
5290 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5292 cm_ReleaseSCache(scp);
5296 code = cm_SetAttr(scp, &setAttr, userp, &req);
5298 } /* lookup succeeded */
5302 char *cp; /* This component */
5303 int clen = 0; /* length of component */
5304 cm_scache_t *tscp1, *tscp2;
5307 /* create directory */
5309 treeStartp = lastNamep;
5310 osi_assert(dscp != NULL);
5311 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
5312 osi_LogSaveString(smb_logp, treeStartp));
5313 openAction = 2; /* created directory */
5315 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5316 setAttr.clientModTime = time(NULL);
5321 cm_HoldSCache(tscp1);
5325 tp = strchr(pp, '\\');
5329 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
5332 strncpy(cp,pp,clen);
5339 continue; /* the supplied path can't have consecutive slashes either , but */
5341 /* cp is the next component to be created. */
5342 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
5343 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
5344 smb_NotifyChange(FILE_ACTION_ADDED,
5345 FILE_NOTIFY_CHANGE_DIR_NAME,
5346 tscp1, cp, NULL, TRUE);
5348 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
5349 /* Not an exclusive create, and someone else tried
5350 * creating it already, then we open it anyway. We
5351 * don't bother retrying after this, since if this next
5352 * fails, that means that the file was deleted after we
5353 * started this call.
5355 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
5356 userp, &req, &tscp2);
5361 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
5362 cm_ReleaseSCache(tscp1);
5363 tscp1 = tscp2; /* Newly created directory will be next parent */
5364 /* the hold is transfered to tscp1 from tscp2 */
5368 cm_ReleaseSCache(dscp);
5370 cm_ReleaseSCache(scp);
5373 * if we get here and code == 0, then scp is the last directory created, and dscp is the
5379 /* something went wrong creating or truncating the file */
5381 cm_ReleaseSCache(scp);
5383 cm_ReleaseSCache(dscp);
5384 cm_ReleaseUser(userp);
5389 /* make sure we have file vs. dir right (only applies for single component case) */
5390 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5391 /* now watch for a symlink */
5393 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5394 cm_scache_t * targetScp = 0;
5395 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5397 /* we have a more accurate file to use (the
5398 * target of the symbolic link). Otherwise,
5399 * we'll just use the symlink anyway.
5401 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
5402 cm_ReleaseSCache(scp);
5407 if (scp->fileType != CM_SCACHETYPE_FILE) {
5409 cm_ReleaseSCache(dscp);
5410 cm_ReleaseSCache(scp);
5411 cm_ReleaseUser(userp);
5413 return CM_ERROR_ISDIR;
5417 /* (only applies to single component case) */
5418 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5419 cm_ReleaseSCache(scp);
5420 cm_ReleaseSCache(dscp);
5421 cm_ReleaseUser(userp);
5423 return CM_ERROR_NOTDIR;
5426 /* open the file itself */
5427 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5429 /* save a pointer to the vnode */
5430 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
5432 fidp->flags = fidflags;
5434 /* save parent dir and pathname for delete or change notification */
5435 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5436 fidp->flags |= SMB_FID_NTOPEN;
5437 fidp->NTopen_dscp = dscp;
5438 cm_HoldSCache(dscp);
5439 fidp->NTopen_pathp = strdup(lastNamep);
5441 fidp->NTopen_wholepathp = realPathp;
5443 /* we don't need this any longer */
5445 cm_ReleaseSCache(dscp);
5448 cm_Open(scp, 0, userp);
5450 /* set inp->fid so that later read calls in same msg can find fid */
5451 inp->fid = fidp->fid;
5455 lock_ObtainMutex(&scp->mx);
5456 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5457 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5458 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
5459 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5460 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5461 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5462 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5463 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5464 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
5466 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5467 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5468 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
5469 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
5470 smb_SetSMBParmByte(outp, parmSlot,
5471 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
5472 lock_ReleaseMutex(&scp->mx);
5473 smb_SetSMBDataLength(outp, 0);
5475 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
5476 osi_LogSaveString(smb_logp, realPathp));
5478 smb_ReleaseFID(fidp);
5480 cm_ReleaseUser(userp);
5482 /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
5484 /* leave scp held since we put it in fidp->scp */
5490 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
5491 * Instead, ultimately, would like to use a subroutine for common code.
5493 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5495 char *pathp, *realPathp;
5499 cm_scache_t *dscp; /* parent dir */
5500 cm_scache_t *scp; /* file to create or open */
5501 cm_scache_t *targetScp; /* if scp is a symlink */
5504 unsigned long nameLength;
5506 unsigned int requestOpLock;
5507 unsigned int requestBatchOpLock;
5508 unsigned int mustBeDir;
5509 unsigned int extendedRespRequired;
5511 unsigned int desiredAccess;
5512 #ifdef DEBUG_VERBOSE
5513 unsigned int allocSize;
5514 unsigned int shareAccess;
5516 unsigned int extAttributes;
5517 unsigned int createDisp;
5518 #ifdef DEBUG_VERBOSE
5521 unsigned int createOptions;
5522 int initialModeBits;
5523 unsigned short baseFid;
5524 smb_fid_t *baseFidp;
5526 cm_scache_t *baseDirp;
5527 unsigned short openAction;
5533 int parmOffset, dataOffset;
5544 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
5545 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
5546 parmp = inp->data + parmOffset;
5547 lparmp = (ULONG *) parmp;
5550 requestOpLock = flags & 0x02;
5551 requestBatchOpLock = flags & 0x04;
5552 mustBeDir = flags & 0x08;
5553 extendedRespRequired = flags & 0x10;
5556 * Why all of a sudden 32-bit FID?
5557 * We will reject all bits higher than 16.
5559 if (lparmp[1] & 0xFFFF0000)
5560 return CM_ERROR_INVAL;
5561 baseFid = (unsigned short)lparmp[1];
5562 desiredAccess = lparmp[2];
5563 #ifdef DEBUG_VERBOSE
5564 allocSize = lparmp[3];
5565 #endif /* DEBUG_VERSOSE */
5566 extAttributes = lparmp[5];
5568 shareAccess = lparmp[6];
5570 createDisp = lparmp[7];
5571 createOptions = lparmp[8];
5572 #ifdef DEBUG_VERBOSE
5575 nameLength = lparmp[11];
5577 #ifdef DEBUG_VERBOSE
5578 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
5579 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
5580 osi_Log1(smb_logp,"... flags[%x]",flags);
5583 /* mustBeDir is never set; createOptions directory bit seems to be
5586 if (createOptions & 1)
5588 else if (createOptions & 0x40)
5594 * compute initial mode bits based on read-only flag in
5595 * extended attributes
5597 initialModeBits = 0666;
5598 if (extAttributes & 1)
5599 initialModeBits &= ~0222;
5601 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
5602 /* Sometimes path is not null-terminated, so we make a copy. */
5603 realPathp = malloc(nameLength+1);
5604 memcpy(realPathp, pathp, nameLength);
5605 realPathp[nameLength] = 0;
5606 if (smb_StoreAnsiFilenames)
5607 OemToChar(realPathp,realPathp);
5609 spacep = cm_GetSpace();
5610 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5613 * Nothing here to handle SMB_IOCTL_FILENAME.
5614 * Will add it if necessary.
5617 #ifdef DEBUG_VERBOSE
5619 char *hexp, *asciip;
5620 asciip = (lastNamep? lastNamep : realPathp);
5621 hexp = osi_HexifyString( asciip );
5622 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
5627 userp = smb_GetUser(vcp, inp);
5629 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
5631 return CM_ERROR_INVAL;
5635 baseDirp = cm_rootSCachep;
5636 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5637 if(code == CM_ERROR_TIDIPC) {
5638 /* Attempt to use TID allocated for IPC. The client is
5639 * probably trying to locate DCE RPC endpoints, which we
5641 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
5643 cm_ReleaseUser(userp);
5644 return CM_ERROR_NOSUCHPATH;
5648 baseFidp = smb_FindFID(vcp, baseFid, 0);
5650 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
5652 cm_ReleaseUser(userp);
5653 return CM_ERROR_INVAL;
5655 baseDirp = baseFidp->scp;
5659 /* compute open mode */
5661 if (desiredAccess & DELETE)
5662 fidflags |= SMB_FID_OPENDELETE;
5663 if (desiredAccess & AFS_ACCESS_READ)
5664 fidflags |= SMB_FID_OPENREAD;
5665 if (desiredAccess & AFS_ACCESS_WRITE)
5666 fidflags |= SMB_FID_OPENWRITE;
5670 if ( createDisp == FILE_OPEN ||
5671 createDisp == FILE_OVERWRITE ||
5672 createDisp == FILE_OVERWRITE_IF) {
5673 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5674 userp, tidPathp, &req, &dscp);
5676 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5678 if (code == CM_ERROR_NOSUCHFILE) {
5679 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
5680 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
5681 if (code == 0 && realDirFlag == 1) {
5682 cm_ReleaseSCache(scp);
5683 cm_ReleaseSCache(dscp);
5684 cm_ReleaseUser(userp);
5686 return CM_ERROR_EXISTS;
5692 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5693 userp, tidPathp, &req, &scp);
5699 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
5700 /* look up parent directory */
5702 code = cm_NameI(baseDirp, spacep->data,
5703 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5704 userp, tidPathp, &req, &dscp);
5708 cm_FreeSpace(spacep);
5711 smb_ReleaseFID(baseFidp);
5716 cm_ReleaseUser(userp);
5721 if (!lastNamep) lastNamep = realPathp;
5724 if (!smb_IsLegalFilename(lastNamep))
5725 return CM_ERROR_BADNTFILENAME;
5728 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
5729 code = cm_Lookup(dscp, lastNamep,
5730 CM_FLAG_FOLLOW, userp, &req, &scp);
5732 code = cm_Lookup(dscp, lastNamep,
5733 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5736 if (code && code != CM_ERROR_NOSUCHFILE) {
5737 cm_ReleaseSCache(dscp);
5738 cm_ReleaseUser(userp);
5746 smb_ReleaseFID(baseFidp);
5749 cm_FreeSpace(spacep);
5752 /* if we get here, if code is 0, the file exists and is represented by
5753 * scp. Otherwise, we have to create it. The dir may be represented
5754 * by dscp, or we may have found the file directly. If code is non-zero,
5758 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
5761 if (dscp) cm_ReleaseSCache(dscp);
5762 cm_ReleaseSCache(scp);
5763 cm_ReleaseUser(userp);
5768 if (createDisp == FILE_CREATE) {
5769 /* oops, file shouldn't be there */
5770 if (dscp) cm_ReleaseSCache(dscp);
5771 cm_ReleaseSCache(scp);
5772 cm_ReleaseUser(userp);
5774 return CM_ERROR_EXISTS;
5777 if (createDisp == FILE_OVERWRITE ||
5778 createDisp == FILE_OVERWRITE_IF) {
5779 setAttr.mask = CM_ATTRMASK_LENGTH;
5780 setAttr.length.LowPart = 0;
5781 setAttr.length.HighPart = 0;
5783 /* now watch for a symlink */
5785 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5787 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5789 /* we have a more accurate file to use (the
5790 * target of the symbolic link). Otherwise,
5791 * we'll just use the symlink anyway.
5793 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5795 cm_ReleaseSCache(scp);
5799 code = cm_SetAttr(scp, &setAttr, userp, &req);
5800 openAction = 3; /* truncated existing file */
5802 else openAction = 1; /* found existing file */
5804 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
5805 /* don't create if not found */
5806 if (dscp) cm_ReleaseSCache(dscp);
5807 cm_ReleaseUser(userp);
5809 return CM_ERROR_NOSUCHFILE;
5811 else if (realDirFlag == 0 || realDirFlag == -1) {
5812 osi_assert(dscp != NULL);
5813 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
5814 osi_LogSaveString(smb_logp, lastNamep));
5815 openAction = 2; /* created file */
5816 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5817 setAttr.clientModTime = time(NULL);
5818 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5820 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5821 smb_NotifyChange(FILE_ACTION_ADDED,
5822 FILE_NOTIFY_CHANGE_FILE_NAME,
5823 dscp, lastNamep, NULL, TRUE);
5824 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
5825 /* Not an exclusive create, and someone else tried
5826 * creating it already, then we open it anyway. We
5827 * don't bother retrying after this, since if this next
5828 * fails, that means that the file was deleted after we
5829 * started this call.
5831 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5834 if (createDisp == FILE_OVERWRITE_IF) {
5835 setAttr.mask = CM_ATTRMASK_LENGTH;
5836 setAttr.length.LowPart = 0;
5837 setAttr.length.HighPart = 0;
5839 /* now watch for a symlink */
5841 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5843 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5845 /* we have a more accurate file to use (the
5846 * target of the symbolic link). Otherwise,
5847 * we'll just use the symlink anyway.
5849 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5851 cm_ReleaseSCache(scp);
5855 code = cm_SetAttr(scp, &setAttr, userp, &req);
5857 } /* lookup succeeded */
5861 /* create directory */
5862 osi_assert(dscp != NULL);
5864 "smb_ReceiveNTTranCreate creating directory %s",
5865 osi_LogSaveString(smb_logp, lastNamep));
5866 openAction = 2; /* created directory */
5867 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5868 setAttr.clientModTime = time(NULL);
5869 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5870 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5871 smb_NotifyChange(FILE_ACTION_ADDED,
5872 FILE_NOTIFY_CHANGE_DIR_NAME,
5873 dscp, lastNamep, NULL, TRUE);
5875 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
5876 /* Not an exclusive create, and someone else tried
5877 * creating it already, then we open it anyway. We
5878 * don't bother retrying after this, since if this next
5879 * fails, that means that the file was deleted after we
5880 * started this call.
5882 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5888 /* something went wrong creating or truncating the file */
5889 if (scp) cm_ReleaseSCache(scp);
5890 cm_ReleaseUser(userp);
5895 /* make sure we have file vs. dir right */
5896 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5897 /* now watch for a symlink */
5899 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5901 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5903 /* we have a more accurate file to use (the
5904 * target of the symbolic link). Otherwise,
5905 * we'll just use the symlink anyway.
5907 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5909 cm_ReleaseSCache(scp);
5914 if (scp->fileType != CM_SCACHETYPE_FILE) {
5915 cm_ReleaseSCache(scp);
5916 cm_ReleaseUser(userp);
5918 return CM_ERROR_ISDIR;
5922 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5923 cm_ReleaseSCache(scp);
5924 cm_ReleaseUser(userp);
5926 return CM_ERROR_NOTDIR;
5929 /* open the file itself */
5930 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5933 /* save a pointer to the vnode */
5936 fidp->flags = fidflags;
5938 /* save parent dir and pathname for deletion or change notification */
5939 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5940 fidp->flags |= SMB_FID_NTOPEN;
5941 fidp->NTopen_dscp = dscp;
5942 cm_HoldSCache(dscp);
5943 fidp->NTopen_pathp = strdup(lastNamep);
5945 fidp->NTopen_wholepathp = realPathp;
5947 /* we don't need this any longer */
5948 if (dscp) cm_ReleaseSCache(dscp);
5950 cm_Open(scp, 0, userp);
5952 /* set inp->fid so that later read calls in same msg can find fid */
5953 inp->fid = fidp->fid;
5955 /* check whether we are required to send an extended response */
5956 if (!extendedRespRequired) {
5958 parmOffset = 8*4 + 39;
5959 parmOffset += 1; /* pad to 4 */
5960 dataOffset = parmOffset + 70;
5964 /* Total Parameter Count */
5965 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
5966 /* Total Data Count */
5967 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5968 /* Parameter Count */
5969 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
5970 /* Parameter Offset */
5971 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5972 /* Parameter Displacement */
5973 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5975 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5977 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5978 /* Data Displacement */
5979 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5980 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5981 smb_SetSMBDataLength(outp, 70);
5983 lock_ObtainMutex(&scp->mx);
5984 outData = smb_GetSMBData(outp, NULL);
5985 outData++; /* round to get to parmOffset */
5986 *outData = 0; outData++; /* oplock */
5987 *outData = 0; outData++; /* reserved */
5988 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
5989 *((ULONG *)outData) = openAction; outData += 4;
5990 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
5991 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5992 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
5993 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
5994 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
5995 *((FILETIME *)outData) = ft; outData += 8; /* change time */
5996 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
5997 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
5998 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
5999 *((USHORT *)outData) = 0; outData += 2; /* filetype */
6000 *((USHORT *)outData) = 0; outData += 2; /* dev state */
6001 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
6002 outData += 2; /* is a dir? */
6003 lock_ReleaseMutex(&scp->mx);
6006 parmOffset = 8*4 + 39;
6007 parmOffset += 1; /* pad to 4 */
6008 dataOffset = parmOffset + 104;
6012 /* Total Parameter Count */
6013 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
6014 /* Total Data Count */
6015 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6016 /* Parameter Count */
6017 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
6018 /* Parameter Offset */
6019 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6020 /* Parameter Displacement */
6021 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6023 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6025 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6026 /* Data Displacement */
6027 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6028 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6029 smb_SetSMBDataLength(outp, 105);
6031 lock_ObtainMutex(&scp->mx);
6032 outData = smb_GetSMBData(outp, NULL);
6033 outData++; /* round to get to parmOffset */
6034 *outData = 0; outData++; /* oplock */
6035 *outData = 1; outData++; /* response type */
6036 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
6037 *((ULONG *)outData) = openAction; outData += 4;
6038 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
6039 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6040 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
6041 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
6042 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
6043 *((FILETIME *)outData) = ft; outData += 8; /* change time */
6044 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
6045 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
6046 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
6047 *((USHORT *)outData) = 0; outData += 2; /* filetype */
6048 *((USHORT *)outData) = 0; outData += 2; /* dev state */
6049 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
6050 outData += 1; /* is a dir? */
6051 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
6052 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
6053 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
6054 lock_ReleaseMutex(&scp->mx);
6057 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
6059 smb_ReleaseFID(fidp);
6061 cm_ReleaseUser(userp);
6063 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
6064 /* leave scp held since we put it in fidp->scp */
6068 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
6071 smb_packet_t *savedPacketp;
6072 ULONG filter; USHORT fid, watchtree;
6076 filter = smb_GetSMBParm(inp, 19) |
6077 (smb_GetSMBParm(inp, 20) << 16);
6078 fid = smb_GetSMBParm(inp, 21);
6079 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
6081 fidp = smb_FindFID(vcp, fid, 0);
6083 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
6084 return CM_ERROR_BADFD;
6087 savedPacketp = smb_CopyPacket(inp);
6089 savedPacketp->vcp = vcp;
6090 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6091 savedPacketp->nextp = smb_Directory_Watches;
6092 smb_Directory_Watches = savedPacketp;
6093 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6095 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
6096 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
6099 lock_ObtainMutex(&scp->mx);
6101 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
6103 scp->flags |= CM_SCACHEFLAG_WATCHED;
6104 lock_ReleaseMutex(&scp->mx);
6105 smb_ReleaseFID(fidp);
6107 outp->flags |= SMB_PACKETFLAG_NOSEND;
6111 unsigned char nullSecurityDesc[36] = {
6112 0x01, /* security descriptor revision */
6113 0x00, /* reserved, should be zero */
6114 0x00, 0x80, /* security descriptor control;
6115 * 0x8000 : self-relative format */
6116 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
6117 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
6118 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
6119 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
6120 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6121 /* "null SID" owner SID */
6122 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
6123 /* "null SID" group SID */
6126 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6128 int parmOffset, parmCount, dataOffset, dataCount;
6136 ULONG securityInformation;
6138 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6139 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6140 parmp = inp->data + parmOffset;
6141 sparmp = (USHORT *) parmp;
6142 lparmp = (ULONG *) parmp;
6145 securityInformation = lparmp[1];
6147 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
6148 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6156 parmOffset = 8*4 + 39;
6157 parmOffset += 1; /* pad to 4 */
6159 dataOffset = parmOffset + parmCount;
6163 /* Total Parameter Count */
6164 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6165 /* Total Data Count */
6166 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6167 /* Parameter Count */
6168 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6169 /* Parameter Offset */
6170 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6171 /* Parameter Displacement */
6172 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6174 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6176 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6177 /* Data Displacement */
6178 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6179 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6180 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
6182 outData = smb_GetSMBData(outp, NULL);
6183 outData++; /* round to get to parmOffset */
6184 *((ULONG *)outData) = 36; outData += 4; /* length */
6186 if (maxData >= 36) {
6187 memcpy(outData, nullSecurityDesc, 36);
6191 return CM_ERROR_BUFFERTOOSMALL;
6194 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6196 unsigned short function;
6198 function = smb_GetSMBParm(inp, 18);
6200 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
6202 /* We can handle long names */
6203 if (vcp->flags & SMB_VCFLAG_USENT)
6204 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
6208 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
6210 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
6212 return smb_ReceiveNTTranCreate(vcp, inp, outp);
6214 return CM_ERROR_INVAL;
6219 * smb_NotifyChange -- find relevant change notification messages and
6222 * If we don't know the file name (i.e. a callback break), filename is
6223 * NULL, and we return a zero-length list.
6225 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
6226 cm_scache_t *dscp, char *filename, char *otherFilename,
6227 BOOL isDirectParent)
6229 smb_packet_t *watch, *lastWatch, *nextWatch;
6230 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
6231 char *outData, *oldOutData;
6235 BOOL twoEntries = FALSE;
6236 ULONG otherNameLen, oldParmCount = 0;
6241 /* Get ready for rename within directory */
6242 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
6244 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
6247 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
6248 osi_LogSaveString(smb_logp,filename),dscp);
6250 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6251 watch = smb_Directory_Watches;
6253 filter = smb_GetSMBParm(watch, 19)
6254 | (smb_GetSMBParm(watch, 20) << 16);
6255 fid = smb_GetSMBParm(watch, 21);
6256 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
6257 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
6258 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
6262 * Strange hack - bug in NT Client and NT Server that we
6265 if (filter == 3 && wtree)
6268 fidp = smb_FindFID(vcp, fid, 0);
6270 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
6272 watch = watch->nextp;
6275 if (fidp->scp != dscp
6276 || (filter & notifyFilter) == 0
6277 || (!isDirectParent && !wtree)) {
6278 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
6279 smb_ReleaseFID(fidp);
6281 watch = watch->nextp;
6284 smb_ReleaseFID(fidp);
6287 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
6288 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
6290 nextWatch = watch->nextp;
6291 if (watch == smb_Directory_Watches)
6292 smb_Directory_Watches = nextWatch;
6294 lastWatch->nextp = nextWatch;
6296 /* Turn off WATCHED flag in dscp */
6297 lock_ObtainMutex(&dscp->mx);
6299 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6301 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
6302 lock_ReleaseMutex(&dscp->mx);
6304 /* Convert to response packet */
6305 ((smb_t *) watch)->reb = 0x80;
6306 ((smb_t *) watch)->wct = 0;
6309 if (filename == NULL)
6312 nameLen = strlen(filename);
6313 parmCount = 3*4 + nameLen*2;
6314 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6316 otherNameLen = strlen(otherFilename);
6317 oldParmCount = parmCount;
6318 parmCount += 3*4 + otherNameLen*2;
6319 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6321 if (maxLen < parmCount)
6322 parmCount = 0; /* not enough room */
6324 parmOffset = 8*4 + 39;
6325 parmOffset += 1; /* pad to 4 */
6326 dataOffset = parmOffset + parmCount;
6330 /* Total Parameter Count */
6331 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6332 /* Total Data Count */
6333 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6334 /* Parameter Count */
6335 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6336 /* Parameter Offset */
6337 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
6338 /* Parameter Displacement */
6339 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6341 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6343 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
6344 /* Data Displacement */
6345 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6346 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
6347 smb_SetSMBDataLength(watch, parmCount + 1);
6349 if (parmCount != 0) {
6351 outData = smb_GetSMBData(watch, NULL);
6352 outData++; /* round to get to parmOffset */
6353 oldOutData = outData;
6354 *((DWORD *)outData) = oldParmCount; outData += 4;
6355 /* Next Entry Offset */
6356 *((DWORD *)outData) = action; outData += 4;
6358 *((DWORD *)outData) = nameLen*2; outData += 4;
6359 /* File Name Length */
6360 p = strdup(filename);
6361 if (smb_StoreAnsiFilenames)
6363 mbstowcs((WCHAR *)outData, p, nameLen);
6367 outData = oldOutData + oldParmCount;
6368 *((DWORD *)outData) = 0; outData += 4;
6369 /* Next Entry Offset */
6370 *((DWORD *)outData) = otherAction; outData += 4;
6372 *((DWORD *)outData) = otherNameLen*2;
6373 outData += 4; /* File Name Length */
6374 p = strdup(otherFilename);
6375 if (smb_StoreAnsiFilenames)
6377 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
6383 * If filename is null, we don't know the cause of the
6384 * change notification. We return zero data (see above),
6385 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
6386 * (= 0x010C). We set the error code here by hand, without
6387 * modifying wct and bcc.
6389 if (filename == NULL) {
6390 ((smb_t *) watch)->rcls = 0x0C;
6391 ((smb_t *) watch)->reh = 0x01;
6392 ((smb_t *) watch)->errLow = 0;
6393 ((smb_t *) watch)->errHigh = 0;
6394 /* Set NT Status codes flag */
6395 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_ERR_STATUS;
6398 smb_SendPacket(vcp, watch);
6399 smb_FreePacket(watch);
6402 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6405 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6407 unsigned char *replyWctp;
6408 smb_packet_t *watch, *lastWatch;
6409 USHORT fid, watchtree;
6413 osi_Log0(smb_logp, "SMB3 receive NT cancel");
6415 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6416 watch = smb_Directory_Watches;
6418 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
6419 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
6420 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
6421 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
6422 if (watch == smb_Directory_Watches)
6423 smb_Directory_Watches = watch->nextp;
6425 lastWatch->nextp = watch->nextp;
6426 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6428 /* Turn off WATCHED flag in scp */
6429 fid = smb_GetSMBParm(watch, 21);
6430 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
6432 if (vcp != watch->vcp)
6433 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
6436 fidp = smb_FindFID(vcp, fid, 0);
6438 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
6440 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
6443 lock_ObtainMutex(&scp->mx);
6445 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6447 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
6448 lock_ReleaseMutex(&scp->mx);
6449 smb_ReleaseFID(fidp);
6451 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
6454 /* assume STATUS32; return 0xC0000120 (CANCELED) */
6455 replyWctp = watch->wctp;
6459 ((smb_t *)watch)->rcls = 0x20;
6460 ((smb_t *)watch)->reh = 0x1;
6461 ((smb_t *)watch)->errLow = 0;
6462 ((smb_t *)watch)->errHigh = 0xC0;
6463 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_ERR_STATUS;
6464 smb_SendPacket(vcp, watch);
6465 smb_FreePacket(watch);
6469 watch = watch->nextp;
6471 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6477 * NT rename also does hard links.
6480 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
6481 #define RENAME_FLAG_HARD_LINK 0x103
6482 #define RENAME_FLAG_RENAME 0x104
6483 #define RENAME_FLAG_COPY 0x105
6485 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6487 char *oldPathp, *newPathp;
6493 attrs = smb_GetSMBParm(inp, 0);
6494 rename_type = smb_GetSMBParm(inp, 1);
6496 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
6497 osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
6498 return CM_ERROR_NOACCESS;
6501 tp = smb_GetSMBData(inp, NULL);
6502 oldPathp = smb_ParseASCIIBlock(tp, &tp);
6503 if (smb_StoreAnsiFilenames)
6504 OemToChar(oldPathp,oldPathp);
6505 newPathp = smb_ParseASCIIBlock(tp, &tp);
6506 if (smb_StoreAnsiFilenames)
6507 OemToChar(newPathp,newPathp);
6509 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
6510 osi_LogSaveString(smb_logp, oldPathp),
6511 osi_LogSaveString(smb_logp, newPathp),
6512 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
6514 if (rename_type == RENAME_FLAG_RENAME) {
6515 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
6516 } else { /* RENAME_FLAG_HARD_LINK */
6517 code = smb_Link(vcp,inp,oldPathp,newPathp);
6524 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
6527 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
6530 smb_username_t *unp;
6532 unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
6534 lock_ObtainMutex(&unp->mx);
6535 unp->userp = cm_NewUser();
6536 lock_ReleaseMutex(&unp->mx);
6537 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6538 osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
6540 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6541 osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);