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>
16 #define SECURITY_WIN32
28 #include <WINNT\afsreg.h>
32 extern osi_hyper_t hzero;
34 smb_packet_t *smb_Directory_Watches = NULL;
35 osi_mutex_t smb_Dir_Watch_Lock;
37 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
39 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
41 /* protected by the smb_globalLock */
42 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
44 /* retrieve a held reference to a user structure corresponding to an incoming
46 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
51 uidp = smb_FindUID(vcp, inp->uid, 0);
55 lock_ObtainMutex(&uidp->mx);
57 up = uidp->unp->userp;
60 lock_ReleaseMutex(&uidp->mx);
68 * Return extended attributes.
69 * Right now, we aren't using any of the "new" bits, so this looks exactly
70 * like smb_Attributes() (see smb.c).
72 unsigned long smb_ExtAttributes(cm_scache_t *scp)
76 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
77 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
78 scp->fileType == CM_SCACHETYPE_INVALID)
80 attrs = SMB_ATTR_DIRECTORY;
81 #ifdef SPECIAL_FOLDERS
82 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
83 #endif /* SPECIAL_FOLDERS */
84 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
85 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
89 * We used to mark a file RO if it was in an RO volume, but that
90 * turns out to be impolitic in NT. See defect 10007.
93 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
94 attrs |= SMB_ATTR_READONLY; /* Read-only */
96 if ((scp->unixModeBits & 0222) == 0)
97 attrs |= SMB_ATTR_READONLY; /* Read-only */
101 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
106 int smb_V3IsStarMask(char *maskp)
110 while (tc = *maskp++)
111 if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
116 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
119 /* skip over null-terminated string */
120 *chainpp = inp + strlen(inp) + 1;
125 void OutputDebugF(char * format, ...) {
130 va_start( args, format );
131 len = _vscprintf( format, args ) // _vscprintf doesn't count
132 + 3; // terminating '\0' + '\n'
133 buffer = malloc( len * sizeof(char) );
134 vsprintf( buffer, format, args );
135 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buffer));
136 strcat(buffer, "\n");
137 OutputDebugString(buffer);
141 void OutputDebugHexDump(unsigned char * buffer, int len) {
144 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
146 OutputDebugF("Hexdump length [%d]",len);
148 for (i=0;i<len;i++) {
151 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
153 OutputDebugString(buf);
155 sprintf(buf,"%5x",i);
156 memset(buf+5,' ',80);
161 j = j*3 + 7 + ((j>7)?1:0);
164 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
167 j = j + 56 + ((j>7)?1:0);
169 buf[j] = (k>32 && k<127)?k:'.';
172 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
174 OutputDebugString(buf);
178 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
180 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
181 SECURITY_STATUS status, istatus;
182 CredHandle creds = {0,0};
184 SecBufferDesc secOut;
192 OutputDebugF("Negotiating Extended Security");
194 status = AcquireCredentialsHandle( NULL,
195 SMB_EXT_SEC_PACKAGE_NAME,
204 if (status != SEC_E_OK) {
205 /* Really bad. We return an empty security blob */
206 OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
211 secOut.pBuffers = &secTok;
212 secOut.ulVersion = SECBUFFER_VERSION;
214 secTok.BufferType = SECBUFFER_TOKEN;
216 secTok.pvBuffer = NULL;
218 ctx.dwLower = ctx.dwUpper = 0;
220 status = AcceptSecurityContext( &creds,
223 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
224 SECURITY_NETWORK_DREP,
231 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
232 OutputDebugF("Completing token...");
233 istatus = CompleteAuthToken(&ctx, &secOut);
234 if ( istatus != SEC_E_OK )
235 OutputDebugF("Token completion failed: %x", istatus);
238 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
239 if (secTok.pvBuffer) {
240 *secBlobLength = secTok.cbBuffer;
241 *secBlob = malloc( secTok.cbBuffer );
242 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
245 if ( status != SEC_E_OK )
246 OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
249 /* Discard partial security context */
250 DeleteSecurityContext(&ctx);
252 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
254 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
255 FreeCredentialsHandle(&creds);
261 struct smb_ext_context {
268 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
269 SECURITY_STATUS status, istatus;
273 SecBufferDesc secBufIn;
275 SecBufferDesc secBufOut;
278 struct smb_ext_context * secCtx = NULL;
279 struct smb_ext_context * newSecCtx = NULL;
280 void * assembledBlob = NULL;
281 int assembledBlobLength = 0;
284 OutputDebugF("In smb_AuthenticateUserExt");
287 *secBlobOutLength = 0;
289 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
290 secCtx = vcp->secCtx;
291 lock_ObtainMutex(&vcp->mx);
292 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
294 lock_ReleaseMutex(&vcp->mx);
298 OutputDebugF("Received incoming token:");
299 OutputDebugHexDump(secBlobIn,secBlobInLength);
303 OutputDebugF("Continuing with existing context.");
304 creds = secCtx->creds;
307 if (secCtx->partialToken) {
308 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
309 assembledBlob = malloc(assembledBlobLength);
310 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
311 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
314 status = AcquireCredentialsHandle( NULL,
315 SMB_EXT_SEC_PACKAGE_NAME,
324 if (status != SEC_E_OK) {
325 OutputDebugF("Can't acquire Credentials handle [%lX]", status);
326 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
334 secBufIn.cBuffers = 1;
335 secBufIn.pBuffers = &secTokIn;
336 secBufIn.ulVersion = SECBUFFER_VERSION;
338 secTokIn.BufferType = SECBUFFER_TOKEN;
340 secTokIn.cbBuffer = assembledBlobLength;
341 secTokIn.pvBuffer = assembledBlob;
343 secTokIn.cbBuffer = secBlobInLength;
344 secTokIn.pvBuffer = secBlobIn;
347 secBufOut.cBuffers = 1;
348 secBufOut.pBuffers = &secTokOut;
349 secBufOut.ulVersion = SECBUFFER_VERSION;
351 secTokOut.BufferType = SECBUFFER_TOKEN;
352 secTokOut.cbBuffer = 0;
353 secTokOut.pvBuffer = NULL;
355 status = AcceptSecurityContext( &creds,
356 ((secCtx)?&ctx:NULL),
358 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
359 SECURITY_NETWORK_DREP,
366 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
367 OutputDebugF("Completing token...");
368 istatus = CompleteAuthToken(&ctx, &secBufOut);
369 if ( istatus != SEC_E_OK )
370 OutputDebugF("Token completion failed: %lX", istatus);
373 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
374 OutputDebugF("Continue needed");
376 newSecCtx = malloc(sizeof(*newSecCtx));
378 newSecCtx->creds = creds;
379 newSecCtx->ctx = ctx;
380 newSecCtx->partialToken = NULL;
381 newSecCtx->partialTokenLen = 0;
383 lock_ObtainMutex( &vcp->mx );
384 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
385 vcp->secCtx = newSecCtx;
386 lock_ReleaseMutex( &vcp->mx );
388 code = CM_ERROR_GSSCONTINUE;
391 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
392 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
393 secTokOut.pvBuffer) {
394 OutputDebugF("Need to send token back to client");
396 *secBlobOutLength = secTokOut.cbBuffer;
397 *secBlobOut = malloc(secTokOut.cbBuffer);
398 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
400 OutputDebugF("Outgoing token:");
401 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
402 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
403 OutputDebugF("Incomplete message");
405 newSecCtx = malloc(sizeof(*newSecCtx));
407 newSecCtx->creds = creds;
408 newSecCtx->ctx = ctx;
409 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
410 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
411 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
413 lock_ObtainMutex( &vcp->mx );
414 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
415 vcp->secCtx = newSecCtx;
416 lock_ReleaseMutex( &vcp->mx );
418 code = CM_ERROR_GSSCONTINUE;
421 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
423 SecPkgContext_Names names;
425 OutputDebugF("Authentication completed");
426 OutputDebugF("Returned flags : [%lX]", flags);
428 if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
429 OutputDebugF("Received name [%s]", names.sUserName);
430 strcpy(usern, names.sUserName);
431 strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
432 FreeContextBuffer(names.sUserName);
434 /* Force the user to retry if the context is invalid */
435 OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
436 code = CM_ERROR_BADPASSWORD;
440 case SEC_E_INVALID_TOKEN:
441 OutputDebugF("Returning bad password :: INVALID_TOKEN");
443 case SEC_E_INVALID_HANDLE:
444 OutputDebugF("Returning bad password :: INVALID_HANDLE");
446 case SEC_E_LOGON_DENIED:
447 OutputDebugF("Returning bad password :: LOGON_DENIED");
449 case SEC_E_UNKNOWN_CREDENTIALS:
450 OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
452 case SEC_E_NO_CREDENTIALS:
453 OutputDebugF("Returning bad password :: NO_CREDENTIALS");
455 case SEC_E_CONTEXT_EXPIRED:
456 OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
458 case SEC_E_INCOMPLETE_CREDENTIALS:
459 OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
461 case SEC_E_WRONG_PRINCIPAL:
462 OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
464 case SEC_E_TIME_SKEW:
465 OutputDebugF("Returning bad password :: TIME_SKEW");
468 OutputDebugF("Returning bad password :: Status == %lX", status);
470 code = CM_ERROR_BADPASSWORD;
474 if (secCtx->partialToken) free(secCtx->partialToken);
482 if (secTokOut.pvBuffer)
483 FreeContextBuffer(secTokOut.pvBuffer);
485 if (code != CM_ERROR_GSSCONTINUE) {
486 DeleteSecurityContext(&ctx);
487 FreeCredentialsHandle(&creds);
495 #define P_RESP_LEN 128
497 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
498 So put stuff in a struct. */
499 struct Lm20AuthBlob {
500 MSV1_0_LM20_LOGON lmlogon;
501 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
502 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
503 WCHAR accountNameW[P_LEN];
504 WCHAR primaryDomainW[P_LEN];
505 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
506 TOKEN_GROUPS tgroups;
507 TOKEN_SOURCE tsource;
510 long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
513 struct Lm20AuthBlob lmAuth;
514 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
515 QUOTA_LIMITS quotaLimits;
517 ULONG lmprofilepSize;
521 OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
522 OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
524 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
525 OutputDebugF("ciPwdLength or csPwdLength is too long");
526 return CM_ERROR_BADPASSWORD;
529 memset(&lmAuth,0,sizeof(lmAuth));
531 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
533 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
534 mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
535 lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
536 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
538 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
539 mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
540 lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
541 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
543 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
544 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
545 size = MAX_COMPUTERNAME_LENGTH + 1;
546 GetComputerNameW(lmAuth.workstationW, &size);
547 lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
549 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
551 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
552 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
553 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
554 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
556 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
557 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
558 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
559 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
561 lmAuth.lmlogon.ParameterControl = 0;
563 lmAuth.tgroups.GroupCount = 0;
564 lmAuth.tgroups.Groups[0].Sid = NULL;
565 lmAuth.tgroups.Groups[0].Attributes = 0;
567 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
568 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
569 strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
571 nts = LsaLogonUser( smb_lsaHandle,
586 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
587 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
590 OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
591 OutputDebugF("Extended status is 0x%lX", ntsEx);
593 if (nts == ERROR_SUCCESS) {
595 LsaFreeReturnBuffer(lmprofilep);
596 CloseHandle(lmToken);
600 if (nts == 0xC000015BL)
601 return CM_ERROR_BADLOGONTYPE;
602 else /* our catchall is a bad password though we could be more specific */
603 return CM_ERROR_BADPASSWORD;
607 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
608 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName)
613 /* check if we have sane input */
614 if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
617 /* we could get : [accountName][domainName]
623 atsign = strchr(accountName, '@');
625 if (atsign) /* [user@domain][] -> [user@domain][domain] */
630 /* if for some reason the client doesn't know what domain to use,
631 it will either return an empty string or a '?' */
632 if (!domain[0] || domain[0] == '?')
633 /* Empty domains and empty usernames are usually sent from tokenless contexts.
634 This way such logins will get an empty username (easy to check). I don't know
635 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
636 strcpy(usern,accountName);
638 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
639 strcpy(usern,domain);
642 strncat(usern,accountName,atsign - accountName);
644 strcat(usern,accountName);
652 /* When using SMB auth, all SMB sessions have to pass through here
653 * first to authenticate the user.
655 * Caveat: If not using SMB auth, the protocol does not require
656 * sending a session setup packet, which means that we can't rely on a
657 * UID in subsequent packets. Though in practice we get one anyway.
659 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
663 unsigned short newUid;
664 unsigned long caps = 0;
669 char usern[SMB_MAX_USERNAME_LENGTH];
670 char *secBlobOut = NULL;
671 int secBlobOutLength = 0;
673 /* Check for bad conns */
674 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
675 return CM_ERROR_REMOTECONN;
677 if (vcp->flags & SMB_VCFLAG_USENT) {
678 if (smb_authType == SMB_AUTH_EXTENDED) {
679 /* extended authentication */
683 OutputDebugF("NT Session Setup: Extended");
685 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
686 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
689 secBlobInLength = smb_GetSMBParm(inp, 7);
690 secBlobIn = smb_GetSMBData(inp, NULL);
692 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
694 if (code == CM_ERROR_GSSCONTINUE) {
695 smb_SetSMBParm(outp, 2, 0);
696 smb_SetSMBParm(outp, 3, secBlobOutLength);
697 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
698 tp = smb_GetSMBData(outp, NULL);
699 if (secBlobOutLength) {
700 memcpy(tp, secBlobOut, secBlobOutLength);
702 tp += secBlobOutLength;
704 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
705 tp += smb_ServerOSLength;
706 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
707 tp += smb_ServerLanManagerLength;
708 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
709 tp += smb_ServerDomainNameLength;
712 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
714 unsigned ciPwdLength, csPwdLength;
720 if (smb_authType == SMB_AUTH_NTLM)
721 OutputDebugF("NT Session Setup: NTLM");
723 OutputDebugF("NT Session Setup: None");
725 /* TODO: parse for extended auth as well */
726 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
727 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
729 tp = smb_GetSMBData(inp, &datalen);
731 OutputDebugF("Session packet data size [%d]",datalen);
738 accountName = smb_ParseString(tp, &tp);
739 primaryDomain = smb_ParseString(tp, NULL);
741 OutputDebugF("Account Name: %s",accountName);
742 OutputDebugF("Primary Domain: %s", primaryDomain);
743 OutputDebugF("Case Sensitive Password: %s", csPwd && csPwd[0] ? "yes" : "no");
744 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
746 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
747 /* shouldn't happen */
748 code = CM_ERROR_BADSMB;
749 goto after_read_packet;
752 /* capabilities are only valid for first session packet */
753 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
754 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
757 if (smb_authType == SMB_AUTH_NTLM) {
758 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
760 OutputDebugF("LM authentication failed [%d]", code);
762 OutputDebugF("LM authentication succeeded");
766 unsigned ciPwdLength;
771 switch ( smb_authType ) {
772 case SMB_AUTH_EXTENDED:
773 OutputDebugF("V3 Session Setup: Extended");
776 OutputDebugF("V3 Session Setup: NTLM");
779 OutputDebugF("V3 Session Setup: None");
781 ciPwdLength = smb_GetSMBParm(inp, 7);
782 tp = smb_GetSMBData(inp, NULL);
786 accountName = smb_ParseString(tp, &tp);
787 primaryDomain = smb_ParseString(tp, NULL);
789 OutputDebugF("Account Name: %s",accountName);
790 OutputDebugF("Primary Domain: %s", primaryDomain);
791 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
793 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
794 /* shouldn't happen */
795 code = CM_ERROR_BADSMB;
796 goto after_read_packet;
799 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
802 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
803 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
805 OutputDebugF("LM authentication failed [%d]", code);
807 OutputDebugF("LM authentication succeeded");
812 /* note down that we received a session setup X and set the capabilities flag */
813 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
814 lock_ObtainMutex(&vcp->mx);
815 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
816 /* for the moment we can only deal with NTSTATUS */
817 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
818 vcp->flags |= SMB_VCFLAG_STATUS32;
820 lock_ReleaseMutex(&vcp->mx);
823 /* code would be non-zero if there was an authentication failure.
824 Ideally we would like to invalidate the uid for this session or break
825 early to avoid accidently stealing someone else's tokens. */
831 OutputDebugF("Received username=[%s]", usern);
833 /* On Windows 2000, this function appears to be called more often than
834 it is expected to be called. This resulted in multiple smb_user_t
835 records existing all for the same user session which results in all
836 of the users tokens disappearing.
838 To avoid this problem, we look for an existing smb_user_t record
839 based on the users name, and use that one if we find it.
842 uidp = smb_FindUserByNameThisSession(vcp, usern);
843 if (uidp) { /* already there, so don't create a new one */
846 newUid = uidp->userID;
847 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
848 smb_ReleaseUID(uidp);
851 /* do a global search for the username/machine name pair */
852 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
854 /* Create a new UID and cm_user_t structure */
857 userp = cm_NewUser();
858 lock_ObtainMutex(&vcp->mx);
859 if (!vcp->uidCounter)
860 vcp->uidCounter++; /* handle unlikely wraparounds */
861 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
862 lock_ReleaseMutex(&vcp->mx);
864 /* Create a new smb_user_t structure and connect them up */
865 lock_ObtainMutex(&unp->mx);
867 lock_ReleaseMutex(&unp->mx);
869 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
870 lock_ObtainMutex(&uidp->mx);
872 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
873 lock_ReleaseMutex(&uidp->mx);
874 smb_ReleaseUID(uidp);
877 /* Return UID to the client */
878 ((smb_t *)outp)->uid = newUid;
879 /* Also to the next chained message */
880 ((smb_t *)inp)->uid = newUid;
882 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
883 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
885 smb_SetSMBParm(outp, 2, 0);
887 if (vcp->flags & SMB_VCFLAG_USENT) {
888 if (smb_authType == SMB_AUTH_EXTENDED) {
889 smb_SetSMBParm(outp, 3, secBlobOutLength);
890 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
891 tp = smb_GetSMBData(outp, NULL);
892 if (secBlobOutLength) {
893 memcpy(tp, secBlobOut, secBlobOutLength);
895 tp += secBlobOutLength;
897 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
898 tp += smb_ServerOSLength;
899 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
900 tp += smb_ServerLanManagerLength;
901 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
902 tp += smb_ServerDomainNameLength;
904 smb_SetSMBDataLength(outp, 0);
907 if (smb_authType == SMB_AUTH_EXTENDED) {
908 smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
909 tp = smb_GetSMBData(outp, NULL);
910 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
911 tp += smb_ServerOSLength;
912 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
913 tp += smb_ServerLanManagerLength;
914 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
915 tp += smb_ServerDomainNameLength;
917 smb_SetSMBDataLength(outp, 0);
924 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
928 /* don't get tokens from this VC */
929 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
931 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
933 /* find the tree and free it */
934 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
936 char *s1 = NULL, *s2 = NULL;
938 if (s2 == NULL) s2 = " ";
939 if (s1 == NULL) {s1 = s2; s2 = " ";}
941 osi_Log4(smb_logp, "SMB3 user logoffX uid %d name %s%s%s", uidp->userID,
942 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "),
943 osi_LogSaveString(smb_logp,s1), osi_LogSaveString(smb_logp,s2));
945 lock_ObtainMutex(&uidp->mx);
946 uidp->flags |= SMB_USERFLAG_DELETE;
948 * it doesn't get deleted right away
949 * because the vcp points to it
951 lock_ReleaseMutex(&uidp->mx);
952 smb_ReleaseUID(uidp);
955 osi_Log0(smb_logp, "SMB3 user logoffX");
957 smb_SetSMBDataLength(outp, 0);
961 #define SMB_SUPPORT_SEARCH_BITS 0x0001
962 #define SMB_SHARE_IS_IN_DFS 0x0002
964 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
968 unsigned short newTid;
979 osi_Log0(smb_logp, "SMB3 receive tree connect");
981 /* parse input parameters */
982 tp = smb_GetSMBData(inp, NULL);
983 passwordp = smb_ParseString(tp, &tp);
984 pathp = smb_ParseString(tp, &tp);
985 if (smb_StoreAnsiFilenames)
986 OemToChar(pathp,pathp);
987 servicep = smb_ParseString(tp, &tp);
989 tp = strrchr(pathp, '\\');
991 return CM_ERROR_BADSMB;
993 strcpy(shareName, tp+1);
995 osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
996 osi_LogSaveString(smb_logp, pathp),
997 osi_LogSaveString(smb_logp, shareName));
999 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
1001 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1004 return CM_ERROR_NOIPC;
1008 userp = smb_GetUser(vcp, inp);
1010 lock_ObtainMutex(&vcp->mx);
1011 newTid = vcp->tidCounter++;
1012 lock_ReleaseMutex(&vcp->mx);
1014 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1017 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1018 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1020 smb_ReleaseUID(uidp);
1022 smb_ReleaseTID(tidp);
1023 return CM_ERROR_BADSHARENAME;
1026 if (vcp->flags & SMB_VCFLAG_USENT)
1028 int policy = smb_FindShareCSCPolicy(shareName);
1029 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1031 SMB_SHARE_IS_IN_DFS |
1036 smb_SetSMBParm(outp, 2, 0);
1040 lock_ObtainMutex(&tidp->mx);
1041 tidp->userp = userp;
1042 tidp->pathname = sharePath;
1044 tidp->flags |= SMB_TIDFLAG_IPC;
1045 lock_ReleaseMutex(&tidp->mx);
1046 smb_ReleaseTID(tidp);
1048 ((smb_t *)outp)->tid = newTid;
1049 ((smb_t *)inp)->tid = newTid;
1050 tp = smb_GetSMBData(outp, NULL);
1052 /* XXX - why is this a drive letter? */
1061 smb_SetSMBDataLength(outp, 8);
1064 smb_SetSMBDataLength(outp, 4);
1067 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1071 /* must be called with global tran lock held */
1072 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1074 smb_tran2Packet_t *tp;
1077 smbp = (smb_t *) inp->data;
1078 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1079 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1085 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1086 int totalParms, int totalData)
1088 smb_tran2Packet_t *tp;
1091 smbp = (smb_t *) inp->data;
1092 tp = malloc(sizeof(*tp));
1093 memset(tp, 0, sizeof(*tp));
1096 tp->curData = tp->curParms = 0;
1097 tp->totalData = totalData;
1098 tp->totalParms = totalParms;
1099 tp->tid = smbp->tid;
1100 tp->mid = smbp->mid;
1101 tp->uid = smbp->uid;
1102 tp->pid = smbp->pid;
1103 tp->res[0] = smbp->res[0];
1104 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1105 if (totalParms != 0)
1106 tp->parmsp = malloc(totalParms);
1108 tp->datap = malloc(totalData);
1109 if (smbp->com == 0x25 || smbp->com == 0x26)
1112 tp->opcode = smb_GetSMBParm(inp, 14);
1115 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1119 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1120 smb_tran2Packet_t *inp, smb_packet_t *outp,
1121 int totalParms, int totalData)
1123 smb_tran2Packet_t *tp;
1124 unsigned short parmOffset;
1125 unsigned short dataOffset;
1126 unsigned short dataAlign;
1128 tp = malloc(sizeof(*tp));
1129 memset(tp, 0, sizeof(*tp));
1132 tp->curData = tp->curParms = 0;
1133 tp->totalData = totalData;
1134 tp->totalParms = totalParms;
1135 tp->oldTotalParms = totalParms;
1140 tp->res[0] = inp->res[0];
1141 tp->opcode = inp->opcode;
1145 * We calculate where the parameters and data will start.
1146 * This calculation must parallel the calculation in
1147 * smb_SendTran2Packet.
1150 parmOffset = 10*2 + 35;
1151 parmOffset++; /* round to even */
1152 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1154 dataOffset = parmOffset + totalParms;
1155 dataAlign = dataOffset & 2; /* quad-align */
1156 dataOffset += dataAlign;
1157 tp->datap = outp->data + dataOffset;
1162 /* free a tran2 packet; must be called with smb_globalLock held */
1163 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1166 smb_ReleaseVC(t2p->vcp);
1167 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1176 /* called with a VC, an input packet to respond to, and an error code.
1177 * sends an error response.
1179 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1180 smb_packet_t *tp, long code)
1183 unsigned short errCode;
1184 unsigned char errClass;
1185 unsigned long NTStatus;
1187 if (vcp->flags & SMB_VCFLAG_STATUS32)
1188 smb_MapNTError(code, &NTStatus);
1190 smb_MapCoreError(code, vcp, &errCode, &errClass);
1192 smb_FormatResponsePacket(vcp, NULL, tp);
1193 smbp = (smb_t *) tp;
1195 /* We can handle long names */
1196 if (vcp->flags & SMB_VCFLAG_USENT)
1197 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1199 /* now copy important fields from the tran 2 packet */
1200 smbp->com = t2p->com;
1201 smbp->tid = t2p->tid;
1202 smbp->mid = t2p->mid;
1203 smbp->pid = t2p->pid;
1204 smbp->uid = t2p->uid;
1205 smbp->res[0] = t2p->res[0];
1206 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1207 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1208 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1209 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1210 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1211 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1214 smbp->rcls = errClass;
1215 smbp->errLow = (unsigned char) (errCode & 0xff);
1216 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1220 smb_SendPacket(vcp, tp);
1223 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1226 unsigned short parmOffset;
1227 unsigned short dataOffset;
1228 unsigned short totalLength;
1229 unsigned short dataAlign;
1232 smb_FormatResponsePacket(vcp, NULL, tp);
1233 smbp = (smb_t *) tp;
1235 /* We can handle long names */
1236 if (vcp->flags & SMB_VCFLAG_USENT)
1237 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1239 /* now copy important fields from the tran 2 packet */
1240 smbp->com = t2p->com;
1241 smbp->tid = t2p->tid;
1242 smbp->mid = t2p->mid;
1243 smbp->pid = t2p->pid;
1244 smbp->uid = t2p->uid;
1245 smbp->res[0] = t2p->res[0];
1247 totalLength = 1 + t2p->totalData + t2p->totalParms;
1249 /* now add the core parameters (tran2 info) to the packet */
1250 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1251 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1252 smb_SetSMBParm(tp, 2, 0); /* reserved */
1253 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1254 parmOffset = 10*2 + 35; /* parm offset in packet */
1255 parmOffset++; /* round to even */
1256 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1257 * hdr, bcc and wct */
1258 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1259 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1260 dataOffset = parmOffset + t2p->oldTotalParms;
1261 dataAlign = dataOffset & 2; /* quad-align */
1262 dataOffset += dataAlign;
1263 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1264 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1265 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1268 datap = smb_GetSMBData(tp, NULL);
1269 *datap++ = 0; /* we rounded to even */
1271 totalLength += dataAlign;
1272 smb_SetSMBDataLength(tp, totalLength);
1274 /* next, send the datagram */
1275 smb_SendPacket(vcp, tp);
1278 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1280 smb_tran2Packet_t *asp;
1293 /* We sometimes see 0 word count. What to do? */
1294 if (*inp->wctp == 0) {
1295 osi_Log0(smb_logp, "Transaction2 word count = 0");
1297 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1300 smb_SetSMBDataLength(outp, 0);
1301 smb_SendPacket(vcp, outp);
1305 totalParms = smb_GetSMBParm(inp, 0);
1306 totalData = smb_GetSMBParm(inp, 1);
1308 firstPacket = (inp->inCom == 0x25);
1310 /* find the packet we're reassembling */
1311 lock_ObtainWrite(&smb_globalLock);
1312 asp = smb_FindTran2Packet(vcp, inp);
1314 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1316 lock_ReleaseWrite(&smb_globalLock);
1318 /* now merge in this latest packet; start by looking up offsets */
1320 parmDisp = dataDisp = 0;
1321 parmOffset = smb_GetSMBParm(inp, 10);
1322 dataOffset = smb_GetSMBParm(inp, 12);
1323 parmCount = smb_GetSMBParm(inp, 9);
1324 dataCount = smb_GetSMBParm(inp, 11);
1325 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1326 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1328 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1329 totalData, dataCount, asp->maxReturnData);
1332 parmDisp = smb_GetSMBParm(inp, 4);
1333 parmOffset = smb_GetSMBParm(inp, 3);
1334 dataDisp = smb_GetSMBParm(inp, 7);
1335 dataOffset = smb_GetSMBParm(inp, 6);
1336 parmCount = smb_GetSMBParm(inp, 2);
1337 dataCount = smb_GetSMBParm(inp, 5);
1339 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1340 parmCount, dataCount);
1343 /* now copy the parms and data */
1344 if ( asp->totalParms > 0 && parmCount != 0 )
1346 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1348 if ( asp->totalData > 0 && dataCount != 0 ) {
1349 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1352 /* account for new bytes */
1353 asp->curData += dataCount;
1354 asp->curParms += parmCount;
1356 /* finally, if we're done, remove the packet from the queue and dispatch it */
1357 if (asp->totalParms > 0 &&
1358 asp->curParms > 0 &&
1359 asp->totalData <= asp->curData &&
1360 asp->totalParms <= asp->curParms) {
1361 /* we've received it all */
1362 lock_ObtainWrite(&smb_globalLock);
1363 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1364 lock_ReleaseWrite(&smb_globalLock);
1366 /* now dispatch it */
1367 rapOp = asp->parmsp[0];
1369 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1370 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1371 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1372 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
1375 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1376 code = CM_ERROR_BADOP;
1379 /* if an error is returned, we're supposed to send an error packet,
1380 * otherwise the dispatched function already did the data sending.
1381 * We give dispatched proc the responsibility since it knows how much
1382 * space to allocate.
1385 smb_SendTran2Error(vcp, asp, outp, code);
1388 /* free the input tran 2 packet */
1389 lock_ObtainWrite(&smb_globalLock);
1390 smb_FreeTran2Packet(asp);
1391 lock_ReleaseWrite(&smb_globalLock);
1393 else if (firstPacket) {
1394 /* the first packet in a multi-packet request, we need to send an
1395 * ack to get more data.
1397 smb_SetSMBDataLength(outp, 0);
1398 smb_SendPacket(vcp, outp);
1404 /* ANSI versions. The unicode versions support arbitrary length
1405 share names, but we don't support unicode yet. */
1407 typedef struct smb_rap_share_info_0 {
1408 char shi0_netname[13];
1409 } smb_rap_share_info_0_t;
1411 typedef struct smb_rap_share_info_1 {
1412 char shi1_netname[13];
1415 DWORD shi1_remark; /* char *shi1_remark; data offset */
1416 } smb_rap_share_info_1_t;
1418 typedef struct smb_rap_share_info_2 {
1419 char shi2_netname[13];
1421 unsigned short shi2_type;
1422 DWORD shi2_remark; /* char *shi2_remark; data offset */
1423 unsigned short shi2_permissions;
1424 unsigned short shi2_max_uses;
1425 unsigned short shi2_current_uses;
1426 DWORD shi2_path; /* char *shi2_path; data offset */
1427 unsigned short shi2_passwd[9];
1428 unsigned short shi2_pad2;
1429 } smb_rap_share_info_2_t;
1431 #define SMB_RAP_MAX_SHARES 512
1433 typedef struct smb_rap_share_list {
1436 smb_rap_share_info_0_t * shares;
1437 } smb_rap_share_list_t;
1439 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1440 smb_rap_share_list_t * sp;
1445 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1446 return 0; /* skip over '.' and '..' */
1448 sp = (smb_rap_share_list_t *) vrockp;
1450 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1451 sp->shares[sp->cShare].shi0_netname[12] = 0;
1455 if (sp->cShare >= sp->maxShares)
1456 return CM_ERROR_STOPNOW;
1461 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1463 smb_tran2Packet_t *outp;
1464 unsigned short * tp;
1468 int outParmsTotal; /* total parameter bytes */
1469 int outDataTotal; /* total data bytes */
1477 HKEY hkSubmount = NULL;
1478 smb_rap_share_info_1_t * shares;
1481 char thisShare[256];
1484 smb_rap_share_list_t rootShares;
1489 tp = p->parmsp + 1; /* skip over function number (always 0) */
1490 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1491 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1495 if (infoLevel != 1) {
1496 return CM_ERROR_INVAL;
1499 /* first figure out how many shares there are */
1500 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1501 KEY_QUERY_VALUE, &hkParam);
1502 if (rv == ERROR_SUCCESS) {
1503 len = sizeof(allSubmount);
1504 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1505 (BYTE *) &allSubmount, &len);
1506 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1509 RegCloseKey (hkParam);
1512 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1513 0, KEY_QUERY_VALUE, &hkSubmount);
1514 if (rv == ERROR_SUCCESS) {
1515 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1516 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1517 if (rv != ERROR_SUCCESS)
1523 /* fetch the root shares */
1524 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1525 rootShares.cShare = 0;
1526 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1530 userp = smb_GetTran2User(vcp,p);
1532 thyper.HighPart = 0;
1535 cm_HoldSCache(cm_data.rootSCachep);
1536 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1537 cm_ReleaseSCache(cm_data.rootSCachep);
1539 cm_ReleaseUser(userp);
1541 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1543 #define REMARK_LEN 1
1544 outParmsTotal = 8; /* 4 dwords */
1545 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1546 if(outDataTotal > bufsize) {
1547 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1548 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1551 nSharesRet = nShares;
1554 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1556 /* now for the submounts */
1557 shares = (smb_rap_share_info_1_t *) outp->datap;
1558 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1560 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1563 strcpy( shares[cshare].shi1_netname, "all" );
1564 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1565 /* type and pad are zero already */
1571 for (i=0; i < nRegShares && cshare < nSharesRet; i++) {
1572 len = sizeof(thisShare);
1573 rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1574 if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1575 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1576 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1577 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1582 nShares--; /* uncount key */
1585 RegCloseKey(hkSubmount);
1588 nonrootShares = cshare;
1590 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1591 /* in case there are collisions with submounts, submounts have higher priority */
1592 for (j=0; j < nonrootShares; j++)
1593 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1596 if (j < nonrootShares) {
1597 nShares--; /* uncount */
1601 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1602 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1607 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1608 outp->parmsp[1] = 0;
1609 outp->parmsp[2] = cshare;
1610 outp->parmsp[3] = nShares;
1612 outp->totalData = (int)(cstrp - outp->datap);
1613 outp->totalParms = outParmsTotal;
1615 smb_SendTran2Packet(vcp, outp, op);
1616 smb_FreeTran2Packet(outp);
1618 free(rootShares.shares);
1623 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1625 smb_tran2Packet_t *outp;
1626 unsigned short * tp;
1628 BOOL shareFound = FALSE;
1629 unsigned short infoLevel;
1630 unsigned short bufsize;
1640 tp = p->parmsp + 1; /* skip over function number (always 1) */
1641 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1642 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1643 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1650 totalData = sizeof(smb_rap_share_info_0_t);
1651 else if(infoLevel == SMB_INFO_STANDARD)
1652 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1653 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1654 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1656 return CM_ERROR_INVAL;
1658 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1660 if(!stricmp(shareName,"all")) {
1661 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1662 KEY_QUERY_VALUE, &hkParam);
1663 if (rv == ERROR_SUCCESS) {
1664 len = sizeof(allSubmount);
1665 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1666 (BYTE *) &allSubmount, &len);
1667 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1670 RegCloseKey (hkParam);
1677 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1678 KEY_QUERY_VALUE, &hkSubmount);
1679 if (rv == ERROR_SUCCESS) {
1680 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1681 if (rv == ERROR_SUCCESS) {
1684 RegCloseKey(hkSubmount);
1689 smb_FreeTran2Packet(outp);
1690 return CM_ERROR_BADSHARENAME;
1693 memset(outp->datap, 0, totalData);
1695 outp->parmsp[0] = 0;
1696 outp->parmsp[1] = 0;
1697 outp->parmsp[2] = totalData;
1699 if (infoLevel == 0) {
1700 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1701 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1702 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1703 } else if(infoLevel == SMB_INFO_STANDARD) {
1704 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1705 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1706 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1707 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1708 /* type and pad are already zero */
1709 } else { /* infoLevel==2 */
1710 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1711 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1712 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1713 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1714 info->shi2_permissions = ACCESS_ALL;
1715 info->shi2_max_uses = (unsigned short) -1;
1716 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
1719 outp->totalData = totalData;
1720 outp->totalParms = totalParam;
1722 smb_SendTran2Packet(vcp, outp, op);
1723 smb_FreeTran2Packet(outp);
1728 typedef struct smb_rap_wksta_info_10 {
1729 DWORD wki10_computername; /*char *wki10_computername;*/
1730 DWORD wki10_username; /* char *wki10_username; */
1731 DWORD wki10_langroup; /* char *wki10_langroup;*/
1732 unsigned char wki10_ver_major;
1733 unsigned char wki10_ver_minor;
1734 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1735 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1736 } smb_rap_wksta_info_10_t;
1739 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1741 smb_tran2Packet_t *outp;
1745 unsigned short * tp;
1748 smb_rap_wksta_info_10_t * info;
1752 tp = p->parmsp + 1; /* Skip over function number */
1753 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1754 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1758 if (infoLevel != 10) {
1759 return CM_ERROR_INVAL;
1765 totalData = sizeof(*info) + /* info */
1766 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1767 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1768 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1769 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1770 1; /* wki10_oth_domains (null)*/
1772 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1774 memset(outp->parmsp,0,totalParams);
1775 memset(outp->datap,0,totalData);
1777 info = (smb_rap_wksta_info_10_t *) outp->datap;
1778 cstrp = (char *) (info + 1);
1780 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1781 strcpy(cstrp, smb_localNamep);
1782 cstrp += strlen(cstrp) + 1;
1784 info->wki10_username = (DWORD) (cstrp - outp->datap);
1785 uidp = smb_FindUID(vcp, p->uid, 0);
1787 lock_ObtainMutex(&uidp->mx);
1788 if(uidp->unp && uidp->unp->name)
1789 strcpy(cstrp, uidp->unp->name);
1790 lock_ReleaseMutex(&uidp->mx);
1791 smb_ReleaseUID(uidp);
1793 cstrp += strlen(cstrp) + 1;
1795 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1796 strcpy(cstrp, "WORKGROUP");
1797 cstrp += strlen(cstrp) + 1;
1799 /* TODO: Not sure what values these should take, but these work */
1800 info->wki10_ver_major = 5;
1801 info->wki10_ver_minor = 1;
1803 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1804 strcpy(cstrp, smb_ServerDomainName);
1805 cstrp += strlen(cstrp) + 1;
1807 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1808 cstrp ++; /* no other domains */
1810 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1811 outp->parmsp[2] = outp->totalData;
1812 outp->totalParms = totalParams;
1814 smb_SendTran2Packet(vcp,outp,op);
1815 smb_FreeTran2Packet(outp);
1820 typedef struct smb_rap_server_info_0 {
1822 } smb_rap_server_info_0_t;
1824 typedef struct smb_rap_server_info_1 {
1826 char sv1_version_major;
1827 char sv1_version_minor;
1828 unsigned long sv1_type;
1829 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1830 } smb_rap_server_info_1_t;
1832 char smb_ServerComment[] = "OpenAFS Client";
1833 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1835 #define SMB_SV_TYPE_SERVER 0x00000002L
1836 #define SMB_SV_TYPE_NT 0x00001000L
1837 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1839 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1841 smb_tran2Packet_t *outp;
1845 unsigned short * tp;
1848 smb_rap_server_info_0_t * info0;
1849 smb_rap_server_info_1_t * info1;
1852 tp = p->parmsp + 1; /* Skip over function number */
1853 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1854 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1858 if (infoLevel != 0 && infoLevel != 1) {
1859 return CM_ERROR_INVAL;
1865 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1866 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1868 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1870 memset(outp->parmsp,0,totalParams);
1871 memset(outp->datap,0,totalData);
1873 if (infoLevel == 0) {
1874 info0 = (smb_rap_server_info_0_t *) outp->datap;
1875 cstrp = (char *) (info0 + 1);
1876 strcpy(info0->sv0_name, "AFS");
1877 } else { /* infoLevel == SMB_INFO_STANDARD */
1878 info1 = (smb_rap_server_info_1_t *) outp->datap;
1879 cstrp = (char *) (info1 + 1);
1880 strcpy(info1->sv1_name, "AFS");
1883 SMB_SV_TYPE_SERVER |
1885 SMB_SV_TYPE_SERVER_NT;
1887 info1->sv1_version_major = 5;
1888 info1->sv1_version_minor = 1;
1889 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1891 strcpy(cstrp, smb_ServerComment);
1893 cstrp += smb_ServerCommentLen;
1896 totalData = (DWORD)(cstrp - outp->datap);
1897 outp->totalData = min(bufsize,totalData); /* actual data size */
1898 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1899 outp->parmsp[2] = totalData;
1900 outp->totalParms = totalParams;
1902 smb_SendTran2Packet(vcp,outp,op);
1903 smb_FreeTran2Packet(outp);
1908 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1910 smb_tran2Packet_t *asp;
1922 /* We sometimes see 0 word count. What to do? */
1923 if (*inp->wctp == 0) {
1924 osi_Log0(smb_logp, "Transaction2 word count = 0");
1926 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1929 smb_SetSMBDataLength(outp, 0);
1930 smb_SendPacket(vcp, outp);
1934 totalParms = smb_GetSMBParm(inp, 0);
1935 totalData = smb_GetSMBParm(inp, 1);
1937 firstPacket = (inp->inCom == 0x32);
1939 /* find the packet we're reassembling */
1940 lock_ObtainWrite(&smb_globalLock);
1941 asp = smb_FindTran2Packet(vcp, inp);
1943 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1945 lock_ReleaseWrite(&smb_globalLock);
1947 /* now merge in this latest packet; start by looking up offsets */
1949 parmDisp = dataDisp = 0;
1950 parmOffset = smb_GetSMBParm(inp, 10);
1951 dataOffset = smb_GetSMBParm(inp, 12);
1952 parmCount = smb_GetSMBParm(inp, 9);
1953 dataCount = smb_GetSMBParm(inp, 11);
1954 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1955 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1957 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1958 totalData, dataCount, asp->maxReturnData);
1961 parmDisp = smb_GetSMBParm(inp, 4);
1962 parmOffset = smb_GetSMBParm(inp, 3);
1963 dataDisp = smb_GetSMBParm(inp, 7);
1964 dataOffset = smb_GetSMBParm(inp, 6);
1965 parmCount = smb_GetSMBParm(inp, 2);
1966 dataCount = smb_GetSMBParm(inp, 5);
1968 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1969 parmCount, dataCount);
1972 /* now copy the parms and data */
1973 if ( asp->totalParms > 0 && parmCount != 0 )
1975 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1977 if ( asp->totalData > 0 && dataCount != 0 ) {
1978 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1981 /* account for new bytes */
1982 asp->curData += dataCount;
1983 asp->curParms += parmCount;
1985 /* finally, if we're done, remove the packet from the queue and dispatch it */
1986 if (asp->totalParms > 0 &&
1987 asp->curParms > 0 &&
1988 asp->totalData <= asp->curData &&
1989 asp->totalParms <= asp->curParms) {
1990 /* we've received it all */
1991 lock_ObtainWrite(&smb_globalLock);
1992 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1993 lock_ReleaseWrite(&smb_globalLock);
1995 /* now dispatch it */
1996 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
1997 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
1998 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2001 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2002 code = CM_ERROR_BADOP;
2005 /* if an error is returned, we're supposed to send an error packet,
2006 * otherwise the dispatched function already did the data sending.
2007 * We give dispatched proc the responsibility since it knows how much
2008 * space to allocate.
2011 smb_SendTran2Error(vcp, asp, outp, code);
2014 /* free the input tran 2 packet */
2015 lock_ObtainWrite(&smb_globalLock);
2016 smb_FreeTran2Packet(asp);
2017 lock_ReleaseWrite(&smb_globalLock);
2019 else if (firstPacket) {
2020 /* the first packet in a multi-packet request, we need to send an
2021 * ack to get more data.
2023 smb_SetSMBDataLength(outp, 0);
2024 smb_SendPacket(vcp, outp);
2030 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2033 smb_tran2Packet_t *outp;
2038 cm_scache_t *dscp; /* dir we're dealing with */
2039 cm_scache_t *scp; /* file we're creating */
2041 int initialModeBits;
2051 int parmSlot; /* which parm we're dealing with */
2052 long returnEALength;
2060 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2061 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2063 openFun = p->parmsp[6]; /* open function */
2064 excl = ((openFun & 3) == 0);
2065 trunc = ((openFun & 3) == 2); /* truncate it */
2066 openMode = (p->parmsp[1] & 0x7);
2067 openAction = 0; /* tracks what we did */
2069 attributes = p->parmsp[3];
2070 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2072 /* compute initial mode bits based on read-only flag in attributes */
2073 initialModeBits = 0666;
2075 initialModeBits &= ~0222;
2077 pathp = (char *) (&p->parmsp[14]);
2078 if (smb_StoreAnsiFilenames)
2079 OemToChar(pathp,pathp);
2081 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2083 spacep = cm_GetSpace();
2084 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2086 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2087 /* special case magic file name for receiving IOCTL requests
2088 * (since IOCTL calls themselves aren't getting through).
2090 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2091 smb_SetupIoctlFid(fidp, spacep);
2093 /* copy out remainder of the parms */
2095 outp->parmsp[parmSlot++] = fidp->fid;
2097 outp->parmsp[parmSlot++] = 0; /* attrs */
2098 outp->parmsp[parmSlot++] = 0; /* mod time */
2099 outp->parmsp[parmSlot++] = 0;
2100 outp->parmsp[parmSlot++] = 0; /* len */
2101 outp->parmsp[parmSlot++] = 0x7fff;
2102 outp->parmsp[parmSlot++] = openMode;
2103 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2104 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2106 /* and the final "always present" stuff */
2107 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2108 /* next write out the "unique" ID */
2109 outp->parmsp[parmSlot++] = 0x1234;
2110 outp->parmsp[parmSlot++] = 0x5678;
2111 outp->parmsp[parmSlot++] = 0;
2112 if (returnEALength) {
2113 outp->parmsp[parmSlot++] = 0;
2114 outp->parmsp[parmSlot++] = 0;
2117 outp->totalData = 0;
2118 outp->totalParms = parmSlot * 2;
2120 smb_SendTran2Packet(vcp, outp, op);
2122 smb_FreeTran2Packet(outp);
2124 /* and clean up fid reference */
2125 smb_ReleaseFID(fidp);
2129 #ifdef DEBUG_VERBOSE
2131 char *hexp, *asciip;
2132 asciip = (lastNamep ? lastNamep : pathp);
2133 hexp = osi_HexifyString( asciip );
2134 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2139 userp = smb_GetTran2User(vcp, p);
2140 /* In the off chance that userp is NULL, we log and abandon */
2142 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2143 smb_FreeTran2Packet(outp);
2144 return CM_ERROR_BADSMB;
2147 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2148 if (code == CM_ERROR_TIDIPC) {
2149 /* Attempt to use a TID allocated for IPC. The client
2150 * is probably looking for DCE RPC end points which we
2151 * don't support OR it could be looking to make a DFS
2154 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2156 cm_ReleaseUser(userp);
2157 smb_FreeTran2Packet(outp);
2158 return CM_ERROR_NOSUCHPATH;
2163 code = cm_NameI(cm_data.rootSCachep, pathp,
2164 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2165 userp, tidPathp, &req, &scp);
2167 code = cm_NameI(cm_data.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);
2179 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2180 cm_ReleaseSCache(dscp);
2181 cm_ReleaseUser(userp);
2182 smb_FreeTran2Packet(outp);
2183 if ( WANTS_DFS_PATHNAMES(p) )
2184 return CM_ERROR_PATH_NOT_COVERED;
2186 return CM_ERROR_BADSHARENAME;
2188 #endif /* DFS_SUPPORT */
2190 /* otherwise, scp points to the parent directory. Do a lookup,
2191 * and truncate the file if we find it, otherwise we create the
2198 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2200 if (code && code != CM_ERROR_NOSUCHFILE) {
2201 cm_ReleaseSCache(dscp);
2202 cm_ReleaseUser(userp);
2203 smb_FreeTran2Packet(outp);
2208 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2209 cm_ReleaseSCache(scp);
2210 cm_ReleaseUser(userp);
2211 smb_FreeTran2Packet(outp);
2212 if ( WANTS_DFS_PATHNAMES(p) )
2213 return CM_ERROR_PATH_NOT_COVERED;
2215 return CM_ERROR_BADSHARENAME;
2217 #endif /* DFS_SUPPORT */
2219 /* macintosh is expensive to program for it */
2220 cm_FreeSpace(spacep);
2223 /* if we get here, if code is 0, the file exists and is represented by
2224 * scp. Otherwise, we have to create it.
2227 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2230 cm_ReleaseSCache(dscp);
2231 cm_ReleaseSCache(scp);
2232 cm_ReleaseUser(userp);
2233 smb_FreeTran2Packet(outp);
2238 /* oops, file shouldn't be there */
2240 cm_ReleaseSCache(dscp);
2241 cm_ReleaseSCache(scp);
2242 cm_ReleaseUser(userp);
2243 smb_FreeTran2Packet(outp);
2244 return CM_ERROR_EXISTS;
2248 setAttr.mask = CM_ATTRMASK_LENGTH;
2249 setAttr.length.LowPart = 0;
2250 setAttr.length.HighPart = 0;
2251 code = cm_SetAttr(scp, &setAttr, userp, &req);
2252 openAction = 3; /* truncated existing file */
2255 openAction = 1; /* found existing file */
2257 else if (!(openFun & 0x10)) {
2258 /* don't create if not found */
2260 cm_ReleaseSCache(dscp);
2261 osi_assert(scp == NULL);
2262 cm_ReleaseUser(userp);
2263 smb_FreeTran2Packet(outp);
2264 return CM_ERROR_NOSUCHFILE;
2267 osi_assert(dscp != NULL && scp == NULL);
2268 openAction = 2; /* created file */
2269 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2270 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2271 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2273 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2274 smb_NotifyChange(FILE_ACTION_ADDED,
2275 FILE_NOTIFY_CHANGE_FILE_NAME,
2276 dscp, lastNamep, NULL, TRUE);
2277 if (!excl && code == CM_ERROR_EXISTS) {
2278 /* not an exclusive create, and someone else tried
2279 * creating it already, then we open it anyway. We
2280 * don't bother retrying after this, since if this next
2281 * fails, that means that the file was deleted after we
2282 * started this call.
2284 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2288 setAttr.mask = CM_ATTRMASK_LENGTH;
2289 setAttr.length.LowPart = 0;
2290 setAttr.length.HighPart = 0;
2291 code = cm_SetAttr(scp, &setAttr, userp,
2294 } /* lookup succeeded */
2298 /* we don't need this any longer */
2300 cm_ReleaseSCache(dscp);
2303 /* something went wrong creating or truncating the file */
2305 cm_ReleaseSCache(scp);
2306 cm_ReleaseUser(userp);
2307 smb_FreeTran2Packet(outp);
2311 /* make sure we're about to open a file */
2312 if (scp->fileType != CM_SCACHETYPE_FILE) {
2314 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2315 cm_scache_t * targetScp = 0;
2316 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2318 /* we have a more accurate file to use (the
2319 * target of the symbolic link). Otherwise,
2320 * we'll just use the symlink anyway.
2322 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2324 cm_ReleaseSCache(scp);
2328 if (scp->fileType != CM_SCACHETYPE_FILE) {
2329 cm_ReleaseSCache(scp);
2330 cm_ReleaseUser(userp);
2331 smb_FreeTran2Packet(outp);
2332 return CM_ERROR_ISDIR;
2336 /* now all we have to do is open the file itself */
2337 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2340 /* save a pointer to the vnode */
2344 fidp->userp = userp;
2346 /* compute open mode */
2347 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2348 if (openMode == 1 || openMode == 2)
2349 fidp->flags |= SMB_FID_OPENWRITE;
2351 smb_ReleaseFID(fidp);
2353 cm_Open(scp, 0, userp);
2355 /* copy out remainder of the parms */
2357 outp->parmsp[parmSlot++] = fidp->fid;
2358 lock_ObtainMutex(&scp->mx);
2360 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2361 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2362 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2363 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2364 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2365 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2366 outp->parmsp[parmSlot++] = openMode;
2367 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2368 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2370 /* and the final "always present" stuff */
2371 outp->parmsp[parmSlot++] = openAction;
2372 /* next write out the "unique" ID */
2373 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2374 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2375 outp->parmsp[parmSlot++] = 0;
2376 if (returnEALength) {
2377 outp->parmsp[parmSlot++] = 0;
2378 outp->parmsp[parmSlot++] = 0;
2380 lock_ReleaseMutex(&scp->mx);
2381 outp->totalData = 0; /* total # of data bytes */
2382 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2384 smb_SendTran2Packet(vcp, outp, op);
2386 smb_FreeTran2Packet(outp);
2388 cm_ReleaseUser(userp);
2389 /* leave scp held since we put it in fidp->scp */
2393 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2395 osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2396 return CM_ERROR_BADOP;
2399 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2401 osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2402 return CM_ERROR_BADOP;
2405 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2407 smb_tran2Packet_t *outp;
2408 smb_tran2QFSInfo_t qi;
2411 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
2413 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2415 switch (p->parmsp[0]) {
2416 case 1: responseSize = sizeof(qi.u.allocInfo); break;
2417 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
2418 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
2419 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
2420 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
2421 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
2422 case 0x200: /* CIFS Unix Info */
2423 case 0x301: /* Mac FS Info */
2424 default: return CM_ERROR_INVAL;
2427 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2428 switch (p->parmsp[0]) {
2431 qi.u.allocInfo.FSID = 0;
2432 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2433 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2434 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2435 qi.u.allocInfo.bytesPerSector = 1024;
2440 qi.u.volumeInfo.vsn = 1234;
2441 qi.u.volumeInfo.vnCount = 4;
2442 /* we're supposed to pad it out with zeroes to the end */
2443 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2444 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2448 /* FS volume info */
2449 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
2450 qi.u.FSvolumeInfo.vsn = 1234;
2451 qi.u.FSvolumeInfo.vnCount = 8;
2452 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
2458 temp.LowPart = 0x7fffffff;
2459 qi.u.FSsizeInfo.totalAllocUnits = temp;
2460 temp.LowPart = 0x3fffffff;
2461 qi.u.FSsizeInfo.availAllocUnits = temp;
2462 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2463 qi.u.FSsizeInfo.bytesPerSector = 1024;
2467 /* FS device info */
2468 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
2469 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2473 /* FS attribute info */
2474 /* attributes, defined in WINNT.H:
2475 * FILE_CASE_SENSITIVE_SEARCH 0x1
2476 * FILE_CASE_PRESERVED_NAMES 0x2
2477 * <no name defined> 0x4000
2478 * If bit 0x4000 is not set, Windows 95 thinks
2479 * we can't handle long (non-8.3) names,
2480 * despite our protestations to the contrary.
2482 qi.u.FSattributeInfo.attributes = 0x4003;
2483 qi.u.FSattributeInfo.maxCompLength = 255;
2484 qi.u.FSattributeInfo.FSnameLength = 6;
2485 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
2489 /* copy out return data, and set corresponding sizes */
2490 outp->totalParms = 0;
2491 outp->totalData = responseSize;
2492 memcpy(outp->datap, &qi, responseSize);
2494 /* send and free the packets */
2495 smb_SendTran2Packet(vcp, outp, op);
2496 smb_FreeTran2Packet(outp);
2501 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2503 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2504 return CM_ERROR_BADOP;
2507 struct smb_ShortNameRock {
2511 size_t shortNameLen;
2514 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2517 struct smb_ShortNameRock *rockp;
2521 /* compare both names and vnodes, though probably just comparing vnodes
2522 * would be safe enough.
2524 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2526 if (ntohl(dep->fid.vnode) != rockp->vnode)
2528 /* This is the entry */
2529 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2530 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2531 return CM_ERROR_STOPNOW;
2534 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2535 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2537 struct smb_ShortNameRock rock;
2541 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2545 spacep = cm_GetSpace();
2546 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2548 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2550 cm_FreeSpace(spacep);
2555 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2556 cm_ReleaseSCache(dscp);
2557 cm_ReleaseUser(userp);
2558 return CM_ERROR_PATH_NOT_COVERED;
2560 #endif /* DFS_SUPPORT */
2562 if (!lastNamep) lastNamep = pathp;
2565 thyper.HighPart = 0;
2566 rock.shortName = shortName;
2568 rock.maskp = lastNamep;
2569 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2571 cm_ReleaseSCache(dscp);
2574 return CM_ERROR_NOSUCHFILE;
2575 if (code == CM_ERROR_STOPNOW) {
2576 *shortNameLenp = rock.shortNameLen;
2582 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2584 smb_tran2Packet_t *outp;
2587 unsigned short infoLevel;
2589 unsigned short attributes;
2590 unsigned long extAttributes;
2595 cm_scache_t *scp, *dscp;
2604 infoLevel = p->parmsp[0];
2605 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2607 else if (infoLevel == SMB_INFO_STANDARD)
2608 nbytesRequired = 22;
2609 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2610 nbytesRequired = 26;
2611 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2612 nbytesRequired = 40;
2613 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2614 nbytesRequired = 24;
2615 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2617 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2618 nbytesRequired = 30;
2620 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2621 p->opcode, infoLevel);
2622 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2625 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2626 osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
2628 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2630 if (infoLevel > 0x100)
2631 outp->totalParms = 2;
2633 outp->totalParms = 0;
2634 outp->totalData = nbytesRequired;
2636 /* now, if we're at infoLevel 6, we're only being asked to check
2637 * the syntax, so we just OK things now. In particular, we're *not*
2638 * being asked to verify anything about the state of any parent dirs.
2640 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2641 smb_SendTran2Packet(vcp, outp, opx);
2642 smb_FreeTran2Packet(outp);
2646 userp = smb_GetTran2User(vcp, p);
2648 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2649 smb_FreeTran2Packet(outp);
2650 return CM_ERROR_BADSMB;
2653 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2655 cm_ReleaseUser(userp);
2656 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2657 smb_FreeTran2Packet(outp);
2662 * XXX Strange hack XXX
2664 * As of Patch 7 (13 January 98), we are having the following problem:
2665 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2666 * requests to look up "desktop.ini" in all the subdirectories.
2667 * This can cause zillions of timeouts looking up non-existent cells
2668 * and volumes, especially in the top-level directory.
2670 * We have not found any way to avoid this or work around it except
2671 * to explicitly ignore the requests for mount points that haven't
2672 * yet been evaluated and for directories that haven't yet been
2675 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2676 spacep = cm_GetSpace();
2677 smb_StripLastComponent(spacep->data, &lastComp,
2678 (char *)(&p->parmsp[3]));
2679 #ifndef SPECIAL_FOLDERS
2680 /* Make sure that lastComp is not NULL */
2682 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2683 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2687 userp, tidPathp, &req, &dscp);
2690 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2691 if ( WANTS_DFS_PATHNAMES(p) )
2692 code = CM_ERROR_PATH_NOT_COVERED;
2694 code = CM_ERROR_BADSHARENAME;
2696 #endif /* DFS_SUPPORT */
2697 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2698 code = CM_ERROR_NOSUCHFILE;
2699 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2700 cm_buf_t *bp = buf_Find(dscp, &hzero);
2704 code = CM_ERROR_NOSUCHFILE;
2706 cm_ReleaseSCache(dscp);
2708 cm_FreeSpace(spacep);
2709 cm_ReleaseUser(userp);
2710 smb_SendTran2Error(vcp, p, opx, code);
2711 smb_FreeTran2Packet(outp);
2717 #endif /* SPECIAL_FOLDERS */
2719 cm_FreeSpace(spacep);
2722 /* now do namei and stat, and copy out the info */
2723 code = cm_NameI(cm_data.rootSCachep, (char *)(&p->parmsp[3]),
2724 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2727 cm_ReleaseUser(userp);
2728 smb_SendTran2Error(vcp, p, opx, code);
2729 smb_FreeTran2Packet(outp);
2734 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2735 cm_ReleaseSCache(scp);
2736 cm_ReleaseUser(userp);
2737 if ( WANTS_DFS_PATHNAMES(p) )
2738 code = CM_ERROR_PATH_NOT_COVERED;
2740 code = CM_ERROR_BADSHARENAME;
2741 smb_SendTran2Error(vcp, p, opx, code);
2742 smb_FreeTran2Packet(outp);
2745 #endif /* DFS_SUPPORT */
2747 lock_ObtainMutex(&scp->mx);
2748 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2749 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2750 if (code) goto done;
2752 /* now we have the status in the cache entry, and everything is locked.
2753 * Marshall the output data.
2756 /* for info level 108, figure out short name */
2757 if (infoLevel == 0x108) {
2758 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
2759 tidPathp, scp->fid.vnode, shortName,
2766 *((u_long *)op) = len * 2; op += 4;
2767 mbstowcs((unsigned short *)op, shortName, len);
2772 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2773 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2774 *((u_long *)op) = dosTime; op += 4; /* creation time */
2775 *((u_long *)op) = dosTime; op += 4; /* access time */
2776 *((u_long *)op) = dosTime; op += 4; /* write time */
2777 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
2778 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
2779 attributes = smb_Attributes(scp);
2780 *((u_short *)op) = attributes; op += 2; /* attributes */
2782 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2783 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2784 *((FILETIME *)op) = ft; op += 8; /* creation time */
2785 *((FILETIME *)op) = ft; op += 8; /* last access time */
2786 *((FILETIME *)op) = ft; op += 8; /* last write time */
2787 *((FILETIME *)op) = ft; op += 8; /* last change time */
2788 extAttributes = smb_ExtAttributes(scp);
2789 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
2790 *((u_long *)op) = 0; op += 4; /* don't know what this is */
2792 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2793 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2794 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2795 *((u_long *)op) = scp->linkCount; op += 4;
2798 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2801 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2802 memset(op, 0, 4); op += 4; /* EA size */
2805 /* now, if we are being asked about extended attrs, return a 0 size */
2806 if (infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2807 *((u_long *)op) = 0; op += 4;
2811 /* send and free the packets */
2813 lock_ReleaseMutex(&scp->mx);
2814 cm_ReleaseSCache(scp);
2815 cm_ReleaseUser(userp);
2817 smb_SendTran2Packet(vcp, outp, opx);
2819 smb_SendTran2Error(vcp, p, opx, code);
2820 smb_FreeTran2Packet(outp);
2825 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2827 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2828 return CM_ERROR_BADOP;
2831 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2833 smb_tran2Packet_t *outp;
2835 unsigned long attributes;
2836 unsigned short infoLevel;
2849 fidp = smb_FindFID(vcp, fid, 0);
2852 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2856 infoLevel = p->parmsp[1];
2857 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2858 nbytesRequired = 40;
2859 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2860 nbytesRequired = 24;
2861 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2863 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2866 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2867 p->opcode, infoLevel);
2868 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2869 smb_ReleaseFID(fidp);
2872 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2874 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2876 if (infoLevel > 0x100)
2877 outp->totalParms = 2;
2879 outp->totalParms = 0;
2880 outp->totalData = nbytesRequired;
2882 userp = smb_GetTran2User(vcp, p);
2884 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2885 code = CM_ERROR_BADSMB;
2890 lock_ObtainMutex(&scp->mx);
2891 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2892 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2896 /* now we have the status in the cache entry, and everything is locked.
2897 * Marshall the output data.
2900 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2901 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2902 *((FILETIME *)op) = ft; op += 8; /* creation time */
2903 *((FILETIME *)op) = ft; op += 8; /* last access time */
2904 *((FILETIME *)op) = ft; op += 8; /* last write time */
2905 *((FILETIME *)op) = ft; op += 8; /* last change time */
2906 attributes = smb_ExtAttributes(scp);
2907 *((u_long *)op) = attributes; op += 4;
2908 *((u_long *)op) = 0; op += 4;
2910 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2911 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2912 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2913 *((u_long *)op) = scp->linkCount; op += 4;
2914 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
2915 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2919 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2920 *((u_long *)op) = 0; op += 4;
2922 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2926 if (fidp->NTopen_wholepathp)
2927 name = fidp->NTopen_wholepathp;
2929 name = "\\"; /* probably can't happen */
2930 len = (unsigned long)strlen(name);
2931 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
2932 *((u_long *)op) = len * 2; op += 4;
2933 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2936 /* send and free the packets */
2938 lock_ReleaseMutex(&scp->mx);
2939 cm_ReleaseUser(userp);
2940 smb_ReleaseFID(fidp);
2942 smb_SendTran2Packet(vcp, outp, opx);
2944 smb_SendTran2Error(vcp, p, opx, code);
2945 smb_FreeTran2Packet(outp);
2950 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2955 unsigned short infoLevel;
2956 smb_tran2Packet_t *outp;
2964 fidp = smb_FindFID(vcp, fid, 0);
2967 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
2971 infoLevel = p->parmsp[1];
2972 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type=[%x] fid=[%x]", infoLevel, fid);
2973 if (infoLevel > 0x104 || infoLevel < 0x101) {
2974 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2975 p->opcode, infoLevel);
2976 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
2977 smb_ReleaseFID(fidp);
2981 if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) {
2982 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2983 smb_ReleaseFID(fidp);
2986 if ((infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO)
2987 && !(fidp->flags & SMB_FID_OPENWRITE)) {
2988 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2989 smb_ReleaseFID(fidp);
2993 osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
2995 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
2997 outp->totalParms = 2;
2998 outp->totalData = 0;
3000 userp = smb_GetTran2User(vcp, p);
3002 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3003 code = CM_ERROR_BADSMB;
3009 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3011 unsigned int attribute;
3014 /* lock the vnode with a callback; we need the current status
3015 * to determine what the new status is, in some cases.
3017 lock_ObtainMutex(&scp->mx);
3018 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3019 CM_SCACHESYNC_GETSTATUS
3020 | CM_SCACHESYNC_NEEDCALLBACK);
3022 lock_ReleaseMutex(&scp->mx);
3026 /* prepare for setattr call */
3029 lastMod = *((FILETIME *)(p->datap + 16));
3030 /* when called as result of move a b, lastMod is (-1, -1).
3031 * If the check for -1 is not present, timestamp
3032 * of the resulting file will be 1969 (-1)
3034 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3035 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3036 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3037 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3038 fidp->flags |= SMB_FID_MTIMESETDONE;
3041 attribute = *((u_long *)(p->datap + 32));
3042 if (attribute != 0) {
3043 if ((scp->unixModeBits & 0222)
3044 && (attribute & 1) != 0) {
3045 /* make a writable file read-only */
3046 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3047 attr.unixModeBits = scp->unixModeBits & ~0222;
3049 else if ((scp->unixModeBits & 0222) == 0
3050 && (attribute & 1) == 0) {
3051 /* make a read-only file writable */
3052 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3053 attr.unixModeBits = scp->unixModeBits | 0222;
3056 lock_ReleaseMutex(&scp->mx);
3060 code = cm_SetAttr(scp, &attr, userp, &req);
3064 else if (infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3065 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3068 attr.mask = CM_ATTRMASK_LENGTH;
3069 attr.length.LowPart = size.LowPart;
3070 attr.length.HighPart = size.HighPart;
3071 code = cm_SetAttr(scp, &attr, userp, &req);
3073 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3074 if (*((char *)(p->datap))) {
3075 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3078 fidp->flags |= SMB_FID_DELONCLOSE;
3082 fidp->flags &= ~SMB_FID_DELONCLOSE;
3087 cm_ReleaseUser(userp);
3088 smb_ReleaseFID(fidp);
3090 smb_SendTran2Packet(vcp, outp, op);
3092 smb_SendTran2Error(vcp, p, op, code);
3093 smb_FreeTran2Packet(outp);
3099 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3101 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3102 return CM_ERROR_BADOP;
3106 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3108 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3109 return CM_ERROR_BADOP;
3113 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3115 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3116 return CM_ERROR_BADOP;
3120 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3122 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3123 return CM_ERROR_BADOP;
3127 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3129 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3130 return CM_ERROR_BADOP;
3134 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3136 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3137 return CM_ERROR_BADOP;
3140 struct smb_v2_referral {
3142 USHORT ReferralFlags;
3145 USHORT DfsPathOffset;
3146 USHORT DfsAlternativePathOffset;
3147 USHORT NetworkAddressOffset;
3151 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3153 /* This is a UNICODE only request (bit15 of Flags2) */
3154 /* The TID must be IPC$ */
3156 /* The documentation for the Flags response field is contradictory */
3158 /* Use Version 1 Referral Element Format */
3159 /* ServerType = 0; indicates the next server should be queried for the file */
3160 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3161 /* Node = UnicodeString of UNC path of the next share name */
3164 int maxReferralLevel = 0;
3165 char requestFileName[1024] = "";
3166 smb_tran2Packet_t *outp = 0;
3167 cm_user_t *userp = 0;
3169 CPINFO CodePageInfo;
3170 int i, nbnLen, reqLen;
3175 maxReferralLevel = p->parmsp[0];
3177 GetCPInfo(CP_ACP, &CodePageInfo);
3178 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
3179 requestFileName, 1024, NULL, NULL);
3181 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
3182 maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3184 nbnLen = strlen(cm_NetbiosName);
3185 reqLen = strlen(requestFileName);
3187 if (reqLen == nbnLen + 5 &&
3188 requestFileName[0] == '\\' &&
3189 !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3190 requestFileName[nbnLen+1] == '\\' &&
3191 !_strnicmp("all",&requestFileName[nbnLen+2],3))
3194 struct smb_v2_referral * v2ref;
3195 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
3197 sp = (USHORT *)outp->datap;
3199 sp[idx++] = reqLen; /* path consumed */
3200 sp[idx++] = 1; /* number of referrals */
3201 sp[idx++] = 0x03; /* flags */
3202 #ifdef DFS_VERSION_1
3203 sp[idx++] = 1; /* Version Number */
3204 sp[idx++] = reqLen + 4; /* Referral Size */
3205 sp[idx++] = 1; /* Type = SMB Server */
3206 sp[idx++] = 0; /* Do not strip path consumed */
3207 for ( i=0;i<=reqLen; i++ )
3208 sp[i+idx] = requestFileName[i];
3209 #else /* DFS_VERSION_2 */
3210 sp[idx++] = 2; /* Version Number */
3211 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3212 idx += (sizeof(struct smb_v2_referral) / 2);
3213 v2ref = (struct smb_v2_referral *) &sp[5];
3214 v2ref->ServerType = 1; /* SMB Server */
3215 v2ref->ReferralFlags = 0x03;
3216 v2ref->Proximity = 0; /* closest */
3217 v2ref->TimeToLive = 3600; /* seconds */
3218 v2ref->DfsPathOffset = idx * 2;
3219 v2ref->DfsAlternativePathOffset = idx * 2;
3220 v2ref->NetworkAddressOffset = 0;
3221 for ( i=0;i<=reqLen; i++ )
3222 sp[i+idx] = requestFileName[i];
3225 userp = smb_GetTran2User(vcp, p);
3227 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3228 code = CM_ERROR_BADSMB;
3233 code = CM_ERROR_NOSUCHPATH;
3238 cm_ReleaseUser(userp);
3240 smb_SendTran2Packet(vcp, outp, op);
3242 smb_SendTran2Error(vcp, p, op, code);
3244 smb_FreeTran2Packet(outp);
3247 #else /* DFS_SUPPORT */
3248 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3249 return CM_ERROR_BADOP;
3250 #endif /* DFS_SUPPORT */
3254 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3256 /* This is a UNICODE only request (bit15 of Flags2) */
3258 /* There is nothing we can do about this operation. The client is going to
3259 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3260 * Unfortunately, there is really nothing we can do about it other then log it
3261 * somewhere. Even then I don't think there is anything for us to do.
3262 * So let's return an error value.
3265 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3266 return CM_ERROR_BADOP;
3270 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3271 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3276 cm_scache_t *targetScp; /* target if scp is a symlink */
3281 unsigned short attr;
3282 unsigned long lattr;
3283 smb_dirListPatch_t *patchp;
3284 smb_dirListPatch_t *npatchp;
3286 for(patchp = *dirPatchespp; patchp; patchp =
3287 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3288 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3290 lock_ObtainMutex(&scp->mx);
3291 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3292 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3294 lock_ReleaseMutex(&scp->mx);
3295 cm_ReleaseSCache(scp);
3297 dptr = patchp->dptr;
3299 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3300 errors in the client. */
3301 if (infoLevel >= 0x101) {
3302 /* 1969-12-31 23:59:59 +00 */
3303 ft.dwHighDateTime = 0x19DB200;
3304 ft.dwLowDateTime = 0x5BB78980;
3306 /* copy to Creation Time */
3307 *((FILETIME *)dptr) = ft;
3310 /* copy to Last Access Time */
3311 *((FILETIME *)dptr) = ft;
3314 /* copy to Last Write Time */
3315 *((FILETIME *)dptr) = ft;
3318 /* copy to Change Time */
3319 *((FILETIME *)dptr) = ft;
3322 /* merge in hidden attribute */
3323 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3324 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3328 /* 1969-12-31 23:59:58 +00*/
3329 dosTime = 0xEBBFBF7D;
3331 /* and copy out date */
3332 shortTemp = (dosTime>>16) & 0xffff;
3333 *((u_short *)dptr) = shortTemp;
3336 /* copy out creation time */
3337 shortTemp = dosTime & 0xffff;
3338 *((u_short *)dptr) = shortTemp;
3341 /* and copy out date */
3342 shortTemp = (dosTime>>16) & 0xffff;
3343 *((u_short *)dptr) = shortTemp;
3346 /* copy out access time */
3347 shortTemp = dosTime & 0xffff;
3348 *((u_short *)dptr) = shortTemp;
3351 /* and copy out date */
3352 shortTemp = (dosTime>>16) & 0xffff;
3353 *((u_short *)dptr) = shortTemp;
3356 /* copy out mod time */
3357 shortTemp = dosTime & 0xffff;
3358 *((u_short *)dptr) = shortTemp;
3361 /* merge in hidden (dot file) attribute */
3362 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3363 attr = SMB_ATTR_HIDDEN;
3364 *dptr++ = attr & 0xff;
3365 *dptr++ = (attr >> 8) & 0xff;
3371 /* now watch for a symlink */
3373 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3374 lock_ReleaseMutex(&scp->mx);
3375 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3377 /* we have a more accurate file to use (the
3378 * target of the symbolic link). Otherwise,
3379 * we'll just use the symlink anyway.
3381 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3383 cm_ReleaseSCache(scp);
3386 lock_ObtainMutex(&scp->mx);
3389 dptr = patchp->dptr;
3391 if (infoLevel >= 0x101) {
3393 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3395 /* copy to Creation Time */
3396 *((FILETIME *)dptr) = ft;
3399 /* copy to Last Access Time */
3400 *((FILETIME *)dptr) = ft;
3403 /* copy to Last Write Time */
3404 *((FILETIME *)dptr) = ft;
3407 /* copy to Change Time */
3408 *((FILETIME *)dptr) = ft;
3411 /* Use length for both file length and alloc length */
3412 *((LARGE_INTEGER *)dptr) = scp->length;
3414 *((LARGE_INTEGER *)dptr) = scp->length;
3417 /* Copy attributes */
3418 lattr = smb_ExtAttributes(scp);
3419 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3420 if (lattr == SMB_ATTR_NORMAL)
3421 lattr = SMB_ATTR_DIRECTORY;
3423 lattr |= SMB_ATTR_DIRECTORY;
3425 /* merge in hidden (dot file) attribute */
3426 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3427 if (lattr == SMB_ATTR_NORMAL)
3428 lattr = SMB_ATTR_HIDDEN;
3430 lattr |= SMB_ATTR_HIDDEN;
3432 *((u_long *)dptr) = lattr;
3436 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3438 /* and copy out date */
3439 shortTemp = (dosTime>>16) & 0xffff;
3440 *((u_short *)dptr) = shortTemp;
3443 /* copy out creation time */
3444 shortTemp = dosTime & 0xffff;
3445 *((u_short *)dptr) = shortTemp;
3448 /* and copy out date */
3449 shortTemp = (dosTime>>16) & 0xffff;
3450 *((u_short *)dptr) = shortTemp;
3453 /* copy out access time */
3454 shortTemp = dosTime & 0xffff;
3455 *((u_short *)dptr) = shortTemp;
3458 /* and copy out date */
3459 shortTemp = (dosTime>>16) & 0xffff;
3460 *((u_short *)dptr) = shortTemp;
3463 /* copy out mod time */
3464 shortTemp = dosTime & 0xffff;
3465 *((u_short *)dptr) = shortTemp;
3468 /* copy out file length and alloc length,
3469 * using the same for both
3471 *((u_long *)dptr) = scp->length.LowPart;
3473 *((u_long *)dptr) = scp->length.LowPart;
3476 /* finally copy out attributes as short */
3477 attr = smb_Attributes(scp);
3478 /* merge in hidden (dot file) attribute */
3479 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3480 if (lattr == SMB_ATTR_NORMAL)
3481 lattr = SMB_ATTR_HIDDEN;
3483 lattr |= SMB_ATTR_HIDDEN;
3485 *dptr++ = attr & 0xff;
3486 *dptr++ = (attr >> 8) & 0xff;
3489 lock_ReleaseMutex(&scp->mx);
3490 cm_ReleaseSCache(scp);
3493 /* now free the patches */
3494 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3495 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3499 /* and mark the list as empty */
3500 *dirPatchespp = NULL;
3505 #ifndef USE_OLD_MATCHING
3506 // char table for case insensitive comparison
3507 char mapCaseTable[256];
3509 VOID initUpperCaseTable(VOID)
3512 for (i = 0; i < 256; ++i)
3513 mapCaseTable[i] = toupper(i);
3514 // make '"' match '.'
3515 mapCaseTable[(int)'"'] = toupper('.');
3516 // make '<' match '*'
3517 mapCaseTable[(int)'<'] = toupper('*');
3518 // make '>' match '?'
3519 mapCaseTable[(int)'>'] = toupper('?');
3522 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3524 // Note : this procedure works recursively calling itself.
3526 // PSZ pattern : string containing metacharacters.
3527 // PSZ name : file name to be compared with 'pattern'.
3529 // BOOL : TRUE/FALSE (match/mistmatch)
3532 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
3534 PSZ pename; // points to the last 'name' character
3536 pename = name + strlen(name) - 1;
3547 if (*pattern == '\0')
3549 for (p = pename; p >= name; --p) {
3550 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
3551 !casefold && (*p == *pattern)) &&
3552 szWildCardMatchFileName(pattern + 1, p + 1, casefold))
3557 if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
3558 (!casefold && *name != *pattern))
3565 /* if all we have left are wildcards, then we match */
3566 for (;*pattern; pattern++) {
3567 if (*pattern != '*' && *pattern != '?')
3573 /* do a case-folding search of the star name mask with the name in namep.
3574 * Return 1 if we match, otherwise 0.
3576 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3579 int i, j, star, qmark, casefold, retval;
3581 /* make sure we only match 8.3 names, if requested */
3582 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3585 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
3587 /* optimize the pattern:
3588 * if there is a mixture of '?' and '*',
3589 * for example the sequence "*?*?*?*"
3590 * must be turned into the form "*"
3592 newmask = (char *)malloc(strlen(maskp)+1);
3593 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3594 switch ( maskp[i] ) {
3606 } else if ( qmark ) {
3610 newmask[j++] = maskp[i];
3617 } else if ( qmark ) {
3621 newmask[j++] = '\0';
3623 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
3629 #else /* USE_OLD_MATCHING */
3630 /* do a case-folding search of the star name mask with the name in namep.
3631 * Return 1 if we match, otherwise 0.
3633 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3635 unsigned char tcp1, tcp2; /* Pattern characters */
3636 unsigned char tcn1; /* Name characters */
3637 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3638 char *starNamep, *starMaskp;
3639 static char nullCharp[] = {0};
3640 int casefold = flags & CM_FLAG_CASEFOLD;
3642 /* make sure we only match 8.3 names, if requested */
3643 req8dot3 = (flags & CM_FLAG_8DOT3);
3644 if (req8dot3 && !cm_Is8Dot3(namep))
3649 /* Next pattern character */
3652 /* Next name character */
3656 /* 0 - end of pattern */
3662 else if (tcp1 == '.' || tcp1 == '"') {
3672 * first dot in pattern;
3673 * must match dot or end of name
3678 else if (tcn1 == '.') {
3687 else if (tcp1 == '?') {
3688 if (tcn1 == 0 || tcn1 == '.')
3693 else if (tcp1 == '>') {
3694 if (tcn1 != 0 && tcn1 != '.')
3698 else if (tcp1 == '*' || tcp1 == '<') {
3702 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3703 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3718 * pattern character after '*' is not null or
3719 * period. If it is '?' or '>', we are not
3720 * going to understand it. If it is '*' or
3721 * '<', we are going to skip over it. None of
3722 * these are likely, I hope.
3724 /* skip over '*' and '<' */
3725 while (tcp2 == '*' || tcp2 == '<')
3728 /* skip over characters that don't match tcp2 */
3729 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
3730 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
3731 (!casefold && tcn1 != tcp2)))
3735 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3738 /* Remember where we are */
3748 /* tcp1 is not a wildcard */
3749 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
3750 (!casefold && tcn1 == tcp1)) {
3755 /* if trying to match a star pattern, go back */
3757 maskp = starMaskp - 2;
3758 namep = starNamep + 1;
3767 #endif /* USE_OLD_MATCHING */
3769 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3774 long code = 0, code2 = 0;
3778 smb_dirListPatch_t *dirListPatchesp;
3779 smb_dirListPatch_t *curPatchp;
3782 long orbytes; /* # of bytes in this output record */
3783 long ohbytes; /* # of bytes, except file name */
3784 long onbytes; /* # of bytes in name, incl. term. null */
3785 osi_hyper_t dirLength;
3786 osi_hyper_t bufferOffset;
3787 osi_hyper_t curOffset;
3789 smb_dirSearch_t *dsp;
3793 cm_pageHeader_t *pageHeaderp;
3794 cm_user_t *userp = NULL;
3797 long nextEntryCookie;
3798 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3799 char *op; /* output data ptr */
3800 char *origOp; /* original value of op */
3801 cm_space_t *spacep; /* for pathname buffer */
3802 long maxReturnData; /* max # of return data */
3803 long maxReturnParms; /* max # of return parms */
3804 long bytesInBuffer; /* # data bytes in the output buffer */
3806 char *maskp; /* mask part of path */
3810 smb_tran2Packet_t *outp; /* response packet */
3813 char shortName[13]; /* 8.3 name if needed */
3824 if (p->opcode == 1) {
3825 /* find first; obtain basic parameters from request */
3826 attribute = p->parmsp[0];
3827 maxCount = p->parmsp[1];
3828 infoLevel = p->parmsp[3];
3829 searchFlags = p->parmsp[2];
3830 dsp = smb_NewDirSearch(1);
3831 dsp->attribute = attribute;
3832 pathp = ((char *) p->parmsp) + 12; /* points to path */
3833 if (smb_StoreAnsiFilenames)
3834 OemToChar(pathp,pathp);
3836 maskp = strrchr(pathp, '\\');
3840 maskp++; /* skip over backslash */
3841 strcpy(dsp->mask, maskp); /* and save mask */
3842 /* track if this is likely to match a lot of entries */
3843 starPattern = smb_V3IsStarMask(maskp);
3846 osi_assert(p->opcode == 2);
3847 /* find next; obtain basic parameters from request or open dir file */
3848 dsp = smb_FindDirSearch(p->parmsp[0]);
3849 maxCount = p->parmsp[1];
3850 infoLevel = p->parmsp[2];
3851 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
3852 searchFlags = p->parmsp[5];
3854 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
3855 p->parmsp[0], nextCookie);
3856 return CM_ERROR_BADFD;
3858 attribute = dsp->attribute;
3861 starPattern = 1; /* assume, since required a Find Next */
3865 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
3866 attribute, infoLevel, maxCount, searchFlags);
3868 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
3869 p->opcode, dsp->cookie, nextCookie);
3871 if (infoLevel >= 0x101)
3872 searchFlags &= ~4; /* no resume keys */
3874 dirListPatchesp = NULL;
3876 maxReturnData = p->maxReturnData;
3877 if (p->opcode == 1) /* find first */
3878 maxReturnParms = 10; /* bytes */
3880 maxReturnParms = 8; /* bytes */
3882 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
3883 if (maxReturnData > 6000)
3884 maxReturnData = 6000;
3885 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
3887 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
3890 osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
3891 maxCount, osi_LogSaveString(smb_logp, pathp));
3893 /* bail out if request looks bad */
3894 if (p->opcode == 1 && !pathp) {
3895 smb_ReleaseDirSearch(dsp);
3896 smb_FreeTran2Packet(outp);
3897 return CM_ERROR_BADSMB;
3900 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
3901 dsp->cookie, nextCookie, attribute);
3903 userp = smb_GetTran2User(vcp, p);
3905 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
3906 smb_ReleaseDirSearch(dsp);
3907 smb_FreeTran2Packet(outp);
3908 return CM_ERROR_BADSMB;
3911 /* try to get the vnode for the path name next */
3912 lock_ObtainMutex(&dsp->mx);
3918 spacep = cm_GetSpace();
3919 smb_StripLastComponent(spacep->data, NULL, pathp);
3920 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3922 cm_ReleaseUser(userp);
3923 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
3924 smb_FreeTran2Packet(outp);
3925 lock_ReleaseMutex(&dsp->mx);
3926 smb_DeleteDirSearch(dsp);
3927 smb_ReleaseDirSearch(dsp);
3930 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3931 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3932 userp, tidPathp, &req, &scp);
3933 cm_FreeSpace(spacep);
3936 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
3937 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3938 cm_ReleaseSCache(scp);
3939 cm_ReleaseUser(userp);
3940 if ( WANTS_DFS_PATHNAMES(p) )
3941 code = CM_ERROR_PATH_NOT_COVERED;
3943 code = CM_ERROR_BADSHARENAME;
3944 smb_SendTran2Error(vcp, p, opx, code);
3945 smb_FreeTran2Packet(outp);
3946 lock_ReleaseMutex(&dsp->mx);
3947 smb_DeleteDirSearch(dsp);
3948 smb_ReleaseDirSearch(dsp);
3951 #endif /* DFS_SUPPORT */
3953 /* we need one hold for the entry we just stored into,
3954 * and one for our own processing. When we're done
3955 * with this function, we'll drop the one for our own
3956 * processing. We held it once from the namei call,
3957 * and so we do another hold now.
3960 lock_ObtainMutex(&scp->mx);
3961 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
3962 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3963 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3964 dsp->flags |= SMB_DIRSEARCH_BULKST;
3966 lock_ReleaseMutex(&scp->mx);
3969 lock_ReleaseMutex(&dsp->mx);
3971 cm_ReleaseUser(userp);
3972 smb_FreeTran2Packet(outp);
3973 smb_DeleteDirSearch(dsp);
3974 smb_ReleaseDirSearch(dsp);
3978 /* get the directory size */
3979 lock_ObtainMutex(&scp->mx);
3980 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3981 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3983 lock_ReleaseMutex(&scp->mx);
3984 cm_ReleaseSCache(scp);
3985 cm_ReleaseUser(userp);
3986 smb_FreeTran2Packet(outp);
3987 smb_DeleteDirSearch(dsp);
3988 smb_ReleaseDirSearch(dsp);
3993 dirLength = scp->length;
3995 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3996 curOffset.HighPart = 0;
3997 curOffset.LowPart = nextCookie;
3998 origOp = outp->datap;
4006 if (searchFlags & 4)
4007 /* skip over resume key */
4010 /* make sure that curOffset.LowPart doesn't point to the first
4011 * 32 bytes in the 2nd through last dir page, and that it doesn't
4012 * point at the first 13 32-byte chunks in the first dir page,
4013 * since those are dir and page headers, and don't contain useful
4016 temp = curOffset.LowPart & (2048-1);
4017 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4018 /* we're in the first page */
4019 if (temp < 13*32) temp = 13*32;
4022 /* we're in a later dir page */
4023 if (temp < 32) temp = 32;
4026 /* make sure the low order 5 bits are zero */
4029 /* now put temp bits back ito curOffset.LowPart */
4030 curOffset.LowPart &= ~(2048-1);
4031 curOffset.LowPart |= temp;
4033 /* check if we've passed the dir's EOF */
4034 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4035 osi_Log0(smb_logp, "T2 search dir passed eof");
4040 /* check if we've returned all the names that will fit in the
4041 * response packet; we check return count as well as the number
4042 * of bytes requested. We check the # of bytes after we find
4043 * the dir entry, since we'll need to check its size.
4045 if (returnedNames >= maxCount) {
4046 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4047 returnedNames, maxCount);
4051 /* see if we can use the bufferp we have now; compute in which
4052 * page the current offset would be, and check whether that's
4053 * the offset of the buffer we have. If not, get the buffer.
4055 thyper.HighPart = curOffset.HighPart;
4056 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4057 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4060 buf_Release(bufferp);
4063 lock_ReleaseMutex(&scp->mx);
4064 lock_ObtainRead(&scp->bufCreateLock);
4065 code = buf_Get(scp, &thyper, &bufferp);
4066 lock_ReleaseRead(&scp->bufCreateLock);
4067 lock_ObtainMutex(&dsp->mx);
4069 /* now, if we're doing a star match, do bulk fetching
4070 * of all of the status info for files in the dir.
4073 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
4076 lock_ObtainMutex(&scp->mx);
4077 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4078 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
4079 /* Don't bulk stat if risking timeout */
4080 int now = GetTickCount();
4081 if (now - req.startTime > 5000) {
4082 scp->bulkStatProgress = thyper;
4083 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4084 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4086 cm_TryBulkStat(scp, &thyper, userp, &req);
4089 lock_ObtainMutex(&scp->mx);
4091 lock_ReleaseMutex(&dsp->mx);
4093 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
4097 bufferOffset = thyper;
4099 /* now get the data in the cache */
4101 code = cm_SyncOp(scp, bufferp, userp, &req,
4103 CM_SCACHESYNC_NEEDCALLBACK
4104 | CM_SCACHESYNC_READ);
4106 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
4110 if (cm_HaveBuffer(scp, bufferp, 0)) {
4111 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4115 /* otherwise, load the buffer and try again */
4116 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4119 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4120 scp, bufferp, code);
4125 buf_Release(bufferp);
4129 } /* if (wrong buffer) ... */
4131 /* now we have the buffer containing the entry we're interested
4132 * in; copy it out if it represents a non-deleted entry.
4134 entryInDir = curOffset.LowPart & (2048-1);
4135 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4137 /* page header will help tell us which entries are free. Page
4138 * header can change more often than once per buffer, since
4139 * AFS 3 dir page size may be less than (but not more than)
4140 * a buffer package buffer.
4142 /* only look intra-buffer */
4143 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4144 temp &= ~(2048 - 1); /* turn off intra-page bits */
4145 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4147 /* now determine which entry we're looking at in the page.
4148 * If it is free (there's a free bitmap at the start of the
4149 * dir), we should skip these 32 bytes.
4151 slotInPage = (entryInDir & 0x7e0) >> 5;
4152 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
4153 (1 << (slotInPage & 0x7)))) {
4154 /* this entry is free */
4155 numDirChunks = 1; /* only skip this guy */
4159 tp = bufferp->datap + entryInBuffer;
4160 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4162 /* while we're here, compute the next entry's location, too,
4163 * since we'll need it when writing out the cookie into the dir
4166 * XXXX Probably should do more sanity checking.
4168 numDirChunks = cm_NameEntries(dep->name, &onbytes);
4170 /* compute offset of cookie representing next entry */
4171 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4173 /* Need 8.3 name? */
4175 if (infoLevel == SMB_QUERY_FILE_NAME_INFO
4176 && dep->fid.vnode != 0
4177 && !cm_Is8Dot3(dep->name)) {
4178 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4182 osi_Log3(smb_logp, "T2 search dir vn %u name %s (%s)",
4183 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4184 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4186 /* When matching, we are using doing a case fold if we have a wildcard mask.
4187 * If we get a non-wildcard match, it's a lookup for a specific file.
4189 if (dep->fid.vnode != 0 &&
4190 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
4192 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
4194 /* Eliminate entries that don't match requested attributes */
4195 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
4196 smb_IsDotFile(dep->name)) {
4197 osi_Log0(smb_logp, "T2 search dir skipping hidden");
4198 goto nextEntry; /* no hidden files */
4200 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4202 /* We have already done the cm_TryBulkStat above */
4203 fid.cell = scp->fid.cell;
4204 fid.volume = scp->fid.volume;
4205 fid.vnode = ntohl(dep->fid.vnode);
4206 fid.unique = ntohl(dep->fid.unique);
4207 fileType = cm_FindFileType(&fid);
4208 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
4209 "has filetype %d", dep->name,
4211 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4212 fileType == CM_SCACHETYPE_DFSLINK ||
4213 fileType == CM_SCACHETYPE_INVALID)
4214 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
4218 /* finally check if this name will fit */
4220 /* standard dir entry stuff */
4221 if (infoLevel < 0x101)
4222 ohbytes = 23; /* pre-NT */
4223 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
4224 ohbytes = 12; /* NT names only */
4226 ohbytes = 64; /* NT */
4228 if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
4229 ohbytes += 26; /* Short name & length */
4231 if (searchFlags & 4) {
4232 ohbytes += 4; /* if resume key required */
4236 && infoLevel != 0x101
4237 && infoLevel != 0x103)
4238 ohbytes += 4; /* EASIZE */
4240 /* add header to name & term. null */
4241 orbytes = onbytes + ohbytes + 1;
4243 /* now, we round up the record to a 4 byte alignment,
4244 * and we make sure that we have enough room here for
4245 * even the aligned version (so we don't have to worry
4246 * about an * overflow when we pad things out below).
4247 * That's the reason for the alignment arithmetic below.
4249 if (infoLevel >= 0x101)
4250 align = (4 - (orbytes & 3)) & 3;
4253 if (orbytes + bytesInBuffer + align > maxReturnData) {
4254 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4259 /* this is one of the entries to use: it is not deleted
4260 * and it matches the star pattern we're looking for.
4261 * Put out the name, preceded by its length.
4263 /* First zero everything else */
4264 memset(origOp, 0, ohbytes);
4266 if (infoLevel <= 0x101)
4267 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4268 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
4269 *((u_long *)(op + 8)) = onbytes;
4271 *((u_long *)(op + 60)) = onbytes;
4272 strcpy(origOp+ohbytes, dep->name);
4273 if (smb_StoreAnsiFilenames)
4274 CharToOem(origOp+ohbytes, origOp+ohbytes);
4276 /* Short name if requested and needed */
4277 if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
4278 if (NeedShortName) {
4279 strcpy(op + 70, shortName);
4280 if (smb_StoreAnsiFilenames)
4281 CharToOem(op + 70, op + 70);
4282 *(op + 68) = (char)(shortNameEnd - shortName);
4286 /* now, adjust the # of entries copied */
4289 /* NextEntryOffset and FileIndex */
4290 if (infoLevel >= 101) {
4291 int entryOffset = orbytes + align;
4292 *((u_long *)op) = entryOffset;
4293 *((u_long *)(op+4)) = nextEntryCookie;
4296 /* now we emit the attribute. This is tricky, since
4297 * we need to really stat the file to find out what
4298 * type of entry we've got. Right now, we're copying
4299 * out data from a buffer, while holding the scp
4300 * locked, so it isn't really convenient to stat
4301 * something now. We'll put in a place holder
4302 * now, and make a second pass before returning this
4303 * to get the real attributes. So, we just skip the
4304 * data for now, and adjust it later. We allocate a
4305 * patch record to make it easy to find this point
4306 * later. The replay will happen at a time when it is
4307 * safe to unlock the directory.
4309 if (infoLevel != 0x103) {
4310 curPatchp = malloc(sizeof(*curPatchp));
4311 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4313 curPatchp->dptr = op;
4314 if (infoLevel >= 0x101)
4315 curPatchp->dptr += 8;
4317 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4318 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4321 curPatchp->flags = 0;
4323 curPatchp->fid.cell = scp->fid.cell;
4324 curPatchp->fid.volume = scp->fid.volume;
4325 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4326 curPatchp->fid.unique = ntohl(dep->fid.unique);
4329 curPatchp->dep = dep;
4332 if (searchFlags & 4)
4333 /* put out resume key */
4334 *((u_long *)origOp) = nextEntryCookie;
4336 /* Adjust byte ptr and count */
4337 origOp += orbytes; /* skip entire record */
4338 bytesInBuffer += orbytes;
4340 /* and pad the record out */
4341 while (--align >= 0) {
4345 } /* if we're including this name */
4346 else if (!starPattern &&
4348 dep->fid.vnode != 0 &&
4349 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4350 /* We were looking for exact matches, but here's an inexact one*/
4355 /* and adjust curOffset to be where the new cookie is */
4356 thyper.HighPart = 0;
4357 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4358 curOffset = LargeIntegerAdd(thyper, curOffset);
4359 } /* while copying data for dir listing */
4361 /* If we didn't get a star pattern, we did an exact match during the first pass.
4362 * If there were no exact matches found, we fail over to inexact matches by
4363 * marking the query as a star pattern (matches all case permutations), and
4364 * re-running the query.
4366 if (returnedNames == 0 && !starPattern && foundInexact) {
4367 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4372 /* release the mutex */
4373 lock_ReleaseMutex(&scp->mx);
4375 buf_Release(bufferp);
4377 /* apply and free last set of patches; if not doing a star match, this
4378 * will be empty, but better safe (and freeing everything) than sorry.
4380 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4383 /* now put out the final parameters */
4384 if (returnedNames == 0)
4386 if (p->opcode == 1) {
4388 outp->parmsp[0] = (unsigned short) dsp->cookie;
4389 outp->parmsp[1] = returnedNames;
4390 outp->parmsp[2] = eos;
4391 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4392 outp->parmsp[4] = 0;
4393 /* don't need last name to continue
4394 * search, cookie is enough. Normally,
4395 * this is the offset of the file name
4396 * of the last entry returned.
4398 outp->totalParms = 10; /* in bytes */
4402 outp->parmsp[0] = returnedNames;
4403 outp->parmsp[1] = eos;
4404 outp->parmsp[2] = 0; /* EAS error */
4405 outp->parmsp[3] = 0; /* last name, as above */
4406 outp->totalParms = 8; /* in bytes */
4409 /* return # of bytes in the buffer */
4410 outp->totalData = bytesInBuffer;
4412 /* Return error code if unsuccessful on first request */
4413 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4414 code = CM_ERROR_NOSUCHFILE;
4416 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
4417 p->opcode, dsp->cookie, returnedNames, code);
4419 /* if we're supposed to close the search after this request, or if
4420 * we're supposed to close the search if we're done, and we're done,
4421 * or if something went wrong, close the search.
4423 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4424 if ((searchFlags & 1) || (returnedNames == 0) ||
4425 ((searchFlags & 2) && eos) || code != 0)
4426 smb_DeleteDirSearch(dsp);
4428 smb_SendTran2Error(vcp, p, opx, code);
4430 smb_SendTran2Packet(vcp, outp, opx);
4432 smb_FreeTran2Packet(outp);
4433 smb_ReleaseDirSearch(dsp);
4434 cm_ReleaseSCache(scp);
4435 cm_ReleaseUser(userp);
4439 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4442 smb_dirSearch_t *dsp;
4444 dirHandle = smb_GetSMBParm(inp, 0);
4446 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4448 dsp = smb_FindDirSearch(dirHandle);
4451 return CM_ERROR_BADFD;
4453 /* otherwise, we have an FD to destroy */
4454 smb_DeleteDirSearch(dsp);
4455 smb_ReleaseDirSearch(dsp);
4457 /* and return results */
4458 smb_SetSMBDataLength(outp, 0);
4463 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4465 smb_SetSMBDataLength(outp, 0);
4469 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4476 cm_scache_t *dscp; /* dir we're dealing with */
4477 cm_scache_t *scp; /* file we're creating */
4479 int initialModeBits;
4489 int parmSlot; /* which parm we're dealing with */
4497 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4498 openFun = smb_GetSMBParm(inp, 8); /* open function */
4499 excl = ((openFun & 3) == 0);
4500 trunc = ((openFun & 3) == 2); /* truncate it */
4501 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4502 openAction = 0; /* tracks what we did */
4504 attributes = smb_GetSMBParm(inp, 5);
4505 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4507 /* compute initial mode bits based on read-only flag in attributes */
4508 initialModeBits = 0666;
4509 if (attributes & 1) initialModeBits &= ~0222;
4511 pathp = smb_GetSMBData(inp, NULL);
4512 if (smb_StoreAnsiFilenames)
4513 OemToChar(pathp,pathp);
4515 spacep = inp->spacep;
4516 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4518 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4519 /* special case magic file name for receiving IOCTL requests
4520 * (since IOCTL calls themselves aren't getting through).
4523 osi_Log0(smb_logp, "IOCTL Open");
4526 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4527 smb_SetupIoctlFid(fidp, spacep);
4529 /* set inp->fid so that later read calls in same msg can find fid */
4530 inp->fid = fidp->fid;
4532 /* copy out remainder of the parms */
4534 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4536 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4537 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4538 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4539 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4540 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4541 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4542 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4543 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4545 /* and the final "always present" stuff */
4546 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4547 /* next write out the "unique" ID */
4548 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4549 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4550 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4551 smb_SetSMBDataLength(outp, 0);
4553 /* and clean up fid reference */
4554 smb_ReleaseFID(fidp);
4558 #ifdef DEBUG_VERBOSE
4560 char *hexp, *asciip;
4561 asciip = (lastNamep ? lastNamep : pathp );
4562 hexp = osi_HexifyString(asciip);
4563 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4567 userp = smb_GetUser(vcp, inp);
4570 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4572 cm_ReleaseUser(userp);
4573 return CM_ERROR_NOSUCHPATH;
4575 code = cm_NameI(cm_data.rootSCachep, pathp,
4576 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4577 userp, tidPathp, &req, &scp);
4580 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4581 cm_ReleaseSCache(scp);
4582 cm_ReleaseUser(userp);
4583 if ( WANTS_DFS_PATHNAMES(inp) )
4584 return CM_ERROR_PATH_NOT_COVERED;
4586 return CM_ERROR_BADSHARENAME;
4588 #endif /* DFS_SUPPORT */
4591 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4592 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4593 userp, tidPathp, &req, &dscp);
4595 cm_ReleaseUser(userp);
4600 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4601 cm_ReleaseSCache(dscp);
4602 cm_ReleaseUser(userp);
4603 if ( WANTS_DFS_PATHNAMES(inp) )
4604 return CM_ERROR_PATH_NOT_COVERED;
4606 return CM_ERROR_BADSHARENAME;
4608 #endif /* DFS_SUPPORT */
4610 /* otherwise, scp points to the parent directory. Do a lookup,
4611 * and truncate the file if we find it, otherwise we create the
4618 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
4620 if (code && code != CM_ERROR_NOSUCHFILE) {
4621 cm_ReleaseSCache(dscp);
4622 cm_ReleaseUser(userp);
4627 /* if we get here, if code is 0, the file exists and is represented by
4628 * scp. Otherwise, we have to create it. The dir may be represented
4629 * by dscp, or we may have found the file directly. If code is non-zero,
4633 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
4635 if (dscp) cm_ReleaseSCache(dscp);
4636 cm_ReleaseSCache(scp);
4637 cm_ReleaseUser(userp);
4642 /* oops, file shouldn't be there */
4644 cm_ReleaseSCache(dscp);
4645 cm_ReleaseSCache(scp);
4646 cm_ReleaseUser(userp);
4647 return CM_ERROR_EXISTS;
4651 setAttr.mask = CM_ATTRMASK_LENGTH;
4652 setAttr.length.LowPart = 0;
4653 setAttr.length.HighPart = 0;
4654 code = cm_SetAttr(scp, &setAttr, userp, &req);
4655 openAction = 3; /* truncated existing file */
4657 else openAction = 1; /* found existing file */
4659 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
4660 /* don't create if not found */
4661 if (dscp) cm_ReleaseSCache(dscp);
4662 cm_ReleaseUser(userp);
4663 return CM_ERROR_NOSUCHFILE;
4666 osi_assert(dscp != NULL);
4667 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
4668 osi_LogSaveString(smb_logp, lastNamep));
4669 openAction = 2; /* created file */
4670 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4671 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
4672 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4674 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4675 smb_NotifyChange(FILE_ACTION_ADDED,
4676 FILE_NOTIFY_CHANGE_FILE_NAME,
4677 dscp, lastNamep, NULL, TRUE);
4678 if (!excl && code == CM_ERROR_EXISTS) {
4679 /* not an exclusive create, and someone else tried
4680 * creating it already, then we open it anyway. We
4681 * don't bother retrying after this, since if this next
4682 * fails, that means that the file was deleted after we
4683 * started this call.
4685 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4689 setAttr.mask = CM_ATTRMASK_LENGTH;
4690 setAttr.length.LowPart = 0;
4691 setAttr.length.HighPart = 0;
4692 code = cm_SetAttr(scp, &setAttr, userp, &req);
4694 } /* lookup succeeded */
4698 /* we don't need this any longer */
4700 cm_ReleaseSCache(dscp);
4703 /* something went wrong creating or truncating the file */
4705 cm_ReleaseSCache(scp);
4706 cm_ReleaseUser(userp);
4710 /* make sure we're about to open a file */
4711 if (scp->fileType != CM_SCACHETYPE_FILE) {
4712 cm_ReleaseSCache(scp);
4713 cm_ReleaseUser(userp);
4714 return CM_ERROR_ISDIR;
4717 /* now all we have to do is open the file itself */
4718 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4721 /* save a pointer to the vnode */
4725 fidp->userp = userp;
4727 /* compute open mode */
4729 fidp->flags |= SMB_FID_OPENREAD;
4730 if (openMode == 1 || openMode == 2)
4731 fidp->flags |= SMB_FID_OPENWRITE;
4733 smb_ReleaseFID(fidp);
4735 cm_Open(scp, 0, userp);
4737 /* set inp->fid so that later read calls in same msg can find fid */
4738 inp->fid = fidp->fid;
4740 /* copy out remainder of the parms */
4742 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4743 lock_ObtainMutex(&scp->mx);
4745 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
4746 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4747 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
4748 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
4749 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
4750 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
4751 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4752 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4753 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4755 /* and the final "always present" stuff */
4756 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
4757 /* next write out the "unique" ID */
4758 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
4759 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
4760 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4761 lock_ReleaseMutex(&scp->mx);
4762 smb_SetSMBDataLength(outp, 0);
4764 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
4766 cm_ReleaseUser(userp);
4767 /* leave scp held since we put it in fidp->scp */
4771 static void smb_GetLockParams(unsigned char LockType,
4773 unsigned int * ppid,
4774 LARGE_INTEGER * pOffset,
4775 LARGE_INTEGER * pLength)
4777 if (LockType & LOCKING_ANDX_LARGE_FILES) {
4779 *ppid = *((USHORT *) *buf);
4780 pOffset->HighPart = *((LONG *)(*buf + 4));
4781 pOffset->LowPart = *((DWORD *)(*buf + 8));
4782 pLength->HighPart = *((LONG *)(*buf + 12));
4783 pLength->LowPart = *((DWORD *)(*buf + 16));
4787 /* Not Large Files */
4788 *ppid = *((USHORT *) *buf);
4789 pOffset->HighPart = 0;
4790 pOffset->LowPart = *((DWORD *)(*buf + 2));
4791 pLength->HighPart = 0;
4792 pLength->LowPart = *((DWORD *)(*buf + 6));
4797 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4804 unsigned char LockType;
4805 unsigned short NumberOfUnlocks, NumberOfLocks;
4809 LARGE_INTEGER LOffset, LLength;
4810 smb_waitingLockRequest_t *wlRequest = NULL;
4811 cm_file_lock_t *lockp;
4819 fid = smb_GetSMBParm(inp, 2);
4820 fid = smb_ChainFID(fid, inp);
4822 fidp = smb_FindFID(vcp, fid, 0);
4823 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4824 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
4825 return CM_ERROR_BADFD;
4827 /* set inp->fid so that later read calls in same msg can find fid */
4830 userp = smb_GetUser(vcp, inp);
4834 lock_ObtainMutex(&scp->mx);
4835 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4836 CM_SCACHESYNC_NEEDCALLBACK
4837 | CM_SCACHESYNC_GETSTATUS
4838 | CM_SCACHESYNC_LOCK);
4840 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
4844 LockType = smb_GetSMBParm(inp, 3) & 0xff;
4845 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
4846 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
4847 NumberOfLocks = smb_GetSMBParm(inp, 7);
4849 if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
4850 (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
4852 /* We don't support these requests. Apparently, we can safely
4853 not deal with them too. */
4854 osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
4855 ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
4856 "LOCKING_ANDX_CANCEL_LOCK":
4857 "LOCKING_ANDX_CHANGE_LOCKTYPE"));
4858 /* No need to call osi_LogSaveString since these are string
4861 code = CM_ERROR_BADOP;
4866 op = smb_GetSMBData(inp, NULL);
4868 for (i=0; i<NumberOfUnlocks; i++) {
4869 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
4871 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
4873 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
4881 for (i=0; i<NumberOfLocks; i++) {
4882 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
4884 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
4886 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
4887 userp, &req, &lockp);
4889 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
4890 smb_waitingLock_t * wLock;
4892 /* Put on waiting list */
4893 if(wlRequest == NULL) {
4897 LARGE_INTEGER tOffset, tLength;
4899 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
4901 osi_assert(wlRequest != NULL);
4903 wlRequest->vcp = vcp;
4905 wlRequest->scp = scp;
4907 wlRequest->inp = smb_CopyPacket(inp);
4908 wlRequest->outp = smb_CopyPacket(outp);
4909 wlRequest->lockType = LockType;
4910 wlRequest->timeRemaining = Timeout;
4911 wlRequest->locks = NULL;
4913 /* The waiting lock request needs to have enough
4914 information to undo all the locks in the request.
4915 We do the following to store info about locks that
4916 have already been granted. Sure, we can get most
4917 of the info from the packet, but the packet doesn't
4918 hold the result of cm_Lock call. In practice we
4919 only receive packets with one or two locks, so we
4920 are only wasting a few bytes here and there and
4921 only for a limited period of time until the waiting
4922 lock times out or is freed. */
4924 for(opt = op_locks, j=i; j > 0; j--) {
4925 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
4927 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
4929 wLock = malloc(sizeof(smb_waitingLock_t));
4931 osi_assert(wLock != NULL);
4934 wLock->LOffset = tOffset;
4935 wLock->LLength = tLength;
4936 wLock->lockp = NULL;
4937 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
4938 osi_QAdd((osi_queue_t **) &wlRequest->locks,
4943 wLock = malloc(sizeof(smb_waitingLock_t));
4945 osi_assert(wLock != NULL);
4948 wLock->LOffset = LOffset;
4949 wLock->LLength = LLength;
4950 wLock->lockp = lockp;
4951 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
4952 osi_QAdd((osi_queue_t **) &wlRequest->locks,
4955 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
4963 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
4970 /* Since something went wrong with the lock number i, we now
4971 have to go ahead and release any locks acquired before the
4972 failure. All locks before lock number i (of which there
4973 are i of them) have either been successful or are waiting.
4974 Either case requires calling cm_Unlock(). */
4976 /* And purge the waiting lock */
4977 if(wlRequest != NULL) {
4978 smb_waitingLock_t * wl;
4979 smb_waitingLock_t * wlNext;
4982 for(wl = wlRequest->locks; wl; wl = wlNext) {
4984 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4986 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
4989 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
4991 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
4994 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4999 smb_ReleaseVC(wlRequest->vcp);
5000 cm_ReleaseSCache(wlRequest->scp);
5001 smb_FreePacket(wlRequest->inp);
5002 smb_FreePacket(wlRequest->outp);
5011 if (wlRequest != NULL) {
5013 lock_ObtainWrite(&smb_globalLock);
5014 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
5016 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
5017 lock_ReleaseWrite(&smb_globalLock);
5019 /* don't send reply immediately */
5020 outp->flags |= SMB_PACKETFLAG_NOSEND;
5023 smb_SetSMBDataLength(outp, 0);
5027 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5030 lock_ReleaseMutex(&scp->mx);
5031 cm_ReleaseUser(userp);
5032 smb_ReleaseFID(fidp);
5037 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5043 afs_uint32 searchTime;
5049 fid = smb_GetSMBParm(inp, 0);
5050 fid = smb_ChainFID(fid, inp);
5052 fidp = smb_FindFID(vcp, fid, 0);
5053 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5054 return CM_ERROR_BADFD;
5057 userp = smb_GetUser(vcp, inp);
5061 /* otherwise, stat the file */
5062 lock_ObtainMutex(&scp->mx);
5063 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5064 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5065 if (code) goto done;
5067 /* decode times. We need a search time, but the response to this
5068 * call provides the date first, not the time, as returned in the
5069 * searchTime variable. So we take the high-order bits first.
5071 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
5072 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
5073 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
5074 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
5075 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
5076 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
5077 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
5079 /* now handle file size and allocation size */
5080 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
5081 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
5082 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
5083 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
5085 /* file attribute */
5086 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
5088 /* and finalize stuff */
5089 smb_SetSMBDataLength(outp, 0);
5093 lock_ReleaseMutex(&scp->mx);
5094 cm_ReleaseUser(userp);
5095 smb_ReleaseFID(fidp);
5099 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5105 afs_uint32 searchTime;
5113 fid = smb_GetSMBParm(inp, 0);
5114 fid = smb_ChainFID(fid, inp);
5116 fidp = smb_FindFID(vcp, fid, 0);
5117 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5118 return CM_ERROR_BADFD;
5121 userp = smb_GetUser(vcp, inp);
5125 /* now prepare to call cm_setattr. This message only sets various times,
5126 * and AFS only implements mtime, and we'll set the mtime if that's
5127 * requested. The others we'll ignore.
5129 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
5131 if (searchTime != 0) {
5132 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
5134 if ( unixTime != -1 ) {
5135 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
5136 attrs.clientModTime = unixTime;
5137 code = cm_SetAttr(scp, &attrs, userp, &req);
5139 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
5141 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
5146 cm_ReleaseUser(userp);
5147 smb_ReleaseFID(fidp);
5152 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5156 long finalCount = 0;
5165 fd = smb_GetSMBParm(inp, 2);
5166 count = smb_GetSMBParm(inp, 5);
5167 offset.HighPart = 0; /* too bad */
5168 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5170 osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
5171 fd, offset.LowPart, count);
5173 fd = smb_ChainFID(fd, inp);
5174 fidp = smb_FindFID(vcp, fd, 0);
5176 return CM_ERROR_BADFD;
5179 pid = ((smb_t *) inp)->pid;
5180 key = cm_GenerateKey(vcp->vcID, pid, fd);
5182 LARGE_INTEGER LOffset, LLength;
5184 LOffset.HighPart = offset.HighPart;
5185 LOffset.LowPart = offset.LowPart;
5186 LLength.HighPart = 0;
5187 LLength.LowPart = count;
5189 lock_ObtainMutex(&fidp->scp->mx);
5190 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
5191 lock_ReleaseMutex(&fidp->scp->mx);
5195 smb_ReleaseFID(fidp);
5199 /* set inp->fid so that later read calls in same msg can find fid */
5202 if (fidp->flags & SMB_FID_IOCTL) {
5203 return smb_IoctlV3Read(fidp, vcp, inp, outp);
5206 userp = smb_GetUser(vcp, inp);
5208 /* 0 and 1 are reserved for request chaining, were setup by our caller,
5209 * and will be further filled in after we return.
5211 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
5212 smb_SetSMBParm(outp, 3, 0); /* resvd */
5213 smb_SetSMBParm(outp, 4, 0); /* resvd */
5214 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
5215 /* fill in #6 when we have all the parameters' space reserved */
5216 smb_SetSMBParm(outp, 7, 0); /* resv'd */
5217 smb_SetSMBParm(outp, 8, 0); /* resv'd */
5218 smb_SetSMBParm(outp, 9, 0); /* resv'd */
5219 smb_SetSMBParm(outp, 10, 0); /* resv'd */
5220 smb_SetSMBParm(outp, 11, 0); /* reserved */
5222 /* get op ptr after putting in the parms, since otherwise we don't
5223 * know where the data really is.
5225 op = smb_GetSMBData(outp, NULL);
5227 /* now fill in offset from start of SMB header to first data byte (to op) */
5228 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
5230 /* set the packet data length the count of the # of bytes */
5231 smb_SetSMBDataLength(outp, count);
5234 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5236 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5239 /* fix some things up */
5240 smb_SetSMBParm(outp, 5, finalCount);
5241 smb_SetSMBDataLength(outp, finalCount);
5243 smb_ReleaseFID(fidp);
5245 cm_ReleaseUser(userp);
5250 * Values for createDisp, copied from NTDDK.H
5252 #define FILE_SUPERSEDE 0 // (???)
5253 #define FILE_OPEN 1 // (open)
5254 #define FILE_CREATE 2 // (exclusive)
5255 #define FILE_OPEN_IF 3 // (non-exclusive)
5256 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
5257 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
5260 #define REQUEST_OPLOCK 2
5261 #define REQUEST_BATCH_OPLOCK 4
5262 #define OPEN_DIRECTORY 8
5263 #define EXTENDED_RESPONSE_REQUIRED 0x10
5265 /* CreateOptions field. */
5266 #define FILE_DIRECTORY_FILE 0x0001
5267 #define FILE_WRITE_THROUGH 0x0002
5268 #define FILE_SEQUENTIAL_ONLY 0x0004
5269 #define FILE_NON_DIRECTORY_FILE 0x0040
5270 #define FILE_NO_EA_KNOWLEDGE 0x0200
5271 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
5272 #define FILE_RANDOM_ACCESS 0x0800
5273 #define FILE_DELETE_ON_CLOSE 0x1000
5274 #define FILE_OPEN_BY_FILE_ID 0x2000
5276 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5278 char *pathp, *realPathp;
5282 cm_scache_t *dscp; /* parent dir */
5283 cm_scache_t *scp; /* file to create or open */
5284 cm_scache_t *targetScp; /* if scp is a symlink */
5288 unsigned short nameLength;
5290 unsigned int requestOpLock;
5291 unsigned int requestBatchOpLock;
5292 unsigned int mustBeDir;
5293 unsigned int extendedRespRequired;
5294 unsigned int treeCreate;
5296 unsigned int desiredAccess;
5297 unsigned int extAttributes;
5298 unsigned int createDisp;
5299 unsigned int createOptions;
5300 unsigned int shareAccess;
5301 int initialModeBits;
5302 unsigned short baseFid;
5303 smb_fid_t *baseFidp;
5305 cm_scache_t *baseDirp;
5306 unsigned short openAction;
5317 /* This code is very long and has a lot of if-then-else clauses
5318 * scp and dscp get reused frequently and we need to ensure that
5319 * we don't lose a reference. Start by ensuring that they are NULL.
5326 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
5327 flags = smb_GetSMBOffsetParm(inp, 3, 1)
5328 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
5329 requestOpLock = flags & REQUEST_OPLOCK;
5330 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
5331 mustBeDir = flags & OPEN_DIRECTORY;
5332 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
5335 * Why all of a sudden 32-bit FID?
5336 * We will reject all bits higher than 16.
5338 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
5339 return CM_ERROR_INVAL;
5340 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
5341 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
5342 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
5343 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
5344 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
5345 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
5346 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
5347 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
5348 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
5349 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
5350 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
5352 /* mustBeDir is never set; createOptions directory bit seems to be
5355 if (createOptions & FILE_DIRECTORY_FILE)
5357 else if (createOptions & FILE_NON_DIRECTORY_FILE)
5363 * compute initial mode bits based on read-only flag in
5364 * extended attributes
5366 initialModeBits = 0666;
5367 if (extAttributes & SMB_ATTR_READONLY)
5368 initialModeBits &= ~0222;
5370 pathp = smb_GetSMBData(inp, NULL);
5371 /* Sometimes path is not null-terminated, so we make a copy. */
5372 realPathp = malloc(nameLength+1);
5373 memcpy(realPathp, pathp, nameLength);
5374 realPathp[nameLength] = 0;
5375 if (smb_StoreAnsiFilenames)
5376 OemToChar(realPathp,realPathp);
5378 spacep = inp->spacep;
5379 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5381 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
5382 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
5383 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
5385 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5386 /* special case magic file name for receiving IOCTL requests
5387 * (since IOCTL calls themselves aren't getting through).
5389 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5390 smb_SetupIoctlFid(fidp, spacep);
5391 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
5393 /* set inp->fid so that later read calls in same msg can find fid */
5394 inp->fid = fidp->fid;
5398 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5399 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5400 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
5402 memset(&ft, 0, sizeof(ft));
5403 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5404 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5405 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5406 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5407 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
5408 sz.HighPart = 0x7fff; sz.LowPart = 0;
5409 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
5410 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
5411 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
5412 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
5413 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
5414 smb_SetSMBDataLength(outp, 0);
5416 /* clean up fid reference */
5417 smb_ReleaseFID(fidp);
5422 #ifdef DEBUG_VERBOSE
5424 char *hexp, *asciip;
5425 asciip = (lastNamep? lastNamep : realPathp);
5426 hexp = osi_HexifyString( asciip );
5427 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
5432 userp = smb_GetUser(vcp, inp);
5434 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
5436 return CM_ERROR_INVAL;
5440 baseDirp = cm_data.rootSCachep;
5441 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5442 if (code == CM_ERROR_TIDIPC) {
5443 /* Attempt to use a TID allocated for IPC. The client
5444 * is probably looking for DCE RPC end points which we
5445 * don't support OR it could be looking to make a DFS
5448 osi_Log0(smb_logp, "NTCreateX received IPC TID");
5451 cm_ReleaseUser(userp);
5452 return CM_ERROR_NOSUCHFILE;
5453 #endif /* DFS_SUPPORT */
5456 baseFidp = smb_FindFID(vcp, baseFid, 0);
5458 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
5460 cm_ReleaseUser(userp);
5461 return CM_ERROR_INVAL;
5463 baseDirp = baseFidp->scp;
5467 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
5469 /* compute open mode */
5471 if (desiredAccess & DELETE)
5472 fidflags |= SMB_FID_OPENDELETE;
5473 if (desiredAccess & AFS_ACCESS_READ)
5474 fidflags |= SMB_FID_OPENREAD;
5475 if (desiredAccess & AFS_ACCESS_WRITE)
5476 fidflags |= SMB_FID_OPENWRITE;
5477 if (createOptions & FILE_DELETE_ON_CLOSE)
5478 fidflags |= SMB_FID_DELONCLOSE;
5480 /* and the share mode */
5481 if (shareAccess & FILE_SHARE_READ)
5482 fidflags |= SMB_FID_SHARE_READ;
5483 if (shareAccess & FILE_SHARE_WRITE)
5484 fidflags |= SMB_FID_SHARE_WRITE;
5488 /* For an exclusive create, we want to do a case sensitive match for the last component. */
5489 if ( createDisp == FILE_CREATE ||
5490 createDisp == FILE_OVERWRITE ||
5491 createDisp == FILE_OVERWRITE_IF) {
5492 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5493 userp, tidPathp, &req, &dscp);
5496 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5497 cm_ReleaseSCache(dscp);
5498 cm_ReleaseUser(userp);
5500 if ( WANTS_DFS_PATHNAMES(inp) )
5501 return CM_ERROR_PATH_NOT_COVERED;
5503 return CM_ERROR_BADSHARENAME;
5505 #endif /* DFS_SUPPORT */
5506 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5508 if (code == CM_ERROR_NOSUCHFILE) {
5509 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
5510 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
5511 if (code == 0 && realDirFlag == 1) {
5512 cm_ReleaseSCache(scp);
5513 cm_ReleaseSCache(dscp);
5514 cm_ReleaseUser(userp);
5516 return CM_ERROR_EXISTS;
5520 /* we have both scp and dscp */
5522 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5523 userp, tidPathp, &req, &scp);
5525 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5526 cm_ReleaseSCache(scp);
5527 cm_ReleaseUser(userp);
5529 if ( WANTS_DFS_PATHNAMES(inp) )
5530 return CM_ERROR_PATH_NOT_COVERED;
5532 return CM_ERROR_BADSHARENAME;
5534 #endif /* DFS_SUPPORT */
5535 /* we might have scp but not dscp */
5541 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
5542 /* look up parent directory */
5543 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
5544 * the immediate parent. We have to work our way up realPathp until we hit something that we
5548 /* we might or might not have scp */
5554 code = cm_NameI(baseDirp, spacep->data,
5555 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5556 userp, tidPathp, &req, &dscp);
5559 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5561 cm_ReleaseSCache(scp);
5562 cm_ReleaseSCache(dscp);
5563 cm_ReleaseUser(userp);
5565 if ( WANTS_DFS_PATHNAMES(inp) )
5566 return CM_ERROR_PATH_NOT_COVERED;
5568 return CM_ERROR_BADSHARENAME;
5570 #endif /* DFS_SUPPORT */
5573 (tp = strrchr(spacep->data,'\\')) &&
5574 (createDisp == FILE_CREATE) &&
5575 (realDirFlag == 1)) {
5578 treeStartp = realPathp + (tp - spacep->data);
5580 if (*tp && !smb_IsLegalFilename(tp)) {
5582 smb_ReleaseFID(baseFidp);
5583 cm_ReleaseUser(userp);
5586 cm_ReleaseSCache(scp);
5587 return CM_ERROR_BADNTFILENAME;
5591 } while (dscp == NULL && code == 0);
5595 /* we might have scp and we might have dscp */
5598 smb_ReleaseFID(baseFidp);
5601 osi_Log0(smb_logp,"NTCreateX parent not found");
5603 cm_ReleaseSCache(scp);
5605 cm_ReleaseSCache(dscp);
5606 cm_ReleaseUser(userp);
5611 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
5612 /* A file exists where we want a directory. */
5614 cm_ReleaseSCache(scp);
5615 cm_ReleaseSCache(dscp);
5616 cm_ReleaseUser(userp);
5618 return CM_ERROR_EXISTS;
5622 lastNamep = realPathp;
5626 if (!smb_IsLegalFilename(lastNamep)) {
5628 cm_ReleaseSCache(scp);
5630 cm_ReleaseSCache(dscp);
5631 cm_ReleaseUser(userp);
5633 return CM_ERROR_BADNTFILENAME;
5636 if (!foundscp && !treeCreate) {
5637 if ( createDisp == FILE_CREATE ||
5638 createDisp == FILE_OVERWRITE ||
5639 createDisp == FILE_OVERWRITE_IF)
5641 code = cm_Lookup(dscp, lastNamep,
5642 CM_FLAG_FOLLOW, userp, &req, &scp);
5644 code = cm_Lookup(dscp, lastNamep,
5645 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5648 if (code && code != CM_ERROR_NOSUCHFILE) {
5650 cm_ReleaseSCache(dscp);
5651 cm_ReleaseUser(userp);
5656 /* we have scp and dscp */
5658 /* we have scp but not dscp */
5660 smb_ReleaseFID(baseFidp);
5663 /* if we get here, if code is 0, the file exists and is represented by
5664 * scp. Otherwise, we have to create it. The dir may be represented
5665 * by dscp, or we may have found the file directly. If code is non-zero,
5668 if (code == 0 && !treeCreate) {
5669 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req);
5672 cm_ReleaseSCache(dscp);
5674 cm_ReleaseSCache(scp);
5675 cm_ReleaseUser(userp);
5680 if (createDisp == FILE_CREATE) {
5681 /* oops, file shouldn't be there */
5683 cm_ReleaseSCache(dscp);
5685 cm_ReleaseSCache(scp);
5686 cm_ReleaseUser(userp);
5688 return CM_ERROR_EXISTS;
5691 if ( createDisp == FILE_OVERWRITE ||
5692 createDisp == FILE_OVERWRITE_IF) {
5694 setAttr.mask = CM_ATTRMASK_LENGTH;
5695 setAttr.length.LowPart = 0;
5696 setAttr.length.HighPart = 0;
5697 /* now watch for a symlink */
5699 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5701 osi_assert(dscp != NULL);
5702 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5704 /* we have a more accurate file to use (the
5705 * target of the symbolic link). Otherwise,
5706 * we'll just use the symlink anyway.
5708 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5710 cm_ReleaseSCache(scp);
5714 code = cm_SetAttr(scp, &setAttr, userp, &req);
5715 openAction = 3; /* truncated existing file */
5718 openAction = 1; /* found existing file */
5720 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
5721 /* don't create if not found */
5723 cm_ReleaseSCache(dscp);
5725 cm_ReleaseSCache(scp);
5726 cm_ReleaseUser(userp);
5728 return CM_ERROR_NOSUCHFILE;
5729 } else if (realDirFlag == 0 || realDirFlag == -1) {
5730 osi_assert(dscp != NULL);
5731 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
5732 osi_LogSaveString(smb_logp, lastNamep));
5733 openAction = 2; /* created file */
5734 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5735 setAttr.clientModTime = time(NULL);
5736 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
5737 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5738 smb_NotifyChange(FILE_ACTION_ADDED,
5739 FILE_NOTIFY_CHANGE_FILE_NAME,
5740 dscp, lastNamep, NULL, TRUE);
5741 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
5742 /* Not an exclusive create, and someone else tried
5743 * creating it already, then we open it anyway. We
5744 * don't bother retrying after this, since if this next
5745 * fails, that means that the file was deleted after we
5746 * started this call.
5748 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5751 if (createDisp == FILE_OVERWRITE_IF) {
5752 setAttr.mask = CM_ATTRMASK_LENGTH;
5753 setAttr.length.LowPart = 0;
5754 setAttr.length.HighPart = 0;
5756 /* now watch for a symlink */
5758 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5760 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5762 /* we have a more accurate file to use (the
5763 * target of the symbolic link). Otherwise,
5764 * we'll just use the symlink anyway.
5766 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5768 cm_ReleaseSCache(scp);
5772 code = cm_SetAttr(scp, &setAttr, userp, &req);
5774 } /* lookup succeeded */
5778 char *cp; /* This component */
5779 int clen = 0; /* length of component */
5780 cm_scache_t *tscp1, *tscp2;
5783 /* create directory */
5785 treeStartp = lastNamep;
5786 osi_assert(dscp != NULL);
5787 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
5788 osi_LogSaveString(smb_logp, treeStartp));
5789 openAction = 2; /* created directory */
5791 /* if the request is to create the root directory
5792 * it will appear as a directory name of the nul-string
5793 * and a code of CM_ERROR_NOSUCHFILE
5795 if ( !*treeStartp && code == CM_ERROR_NOSUCHFILE)
5796 code = CM_ERROR_EXISTS;
5798 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5799 setAttr.clientModTime = time(NULL);
5804 cm_HoldSCache(tscp1);
5808 tp = strchr(pp, '\\');
5811 clen = (int)strlen(cp);
5812 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
5814 clen = (int)(tp - pp);
5815 strncpy(cp,pp,clen);
5822 continue; /* the supplied path can't have consecutive slashes either , but */
5824 /* cp is the next component to be created. */
5825 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
5826 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
5827 smb_NotifyChange(FILE_ACTION_ADDED,
5828 FILE_NOTIFY_CHANGE_DIR_NAME,
5829 tscp1, cp, 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(tscp1, cp, CM_FLAG_CASEFOLD,
5839 userp, &req, &tscp2);
5844 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
5845 cm_ReleaseSCache(tscp1);
5846 tscp1 = tscp2; /* Newly created directory will be next parent */
5847 /* the hold is transfered to tscp1 from tscp2 */
5852 cm_ReleaseSCache(dscp);
5855 cm_ReleaseSCache(scp);
5858 * if we get here and code == 0, then scp is the last directory created, and dscp is the
5864 /* something went wrong creating or truncating the file */
5866 cm_ReleaseSCache(scp);
5868 cm_ReleaseSCache(dscp);
5869 cm_ReleaseUser(userp);
5874 /* make sure we have file vs. dir right (only applies for single component case) */
5875 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5876 /* now watch for a symlink */
5878 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5879 cm_scache_t * targetScp = 0;
5880 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5882 /* we have a more accurate file to use (the
5883 * target of the symbolic link). Otherwise,
5884 * we'll just use the symlink anyway.
5886 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
5887 cm_ReleaseSCache(scp);
5892 if (scp->fileType != CM_SCACHETYPE_FILE) {
5894 cm_ReleaseSCache(dscp);
5895 cm_ReleaseSCache(scp);
5896 cm_ReleaseUser(userp);
5898 return CM_ERROR_ISDIR;
5902 /* (only applies to single component case) */
5903 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5904 cm_ReleaseSCache(scp);
5906 cm_ReleaseSCache(dscp);
5907 cm_ReleaseUser(userp);
5909 return CM_ERROR_NOTDIR;
5912 /* open the file itself */
5913 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5916 /* save a reference to the user */
5918 fidp->userp = userp;
5920 /* If we are restricting sharing, we should do so with a suitable
5922 if (scp->fileType == CM_SCACHETYPE_FILE &&
5923 !(fidflags & SMB_FID_SHARE_WRITE)) {
5925 LARGE_INTEGER LOffset, LLength;
5928 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
5929 LOffset.LowPart = SMB_FID_QLOCK_LOW;
5930 LLength.HighPart = 0;
5931 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
5933 if (fidflags & SMB_FID_SHARE_READ) {
5934 sLockType = LOCKING_ANDX_SHARED_LOCK;
5939 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
5941 lock_ObtainMutex(&scp->mx);
5942 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
5943 lock_ReleaseMutex(&scp->mx);
5946 fidp->flags = SMB_FID_DELETE;
5947 smb_ReleaseFID(fidp);
5949 cm_ReleaseSCache(scp);
5951 cm_ReleaseSCache(dscp);
5952 cm_ReleaseUser(userp);
5959 /* save a pointer to the vnode */
5960 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
5962 fidp->flags = fidflags;
5964 /* save parent dir and pathname for delete or change notification */
5965 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5966 fidp->flags |= SMB_FID_NTOPEN;
5967 fidp->NTopen_dscp = dscp;
5968 cm_HoldSCache(dscp);
5969 fidp->NTopen_pathp = strdup(lastNamep);
5971 fidp->NTopen_wholepathp = realPathp;
5973 /* we don't need this any longer */
5975 cm_ReleaseSCache(dscp);
5979 cm_Open(scp, 0, userp);
5981 /* set inp->fid so that later read calls in same msg can find fid */
5982 inp->fid = fidp->fid;
5986 lock_ObtainMutex(&scp->mx);
5987 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5988 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5989 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
5990 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5991 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5992 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5993 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5994 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5995 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
5997 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5998 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5999 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6000 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6001 smb_SetSMBParmByte(outp, parmSlot,
6002 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
6003 lock_ReleaseMutex(&scp->mx);
6004 smb_SetSMBDataLength(outp, 0);
6006 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
6007 osi_LogSaveString(smb_logp, realPathp));
6009 smb_ReleaseFID(fidp);
6011 cm_ReleaseUser(userp);
6013 /* Can't free realPathp if we get here since
6014 fidp->NTopen_wholepathp is pointing there */
6016 /* leave scp held since we put it in fidp->scp */
6021 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
6022 * Instead, ultimately, would like to use a subroutine for common code.
6024 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6026 char *pathp, *realPathp;
6030 cm_scache_t *dscp; /* parent dir */
6031 cm_scache_t *scp; /* file to create or open */
6032 cm_scache_t *targetScp; /* if scp is a symlink */
6035 unsigned long nameLength;
6037 unsigned int requestOpLock;
6038 unsigned int requestBatchOpLock;
6039 unsigned int mustBeDir;
6040 unsigned int extendedRespRequired;
6042 unsigned int desiredAccess;
6043 #ifdef DEBUG_VERBOSE
6044 unsigned int allocSize;
6046 unsigned int shareAccess;
6047 unsigned int extAttributes;
6048 unsigned int createDisp;
6049 #ifdef DEBUG_VERBOSE
6052 unsigned int createOptions;
6053 int initialModeBits;
6054 unsigned short baseFid;
6055 smb_fid_t *baseFidp;
6057 cm_scache_t *baseDirp;
6058 unsigned short openAction;
6064 int parmOffset, dataOffset;
6075 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6076 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6077 parmp = inp->data + parmOffset;
6078 lparmp = (ULONG *) parmp;
6081 requestOpLock = flags & REQUEST_OPLOCK;
6082 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6083 mustBeDir = flags & OPEN_DIRECTORY;
6084 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6087 * Why all of a sudden 32-bit FID?
6088 * We will reject all bits higher than 16.
6090 if (lparmp[1] & 0xFFFF0000)
6091 return CM_ERROR_INVAL;
6092 baseFid = (unsigned short)lparmp[1];
6093 desiredAccess = lparmp[2];
6094 #ifdef DEBUG_VERBOSE
6095 allocSize = lparmp[3];
6096 #endif /* DEBUG_VERSOSE */
6097 extAttributes = lparmp[5];
6098 shareAccess = lparmp[6];
6099 createDisp = lparmp[7];
6100 createOptions = lparmp[8];
6101 #ifdef DEBUG_VERBOSE
6104 nameLength = lparmp[11];
6106 #ifdef DEBUG_VERBOSE
6107 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
6108 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
6109 osi_Log1(smb_logp,"... flags[%x]",flags);
6112 /* mustBeDir is never set; createOptions directory bit seems to be
6115 if (createOptions & FILE_DIRECTORY_FILE)
6117 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6123 * compute initial mode bits based on read-only flag in
6124 * extended attributes
6126 initialModeBits = 0666;
6127 if (extAttributes & 1)
6128 initialModeBits &= ~0222;
6130 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
6131 /* Sometimes path is not null-terminated, so we make a copy. */
6132 realPathp = malloc(nameLength+1);
6133 memcpy(realPathp, pathp, nameLength);
6134 realPathp[nameLength] = 0;
6135 if (smb_StoreAnsiFilenames)
6136 OemToChar(realPathp,realPathp);
6138 spacep = cm_GetSpace();
6139 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6142 * Nothing here to handle SMB_IOCTL_FILENAME.
6143 * Will add it if necessary.
6146 #ifdef DEBUG_VERBOSE
6148 char *hexp, *asciip;
6149 asciip = (lastNamep? lastNamep : realPathp);
6150 hexp = osi_HexifyString( asciip );
6151 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
6156 userp = smb_GetUser(vcp, inp);
6158 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
6160 return CM_ERROR_INVAL;
6164 baseDirp = cm_data.rootSCachep;
6165 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6166 if (code == CM_ERROR_TIDIPC) {
6167 /* Attempt to use a TID allocated for IPC. The client
6168 * is probably looking for DCE RPC end points which we
6169 * don't support OR it could be looking to make a DFS
6172 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
6175 cm_ReleaseUser(userp);
6176 return CM_ERROR_NOSUCHPATH;
6180 baseFidp = smb_FindFID(vcp, baseFid, 0);
6182 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
6184 cm_ReleaseUser(userp);
6185 return CM_ERROR_INVAL;
6187 baseDirp = baseFidp->scp;
6191 /* compute open mode */
6193 if (desiredAccess & DELETE)
6194 fidflags |= SMB_FID_OPENDELETE;
6195 if (desiredAccess & AFS_ACCESS_READ)
6196 fidflags |= SMB_FID_OPENREAD;
6197 if (desiredAccess & AFS_ACCESS_WRITE)
6198 fidflags |= SMB_FID_OPENWRITE;
6199 if (createOptions & FILE_DELETE_ON_CLOSE)
6200 fidflags |= SMB_FID_DELONCLOSE;
6202 /* And the share mode */
6203 if (shareAccess & FILE_SHARE_READ)
6204 fidflags |= SMB_FID_SHARE_READ;
6205 if (shareAccess & FILE_SHARE_WRITE)
6206 fidflags |= SMB_FID_SHARE_WRITE;
6210 if ( createDisp == FILE_OPEN ||
6211 createDisp == FILE_OVERWRITE ||
6212 createDisp == FILE_OVERWRITE_IF) {
6213 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6214 userp, tidPathp, &req, &dscp);
6217 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6218 cm_ReleaseSCache(dscp);
6219 cm_ReleaseUser(userp);
6221 if ( WANTS_DFS_PATHNAMES(inp) )
6222 return CM_ERROR_PATH_NOT_COVERED;
6224 return CM_ERROR_BADSHARENAME;
6226 #endif /* DFS_SUPPORT */
6227 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6229 if (code == CM_ERROR_NOSUCHFILE) {
6230 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6231 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6232 if (code == 0 && realDirFlag == 1) {
6233 cm_ReleaseSCache(scp);
6234 cm_ReleaseSCache(dscp);
6235 cm_ReleaseUser(userp);
6237 return CM_ERROR_EXISTS;
6243 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6244 userp, tidPathp, &req, &scp);
6246 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6247 cm_ReleaseSCache(scp);
6248 cm_ReleaseUser(userp);
6250 if ( WANTS_DFS_PATHNAMES(inp) )
6251 return CM_ERROR_PATH_NOT_COVERED;
6253 return CM_ERROR_BADSHARENAME;
6255 #endif /* DFS_SUPPORT */
6261 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6262 /* look up parent directory */
6264 code = cm_NameI(baseDirp, spacep->data,
6265 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6266 userp, tidPathp, &req, &dscp);
6268 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6269 cm_ReleaseSCache(dscp);
6270 cm_ReleaseUser(userp);
6272 if ( WANTS_DFS_PATHNAMES(inp) )
6273 return CM_ERROR_PATH_NOT_COVERED;
6275 return CM_ERROR_BADSHARENAME;
6277 #endif /* DFS_SUPPORT */
6281 cm_FreeSpace(spacep);
6284 smb_ReleaseFID(baseFidp);
6289 cm_ReleaseUser(userp);
6294 if (!lastNamep) lastNamep = realPathp;
6297 if (!smb_IsLegalFilename(lastNamep))
6298 return CM_ERROR_BADNTFILENAME;
6301 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
6302 code = cm_Lookup(dscp, lastNamep,
6303 CM_FLAG_FOLLOW, userp, &req, &scp);
6305 code = cm_Lookup(dscp, lastNamep,
6306 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6309 if (code && code != CM_ERROR_NOSUCHFILE) {
6310 cm_ReleaseSCache(dscp);
6311 cm_ReleaseUser(userp);
6318 smb_ReleaseFID(baseFidp);
6321 cm_FreeSpace(spacep);
6324 /* if we get here, if code is 0, the file exists and is represented by
6325 * scp. Otherwise, we have to create it. The dir may be represented
6326 * by dscp, or we may have found the file directly. If code is non-zero,
6330 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
6334 cm_ReleaseSCache(dscp);
6335 cm_ReleaseSCache(scp);
6336 cm_ReleaseUser(userp);
6341 if (createDisp == FILE_CREATE) {
6342 /* oops, file shouldn't be there */
6344 cm_ReleaseSCache(dscp);
6345 cm_ReleaseSCache(scp);
6346 cm_ReleaseUser(userp);
6348 return CM_ERROR_EXISTS;
6351 if (createDisp == FILE_OVERWRITE ||
6352 createDisp == FILE_OVERWRITE_IF) {
6353 setAttr.mask = CM_ATTRMASK_LENGTH;
6354 setAttr.length.LowPart = 0;
6355 setAttr.length.HighPart = 0;
6357 /* now watch for a symlink */
6359 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6361 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6363 /* we have a more accurate file to use (the
6364 * target of the symbolic link). Otherwise,
6365 * we'll just use the symlink anyway.
6367 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6369 cm_ReleaseSCache(scp);
6373 code = cm_SetAttr(scp, &setAttr, userp, &req);
6374 openAction = 3; /* truncated existing file */
6376 else openAction = 1; /* found existing file */
6378 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6379 /* don't create if not found */
6381 cm_ReleaseSCache(dscp);
6382 cm_ReleaseUser(userp);
6384 return CM_ERROR_NOSUCHFILE;
6386 else if (realDirFlag == 0 || realDirFlag == -1) {
6387 osi_assert(dscp != NULL);
6388 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
6389 osi_LogSaveString(smb_logp, lastNamep));
6390 openAction = 2; /* created file */
6391 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6392 setAttr.clientModTime = time(NULL);
6393 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6395 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6396 smb_NotifyChange(FILE_ACTION_ADDED,
6397 FILE_NOTIFY_CHANGE_FILE_NAME,
6398 dscp, lastNamep, NULL, TRUE);
6399 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6400 /* Not an exclusive create, and someone else tried
6401 * creating it already, then we open it anyway. We
6402 * don't bother retrying after this, since if this next
6403 * fails, that means that the file was deleted after we
6404 * started this call.
6406 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6409 if (createDisp == FILE_OVERWRITE_IF) {
6410 setAttr.mask = CM_ATTRMASK_LENGTH;
6411 setAttr.length.LowPart = 0;
6412 setAttr.length.HighPart = 0;
6414 /* now watch for a symlink */
6416 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6418 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6420 /* we have a more accurate file to use (the
6421 * target of the symbolic link). Otherwise,
6422 * we'll just use the symlink anyway.
6424 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6426 cm_ReleaseSCache(scp);
6430 code = cm_SetAttr(scp, &setAttr, userp, &req);
6432 } /* lookup succeeded */
6435 /* create directory */
6436 osi_assert(dscp != NULL);
6438 "smb_ReceiveNTTranCreate creating directory %s",
6439 osi_LogSaveString(smb_logp, lastNamep));
6440 openAction = 2; /* created directory */
6441 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6442 setAttr.clientModTime = time(NULL);
6443 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6444 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6445 smb_NotifyChange(FILE_ACTION_ADDED,
6446 FILE_NOTIFY_CHANGE_DIR_NAME,
6447 dscp, lastNamep, NULL, TRUE);
6449 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6450 /* Not an exclusive create, and someone else tried
6451 * creating it already, then we open it anyway. We
6452 * don't bother retrying after this, since if this next
6453 * fails, that means that the file was deleted after we
6454 * started this call.
6456 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6462 /* something went wrong creating or truncating the file */
6464 cm_ReleaseSCache(scp);
6465 cm_ReleaseUser(userp);
6470 /* make sure we have file vs. dir right */
6471 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
6472 /* now watch for a symlink */
6474 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6476 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6478 /* we have a more accurate file to use (the
6479 * target of the symbolic link). Otherwise,
6480 * we'll just use the symlink anyway.
6482 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6484 cm_ReleaseSCache(scp);
6489 if (scp->fileType != CM_SCACHETYPE_FILE) {
6490 cm_ReleaseSCache(scp);
6491 cm_ReleaseUser(userp);
6493 return CM_ERROR_ISDIR;
6497 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
6498 cm_ReleaseSCache(scp);
6499 cm_ReleaseUser(userp);
6501 return CM_ERROR_NOTDIR;
6504 /* open the file itself */
6505 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6508 /* save a reference to the user */
6510 fidp->userp = userp;
6512 /* If we are restricting sharing, we should do so with a suitable
6514 if (scp->fileType == CM_SCACHETYPE_FILE &&
6515 !(fidflags & SMB_FID_SHARE_WRITE)) {
6517 LARGE_INTEGER LOffset, LLength;
6520 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
6521 LOffset.LowPart = SMB_FID_QLOCK_LOW;
6522 LLength.HighPart = 0;
6523 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
6525 if (fidflags & SMB_FID_SHARE_READ) {
6526 sLockType = LOCKING_ANDX_SHARED_LOCK;
6531 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
6533 lock_ObtainMutex(&scp->mx);
6534 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
6535 lock_ReleaseMutex(&scp->mx);
6538 fidp->flags = SMB_FID_DELETE;
6539 smb_ReleaseFID(fidp);
6541 cm_ReleaseSCache(scp);
6542 cm_ReleaseUser(userp);
6545 return CM_ERROR_SHARING_VIOLATION;
6549 /* save a pointer to the vnode */
6552 fidp->flags = fidflags;
6554 /* save parent dir and pathname for deletion or change notification */
6555 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
6556 fidp->flags |= SMB_FID_NTOPEN;
6557 fidp->NTopen_dscp = dscp;
6558 cm_HoldSCache(dscp);
6559 fidp->NTopen_pathp = strdup(lastNamep);
6561 fidp->NTopen_wholepathp = realPathp;
6563 /* we don't need this any longer */
6565 cm_ReleaseSCache(dscp);
6567 cm_Open(scp, 0, userp);
6569 /* set inp->fid so that later read calls in same msg can find fid */
6570 inp->fid = fidp->fid;
6572 /* check whether we are required to send an extended response */
6573 if (!extendedRespRequired) {
6575 parmOffset = 8*4 + 39;
6576 parmOffset += 1; /* pad to 4 */
6577 dataOffset = parmOffset + 70;
6581 /* Total Parameter Count */
6582 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
6583 /* Total Data Count */
6584 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6585 /* Parameter Count */
6586 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
6587 /* Parameter Offset */
6588 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6589 /* Parameter Displacement */
6590 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6592 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6594 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6595 /* Data Displacement */
6596 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6597 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6598 smb_SetSMBDataLength(outp, 70);
6600 lock_ObtainMutex(&scp->mx);
6601 outData = smb_GetSMBData(outp, NULL);
6602 outData++; /* round to get to parmOffset */
6603 *outData = 0; outData++; /* oplock */
6604 *outData = 0; outData++; /* reserved */
6605 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
6606 *((ULONG *)outData) = openAction; outData += 4;
6607 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
6608 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6609 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
6610 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
6611 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
6612 *((FILETIME *)outData) = ft; outData += 8; /* change time */
6613 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
6614 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
6615 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
6616 *((USHORT *)outData) = 0; outData += 2; /* filetype */
6617 *((USHORT *)outData) = 0; outData += 2; /* dev state */
6618 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
6619 outData += 2; /* is a dir? */
6620 lock_ReleaseMutex(&scp->mx);
6623 parmOffset = 8*4 + 39;
6624 parmOffset += 1; /* pad to 4 */
6625 dataOffset = parmOffset + 104;
6629 /* Total Parameter Count */
6630 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
6631 /* Total Data Count */
6632 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6633 /* Parameter Count */
6634 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
6635 /* Parameter Offset */
6636 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6637 /* Parameter Displacement */
6638 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6640 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6642 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6643 /* Data Displacement */
6644 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6645 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6646 smb_SetSMBDataLength(outp, 105);
6648 lock_ObtainMutex(&scp->mx);
6649 outData = smb_GetSMBData(outp, NULL);
6650 outData++; /* round to get to parmOffset */
6651 *outData = 0; outData++; /* oplock */
6652 *outData = 1; outData++; /* response type */
6653 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
6654 *((ULONG *)outData) = openAction; outData += 4;
6655 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
6656 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6657 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
6658 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
6659 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
6660 *((FILETIME *)outData) = ft; outData += 8; /* change time */
6661 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
6662 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
6663 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
6664 *((USHORT *)outData) = 0; outData += 2; /* filetype */
6665 *((USHORT *)outData) = 0; outData += 2; /* dev state */
6666 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
6667 outData += 1; /* is a dir? */
6668 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
6669 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
6670 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
6671 lock_ReleaseMutex(&scp->mx);
6674 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
6676 smb_ReleaseFID(fidp);
6678 cm_ReleaseUser(userp);
6680 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
6681 /* leave scp held since we put it in fidp->scp */
6685 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
6688 smb_packet_t *savedPacketp;
6689 ULONG filter; USHORT fid, watchtree;
6693 filter = smb_GetSMBParm(inp, 19) |
6694 (smb_GetSMBParm(inp, 20) << 16);
6695 fid = smb_GetSMBParm(inp, 21);
6696 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
6698 fidp = smb_FindFID(vcp, fid, 0);
6700 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
6701 return CM_ERROR_BADFD;
6704 savedPacketp = smb_CopyPacket(inp);
6706 if (savedPacketp->vcp)
6707 smb_ReleaseVC(savedPacketp->vcp);
6708 savedPacketp->vcp = vcp;
6709 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6710 savedPacketp->nextp = smb_Directory_Watches;
6711 smb_Directory_Watches = savedPacketp;
6712 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6714 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
6715 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
6718 lock_ObtainMutex(&scp->mx);
6720 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
6722 scp->flags |= CM_SCACHEFLAG_WATCHED;
6723 lock_ReleaseMutex(&scp->mx);
6724 smb_ReleaseFID(fidp);
6726 outp->flags |= SMB_PACKETFLAG_NOSEND;
6730 unsigned char nullSecurityDesc[36] = {
6731 0x01, /* security descriptor revision */
6732 0x00, /* reserved, should be zero */
6733 0x00, 0x80, /* security descriptor control;
6734 * 0x8000 : self-relative format */
6735 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
6736 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
6737 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
6738 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
6739 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6740 /* "null SID" owner SID */
6741 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
6742 /* "null SID" group SID */
6745 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6747 int parmOffset, parmCount, dataOffset, dataCount;
6755 ULONG securityInformation;
6757 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6758 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6759 parmp = inp->data + parmOffset;
6760 sparmp = (USHORT *) parmp;
6761 lparmp = (ULONG *) parmp;
6764 securityInformation = lparmp[1];
6766 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
6767 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6775 parmOffset = 8*4 + 39;
6776 parmOffset += 1; /* pad to 4 */
6778 dataOffset = parmOffset + parmCount;
6782 /* Total Parameter Count */
6783 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6784 /* Total Data Count */
6785 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6786 /* Parameter Count */
6787 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6788 /* Parameter Offset */
6789 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6790 /* Parameter Displacement */
6791 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6793 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6795 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6796 /* Data Displacement */
6797 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6798 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6799 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
6801 outData = smb_GetSMBData(outp, NULL);
6802 outData++; /* round to get to parmOffset */
6803 *((ULONG *)outData) = 36; outData += 4; /* length */
6805 if (maxData >= 36) {
6806 memcpy(outData, nullSecurityDesc, 36);
6810 return CM_ERROR_BUFFERTOOSMALL;
6813 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6815 unsigned short function;
6817 function = smb_GetSMBParm(inp, 18);
6819 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
6821 /* We can handle long names */
6822 if (vcp->flags & SMB_VCFLAG_USENT)
6823 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
6827 return smb_ReceiveNTTranCreate(vcp, inp, outp);
6829 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
6832 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
6835 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
6837 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
6840 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
6842 return CM_ERROR_INVAL;
6846 * smb_NotifyChange -- find relevant change notification messages and
6849 * If we don't know the file name (i.e. a callback break), filename is
6850 * NULL, and we return a zero-length list.
6852 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
6853 cm_scache_t *dscp, char *filename, char *otherFilename,
6854 BOOL isDirectParent)
6856 smb_packet_t *watch, *lastWatch, *nextWatch;
6857 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
6858 char *outData, *oldOutData;
6862 BOOL twoEntries = FALSE;
6863 ULONG otherNameLen, oldParmCount = 0;
6867 /* Get ready for rename within directory */
6868 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
6870 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
6873 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
6874 osi_LogSaveString(smb_logp,filename),dscp);
6876 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6877 watch = smb_Directory_Watches;
6879 filter = smb_GetSMBParm(watch, 19)
6880 | (smb_GetSMBParm(watch, 20) << 16);
6881 fid = smb_GetSMBParm(watch, 21);
6882 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
6883 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
6884 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
6887 * Strange hack - bug in NT Client and NT Server that we
6890 if (filter == 3 && wtree)
6893 fidp = smb_FindFID(watch->vcp, fid, 0);
6895 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
6897 watch = watch->nextp;
6900 if (fidp->scp != dscp
6901 || (filter & notifyFilter) == 0
6902 || (!isDirectParent && !wtree)) {
6903 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
6904 smb_ReleaseFID(fidp);
6906 watch = watch->nextp;
6909 smb_ReleaseFID(fidp);
6912 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
6913 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
6915 nextWatch = watch->nextp;
6916 if (watch == smb_Directory_Watches)
6917 smb_Directory_Watches = nextWatch;
6919 lastWatch->nextp = nextWatch;
6921 /* Turn off WATCHED flag in dscp */
6922 lock_ObtainMutex(&dscp->mx);
6924 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6926 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
6927 lock_ReleaseMutex(&dscp->mx);
6929 /* Convert to response packet */
6930 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
6931 ((smb_t *) watch)->wct = 0;
6934 if (filename == NULL)
6937 nameLen = (ULONG)strlen(filename);
6938 parmCount = 3*4 + nameLen*2;
6939 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6941 otherNameLen = (ULONG)strlen(otherFilename);
6942 oldParmCount = parmCount;
6943 parmCount += 3*4 + otherNameLen*2;
6944 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6946 if (maxLen < parmCount)
6947 parmCount = 0; /* not enough room */
6949 parmOffset = 8*4 + 39;
6950 parmOffset += 1; /* pad to 4 */
6951 dataOffset = parmOffset + parmCount;
6955 /* Total Parameter Count */
6956 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6957 /* Total Data Count */
6958 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6959 /* Parameter Count */
6960 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6961 /* Parameter Offset */
6962 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
6963 /* Parameter Displacement */
6964 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6966 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6968 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
6969 /* Data Displacement */
6970 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6971 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
6972 smb_SetSMBDataLength(watch, parmCount + 1);
6974 if (parmCount != 0) {
6976 outData = smb_GetSMBData(watch, NULL);
6977 outData++; /* round to get to parmOffset */
6978 oldOutData = outData;
6979 *((DWORD *)outData) = oldParmCount; outData += 4;
6980 /* Next Entry Offset */
6981 *((DWORD *)outData) = action; outData += 4;
6983 *((DWORD *)outData) = nameLen*2; outData += 4;
6984 /* File Name Length */
6985 p = strdup(filename);
6986 if (smb_StoreAnsiFilenames)
6988 mbstowcs((WCHAR *)outData, p, nameLen);
6992 outData = oldOutData + oldParmCount;
6993 *((DWORD *)outData) = 0; outData += 4;
6994 /* Next Entry Offset */
6995 *((DWORD *)outData) = otherAction; outData += 4;
6997 *((DWORD *)outData) = otherNameLen*2;
6998 outData += 4; /* File Name Length */
6999 p = strdup(otherFilename);
7000 if (smb_StoreAnsiFilenames)
7002 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
7008 * If filename is null, we don't know the cause of the
7009 * change notification. We return zero data (see above),
7010 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
7011 * (= 0x010C). We set the error code here by hand, without
7012 * modifying wct and bcc.
7014 if (filename == NULL) {
7015 ((smb_t *) watch)->rcls = 0x0C;
7016 ((smb_t *) watch)->reh = 0x01;
7017 ((smb_t *) watch)->errLow = 0;
7018 ((smb_t *) watch)->errHigh = 0;
7019 /* Set NT Status codes flag */
7020 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7023 smb_SendPacket(watch->vcp, watch);
7024 smb_FreePacket(watch);
7027 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7030 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7032 unsigned char *replyWctp;
7033 smb_packet_t *watch, *lastWatch;
7034 USHORT fid, watchtree;
7038 osi_Log0(smb_logp, "SMB3 receive NT cancel");
7040 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7041 watch = smb_Directory_Watches;
7043 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
7044 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
7045 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
7046 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
7047 if (watch == smb_Directory_Watches)
7048 smb_Directory_Watches = watch->nextp;
7050 lastWatch->nextp = watch->nextp;
7051 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7053 /* Turn off WATCHED flag in scp */
7054 fid = smb_GetSMBParm(watch, 21);
7055 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
7057 if (vcp != watch->vcp)
7058 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
7061 fidp = smb_FindFID(vcp, fid, 0);
7063 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
7065 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
7068 lock_ObtainMutex(&scp->mx);
7070 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
7072 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
7073 lock_ReleaseMutex(&scp->mx);
7074 smb_ReleaseFID(fidp);
7076 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
7079 /* assume STATUS32; return 0xC0000120 (CANCELED) */
7080 replyWctp = watch->wctp;
7084 ((smb_t *)watch)->rcls = 0x20;
7085 ((smb_t *)watch)->reh = 0x1;
7086 ((smb_t *)watch)->errLow = 0;
7087 ((smb_t *)watch)->errHigh = 0xC0;
7088 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7089 smb_SendPacket(vcp, watch);
7090 smb_FreePacket(watch);
7094 watch = watch->nextp;
7096 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7102 * NT rename also does hard links.
7105 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
7106 #define RENAME_FLAG_HARD_LINK 0x103
7107 #define RENAME_FLAG_RENAME 0x104
7108 #define RENAME_FLAG_COPY 0x105
7110 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7112 char *oldPathp, *newPathp;
7118 attrs = smb_GetSMBParm(inp, 0);
7119 rename_type = smb_GetSMBParm(inp, 1);
7121 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
7122 osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
7123 return CM_ERROR_NOACCESS;
7126 tp = smb_GetSMBData(inp, NULL);
7127 oldPathp = smb_ParseASCIIBlock(tp, &tp);
7128 if (smb_StoreAnsiFilenames)
7129 OemToChar(oldPathp,oldPathp);
7130 newPathp = smb_ParseASCIIBlock(tp, &tp);
7131 if (smb_StoreAnsiFilenames)
7132 OemToChar(newPathp,newPathp);
7134 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
7135 osi_LogSaveString(smb_logp, oldPathp),
7136 osi_LogSaveString(smb_logp, newPathp),
7137 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
7139 if (rename_type == RENAME_FLAG_RENAME) {
7140 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
7141 } else { /* RENAME_FLAG_HARD_LINK */
7142 code = smb_Link(vcp,inp,oldPathp,newPathp);
7149 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
7152 cm_user_t *smb_FindCMUserByName(char *usern, char *machine)
7154 smb_username_t *unp;
7157 unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
7159 lock_ObtainMutex(&unp->mx);
7160 unp->userp = cm_NewUser();
7161 lock_ReleaseMutex(&unp->mx);
7162 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7164 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7168 smb_ReleaseUsername(unp);