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)
1148 if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
1149 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1158 /* called with a VC, an input packet to respond to, and an error code.
1159 * sends an error response.
1161 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1162 smb_packet_t *tp, long code)
1165 unsigned short errCode;
1166 unsigned char errClass;
1167 unsigned long NTStatus;
1169 if (vcp->flags & SMB_VCFLAG_STATUS32)
1170 smb_MapNTError(code, &NTStatus);
1172 smb_MapCoreError(code, vcp, &errCode, &errClass);
1174 smb_FormatResponsePacket(vcp, NULL, tp);
1175 smbp = (smb_t *) tp;
1177 /* We can handle long names */
1178 if (vcp->flags & SMB_VCFLAG_USENT)
1179 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1181 /* now copy important fields from the tran 2 packet */
1182 smbp->com = t2p->com;
1183 smbp->tid = t2p->tid;
1184 smbp->mid = t2p->mid;
1185 smbp->pid = t2p->pid;
1186 smbp->uid = t2p->uid;
1187 smbp->res[0] = t2p->res[0];
1188 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1189 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1190 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1191 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1192 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1193 smbp->flg2 |= SMB_FLAGS2_ERR_STATUS;
1196 smbp->rcls = errClass;
1197 smbp->errLow = (unsigned char) (errCode & 0xff);
1198 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1202 smb_SendPacket(vcp, tp);
1205 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1208 unsigned short parmOffset;
1209 unsigned short dataOffset;
1210 unsigned short totalLength;
1211 unsigned short dataAlign;
1214 smb_FormatResponsePacket(vcp, NULL, tp);
1215 smbp = (smb_t *) tp;
1217 /* We can handle long names */
1218 if (vcp->flags & SMB_VCFLAG_USENT)
1219 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1221 /* now copy important fields from the tran 2 packet */
1222 smbp->com = t2p->com;
1223 smbp->tid = t2p->tid;
1224 smbp->mid = t2p->mid;
1225 smbp->pid = t2p->pid;
1226 smbp->uid = t2p->uid;
1227 smbp->res[0] = t2p->res[0];
1229 totalLength = 1 + t2p->totalData + t2p->totalParms;
1231 /* now add the core parameters (tran2 info) to the packet */
1232 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1233 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1234 smb_SetSMBParm(tp, 2, 0); /* reserved */
1235 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1236 parmOffset = 10*2 + 35; /* parm offset in packet */
1237 parmOffset++; /* round to even */
1238 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1239 * hdr, bcc and wct */
1240 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1241 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1242 dataOffset = parmOffset + t2p->oldTotalParms;
1243 dataAlign = dataOffset & 2; /* quad-align */
1244 dataOffset += dataAlign;
1245 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1246 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1247 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1250 datap = smb_GetSMBData(tp, NULL);
1251 *datap++ = 0; /* we rounded to even */
1253 totalLength += dataAlign;
1254 smb_SetSMBDataLength(tp, totalLength);
1256 /* next, send the datagram */
1257 smb_SendPacket(vcp, tp);
1260 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1262 smb_tran2Packet_t *asp;
1275 /* We sometimes see 0 word count. What to do? */
1276 if (*inp->wctp == 0) {
1281 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1283 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1284 ptbuf[0] = "Transaction2 word count = 0";
1285 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1286 1, inp->ncb_length, ptbuf, inp);
1287 DeregisterEventSource(h);
1289 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1292 smb_SetSMBDataLength(outp, 0);
1293 smb_SendPacket(vcp, outp);
1297 totalParms = smb_GetSMBParm(inp, 0);
1298 totalData = smb_GetSMBParm(inp, 1);
1300 firstPacket = (inp->inCom == 0x25);
1302 /* find the packet we're reassembling */
1303 lock_ObtainWrite(&smb_globalLock);
1304 asp = smb_FindTran2Packet(vcp, inp);
1306 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1308 lock_ReleaseWrite(&smb_globalLock);
1310 /* now merge in this latest packet; start by looking up offsets */
1312 parmDisp = dataDisp = 0;
1313 parmOffset = smb_GetSMBParm(inp, 10);
1314 dataOffset = smb_GetSMBParm(inp, 12);
1315 parmCount = smb_GetSMBParm(inp, 9);
1316 dataCount = smb_GetSMBParm(inp, 11);
1317 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1318 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1320 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1321 totalData, dataCount, asp->maxReturnData);
1324 parmDisp = smb_GetSMBParm(inp, 4);
1325 parmOffset = smb_GetSMBParm(inp, 3);
1326 dataDisp = smb_GetSMBParm(inp, 7);
1327 dataOffset = smb_GetSMBParm(inp, 6);
1328 parmCount = smb_GetSMBParm(inp, 2);
1329 dataCount = smb_GetSMBParm(inp, 5);
1331 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1332 parmCount, dataCount);
1335 /* now copy the parms and data */
1336 if ( asp->totalParms > 0 && parmCount != 0 )
1338 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1340 if ( asp->totalData > 0 && dataCount != 0 ) {
1341 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1344 /* account for new bytes */
1345 asp->curData += dataCount;
1346 asp->curParms += parmCount;
1348 /* finally, if we're done, remove the packet from the queue and dispatch it */
1349 if (asp->totalParms > 0 &&
1350 asp->curParms > 0 &&
1351 asp->totalData <= asp->curData &&
1352 asp->totalParms <= asp->curParms) {
1353 /* we've received it all */
1354 lock_ObtainWrite(&smb_globalLock);
1355 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1356 lock_ReleaseWrite(&smb_globalLock);
1358 /* now dispatch it */
1359 rapOp = asp->parmsp[0];
1361 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1362 osi_LogEvent("AFS-Dispatch-RAP[%s]",myCrt_RapDispatch(rapOp),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1363 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%x] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1364 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1367 osi_LogEvent("AFS-Dispatch-RAP [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1368 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1369 code = CM_ERROR_BADOP;
1372 /* if an error is returned, we're supposed to send an error packet,
1373 * otherwise the dispatched function already did the data sending.
1374 * We give dispatched proc the responsibility since it knows how much
1375 * space to allocate.
1378 smb_SendTran2Error(vcp, asp, outp, code);
1381 /* free the input tran 2 packet */
1382 lock_ObtainWrite(&smb_globalLock);
1383 smb_FreeTran2Packet(asp);
1384 lock_ReleaseWrite(&smb_globalLock);
1386 else if (firstPacket) {
1387 /* the first packet in a multi-packet request, we need to send an
1388 * ack to get more data.
1390 smb_SetSMBDataLength(outp, 0);
1391 smb_SendPacket(vcp, outp);
1397 /* ANSI versions. The unicode versions support arbitrary length
1398 share names, but we don't support unicode yet. */
1400 typedef struct smb_rap_share_info_0 {
1401 char shi0_netname[13];
1402 } smb_rap_share_info_0_t;
1404 typedef struct smb_rap_share_info_1 {
1405 char shi1_netname[13];
1408 DWORD shi1_remark; /* char *shi1_remark; data offset */
1409 } smb_rap_share_info_1_t;
1411 typedef struct smb_rap_share_info_2 {
1412 char shi2_netname[13];
1414 unsigned short shi2_type;
1415 DWORD shi2_remark; /* char *shi2_remark; data offset */
1416 unsigned short shi2_permissions;
1417 unsigned short shi2_max_uses;
1418 unsigned short shi2_current_uses;
1419 DWORD shi2_path; /* char *shi2_path; data offset */
1420 unsigned short shi2_passwd[9];
1421 unsigned short shi2_pad2;
1422 } smb_rap_share_info_2_t;
1424 #define SMB_RAP_MAX_SHARES 512
1426 typedef struct smb_rap_share_list {
1429 smb_rap_share_info_0_t * shares;
1430 } smb_rap_share_list_t;
1432 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1433 smb_rap_share_list_t * sp;
1438 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1439 return 0; /* skip over '.' and '..' */
1441 sp = (smb_rap_share_list_t *) vrockp;
1443 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1444 sp->shares[sp->cShare].shi0_netname[12] = 0;
1448 if (sp->cShare >= sp->maxShares)
1449 return CM_ERROR_STOPNOW;
1454 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1456 smb_tran2Packet_t *outp;
1457 unsigned short * tp;
1461 int outParmsTotal; /* total parameter bytes */
1462 int outDataTotal; /* total data bytes */
1470 HKEY hkSubmount = NULL;
1471 smb_rap_share_info_1_t * shares;
1474 char thisShare[256];
1477 smb_rap_share_list_t rootShares;
1482 tp = p->parmsp + 1; /* skip over function number (always 0) */
1483 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1484 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1488 if (infoLevel != 1) {
1489 return CM_ERROR_INVAL;
1492 /* first figure out how many shares there are */
1493 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1494 KEY_QUERY_VALUE, &hkParam);
1495 if (rv == ERROR_SUCCESS) {
1496 len = sizeof(allSubmount);
1497 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1498 (BYTE *) &allSubmount, &len);
1499 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1502 RegCloseKey (hkParam);
1505 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1506 0, KEY_QUERY_VALUE, &hkSubmount);
1507 if (rv == ERROR_SUCCESS) {
1508 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1509 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1510 if (rv != ERROR_SUCCESS)
1516 /* fetch the root shares */
1517 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1518 rootShares.cShare = 0;
1519 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1523 userp = smb_GetTran2User(vcp,p);
1525 thyper.HighPart = 0;
1528 cm_HoldSCache(cm_rootSCachep);
1529 cm_ApplyDir(cm_rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1530 cm_ReleaseSCache(cm_rootSCachep);
1532 cm_ReleaseUser(userp);
1534 nShares = rootShares.cShare + nRegShares + allSubmount;
1536 #define REMARK_LEN 1
1537 outParmsTotal = 8; /* 4 dwords */
1538 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1539 if(outDataTotal > bufsize) {
1540 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1541 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1544 nSharesRet = nShares;
1547 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1549 /* now for the submounts */
1550 shares = (smb_rap_share_info_1_t *) outp->datap;
1551 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1553 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1556 strcpy( shares[cshare].shi1_netname, "all" );
1557 shares[cshare].shi1_remark = cstrp - outp->datap;
1558 /* type and pad are zero already */
1564 for (i=0; i < nRegShares && cshare < nSharesRet; i++) {
1565 len = sizeof(thisShare);
1566 rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1567 if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1568 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1569 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1570 shares[cshare].shi1_remark = cstrp - outp->datap;
1575 nShares--; /* uncount key */
1578 RegCloseKey(hkSubmount);
1581 nonrootShares = cshare;
1583 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1584 /* in case there are collisions with submounts, submounts have higher priority */
1585 for (j=0; j < nonrootShares; j++)
1586 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1589 if (j < nonrootShares) {
1590 nShares--; /* uncount */
1594 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1595 shares[cshare].shi1_remark = cstrp - outp->datap;
1600 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1601 outp->parmsp[1] = 0;
1602 outp->parmsp[2] = cshare;
1603 outp->parmsp[3] = nShares;
1605 outp->totalData = cstrp - outp->datap;
1606 outp->totalParms = outParmsTotal;
1608 smb_SendTran2Packet(vcp, outp, op);
1609 smb_FreeTran2Packet(outp);
1611 free(rootShares.shares);
1616 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1618 smb_tran2Packet_t *outp;
1619 unsigned short * tp;
1621 BOOL shareFound = FALSE;
1622 unsigned short infoLevel;
1623 unsigned short bufsize;
1633 tp = p->parmsp + 1; /* skip over function number (always 1) */
1634 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1635 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1636 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1643 totalData = sizeof(smb_rap_share_info_0_t);
1644 else if(infoLevel == SMB_INFO_STANDARD)
1645 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1646 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1647 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1649 return CM_ERROR_INVAL;
1651 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1653 if(!stricmp(shareName,"all")) {
1654 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1655 KEY_QUERY_VALUE, &hkParam);
1656 if (rv == ERROR_SUCCESS) {
1657 len = sizeof(allSubmount);
1658 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1659 (BYTE *) &allSubmount, &len);
1660 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1663 RegCloseKey (hkParam);
1670 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts", 0,
1671 KEY_QUERY_VALUE, &hkSubmount);
1672 if (rv == ERROR_SUCCESS) {
1673 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1674 if (rv == ERROR_SUCCESS) {
1677 RegCloseKey(hkSubmount);
1682 smb_FreeTran2Packet(outp);
1683 return CM_ERROR_BADSHARENAME;
1686 memset(outp->datap, 0, totalData);
1688 outp->parmsp[0] = 0;
1689 outp->parmsp[1] = 0;
1690 outp->parmsp[2] = totalData;
1692 if (infoLevel == 0) {
1693 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1694 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1695 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1696 } else if(infoLevel == SMB_INFO_STANDARD) {
1697 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1698 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1699 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1700 info->shi1_remark = ((unsigned char *) (info + 1)) - outp->datap;
1701 /* type and pad are already zero */
1702 } else { /* infoLevel==2 */
1703 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1704 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1705 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1706 info->shi2_remark = ((unsigned char *) (info + 1)) - outp->datap;
1707 info->shi2_permissions = ACCESS_ALL;
1708 info->shi2_max_uses = (unsigned short) -1;
1709 info->shi2_path = 1 + (((unsigned char *) (info + 1)) - outp->datap);
1712 outp->totalData = totalData;
1713 outp->totalParms = totalParam;
1715 smb_SendTran2Packet(vcp, outp, op);
1716 smb_FreeTran2Packet(outp);
1721 typedef struct smb_rap_wksta_info_10 {
1722 DWORD wki10_computername; /*char *wki10_computername;*/
1723 DWORD wki10_username; /* char *wki10_username; */
1724 DWORD wki10_langroup; /* char *wki10_langroup;*/
1725 unsigned char wki10_ver_major;
1726 unsigned char wki10_ver_minor;
1727 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1728 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1729 } smb_rap_wksta_info_10_t;
1732 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1734 smb_tran2Packet_t *outp;
1738 unsigned short * tp;
1741 smb_rap_wksta_info_10_t * info;
1745 tp = p->parmsp + 1; /* Skip over function number */
1746 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1747 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1751 if (infoLevel != 10) {
1752 return CM_ERROR_INVAL;
1758 totalData = sizeof(*info) + /* info */
1759 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1760 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1761 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1762 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1763 1; /* wki10_oth_domains (null)*/
1765 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1767 memset(outp->parmsp,0,totalParams);
1768 memset(outp->datap,0,totalData);
1770 info = (smb_rap_wksta_info_10_t *) outp->datap;
1771 cstrp = (char *) (info + 1);
1773 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1774 strcpy(cstrp, smb_localNamep);
1775 cstrp += strlen(cstrp) + 1;
1777 info->wki10_username = (DWORD) (cstrp - outp->datap);
1778 uidp = smb_FindUID(vcp, p->uid, 0);
1780 lock_ObtainMutex(&uidp->mx);
1781 if(uidp->unp && uidp->unp->name)
1782 strcpy(cstrp, uidp->unp->name);
1783 lock_ReleaseMutex(&uidp->mx);
1784 smb_ReleaseUID(uidp);
1786 cstrp += strlen(cstrp) + 1;
1788 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1789 strcpy(cstrp, "WORKGROUP");
1790 cstrp += strlen(cstrp) + 1;
1792 /* TODO: Not sure what values these should take, but these work */
1793 info->wki10_ver_major = 5;
1794 info->wki10_ver_minor = 1;
1796 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1797 strcpy(cstrp, smb_ServerDomainName);
1798 cstrp += strlen(cstrp) + 1;
1800 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1801 cstrp ++; /* no other domains */
1803 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1804 outp->parmsp[2] = outp->totalData;
1805 outp->totalParms = totalParams;
1807 smb_SendTran2Packet(vcp,outp,op);
1808 smb_FreeTran2Packet(outp);
1813 typedef struct smb_rap_server_info_0 {
1815 } smb_rap_server_info_0_t;
1817 typedef struct smb_rap_server_info_1 {
1819 char sv1_version_major;
1820 char sv1_version_minor;
1821 unsigned long sv1_type;
1822 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1823 } smb_rap_server_info_1_t;
1825 char smb_ServerComment[] = "OpenAFS Client";
1826 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1828 #define SMB_SV_TYPE_SERVER 0x00000002L
1829 #define SMB_SV_TYPE_NT 0x00001000L
1830 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1832 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1834 smb_tran2Packet_t *outp;
1838 unsigned short * tp;
1841 smb_rap_server_info_0_t * info0;
1842 smb_rap_server_info_1_t * info1;
1845 tp = p->parmsp + 1; /* Skip over function number */
1846 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1847 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1851 if (infoLevel != 0 && infoLevel != 1) {
1852 return CM_ERROR_INVAL;
1858 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1859 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1861 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1863 memset(outp->parmsp,0,totalParams);
1864 memset(outp->datap,0,totalData);
1866 if (infoLevel == 0) {
1867 info0 = (smb_rap_server_info_0_t *) outp->datap;
1868 cstrp = (char *) (info0 + 1);
1869 strcpy(info0->sv0_name, "AFS");
1870 } else { /* infoLevel == SMB_INFO_STANDARD */
1871 info1 = (smb_rap_server_info_1_t *) outp->datap;
1872 cstrp = (char *) (info1 + 1);
1873 strcpy(info1->sv1_name, "AFS");
1876 SMB_SV_TYPE_SERVER |
1878 SMB_SV_TYPE_SERVER_NT;
1880 info1->sv1_version_major = 5;
1881 info1->sv1_version_minor = 1;
1882 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1884 strcpy(cstrp, smb_ServerComment);
1886 cstrp += smb_ServerCommentLen;
1889 totalData = cstrp - outp->datap;
1890 outp->totalData = min(bufsize,totalData); /* actual data size */
1891 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1892 outp->parmsp[2] = totalData;
1893 outp->totalParms = totalParams;
1895 smb_SendTran2Packet(vcp,outp,op);
1896 smb_FreeTran2Packet(outp);
1901 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1903 smb_tran2Packet_t *asp;
1915 /* We sometimes see 0 word count. What to do? */
1916 if (*inp->wctp == 0) {
1921 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1923 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1924 ptbuf[0] = "Transaction2 word count = 0";
1925 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1926 1, inp->ncb_length, ptbuf, inp);
1927 DeregisterEventSource(h);
1929 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1932 smb_SetSMBDataLength(outp, 0);
1933 smb_SendPacket(vcp, outp);
1937 totalParms = smb_GetSMBParm(inp, 0);
1938 totalData = smb_GetSMBParm(inp, 1);
1940 firstPacket = (inp->inCom == 0x32);
1942 /* find the packet we're reassembling */
1943 lock_ObtainWrite(&smb_globalLock);
1944 asp = smb_FindTran2Packet(vcp, inp);
1946 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1948 lock_ReleaseWrite(&smb_globalLock);
1950 /* now merge in this latest packet; start by looking up offsets */
1952 parmDisp = dataDisp = 0;
1953 parmOffset = smb_GetSMBParm(inp, 10);
1954 dataOffset = smb_GetSMBParm(inp, 12);
1955 parmCount = smb_GetSMBParm(inp, 9);
1956 dataCount = smb_GetSMBParm(inp, 11);
1957 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1958 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1960 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1961 totalData, dataCount, asp->maxReturnData);
1964 parmDisp = smb_GetSMBParm(inp, 4);
1965 parmOffset = smb_GetSMBParm(inp, 3);
1966 dataDisp = smb_GetSMBParm(inp, 7);
1967 dataOffset = smb_GetSMBParm(inp, 6);
1968 parmCount = smb_GetSMBParm(inp, 2);
1969 dataCount = smb_GetSMBParm(inp, 5);
1971 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1972 parmCount, dataCount);
1975 /* now copy the parms and data */
1976 if ( asp->totalParms > 0 && parmCount != 0 )
1978 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1980 if ( asp->totalData > 0 && dataCount != 0 ) {
1981 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1984 /* account for new bytes */
1985 asp->curData += dataCount;
1986 asp->curParms += parmCount;
1988 /* finally, if we're done, remove the packet from the queue and dispatch it */
1989 if (asp->totalParms > 0 &&
1990 asp->curParms > 0 &&
1991 asp->totalData <= asp->curData &&
1992 asp->totalParms <= asp->curParms) {
1993 /* we've received it all */
1994 lock_ObtainWrite(&smb_globalLock);
1995 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1996 lock_ReleaseWrite(&smb_globalLock);
1998 /* now dispatch it */
1999 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2000 osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
2001 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2002 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2005 osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2006 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2007 code = CM_ERROR_BADOP;
2010 /* if an error is returned, we're supposed to send an error packet,
2011 * otherwise the dispatched function already did the data sending.
2012 * We give dispatched proc the responsibility since it knows how much
2013 * space to allocate.
2016 smb_SendTran2Error(vcp, asp, outp, code);
2019 /* free the input tran 2 packet */
2020 lock_ObtainWrite(&smb_globalLock);
2021 smb_FreeTran2Packet(asp);
2022 lock_ReleaseWrite(&smb_globalLock);
2024 else if (firstPacket) {
2025 /* the first packet in a multi-packet request, we need to send an
2026 * ack to get more data.
2028 smb_SetSMBDataLength(outp, 0);
2029 smb_SendPacket(vcp, outp);
2035 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2038 smb_tran2Packet_t *outp;
2043 cm_scache_t *dscp; /* dir we're dealing with */
2044 cm_scache_t *scp; /* file we're creating */
2046 int initialModeBits;
2056 int parmSlot; /* which parm we're dealing with */
2057 long returnEALength;
2065 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2066 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2068 openFun = p->parmsp[6]; /* open function */
2069 excl = ((openFun & 3) == 0);
2070 trunc = ((openFun & 3) == 2); /* truncate it */
2071 openMode = (p->parmsp[1] & 0x7);
2072 openAction = 0; /* tracks what we did */
2074 attributes = p->parmsp[3];
2075 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2077 /* compute initial mode bits based on read-only flag in attributes */
2078 initialModeBits = 0666;
2079 if (attributes & 1) initialModeBits &= ~0222;
2081 pathp = (char *) (&p->parmsp[14]);
2082 if (smb_StoreAnsiFilenames)
2083 OemToChar(pathp,pathp);
2085 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2087 spacep = cm_GetSpace();
2088 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2090 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2091 /* special case magic file name for receiving IOCTL requests
2092 * (since IOCTL calls themselves aren't getting through).
2094 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2095 smb_SetupIoctlFid(fidp, spacep);
2097 /* copy out remainder of the parms */
2099 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2101 outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
2102 outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
2103 outp->parmsp[parmSlot] = 0; parmSlot++;
2104 outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
2105 outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
2106 outp->parmsp[parmSlot] = openMode; parmSlot++;
2107 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2108 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2110 /* and the final "always present" stuff */
2111 outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
2112 /* next write out the "unique" ID */
2113 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
2114 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
2115 outp->parmsp[parmSlot] = 0; parmSlot++;
2116 if (returnEALength) {
2117 outp->parmsp[parmSlot] = 0; parmSlot++;
2118 outp->parmsp[parmSlot] = 0; parmSlot++;
2121 outp->totalData = 0;
2122 outp->totalParms = parmSlot * 2;
2124 smb_SendTran2Packet(vcp, outp, op);
2126 smb_FreeTran2Packet(outp);
2128 /* and clean up fid reference */
2129 smb_ReleaseFID(fidp);
2133 #ifdef DEBUG_VERBOSE
2135 char *hexp, *asciip;
2136 asciip = (lastNamep ? lastNamep : pathp);
2137 hexp = osi_HexifyString( asciip );
2138 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2143 userp = smb_GetTran2User(vcp, p);
2144 /* In the off chance that userp is NULL, we log and abandon */
2146 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2147 smb_FreeTran2Packet(outp);
2148 return CM_ERROR_BADSMB;
2151 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2152 if (code == CM_ERROR_TIDIPC) {
2153 /* Attempt to use TID allocated for IPC. The client is
2154 probably trying to locate DCE RPC end points, which
2155 we don't support. */
2156 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2157 cm_ReleaseUser(userp);
2158 smb_FreeTran2Packet(outp);
2159 return CM_ERROR_NOSUCHPATH;
2163 code = cm_NameI(cm_rootSCachep, pathp,
2164 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2165 userp, tidPathp, &req, &scp);
2167 code = cm_NameI(cm_rootSCachep, spacep->data,
2168 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2169 userp, tidPathp, &req, &dscp);
2170 cm_FreeSpace(spacep);
2173 cm_ReleaseUser(userp);
2174 smb_FreeTran2Packet(outp);
2178 /* otherwise, scp points to the parent directory. Do a lookup,
2179 * and truncate the file if we find it, otherwise we create the
2186 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2188 if (code && code != CM_ERROR_NOSUCHFILE) {
2189 cm_ReleaseSCache(dscp);
2190 cm_ReleaseUser(userp);
2191 smb_FreeTran2Packet(outp);
2196 cm_FreeSpace(spacep);
2199 /* if we get here, if code is 0, the file exists and is represented by
2200 * scp. Otherwise, we have to create it.
2203 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2205 if (dscp) cm_ReleaseSCache(dscp);
2206 cm_ReleaseSCache(scp);
2207 cm_ReleaseUser(userp);
2208 smb_FreeTran2Packet(outp);
2213 /* oops, file shouldn't be there */
2214 if (dscp) cm_ReleaseSCache(dscp);
2215 cm_ReleaseSCache(scp);
2216 cm_ReleaseUser(userp);
2217 smb_FreeTran2Packet(outp);
2218 return CM_ERROR_EXISTS;
2222 setAttr.mask = CM_ATTRMASK_LENGTH;
2223 setAttr.length.LowPart = 0;
2224 setAttr.length.HighPart = 0;
2225 code = cm_SetAttr(scp, &setAttr, userp, &req);
2226 openAction = 3; /* truncated existing file */
2229 openAction = 1; /* found existing file */
2231 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
2232 /* don't create if not found */
2233 if (dscp) cm_ReleaseSCache(dscp);
2234 osi_assert(scp == NULL);
2235 cm_ReleaseUser(userp);
2236 smb_FreeTran2Packet(outp);
2237 return CM_ERROR_NOSUCHFILE;
2240 osi_assert(dscp != NULL && scp == NULL);
2241 openAction = 2; /* created file */
2242 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2243 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2244 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2246 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2247 smb_NotifyChange(FILE_ACTION_ADDED,
2248 FILE_NOTIFY_CHANGE_FILE_NAME,
2249 dscp, lastNamep, NULL, TRUE);
2250 if (!excl && code == CM_ERROR_EXISTS) {
2251 /* not an exclusive create, and someone else tried
2252 * creating it already, then we open it anyway. We
2253 * don't bother retrying after this, since if this next
2254 * fails, that means that the file was deleted after we
2255 * started this call.
2257 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2261 setAttr.mask = CM_ATTRMASK_LENGTH;
2262 setAttr.length.LowPart = 0;
2263 setAttr.length.HighPart = 0;
2264 code = cm_SetAttr(scp, &setAttr, userp,
2267 } /* lookup succeeded */
2271 /* we don't need this any longer */
2272 if (dscp) cm_ReleaseSCache(dscp);
2275 /* something went wrong creating or truncating the file */
2276 if (scp) cm_ReleaseSCache(scp);
2277 cm_ReleaseUser(userp);
2278 smb_FreeTran2Packet(outp);
2282 /* make sure we're about to open a file */
2283 if (scp->fileType != CM_SCACHETYPE_FILE) {
2285 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2286 cm_scache_t * targetScp = 0;
2287 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2289 /* we have a more accurate file to use (the
2290 * target of the symbolic link). Otherwise,
2291 * we'll just use the symlink anyway.
2293 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2295 cm_ReleaseSCache(scp);
2299 if (scp->fileType != CM_SCACHETYPE_FILE) {
2300 cm_ReleaseSCache(scp);
2301 cm_ReleaseUser(userp);
2302 smb_FreeTran2Packet(outp);
2303 return CM_ERROR_ISDIR;
2307 /* now all we have to do is open the file itself */
2308 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2311 /* save a pointer to the vnode */
2314 /* compute open mode */
2315 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2316 if (openMode == 1 || openMode == 2)
2317 fidp->flags |= SMB_FID_OPENWRITE;
2319 smb_ReleaseFID(fidp);
2321 cm_Open(scp, 0, userp);
2323 /* copy out remainder of the parms */
2325 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2326 lock_ObtainMutex(&scp->mx);
2328 outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
2329 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2330 outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
2331 outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
2332 outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
2334 outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2336 outp->parmsp[parmSlot] = openMode; parmSlot++;
2337 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2338 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2340 /* and the final "always present" stuff */
2341 outp->parmsp[parmSlot] = openAction; parmSlot++;
2342 /* next write out the "unique" ID */
2343 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
2344 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
2345 outp->parmsp[parmSlot] = 0; parmSlot++;
2346 if (returnEALength) {
2347 outp->parmsp[parmSlot] = 0; parmSlot++;
2348 outp->parmsp[parmSlot] = 0; parmSlot++;
2350 lock_ReleaseMutex(&scp->mx);
2351 outp->totalData = 0; /* total # of data bytes */
2352 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2354 smb_SendTran2Packet(vcp, outp, op);
2356 smb_FreeTran2Packet(outp);
2358 cm_ReleaseUser(userp);
2359 /* leave scp held since we put it in fidp->scp */
2363 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2365 osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2366 return CM_ERROR_BADOP;
2369 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2371 osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2372 return CM_ERROR_BADOP;
2375 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2377 smb_tran2Packet_t *outp;
2378 smb_tran2QFSInfo_t qi;
2381 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
2383 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2385 switch (p->parmsp[0]) {
2386 case 1: responseSize = sizeof(qi.u.allocInfo); break;
2387 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
2388 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
2389 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
2390 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
2391 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
2392 case 0x200: /* CIFS Unix Info */
2393 case 0x301: /* Mac FS Info */
2394 default: return CM_ERROR_INVAL;
2397 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2398 switch (p->parmsp[0]) {
2401 qi.u.allocInfo.FSID = 0;
2402 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2403 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2404 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2405 qi.u.allocInfo.bytesPerSector = 1024;
2410 qi.u.volumeInfo.vsn = 1234;
2411 qi.u.volumeInfo.vnCount = 4;
2412 /* we're supposed to pad it out with zeroes to the end */
2413 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2414 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2418 /* FS volume info */
2419 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
2420 qi.u.FSvolumeInfo.vsn = 1234;
2421 qi.u.FSvolumeInfo.vnCount = 8;
2422 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
2428 temp.LowPart = 0x7fffffff;
2429 qi.u.FSsizeInfo.totalAllocUnits = temp;
2430 temp.LowPart = 0x3fffffff;
2431 qi.u.FSsizeInfo.availAllocUnits = temp;
2432 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2433 qi.u.FSsizeInfo.bytesPerSector = 1024;
2437 /* FS device info */
2438 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
2439 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2443 /* FS attribute info */
2444 /* attributes, defined in WINNT.H:
2445 * FILE_CASE_SENSITIVE_SEARCH 0x1
2446 * FILE_CASE_PRESERVED_NAMES 0x2
2447 * <no name defined> 0x4000
2448 * If bit 0x4000 is not set, Windows 95 thinks
2449 * we can't handle long (non-8.3) names,
2450 * despite our protestations to the contrary.
2452 qi.u.FSattributeInfo.attributes = 0x4003;
2453 qi.u.FSattributeInfo.maxCompLength = 255;
2454 qi.u.FSattributeInfo.FSnameLength = 6;
2455 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
2459 /* copy out return data, and set corresponding sizes */
2460 outp->totalParms = 0;
2461 outp->totalData = responseSize;
2462 memcpy(outp->datap, &qi, responseSize);
2464 /* send and free the packets */
2465 smb_SendTran2Packet(vcp, outp, op);
2466 smb_FreeTran2Packet(outp);
2471 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2473 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2474 return CM_ERROR_BADOP;
2477 struct smb_ShortNameRock {
2481 size_t shortNameLen;
2484 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2487 struct smb_ShortNameRock *rockp;
2491 /* compare both names and vnodes, though probably just comparing vnodes
2492 * would be safe enough.
2494 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2496 if (ntohl(dep->fid.vnode) != rockp->vnode)
2498 /* This is the entry */
2499 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2500 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2501 return CM_ERROR_STOPNOW;
2504 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2505 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2507 struct smb_ShortNameRock rock;
2511 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2515 spacep = cm_GetSpace();
2516 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2518 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
2520 cm_FreeSpace(spacep);
2521 if (code) return code;
2523 if (!lastNamep) lastNamep = pathp;
2526 thyper.HighPart = 0;
2527 rock.shortName = shortName;
2529 rock.maskp = lastNamep;
2530 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2532 cm_ReleaseSCache(dscp);
2535 return CM_ERROR_NOSUCHFILE;
2536 if (code == CM_ERROR_STOPNOW) {
2537 *shortNameLenp = rock.shortNameLen;
2543 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2545 smb_tran2Packet_t *outp;
2548 unsigned short infoLevel;
2550 unsigned short attributes;
2551 unsigned long extAttributes;
2556 cm_scache_t *scp, *dscp;
2565 infoLevel = p->parmsp[0];
2566 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2568 else if (infoLevel == SMB_INFO_STANDARD)
2569 nbytesRequired = 22;
2570 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2571 nbytesRequired = 26;
2572 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2573 nbytesRequired = 40;
2574 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2575 nbytesRequired = 24;
2576 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2578 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2579 nbytesRequired = 30;
2581 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2582 p->opcode, infoLevel);
2583 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2586 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2587 osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
2589 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2591 if (infoLevel > 0x100)
2592 outp->totalParms = 2;
2594 outp->totalParms = 0;
2595 outp->totalData = nbytesRequired;
2597 /* now, if we're at infoLevel 6, we're only being asked to check
2598 * the syntax, so we just OK things now. In particular, we're *not*
2599 * being asked to verify anything about the state of any parent dirs.
2601 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2602 smb_SendTran2Packet(vcp, outp, opx);
2603 smb_FreeTran2Packet(outp);
2607 userp = smb_GetTran2User(vcp, p);
2609 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2610 smb_FreeTran2Packet(outp);
2611 return CM_ERROR_BADSMB;
2614 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2616 cm_ReleaseUser(userp);
2617 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2618 smb_FreeTran2Packet(outp);
2623 * XXX Strange hack XXX
2625 * As of Patch 7 (13 January 98), we are having the following problem:
2626 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2627 * requests to look up "desktop.ini" in all the subdirectories.
2628 * This can cause zillions of timeouts looking up non-existent cells
2629 * and volumes, especially in the top-level directory.
2631 * We have not found any way to avoid this or work around it except
2632 * to explicitly ignore the requests for mount points that haven't
2633 * yet been evaluated and for directories that haven't yet been
2636 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2637 spacep = cm_GetSpace();
2638 smb_StripLastComponent(spacep->data, &lastComp,
2639 (char *)(&p->parmsp[3]));
2640 #ifndef SPECIAL_FOLDERS
2641 /* Make sure that lastComp is not NULL */
2643 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2644 code = cm_NameI(cm_rootSCachep, spacep->data,
2648 userp, tidPathp, &req, &dscp);
2650 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
2651 && !dscp->mountRootFidp)
2652 code = CM_ERROR_NOSUCHFILE;
2653 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2654 cm_buf_t *bp = buf_Find(dscp, &hzero);
2658 code = CM_ERROR_NOSUCHFILE;
2660 cm_ReleaseSCache(dscp);
2662 cm_FreeSpace(spacep);
2663 cm_ReleaseUser(userp);
2664 smb_SendTran2Error(vcp, p, opx, code);
2665 smb_FreeTran2Packet(outp);
2671 #endif /* SPECIAL_FOLDERS */
2673 cm_FreeSpace(spacep);
2676 /* now do namei and stat, and copy out the info */
2677 code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
2678 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2681 cm_ReleaseUser(userp);
2682 smb_SendTran2Error(vcp, p, opx, code);
2683 smb_FreeTran2Packet(outp);
2687 lock_ObtainMutex(&scp->mx);
2688 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2689 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2690 if (code) goto done;
2692 /* now we have the status in the cache entry, and everything is locked.
2693 * Marshall the output data.
2696 /* for info level 108, figure out short name */
2697 if (infoLevel == 0x108) {
2698 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
2699 tidPathp, scp->fid.vnode, shortName,
2706 *((u_long *)op) = len * 2; op += 4;
2707 mbstowcs((unsigned short *)op, shortName, len);
2712 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2713 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2714 *((u_long *)op) = dosTime; op += 4; /* creation time */
2715 *((u_long *)op) = dosTime; op += 4; /* access time */
2716 *((u_long *)op) = dosTime; op += 4; /* write time */
2717 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
2718 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
2719 attributes = smb_Attributes(scp);
2720 *((u_short *)op) = attributes; op += 2; /* attributes */
2722 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2723 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2724 *((FILETIME *)op) = ft; op += 8; /* creation time */
2725 *((FILETIME *)op) = ft; op += 8; /* last access time */
2726 *((FILETIME *)op) = ft; op += 8; /* last write time */
2727 *((FILETIME *)op) = ft; op += 8; /* last change time */
2728 extAttributes = smb_ExtAttributes(scp);
2729 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
2730 *((u_long *)op) = 0; op += 4; /* don't know what this is */
2732 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2733 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2734 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2735 *((u_long *)op) = scp->linkCount; op += 4;
2738 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2741 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2742 memset(op, 0, 4); op += 4; /* EA size */
2745 /* now, if we are being asked about extended attrs, return a 0 size */
2746 if (infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2747 *((u_long *)op) = 0; op += 4;
2751 /* send and free the packets */
2753 lock_ReleaseMutex(&scp->mx);
2754 cm_ReleaseSCache(scp);
2755 cm_ReleaseUser(userp);
2757 smb_SendTran2Packet(vcp, outp, opx);
2759 smb_SendTran2Error(vcp, p, opx, code);
2760 smb_FreeTran2Packet(outp);
2765 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2767 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2768 return CM_ERROR_BADOP;
2771 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2773 smb_tran2Packet_t *outp;
2775 unsigned long attributes;
2776 unsigned short infoLevel;
2789 fidp = smb_FindFID(vcp, fid, 0);
2792 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2796 infoLevel = p->parmsp[1];
2797 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2798 nbytesRequired = 40;
2799 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2800 nbytesRequired = 24;
2801 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2803 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2806 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2807 p->opcode, infoLevel);
2808 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2809 smb_ReleaseFID(fidp);
2812 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2814 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2816 if (infoLevel > 0x100)
2817 outp->totalParms = 2;
2819 outp->totalParms = 0;
2820 outp->totalData = nbytesRequired;
2822 userp = smb_GetTran2User(vcp, p);
2824 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2825 code = CM_ERROR_BADSMB;
2830 lock_ObtainMutex(&scp->mx);
2831 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2832 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2836 /* now we have the status in the cache entry, and everything is locked.
2837 * Marshall the output data.
2840 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2841 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2842 *((FILETIME *)op) = ft; op += 8; /* creation time */
2843 *((FILETIME *)op) = ft; op += 8; /* last access time */
2844 *((FILETIME *)op) = ft; op += 8; /* last write time */
2845 *((FILETIME *)op) = ft; op += 8; /* last change time */
2846 attributes = smb_ExtAttributes(scp);
2847 *((u_long *)op) = attributes; op += 4;
2848 *((u_long *)op) = 0; op += 4;
2850 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2851 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2852 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2853 *((u_long *)op) = scp->linkCount; op += 4;
2854 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
2855 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2859 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2860 *((u_long *)op) = 0; op += 4;
2862 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2866 if (fidp->NTopen_wholepathp)
2867 name = fidp->NTopen_wholepathp;
2869 name = "\\"; /* probably can't happen */
2871 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
2872 *((u_long *)op) = len * 2; op += 4;
2873 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2876 /* send and free the packets */
2878 lock_ReleaseMutex(&scp->mx);
2879 cm_ReleaseUser(userp);
2880 smb_ReleaseFID(fidp);
2882 smb_SendTran2Packet(vcp, outp, opx);
2884 smb_SendTran2Error(vcp, p, opx, code);
2885 smb_FreeTran2Packet(outp);
2890 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2895 unsigned short infoLevel;
2896 smb_tran2Packet_t *outp;
2904 fidp = smb_FindFID(vcp, fid, 0);
2907 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
2911 infoLevel = p->parmsp[1];
2912 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type=[%x] fid=[%x]", infoLevel, fid);
2913 if (infoLevel > 0x104 || infoLevel < 0x101) {
2914 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2915 p->opcode, infoLevel);
2916 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
2917 smb_ReleaseFID(fidp);
2921 if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) {
2922 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2923 smb_ReleaseFID(fidp);
2926 if ((infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO)
2927 && !(fidp->flags & SMB_FID_OPENWRITE)) {
2928 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2929 smb_ReleaseFID(fidp);
2933 osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
2935 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
2937 outp->totalParms = 2;
2938 outp->totalData = 0;
2940 userp = smb_GetTran2User(vcp, p);
2942 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
2943 code = CM_ERROR_BADSMB;
2949 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2951 unsigned int attribute;
2954 /* lock the vnode with a callback; we need the current status
2955 * to determine what the new status is, in some cases.
2957 lock_ObtainMutex(&scp->mx);
2958 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2959 CM_SCACHESYNC_GETSTATUS
2960 | CM_SCACHESYNC_NEEDCALLBACK);
2962 lock_ReleaseMutex(&scp->mx);
2966 /* prepare for setattr call */
2969 lastMod = *((FILETIME *)(p->datap + 16));
2970 /* when called as result of move a b, lastMod is (-1, -1).
2971 * If the check for -1 is not present, timestamp
2972 * of the resulting file will be 1969 (-1)
2974 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
2975 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
2976 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
2977 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
2979 fidp->flags |= SMB_FID_MTIMESETDONE;
2982 attribute = *((u_long *)(p->datap + 32));
2983 if (attribute != 0) {
2984 if ((scp->unixModeBits & 0222)
2985 && (attribute & 1) != 0) {
2986 /* make a writable file read-only */
2987 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2988 attr.unixModeBits = scp->unixModeBits & ~0222;
2990 else if ((scp->unixModeBits & 0222) == 0
2991 && (attribute & 1) == 0) {
2992 /* make a read-only file writable */
2993 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2994 attr.unixModeBits = scp->unixModeBits | 0222;
2997 lock_ReleaseMutex(&scp->mx);
3001 code = cm_SetAttr(scp, &attr, userp, &req);
3005 else if (infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3006 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3009 attr.mask = CM_ATTRMASK_LENGTH;
3010 attr.length.LowPart = size.LowPart;
3011 attr.length.HighPart = size.HighPart;
3012 code = cm_SetAttr(scp, &attr, userp, &req);
3014 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3015 if (*((char *)(p->datap))) {
3016 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3019 fidp->flags |= SMB_FID_DELONCLOSE;
3023 fidp->flags &= ~SMB_FID_DELONCLOSE;
3028 cm_ReleaseUser(userp);
3029 smb_ReleaseFID(fidp);
3031 smb_SendTran2Packet(vcp, outp, op);
3033 smb_SendTran2Error(vcp, p, op, code);
3034 smb_FreeTran2Packet(outp);
3040 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3042 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3043 return CM_ERROR_BADOP;
3047 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3049 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3050 return CM_ERROR_BADOP;
3054 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3056 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3057 return CM_ERROR_BADOP;
3061 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3063 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3064 return CM_ERROR_BADOP;
3068 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3070 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3071 return CM_ERROR_BADOP;
3075 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3077 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3078 return CM_ERROR_BADOP;
3082 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3084 /* This is a UNICODE only request (bit15 of Flags2) */
3085 /* The TID must be IPC$ */
3087 /* The documentation for the Flags response field is contradictory */
3089 /* Use Version 1 Referral Element Format */
3090 /* ServerType = 0; indicates the next server should be queried for the file */
3091 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3092 /* Node = UnicodeString of UNC path of the next share name */
3094 osi_Log0(smb_logp,"ReceiveTran2GetDFSReferral - NOT_SUPPORTED");
3095 return CM_ERROR_BADOP;
3099 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3101 /* This is a UNICODE only request (bit15 of Flags2) */
3103 /* There is nothing we can do about this operation. The client is going to
3104 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3105 * Unfortunately, there is really nothing we can do about it other then log it
3106 * somewhere. Even then I don't think there is anything for us to do.
3107 * So let's return an error value.
3110 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3111 return CM_ERROR_BADOP;
3115 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3116 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3121 cm_scache_t *targetScp; /* target if scp is a symlink */
3126 unsigned short attr;
3127 unsigned long lattr;
3128 smb_dirListPatch_t *patchp;
3129 smb_dirListPatch_t *npatchp;
3131 for(patchp = *dirPatchespp; patchp; patchp =
3132 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3133 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3135 lock_ObtainMutex(&scp->mx);
3136 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3137 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3139 lock_ReleaseMutex(&scp->mx);
3140 cm_ReleaseSCache(scp);
3142 dptr = patchp->dptr;
3144 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3145 errors in the client. */
3146 if (infoLevel >= 0x101) {
3147 /* 1969-12-31 23:59:59 +00 */
3148 ft.dwHighDateTime = 0x19DB200;
3149 ft.dwLowDateTime = 0x5BB78980;
3151 /* copy to Creation Time */
3152 *((FILETIME *)dptr) = ft;
3155 /* copy to Last Access Time */
3156 *((FILETIME *)dptr) = ft;
3159 /* copy to Last Write Time */
3160 *((FILETIME *)dptr) = ft;
3163 /* copy to Change Time */
3164 *((FILETIME *)dptr) = ft;
3167 /* merge in hidden attribute */
3168 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3169 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3173 /* 1969-12-31 23:59:58 +00*/
3174 dosTime = 0xEBBFBF7D;
3176 /* and copy out date */
3177 shortTemp = (dosTime>>16) & 0xffff;
3178 *((u_short *)dptr) = shortTemp;
3181 /* copy out creation time */
3182 shortTemp = dosTime & 0xffff;
3183 *((u_short *)dptr) = shortTemp;
3186 /* and copy out date */
3187 shortTemp = (dosTime>>16) & 0xffff;
3188 *((u_short *)dptr) = shortTemp;
3191 /* copy out access time */
3192 shortTemp = dosTime & 0xffff;
3193 *((u_short *)dptr) = shortTemp;
3196 /* and copy out date */
3197 shortTemp = (dosTime>>16) & 0xffff;
3198 *((u_short *)dptr) = shortTemp;
3201 /* copy out mod time */
3202 shortTemp = dosTime & 0xffff;
3203 *((u_short *)dptr) = shortTemp;
3206 /* merge in hidden (dot file) attribute */
3207 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3208 attr = SMB_ATTR_HIDDEN;
3209 *dptr++ = attr & 0xff;
3210 *dptr++ = (attr >> 8) & 0xff;
3216 /* now watch for a symlink */
3218 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3219 lock_ReleaseMutex(&scp->mx);
3220 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3222 /* we have a more accurate file to use (the
3223 * target of the symbolic link). Otherwise,
3224 * we'll just use the symlink anyway.
3226 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3228 cm_ReleaseSCache(scp);
3231 lock_ObtainMutex(&scp->mx);
3234 dptr = patchp->dptr;
3236 if (infoLevel >= 0x101) {
3238 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3240 /* copy to Creation Time */
3241 *((FILETIME *)dptr) = ft;
3244 /* copy to Last Access Time */
3245 *((FILETIME *)dptr) = ft;
3248 /* copy to Last Write Time */
3249 *((FILETIME *)dptr) = ft;
3252 /* copy to Change Time */
3253 *((FILETIME *)dptr) = ft;
3256 /* Use length for both file length and alloc length */
3257 *((LARGE_INTEGER *)dptr) = scp->length;
3259 *((LARGE_INTEGER *)dptr) = scp->length;
3262 /* Copy attributes */
3263 lattr = smb_ExtAttributes(scp);
3264 /* merge in hidden (dot file) attribute */
3265 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3266 lattr |= SMB_ATTR_HIDDEN;
3267 *((u_long *)dptr) = lattr;
3272 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3274 /* and copy out date */
3275 shortTemp = (dosTime>>16) & 0xffff;
3276 *((u_short *)dptr) = shortTemp;
3279 /* copy out creation time */
3280 shortTemp = dosTime & 0xffff;
3281 *((u_short *)dptr) = shortTemp;
3284 /* and copy out date */
3285 shortTemp = (dosTime>>16) & 0xffff;
3286 *((u_short *)dptr) = shortTemp;
3289 /* copy out access time */
3290 shortTemp = dosTime & 0xffff;
3291 *((u_short *)dptr) = shortTemp;
3294 /* and copy out date */
3295 shortTemp = (dosTime>>16) & 0xffff;
3296 *((u_short *)dptr) = shortTemp;
3299 /* copy out mod time */
3300 shortTemp = dosTime & 0xffff;
3301 *((u_short *)dptr) = shortTemp;
3304 /* copy out file length and alloc length,
3305 * using the same for both
3307 *((u_long *)dptr) = scp->length.LowPart;
3309 *((u_long *)dptr) = scp->length.LowPart;
3312 /* finally copy out attributes as short */
3313 attr = smb_Attributes(scp);
3314 /* merge in hidden (dot file) attribute */
3315 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3316 attr |= SMB_ATTR_HIDDEN;
3317 *dptr++ = attr & 0xff;
3318 *dptr++ = (attr >> 8) & 0xff;
3321 lock_ReleaseMutex(&scp->mx);
3322 cm_ReleaseSCache(scp);
3325 /* now free the patches */
3326 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3327 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3331 /* and mark the list as empty */
3332 *dirPatchespp = NULL;
3337 #ifndef USE_OLD_MATCHING
3338 // char table for case insensitive comparison
3339 char mapCaseTable[256];
3341 VOID initUpperCaseTable(VOID)
3344 for (i = 0; i < 256; ++i)
3345 mapCaseTable[i] = toupper(i);
3346 // make '"' match '.'
3347 mapCaseTable[(int)'"'] = toupper('.');
3348 // make '<' match '*'
3349 mapCaseTable[(int)'<'] = toupper('*');
3350 // make '>' match '?'
3351 mapCaseTable[(int)'>'] = toupper('?');
3354 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3356 // Note : this procedure works recursively calling itself.
3358 // PSZ pattern : string containing metacharacters.
3359 // PSZ name : file name to be compared with 'pattern'.
3361 // BOOL : TRUE/FALSE (match/mistmatch)
3364 szWildCardMatchFileName(PSZ pattern, PSZ name)
3366 PSZ pename; // points to the last 'name' character
3368 pename = name + strlen(name) - 1;
3378 if (*pattern == '\0')
3380 for (p = pename; p >= name; --p) {
3381 if ((mapCaseTable[*p] == mapCaseTable[*pattern]) &&
3382 szWildCardMatchFileName(pattern + 1, p + 1))
3387 if (mapCaseTable[*name] != mapCaseTable[*pattern])
3394 if (*pattern == '\0' || *pattern == '*' && *(pattern+1) == '\0')
3400 /* do a case-folding search of the star name mask with the name in namep.
3401 * Return 1 if we match, otherwise 0.
3403 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3406 int i, j, star, qmark, retval;
3408 /* make sure we only match 8.3 names, if requested */
3409 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3412 /* optimize the pattern:
3413 * if there is a mixture of '?' and '*',
3414 * for example the sequence "*?*?*?*"
3415 * must be turned into the form "*"
3417 newmask = (char *)malloc(strlen(maskp)+1);
3418 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3419 switch ( maskp[i] ) {
3431 } else if ( qmark ) {
3435 newmask[j++] = maskp[i];
3442 } else if ( qmark ) {
3446 newmask[j++] = '\0';
3448 retval = szWildCardMatchFileName(newmask, namep) ? 1:0;
3454 #else /* USE_OLD_MATCHING */
3455 /* do a case-folding search of the star name mask with the name in namep.
3456 * Return 1 if we match, otherwise 0.
3458 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3460 unsigned char tcp1, tcp2; /* Pattern characters */
3461 unsigned char tcn1; /* Name characters */
3462 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3463 char *starNamep, *starMaskp;
3464 static char nullCharp[] = {0};
3465 int casefold = flags & CM_FLAG_CASEFOLD;
3467 /* make sure we only match 8.3 names, if requested */
3468 req8dot3 = (flags & CM_FLAG_8DOT3);
3469 if (req8dot3 && !cm_Is8Dot3(namep))
3474 /* Next pattern character */
3477 /* Next name character */
3481 /* 0 - end of pattern */
3487 else if (tcp1 == '.' || tcp1 == '"') {
3497 * first dot in pattern;
3498 * must match dot or end of name
3503 else if (tcn1 == '.') {
3512 else if (tcp1 == '?') {
3513 if (tcn1 == 0 || tcn1 == '.')
3518 else if (tcp1 == '>') {
3519 if (tcn1 != 0 && tcn1 != '.')
3523 else if (tcp1 == '*' || tcp1 == '<') {
3527 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3528 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3543 * pattern character after '*' is not null or
3544 * period. If it is '?' or '>', we are not
3545 * going to understand it. If it is '*' or
3546 * '<', we are going to skip over it. None of
3547 * these are likely, I hope.
3549 /* skip over '*' and '<' */
3550 while (tcp2 == '*' || tcp2 == '<')
3553 /* skip over characters that don't match tcp2 */
3554 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
3555 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
3556 (!casefold && tcn1 != tcp2)))
3560 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3563 /* Remember where we are */
3573 /* tcp1 is not a wildcard */
3574 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
3575 (!casefold && tcn1 == tcp1)) {
3580 /* if trying to match a star pattern, go back */
3582 maskp = starMaskp - 2;
3583 namep = starNamep + 1;
3592 #endif /* USE_OLD_MATCHING */
3594 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3603 smb_dirListPatch_t *dirListPatchesp;
3604 smb_dirListPatch_t *curPatchp;
3607 long orbytes; /* # of bytes in this output record */
3608 long ohbytes; /* # of bytes, except file name */
3609 long onbytes; /* # of bytes in name, incl. term. null */
3610 osi_hyper_t dirLength;
3611 osi_hyper_t bufferOffset;
3612 osi_hyper_t curOffset;
3614 smb_dirSearch_t *dsp;
3618 cm_pageHeader_t *pageHeaderp;
3619 cm_user_t *userp = NULL;
3622 long nextEntryCookie;
3623 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3624 char *op; /* output data ptr */
3625 char *origOp; /* original value of op */
3626 cm_space_t *spacep; /* for pathname buffer */
3627 long maxReturnData; /* max # of return data */
3628 long maxReturnParms; /* max # of return parms */
3629 long bytesInBuffer; /* # data bytes in the output buffer */
3631 char *maskp; /* mask part of path */
3635 smb_tran2Packet_t *outp; /* response packet */
3638 char shortName[13]; /* 8.3 name if needed */
3649 if (p->opcode == 1) {
3650 /* find first; obtain basic parameters from request */
3651 attribute = p->parmsp[0];
3652 maxCount = p->parmsp[1];
3653 infoLevel = p->parmsp[3];
3654 searchFlags = p->parmsp[2];
3655 dsp = smb_NewDirSearch(1);
3656 dsp->attribute = attribute;
3657 pathp = ((char *) p->parmsp) + 12; /* points to path */
3658 if (smb_StoreAnsiFilenames)
3659 OemToChar(pathp,pathp);
3661 maskp = strrchr(pathp, '\\');
3665 maskp++; /* skip over backslash */
3666 strcpy(dsp->mask, maskp); /* and save mask */
3667 /* track if this is likely to match a lot of entries */
3668 starPattern = smb_V3IsStarMask(maskp);
3671 osi_assert(p->opcode == 2);
3672 /* find next; obtain basic parameters from request or open dir file */
3673 dsp = smb_FindDirSearch(p->parmsp[0]);
3675 return CM_ERROR_BADFD;
3676 attribute = dsp->attribute;
3677 maxCount = p->parmsp[1];
3678 infoLevel = p->parmsp[2];
3679 searchFlags = p->parmsp[5];
3681 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
3683 starPattern = 1; /* assume, since required a Find Next */
3687 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
3688 attribute, infoLevel, maxCount, searchFlags);
3690 osi_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
3691 p->opcode, nextCookie);
3693 if (infoLevel >= 0x101)
3694 searchFlags &= ~4; /* no resume keys */
3696 dirListPatchesp = NULL;
3698 maxReturnData = p->maxReturnData;
3699 if (p->opcode == 1) /* find first */
3700 maxReturnParms = 10; /* bytes */
3702 maxReturnParms = 8; /* bytes */
3704 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
3705 if (maxReturnData > 6000)
3706 maxReturnData = 6000;
3707 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
3709 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
3712 osi_Log1(smb_logp, "T2 receive search dir %s",
3713 osi_LogSaveString(smb_logp, pathp));
3715 /* bail out if request looks bad */
3716 if (p->opcode == 1 && !pathp) {
3717 smb_ReleaseDirSearch(dsp);
3718 smb_FreeTran2Packet(outp);
3719 return CM_ERROR_BADSMB;
3722 osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
3723 nextCookie, dsp->cookie);
3725 userp = smb_GetTran2User(vcp, p);
3727 osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p->uid);
3728 smb_ReleaseDirSearch(dsp);
3729 smb_FreeTran2Packet(outp);
3730 return CM_ERROR_BADSMB;
3733 /* try to get the vnode for the path name next */
3734 lock_ObtainMutex(&dsp->mx);
3741 spacep = cm_GetSpace();
3742 smb_StripLastComponent(spacep->data, NULL, pathp);
3743 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3745 lock_ReleaseMutex(&dsp->mx);
3746 cm_ReleaseUser(userp);
3747 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
3748 smb_FreeTran2Packet(outp);
3749 smb_DeleteDirSearch(dsp);
3750 smb_ReleaseDirSearch(dsp);
3753 code = cm_NameI(cm_rootSCachep, spacep->data,
3754 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3755 userp, tidPathp, &req, &scp);
3756 cm_FreeSpace(spacep);
3760 cm_ReleaseSCache(dsp->scp);
3762 /* we need one hold for the entry we just stored into,
3763 * and one for our own processing. When we're done
3764 * with this function, we'll drop the one for our own
3765 * processing. We held it once from the namei call,
3766 * and so we do another hold now.
3769 lock_ObtainMutex(&scp->mx);
3770 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
3771 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3772 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3773 dsp->flags |= SMB_DIRSEARCH_BULKST;
3775 lock_ReleaseMutex(&scp->mx);
3778 lock_ReleaseMutex(&dsp->mx);
3780 cm_ReleaseUser(userp);
3781 smb_FreeTran2Packet(outp);
3782 smb_DeleteDirSearch(dsp);
3783 smb_ReleaseDirSearch(dsp);
3787 /* get the directory size */
3788 lock_ObtainMutex(&scp->mx);
3789 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3790 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3792 lock_ReleaseMutex(&scp->mx);
3793 cm_ReleaseSCache(scp);
3794 cm_ReleaseUser(userp);
3795 smb_FreeTran2Packet(outp);
3796 smb_DeleteDirSearch(dsp);
3797 smb_ReleaseDirSearch(dsp);
3802 dirLength = scp->length;
3804 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3805 curOffset.HighPart = 0;
3806 curOffset.LowPart = nextCookie;
3807 origOp = outp->datap;
3815 if (searchFlags & 4)
3816 /* skip over resume key */
3819 /* make sure that curOffset.LowPart doesn't point to the first
3820 * 32 bytes in the 2nd through last dir page, and that it doesn't
3821 * point at the first 13 32-byte chunks in the first dir page,
3822 * since those are dir and page headers, and don't contain useful
3825 temp = curOffset.LowPart & (2048-1);
3826 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3827 /* we're in the first page */
3828 if (temp < 13*32) temp = 13*32;
3831 /* we're in a later dir page */
3832 if (temp < 32) temp = 32;
3835 /* make sure the low order 5 bits are zero */
3838 /* now put temp bits back ito curOffset.LowPart */
3839 curOffset.LowPart &= ~(2048-1);
3840 curOffset.LowPart |= temp;
3842 /* check if we've passed the dir's EOF */
3843 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
3848 /* check if we've returned all the names that will fit in the
3849 * response packet; we check return count as well as the number
3850 * of bytes requested. We check the # of bytes after we find
3851 * the dir entry, since we'll need to check its size.
3853 if (returnedNames >= maxCount) {
3857 /* see if we can use the bufferp we have now; compute in which
3858 * page the current offset would be, and check whether that's
3859 * the offset of the buffer we have. If not, get the buffer.
3861 thyper.HighPart = curOffset.HighPart;
3862 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3863 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3866 buf_Release(bufferp);
3869 lock_ReleaseMutex(&scp->mx);
3870 lock_ObtainRead(&scp->bufCreateLock);
3871 code = buf_Get(scp, &thyper, &bufferp);
3872 lock_ReleaseRead(&scp->bufCreateLock);
3873 lock_ObtainMutex(&dsp->mx);
3875 /* now, if we're doing a star match, do bulk fetching
3876 * of all of the status info for files in the dir.
3879 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
3882 lock_ObtainMutex(&scp->mx);
3883 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3884 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
3885 /* Don't bulk stat if risking timeout */
3886 int now = GetCurrentTime();
3887 if (now - req.startTime > 5000) {
3888 scp->bulkStatProgress = thyper;
3889 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3890 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3892 cm_TryBulkStat(scp, &thyper, userp, &req);
3895 lock_ObtainMutex(&scp->mx);
3897 lock_ReleaseMutex(&dsp->mx);
3901 bufferOffset = thyper;
3903 /* now get the data in the cache */
3905 code = cm_SyncOp(scp, bufferp, userp, &req,
3907 CM_SCACHESYNC_NEEDCALLBACK
3908 | CM_SCACHESYNC_READ);
3911 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3913 /* otherwise, load the buffer and try again */
3914 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3919 buf_Release(bufferp);
3923 } /* if (wrong buffer) ... */
3925 /* now we have the buffer containing the entry we're interested
3926 * in; copy it out if it represents a non-deleted entry.
3928 entryInDir = curOffset.LowPart & (2048-1);
3929 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3931 /* page header will help tell us which entries are free. Page
3932 * header can change more often than once per buffer, since
3933 * AFS 3 dir page size may be less than (but not more than)
3934 * a buffer package buffer.
3936 /* only look intra-buffer */
3937 temp = curOffset.LowPart & (buf_bufferSize - 1);
3938 temp &= ~(2048 - 1); /* turn off intra-page bits */
3939 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3941 /* now determine which entry we're looking at in the page.
3942 * If it is free (there's a free bitmap at the start of the
3943 * dir), we should skip these 32 bytes.
3945 slotInPage = (entryInDir & 0x7e0) >> 5;
3946 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
3947 (1 << (slotInPage & 0x7)))) {
3948 /* this entry is free */
3949 numDirChunks = 1; /* only skip this guy */
3953 tp = bufferp->datap + entryInBuffer;
3954 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3956 /* while we're here, compute the next entry's location, too,
3957 * since we'll need it when writing out the cookie into the dir
3960 * XXXX Probably should do more sanity checking.
3962 numDirChunks = cm_NameEntries(dep->name, &onbytes);
3964 /* compute offset of cookie representing next entry */
3965 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3967 /* Need 8.3 name? */
3969 if (infoLevel == SMB_QUERY_FILE_NAME_INFO
3970 && dep->fid.vnode != 0
3971 && !cm_Is8Dot3(dep->name)) {
3972 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3976 /* When matching, we are using doing a case fold if we have a wildcard mask.
3977 * If we get a non-wildcard match, it's a lookup for a specific file.
3979 if (dep->fid.vnode != 0 &&
3980 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
3982 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
3984 /* Eliminate entries that don't match requested attributes */
3985 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
3986 smb_IsDotFile(dep->name))
3987 goto nextEntry; /* no hidden files */
3989 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3991 /* We have already done the cm_TryBulkStat above */
3992 fid.cell = scp->fid.cell;
3993 fid.volume = scp->fid.volume;
3994 fid.vnode = ntohl(dep->fid.vnode);
3995 fid.unique = ntohl(dep->fid.unique);
3996 fileType = cm_FindFileType(&fid);
3997 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
3998 "has filetype %d", dep->name,
4000 if (fileType == CM_SCACHETYPE_DIRECTORY)
4004 /* finally check if this name will fit */
4006 /* standard dir entry stuff */
4007 if (infoLevel < 0x101)
4008 ohbytes = 23; /* pre-NT */
4009 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
4010 ohbytes = 12; /* NT names only */
4012 ohbytes = 64; /* NT */
4014 if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
4015 ohbytes += 26; /* Short name & length */
4017 if (searchFlags & 4) {
4018 ohbytes += 4; /* if resume key required */
4022 && infoLevel != 0x101
4023 && infoLevel != 0x103)
4024 ohbytes += 4; /* EASIZE */
4026 /* add header to name & term. null */
4027 orbytes = onbytes + ohbytes + 1;
4029 /* now, we round up the record to a 4 byte alignment,
4030 * and we make sure that we have enough room here for
4031 * even the aligned version (so we don't have to worry
4032 * about an * overflow when we pad things out below).
4033 * That's the reason for the alignment arithmetic below.
4035 if (infoLevel >= 0x101)
4036 align = (4 - (orbytes & 3)) & 3;
4039 if (orbytes + bytesInBuffer + align > maxReturnData)
4042 /* this is one of the entries to use: it is not deleted
4043 * and it matches the star pattern we're looking for.
4044 * Put out the name, preceded by its length.
4046 /* First zero everything else */
4047 memset(origOp, 0, ohbytes);
4049 if (infoLevel <= 0x101)
4050 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4051 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
4052 *((u_long *)(op + 8)) = onbytes;
4054 *((u_long *)(op + 60)) = onbytes;
4055 strcpy(origOp+ohbytes, dep->name);
4056 if (smb_StoreAnsiFilenames)
4057 CharToOem(origOp+ohbytes, origOp+ohbytes);
4059 /* Short name if requested and needed */
4060 if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
4061 if (NeedShortName) {
4062 strcpy(op + 70, shortName);
4063 if (smb_StoreAnsiFilenames)
4064 CharToOem(op + 70, op + 70);
4065 *(op + 68) = shortNameEnd - shortName;
4069 /* now, adjust the # of entries copied */
4072 /* NextEntryOffset and FileIndex */
4073 if (infoLevel >= 101) {
4074 int entryOffset = orbytes + align;
4075 *((u_long *)op) = entryOffset;
4076 *((u_long *)(op+4)) = nextEntryCookie;
4079 /* now we emit the attribute. This is tricky, since
4080 * we need to really stat the file to find out what
4081 * type of entry we've got. Right now, we're copying
4082 * out data from a buffer, while holding the scp
4083 * locked, so it isn't really convenient to stat
4084 * something now. We'll put in a place holder
4085 * now, and make a second pass before returning this
4086 * to get the real attributes. So, we just skip the
4087 * data for now, and adjust it later. We allocate a
4088 * patch record to make it easy to find this point
4089 * later. The replay will happen at a time when it is
4090 * safe to unlock the directory.
4092 if (infoLevel != 0x103) {
4093 curPatchp = malloc(sizeof(*curPatchp));
4094 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4096 curPatchp->dptr = op;
4097 if (infoLevel >= 0x101)
4098 curPatchp->dptr += 8;
4100 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4101 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4104 curPatchp->flags = 0;
4106 curPatchp->fid.cell = scp->fid.cell;
4107 curPatchp->fid.volume = scp->fid.volume;
4108 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4109 curPatchp->fid.unique = ntohl(dep->fid.unique);
4112 curPatchp->dep = dep;
4115 if (searchFlags & 4)
4116 /* put out resume key */
4117 *((u_long *)origOp) = nextEntryCookie;
4119 /* Adjust byte ptr and count */
4120 origOp += orbytes; /* skip entire record */
4121 bytesInBuffer += orbytes;
4123 /* and pad the record out */
4124 while (--align >= 0) {
4128 } /* if we're including this name */
4129 else if (!NeedShortName &&
4132 dep->fid.vnode != 0 &&
4133 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4134 /* We were looking for exact matches, but here's an inexact one*/
4139 /* and adjust curOffset to be where the new cookie is */
4140 thyper.HighPart = 0;
4141 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4142 curOffset = LargeIntegerAdd(thyper, curOffset);
4143 } /* while copying data for dir listing */
4145 /* If we didn't get a star pattern, we did an exact match during the first pass.
4146 * If there were no exact matches found, we fail over to inexact matches by
4147 * marking the query as a star pattern (matches all case permutations), and
4148 * re-running the query.
4150 if (returnedNames == 0 && !starPattern && foundInexact) {
4151 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4156 /* release the mutex */
4157 lock_ReleaseMutex(&scp->mx);
4158 if (bufferp) buf_Release(bufferp);
4160 /* apply and free last set of patches; if not doing a star match, this
4161 * will be empty, but better safe (and freeing everything) than sorry.
4163 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4166 /* now put out the final parameters */
4167 if (returnedNames == 0) eos = 1;
4168 if (p->opcode == 1) {
4170 outp->parmsp[0] = (unsigned short) dsp->cookie;
4171 outp->parmsp[1] = returnedNames;
4172 outp->parmsp[2] = eos;
4173 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4174 outp->parmsp[4] = 0;
4175 /* don't need last name to continue
4176 * search, cookie is enough. Normally,
4177 * this is the offset of the file name
4178 * of the last entry returned.
4180 outp->totalParms = 10; /* in bytes */
4184 outp->parmsp[0] = returnedNames;
4185 outp->parmsp[1] = eos;
4186 outp->parmsp[2] = 0; /* EAS error */
4187 outp->parmsp[3] = 0; /* last name, as above */
4188 outp->totalParms = 8; /* in bytes */
4191 /* return # of bytes in the buffer */
4192 outp->totalData = bytesInBuffer;
4194 osi_Log2(smb_logp, "T2 search dir done, %d names, code %d",
4195 returnedNames, code);
4197 /* Return error code if unsuccessful on first request */
4198 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4199 code = CM_ERROR_NOSUCHFILE;
4201 /* if we're supposed to close the search after this request, or if
4202 * we're supposed to close the search if we're done, and we're done,
4203 * or if something went wrong, close the search.
4205 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4206 if ((searchFlags & 1) || (returnedNames == 0) ||
4207 ((searchFlags & 2) && eos) || code != 0)
4208 smb_DeleteDirSearch(dsp);
4210 smb_SendTran2Error(vcp, p, opx, code);
4212 smb_SendTran2Packet(vcp, outp, opx);
4214 smb_FreeTran2Packet(outp);
4215 smb_ReleaseDirSearch(dsp);
4216 cm_ReleaseSCache(scp);
4217 cm_ReleaseUser(userp);
4221 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4224 smb_dirSearch_t *dsp;
4226 dirHandle = smb_GetSMBParm(inp, 0);
4228 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4230 dsp = smb_FindDirSearch(dirHandle);
4233 return CM_ERROR_BADFD;
4235 /* otherwise, we have an FD to destroy */
4236 smb_DeleteDirSearch(dsp);
4237 smb_ReleaseDirSearch(dsp);
4239 /* and return results */
4240 smb_SetSMBDataLength(outp, 0);
4245 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4247 smb_SetSMBDataLength(outp, 0);
4251 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4258 cm_scache_t *dscp; /* dir we're dealing with */
4259 cm_scache_t *scp; /* file we're creating */
4261 int initialModeBits;
4271 int parmSlot; /* which parm we're dealing with */
4279 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4280 openFun = smb_GetSMBParm(inp, 8); /* open function */
4281 excl = ((openFun & 3) == 0);
4282 trunc = ((openFun & 3) == 2); /* truncate it */
4283 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4284 openAction = 0; /* tracks what we did */
4286 attributes = smb_GetSMBParm(inp, 5);
4287 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4289 /* compute initial mode bits based on read-only flag in attributes */
4290 initialModeBits = 0666;
4291 if (attributes & 1) initialModeBits &= ~0222;
4293 pathp = smb_GetSMBData(inp, NULL);
4294 if (smb_StoreAnsiFilenames)
4295 OemToChar(pathp,pathp);
4297 spacep = inp->spacep;
4298 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4300 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4301 /* special case magic file name for receiving IOCTL requests
4302 * (since IOCTL calls themselves aren't getting through).
4305 osi_Log0(smb_logp, "IOCTL Open");
4308 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4309 smb_SetupIoctlFid(fidp, spacep);
4311 /* set inp->fid so that later read calls in same msg can find fid */
4312 inp->fid = fidp->fid;
4314 /* copy out remainder of the parms */
4316 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4318 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4319 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4320 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4321 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4322 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4323 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4324 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4325 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4327 /* and the final "always present" stuff */
4328 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4329 /* next write out the "unique" ID */
4330 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4331 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4332 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4333 smb_SetSMBDataLength(outp, 0);
4335 /* and clean up fid reference */
4336 smb_ReleaseFID(fidp);
4340 #ifdef DEBUG_VERBOSE
4342 char *hexp, *asciip;
4343 asciip = (lastNamep ? lastNamep : pathp );
4344 hexp = osi_HexifyString(asciip);
4345 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4349 userp = smb_GetUser(vcp, inp);
4352 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4354 cm_ReleaseUser(userp);
4355 return CM_ERROR_NOSUCHPATH;
4357 code = cm_NameI(cm_rootSCachep, pathp,
4358 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4359 userp, tidPathp, &req, &scp);
4361 code = cm_NameI(cm_rootSCachep, spacep->data,
4362 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4363 userp, tidPathp, &req, &dscp);
4366 cm_ReleaseUser(userp);
4370 /* otherwise, scp points to the parent directory. Do a lookup,
4371 * and truncate the file if we find it, otherwise we create the
4374 if (!lastNamep) lastNamep = pathp;
4376 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
4378 if (code && code != CM_ERROR_NOSUCHFILE) {
4379 cm_ReleaseSCache(dscp);
4380 cm_ReleaseUser(userp);
4385 /* if we get here, if code is 0, the file exists and is represented by
4386 * scp. Otherwise, we have to create it. The dir may be represented
4387 * by dscp, or we may have found the file directly. If code is non-zero,
4391 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
4393 if (dscp) cm_ReleaseSCache(dscp);
4394 cm_ReleaseSCache(scp);
4395 cm_ReleaseUser(userp);
4400 /* oops, file shouldn't be there */
4401 if (dscp) cm_ReleaseSCache(dscp);
4402 cm_ReleaseSCache(scp);
4403 cm_ReleaseUser(userp);
4404 return CM_ERROR_EXISTS;
4408 setAttr.mask = CM_ATTRMASK_LENGTH;
4409 setAttr.length.LowPart = 0;
4410 setAttr.length.HighPart = 0;
4411 code = cm_SetAttr(scp, &setAttr, userp, &req);
4412 openAction = 3; /* truncated existing file */
4414 else openAction = 1; /* found existing file */
4416 else if (!(openFun & 0x10)) {
4417 /* don't create if not found */
4418 if (dscp) cm_ReleaseSCache(dscp);
4419 cm_ReleaseUser(userp);
4420 return CM_ERROR_NOSUCHFILE;
4423 osi_assert(dscp != NULL);
4424 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
4425 osi_LogSaveString(smb_logp, lastNamep));
4426 openAction = 2; /* created file */
4427 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4428 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
4429 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4431 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4432 smb_NotifyChange(FILE_ACTION_ADDED,
4433 FILE_NOTIFY_CHANGE_FILE_NAME,
4434 dscp, lastNamep, NULL, TRUE);
4435 if (!excl && code == CM_ERROR_EXISTS) {
4436 /* not an exclusive create, and someone else tried
4437 * creating it already, then we open it anyway. We
4438 * don't bother retrying after this, since if this next
4439 * fails, that means that the file was deleted after we
4440 * started this call.
4442 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4446 setAttr.mask = CM_ATTRMASK_LENGTH;
4447 setAttr.length.LowPart = 0;
4448 setAttr.length.HighPart = 0;
4449 code = cm_SetAttr(scp, &setAttr, userp, &req);
4451 } /* lookup succeeded */
4455 /* we don't need this any longer */
4456 if (dscp) cm_ReleaseSCache(dscp);
4459 /* something went wrong creating or truncating the file */
4460 if (scp) cm_ReleaseSCache(scp);
4461 cm_ReleaseUser(userp);
4465 /* make sure we're about to open a file */
4466 if (scp->fileType != CM_SCACHETYPE_FILE) {
4467 cm_ReleaseSCache(scp);
4468 cm_ReleaseUser(userp);
4469 return CM_ERROR_ISDIR;
4472 /* now all we have to do is open the file itself */
4473 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4476 /* save a pointer to the vnode */
4479 /* compute open mode */
4480 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
4481 if (openMode == 1 || openMode == 2)
4482 fidp->flags |= SMB_FID_OPENWRITE;
4484 smb_ReleaseFID(fidp);
4486 cm_Open(scp, 0, userp);
4488 /* set inp->fid so that later read calls in same msg can find fid */
4489 inp->fid = fidp->fid;
4491 /* copy out remainder of the parms */
4493 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4494 lock_ObtainMutex(&scp->mx);
4496 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
4497 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4498 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
4499 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
4500 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
4501 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
4502 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4503 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4504 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4506 /* and the final "always present" stuff */
4507 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
4508 /* next write out the "unique" ID */
4509 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
4510 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
4511 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4512 lock_ReleaseMutex(&scp->mx);
4513 smb_SetSMBDataLength(outp, 0);
4515 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
4517 cm_ReleaseUser(userp);
4518 /* leave scp held since we put it in fidp->scp */
4522 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4529 unsigned char LockType;
4530 unsigned short NumberOfUnlocks, NumberOfLocks;
4531 unsigned long Timeout;
4533 LARGE_INTEGER LOffset, LLength;
4534 smb_waitingLock_t *waitingLock;
4541 fid = smb_GetSMBParm(inp, 2);
4542 fid = smb_ChainFID(fid, inp);
4544 fidp = smb_FindFID(vcp, fid, 0);
4545 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4546 return CM_ERROR_BADFD;
4548 /* set inp->fid so that later read calls in same msg can find fid */
4551 userp = smb_GetUser(vcp, inp);
4555 lock_ObtainMutex(&scp->mx);
4556 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4557 CM_SCACHESYNC_NEEDCALLBACK
4558 | CM_SCACHESYNC_GETSTATUS
4559 | CM_SCACHESYNC_LOCK);
4560 if (code) goto doneSync;
4562 LockType = smb_GetSMBParm(inp, 3) & 0xff;
4563 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
4564 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
4565 NumberOfLocks = smb_GetSMBParm(inp, 7);
4567 op = smb_GetSMBData(inp, NULL);
4569 for (i=0; i<NumberOfUnlocks; i++) {
4570 if (LockType & 0x10) {
4572 LOffset.HighPart = *((LONG *)(op + 4));
4573 LOffset.LowPart = *((DWORD *)(op + 8));
4574 LLength.HighPart = *((LONG *)(op + 12));
4575 LLength.LowPart = *((DWORD *)(op + 16));
4579 /* Not Large Files */
4580 LOffset.HighPart = 0;
4581 LOffset.LowPart = *((DWORD *)(op + 2));
4582 LLength.HighPart = 0;
4583 LLength.LowPart = *((DWORD *)(op + 6));
4586 if (LargeIntegerNotEqualToZero(LOffset))
4588 /* Do not check length -- length check done in cm_Unlock */
4590 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
4591 if (code) goto done;
4594 for (i=0; i<NumberOfLocks; i++) {
4595 if (LockType & 0x10) {
4597 LOffset.HighPart = *((LONG *)(op + 4));
4598 LOffset.LowPart = *((DWORD *)(op + 8));
4599 LLength.HighPart = *((LONG *)(op + 12));
4600 LLength.LowPart = *((DWORD *)(op + 16));
4604 /* Not Large Files */
4605 LOffset.HighPart = 0;
4606 LOffset.LowPart = *((DWORD *)(op + 2));
4607 LLength.HighPart = 0;
4608 LLength.LowPart = *((DWORD *)(op + 6));
4611 if (LargeIntegerNotEqualToZero(LOffset))
4613 if (LargeIntegerLessThan(LOffset, scp->length))
4616 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
4617 userp, &req, &lockp);
4618 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
4619 /* Put on waiting list */
4620 waitingLock = malloc(sizeof(smb_waitingLock_t));
4621 waitingLock->vcp = vcp;
4622 waitingLock->inp = smb_CopyPacket(inp);
4623 waitingLock->outp = smb_CopyPacket(outp);
4624 waitingLock->timeRemaining = Timeout;
4625 waitingLock->lockp = lockp;
4626 lock_ObtainWrite(&smb_globalLock);
4627 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
4629 osi_Wakeup((long) &smb_allWaitingLocks);
4630 lock_ReleaseWrite(&smb_globalLock);
4631 /* don't send reply immediately */
4632 outp->flags |= SMB_PACKETFLAG_NOSEND;
4638 /* release any locks acquired before the failure */
4641 smb_SetSMBDataLength(outp, 0);
4643 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
4645 lock_ReleaseMutex(&scp->mx);
4646 cm_ReleaseUser(userp);
4647 smb_ReleaseFID(fidp);
4652 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4664 fid = smb_GetSMBParm(inp, 0);
4665 fid = smb_ChainFID(fid, inp);
4667 fidp = smb_FindFID(vcp, fid, 0);
4668 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4669 return CM_ERROR_BADFD;
4672 userp = smb_GetUser(vcp, inp);
4676 /* otherwise, stat the file */
4677 lock_ObtainMutex(&scp->mx);
4678 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4679 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4680 if (code) goto done;
4682 /* decode times. We need a search time, but the response to this
4683 * call provides the date first, not the time, as returned in the
4684 * searchTime variable. So we take the high-order bits first.
4686 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
4687 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
4688 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
4689 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
4690 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
4691 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
4692 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
4694 /* now handle file size and allocation size */
4695 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
4696 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
4697 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
4698 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
4700 /* file attribute */
4701 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
4703 /* and finalize stuff */
4704 smb_SetSMBDataLength(outp, 0);
4708 lock_ReleaseMutex(&scp->mx);
4709 cm_ReleaseUser(userp);
4710 smb_ReleaseFID(fidp);
4714 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4728 fid = smb_GetSMBParm(inp, 0);
4729 fid = smb_ChainFID(fid, inp);
4731 fidp = smb_FindFID(vcp, fid, 0);
4732 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4733 return CM_ERROR_BADFD;
4736 userp = smb_GetUser(vcp, inp);
4740 /* now prepare to call cm_setattr. This message only sets various times,
4741 * and AFS only implements mtime, and we'll set the mtime if that's
4742 * requested. The others we'll ignore.
4744 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
4746 if (searchTime != 0) {
4747 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
4749 if ( unixTime != -1 ) {
4750 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
4751 attrs.clientModTime = unixTime;
4752 code = cm_SetAttr(scp, &attrs, userp, &req);
4754 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
4756 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
4761 cm_ReleaseUser(userp);
4762 smb_ReleaseFID(fidp);
4767 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4770 long count, finalCount;
4777 fd = smb_GetSMBParm(inp, 2);
4778 count = smb_GetSMBParm(inp, 5);
4779 offset.HighPart = 0; /* too bad */
4780 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
4782 osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
4783 fd, offset.LowPart, count);
4785 fd = smb_ChainFID(fd, inp);
4786 fidp = smb_FindFID(vcp, fd, 0);
4788 return CM_ERROR_BADFD;
4790 /* set inp->fid so that later read calls in same msg can find fid */
4793 if (fidp->flags & SMB_FID_IOCTL) {
4794 return smb_IoctlV3Read(fidp, vcp, inp, outp);
4797 userp = smb_GetUser(vcp, inp);
4799 /* 0 and 1 are reserved for request chaining, were setup by our caller,
4800 * and will be further filled in after we return.
4802 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
4803 smb_SetSMBParm(outp, 3, 0); /* resvd */
4804 smb_SetSMBParm(outp, 4, 0); /* resvd */
4805 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
4806 /* fill in #6 when we have all the parameters' space reserved */
4807 smb_SetSMBParm(outp, 7, 0); /* resv'd */
4808 smb_SetSMBParm(outp, 8, 0); /* resv'd */
4809 smb_SetSMBParm(outp, 9, 0); /* resv'd */
4810 smb_SetSMBParm(outp, 10, 0); /* resv'd */
4811 smb_SetSMBParm(outp, 11, 0); /* reserved */
4813 /* get op ptr after putting in the parms, since otherwise we don't
4814 * know where the data really is.
4816 op = smb_GetSMBData(outp, NULL);
4818 /* now fill in offset from start of SMB header to first data byte (to op) */
4819 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
4821 /* set the packet data length the count of the # of bytes */
4822 smb_SetSMBDataLength(outp, count);
4825 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
4827 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
4830 /* fix some things up */
4831 smb_SetSMBParm(outp, 5, finalCount);
4832 smb_SetSMBDataLength(outp, finalCount);
4834 smb_ReleaseFID(fidp);
4836 cm_ReleaseUser(userp);
4841 * Values for createDisp, copied from NTDDK.H
4843 #define FILE_SUPERSEDE 0 // (???)
4844 #define FILE_OPEN 1 // (open)
4845 #define FILE_CREATE 2 // (exclusive)
4846 #define FILE_OPEN_IF 3 // (non-exclusive)
4847 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
4848 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
4850 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4852 char *pathp, *realPathp;
4856 cm_scache_t *dscp; /* parent dir */
4857 cm_scache_t *scp; /* file to create or open */
4858 cm_scache_t *targetScp; /* if scp is a symlink */
4862 unsigned short nameLength;
4864 unsigned int requestOpLock;
4865 unsigned int requestBatchOpLock;
4866 unsigned int mustBeDir;
4867 unsigned int treeCreate;
4869 unsigned int desiredAccess;
4870 unsigned int extAttributes;
4871 unsigned int createDisp;
4872 unsigned int createOptions;
4873 int initialModeBits;
4874 unsigned short baseFid;
4875 smb_fid_t *baseFidp;
4877 cm_scache_t *baseDirp;
4878 unsigned short openAction;
4893 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
4894 flags = smb_GetSMBOffsetParm(inp, 3, 1)
4895 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
4896 requestOpLock = flags & 0x02;
4897 requestBatchOpLock = flags & 0x04;
4898 mustBeDir = flags & 0x08;
4901 * Why all of a sudden 32-bit FID?
4902 * We will reject all bits higher than 16.
4904 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
4905 return CM_ERROR_INVAL;
4906 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
4907 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
4908 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
4909 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
4910 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
4911 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
4912 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
4913 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
4914 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
4916 /* mustBeDir is never set; createOptions directory bit seems to be
4919 if (createOptions & 1)
4921 else if (createOptions & 0x40)
4927 * compute initial mode bits based on read-only flag in
4928 * extended attributes
4930 initialModeBits = 0666;
4931 if (extAttributes & 1)
4932 initialModeBits &= ~0222;
4934 pathp = smb_GetSMBData(inp, NULL);
4935 /* Sometimes path is not null-terminated, so we make a copy. */
4936 realPathp = malloc(nameLength+1);
4937 memcpy(realPathp, pathp, nameLength);
4938 realPathp[nameLength] = 0;
4939 if (smb_StoreAnsiFilenames)
4940 OemToChar(realPathp,realPathp);
4942 spacep = inp->spacep;
4943 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
4945 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
4946 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
4947 osi_Log2(smb_logp,"... flags=[%x] lastNamep=[%s]", flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
4949 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4950 /* special case magic file name for receiving IOCTL requests
4951 * (since IOCTL calls themselves aren't getting through).
4953 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4954 smb_SetupIoctlFid(fidp, spacep);
4955 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
4957 /* set inp->fid so that later read calls in same msg can find fid */
4958 inp->fid = fidp->fid;
4962 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
4963 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4964 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
4966 memset(&ft, 0, sizeof(ft));
4967 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4968 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4969 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4970 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4971 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
4972 sz.HighPart = 0x7fff; sz.LowPart = 0;
4973 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
4974 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
4975 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
4976 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
4977 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
4978 smb_SetSMBDataLength(outp, 0);
4980 /* clean up fid reference */
4981 smb_ReleaseFID(fidp);
4986 #ifdef DEBUG_VERBOSE
4988 char *hexp, *asciip;
4989 asciip = (lastNamep? lastNamep : realPathp);
4990 hexp = osi_HexifyString( asciip );
4991 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
4995 userp = smb_GetUser(vcp, inp);
4997 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
4999 return CM_ERROR_INVAL;
5003 baseDirp = cm_rootSCachep;
5004 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5005 if (code == CM_ERROR_TIDIPC) {
5006 /* Attempt to use a TID allocated for IPC. The client
5007 * is probably looking for DCE RPC end points which we
5009 osi_Log0(smb_logp, "NTCreateX received IPC TID");
5011 cm_ReleaseUser(userp);
5012 return CM_ERROR_NOSUCHFILE;
5016 baseFidp = smb_FindFID(vcp, baseFid, 0);
5018 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
5020 cm_ReleaseUser(userp);
5021 return CM_ERROR_INVAL;
5023 baseDirp = baseFidp->scp;
5027 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
5029 /* compute open mode */
5031 if (desiredAccess & DELETE)
5032 fidflags |= SMB_FID_OPENDELETE;
5033 if (desiredAccess & AFS_ACCESS_READ)
5034 fidflags |= SMB_FID_OPENREAD;
5035 if (desiredAccess & AFS_ACCESS_WRITE)
5036 fidflags |= SMB_FID_OPENWRITE;
5040 /* For an exclusive create, we want to do a case sensitive match for the last component. */
5041 if ( createDisp == FILE_CREATE ||
5042 createDisp == FILE_OVERWRITE ||
5043 createDisp == FILE_OVERWRITE_IF) {
5044 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5045 userp, tidPathp, &req, &dscp);
5047 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5049 if (code == CM_ERROR_NOSUCHFILE) {
5050 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
5051 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
5052 if (code == 0 && realDirFlag == 1) {
5053 cm_ReleaseSCache(scp);
5054 cm_ReleaseSCache(dscp);
5055 cm_ReleaseUser(userp);
5057 return CM_ERROR_EXISTS;
5063 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5064 userp, tidPathp, &req, &scp);
5069 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
5070 /* look up parent directory */
5071 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
5072 * the immediate parent. We have to work our way up realPathp until we hit something that we
5080 code = cm_NameI(baseDirp, spacep->data,
5081 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5082 userp, tidPathp, &req, &dscp);
5085 (tp = strrchr(spacep->data,'\\')) &&
5086 (createDisp == FILE_CREATE) &&
5087 (realDirFlag == 1)) {
5090 treeStartp = realPathp + (tp - spacep->data);
5092 if (*tp && !smb_IsLegalFilename(tp)) {
5094 smb_ReleaseFID(baseFidp);
5095 cm_ReleaseUser(userp);
5097 return CM_ERROR_BADNTFILENAME;
5107 smb_ReleaseFID(baseFidp);
5110 osi_Log0(smb_logp,"NTCreateX parent not found");
5111 cm_ReleaseUser(userp);
5116 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
5117 /* A file exists where we want a directory. */
5118 cm_ReleaseSCache(dscp);
5119 cm_ReleaseUser(userp);
5121 return CM_ERROR_EXISTS;
5125 lastNamep = realPathp;
5129 if (!smb_IsLegalFilename(lastNamep)) {
5130 cm_ReleaseSCache(dscp);
5131 cm_ReleaseUser(userp);
5133 return CM_ERROR_BADNTFILENAME;
5136 if (!foundscp && !treeCreate) {
5137 if ( createDisp == FILE_CREATE ||
5138 createDisp == FILE_OVERWRITE ||
5139 createDisp == FILE_OVERWRITE_IF)
5141 code = cm_Lookup(dscp, lastNamep,
5142 CM_FLAG_FOLLOW, userp, &req, &scp);
5144 code = cm_Lookup(dscp, lastNamep,
5145 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5148 if (code && code != CM_ERROR_NOSUCHFILE) {
5149 cm_ReleaseSCache(dscp);
5150 cm_ReleaseUser(userp);
5158 smb_ReleaseFID(baseFidp);
5161 /* if we get here, if code is 0, the file exists and is represented by
5162 * scp. Otherwise, we have to create it. The dir may be represented
5163 * by dscp, or we may have found the file directly. If code is non-zero,
5166 if (code == 0 && !treeCreate) {
5167 if (createDisp == FILE_CREATE) {
5168 /* oops, file shouldn't be there */
5169 if (dscp) cm_ReleaseSCache(dscp);
5170 cm_ReleaseSCache(scp);
5171 cm_ReleaseUser(userp);
5173 return CM_ERROR_EXISTS;
5176 if ( createDisp == FILE_OVERWRITE ||
5177 createDisp == FILE_OVERWRITE_IF) {
5178 setAttr.mask = CM_ATTRMASK_LENGTH;
5179 setAttr.length.LowPart = 0;
5180 setAttr.length.HighPart = 0;
5181 /* now watch for a symlink */
5183 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5185 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5187 /* we have a more accurate file to use (the
5188 * target of the symbolic link). Otherwise,
5189 * we'll just use the symlink anyway.
5191 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5193 cm_ReleaseSCache(scp);
5197 code = cm_SetAttr(scp, &setAttr, userp, &req);
5198 openAction = 3; /* truncated existing file */
5201 openAction = 1; /* found existing file */
5203 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
5206 if (dscp) cm_ReleaseSCache(dscp);
5207 cm_ReleaseSCache(scp);
5208 cm_ReleaseUser(userp);
5213 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
5214 /* don't create if not found */
5215 if (dscp) cm_ReleaseSCache(dscp);
5216 cm_ReleaseUser(userp);
5218 return CM_ERROR_NOSUCHFILE;
5220 else if (realDirFlag == 0 || realDirFlag == -1) {
5221 osi_assert(dscp != NULL);
5222 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
5223 osi_LogSaveString(smb_logp, lastNamep));
5224 openAction = 2; /* created file */
5225 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5226 setAttr.clientModTime = time(NULL);
5227 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5229 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5230 smb_NotifyChange(FILE_ACTION_ADDED,
5231 FILE_NOTIFY_CHANGE_FILE_NAME,
5232 dscp, lastNamep, NULL, TRUE);
5233 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
5234 /* Not an exclusive create, and someone else tried
5235 * creating it already, then we open it anyway. We
5236 * don't bother retrying after this, since if this next
5237 * fails, that means that the file was deleted after we
5238 * started this call.
5240 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5243 if (createDisp == FILE_OVERWRITE_IF) {
5244 setAttr.mask = CM_ATTRMASK_LENGTH;
5245 setAttr.length.LowPart = 0;
5246 setAttr.length.HighPart = 0;
5248 /* now watch for a symlink */
5250 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5252 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5254 /* we have a more accurate file to use (the
5255 * target of the symbolic link). Otherwise,
5256 * we'll just use the symlink anyway.
5258 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5260 cm_ReleaseSCache(scp);
5264 code = cm_SetAttr(scp, &setAttr, userp, &req);
5266 } /* lookup succeeded */
5271 char *cp; /* This component */
5272 int clen = 0; /* length of component */
5276 /* create directory */
5278 treeStartp = lastNamep;
5279 osi_assert(dscp != NULL);
5280 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
5281 osi_LogSaveString(smb_logp, treeStartp));
5282 openAction = 2; /* created directory */
5284 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5285 setAttr.clientModTime = time(NULL);
5292 tp = strchr(pp, '\\');
5296 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
5300 strncpy(cp,pp,clen);
5307 continue; /* the supplied path can't have consecutive slashes either , but */
5309 /* cp is the next component to be created. */
5310 code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
5311 if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
5312 smb_NotifyChange(FILE_ACTION_ADDED,
5313 FILE_NOTIFY_CHANGE_DIR_NAME,
5314 tscp, cp, NULL, TRUE);
5316 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
5317 /* Not an exclusive create, and someone else tried
5318 * creating it already, then we open it anyway. We
5319 * don't bother retrying after this, since if this next
5320 * fails, that means that the file was deleted after we
5321 * started this call.
5323 code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
5328 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
5329 cm_ReleaseSCache(tscp);
5330 tscp = scp; /* Newly created directory will be next parent */
5335 * if we get here and code == 0, then scp is the last directory created, and tscp is the
5336 * parent of scp. dscp got released if dscp != tscp. both tscp and scp are held.
5342 /* something went wrong creating or truncating the file */
5343 if (scp) cm_ReleaseSCache(scp);
5344 if (dscp) cm_ReleaseSCache(dscp);
5345 cm_ReleaseUser(userp);
5350 /* make sure we have file vs. dir right (only applies for single component case) */
5351 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5352 /* now watch for a symlink */
5354 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5355 cm_scache_t * targetScp = 0;
5356 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5358 /* we have a more accurate file to use (the
5359 * target of the symbolic link). Otherwise,
5360 * we'll just use the symlink anyway.
5362 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5364 cm_ReleaseSCache(scp);
5369 if (scp->fileType != CM_SCACHETYPE_FILE) {
5370 cm_ReleaseSCache(scp);
5371 cm_ReleaseUser(userp);
5373 return CM_ERROR_ISDIR;
5377 /* (only applies to single component case) */
5378 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5379 cm_ReleaseSCache(scp);
5380 if (dscp) cm_ReleaseSCache(dscp);
5381 cm_ReleaseUser(userp);
5383 return CM_ERROR_NOTDIR;
5386 /* open the file itself */
5387 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5389 /* save a pointer to the vnode */
5392 fidp->flags = fidflags;
5394 /* save parent dir and pathname for delete or change notification */
5395 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5396 fidp->flags |= SMB_FID_NTOPEN;
5397 fidp->NTopen_dscp = dscp;
5398 cm_HoldSCache(dscp);
5399 fidp->NTopen_pathp = strdup(lastNamep);
5401 fidp->NTopen_wholepathp = realPathp;
5403 /* we don't need this any longer */
5404 if (dscp) cm_ReleaseSCache(dscp);
5405 cm_Open(scp, 0, userp);
5407 /* set inp->fid so that later read calls in same msg can find fid */
5408 inp->fid = fidp->fid;
5412 lock_ObtainMutex(&scp->mx);
5413 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5414 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5415 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
5416 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5417 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5418 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5419 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5420 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5421 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
5423 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5424 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5425 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
5426 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
5427 smb_SetSMBParmByte(outp, parmSlot,
5428 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
5429 lock_ReleaseMutex(&scp->mx);
5430 smb_SetSMBDataLength(outp, 0);
5432 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
5433 osi_LogSaveString(smb_logp, realPathp));
5435 smb_ReleaseFID(fidp);
5437 cm_ReleaseUser(userp);
5439 /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
5441 /* leave scp held since we put it in fidp->scp */
5446 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
5447 * Instead, ultimately, would like to use a subroutine for common code.
5449 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5451 char *pathp, *realPathp;
5455 cm_scache_t *dscp; /* parent dir */
5456 cm_scache_t *scp; /* file to create or open */
5457 cm_scache_t *targetScp; /* if scp is a symlink */
5460 unsigned long nameLength;
5462 unsigned int requestOpLock;
5463 unsigned int requestBatchOpLock;
5464 unsigned int mustBeDir;
5465 unsigned int extendedRespRequired;
5467 unsigned int desiredAccess;
5468 #ifdef DEBUG_VERBOSE
5469 unsigned int allocSize;
5470 unsigned int shareAccess;
5472 unsigned int extAttributes;
5473 unsigned int createDisp;
5474 #ifdef DEBUG_VERBOSE
5477 unsigned int createOptions;
5478 int initialModeBits;
5479 unsigned short baseFid;
5480 smb_fid_t *baseFidp;
5482 cm_scache_t *baseDirp;
5483 unsigned short openAction;
5489 int parmOffset, dataOffset;
5500 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
5501 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
5502 parmp = inp->data + parmOffset;
5503 lparmp = (ULONG *) parmp;
5506 requestOpLock = flags & 0x02;
5507 requestBatchOpLock = flags & 0x04;
5508 mustBeDir = flags & 0x08;
5509 extendedRespRequired = flags & 0x10;
5512 * Why all of a sudden 32-bit FID?
5513 * We will reject all bits higher than 16.
5515 if (lparmp[1] & 0xFFFF0000)
5516 return CM_ERROR_INVAL;
5517 baseFid = (unsigned short)lparmp[1];
5518 desiredAccess = lparmp[2];
5519 #ifdef DEBUG_VERBOSE
5520 allocSize = lparmp[3];
5521 #endif /* DEBUG_VERSOSE */
5522 extAttributes = lparmp[5];
5524 shareAccess = lparmp[6];
5526 createDisp = lparmp[7];
5527 createOptions = lparmp[8];
5528 #ifdef DEBUG_VERBOSE
5531 nameLength = lparmp[11];
5533 #ifdef DEBUG_VERBOSE
5534 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
5535 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
5536 osi_Log1(smb_logp,"... flags[%x]",flags);
5539 /* mustBeDir is never set; createOptions directory bit seems to be
5542 if (createOptions & 1)
5544 else if (createOptions & 0x40)
5550 * compute initial mode bits based on read-only flag in
5551 * extended attributes
5553 initialModeBits = 0666;
5554 if (extAttributes & 1)
5555 initialModeBits &= ~0222;
5557 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
5558 /* Sometimes path is not null-terminated, so we make a copy. */
5559 realPathp = malloc(nameLength+1);
5560 memcpy(realPathp, pathp, nameLength);
5561 realPathp[nameLength] = 0;
5562 if (smb_StoreAnsiFilenames)
5563 OemToChar(realPathp,realPathp);
5565 spacep = cm_GetSpace();
5566 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5569 * Nothing here to handle SMB_IOCTL_FILENAME.
5570 * Will add it if necessary.
5573 #ifdef DEBUG_VERBOSE
5575 char *hexp, *asciip;
5576 asciip = (lastNamep? lastNamep : realPathp);
5577 hexp = osi_HexifyString( asciip );
5578 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
5583 userp = smb_GetUser(vcp, inp);
5585 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
5587 return CM_ERROR_INVAL;
5591 baseDirp = cm_rootSCachep;
5592 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5593 if(code == CM_ERROR_TIDIPC) {
5594 /* Attempt to use TID allocated for IPC. The client is
5595 * probably trying to locate DCE RPC endpoints, which we
5597 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
5599 cm_ReleaseUser(userp);
5600 return CM_ERROR_NOSUCHPATH;
5604 baseFidp = smb_FindFID(vcp, baseFid, 0);
5606 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
5608 cm_ReleaseUser(userp);
5609 return CM_ERROR_INVAL;
5611 baseDirp = baseFidp->scp;
5615 /* compute open mode */
5617 if (desiredAccess & DELETE)
5618 fidflags |= SMB_FID_OPENDELETE;
5619 if (desiredAccess & AFS_ACCESS_READ)
5620 fidflags |= SMB_FID_OPENREAD;
5621 if (desiredAccess & AFS_ACCESS_WRITE)
5622 fidflags |= SMB_FID_OPENWRITE;
5626 if ( createDisp == FILE_OPEN ||
5627 createDisp == FILE_OVERWRITE ||
5628 createDisp == FILE_OVERWRITE_IF) {
5629 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5630 userp, tidPathp, &req, &dscp);
5632 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5634 if (code == CM_ERROR_NOSUCHFILE) {
5635 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
5636 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
5637 if (code == 0 && realDirFlag == 1) {
5638 cm_ReleaseSCache(scp);
5639 cm_ReleaseSCache(dscp);
5640 cm_ReleaseUser(userp);
5642 return CM_ERROR_EXISTS;
5648 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5649 userp, tidPathp, &req, &scp);
5655 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
5656 /* look up parent directory */
5658 code = cm_NameI(baseDirp, spacep->data,
5659 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5660 userp, tidPathp, &req, &dscp);
5664 cm_FreeSpace(spacep);
5667 smb_ReleaseFID(baseFidp);
5672 cm_ReleaseUser(userp);
5677 if (!lastNamep) lastNamep = realPathp;
5680 if (!smb_IsLegalFilename(lastNamep))
5681 return CM_ERROR_BADNTFILENAME;
5684 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
5685 code = cm_Lookup(dscp, lastNamep,
5686 CM_FLAG_FOLLOW, userp, &req, &scp);
5688 code = cm_Lookup(dscp, lastNamep,
5689 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5692 if (code && code != CM_ERROR_NOSUCHFILE) {
5693 cm_ReleaseSCache(dscp);
5694 cm_ReleaseUser(userp);
5702 smb_ReleaseFID(baseFidp);
5705 cm_FreeSpace(spacep);
5708 /* if we get here, if code is 0, the file exists and is represented by
5709 * scp. Otherwise, we have to create it. The dir may be represented
5710 * by dscp, or we may have found the file directly. If code is non-zero,
5714 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
5717 if (dscp) cm_ReleaseSCache(dscp);
5718 cm_ReleaseSCache(scp);
5719 cm_ReleaseUser(userp);
5724 if (createDisp == FILE_CREATE) {
5725 /* oops, file shouldn't be there */
5726 if (dscp) cm_ReleaseSCache(dscp);
5727 cm_ReleaseSCache(scp);
5728 cm_ReleaseUser(userp);
5730 return CM_ERROR_EXISTS;
5733 if (createDisp == FILE_OVERWRITE ||
5734 createDisp == FILE_OVERWRITE_IF) {
5735 setAttr.mask = CM_ATTRMASK_LENGTH;
5736 setAttr.length.LowPart = 0;
5737 setAttr.length.HighPart = 0;
5739 /* now watch for a symlink */
5741 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5743 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5745 /* we have a more accurate file to use (the
5746 * target of the symbolic link). Otherwise,
5747 * we'll just use the symlink anyway.
5749 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5751 cm_ReleaseSCache(scp);
5755 code = cm_SetAttr(scp, &setAttr, userp, &req);
5756 openAction = 3; /* truncated existing file */
5758 else openAction = 1; /* found existing file */
5760 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
5761 /* don't create if not found */
5762 if (dscp) cm_ReleaseSCache(dscp);
5763 cm_ReleaseUser(userp);
5765 return CM_ERROR_NOSUCHFILE;
5767 else if (realDirFlag == 0 || realDirFlag == -1) {
5768 osi_assert(dscp != NULL);
5769 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
5770 osi_LogSaveString(smb_logp, lastNamep));
5771 openAction = 2; /* created file */
5772 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5773 setAttr.clientModTime = time(NULL);
5774 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5776 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5777 smb_NotifyChange(FILE_ACTION_ADDED,
5778 FILE_NOTIFY_CHANGE_FILE_NAME,
5779 dscp, lastNamep, NULL, TRUE);
5780 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
5781 /* Not an exclusive create, and someone else tried
5782 * creating it already, then we open it anyway. We
5783 * don't bother retrying after this, since if this next
5784 * fails, that means that the file was deleted after we
5785 * started this call.
5787 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5790 if (createDisp == FILE_OVERWRITE_IF) {
5791 setAttr.mask = CM_ATTRMASK_LENGTH;
5792 setAttr.length.LowPart = 0;
5793 setAttr.length.HighPart = 0;
5795 /* now watch for a symlink */
5797 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5799 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5801 /* we have a more accurate file to use (the
5802 * target of the symbolic link). Otherwise,
5803 * we'll just use the symlink anyway.
5805 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5807 cm_ReleaseSCache(scp);
5811 code = cm_SetAttr(scp, &setAttr, userp, &req);
5813 } /* lookup succeeded */
5817 /* create directory */
5818 osi_assert(dscp != NULL);
5820 "smb_ReceiveNTTranCreate creating directory %s",
5821 osi_LogSaveString(smb_logp, lastNamep));
5822 openAction = 2; /* created directory */
5823 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5824 setAttr.clientModTime = time(NULL);
5825 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5826 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5827 smb_NotifyChange(FILE_ACTION_ADDED,
5828 FILE_NOTIFY_CHANGE_DIR_NAME,
5829 dscp, lastNamep, NULL, TRUE);
5831 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
5832 /* Not an exclusive create, and someone else tried
5833 * creating it already, then we open it anyway. We
5834 * don't bother retrying after this, since if this next
5835 * fails, that means that the file was deleted after we
5836 * started this call.
5838 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5844 /* something went wrong creating or truncating the file */
5845 if (scp) cm_ReleaseSCache(scp);
5846 cm_ReleaseUser(userp);
5851 /* make sure we have file vs. dir right */
5852 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5853 /* now watch for a symlink */
5855 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5857 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5859 /* we have a more accurate file to use (the
5860 * target of the symbolic link). Otherwise,
5861 * we'll just use the symlink anyway.
5863 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5865 cm_ReleaseSCache(scp);
5870 if (scp->fileType != CM_SCACHETYPE_FILE) {
5871 cm_ReleaseSCache(scp);
5872 cm_ReleaseUser(userp);
5874 return CM_ERROR_ISDIR;
5878 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5879 cm_ReleaseSCache(scp);
5880 cm_ReleaseUser(userp);
5882 return CM_ERROR_NOTDIR;
5885 /* open the file itself */
5886 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5889 /* save a pointer to the vnode */
5892 fidp->flags = fidflags;
5894 /* save parent dir and pathname for deletion or change notification */
5895 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5896 fidp->flags |= SMB_FID_NTOPEN;
5897 fidp->NTopen_dscp = dscp;
5898 cm_HoldSCache(dscp);
5899 fidp->NTopen_pathp = strdup(lastNamep);
5901 fidp->NTopen_wholepathp = realPathp;
5903 /* we don't need this any longer */
5904 if (dscp) cm_ReleaseSCache(dscp);
5906 cm_Open(scp, 0, userp);
5908 /* set inp->fid so that later read calls in same msg can find fid */
5909 inp->fid = fidp->fid;
5911 /* check whether we are required to send an extended response */
5912 if (!extendedRespRequired) {
5914 parmOffset = 8*4 + 39;
5915 parmOffset += 1; /* pad to 4 */
5916 dataOffset = parmOffset + 70;
5920 /* Total Parameter Count */
5921 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
5922 /* Total Data Count */
5923 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5924 /* Parameter Count */
5925 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
5926 /* Parameter Offset */
5927 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5928 /* Parameter Displacement */
5929 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5931 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5933 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5934 /* Data Displacement */
5935 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5936 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5937 smb_SetSMBDataLength(outp, 70);
5939 lock_ObtainMutex(&scp->mx);
5940 outData = smb_GetSMBData(outp, NULL);
5941 outData++; /* round to get to parmOffset */
5942 *outData = 0; outData++; /* oplock */
5943 *outData = 0; outData++; /* reserved */
5944 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
5945 *((ULONG *)outData) = openAction; outData += 4;
5946 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
5947 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5948 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
5949 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
5950 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
5951 *((FILETIME *)outData) = ft; outData += 8; /* change time */
5952 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
5953 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
5954 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
5955 *((USHORT *)outData) = 0; outData += 2; /* filetype */
5956 *((USHORT *)outData) = 0; outData += 2; /* dev state */
5957 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
5958 outData += 2; /* is a dir? */
5959 lock_ReleaseMutex(&scp->mx);
5962 parmOffset = 8*4 + 39;
5963 parmOffset += 1; /* pad to 4 */
5964 dataOffset = parmOffset + 104;
5968 /* Total Parameter Count */
5969 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
5970 /* Total Data Count */
5971 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5972 /* Parameter Count */
5973 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
5974 /* Parameter Offset */
5975 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5976 /* Parameter Displacement */
5977 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5979 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5981 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5982 /* Data Displacement */
5983 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5984 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
5985 smb_SetSMBDataLength(outp, 105);
5987 lock_ObtainMutex(&scp->mx);
5988 outData = smb_GetSMBData(outp, NULL);
5989 outData++; /* round to get to parmOffset */
5990 *outData = 0; outData++; /* oplock */
5991 *outData = 1; outData++; /* response type */
5992 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
5993 *((ULONG *)outData) = openAction; outData += 4;
5994 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
5995 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5996 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
5997 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
5998 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
5999 *((FILETIME *)outData) = ft; outData += 8; /* change time */
6000 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
6001 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
6002 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
6003 *((USHORT *)outData) = 0; outData += 2; /* filetype */
6004 *((USHORT *)outData) = 0; outData += 2; /* dev state */
6005 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
6006 outData += 1; /* is a dir? */
6007 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
6008 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
6009 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
6010 lock_ReleaseMutex(&scp->mx);
6013 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
6015 smb_ReleaseFID(fidp);
6017 cm_ReleaseUser(userp);
6019 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
6020 /* leave scp held since we put it in fidp->scp */
6024 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
6027 smb_packet_t *savedPacketp;
6028 ULONG filter; USHORT fid, watchtree;
6032 filter = smb_GetSMBParm(inp, 19) |
6033 (smb_GetSMBParm(inp, 20) << 16);
6034 fid = smb_GetSMBParm(inp, 21);
6035 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
6037 fidp = smb_FindFID(vcp, fid, 0);
6039 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
6040 return CM_ERROR_BADFD;
6043 savedPacketp = smb_CopyPacket(inp);
6045 savedPacketp->vcp = vcp;
6046 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6047 savedPacketp->nextp = smb_Directory_Watches;
6048 smb_Directory_Watches = savedPacketp;
6049 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6051 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
6052 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
6055 lock_ObtainMutex(&scp->mx);
6057 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
6059 scp->flags |= CM_SCACHEFLAG_WATCHED;
6060 lock_ReleaseMutex(&scp->mx);
6061 smb_ReleaseFID(fidp);
6063 outp->flags |= SMB_PACKETFLAG_NOSEND;
6067 unsigned char nullSecurityDesc[36] = {
6068 0x01, /* security descriptor revision */
6069 0x00, /* reserved, should be zero */
6070 0x00, 0x80, /* security descriptor control;
6071 * 0x8000 : self-relative format */
6072 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
6073 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
6074 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
6075 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
6076 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6077 /* "null SID" owner SID */
6078 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
6079 /* "null SID" group SID */
6082 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6084 int parmOffset, parmCount, dataOffset, dataCount;
6092 ULONG securityInformation;
6094 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6095 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6096 parmp = inp->data + parmOffset;
6097 sparmp = (USHORT *) parmp;
6098 lparmp = (ULONG *) parmp;
6101 securityInformation = lparmp[1];
6103 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
6104 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6112 parmOffset = 8*4 + 39;
6113 parmOffset += 1; /* pad to 4 */
6115 dataOffset = parmOffset + parmCount;
6119 /* Total Parameter Count */
6120 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6121 /* Total Data Count */
6122 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6123 /* Parameter Count */
6124 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6125 /* Parameter Offset */
6126 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6127 /* Parameter Displacement */
6128 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6130 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6132 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6133 /* Data Displacement */
6134 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6135 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6136 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
6138 outData = smb_GetSMBData(outp, NULL);
6139 outData++; /* round to get to parmOffset */
6140 *((ULONG *)outData) = 36; outData += 4; /* length */
6142 if (maxData >= 36) {
6143 memcpy(outData, nullSecurityDesc, 36);
6147 return CM_ERROR_BUFFERTOOSMALL;
6150 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6152 unsigned short function;
6154 function = smb_GetSMBParm(inp, 18);
6156 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
6158 /* We can handle long names */
6159 if (vcp->flags & SMB_VCFLAG_USENT)
6160 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
6164 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
6166 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
6168 return smb_ReceiveNTTranCreate(vcp, inp, outp);
6170 return CM_ERROR_INVAL;
6175 * smb_NotifyChange -- find relevant change notification messages and
6178 * If we don't know the file name (i.e. a callback break), filename is
6179 * NULL, and we return a zero-length list.
6181 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
6182 cm_scache_t *dscp, char *filename, char *otherFilename,
6183 BOOL isDirectParent)
6185 smb_packet_t *watch, *lastWatch, *nextWatch;
6186 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
6187 char *outData, *oldOutData;
6191 BOOL twoEntries = FALSE;
6192 ULONG otherNameLen, oldParmCount = 0;
6197 /* Get ready for rename within directory */
6198 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
6200 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
6203 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
6204 osi_LogSaveString(smb_logp,filename),dscp);
6206 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6207 watch = smb_Directory_Watches;
6209 filter = smb_GetSMBParm(watch, 19)
6210 | (smb_GetSMBParm(watch, 20) << 16);
6211 fid = smb_GetSMBParm(watch, 21);
6212 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
6213 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
6214 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
6218 * Strange hack - bug in NT Client and NT Server that we
6221 if (filter == 3 && wtree)
6224 fidp = smb_FindFID(vcp, fid, 0);
6226 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
6228 watch = watch->nextp;
6231 if (fidp->scp != dscp
6232 || (filter & notifyFilter) == 0
6233 || (!isDirectParent && !wtree)) {
6234 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
6235 smb_ReleaseFID(fidp);
6237 watch = watch->nextp;
6240 smb_ReleaseFID(fidp);
6243 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
6244 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
6246 nextWatch = watch->nextp;
6247 if (watch == smb_Directory_Watches)
6248 smb_Directory_Watches = nextWatch;
6250 lastWatch->nextp = nextWatch;
6252 /* Turn off WATCHED flag in dscp */
6253 lock_ObtainMutex(&dscp->mx);
6255 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6257 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
6258 lock_ReleaseMutex(&dscp->mx);
6260 /* Convert to response packet */
6261 ((smb_t *) watch)->reb = 0x80;
6262 ((smb_t *) watch)->wct = 0;
6265 if (filename == NULL)
6268 nameLen = strlen(filename);
6269 parmCount = 3*4 + nameLen*2;
6270 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6272 otherNameLen = strlen(otherFilename);
6273 oldParmCount = parmCount;
6274 parmCount += 3*4 + otherNameLen*2;
6275 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6277 if (maxLen < parmCount)
6278 parmCount = 0; /* not enough room */
6280 parmOffset = 8*4 + 39;
6281 parmOffset += 1; /* pad to 4 */
6282 dataOffset = parmOffset + parmCount;
6286 /* Total Parameter Count */
6287 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6288 /* Total Data Count */
6289 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6290 /* Parameter Count */
6291 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6292 /* Parameter Offset */
6293 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
6294 /* Parameter Displacement */
6295 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6297 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6299 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
6300 /* Data Displacement */
6301 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6302 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
6303 smb_SetSMBDataLength(watch, parmCount + 1);
6305 if (parmCount != 0) {
6307 outData = smb_GetSMBData(watch, NULL);
6308 outData++; /* round to get to parmOffset */
6309 oldOutData = outData;
6310 *((DWORD *)outData) = oldParmCount; outData += 4;
6311 /* Next Entry Offset */
6312 *((DWORD *)outData) = action; outData += 4;
6314 *((DWORD *)outData) = nameLen*2; outData += 4;
6315 /* File Name Length */
6316 p = strdup(filename);
6317 if (smb_StoreAnsiFilenames)
6319 mbstowcs((WCHAR *)outData, p, nameLen);
6323 outData = oldOutData + oldParmCount;
6324 *((DWORD *)outData) = 0; outData += 4;
6325 /* Next Entry Offset */
6326 *((DWORD *)outData) = otherAction; outData += 4;
6328 *((DWORD *)outData) = otherNameLen*2;
6329 outData += 4; /* File Name Length */
6330 p = strdup(otherFilename);
6331 if (smb_StoreAnsiFilenames)
6333 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
6339 * If filename is null, we don't know the cause of the
6340 * change notification. We return zero data (see above),
6341 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
6342 * (= 0x010C). We set the error code here by hand, without
6343 * modifying wct and bcc.
6345 if (filename == NULL) {
6346 ((smb_t *) watch)->rcls = 0x0C;
6347 ((smb_t *) watch)->reh = 0x01;
6348 ((smb_t *) watch)->errLow = 0;
6349 ((smb_t *) watch)->errHigh = 0;
6350 /* Set NT Status codes flag */
6351 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_ERR_STATUS;
6354 smb_SendPacket(vcp, watch);
6356 smb_FreePacket(watch);
6359 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6362 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6364 unsigned char *replyWctp;
6365 smb_packet_t *watch, *lastWatch;
6366 USHORT fid, watchtree;
6370 osi_Log0(smb_logp, "SMB3 receive NT cancel");
6372 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6373 watch = smb_Directory_Watches;
6375 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
6376 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
6377 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
6378 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
6379 if (watch == smb_Directory_Watches)
6380 smb_Directory_Watches = watch->nextp;
6382 lastWatch->nextp = watch->nextp;
6383 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6385 /* Turn off WATCHED flag in scp */
6386 fid = smb_GetSMBParm(watch, 21);
6387 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
6389 if (vcp != watch->vcp)
6390 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
6393 fidp = smb_FindFID(vcp, fid, 0);
6395 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
6397 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
6400 lock_ObtainMutex(&scp->mx);
6402 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6404 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
6405 lock_ReleaseMutex(&scp->mx);
6406 smb_ReleaseFID(fidp);
6408 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
6411 /* assume STATUS32; return 0xC0000120 (CANCELED) */
6412 replyWctp = watch->wctp;
6416 ((smb_t *)watch)->rcls = 0x20;
6417 ((smb_t *)watch)->reh = 0x1;
6418 ((smb_t *)watch)->errLow = 0;
6419 ((smb_t *)watch)->errHigh = 0xC0;
6420 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_ERR_STATUS;
6421 smb_SendPacket(vcp, watch);
6423 smb_ReleaseVC(watch->vcp);
6424 smb_FreePacket(watch);
6428 watch = watch->nextp;
6430 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6436 * NT rename also does hard links.
6439 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
6440 #define RENAME_FLAG_HARD_LINK 0x103
6441 #define RENAME_FLAG_RENAME 0x104
6442 #define RENAME_FLAG_COPY 0x105
6444 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6446 char *oldPathp, *newPathp;
6453 attrs = smb_GetSMBParm(inp, 0);
6454 rename_type = smb_GetSMBParm(inp, 1);
6456 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
6457 osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
6458 return CM_ERROR_NOACCESS;
6461 tp = smb_GetSMBData(inp, NULL);
6462 oldPathp = smb_ParseASCIIBlock(tp, &tp);
6463 if (smb_StoreAnsiFilenames)
6464 OemToChar(oldPathp,oldPathp);
6465 newPathp = smb_ParseASCIIBlock(tp, &tp);
6466 if (smb_StoreAnsiFilenames)
6467 OemToChar(newPathp,newPathp);
6469 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
6470 osi_LogSaveString(smb_logp, oldPathp),
6471 osi_LogSaveString(smb_logp, newPathp),
6472 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
6474 if (rename_type == RENAME_FLAG_RENAME) {
6475 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
6476 } else { /* RENAME_FLAG_HARD_LINK */
6477 code = smb_Link(vcp,inp,oldPathp,newPathp);
6484 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
6487 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
6490 smb_username_t *unp;
6492 unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
6494 lock_ObtainMutex(&unp->mx);
6495 unp->userp = cm_NewUser();
6496 lock_ReleaseMutex(&unp->mx);
6497 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6498 osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
6500 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6501 osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);