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 up = smb_GetUserFromUID(uidp);
63 * Return extended attributes.
64 * Right now, we aren't using any of the "new" bits, so this looks exactly
65 * like smb_Attributes() (see smb.c).
67 unsigned long smb_ExtAttributes(cm_scache_t *scp)
71 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
72 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
73 scp->fileType == CM_SCACHETYPE_INVALID)
75 attrs = SMB_ATTR_DIRECTORY;
76 #ifdef SPECIAL_FOLDERS
77 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
78 #endif /* SPECIAL_FOLDERS */
79 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
80 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
84 * We used to mark a file RO if it was in an RO volume, but that
85 * turns out to be impolitic in NT. See defect 10007.
88 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
89 attrs |= SMB_ATTR_READONLY; /* Read-only */
91 if ((scp->unixModeBits & 0222) == 0)
92 attrs |= SMB_ATTR_READONLY; /* Read-only */
96 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
101 int smb_V3IsStarMask(char *maskp)
105 while (tc = *maskp++)
106 if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
111 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
114 /* skip over null-terminated string */
115 *chainpp = inp + strlen(inp) + 1;
120 void OutputDebugF(char * format, ...) {
125 va_start( args, format );
126 len = _vscprintf( format, args ) // _vscprintf doesn't count
127 + 3; // terminating '\0' + '\n'
128 buffer = malloc( len * sizeof(char) );
129 vsprintf( buffer, format, args );
130 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buffer));
131 strcat(buffer, "\n");
132 OutputDebugString(buffer);
136 void OutputDebugHexDump(unsigned char * buffer, int len) {
139 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
141 OutputDebugF("Hexdump length [%d]",len);
143 for (i=0;i<len;i++) {
146 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
148 OutputDebugString(buf);
150 sprintf(buf,"%5x",i);
151 memset(buf+5,' ',80);
156 j = j*3 + 7 + ((j>7)?1:0);
159 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
162 j = j + 56 + ((j>7)?1:0);
164 buf[j] = (k>32 && k<127)?k:'.';
167 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
169 OutputDebugString(buf);
173 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
175 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
176 SECURITY_STATUS status, istatus;
177 CredHandle creds = {0,0};
179 SecBufferDesc secOut;
187 OutputDebugF("Negotiating Extended Security");
189 status = AcquireCredentialsHandle( NULL,
190 SMB_EXT_SEC_PACKAGE_NAME,
199 if (status != SEC_E_OK) {
200 /* Really bad. We return an empty security blob */
201 OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
206 secOut.pBuffers = &secTok;
207 secOut.ulVersion = SECBUFFER_VERSION;
209 secTok.BufferType = SECBUFFER_TOKEN;
211 secTok.pvBuffer = NULL;
213 ctx.dwLower = ctx.dwUpper = 0;
215 status = AcceptSecurityContext( &creds,
218 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
219 SECURITY_NETWORK_DREP,
226 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
227 OutputDebugF("Completing token...");
228 istatus = CompleteAuthToken(&ctx, &secOut);
229 if ( istatus != SEC_E_OK )
230 OutputDebugF("Token completion failed: %x", istatus);
233 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
234 if (secTok.pvBuffer) {
235 *secBlobLength = secTok.cbBuffer;
236 *secBlob = malloc( secTok.cbBuffer );
237 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
240 if ( status != SEC_E_OK )
241 OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
244 /* Discard partial security context */
245 DeleteSecurityContext(&ctx);
247 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
249 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
250 FreeCredentialsHandle(&creds);
256 struct smb_ext_context {
263 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
264 SECURITY_STATUS status, istatus;
268 SecBufferDesc secBufIn;
270 SecBufferDesc secBufOut;
273 struct smb_ext_context * secCtx = NULL;
274 struct smb_ext_context * newSecCtx = NULL;
275 void * assembledBlob = NULL;
276 int assembledBlobLength = 0;
279 OutputDebugF("In smb_AuthenticateUserExt");
282 *secBlobOutLength = 0;
284 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
285 secCtx = vcp->secCtx;
286 lock_ObtainMutex(&vcp->mx);
287 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
289 lock_ReleaseMutex(&vcp->mx);
293 OutputDebugF("Received incoming token:");
294 OutputDebugHexDump(secBlobIn,secBlobInLength);
298 OutputDebugF("Continuing with existing context.");
299 creds = secCtx->creds;
302 if (secCtx->partialToken) {
303 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
304 assembledBlob = malloc(assembledBlobLength);
305 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
306 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
309 status = AcquireCredentialsHandle( NULL,
310 SMB_EXT_SEC_PACKAGE_NAME,
319 if (status != SEC_E_OK) {
320 OutputDebugF("Can't acquire Credentials handle [%lX]", status);
321 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
329 secBufIn.cBuffers = 1;
330 secBufIn.pBuffers = &secTokIn;
331 secBufIn.ulVersion = SECBUFFER_VERSION;
333 secTokIn.BufferType = SECBUFFER_TOKEN;
335 secTokIn.cbBuffer = assembledBlobLength;
336 secTokIn.pvBuffer = assembledBlob;
338 secTokIn.cbBuffer = secBlobInLength;
339 secTokIn.pvBuffer = secBlobIn;
342 secBufOut.cBuffers = 1;
343 secBufOut.pBuffers = &secTokOut;
344 secBufOut.ulVersion = SECBUFFER_VERSION;
346 secTokOut.BufferType = SECBUFFER_TOKEN;
347 secTokOut.cbBuffer = 0;
348 secTokOut.pvBuffer = NULL;
350 status = AcceptSecurityContext( &creds,
351 ((secCtx)?&ctx:NULL),
353 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
354 SECURITY_NETWORK_DREP,
361 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
362 OutputDebugF("Completing token...");
363 istatus = CompleteAuthToken(&ctx, &secBufOut);
364 if ( istatus != SEC_E_OK )
365 OutputDebugF("Token completion failed: %lX", istatus);
368 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
369 OutputDebugF("Continue needed");
371 newSecCtx = malloc(sizeof(*newSecCtx));
373 newSecCtx->creds = creds;
374 newSecCtx->ctx = ctx;
375 newSecCtx->partialToken = NULL;
376 newSecCtx->partialTokenLen = 0;
378 lock_ObtainMutex( &vcp->mx );
379 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
380 vcp->secCtx = newSecCtx;
381 lock_ReleaseMutex( &vcp->mx );
383 code = CM_ERROR_GSSCONTINUE;
386 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
387 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
388 secTokOut.pvBuffer) {
389 OutputDebugF("Need to send token back to client");
391 *secBlobOutLength = secTokOut.cbBuffer;
392 *secBlobOut = malloc(secTokOut.cbBuffer);
393 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
395 OutputDebugF("Outgoing token:");
396 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
397 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
398 OutputDebugF("Incomplete message");
400 newSecCtx = malloc(sizeof(*newSecCtx));
402 newSecCtx->creds = creds;
403 newSecCtx->ctx = ctx;
404 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
405 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
406 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
408 lock_ObtainMutex( &vcp->mx );
409 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
410 vcp->secCtx = newSecCtx;
411 lock_ReleaseMutex( &vcp->mx );
413 code = CM_ERROR_GSSCONTINUE;
416 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
418 SecPkgContext_Names names;
420 OutputDebugF("Authentication completed");
421 OutputDebugF("Returned flags : [%lX]", flags);
423 if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
424 OutputDebugF("Received name [%s]", names.sUserName);
425 strcpy(usern, names.sUserName);
426 strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
427 FreeContextBuffer(names.sUserName);
429 /* Force the user to retry if the context is invalid */
430 OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
431 code = CM_ERROR_BADPASSWORD;
435 case SEC_E_INVALID_TOKEN:
436 OutputDebugF("Returning bad password :: INVALID_TOKEN");
438 case SEC_E_INVALID_HANDLE:
439 OutputDebugF("Returning bad password :: INVALID_HANDLE");
441 case SEC_E_LOGON_DENIED:
442 OutputDebugF("Returning bad password :: LOGON_DENIED");
444 case SEC_E_UNKNOWN_CREDENTIALS:
445 OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
447 case SEC_E_NO_CREDENTIALS:
448 OutputDebugF("Returning bad password :: NO_CREDENTIALS");
450 case SEC_E_CONTEXT_EXPIRED:
451 OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
453 case SEC_E_INCOMPLETE_CREDENTIALS:
454 OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
456 case SEC_E_WRONG_PRINCIPAL:
457 OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
459 case SEC_E_TIME_SKEW:
460 OutputDebugF("Returning bad password :: TIME_SKEW");
463 OutputDebugF("Returning bad password :: Status == %lX", status);
465 code = CM_ERROR_BADPASSWORD;
469 if (secCtx->partialToken) free(secCtx->partialToken);
477 if (secTokOut.pvBuffer)
478 FreeContextBuffer(secTokOut.pvBuffer);
480 if (code != CM_ERROR_GSSCONTINUE) {
481 DeleteSecurityContext(&ctx);
482 FreeCredentialsHandle(&creds);
490 #define P_RESP_LEN 128
492 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
493 So put stuff in a struct. */
494 struct Lm20AuthBlob {
495 MSV1_0_LM20_LOGON lmlogon;
496 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
497 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
498 WCHAR accountNameW[P_LEN];
499 WCHAR primaryDomainW[P_LEN];
500 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
501 TOKEN_GROUPS tgroups;
502 TOKEN_SOURCE tsource;
505 long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
508 struct Lm20AuthBlob lmAuth;
509 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
510 QUOTA_LIMITS quotaLimits;
512 ULONG lmprofilepSize;
516 OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
517 OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
519 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
520 OutputDebugF("ciPwdLength or csPwdLength is too long");
521 return CM_ERROR_BADPASSWORD;
524 memset(&lmAuth,0,sizeof(lmAuth));
526 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
528 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
529 mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
530 lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
531 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
533 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
534 mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
535 lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
536 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
538 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
539 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
540 size = MAX_COMPUTERNAME_LENGTH + 1;
541 GetComputerNameW(lmAuth.workstationW, &size);
542 lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
544 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
546 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
547 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
548 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
549 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
551 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
552 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
553 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
554 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
556 lmAuth.lmlogon.ParameterControl = 0;
558 lmAuth.tgroups.GroupCount = 0;
559 lmAuth.tgroups.Groups[0].Sid = NULL;
560 lmAuth.tgroups.Groups[0].Attributes = 0;
562 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
563 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
564 strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
566 nts = LsaLogonUser( smb_lsaHandle,
581 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
582 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
585 OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
586 OutputDebugF("Extended status is 0x%lX", ntsEx);
588 if (nts == ERROR_SUCCESS) {
590 LsaFreeReturnBuffer(lmprofilep);
591 CloseHandle(lmToken);
595 if (nts == 0xC000015BL)
596 return CM_ERROR_BADLOGONTYPE;
597 else /* our catchall is a bad password though we could be more specific */
598 return CM_ERROR_BADPASSWORD;
602 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
603 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName)
608 /* check if we have sane input */
609 if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
612 /* we could get : [accountName][domainName]
618 atsign = strchr(accountName, '@');
620 if (atsign) /* [user@domain][] -> [user@domain][domain] */
625 /* if for some reason the client doesn't know what domain to use,
626 it will either return an empty string or a '?' */
627 if (!domain[0] || domain[0] == '?')
628 /* Empty domains and empty usernames are usually sent from tokenless contexts.
629 This way such logins will get an empty username (easy to check). I don't know
630 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
631 strcpy(usern,accountName);
633 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
634 strcpy(usern,domain);
637 strncat(usern,accountName,atsign - accountName);
639 strcat(usern,accountName);
647 /* When using SMB auth, all SMB sessions have to pass through here
648 * first to authenticate the user.
650 * Caveat: If not using SMB auth, the protocol does not require
651 * sending a session setup packet, which means that we can't rely on a
652 * UID in subsequent packets. Though in practice we get one anyway.
654 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
658 unsigned short newUid;
659 unsigned long caps = 0;
663 char usern[SMB_MAX_USERNAME_LENGTH];
664 char *secBlobOut = NULL;
665 int secBlobOutLength = 0;
667 /* Check for bad conns */
668 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
669 return CM_ERROR_REMOTECONN;
671 if (vcp->flags & SMB_VCFLAG_USENT) {
672 if (smb_authType == SMB_AUTH_EXTENDED) {
673 /* extended authentication */
677 OutputDebugF("NT Session Setup: Extended");
679 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
680 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
683 secBlobInLength = smb_GetSMBParm(inp, 7);
684 secBlobIn = smb_GetSMBData(inp, NULL);
686 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
688 if (code == CM_ERROR_GSSCONTINUE) {
689 smb_SetSMBParm(outp, 2, 0);
690 smb_SetSMBParm(outp, 3, secBlobOutLength);
691 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
692 tp = smb_GetSMBData(outp, NULL);
693 if (secBlobOutLength) {
694 memcpy(tp, secBlobOut, secBlobOutLength);
696 tp += secBlobOutLength;
698 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
699 tp += smb_ServerOSLength;
700 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
701 tp += smb_ServerLanManagerLength;
702 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
703 tp += smb_ServerDomainNameLength;
706 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
708 unsigned ciPwdLength, csPwdLength;
714 if (smb_authType == SMB_AUTH_NTLM)
715 OutputDebugF("NT Session Setup: NTLM");
717 OutputDebugF("NT Session Setup: None");
719 /* TODO: parse for extended auth as well */
720 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
721 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
723 tp = smb_GetSMBData(inp, &datalen);
725 OutputDebugF("Session packet data size [%d]",datalen);
732 accountName = smb_ParseString(tp, &tp);
733 primaryDomain = smb_ParseString(tp, NULL);
735 OutputDebugF("Account Name: %s",accountName);
736 OutputDebugF("Primary Domain: %s", primaryDomain);
737 OutputDebugF("Case Sensitive Password: %s", csPwd && csPwd[0] ? "yes" : "no");
738 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
740 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
741 /* shouldn't happen */
742 code = CM_ERROR_BADSMB;
743 goto after_read_packet;
746 /* capabilities are only valid for first session packet */
747 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
748 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
751 if (smb_authType == SMB_AUTH_NTLM) {
752 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
754 OutputDebugF("LM authentication failed [%d]", code);
756 OutputDebugF("LM authentication succeeded");
760 unsigned ciPwdLength;
765 switch ( smb_authType ) {
766 case SMB_AUTH_EXTENDED:
767 OutputDebugF("V3 Session Setup: Extended");
770 OutputDebugF("V3 Session Setup: NTLM");
773 OutputDebugF("V3 Session Setup: None");
775 ciPwdLength = smb_GetSMBParm(inp, 7);
776 tp = smb_GetSMBData(inp, NULL);
780 accountName = smb_ParseString(tp, &tp);
781 primaryDomain = smb_ParseString(tp, NULL);
783 OutputDebugF("Account Name: %s",accountName);
784 OutputDebugF("Primary Domain: %s", primaryDomain);
785 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
787 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
788 /* shouldn't happen */
789 code = CM_ERROR_BADSMB;
790 goto after_read_packet;
793 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
796 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
797 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
799 OutputDebugF("LM authentication failed [%d]", code);
801 OutputDebugF("LM authentication succeeded");
806 /* note down that we received a session setup X and set the capabilities flag */
807 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
808 lock_ObtainMutex(&vcp->mx);
809 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
810 /* for the moment we can only deal with NTSTATUS */
811 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
812 vcp->flags |= SMB_VCFLAG_STATUS32;
814 lock_ReleaseMutex(&vcp->mx);
817 /* code would be non-zero if there was an authentication failure.
818 Ideally we would like to invalidate the uid for this session or break
819 early to avoid accidently stealing someone else's tokens. */
825 OutputDebugF("Received username=[%s]", usern);
827 /* On Windows 2000, this function appears to be called more often than
828 it is expected to be called. This resulted in multiple smb_user_t
829 records existing all for the same user session which results in all
830 of the users tokens disappearing.
832 To avoid this problem, we look for an existing smb_user_t record
833 based on the users name, and use that one if we find it.
836 uidp = smb_FindUserByNameThisSession(vcp, usern);
837 if (uidp) { /* already there, so don't create a new one */
839 newUid = uidp->userID;
840 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
841 vcp->lana,vcp->lsn,newUid);
842 smb_ReleaseUID(uidp);
847 /* do a global search for the username/machine name pair */
848 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
849 lock_ObtainMutex(&unp->mx);
850 if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
851 /* clear the afslogon flag so that the tickets can now
852 * be freed when the refCount returns to zero.
854 unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
856 lock_ReleaseMutex(&unp->mx);
858 /* Create a new UID and cm_user_t structure */
861 userp = cm_NewUser();
862 cm_HoldUserVCRef(userp);
863 lock_ObtainMutex(&vcp->mx);
864 if (!vcp->uidCounter)
865 vcp->uidCounter++; /* handle unlikely wraparounds */
866 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
867 lock_ReleaseMutex(&vcp->mx);
869 /* Create a new smb_user_t structure and connect them up */
870 lock_ObtainMutex(&unp->mx);
872 lock_ReleaseMutex(&unp->mx);
874 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
875 lock_ObtainMutex(&uidp->mx);
877 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
878 lock_ReleaseMutex(&uidp->mx);
879 smb_ReleaseUID(uidp);
882 /* Return UID to the client */
883 ((smb_t *)outp)->uid = newUid;
884 /* Also to the next chained message */
885 ((smb_t *)inp)->uid = newUid;
887 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
888 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
890 smb_SetSMBParm(outp, 2, 0);
892 if (vcp->flags & SMB_VCFLAG_USENT) {
893 if (smb_authType == SMB_AUTH_EXTENDED) {
894 smb_SetSMBParm(outp, 3, secBlobOutLength);
895 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
896 tp = smb_GetSMBData(outp, NULL);
897 if (secBlobOutLength) {
898 memcpy(tp, secBlobOut, secBlobOutLength);
900 tp += secBlobOutLength;
902 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
903 tp += smb_ServerOSLength;
904 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
905 tp += smb_ServerLanManagerLength;
906 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
907 tp += smb_ServerDomainNameLength;
909 smb_SetSMBDataLength(outp, 0);
912 if (smb_authType == SMB_AUTH_EXTENDED) {
913 smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
914 tp = smb_GetSMBData(outp, NULL);
915 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
916 tp += smb_ServerOSLength;
917 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
918 tp += smb_ServerLanManagerLength;
919 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
920 tp += smb_ServerDomainNameLength;
922 smb_SetSMBDataLength(outp, 0);
929 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
933 /* find the tree and free it */
934 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
936 smb_username_t * unp;
938 osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %s", uidp->userID,
939 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "));
941 lock_ObtainMutex(&uidp->mx);
942 uidp->flags |= SMB_USERFLAG_DELETE;
944 * it doesn't get deleted right away
945 * because the vcp points to it
948 lock_ReleaseMutex(&uidp->mx);
951 /* we can't do this. we get logoff messages prior to a session
952 * disconnect even though it doesn't mean the user is logging out.
953 * we need to create a new pioctl and EventLogoff handler to set
954 * SMB_USERNAMEFLAG_LOGOFF.
956 if (unp && smb_LogoffTokenTransfer) {
957 lock_ObtainMutex(&unp->mx);
958 unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
959 unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
960 lock_ReleaseMutex(&unp->mx);
964 smb_ReleaseUID(uidp);
967 osi_Log0(smb_logp, "SMB3 user logoffX");
969 smb_SetSMBDataLength(outp, 0);
973 #define SMB_SUPPORT_SEARCH_BITS 0x0001
974 #define SMB_SHARE_IS_IN_DFS 0x0002
976 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
980 unsigned short newTid;
991 osi_Log0(smb_logp, "SMB3 receive tree connect");
993 /* parse input parameters */
994 tp = smb_GetSMBData(inp, NULL);
995 passwordp = smb_ParseString(tp, &tp);
996 pathp = smb_ParseString(tp, &tp);
997 if (smb_StoreAnsiFilenames)
998 OemToChar(pathp,pathp);
999 servicep = smb_ParseString(tp, &tp);
1001 tp = strrchr(pathp, '\\');
1003 return CM_ERROR_BADSMB;
1005 strcpy(shareName, tp+1);
1007 osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
1008 osi_LogSaveString(smb_logp, pathp),
1009 osi_LogSaveString(smb_logp, shareName));
1011 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
1013 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1016 return CM_ERROR_NOIPC;
1020 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1021 userp = smb_GetUserFromUID(uidp);
1023 lock_ObtainMutex(&vcp->mx);
1024 newTid = vcp->tidCounter++;
1025 lock_ReleaseMutex(&vcp->mx);
1027 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1030 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1032 smb_ReleaseUID(uidp);
1033 smb_ReleaseTID(tidp);
1034 return CM_ERROR_BADSHARENAME;
1037 if (vcp->flags & SMB_VCFLAG_USENT)
1039 int policy = smb_FindShareCSCPolicy(shareName);
1040 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1042 SMB_SHARE_IS_IN_DFS |
1047 smb_SetSMBParm(outp, 2, 0);
1050 smb_ReleaseUID(uidp);
1052 lock_ObtainMutex(&tidp->mx);
1053 tidp->userp = userp;
1054 tidp->pathname = sharePath;
1056 tidp->flags |= SMB_TIDFLAG_IPC;
1057 lock_ReleaseMutex(&tidp->mx);
1058 smb_ReleaseTID(tidp);
1060 ((smb_t *)outp)->tid = newTid;
1061 ((smb_t *)inp)->tid = newTid;
1062 tp = smb_GetSMBData(outp, NULL);
1064 /* XXX - why is this a drive letter? */
1073 smb_SetSMBDataLength(outp, 8);
1076 smb_SetSMBDataLength(outp, 4);
1079 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1083 /* must be called with global tran lock held */
1084 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1086 smb_tran2Packet_t *tp;
1089 smbp = (smb_t *) inp->data;
1090 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1091 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1097 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1098 int totalParms, int totalData)
1100 smb_tran2Packet_t *tp;
1103 smbp = (smb_t *) inp->data;
1104 tp = malloc(sizeof(*tp));
1105 memset(tp, 0, sizeof(*tp));
1108 tp->curData = tp->curParms = 0;
1109 tp->totalData = totalData;
1110 tp->totalParms = totalParms;
1111 tp->tid = smbp->tid;
1112 tp->mid = smbp->mid;
1113 tp->uid = smbp->uid;
1114 tp->pid = smbp->pid;
1115 tp->res[0] = smbp->res[0];
1116 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1117 if (totalParms != 0)
1118 tp->parmsp = malloc(totalParms);
1120 tp->datap = malloc(totalData);
1121 if (smbp->com == 0x25 || smbp->com == 0x26)
1124 tp->opcode = smb_GetSMBParm(inp, 14);
1127 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1131 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1132 smb_tran2Packet_t *inp, smb_packet_t *outp,
1133 int totalParms, int totalData)
1135 smb_tran2Packet_t *tp;
1136 unsigned short parmOffset;
1137 unsigned short dataOffset;
1138 unsigned short dataAlign;
1140 tp = malloc(sizeof(*tp));
1141 memset(tp, 0, sizeof(*tp));
1144 tp->curData = tp->curParms = 0;
1145 tp->totalData = totalData;
1146 tp->totalParms = totalParms;
1147 tp->oldTotalParms = totalParms;
1152 tp->res[0] = inp->res[0];
1153 tp->opcode = inp->opcode;
1157 * We calculate where the parameters and data will start.
1158 * This calculation must parallel the calculation in
1159 * smb_SendTran2Packet.
1162 parmOffset = 10*2 + 35;
1163 parmOffset++; /* round to even */
1164 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1166 dataOffset = parmOffset + totalParms;
1167 dataAlign = dataOffset & 2; /* quad-align */
1168 dataOffset += dataAlign;
1169 tp->datap = outp->data + dataOffset;
1174 /* free a tran2 packet */
1175 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1178 smb_ReleaseVC(t2p->vcp);
1181 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1190 /* called with a VC, an input packet to respond to, and an error code.
1191 * sends an error response.
1193 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1194 smb_packet_t *tp, long code)
1197 unsigned short errCode;
1198 unsigned char errClass;
1199 unsigned long NTStatus;
1201 if (vcp->flags & SMB_VCFLAG_STATUS32)
1202 smb_MapNTError(code, &NTStatus);
1204 smb_MapCoreError(code, vcp, &errCode, &errClass);
1206 smb_FormatResponsePacket(vcp, NULL, tp);
1207 smbp = (smb_t *) tp;
1209 /* We can handle long names */
1210 if (vcp->flags & SMB_VCFLAG_USENT)
1211 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1213 /* now copy important fields from the tran 2 packet */
1214 smbp->com = t2p->com;
1215 smbp->tid = t2p->tid;
1216 smbp->mid = t2p->mid;
1217 smbp->pid = t2p->pid;
1218 smbp->uid = t2p->uid;
1219 smbp->res[0] = t2p->res[0];
1220 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1221 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1222 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1223 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1224 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1225 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1228 smbp->rcls = errClass;
1229 smbp->errLow = (unsigned char) (errCode & 0xff);
1230 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1234 smb_SendPacket(vcp, tp);
1237 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1240 unsigned short parmOffset;
1241 unsigned short dataOffset;
1242 unsigned short totalLength;
1243 unsigned short dataAlign;
1246 smb_FormatResponsePacket(vcp, NULL, tp);
1247 smbp = (smb_t *) tp;
1249 /* We can handle long names */
1250 if (vcp->flags & SMB_VCFLAG_USENT)
1251 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1253 /* now copy important fields from the tran 2 packet */
1254 smbp->com = t2p->com;
1255 smbp->tid = t2p->tid;
1256 smbp->mid = t2p->mid;
1257 smbp->pid = t2p->pid;
1258 smbp->uid = t2p->uid;
1259 smbp->res[0] = t2p->res[0];
1261 totalLength = 1 + t2p->totalData + t2p->totalParms;
1263 /* now add the core parameters (tran2 info) to the packet */
1264 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1265 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1266 smb_SetSMBParm(tp, 2, 0); /* reserved */
1267 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1268 parmOffset = 10*2 + 35; /* parm offset in packet */
1269 parmOffset++; /* round to even */
1270 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1271 * hdr, bcc and wct */
1272 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1273 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1274 dataOffset = parmOffset + t2p->oldTotalParms;
1275 dataAlign = dataOffset & 2; /* quad-align */
1276 dataOffset += dataAlign;
1277 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1278 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1279 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1282 datap = smb_GetSMBData(tp, NULL);
1283 *datap++ = 0; /* we rounded to even */
1285 totalLength += dataAlign;
1286 smb_SetSMBDataLength(tp, totalLength);
1288 /* next, send the datagram */
1289 smb_SendPacket(vcp, tp);
1292 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1294 smb_tran2Packet_t *asp;
1307 /* We sometimes see 0 word count. What to do? */
1308 if (*inp->wctp == 0) {
1309 osi_Log0(smb_logp, "Transaction2 word count = 0");
1311 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1314 smb_SetSMBDataLength(outp, 0);
1315 smb_SendPacket(vcp, outp);
1319 totalParms = smb_GetSMBParm(inp, 0);
1320 totalData = smb_GetSMBParm(inp, 1);
1322 firstPacket = (inp->inCom == 0x25);
1324 /* find the packet we're reassembling */
1325 lock_ObtainWrite(&smb_globalLock);
1326 asp = smb_FindTran2Packet(vcp, inp);
1328 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1330 lock_ReleaseWrite(&smb_globalLock);
1332 /* now merge in this latest packet; start by looking up offsets */
1334 parmDisp = dataDisp = 0;
1335 parmOffset = smb_GetSMBParm(inp, 10);
1336 dataOffset = smb_GetSMBParm(inp, 12);
1337 parmCount = smb_GetSMBParm(inp, 9);
1338 dataCount = smb_GetSMBParm(inp, 11);
1339 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1340 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1342 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1343 totalData, dataCount, asp->maxReturnData);
1346 parmDisp = smb_GetSMBParm(inp, 4);
1347 parmOffset = smb_GetSMBParm(inp, 3);
1348 dataDisp = smb_GetSMBParm(inp, 7);
1349 dataOffset = smb_GetSMBParm(inp, 6);
1350 parmCount = smb_GetSMBParm(inp, 2);
1351 dataCount = smb_GetSMBParm(inp, 5);
1353 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1354 parmCount, dataCount);
1357 /* now copy the parms and data */
1358 if ( asp->totalParms > 0 && parmCount != 0 )
1360 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1362 if ( asp->totalData > 0 && dataCount != 0 ) {
1363 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1366 /* account for new bytes */
1367 asp->curData += dataCount;
1368 asp->curParms += parmCount;
1370 /* finally, if we're done, remove the packet from the queue and dispatch it */
1371 if (asp->totalParms > 0 &&
1372 asp->curParms > 0 &&
1373 asp->totalData <= asp->curData &&
1374 asp->totalParms <= asp->curParms) {
1375 /* we've received it all */
1376 lock_ObtainWrite(&smb_globalLock);
1377 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1378 lock_ReleaseWrite(&smb_globalLock);
1380 /* now dispatch it */
1381 rapOp = asp->parmsp[0];
1383 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1384 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1385 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1386 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
1389 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1390 code = CM_ERROR_BADOP;
1393 /* if an error is returned, we're supposed to send an error packet,
1394 * otherwise the dispatched function already did the data sending.
1395 * We give dispatched proc the responsibility since it knows how much
1396 * space to allocate.
1399 smb_SendTran2Error(vcp, asp, outp, code);
1402 /* free the input tran 2 packet */
1403 smb_FreeTran2Packet(asp);
1405 else if (firstPacket) {
1406 /* the first packet in a multi-packet request, we need to send an
1407 * ack to get more data.
1409 smb_SetSMBDataLength(outp, 0);
1410 smb_SendPacket(vcp, outp);
1416 /* ANSI versions. The unicode versions support arbitrary length
1417 share names, but we don't support unicode yet. */
1419 typedef struct smb_rap_share_info_0 {
1420 char shi0_netname[13];
1421 } smb_rap_share_info_0_t;
1423 typedef struct smb_rap_share_info_1 {
1424 char shi1_netname[13];
1427 DWORD shi1_remark; /* char *shi1_remark; data offset */
1428 } smb_rap_share_info_1_t;
1430 typedef struct smb_rap_share_info_2 {
1431 char shi2_netname[13];
1433 unsigned short shi2_type;
1434 DWORD shi2_remark; /* char *shi2_remark; data offset */
1435 unsigned short shi2_permissions;
1436 unsigned short shi2_max_uses;
1437 unsigned short shi2_current_uses;
1438 DWORD shi2_path; /* char *shi2_path; data offset */
1439 unsigned short shi2_passwd[9];
1440 unsigned short shi2_pad2;
1441 } smb_rap_share_info_2_t;
1443 #define SMB_RAP_MAX_SHARES 512
1445 typedef struct smb_rap_share_list {
1448 smb_rap_share_info_0_t * shares;
1449 } smb_rap_share_list_t;
1451 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1452 smb_rap_share_list_t * sp;
1457 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1458 return 0; /* skip over '.' and '..' */
1460 sp = (smb_rap_share_list_t *) vrockp;
1462 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1463 sp->shares[sp->cShare].shi0_netname[12] = 0;
1467 if (sp->cShare >= sp->maxShares)
1468 return CM_ERROR_STOPNOW;
1473 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1475 smb_tran2Packet_t *outp;
1476 unsigned short * tp;
1480 int outParmsTotal; /* total parameter bytes */
1481 int outDataTotal; /* total data bytes */
1484 DWORD allSubmount = 0;
1486 DWORD nRegShares = 0;
1487 DWORD nSharesRet = 0;
1489 HKEY hkSubmount = NULL;
1490 smb_rap_share_info_1_t * shares;
1493 char thisShare[256];
1496 smb_rap_share_list_t rootShares;
1501 tp = p->parmsp + 1; /* skip over function number (always 0) */
1502 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1503 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1507 if (infoLevel != 1) {
1508 return CM_ERROR_INVAL;
1511 /* first figure out how many shares there are */
1512 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1513 KEY_QUERY_VALUE, &hkParam);
1514 if (rv == ERROR_SUCCESS) {
1515 len = sizeof(allSubmount);
1516 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1517 (BYTE *) &allSubmount, &len);
1518 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1521 RegCloseKey (hkParam);
1524 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1525 0, KEY_QUERY_VALUE, &hkSubmount);
1526 if (rv == ERROR_SUCCESS) {
1527 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1528 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1529 if (rv != ERROR_SUCCESS)
1535 /* fetch the root shares */
1536 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1537 rootShares.cShare = 0;
1538 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1542 userp = smb_GetTran2User(vcp,p);
1544 thyper.HighPart = 0;
1547 cm_HoldSCache(cm_data.rootSCachep);
1548 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1549 cm_ReleaseSCache(cm_data.rootSCachep);
1551 cm_ReleaseUser(userp);
1553 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1555 #define REMARK_LEN 1
1556 outParmsTotal = 8; /* 4 dwords */
1557 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1558 if(outDataTotal > bufsize) {
1559 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1560 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1563 nSharesRet = nShares;
1566 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1568 /* now for the submounts */
1569 shares = (smb_rap_share_info_1_t *) outp->datap;
1570 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1572 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1575 strcpy( shares[cshare].shi1_netname, "all" );
1576 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1577 /* type and pad are zero already */
1583 for (i=0; i < nRegShares && cshare < nSharesRet; i++) {
1584 len = sizeof(thisShare);
1585 rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1586 if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1587 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1588 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1589 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1594 nShares--; /* uncount key */
1597 RegCloseKey(hkSubmount);
1600 nonrootShares = cshare;
1602 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1603 /* in case there are collisions with submounts, submounts have higher priority */
1604 for (j=0; j < nonrootShares; j++)
1605 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1608 if (j < nonrootShares) {
1609 nShares--; /* uncount */
1613 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1614 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1619 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1620 outp->parmsp[1] = 0;
1621 outp->parmsp[2] = cshare;
1622 outp->parmsp[3] = nShares;
1624 outp->totalData = (int)(cstrp - outp->datap);
1625 outp->totalParms = outParmsTotal;
1627 smb_SendTran2Packet(vcp, outp, op);
1628 smb_FreeTran2Packet(outp);
1630 free(rootShares.shares);
1635 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1637 smb_tran2Packet_t *outp;
1638 unsigned short * tp;
1640 BOOL shareFound = FALSE;
1641 unsigned short infoLevel;
1642 unsigned short bufsize;
1652 tp = p->parmsp + 1; /* skip over function number (always 1) */
1653 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1654 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1655 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1662 totalData = sizeof(smb_rap_share_info_0_t);
1663 else if(infoLevel == SMB_INFO_STANDARD)
1664 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1665 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1666 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1668 return CM_ERROR_INVAL;
1670 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1672 if(!stricmp(shareName,"all")) {
1673 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1674 KEY_QUERY_VALUE, &hkParam);
1675 if (rv == ERROR_SUCCESS) {
1676 len = sizeof(allSubmount);
1677 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1678 (BYTE *) &allSubmount, &len);
1679 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1682 RegCloseKey (hkParam);
1689 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1690 KEY_QUERY_VALUE, &hkSubmount);
1691 if (rv == ERROR_SUCCESS) {
1692 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1693 if (rv == ERROR_SUCCESS) {
1696 RegCloseKey(hkSubmount);
1701 smb_FreeTran2Packet(outp);
1702 return CM_ERROR_BADSHARENAME;
1705 memset(outp->datap, 0, totalData);
1707 outp->parmsp[0] = 0;
1708 outp->parmsp[1] = 0;
1709 outp->parmsp[2] = totalData;
1711 if (infoLevel == 0) {
1712 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1713 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1714 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1715 } else if(infoLevel == SMB_INFO_STANDARD) {
1716 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1717 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1718 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1719 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1720 /* type and pad are already zero */
1721 } else { /* infoLevel==2 */
1722 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1723 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1724 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1725 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1726 info->shi2_permissions = ACCESS_ALL;
1727 info->shi2_max_uses = (unsigned short) -1;
1728 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
1731 outp->totalData = totalData;
1732 outp->totalParms = totalParam;
1734 smb_SendTran2Packet(vcp, outp, op);
1735 smb_FreeTran2Packet(outp);
1740 typedef struct smb_rap_wksta_info_10 {
1741 DWORD wki10_computername; /*char *wki10_computername;*/
1742 DWORD wki10_username; /* char *wki10_username; */
1743 DWORD wki10_langroup; /* char *wki10_langroup;*/
1744 unsigned char wki10_ver_major;
1745 unsigned char wki10_ver_minor;
1746 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1747 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1748 } smb_rap_wksta_info_10_t;
1751 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1753 smb_tran2Packet_t *outp;
1757 unsigned short * tp;
1760 smb_rap_wksta_info_10_t * info;
1764 tp = p->parmsp + 1; /* Skip over function number */
1765 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1766 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1770 if (infoLevel != 10) {
1771 return CM_ERROR_INVAL;
1777 totalData = sizeof(*info) + /* info */
1778 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1779 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1780 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1781 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1782 1; /* wki10_oth_domains (null)*/
1784 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1786 memset(outp->parmsp,0,totalParams);
1787 memset(outp->datap,0,totalData);
1789 info = (smb_rap_wksta_info_10_t *) outp->datap;
1790 cstrp = (char *) (info + 1);
1792 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1793 strcpy(cstrp, smb_localNamep);
1794 cstrp += strlen(cstrp) + 1;
1796 info->wki10_username = (DWORD) (cstrp - outp->datap);
1797 uidp = smb_FindUID(vcp, p->uid, 0);
1799 lock_ObtainMutex(&uidp->mx);
1800 if(uidp->unp && uidp->unp->name)
1801 strcpy(cstrp, uidp->unp->name);
1802 lock_ReleaseMutex(&uidp->mx);
1803 smb_ReleaseUID(uidp);
1805 cstrp += strlen(cstrp) + 1;
1807 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1808 strcpy(cstrp, "WORKGROUP");
1809 cstrp += strlen(cstrp) + 1;
1811 /* TODO: Not sure what values these should take, but these work */
1812 info->wki10_ver_major = 5;
1813 info->wki10_ver_minor = 1;
1815 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1816 strcpy(cstrp, smb_ServerDomainName);
1817 cstrp += strlen(cstrp) + 1;
1819 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1820 cstrp ++; /* no other domains */
1822 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1823 outp->parmsp[2] = outp->totalData;
1824 outp->totalParms = totalParams;
1826 smb_SendTran2Packet(vcp,outp,op);
1827 smb_FreeTran2Packet(outp);
1832 typedef struct smb_rap_server_info_0 {
1834 } smb_rap_server_info_0_t;
1836 typedef struct smb_rap_server_info_1 {
1838 char sv1_version_major;
1839 char sv1_version_minor;
1840 unsigned long sv1_type;
1841 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1842 } smb_rap_server_info_1_t;
1844 char smb_ServerComment[] = "OpenAFS Client";
1845 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1847 #define SMB_SV_TYPE_SERVER 0x00000002L
1848 #define SMB_SV_TYPE_NT 0x00001000L
1849 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1851 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1853 smb_tran2Packet_t *outp;
1857 unsigned short * tp;
1860 smb_rap_server_info_0_t * info0;
1861 smb_rap_server_info_1_t * info1;
1864 tp = p->parmsp + 1; /* Skip over function number */
1865 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1866 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1870 if (infoLevel != 0 && infoLevel != 1) {
1871 return CM_ERROR_INVAL;
1877 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1878 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1880 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1882 memset(outp->parmsp,0,totalParams);
1883 memset(outp->datap,0,totalData);
1885 if (infoLevel == 0) {
1886 info0 = (smb_rap_server_info_0_t *) outp->datap;
1887 cstrp = (char *) (info0 + 1);
1888 strcpy(info0->sv0_name, "AFS");
1889 } else { /* infoLevel == SMB_INFO_STANDARD */
1890 info1 = (smb_rap_server_info_1_t *) outp->datap;
1891 cstrp = (char *) (info1 + 1);
1892 strcpy(info1->sv1_name, "AFS");
1895 SMB_SV_TYPE_SERVER |
1897 SMB_SV_TYPE_SERVER_NT;
1899 info1->sv1_version_major = 5;
1900 info1->sv1_version_minor = 1;
1901 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1903 strcpy(cstrp, smb_ServerComment);
1905 cstrp += smb_ServerCommentLen;
1908 totalData = (DWORD)(cstrp - outp->datap);
1909 outp->totalData = min(bufsize,totalData); /* actual data size */
1910 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1911 outp->parmsp[2] = totalData;
1912 outp->totalParms = totalParams;
1914 smb_SendTran2Packet(vcp,outp,op);
1915 smb_FreeTran2Packet(outp);
1920 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1922 smb_tran2Packet_t *asp;
1934 /* We sometimes see 0 word count. What to do? */
1935 if (*inp->wctp == 0) {
1936 osi_Log0(smb_logp, "Transaction2 word count = 0");
1938 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1941 smb_SetSMBDataLength(outp, 0);
1942 smb_SendPacket(vcp, outp);
1946 totalParms = smb_GetSMBParm(inp, 0);
1947 totalData = smb_GetSMBParm(inp, 1);
1949 firstPacket = (inp->inCom == 0x32);
1951 /* find the packet we're reassembling */
1952 lock_ObtainWrite(&smb_globalLock);
1953 asp = smb_FindTran2Packet(vcp, inp);
1955 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1957 lock_ReleaseWrite(&smb_globalLock);
1959 /* now merge in this latest packet; start by looking up offsets */
1961 parmDisp = dataDisp = 0;
1962 parmOffset = smb_GetSMBParm(inp, 10);
1963 dataOffset = smb_GetSMBParm(inp, 12);
1964 parmCount = smb_GetSMBParm(inp, 9);
1965 dataCount = smb_GetSMBParm(inp, 11);
1966 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1967 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1969 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1970 totalData, dataCount, asp->maxReturnData);
1973 parmDisp = smb_GetSMBParm(inp, 4);
1974 parmOffset = smb_GetSMBParm(inp, 3);
1975 dataDisp = smb_GetSMBParm(inp, 7);
1976 dataOffset = smb_GetSMBParm(inp, 6);
1977 parmCount = smb_GetSMBParm(inp, 2);
1978 dataCount = smb_GetSMBParm(inp, 5);
1980 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1981 parmCount, dataCount);
1984 /* now copy the parms and data */
1985 if ( asp->totalParms > 0 && parmCount != 0 )
1987 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1989 if ( asp->totalData > 0 && dataCount != 0 ) {
1990 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1993 /* account for new bytes */
1994 asp->curData += dataCount;
1995 asp->curParms += parmCount;
1997 /* finally, if we're done, remove the packet from the queue and dispatch it */
1998 if (asp->totalParms > 0 &&
1999 asp->curParms > 0 &&
2000 asp->totalData <= asp->curData &&
2001 asp->totalParms <= asp->curParms) {
2002 /* we've received it all */
2003 lock_ObtainWrite(&smb_globalLock);
2004 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2005 lock_ReleaseWrite(&smb_globalLock);
2007 /* now dispatch it */
2008 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2009 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2010 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2013 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2014 code = CM_ERROR_BADOP;
2017 /* if an error is returned, we're supposed to send an error packet,
2018 * otherwise the dispatched function already did the data sending.
2019 * We give dispatched proc the responsibility since it knows how much
2020 * space to allocate.
2023 smb_SendTran2Error(vcp, asp, outp, code);
2026 /* free the input tran 2 packet */
2027 smb_FreeTran2Packet(asp);
2029 else if (firstPacket) {
2030 /* the first packet in a multi-packet request, we need to send an
2031 * ack to get more data.
2033 smb_SetSMBDataLength(outp, 0);
2034 smb_SendPacket(vcp, outp);
2040 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2043 smb_tran2Packet_t *outp;
2048 cm_scache_t *dscp; /* dir we're dealing with */
2049 cm_scache_t *scp; /* file we're creating */
2051 int initialModeBits;
2061 int parmSlot; /* which parm we're dealing with */
2062 long returnEALength;
2071 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2072 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2074 openFun = p->parmsp[6]; /* open function */
2075 excl = ((openFun & 3) == 0);
2076 trunc = ((openFun & 3) == 2); /* truncate it */
2077 openMode = (p->parmsp[1] & 0x7);
2078 openAction = 0; /* tracks what we did */
2080 attributes = p->parmsp[3];
2081 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2083 /* compute initial mode bits based on read-only flag in attributes */
2084 initialModeBits = 0666;
2086 initialModeBits &= ~0222;
2088 pathp = (char *) (&p->parmsp[14]);
2089 if (smb_StoreAnsiFilenames)
2090 OemToChar(pathp,pathp);
2092 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2094 spacep = cm_GetSpace();
2095 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2097 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2098 /* special case magic file name for receiving IOCTL requests
2099 * (since IOCTL calls themselves aren't getting through).
2101 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2102 smb_SetupIoctlFid(fidp, spacep);
2104 /* copy out remainder of the parms */
2106 outp->parmsp[parmSlot++] = fidp->fid;
2108 outp->parmsp[parmSlot++] = 0; /* attrs */
2109 outp->parmsp[parmSlot++] = 0; /* mod time */
2110 outp->parmsp[parmSlot++] = 0;
2111 outp->parmsp[parmSlot++] = 0; /* len */
2112 outp->parmsp[parmSlot++] = 0x7fff;
2113 outp->parmsp[parmSlot++] = openMode;
2114 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2115 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2117 /* and the final "always present" stuff */
2118 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2119 /* next write out the "unique" ID */
2120 outp->parmsp[parmSlot++] = 0x1234;
2121 outp->parmsp[parmSlot++] = 0x5678;
2122 outp->parmsp[parmSlot++] = 0;
2123 if (returnEALength) {
2124 outp->parmsp[parmSlot++] = 0;
2125 outp->parmsp[parmSlot++] = 0;
2128 outp->totalData = 0;
2129 outp->totalParms = parmSlot * 2;
2131 smb_SendTran2Packet(vcp, outp, op);
2133 smb_FreeTran2Packet(outp);
2135 /* and clean up fid reference */
2136 smb_ReleaseFID(fidp);
2140 #ifdef DEBUG_VERBOSE
2142 char *hexp, *asciip;
2143 asciip = (lastNamep ? lastNamep : pathp);
2144 hexp = osi_HexifyString( asciip );
2145 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2150 userp = smb_GetTran2User(vcp, p);
2151 /* In the off chance that userp is NULL, we log and abandon */
2153 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2154 smb_FreeTran2Packet(outp);
2155 return CM_ERROR_BADSMB;
2158 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2159 if (code == CM_ERROR_TIDIPC) {
2160 /* Attempt to use a TID allocated for IPC. The client
2161 * is probably looking for DCE RPC end points which we
2162 * don't support OR it could be looking to make a DFS
2165 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2167 cm_ReleaseUser(userp);
2168 smb_FreeTran2Packet(outp);
2169 return CM_ERROR_NOSUCHPATH;
2174 code = cm_NameI(cm_data.rootSCachep, pathp,
2175 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2176 userp, tidPathp, &req, &scp);
2178 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2179 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2180 userp, tidPathp, &req, &dscp);
2181 cm_FreeSpace(spacep);
2184 cm_ReleaseUser(userp);
2185 smb_FreeTran2Packet(outp);
2190 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2191 cm_ReleaseSCache(dscp);
2192 cm_ReleaseUser(userp);
2193 smb_FreeTran2Packet(outp);
2194 if ( WANTS_DFS_PATHNAMES(p) )
2195 return CM_ERROR_PATH_NOT_COVERED;
2197 return CM_ERROR_BADSHARENAME;
2199 #endif /* DFS_SUPPORT */
2201 /* otherwise, scp points to the parent directory. Do a lookup,
2202 * and truncate the file if we find it, otherwise we create the
2209 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2211 if (code && code != CM_ERROR_NOSUCHFILE) {
2212 cm_ReleaseSCache(dscp);
2213 cm_ReleaseUser(userp);
2214 smb_FreeTran2Packet(outp);
2219 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2220 cm_ReleaseSCache(scp);
2221 cm_ReleaseUser(userp);
2222 smb_FreeTran2Packet(outp);
2223 if ( WANTS_DFS_PATHNAMES(p) )
2224 return CM_ERROR_PATH_NOT_COVERED;
2226 return CM_ERROR_BADSHARENAME;
2228 #endif /* DFS_SUPPORT */
2230 /* macintosh is expensive to program for it */
2231 cm_FreeSpace(spacep);
2234 /* if we get here, if code is 0, the file exists and is represented by
2235 * scp. Otherwise, we have to create it.
2238 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2241 cm_ReleaseSCache(dscp);
2242 cm_ReleaseSCache(scp);
2243 cm_ReleaseUser(userp);
2244 smb_FreeTran2Packet(outp);
2249 /* oops, file shouldn't be there */
2251 cm_ReleaseSCache(dscp);
2252 cm_ReleaseSCache(scp);
2253 cm_ReleaseUser(userp);
2254 smb_FreeTran2Packet(outp);
2255 return CM_ERROR_EXISTS;
2259 setAttr.mask = CM_ATTRMASK_LENGTH;
2260 setAttr.length.LowPart = 0;
2261 setAttr.length.HighPart = 0;
2262 code = cm_SetAttr(scp, &setAttr, userp, &req);
2263 openAction = 3; /* truncated existing file */
2266 openAction = 1; /* found existing file */
2268 else if (!(openFun & 0x10)) {
2269 /* don't create if not found */
2271 cm_ReleaseSCache(dscp);
2272 osi_assert(scp == NULL);
2273 cm_ReleaseUser(userp);
2274 smb_FreeTran2Packet(outp);
2275 return CM_ERROR_NOSUCHFILE;
2278 osi_assert(dscp != NULL && scp == NULL);
2279 openAction = 2; /* created file */
2280 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2281 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2282 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2286 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2287 smb_NotifyChange(FILE_ACTION_ADDED,
2288 FILE_NOTIFY_CHANGE_FILE_NAME,
2289 dscp, lastNamep, NULL, TRUE);
2290 } else if (!excl && code == CM_ERROR_EXISTS) {
2291 /* not an exclusive create, and someone else tried
2292 * creating it already, then we open it anyway. We
2293 * don't bother retrying after this, since if this next
2294 * fails, that means that the file was deleted after we
2295 * started this call.
2297 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2301 setAttr.mask = CM_ATTRMASK_LENGTH;
2302 setAttr.length.LowPart = 0;
2303 setAttr.length.HighPart = 0;
2304 code = cm_SetAttr(scp, &setAttr, userp,
2307 } /* lookup succeeded */
2311 /* we don't need this any longer */
2313 cm_ReleaseSCache(dscp);
2316 /* something went wrong creating or truncating the file */
2318 cm_ReleaseSCache(scp);
2319 cm_ReleaseUser(userp);
2320 smb_FreeTran2Packet(outp);
2324 /* make sure we're about to open a file */
2325 if (scp->fileType != CM_SCACHETYPE_FILE) {
2327 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2328 cm_scache_t * targetScp = 0;
2329 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2331 /* we have a more accurate file to use (the
2332 * target of the symbolic link). Otherwise,
2333 * we'll just use the symlink anyway.
2335 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2337 cm_ReleaseSCache(scp);
2341 if (scp->fileType != CM_SCACHETYPE_FILE) {
2342 cm_ReleaseSCache(scp);
2343 cm_ReleaseUser(userp);
2344 smb_FreeTran2Packet(outp);
2345 return CM_ERROR_ISDIR;
2349 /* now all we have to do is open the file itself */
2350 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2354 lock_ObtainMutex(&fidp->mx);
2355 /* save a pointer to the vnode */
2358 fidp->userp = userp;
2360 /* compute open mode */
2362 fidp->flags |= SMB_FID_OPENREAD;
2363 if (openMode == 1 || openMode == 2)
2364 fidp->flags |= SMB_FID_OPENWRITE;
2366 /* remember that the file was newly created */
2368 fidp->flags |= SMB_FID_CREATED;
2370 lock_ReleaseMutex(&fidp->mx);
2372 smb_ReleaseFID(fidp);
2374 cm_Open(scp, 0, userp);
2376 /* copy out remainder of the parms */
2378 outp->parmsp[parmSlot++] = fidp->fid;
2379 lock_ObtainMutex(&scp->mx);
2381 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2382 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2383 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2384 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2385 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2386 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2387 outp->parmsp[parmSlot++] = openMode;
2388 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2389 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2391 /* and the final "always present" stuff */
2392 outp->parmsp[parmSlot++] = openAction;
2393 /* next write out the "unique" ID */
2394 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2395 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2396 outp->parmsp[parmSlot++] = 0;
2397 if (returnEALength) {
2398 outp->parmsp[parmSlot++] = 0;
2399 outp->parmsp[parmSlot++] = 0;
2401 lock_ReleaseMutex(&scp->mx);
2402 outp->totalData = 0; /* total # of data bytes */
2403 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2405 smb_SendTran2Packet(vcp, outp, op);
2407 smb_FreeTran2Packet(outp);
2409 cm_ReleaseUser(userp);
2410 /* leave scp held since we put it in fidp->scp */
2414 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2416 osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2417 return CM_ERROR_BADOP;
2420 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2422 osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2423 return CM_ERROR_BADOP;
2426 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2428 smb_tran2Packet_t *outp;
2429 smb_tran2QFSInfo_t qi;
2432 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
2434 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2436 switch (p->parmsp[0]) {
2437 case 1: responseSize = sizeof(qi.u.allocInfo); break;
2438 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
2440 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
2441 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
2442 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
2443 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
2444 case 0x200: /* CIFS Unix Info */
2445 case 0x301: /* Mac FS Info */
2447 return CM_ERROR_INVAL;
2450 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2451 switch (p->parmsp[0]) {
2454 qi.u.allocInfo.FSID = 0;
2455 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2456 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2457 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2458 qi.u.allocInfo.bytesPerSector = 1024;
2463 qi.u.volumeInfo.vsn = 1234;
2464 qi.u.volumeInfo.vnCount = 4;
2465 /* we're supposed to pad it out with zeroes to the end */
2466 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2467 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2471 /* FS volume info */
2472 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
2473 qi.u.FSvolumeInfo.vsn = 1234;
2474 qi.u.FSvolumeInfo.vnCount = 8;
2475 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
2481 temp.LowPart = 0x7fffffff;
2482 qi.u.FSsizeInfo.totalAllocUnits = temp;
2483 temp.LowPart = 0x3fffffff;
2484 qi.u.FSsizeInfo.availAllocUnits = temp;
2485 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2486 qi.u.FSsizeInfo.bytesPerSector = 1024;
2490 /* FS device info */
2491 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
2492 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2496 /* FS attribute info */
2497 /* attributes, defined in WINNT.H:
2498 * FILE_CASE_SENSITIVE_SEARCH 0x1
2499 * FILE_CASE_PRESERVED_NAMES 0x2
2500 * <no name defined> 0x4000
2501 * If bit 0x4000 is not set, Windows 95 thinks
2502 * we can't handle long (non-8.3) names,
2503 * despite our protestations to the contrary.
2505 qi.u.FSattributeInfo.attributes = 0x4003;
2506 qi.u.FSattributeInfo.maxCompLength = 255;
2507 qi.u.FSattributeInfo.FSnameLength = 6;
2508 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
2512 /* copy out return data, and set corresponding sizes */
2513 outp->totalParms = 0;
2514 outp->totalData = responseSize;
2515 memcpy(outp->datap, &qi, responseSize);
2517 /* send and free the packets */
2518 smb_SendTran2Packet(vcp, outp, op);
2519 smb_FreeTran2Packet(outp);
2524 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2526 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2527 return CM_ERROR_BADOP;
2530 struct smb_ShortNameRock {
2534 size_t shortNameLen;
2537 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2540 struct smb_ShortNameRock *rockp;
2544 /* compare both names and vnodes, though probably just comparing vnodes
2545 * would be safe enough.
2547 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2549 if (ntohl(dep->fid.vnode) != rockp->vnode)
2551 /* This is the entry */
2552 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2553 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2554 return CM_ERROR_STOPNOW;
2557 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2558 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2560 struct smb_ShortNameRock rock;
2564 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2568 spacep = cm_GetSpace();
2569 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2571 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2573 cm_FreeSpace(spacep);
2578 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2579 cm_ReleaseSCache(dscp);
2580 cm_ReleaseUser(userp);
2581 return CM_ERROR_PATH_NOT_COVERED;
2583 #endif /* DFS_SUPPORT */
2585 if (!lastNamep) lastNamep = pathp;
2588 thyper.HighPart = 0;
2589 rock.shortName = shortName;
2591 rock.maskp = lastNamep;
2592 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2594 cm_ReleaseSCache(dscp);
2597 return CM_ERROR_NOSUCHFILE;
2598 if (code == CM_ERROR_STOPNOW) {
2599 *shortNameLenp = rock.shortNameLen;
2605 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2607 smb_tran2Packet_t *outp;
2610 unsigned short infoLevel;
2612 unsigned short attributes;
2613 unsigned long extAttributes;
2618 cm_scache_t *scp, *dscp;
2627 infoLevel = p->parmsp[0];
2628 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2630 else if (infoLevel == SMB_INFO_STANDARD)
2631 nbytesRequired = 22;
2632 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2633 nbytesRequired = 26;
2634 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2635 nbytesRequired = 40;
2636 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2637 nbytesRequired = 24;
2638 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2640 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2641 nbytesRequired = 30;
2643 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2644 p->opcode, infoLevel);
2645 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2648 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2649 osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
2651 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2653 if (infoLevel > 0x100)
2654 outp->totalParms = 2;
2656 outp->totalParms = 0;
2657 outp->totalData = nbytesRequired;
2659 /* now, if we're at infoLevel 6, we're only being asked to check
2660 * the syntax, so we just OK things now. In particular, we're *not*
2661 * being asked to verify anything about the state of any parent dirs.
2663 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2664 smb_SendTran2Packet(vcp, outp, opx);
2665 smb_FreeTran2Packet(outp);
2669 userp = smb_GetTran2User(vcp, p);
2671 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2672 smb_FreeTran2Packet(outp);
2673 return CM_ERROR_BADSMB;
2676 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2678 cm_ReleaseUser(userp);
2679 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2680 smb_FreeTran2Packet(outp);
2685 * XXX Strange hack XXX
2687 * As of Patch 7 (13 January 98), we are having the following problem:
2688 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2689 * requests to look up "desktop.ini" in all the subdirectories.
2690 * This can cause zillions of timeouts looking up non-existent cells
2691 * and volumes, especially in the top-level directory.
2693 * We have not found any way to avoid this or work around it except
2694 * to explicitly ignore the requests for mount points that haven't
2695 * yet been evaluated and for directories that haven't yet been
2698 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2699 spacep = cm_GetSpace();
2700 smb_StripLastComponent(spacep->data, &lastComp,
2701 (char *)(&p->parmsp[3]));
2702 #ifndef SPECIAL_FOLDERS
2703 /* Make sure that lastComp is not NULL */
2705 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2706 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2710 userp, tidPathp, &req, &dscp);
2713 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2714 if ( WANTS_DFS_PATHNAMES(p) )
2715 code = CM_ERROR_PATH_NOT_COVERED;
2717 code = CM_ERROR_BADSHARENAME;
2719 #endif /* DFS_SUPPORT */
2720 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2721 code = CM_ERROR_NOSUCHFILE;
2722 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2723 cm_buf_t *bp = buf_Find(dscp, &hzero);
2727 code = CM_ERROR_NOSUCHFILE;
2729 cm_ReleaseSCache(dscp);
2731 cm_FreeSpace(spacep);
2732 cm_ReleaseUser(userp);
2733 smb_SendTran2Error(vcp, p, opx, code);
2734 smb_FreeTran2Packet(outp);
2740 #endif /* SPECIAL_FOLDERS */
2742 cm_FreeSpace(spacep);
2745 /* now do namei and stat, and copy out the info */
2746 code = cm_NameI(cm_data.rootSCachep, (char *)(&p->parmsp[3]),
2747 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2750 cm_ReleaseUser(userp);
2751 smb_SendTran2Error(vcp, p, opx, code);
2752 smb_FreeTran2Packet(outp);
2757 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2758 cm_ReleaseSCache(scp);
2759 cm_ReleaseUser(userp);
2760 if ( WANTS_DFS_PATHNAMES(p) )
2761 code = CM_ERROR_PATH_NOT_COVERED;
2763 code = CM_ERROR_BADSHARENAME;
2764 smb_SendTran2Error(vcp, p, opx, code);
2765 smb_FreeTran2Packet(outp);
2768 #endif /* DFS_SUPPORT */
2770 lock_ObtainMutex(&scp->mx);
2771 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2772 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2773 if (code) goto done;
2775 /* now we have the status in the cache entry, and everything is locked.
2776 * Marshall the output data.
2779 /* for info level 108, figure out short name */
2780 if (infoLevel == 0x108) {
2781 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
2782 tidPathp, scp->fid.vnode, shortName,
2789 *((u_long *)op) = len * 2; op += 4;
2790 mbstowcs((unsigned short *)op, shortName, len);
2795 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2796 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2797 *((u_long *)op) = dosTime; op += 4; /* creation time */
2798 *((u_long *)op) = dosTime; op += 4; /* access time */
2799 *((u_long *)op) = dosTime; op += 4; /* write time */
2800 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
2801 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
2802 attributes = smb_Attributes(scp);
2803 *((u_short *)op) = attributes; op += 2; /* attributes */
2805 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2806 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2807 *((FILETIME *)op) = ft; op += 8; /* creation time */
2808 *((FILETIME *)op) = ft; op += 8; /* last access time */
2809 *((FILETIME *)op) = ft; op += 8; /* last write time */
2810 *((FILETIME *)op) = ft; op += 8; /* last change time */
2811 extAttributes = smb_ExtAttributes(scp);
2812 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
2813 *((u_long *)op) = 0; op += 4; /* don't know what this is */
2815 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2816 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2817 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2818 *((u_long *)op) = scp->linkCount; op += 4;
2821 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2824 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2825 memset(op, 0, 4); op += 4; /* EA size */
2828 /* now, if we are being asked about extended attrs, return a 0 size */
2829 if (infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2830 *((u_long *)op) = 0; op += 4;
2834 /* send and free the packets */
2836 lock_ReleaseMutex(&scp->mx);
2837 cm_ReleaseSCache(scp);
2838 cm_ReleaseUser(userp);
2840 smb_SendTran2Packet(vcp, outp, opx);
2842 smb_SendTran2Error(vcp, p, opx, code);
2843 smb_FreeTran2Packet(outp);
2848 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2850 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2851 return CM_ERROR_BADOP;
2854 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2856 smb_tran2Packet_t *outp;
2858 unsigned long attributes;
2859 unsigned short infoLevel;
2872 fidp = smb_FindFID(vcp, fid, 0);
2875 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2879 infoLevel = p->parmsp[1];
2880 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2881 nbytesRequired = 40;
2882 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2883 nbytesRequired = 24;
2884 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2886 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2889 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2890 p->opcode, infoLevel);
2891 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2892 smb_ReleaseFID(fidp);
2895 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2897 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2899 if (infoLevel > 0x100)
2900 outp->totalParms = 2;
2902 outp->totalParms = 0;
2903 outp->totalData = nbytesRequired;
2905 userp = smb_GetTran2User(vcp, p);
2907 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2908 code = CM_ERROR_BADSMB;
2912 lock_ObtainMutex(&fidp->mx);
2914 lock_ObtainMutex(&scp->mx);
2915 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2916 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2920 /* now we have the status in the cache entry, and everything is locked.
2921 * Marshall the output data.
2924 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2925 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2926 *((FILETIME *)op) = ft; op += 8; /* creation time */
2927 *((FILETIME *)op) = ft; op += 8; /* last access time */
2928 *((FILETIME *)op) = ft; op += 8; /* last write time */
2929 *((FILETIME *)op) = ft; op += 8; /* last change time */
2930 attributes = smb_ExtAttributes(scp);
2931 *((u_long *)op) = attributes; op += 4;
2932 *((u_long *)op) = 0; op += 4;
2934 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2935 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2936 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2937 *((u_long *)op) = scp->linkCount; op += 4;
2938 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
2939 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2943 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2944 *((u_long *)op) = 0; op += 4;
2946 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2950 if (fidp->NTopen_wholepathp)
2951 name = fidp->NTopen_wholepathp;
2953 name = "\\"; /* probably can't happen */
2954 len = (unsigned long)strlen(name);
2955 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
2956 *((u_long *)op) = len * 2; op += 4;
2957 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2960 /* send and free the packets */
2962 lock_ReleaseMutex(&scp->mx);
2963 lock_ReleaseMutex(&fidp->mx);
2964 cm_ReleaseUser(userp);
2965 smb_ReleaseFID(fidp);
2967 smb_SendTran2Packet(vcp, outp, opx);
2969 smb_SendTran2Error(vcp, p, opx, code);
2970 smb_FreeTran2Packet(outp);
2975 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2980 unsigned short infoLevel;
2981 smb_tran2Packet_t *outp;
2989 fidp = smb_FindFID(vcp, fid, 0);
2992 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
2996 infoLevel = p->parmsp[1];
2997 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
2998 if (infoLevel > 0x104 || infoLevel < 0x101) {
2999 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3000 p->opcode, infoLevel);
3001 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
3002 smb_ReleaseFID(fidp);
3006 lock_ObtainMutex(&fidp->mx);
3007 if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) {
3008 lock_ReleaseMutex(&fidp->mx);
3009 smb_ReleaseFID(fidp);
3010 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
3013 if ((infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO)
3014 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3015 lock_ReleaseMutex(&fidp->mx);
3016 smb_ReleaseFID(fidp);
3017 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
3020 lock_ReleaseMutex(&fidp->mx);
3022 osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
3024 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
3026 outp->totalParms = 2;
3027 outp->totalData = 0;
3029 userp = smb_GetTran2User(vcp, p);
3031 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3032 code = CM_ERROR_BADSMB;
3038 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3040 unsigned int attribute;
3043 /* lock the vnode with a callback; we need the current status
3044 * to determine what the new status is, in some cases.
3046 lock_ObtainMutex(&fidp->mx);
3047 lock_ObtainMutex(&scp->mx);
3048 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3049 CM_SCACHESYNC_GETSTATUS
3050 | CM_SCACHESYNC_NEEDCALLBACK);
3052 lock_ReleaseMutex(&scp->mx);
3056 /* prepare for setattr call */
3059 lastMod = *((FILETIME *)(p->datap + 16));
3060 /* when called as result of move a b, lastMod is (-1, -1).
3061 * If the check for -1 is not present, timestamp
3062 * of the resulting file will be 1969 (-1)
3064 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3065 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3066 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3067 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3068 fidp->flags |= SMB_FID_MTIMESETDONE;
3071 attribute = *((u_long *)(p->datap + 32));
3072 if (attribute != 0) {
3073 if ((scp->unixModeBits & 0222)
3074 && (attribute & 1) != 0) {
3075 /* make a writable file read-only */
3076 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3077 attr.unixModeBits = scp->unixModeBits & ~0222;
3079 else if ((scp->unixModeBits & 0222) == 0
3080 && (attribute & 1) == 0) {
3081 /* make a read-only file writable */
3082 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3083 attr.unixModeBits = scp->unixModeBits | 0222;
3086 lock_ReleaseMutex(&scp->mx);
3087 lock_ReleaseMutex(&fidp->mx);
3091 code = cm_SetAttr(scp, &attr, userp, &req);
3095 else if (infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3096 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3099 attr.mask = CM_ATTRMASK_LENGTH;
3100 attr.length.LowPart = size.LowPart;
3101 attr.length.HighPart = size.HighPart;
3102 code = cm_SetAttr(scp, &attr, userp, &req);
3104 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3105 if (*((char *)(p->datap))) {
3106 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3109 lock_ObtainMutex(&fidp->mx);
3110 fidp->flags |= SMB_FID_DELONCLOSE;
3111 lock_ReleaseMutex(&fidp->mx);
3116 lock_ObtainMutex(&fidp->mx);
3117 fidp->flags &= ~SMB_FID_DELONCLOSE;
3118 lock_ReleaseMutex(&fidp->mx);
3123 cm_ReleaseUser(userp);
3124 smb_ReleaseFID(fidp);
3126 smb_SendTran2Packet(vcp, outp, op);
3128 smb_SendTran2Error(vcp, p, op, code);
3129 smb_FreeTran2Packet(outp);
3135 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3137 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3138 return CM_ERROR_BADOP;
3142 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3144 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3145 return CM_ERROR_BADOP;
3149 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3151 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3152 return CM_ERROR_BADOP;
3156 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3158 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3159 return CM_ERROR_BADOP;
3163 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3165 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3166 return CM_ERROR_BADOP;
3170 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3172 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3173 return CM_ERROR_BADOP;
3176 struct smb_v2_referral {
3178 USHORT ReferralFlags;
3181 USHORT DfsPathOffset;
3182 USHORT DfsAlternativePathOffset;
3183 USHORT NetworkAddressOffset;
3187 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3189 /* This is a UNICODE only request (bit15 of Flags2) */
3190 /* The TID must be IPC$ */
3192 /* The documentation for the Flags response field is contradictory */
3194 /* Use Version 1 Referral Element Format */
3195 /* ServerType = 0; indicates the next server should be queried for the file */
3196 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3197 /* Node = UnicodeString of UNC path of the next share name */
3200 int maxReferralLevel = 0;
3201 char requestFileName[1024] = "";
3202 smb_tran2Packet_t *outp = 0;
3203 cm_user_t *userp = 0;
3205 CPINFO CodePageInfo;
3206 int i, nbnLen, reqLen;
3211 maxReferralLevel = p->parmsp[0];
3213 GetCPInfo(CP_ACP, &CodePageInfo);
3214 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
3215 requestFileName, 1024, NULL, NULL);
3217 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
3218 maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3220 nbnLen = strlen(cm_NetbiosName);
3221 reqLen = strlen(requestFileName);
3223 if (reqLen == nbnLen + 5 &&
3224 requestFileName[0] == '\\' &&
3225 !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3226 requestFileName[nbnLen+1] == '\\' &&
3227 !_strnicmp("all",&requestFileName[nbnLen+2],3))
3230 struct smb_v2_referral * v2ref;
3231 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
3233 sp = (USHORT *)outp->datap;
3235 sp[idx++] = reqLen; /* path consumed */
3236 sp[idx++] = 1; /* number of referrals */
3237 sp[idx++] = 0x03; /* flags */
3238 #ifdef DFS_VERSION_1
3239 sp[idx++] = 1; /* Version Number */
3240 sp[idx++] = reqLen + 4; /* Referral Size */
3241 sp[idx++] = 1; /* Type = SMB Server */
3242 sp[idx++] = 0; /* Do not strip path consumed */
3243 for ( i=0;i<=reqLen; i++ )
3244 sp[i+idx] = requestFileName[i];
3245 #else /* DFS_VERSION_2 */
3246 sp[idx++] = 2; /* Version Number */
3247 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3248 idx += (sizeof(struct smb_v2_referral) / 2);
3249 v2ref = (struct smb_v2_referral *) &sp[5];
3250 v2ref->ServerType = 1; /* SMB Server */
3251 v2ref->ReferralFlags = 0x03;
3252 v2ref->Proximity = 0; /* closest */
3253 v2ref->TimeToLive = 3600; /* seconds */
3254 v2ref->DfsPathOffset = idx * 2;
3255 v2ref->DfsAlternativePathOffset = idx * 2;
3256 v2ref->NetworkAddressOffset = 0;
3257 for ( i=0;i<=reqLen; i++ )
3258 sp[i+idx] = requestFileName[i];
3261 userp = smb_GetTran2User(vcp, p);
3263 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3264 code = CM_ERROR_BADSMB;
3269 code = CM_ERROR_NOSUCHPATH;
3274 cm_ReleaseUser(userp);
3276 smb_SendTran2Packet(vcp, outp, op);
3278 smb_SendTran2Error(vcp, p, op, code);
3280 smb_FreeTran2Packet(outp);
3283 #else /* DFS_SUPPORT */
3284 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3285 return CM_ERROR_BADOP;
3286 #endif /* DFS_SUPPORT */
3290 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3292 /* This is a UNICODE only request (bit15 of Flags2) */
3294 /* There is nothing we can do about this operation. The client is going to
3295 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3296 * Unfortunately, there is really nothing we can do about it other then log it
3297 * somewhere. Even then I don't think there is anything for us to do.
3298 * So let's return an error value.
3301 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3302 return CM_ERROR_BADOP;
3306 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3307 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3312 cm_scache_t *targetScp; /* target if scp is a symlink */
3317 unsigned short attr;
3318 unsigned long lattr;
3319 smb_dirListPatch_t *patchp;
3320 smb_dirListPatch_t *npatchp;
3322 for(patchp = *dirPatchespp; patchp; patchp =
3323 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3324 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3326 lock_ObtainMutex(&scp->mx);
3327 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3328 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3330 lock_ReleaseMutex(&scp->mx);
3331 cm_ReleaseSCache(scp);
3333 dptr = patchp->dptr;
3335 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3336 errors in the client. */
3337 if (infoLevel >= 0x101) {
3338 /* 1969-12-31 23:59:59 +00 */
3339 ft.dwHighDateTime = 0x19DB200;
3340 ft.dwLowDateTime = 0x5BB78980;
3342 /* copy to Creation Time */
3343 *((FILETIME *)dptr) = ft;
3346 /* copy to Last Access Time */
3347 *((FILETIME *)dptr) = ft;
3350 /* copy to Last Write Time */
3351 *((FILETIME *)dptr) = ft;
3354 /* copy to Change Time */
3355 *((FILETIME *)dptr) = ft;
3358 /* merge in hidden attribute */
3359 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3360 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3364 /* 1969-12-31 23:59:58 +00*/
3365 dosTime = 0xEBBFBF7D;
3367 /* and copy out date */
3368 shortTemp = (dosTime>>16) & 0xffff;
3369 *((u_short *)dptr) = shortTemp;
3372 /* copy out creation time */
3373 shortTemp = dosTime & 0xffff;
3374 *((u_short *)dptr) = shortTemp;
3377 /* and copy out date */
3378 shortTemp = (dosTime>>16) & 0xffff;
3379 *((u_short *)dptr) = shortTemp;
3382 /* copy out access time */
3383 shortTemp = dosTime & 0xffff;
3384 *((u_short *)dptr) = shortTemp;
3387 /* and copy out date */
3388 shortTemp = (dosTime>>16) & 0xffff;
3389 *((u_short *)dptr) = shortTemp;
3392 /* copy out mod time */
3393 shortTemp = dosTime & 0xffff;
3394 *((u_short *)dptr) = shortTemp;
3397 /* merge in hidden (dot file) attribute */
3398 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3399 attr = SMB_ATTR_HIDDEN;
3400 *dptr++ = attr & 0xff;
3401 *dptr++ = (attr >> 8) & 0xff;
3407 /* now watch for a symlink */
3409 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3410 lock_ReleaseMutex(&scp->mx);
3411 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3413 /* we have a more accurate file to use (the
3414 * target of the symbolic link). Otherwise,
3415 * we'll just use the symlink anyway.
3417 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3419 cm_ReleaseSCache(scp);
3422 lock_ObtainMutex(&scp->mx);
3425 dptr = patchp->dptr;
3427 if (infoLevel >= 0x101) {
3429 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3431 /* copy to Creation Time */
3432 *((FILETIME *)dptr) = ft;
3435 /* copy to Last Access Time */
3436 *((FILETIME *)dptr) = ft;
3439 /* copy to Last Write Time */
3440 *((FILETIME *)dptr) = ft;
3443 /* copy to Change Time */
3444 *((FILETIME *)dptr) = ft;
3447 /* Use length for both file length and alloc length */
3448 *((LARGE_INTEGER *)dptr) = scp->length;
3450 *((LARGE_INTEGER *)dptr) = scp->length;
3453 /* Copy attributes */
3454 lattr = smb_ExtAttributes(scp);
3455 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3456 if (lattr == SMB_ATTR_NORMAL)
3457 lattr = SMB_ATTR_DIRECTORY;
3459 lattr |= SMB_ATTR_DIRECTORY;
3461 /* merge in hidden (dot file) attribute */
3462 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3463 if (lattr == SMB_ATTR_NORMAL)
3464 lattr = SMB_ATTR_HIDDEN;
3466 lattr |= SMB_ATTR_HIDDEN;
3468 *((u_long *)dptr) = lattr;
3472 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3474 /* and copy out date */
3475 shortTemp = (dosTime>>16) & 0xffff;
3476 *((u_short *)dptr) = shortTemp;
3479 /* copy out creation time */
3480 shortTemp = dosTime & 0xffff;
3481 *((u_short *)dptr) = shortTemp;
3484 /* and copy out date */
3485 shortTemp = (dosTime>>16) & 0xffff;
3486 *((u_short *)dptr) = shortTemp;
3489 /* copy out access time */
3490 shortTemp = dosTime & 0xffff;
3491 *((u_short *)dptr) = shortTemp;
3494 /* and copy out date */
3495 shortTemp = (dosTime>>16) & 0xffff;
3496 *((u_short *)dptr) = shortTemp;
3499 /* copy out mod time */
3500 shortTemp = dosTime & 0xffff;
3501 *((u_short *)dptr) = shortTemp;
3504 /* copy out file length and alloc length,
3505 * using the same for both
3507 *((u_long *)dptr) = scp->length.LowPart;
3509 *((u_long *)dptr) = scp->length.LowPart;
3512 /* finally copy out attributes as short */
3513 attr = smb_Attributes(scp);
3514 /* merge in hidden (dot file) attribute */
3515 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3516 if (lattr == SMB_ATTR_NORMAL)
3517 lattr = SMB_ATTR_HIDDEN;
3519 lattr |= SMB_ATTR_HIDDEN;
3521 *dptr++ = attr & 0xff;
3522 *dptr++ = (attr >> 8) & 0xff;
3525 lock_ReleaseMutex(&scp->mx);
3526 cm_ReleaseSCache(scp);
3529 /* now free the patches */
3530 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3531 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3535 /* and mark the list as empty */
3536 *dirPatchespp = NULL;
3541 #ifndef USE_OLD_MATCHING
3542 // char table for case insensitive comparison
3543 char mapCaseTable[256];
3545 VOID initUpperCaseTable(VOID)
3548 for (i = 0; i < 256; ++i)
3549 mapCaseTable[i] = toupper(i);
3550 // make '"' match '.'
3551 mapCaseTable[(int)'"'] = toupper('.');
3552 // make '<' match '*'
3553 mapCaseTable[(int)'<'] = toupper('*');
3554 // make '>' match '?'
3555 mapCaseTable[(int)'>'] = toupper('?');
3558 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3560 // Note : this procedure works recursively calling itself.
3562 // PSZ pattern : string containing metacharacters.
3563 // PSZ name : file name to be compared with 'pattern'.
3565 // BOOL : TRUE/FALSE (match/mistmatch)
3568 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
3570 PSZ pename; // points to the last 'name' character
3572 pename = name + strlen(name) - 1;
3583 if (*pattern == '\0')
3585 for (p = pename; p >= name; --p) {
3586 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
3587 !casefold && (*p == *pattern)) &&
3588 szWildCardMatchFileName(pattern + 1, p + 1, casefold))
3593 if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
3594 (!casefold && *name != *pattern))
3601 /* if all we have left are wildcards, then we match */
3602 for (;*pattern; pattern++) {
3603 if (*pattern != '*' && *pattern != '?')
3609 /* do a case-folding search of the star name mask with the name in namep.
3610 * Return 1 if we match, otherwise 0.
3612 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3615 int i, j, star, qmark, casefold, retval;
3617 /* make sure we only match 8.3 names, if requested */
3618 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3621 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
3623 /* optimize the pattern:
3624 * if there is a mixture of '?' and '*',
3625 * for example the sequence "*?*?*?*"
3626 * must be turned into the form "*"
3628 newmask = (char *)malloc(strlen(maskp)+1);
3629 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3630 switch ( maskp[i] ) {
3642 } else if ( qmark ) {
3646 newmask[j++] = maskp[i];
3653 } else if ( qmark ) {
3657 newmask[j++] = '\0';
3659 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
3665 #else /* USE_OLD_MATCHING */
3666 /* do a case-folding search of the star name mask with the name in namep.
3667 * Return 1 if we match, otherwise 0.
3669 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3671 unsigned char tcp1, tcp2; /* Pattern characters */
3672 unsigned char tcn1; /* Name characters */
3673 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3674 char *starNamep, *starMaskp;
3675 static char nullCharp[] = {0};
3676 int casefold = flags & CM_FLAG_CASEFOLD;
3678 /* make sure we only match 8.3 names, if requested */
3679 req8dot3 = (flags & CM_FLAG_8DOT3);
3680 if (req8dot3 && !cm_Is8Dot3(namep))
3685 /* Next pattern character */
3688 /* Next name character */
3692 /* 0 - end of pattern */
3698 else if (tcp1 == '.' || tcp1 == '"') {
3708 * first dot in pattern;
3709 * must match dot or end of name
3714 else if (tcn1 == '.') {
3723 else if (tcp1 == '?') {
3724 if (tcn1 == 0 || tcn1 == '.')
3729 else if (tcp1 == '>') {
3730 if (tcn1 != 0 && tcn1 != '.')
3734 else if (tcp1 == '*' || tcp1 == '<') {
3738 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3739 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3754 * pattern character after '*' is not null or
3755 * period. If it is '?' or '>', we are not
3756 * going to understand it. If it is '*' or
3757 * '<', we are going to skip over it. None of
3758 * these are likely, I hope.
3760 /* skip over '*' and '<' */
3761 while (tcp2 == '*' || tcp2 == '<')
3764 /* skip over characters that don't match tcp2 */
3765 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
3766 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
3767 (!casefold && tcn1 != tcp2)))
3771 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3774 /* Remember where we are */
3784 /* tcp1 is not a wildcard */
3785 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
3786 (!casefold && tcn1 == tcp1)) {
3791 /* if trying to match a star pattern, go back */
3793 maskp = starMaskp - 2;
3794 namep = starNamep + 1;
3803 #endif /* USE_OLD_MATCHING */
3805 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3810 long code = 0, code2 = 0;
3814 smb_dirListPatch_t *dirListPatchesp;
3815 smb_dirListPatch_t *curPatchp;
3818 long orbytes; /* # of bytes in this output record */
3819 long ohbytes; /* # of bytes, except file name */
3820 long onbytes; /* # of bytes in name, incl. term. null */
3821 osi_hyper_t dirLength;
3822 osi_hyper_t bufferOffset;
3823 osi_hyper_t curOffset;
3825 smb_dirSearch_t *dsp;
3829 cm_pageHeader_t *pageHeaderp;
3830 cm_user_t *userp = NULL;
3833 long nextEntryCookie;
3834 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3835 char *op; /* output data ptr */
3836 char *origOp; /* original value of op */
3837 cm_space_t *spacep; /* for pathname buffer */
3838 long maxReturnData; /* max # of return data */
3839 long maxReturnParms; /* max # of return parms */
3840 long bytesInBuffer; /* # data bytes in the output buffer */
3842 char *maskp; /* mask part of path */
3846 smb_tran2Packet_t *outp; /* response packet */
3849 char shortName[13]; /* 8.3 name if needed */
3860 if (p->opcode == 1) {
3861 /* find first; obtain basic parameters from request */
3862 attribute = p->parmsp[0];
3863 maxCount = p->parmsp[1];
3864 infoLevel = p->parmsp[3];
3865 searchFlags = p->parmsp[2];
3866 dsp = smb_NewDirSearch(1);
3867 dsp->attribute = attribute;
3868 pathp = ((char *) p->parmsp) + 12; /* points to path */
3869 if (smb_StoreAnsiFilenames)
3870 OemToChar(pathp,pathp);
3872 maskp = strrchr(pathp, '\\');
3876 maskp++; /* skip over backslash */
3877 strcpy(dsp->mask, maskp); /* and save mask */
3878 /* track if this is likely to match a lot of entries */
3879 starPattern = smb_V3IsStarMask(maskp);
3882 osi_assert(p->opcode == 2);
3883 /* find next; obtain basic parameters from request or open dir file */
3884 dsp = smb_FindDirSearch(p->parmsp[0]);
3885 maxCount = p->parmsp[1];
3886 infoLevel = p->parmsp[2];
3887 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
3888 searchFlags = p->parmsp[5];
3890 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
3891 p->parmsp[0], nextCookie);
3892 return CM_ERROR_BADFD;
3894 attribute = dsp->attribute;
3897 starPattern = 1; /* assume, since required a Find Next */
3901 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
3902 attribute, infoLevel, maxCount, searchFlags);
3904 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
3905 p->opcode, dsp->cookie, nextCookie);
3907 if (infoLevel >= 0x101)
3908 searchFlags &= ~4; /* no resume keys */
3910 dirListPatchesp = NULL;
3912 maxReturnData = p->maxReturnData;
3913 if (p->opcode == 1) /* find first */
3914 maxReturnParms = 10; /* bytes */
3916 maxReturnParms = 8; /* bytes */
3918 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
3919 if (maxReturnData > 6000)
3920 maxReturnData = 6000;
3921 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
3923 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
3926 osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
3927 maxCount, osi_LogSaveString(smb_logp, pathp));
3929 /* bail out if request looks bad */
3930 if (p->opcode == 1 && !pathp) {
3931 smb_ReleaseDirSearch(dsp);
3932 smb_FreeTran2Packet(outp);
3933 return CM_ERROR_BADSMB;
3936 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
3937 dsp->cookie, nextCookie, attribute);
3939 userp = smb_GetTran2User(vcp, p);
3941 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
3942 smb_ReleaseDirSearch(dsp);
3943 smb_FreeTran2Packet(outp);
3944 return CM_ERROR_BADSMB;
3947 /* try to get the vnode for the path name next */
3948 lock_ObtainMutex(&dsp->mx);
3954 spacep = cm_GetSpace();
3955 smb_StripLastComponent(spacep->data, NULL, pathp);
3956 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3958 cm_ReleaseUser(userp);
3959 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
3960 smb_FreeTran2Packet(outp);
3961 lock_ReleaseMutex(&dsp->mx);
3962 smb_DeleteDirSearch(dsp);
3963 smb_ReleaseDirSearch(dsp);
3966 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3967 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3968 userp, tidPathp, &req, &scp);
3969 cm_FreeSpace(spacep);
3972 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
3973 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3974 cm_ReleaseSCache(scp);
3975 cm_ReleaseUser(userp);
3976 if ( WANTS_DFS_PATHNAMES(p) )
3977 code = CM_ERROR_PATH_NOT_COVERED;
3979 code = CM_ERROR_BADSHARENAME;
3980 smb_SendTran2Error(vcp, p, opx, code);
3981 smb_FreeTran2Packet(outp);
3982 lock_ReleaseMutex(&dsp->mx);
3983 smb_DeleteDirSearch(dsp);
3984 smb_ReleaseDirSearch(dsp);
3987 #endif /* DFS_SUPPORT */
3989 /* we need one hold for the entry we just stored into,
3990 * and one for our own processing. When we're done
3991 * with this function, we'll drop the one for our own
3992 * processing. We held it once from the namei call,
3993 * and so we do another hold now.
3996 lock_ObtainMutex(&scp->mx);
3997 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
3998 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3999 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4000 dsp->flags |= SMB_DIRSEARCH_BULKST;
4002 lock_ReleaseMutex(&scp->mx);
4005 lock_ReleaseMutex(&dsp->mx);
4007 cm_ReleaseUser(userp);
4008 smb_FreeTran2Packet(outp);
4009 smb_DeleteDirSearch(dsp);
4010 smb_ReleaseDirSearch(dsp);
4014 /* get the directory size */
4015 lock_ObtainMutex(&scp->mx);
4016 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4017 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4019 lock_ReleaseMutex(&scp->mx);
4020 cm_ReleaseSCache(scp);
4021 cm_ReleaseUser(userp);
4022 smb_FreeTran2Packet(outp);
4023 smb_DeleteDirSearch(dsp);
4024 smb_ReleaseDirSearch(dsp);
4029 dirLength = scp->length;
4031 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4032 curOffset.HighPart = 0;
4033 curOffset.LowPart = nextCookie;
4034 origOp = outp->datap;
4042 if (searchFlags & 4)
4043 /* skip over resume key */
4046 /* make sure that curOffset.LowPart doesn't point to the first
4047 * 32 bytes in the 2nd through last dir page, and that it doesn't
4048 * point at the first 13 32-byte chunks in the first dir page,
4049 * since those are dir and page headers, and don't contain useful
4052 temp = curOffset.LowPart & (2048-1);
4053 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4054 /* we're in the first page */
4055 if (temp < 13*32) temp = 13*32;
4058 /* we're in a later dir page */
4059 if (temp < 32) temp = 32;
4062 /* make sure the low order 5 bits are zero */
4065 /* now put temp bits back ito curOffset.LowPart */
4066 curOffset.LowPart &= ~(2048-1);
4067 curOffset.LowPart |= temp;
4069 /* check if we've passed the dir's EOF */
4070 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4071 osi_Log0(smb_logp, "T2 search dir passed eof");
4076 /* check if we've returned all the names that will fit in the
4077 * response packet; we check return count as well as the number
4078 * of bytes requested. We check the # of bytes after we find
4079 * the dir entry, since we'll need to check its size.
4081 if (returnedNames >= maxCount) {
4082 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4083 returnedNames, maxCount);
4087 /* see if we can use the bufferp we have now; compute in which
4088 * page the current offset would be, and check whether that's
4089 * the offset of the buffer we have. If not, get the buffer.
4091 thyper.HighPart = curOffset.HighPart;
4092 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4093 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4096 buf_Release(bufferp);
4099 lock_ReleaseMutex(&scp->mx);
4100 lock_ObtainRead(&scp->bufCreateLock);
4101 code = buf_Get(scp, &thyper, &bufferp);
4102 lock_ReleaseRead(&scp->bufCreateLock);
4103 lock_ObtainMutex(&dsp->mx);
4105 /* now, if we're doing a star match, do bulk fetching
4106 * of all of the status info for files in the dir.
4109 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
4112 lock_ObtainMutex(&scp->mx);
4113 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4114 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
4115 /* Don't bulk stat if risking timeout */
4116 int now = GetTickCount();
4117 if (now - req.startTime > 5000) {
4118 scp->bulkStatProgress = thyper;
4119 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4120 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4122 cm_TryBulkStat(scp, &thyper, userp, &req);
4125 lock_ObtainMutex(&scp->mx);
4127 lock_ReleaseMutex(&dsp->mx);
4129 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
4133 bufferOffset = thyper;
4135 /* now get the data in the cache */
4137 code = cm_SyncOp(scp, bufferp, userp, &req,
4139 CM_SCACHESYNC_NEEDCALLBACK
4140 | CM_SCACHESYNC_READ);
4142 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
4146 if (cm_HaveBuffer(scp, bufferp, 0)) {
4147 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4151 /* otherwise, load the buffer and try again */
4152 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4155 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4156 scp, bufferp, code);
4161 buf_Release(bufferp);
4165 } /* if (wrong buffer) ... */
4167 /* now we have the buffer containing the entry we're interested
4168 * in; copy it out if it represents a non-deleted entry.
4170 entryInDir = curOffset.LowPart & (2048-1);
4171 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4173 /* page header will help tell us which entries are free. Page
4174 * header can change more often than once per buffer, since
4175 * AFS 3 dir page size may be less than (but not more than)
4176 * a buffer package buffer.
4178 /* only look intra-buffer */
4179 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4180 temp &= ~(2048 - 1); /* turn off intra-page bits */
4181 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4183 /* now determine which entry we're looking at in the page.
4184 * If it is free (there's a free bitmap at the start of the
4185 * dir), we should skip these 32 bytes.
4187 slotInPage = (entryInDir & 0x7e0) >> 5;
4188 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
4189 (1 << (slotInPage & 0x7)))) {
4190 /* this entry is free */
4191 numDirChunks = 1; /* only skip this guy */
4195 tp = bufferp->datap + entryInBuffer;
4196 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4198 /* while we're here, compute the next entry's location, too,
4199 * since we'll need it when writing out the cookie into the dir
4202 * XXXX Probably should do more sanity checking.
4204 numDirChunks = cm_NameEntries(dep->name, &onbytes);
4206 /* compute offset of cookie representing next entry */
4207 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4209 /* Need 8.3 name? */
4211 if (infoLevel == SMB_QUERY_FILE_NAME_INFO
4212 && dep->fid.vnode != 0
4213 && !cm_Is8Dot3(dep->name)) {
4214 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4218 osi_Log3(smb_logp, "T2 search dir vn %u name %s (%s)",
4219 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4220 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4222 /* When matching, we are using doing a case fold if we have a wildcard mask.
4223 * If we get a non-wildcard match, it's a lookup for a specific file.
4225 if (dep->fid.vnode != 0 &&
4226 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
4228 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
4230 /* Eliminate entries that don't match requested attributes */
4231 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
4232 smb_IsDotFile(dep->name)) {
4233 osi_Log0(smb_logp, "T2 search dir skipping hidden");
4234 goto nextEntry; /* no hidden files */
4236 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4238 /* We have already done the cm_TryBulkStat above */
4239 fid.cell = scp->fid.cell;
4240 fid.volume = scp->fid.volume;
4241 fid.vnode = ntohl(dep->fid.vnode);
4242 fid.unique = ntohl(dep->fid.unique);
4243 fileType = cm_FindFileType(&fid);
4244 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
4245 "has filetype %d", dep->name,
4247 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4248 fileType == CM_SCACHETYPE_DFSLINK ||
4249 fileType == CM_SCACHETYPE_INVALID)
4250 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
4254 /* finally check if this name will fit */
4256 /* standard dir entry stuff */
4257 if (infoLevel < 0x101)
4258 ohbytes = 23; /* pre-NT */
4259 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
4260 ohbytes = 12; /* NT names only */
4262 ohbytes = 64; /* NT */
4264 if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
4265 ohbytes += 26; /* Short name & length */
4267 if (searchFlags & 4) {
4268 ohbytes += 4; /* if resume key required */
4272 && infoLevel != 0x101
4273 && infoLevel != 0x103)
4274 ohbytes += 4; /* EASIZE */
4276 /* add header to name & term. null */
4277 orbytes = onbytes + ohbytes + 1;
4279 /* now, we round up the record to a 4 byte alignment,
4280 * and we make sure that we have enough room here for
4281 * even the aligned version (so we don't have to worry
4282 * about an * overflow when we pad things out below).
4283 * That's the reason for the alignment arithmetic below.
4285 if (infoLevel >= 0x101)
4286 align = (4 - (orbytes & 3)) & 3;
4289 if (orbytes + bytesInBuffer + align > maxReturnData) {
4290 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4295 /* this is one of the entries to use: it is not deleted
4296 * and it matches the star pattern we're looking for.
4297 * Put out the name, preceded by its length.
4299 /* First zero everything else */
4300 memset(origOp, 0, ohbytes);
4302 if (infoLevel <= 0x101)
4303 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4304 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
4305 *((u_long *)(op + 8)) = onbytes;
4307 *((u_long *)(op + 60)) = onbytes;
4308 strcpy(origOp+ohbytes, dep->name);
4309 if (smb_StoreAnsiFilenames)
4310 CharToOem(origOp+ohbytes, origOp+ohbytes);
4312 /* Short name if requested and needed */
4313 if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
4314 if (NeedShortName) {
4315 strcpy(op + 70, shortName);
4316 if (smb_StoreAnsiFilenames)
4317 CharToOem(op + 70, op + 70);
4318 *(op + 68) = (char)(shortNameEnd - shortName);
4322 /* now, adjust the # of entries copied */
4325 /* NextEntryOffset and FileIndex */
4326 if (infoLevel >= 101) {
4327 int entryOffset = orbytes + align;
4328 *((u_long *)op) = entryOffset;
4329 *((u_long *)(op+4)) = nextEntryCookie;
4332 /* now we emit the attribute. This is tricky, since
4333 * we need to really stat the file to find out what
4334 * type of entry we've got. Right now, we're copying
4335 * out data from a buffer, while holding the scp
4336 * locked, so it isn't really convenient to stat
4337 * something now. We'll put in a place holder
4338 * now, and make a second pass before returning this
4339 * to get the real attributes. So, we just skip the
4340 * data for now, and adjust it later. We allocate a
4341 * patch record to make it easy to find this point
4342 * later. The replay will happen at a time when it is
4343 * safe to unlock the directory.
4345 if (infoLevel != 0x103) {
4346 curPatchp = malloc(sizeof(*curPatchp));
4347 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4349 curPatchp->dptr = op;
4350 if (infoLevel >= 0x101)
4351 curPatchp->dptr += 8;
4353 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4354 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4357 curPatchp->flags = 0;
4359 curPatchp->fid.cell = scp->fid.cell;
4360 curPatchp->fid.volume = scp->fid.volume;
4361 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4362 curPatchp->fid.unique = ntohl(dep->fid.unique);
4365 curPatchp->dep = dep;
4368 if (searchFlags & 4)
4369 /* put out resume key */
4370 *((u_long *)origOp) = nextEntryCookie;
4372 /* Adjust byte ptr and count */
4373 origOp += orbytes; /* skip entire record */
4374 bytesInBuffer += orbytes;
4376 /* and pad the record out */
4377 while (--align >= 0) {
4381 } /* if we're including this name */
4382 else if (!starPattern &&
4384 dep->fid.vnode != 0 &&
4385 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4386 /* We were looking for exact matches, but here's an inexact one*/
4391 /* and adjust curOffset to be where the new cookie is */
4392 thyper.HighPart = 0;
4393 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4394 curOffset = LargeIntegerAdd(thyper, curOffset);
4395 } /* while copying data for dir listing */
4397 /* If we didn't get a star pattern, we did an exact match during the first pass.
4398 * If there were no exact matches found, we fail over to inexact matches by
4399 * marking the query as a star pattern (matches all case permutations), and
4400 * re-running the query.
4402 if (returnedNames == 0 && !starPattern && foundInexact) {
4403 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4408 /* release the mutex */
4409 lock_ReleaseMutex(&scp->mx);
4411 buf_Release(bufferp);
4413 /* apply and free last set of patches; if not doing a star match, this
4414 * will be empty, but better safe (and freeing everything) than sorry.
4416 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4419 /* now put out the final parameters */
4420 if (returnedNames == 0)
4422 if (p->opcode == 1) {
4424 outp->parmsp[0] = (unsigned short) dsp->cookie;
4425 outp->parmsp[1] = returnedNames;
4426 outp->parmsp[2] = eos;
4427 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4428 outp->parmsp[4] = 0;
4429 /* don't need last name to continue
4430 * search, cookie is enough. Normally,
4431 * this is the offset of the file name
4432 * of the last entry returned.
4434 outp->totalParms = 10; /* in bytes */
4438 outp->parmsp[0] = returnedNames;
4439 outp->parmsp[1] = eos;
4440 outp->parmsp[2] = 0; /* EAS error */
4441 outp->parmsp[3] = 0; /* last name, as above */
4442 outp->totalParms = 8; /* in bytes */
4445 /* return # of bytes in the buffer */
4446 outp->totalData = bytesInBuffer;
4448 /* Return error code if unsuccessful on first request */
4449 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4450 code = CM_ERROR_NOSUCHFILE;
4452 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
4453 p->opcode, dsp->cookie, returnedNames, code);
4455 /* if we're supposed to close the search after this request, or if
4456 * we're supposed to close the search if we're done, and we're done,
4457 * or if something went wrong, close the search.
4459 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4460 if ((searchFlags & 1) || (returnedNames == 0) ||
4461 ((searchFlags & 2) && eos) || code != 0)
4462 smb_DeleteDirSearch(dsp);
4464 smb_SendTran2Error(vcp, p, opx, code);
4466 smb_SendTran2Packet(vcp, outp, opx);
4468 smb_FreeTran2Packet(outp);
4469 smb_ReleaseDirSearch(dsp);
4470 cm_ReleaseSCache(scp);
4471 cm_ReleaseUser(userp);
4475 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4478 smb_dirSearch_t *dsp;
4480 dirHandle = smb_GetSMBParm(inp, 0);
4482 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4484 dsp = smb_FindDirSearch(dirHandle);
4487 return CM_ERROR_BADFD;
4489 /* otherwise, we have an FD to destroy */
4490 smb_DeleteDirSearch(dsp);
4491 smb_ReleaseDirSearch(dsp);
4493 /* and return results */
4494 smb_SetSMBDataLength(outp, 0);
4499 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4501 smb_SetSMBDataLength(outp, 0);
4505 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4512 cm_scache_t *dscp; /* dir we're dealing with */
4513 cm_scache_t *scp; /* file we're creating */
4515 int initialModeBits;
4525 int parmSlot; /* which parm we're dealing with */
4534 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4535 openFun = smb_GetSMBParm(inp, 8); /* open function */
4536 excl = ((openFun & 3) == 0);
4537 trunc = ((openFun & 3) == 2); /* truncate it */
4538 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4539 openAction = 0; /* tracks what we did */
4541 attributes = smb_GetSMBParm(inp, 5);
4542 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4544 /* compute initial mode bits based on read-only flag in attributes */
4545 initialModeBits = 0666;
4546 if (attributes & 1) initialModeBits &= ~0222;
4548 pathp = smb_GetSMBData(inp, NULL);
4549 if (smb_StoreAnsiFilenames)
4550 OemToChar(pathp,pathp);
4552 spacep = inp->spacep;
4553 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4555 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4556 /* special case magic file name for receiving IOCTL requests
4557 * (since IOCTL calls themselves aren't getting through).
4560 osi_Log0(smb_logp, "IOCTL Open");
4563 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4564 smb_SetupIoctlFid(fidp, spacep);
4566 /* set inp->fid so that later read calls in same msg can find fid */
4567 inp->fid = fidp->fid;
4569 /* copy out remainder of the parms */
4571 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4573 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4574 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4575 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4576 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4577 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4578 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4579 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4580 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4582 /* and the final "always present" stuff */
4583 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4584 /* next write out the "unique" ID */
4585 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4586 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4587 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4588 smb_SetSMBDataLength(outp, 0);
4590 /* and clean up fid reference */
4591 smb_ReleaseFID(fidp);
4595 #ifdef DEBUG_VERBOSE
4597 char *hexp, *asciip;
4598 asciip = (lastNamep ? lastNamep : pathp );
4599 hexp = osi_HexifyString(asciip);
4600 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4604 userp = smb_GetUserFromVCP(vcp, inp);
4607 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4609 cm_ReleaseUser(userp);
4610 return CM_ERROR_NOSUCHPATH;
4612 code = cm_NameI(cm_data.rootSCachep, pathp,
4613 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4614 userp, tidPathp, &req, &scp);
4617 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4618 cm_ReleaseSCache(scp);
4619 cm_ReleaseUser(userp);
4620 if ( WANTS_DFS_PATHNAMES(inp) )
4621 return CM_ERROR_PATH_NOT_COVERED;
4623 return CM_ERROR_BADSHARENAME;
4625 #endif /* DFS_SUPPORT */
4628 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4629 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4630 userp, tidPathp, &req, &dscp);
4632 cm_ReleaseUser(userp);
4637 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4638 cm_ReleaseSCache(dscp);
4639 cm_ReleaseUser(userp);
4640 if ( WANTS_DFS_PATHNAMES(inp) )
4641 return CM_ERROR_PATH_NOT_COVERED;
4643 return CM_ERROR_BADSHARENAME;
4645 #endif /* DFS_SUPPORT */
4647 /* otherwise, scp points to the parent directory. Do a lookup,
4648 * and truncate the file if we find it, otherwise we create the
4655 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
4657 if (code && code != CM_ERROR_NOSUCHFILE) {
4658 cm_ReleaseSCache(dscp);
4659 cm_ReleaseUser(userp);
4664 /* if we get here, if code is 0, the file exists and is represented by
4665 * scp. Otherwise, we have to create it. The dir may be represented
4666 * by dscp, or we may have found the file directly. If code is non-zero,
4670 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
4672 if (dscp) cm_ReleaseSCache(dscp);
4673 cm_ReleaseSCache(scp);
4674 cm_ReleaseUser(userp);
4679 /* oops, file shouldn't be there */
4681 cm_ReleaseSCache(dscp);
4682 cm_ReleaseSCache(scp);
4683 cm_ReleaseUser(userp);
4684 return CM_ERROR_EXISTS;
4688 setAttr.mask = CM_ATTRMASK_LENGTH;
4689 setAttr.length.LowPart = 0;
4690 setAttr.length.HighPart = 0;
4691 code = cm_SetAttr(scp, &setAttr, userp, &req);
4692 openAction = 3; /* truncated existing file */
4694 else openAction = 1; /* found existing file */
4696 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
4697 /* don't create if not found */
4698 if (dscp) cm_ReleaseSCache(dscp);
4699 cm_ReleaseUser(userp);
4700 return CM_ERROR_NOSUCHFILE;
4703 osi_assert(dscp != NULL);
4704 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
4705 osi_LogSaveString(smb_logp, lastNamep));
4706 openAction = 2; /* created file */
4707 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4708 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
4709 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4713 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
4714 smb_NotifyChange(FILE_ACTION_ADDED,
4715 FILE_NOTIFY_CHANGE_FILE_NAME,
4716 dscp, lastNamep, NULL, TRUE);
4717 } else if (!excl && code == CM_ERROR_EXISTS) {
4718 /* not an exclusive create, and someone else tried
4719 * creating it already, then we open it anyway. We
4720 * don't bother retrying after this, since if this next
4721 * fails, that means that the file was deleted after we
4722 * started this call.
4724 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4728 setAttr.mask = CM_ATTRMASK_LENGTH;
4729 setAttr.length.LowPart = 0;
4730 setAttr.length.HighPart = 0;
4731 code = cm_SetAttr(scp, &setAttr, userp, &req);
4733 } /* lookup succeeded */
4737 /* we don't need this any longer */
4739 cm_ReleaseSCache(dscp);
4742 /* something went wrong creating or truncating the file */
4744 cm_ReleaseSCache(scp);
4745 cm_ReleaseUser(userp);
4749 /* make sure we're about to open a file */
4750 if (scp->fileType != CM_SCACHETYPE_FILE) {
4751 cm_ReleaseSCache(scp);
4752 cm_ReleaseUser(userp);
4753 return CM_ERROR_ISDIR;
4756 /* now all we have to do is open the file itself */
4757 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4761 lock_ObtainMutex(&fidp->mx);
4762 /* save a pointer to the vnode */
4765 fidp->userp = userp;
4767 /* compute open mode */
4769 fidp->flags |= SMB_FID_OPENREAD;
4770 if (openMode == 1 || openMode == 2)
4771 fidp->flags |= SMB_FID_OPENWRITE;
4773 /* remember if the file was newly created */
4775 fidp->flags |= SMB_FID_CREATED;
4777 lock_ReleaseMutex(&fidp->mx);
4778 smb_ReleaseFID(fidp);
4780 cm_Open(scp, 0, userp);
4782 /* set inp->fid so that later read calls in same msg can find fid */
4783 inp->fid = fidp->fid;
4785 /* copy out remainder of the parms */
4787 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4788 lock_ObtainMutex(&scp->mx);
4790 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
4791 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4792 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
4793 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
4794 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
4795 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
4796 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4797 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4798 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4800 /* and the final "always present" stuff */
4801 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
4802 /* next write out the "unique" ID */
4803 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
4804 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
4805 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4806 lock_ReleaseMutex(&scp->mx);
4807 smb_SetSMBDataLength(outp, 0);
4809 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
4811 cm_ReleaseUser(userp);
4812 /* leave scp held since we put it in fidp->scp */
4816 static void smb_GetLockParams(unsigned char LockType,
4818 unsigned int * ppid,
4819 LARGE_INTEGER * pOffset,
4820 LARGE_INTEGER * pLength)
4822 if (LockType & LOCKING_ANDX_LARGE_FILES) {
4824 *ppid = *((USHORT *) *buf);
4825 pOffset->HighPart = *((LONG *)(*buf + 4));
4826 pOffset->LowPart = *((DWORD *)(*buf + 8));
4827 pLength->HighPart = *((LONG *)(*buf + 12));
4828 pLength->LowPart = *((DWORD *)(*buf + 16));
4832 /* Not Large Files */
4833 *ppid = *((USHORT *) *buf);
4834 pOffset->HighPart = 0;
4835 pOffset->LowPart = *((DWORD *)(*buf + 2));
4836 pLength->HighPart = 0;
4837 pLength->LowPart = *((DWORD *)(*buf + 6));
4842 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4849 unsigned char LockType;
4850 unsigned short NumberOfUnlocks, NumberOfLocks;
4854 LARGE_INTEGER LOffset, LLength;
4855 smb_waitingLockRequest_t *wlRequest = NULL;
4856 cm_file_lock_t *lockp;
4864 fid = smb_GetSMBParm(inp, 2);
4865 fid = smb_ChainFID(fid, inp);
4867 fidp = smb_FindFID(vcp, fid, 0);
4869 return CM_ERROR_BADFD;
4871 lock_ObtainMutex(&fidp->mx);
4872 if (fidp->flags & SMB_FID_IOCTL) {
4873 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
4874 lock_ReleaseMutex(&fidp->mx);
4875 smb_ReleaseFID(fidp);
4876 return CM_ERROR_BADFD;
4878 lock_ReleaseMutex(&fidp->mx);
4880 /* set inp->fid so that later read calls in same msg can find fid */
4883 userp = smb_GetUserFromVCP(vcp, inp);
4887 lock_ObtainMutex(&scp->mx);
4888 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4889 CM_SCACHESYNC_NEEDCALLBACK
4890 | CM_SCACHESYNC_GETSTATUS
4891 | CM_SCACHESYNC_LOCK);
4893 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
4897 LockType = smb_GetSMBParm(inp, 3) & 0xff;
4898 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
4899 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
4900 NumberOfLocks = smb_GetSMBParm(inp, 7);
4902 if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
4903 (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
4905 /* We don't support these requests. Apparently, we can safely
4906 not deal with them too. */
4907 osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
4908 ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
4909 "LOCKING_ANDX_CANCEL_LOCK":
4910 "LOCKING_ANDX_CHANGE_LOCKTYPE"));
4911 /* No need to call osi_LogSaveString since these are string
4914 code = CM_ERROR_BADOP;
4919 op = smb_GetSMBData(inp, NULL);
4921 for (i=0; i<NumberOfUnlocks; i++) {
4922 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
4924 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
4926 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
4934 for (i=0; i<NumberOfLocks; i++) {
4935 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
4937 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
4939 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
4940 userp, &req, &lockp);
4942 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
4943 smb_waitingLock_t * wLock;
4945 /* Put on waiting list */
4946 if(wlRequest == NULL) {
4950 LARGE_INTEGER tOffset, tLength;
4952 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
4954 osi_assert(wlRequest != NULL);
4956 wlRequest->vcp = vcp;
4958 wlRequest->scp = scp;
4960 wlRequest->inp = smb_CopyPacket(inp);
4961 wlRequest->outp = smb_CopyPacket(outp);
4962 wlRequest->lockType = LockType;
4963 wlRequest->timeRemaining = Timeout;
4964 wlRequest->locks = NULL;
4966 /* The waiting lock request needs to have enough
4967 information to undo all the locks in the request.
4968 We do the following to store info about locks that
4969 have already been granted. Sure, we can get most
4970 of the info from the packet, but the packet doesn't
4971 hold the result of cm_Lock call. In practice we
4972 only receive packets with one or two locks, so we
4973 are only wasting a few bytes here and there and
4974 only for a limited period of time until the waiting
4975 lock times out or is freed. */
4977 for(opt = op_locks, j=i; j > 0; j--) {
4978 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
4980 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
4982 wLock = malloc(sizeof(smb_waitingLock_t));
4984 osi_assert(wLock != NULL);
4987 wLock->LOffset = tOffset;
4988 wLock->LLength = tLength;
4989 wLock->lockp = NULL;
4990 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
4991 osi_QAdd((osi_queue_t **) &wlRequest->locks,
4996 wLock = malloc(sizeof(smb_waitingLock_t));
4998 osi_assert(wLock != NULL);
5001 wLock->LOffset = LOffset;
5002 wLock->LLength = LLength;
5003 wLock->lockp = lockp;
5004 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
5005 osi_QAdd((osi_queue_t **) &wlRequest->locks,
5008 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
5016 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
5023 /* Since something went wrong with the lock number i, we now
5024 have to go ahead and release any locks acquired before the
5025 failure. All locks before lock number i (of which there
5026 are i of them) have either been successful or are waiting.
5027 Either case requires calling cm_Unlock(). */
5029 /* And purge the waiting lock */
5030 if(wlRequest != NULL) {
5031 smb_waitingLock_t * wl;
5032 smb_waitingLock_t * wlNext;
5035 for(wl = wlRequest->locks; wl; wl = wlNext) {
5037 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
5039 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
5042 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
5044 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
5047 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
5052 smb_ReleaseVC(wlRequest->vcp);
5053 cm_ReleaseSCache(wlRequest->scp);
5054 smb_FreePacket(wlRequest->inp);
5055 smb_FreePacket(wlRequest->outp);
5064 if (wlRequest != NULL) {
5066 lock_ObtainWrite(&smb_globalLock);
5067 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
5069 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
5070 lock_ReleaseWrite(&smb_globalLock);
5072 /* don't send reply immediately */
5073 outp->flags |= SMB_PACKETFLAG_NOSEND;
5076 smb_SetSMBDataLength(outp, 0);
5080 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5083 lock_ReleaseMutex(&scp->mx);
5084 cm_ReleaseUser(userp);
5085 smb_ReleaseFID(fidp);
5090 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5096 afs_uint32 searchTime;
5102 fid = smb_GetSMBParm(inp, 0);
5103 fid = smb_ChainFID(fid, inp);
5105 fidp = smb_FindFID(vcp, fid, 0);
5107 return CM_ERROR_BADFD;
5109 lock_ObtainMutex(&fidp->mx);
5110 if (fidp->flags & SMB_FID_IOCTL) {
5111 lock_ReleaseMutex(&fidp->mx);
5112 smb_ReleaseFID(fidp);
5113 return CM_ERROR_BADFD;
5115 lock_ReleaseMutex(&fidp->mx);
5117 userp = smb_GetUserFromVCP(vcp, inp);
5121 /* otherwise, stat the file */
5122 lock_ObtainMutex(&scp->mx);
5123 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5124 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5125 if (code) goto done;
5127 /* decode times. We need a search time, but the response to this
5128 * call provides the date first, not the time, as returned in the
5129 * searchTime variable. So we take the high-order bits first.
5131 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
5132 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
5133 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
5134 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
5135 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
5136 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
5137 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
5139 /* now handle file size and allocation size */
5140 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
5141 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
5142 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
5143 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
5145 /* file attribute */
5146 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
5148 /* and finalize stuff */
5149 smb_SetSMBDataLength(outp, 0);
5153 lock_ReleaseMutex(&scp->mx);
5154 cm_ReleaseUser(userp);
5155 smb_ReleaseFID(fidp);
5159 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5165 afs_uint32 searchTime;
5173 fid = smb_GetSMBParm(inp, 0);
5174 fid = smb_ChainFID(fid, inp);
5176 fidp = smb_FindFID(vcp, fid, 0);
5178 return CM_ERROR_BADFD;
5180 lock_ObtainMutex(&fidp->mx);
5181 if (fidp->flags & SMB_FID_IOCTL) {
5182 lock_ReleaseMutex(&fidp->mx);
5183 smb_ReleaseFID(fidp);
5184 return CM_ERROR_BADFD;
5186 lock_ReleaseMutex(&fidp->mx);
5188 userp = smb_GetUserFromVCP(vcp, inp);
5192 /* now prepare to call cm_setattr. This message only sets various times,
5193 * and AFS only implements mtime, and we'll set the mtime if that's
5194 * requested. The others we'll ignore.
5196 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
5198 if (searchTime != 0) {
5199 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
5201 if ( unixTime != -1 ) {
5202 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
5203 attrs.clientModTime = unixTime;
5204 code = cm_SetAttr(scp, &attrs, userp, &req);
5206 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
5208 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
5213 cm_ReleaseUser(userp);
5214 smb_ReleaseFID(fidp);
5219 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5223 long finalCount = 0;
5232 fd = smb_GetSMBParm(inp, 2);
5233 count = smb_GetSMBParm(inp, 5);
5234 offset.HighPart = 0; /* too bad */
5235 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5237 osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
5238 fd, offset.LowPart, count);
5240 fd = smb_ChainFID(fd, inp);
5241 fidp = smb_FindFID(vcp, fd, 0);
5243 return CM_ERROR_BADFD;
5246 pid = ((smb_t *) inp)->pid;
5247 key = cm_GenerateKey(vcp->vcID, pid, fd);
5249 LARGE_INTEGER LOffset, LLength;
5251 LOffset.HighPart = offset.HighPart;
5252 LOffset.LowPart = offset.LowPart;
5253 LLength.HighPart = 0;
5254 LLength.LowPart = count;
5256 lock_ObtainMutex(&fidp->scp->mx);
5257 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
5258 lock_ReleaseMutex(&fidp->scp->mx);
5262 smb_ReleaseFID(fidp);
5266 /* set inp->fid so that later read calls in same msg can find fid */
5269 lock_ObtainMutex(&fidp->mx);
5270 if (fidp->flags & SMB_FID_IOCTL) {
5271 lock_ReleaseMutex(&fidp->mx);
5272 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
5273 smb_ReleaseFID(fidp);
5276 lock_ReleaseMutex(&fidp->mx);
5278 userp = smb_GetUserFromVCP(vcp, inp);
5280 /* 0 and 1 are reserved for request chaining, were setup by our caller,
5281 * and will be further filled in after we return.
5283 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
5284 smb_SetSMBParm(outp, 3, 0); /* resvd */
5285 smb_SetSMBParm(outp, 4, 0); /* resvd */
5286 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
5287 /* fill in #6 when we have all the parameters' space reserved */
5288 smb_SetSMBParm(outp, 7, 0); /* resv'd */
5289 smb_SetSMBParm(outp, 8, 0); /* resv'd */
5290 smb_SetSMBParm(outp, 9, 0); /* resv'd */
5291 smb_SetSMBParm(outp, 10, 0); /* resv'd */
5292 smb_SetSMBParm(outp, 11, 0); /* reserved */
5294 /* get op ptr after putting in the parms, since otherwise we don't
5295 * know where the data really is.
5297 op = smb_GetSMBData(outp, NULL);
5299 /* now fill in offset from start of SMB header to first data byte (to op) */
5300 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
5302 /* set the packet data length the count of the # of bytes */
5303 smb_SetSMBDataLength(outp, count);
5306 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5308 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5311 /* fix some things up */
5312 smb_SetSMBParm(outp, 5, finalCount);
5313 smb_SetSMBDataLength(outp, finalCount);
5315 smb_ReleaseFID(fidp);
5317 cm_ReleaseUser(userp);
5322 * Values for createDisp, copied from NTDDK.H
5324 #define FILE_SUPERSEDE 0 // (???)
5325 #define FILE_OPEN 1 // (open)
5326 #define FILE_CREATE 2 // (exclusive)
5327 #define FILE_OPEN_IF 3 // (non-exclusive)
5328 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
5329 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
5332 #define REQUEST_OPLOCK 2
5333 #define REQUEST_BATCH_OPLOCK 4
5334 #define OPEN_DIRECTORY 8
5335 #define EXTENDED_RESPONSE_REQUIRED 0x10
5337 /* CreateOptions field. */
5338 #define FILE_DIRECTORY_FILE 0x0001
5339 #define FILE_WRITE_THROUGH 0x0002
5340 #define FILE_SEQUENTIAL_ONLY 0x0004
5341 #define FILE_NON_DIRECTORY_FILE 0x0040
5342 #define FILE_NO_EA_KNOWLEDGE 0x0200
5343 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
5344 #define FILE_RANDOM_ACCESS 0x0800
5345 #define FILE_DELETE_ON_CLOSE 0x1000
5346 #define FILE_OPEN_BY_FILE_ID 0x2000
5348 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5350 char *pathp, *realPathp;
5354 cm_scache_t *dscp; /* parent dir */
5355 cm_scache_t *scp; /* file to create or open */
5356 cm_scache_t *targetScp; /* if scp is a symlink */
5360 unsigned short nameLength;
5362 unsigned int requestOpLock;
5363 unsigned int requestBatchOpLock;
5364 unsigned int mustBeDir;
5365 unsigned int extendedRespRequired;
5366 unsigned int treeCreate;
5368 unsigned int desiredAccess;
5369 unsigned int extAttributes;
5370 unsigned int createDisp;
5371 unsigned int createOptions;
5372 unsigned int shareAccess;
5373 int initialModeBits;
5374 unsigned short baseFid;
5375 smb_fid_t *baseFidp;
5377 cm_scache_t *baseDirp;
5378 unsigned short openAction;
5390 /* This code is very long and has a lot of if-then-else clauses
5391 * scp and dscp get reused frequently and we need to ensure that
5392 * we don't lose a reference. Start by ensuring that they are NULL.
5399 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
5400 flags = smb_GetSMBOffsetParm(inp, 3, 1)
5401 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
5402 requestOpLock = flags & REQUEST_OPLOCK;
5403 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
5404 mustBeDir = flags & OPEN_DIRECTORY;
5405 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
5408 * Why all of a sudden 32-bit FID?
5409 * We will reject all bits higher than 16.
5411 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
5412 return CM_ERROR_INVAL;
5413 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
5414 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
5415 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
5416 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
5417 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
5418 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
5419 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
5420 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
5421 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
5422 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
5423 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
5425 /* mustBeDir is never set; createOptions directory bit seems to be
5428 if (createOptions & FILE_DIRECTORY_FILE)
5430 else if (createOptions & FILE_NON_DIRECTORY_FILE)
5436 * compute initial mode bits based on read-only flag in
5437 * extended attributes
5439 initialModeBits = 0666;
5440 if (extAttributes & SMB_ATTR_READONLY)
5441 initialModeBits &= ~0222;
5443 pathp = smb_GetSMBData(inp, NULL);
5444 /* Sometimes path is not null-terminated, so we make a copy. */
5445 realPathp = malloc(nameLength+1);
5446 memcpy(realPathp, pathp, nameLength);
5447 realPathp[nameLength] = 0;
5448 if (smb_StoreAnsiFilenames)
5449 OemToChar(realPathp,realPathp);
5451 spacep = inp->spacep;
5452 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5454 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
5455 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
5456 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
5458 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5459 /* special case magic file name for receiving IOCTL requests
5460 * (since IOCTL calls themselves aren't getting through).
5462 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5463 smb_SetupIoctlFid(fidp, spacep);
5464 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
5466 /* set inp->fid so that later read calls in same msg can find fid */
5467 inp->fid = fidp->fid;
5471 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5472 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5473 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
5475 memset(&ft, 0, sizeof(ft));
5476 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5477 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5478 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5479 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5480 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
5481 sz.HighPart = 0x7fff; sz.LowPart = 0;
5482 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
5483 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
5484 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
5485 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
5486 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
5487 smb_SetSMBDataLength(outp, 0);
5489 /* clean up fid reference */
5490 smb_ReleaseFID(fidp);
5495 #ifdef DEBUG_VERBOSE
5497 char *hexp, *asciip;
5498 asciip = (lastNamep? lastNamep : realPathp);
5499 hexp = osi_HexifyString( asciip );
5500 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
5505 userp = smb_GetUserFromVCP(vcp, inp);
5507 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
5509 return CM_ERROR_INVAL;
5514 baseDirp = cm_data.rootSCachep;
5515 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5516 if (code == CM_ERROR_TIDIPC) {
5517 /* Attempt to use a TID allocated for IPC. The client
5518 * is probably looking for DCE RPC end points which we
5519 * don't support OR it could be looking to make a DFS
5522 osi_Log0(smb_logp, "NTCreateX received IPC TID");
5525 cm_ReleaseUser(userp);
5526 return CM_ERROR_NOSUCHFILE;
5527 #endif /* DFS_SUPPORT */
5530 baseFidp = smb_FindFID(vcp, baseFid, 0);
5532 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
5534 cm_ReleaseUser(userp);
5535 return CM_ERROR_INVAL;
5537 baseDirp = baseFidp->scp;
5541 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
5543 /* compute open mode */
5545 if (desiredAccess & DELETE)
5546 fidflags |= SMB_FID_OPENDELETE;
5547 if (desiredAccess & AFS_ACCESS_READ)
5548 fidflags |= SMB_FID_OPENREAD;
5549 if (desiredAccess & AFS_ACCESS_WRITE)
5550 fidflags |= SMB_FID_OPENWRITE;
5551 if (createOptions & FILE_DELETE_ON_CLOSE)
5552 fidflags |= SMB_FID_DELONCLOSE;
5554 /* and the share mode */
5555 if (shareAccess & FILE_SHARE_READ)
5556 fidflags |= SMB_FID_SHARE_READ;
5557 if (shareAccess & FILE_SHARE_WRITE)
5558 fidflags |= SMB_FID_SHARE_WRITE;
5560 osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
5563 /* For an exclusive create, we want to do a case sensitive match for the last component. */
5564 if ( createDisp == FILE_CREATE ||
5565 createDisp == FILE_OVERWRITE ||
5566 createDisp == FILE_OVERWRITE_IF) {
5567 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5568 userp, tidPathp, &req, &dscp);
5571 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5572 cm_ReleaseSCache(dscp);
5573 cm_ReleaseUser(userp);
5576 smb_ReleaseFID(baseFidp);
5577 if ( WANTS_DFS_PATHNAMES(inp) )
5578 return CM_ERROR_PATH_NOT_COVERED;
5580 return CM_ERROR_BADSHARENAME;
5582 #endif /* DFS_SUPPORT */
5583 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5585 if (code == CM_ERROR_NOSUCHFILE) {
5586 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
5587 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
5588 if (code == 0 && realDirFlag == 1) {
5589 cm_ReleaseSCache(scp);
5590 cm_ReleaseSCache(dscp);
5591 cm_ReleaseUser(userp);
5594 smb_ReleaseFID(baseFidp);
5595 return CM_ERROR_EXISTS;
5599 /* we have both scp and dscp */
5601 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5602 userp, tidPathp, &req, &scp);
5604 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5605 cm_ReleaseSCache(scp);
5606 cm_ReleaseUser(userp);
5609 smb_ReleaseFID(baseFidp);
5610 if ( WANTS_DFS_PATHNAMES(inp) )
5611 return CM_ERROR_PATH_NOT_COVERED;
5613 return CM_ERROR_BADSHARENAME;
5615 #endif /* DFS_SUPPORT */
5616 /* we might have scp but not dscp */
5622 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
5623 /* look up parent directory */
5624 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
5625 * the immediate parent. We have to work our way up realPathp until we hit something that we
5629 /* we might or might not have scp */
5635 code = cm_NameI(baseDirp, spacep->data,
5636 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5637 userp, tidPathp, &req, &dscp);
5640 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5642 cm_ReleaseSCache(scp);
5643 cm_ReleaseSCache(dscp);
5644 cm_ReleaseUser(userp);
5647 smb_ReleaseFID(baseFidp);
5648 if ( WANTS_DFS_PATHNAMES(inp) )
5649 return CM_ERROR_PATH_NOT_COVERED;
5651 return CM_ERROR_BADSHARENAME;
5653 #endif /* DFS_SUPPORT */
5656 (tp = strrchr(spacep->data,'\\')) &&
5657 (createDisp == FILE_CREATE) &&
5658 (realDirFlag == 1)) {
5661 treeStartp = realPathp + (tp - spacep->data);
5663 if (*tp && !smb_IsLegalFilename(tp)) {
5665 smb_ReleaseFID(baseFidp);
5666 cm_ReleaseUser(userp);
5669 cm_ReleaseSCache(scp);
5670 return CM_ERROR_BADNTFILENAME;
5674 } while (dscp == NULL && code == 0);
5678 /* we might have scp and we might have dscp */
5681 smb_ReleaseFID(baseFidp);
5684 osi_Log0(smb_logp,"NTCreateX parent not found");
5686 cm_ReleaseSCache(scp);
5688 cm_ReleaseSCache(dscp);
5689 cm_ReleaseUser(userp);
5694 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
5695 /* A file exists where we want a directory. */
5697 cm_ReleaseSCache(scp);
5698 cm_ReleaseSCache(dscp);
5699 cm_ReleaseUser(userp);
5701 return CM_ERROR_EXISTS;
5705 lastNamep = realPathp;
5709 if (!smb_IsLegalFilename(lastNamep)) {
5711 cm_ReleaseSCache(scp);
5713 cm_ReleaseSCache(dscp);
5714 cm_ReleaseUser(userp);
5716 return CM_ERROR_BADNTFILENAME;
5719 if (!foundscp && !treeCreate) {
5720 if ( createDisp == FILE_CREATE ||
5721 createDisp == FILE_OVERWRITE ||
5722 createDisp == FILE_OVERWRITE_IF)
5724 code = cm_Lookup(dscp, lastNamep,
5725 CM_FLAG_FOLLOW, userp, &req, &scp);
5727 code = cm_Lookup(dscp, lastNamep,
5728 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5731 if (code && code != CM_ERROR_NOSUCHFILE) {
5733 cm_ReleaseSCache(dscp);
5734 cm_ReleaseUser(userp);
5739 /* we have scp and dscp */
5741 /* we have scp but not dscp */
5743 smb_ReleaseFID(baseFidp);
5746 /* if we get here, if code is 0, the file exists and is represented by
5747 * scp. Otherwise, we have to create it. The dir may be represented
5748 * by dscp, or we may have found the file directly. If code is non-zero,
5751 if (code == 0 && !treeCreate) {
5752 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req);
5755 cm_ReleaseSCache(dscp);
5757 cm_ReleaseSCache(scp);
5758 cm_ReleaseUser(userp);
5763 if (createDisp == FILE_CREATE) {
5764 /* oops, file shouldn't be there */
5766 cm_ReleaseSCache(dscp);
5768 cm_ReleaseSCache(scp);
5769 cm_ReleaseUser(userp);
5771 return CM_ERROR_EXISTS;
5774 if ( createDisp == FILE_OVERWRITE ||
5775 createDisp == FILE_OVERWRITE_IF) {
5777 setAttr.mask = CM_ATTRMASK_LENGTH;
5778 setAttr.length.LowPart = 0;
5779 setAttr.length.HighPart = 0;
5780 /* now watch for a symlink */
5782 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5784 osi_assert(dscp != NULL);
5785 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5787 /* we have a more accurate file to use (the
5788 * target of the symbolic link). Otherwise,
5789 * we'll just use the symlink anyway.
5791 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5793 cm_ReleaseSCache(scp);
5797 code = cm_SetAttr(scp, &setAttr, userp, &req);
5798 openAction = 3; /* truncated existing file */
5801 openAction = 1; /* found existing file */
5803 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
5804 /* don't create if not found */
5806 cm_ReleaseSCache(dscp);
5808 cm_ReleaseSCache(scp);
5809 cm_ReleaseUser(userp);
5811 return CM_ERROR_NOSUCHFILE;
5812 } else if (realDirFlag == 0 || realDirFlag == -1) {
5813 osi_assert(dscp != NULL);
5814 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
5815 osi_LogSaveString(smb_logp, lastNamep));
5816 openAction = 2; /* created file */
5817 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5818 setAttr.clientModTime = time(NULL);
5819 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
5822 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5823 smb_NotifyChange(FILE_ACTION_ADDED,
5824 FILE_NOTIFY_CHANGE_FILE_NAME,
5825 dscp, lastNamep, NULL, TRUE);
5826 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
5827 /* Not an exclusive create, and someone else tried
5828 * creating it already, then we open it anyway. We
5829 * don't bother retrying after this, since if this next
5830 * fails, that means that the file was deleted after we
5831 * started this call.
5833 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5836 if (createDisp == FILE_OVERWRITE_IF) {
5837 setAttr.mask = CM_ATTRMASK_LENGTH;
5838 setAttr.length.LowPart = 0;
5839 setAttr.length.HighPart = 0;
5841 /* now watch for a symlink */
5843 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5845 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5847 /* we have a more accurate file to use (the
5848 * target of the symbolic link). Otherwise,
5849 * we'll just use the symlink anyway.
5851 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5853 cm_ReleaseSCache(scp);
5857 code = cm_SetAttr(scp, &setAttr, userp, &req);
5859 } /* lookup succeeded */
5863 char *cp; /* This component */
5864 int clen = 0; /* length of component */
5865 cm_scache_t *tscp1, *tscp2;
5868 /* create directory */
5870 treeStartp = lastNamep;
5871 osi_assert(dscp != NULL);
5872 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
5873 osi_LogSaveString(smb_logp, treeStartp));
5874 openAction = 2; /* created directory */
5876 /* if the request is to create the root directory
5877 * it will appear as a directory name of the nul-string
5878 * and a code of CM_ERROR_NOSUCHFILE
5880 if ( !*treeStartp && code == CM_ERROR_NOSUCHFILE)
5881 code = CM_ERROR_EXISTS;
5883 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5884 setAttr.clientModTime = time(NULL);
5889 cm_HoldSCache(tscp1);
5893 tp = strchr(pp, '\\');
5896 clen = (int)strlen(cp);
5897 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
5899 clen = (int)(tp - pp);
5900 strncpy(cp,pp,clen);
5907 continue; /* the supplied path can't have consecutive slashes either , but */
5909 /* cp is the next component to be created. */
5910 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
5911 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
5912 smb_NotifyChange(FILE_ACTION_ADDED,
5913 FILE_NOTIFY_CHANGE_DIR_NAME,
5914 tscp1, cp, NULL, TRUE);
5916 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
5917 /* Not an exclusive create, and someone else tried
5918 * creating it already, then we open it anyway. We
5919 * don't bother retrying after this, since if this next
5920 * fails, that means that the file was deleted after we
5921 * started this call.
5923 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
5924 userp, &req, &tscp2);
5929 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
5930 cm_ReleaseSCache(tscp1);
5931 tscp1 = tscp2; /* Newly created directory will be next parent */
5932 /* the hold is transfered to tscp1 from tscp2 */
5937 cm_ReleaseSCache(dscp);
5940 cm_ReleaseSCache(scp);
5943 * if we get here and code == 0, then scp is the last directory created, and dscp is the
5949 /* something went wrong creating or truncating the file */
5951 cm_ReleaseSCache(scp);
5953 cm_ReleaseSCache(dscp);
5954 cm_ReleaseUser(userp);
5959 /* make sure we have file vs. dir right (only applies for single component case) */
5960 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5961 /* now watch for a symlink */
5963 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5964 cm_scache_t * targetScp = 0;
5965 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5967 /* we have a more accurate file to use (the
5968 * target of the symbolic link). Otherwise,
5969 * we'll just use the symlink anyway.
5971 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
5972 cm_ReleaseSCache(scp);
5977 if (scp->fileType != CM_SCACHETYPE_FILE) {
5979 cm_ReleaseSCache(dscp);
5980 cm_ReleaseSCache(scp);
5981 cm_ReleaseUser(userp);
5983 return CM_ERROR_ISDIR;
5987 /* (only applies to single component case) */
5988 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5989 cm_ReleaseSCache(scp);
5991 cm_ReleaseSCache(dscp);
5992 cm_ReleaseUser(userp);
5994 return CM_ERROR_NOTDIR;
5997 /* open the file itself */
5998 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6001 /* save a reference to the user */
6003 fidp->userp = userp;
6005 /* If we are restricting sharing, we should do so with a suitable
6007 if (scp->fileType == CM_SCACHETYPE_FILE &&
6008 !(fidflags & SMB_FID_SHARE_WRITE)) {
6010 LARGE_INTEGER LOffset, LLength;
6013 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
6014 LOffset.LowPart = SMB_FID_QLOCK_LOW;
6015 LLength.HighPart = 0;
6016 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
6018 if (fidflags & SMB_FID_SHARE_READ) {
6019 sLockType = LOCKING_ANDX_SHARED_LOCK;
6024 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
6026 lock_ObtainMutex(&scp->mx);
6027 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
6028 lock_ReleaseMutex(&scp->mx);
6031 /* shouldn't this be smb_CloseFID() fidp->flags = SMB_FID_DELETE; */
6032 smb_CloseFID(vcp, fidp, NULL, 0);
6033 smb_ReleaseFID(fidp);
6035 cm_ReleaseSCache(scp);
6037 cm_ReleaseSCache(dscp);
6038 cm_ReleaseUser(userp);
6045 lock_ObtainMutex(&fidp->mx);
6046 /* save a pointer to the vnode */
6047 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
6049 fidp->flags = fidflags;
6051 /* remember if the file was newly created */
6053 fidp->flags |= SMB_FID_CREATED;
6055 /* save parent dir and pathname for delete or change notification */
6056 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
6057 fidp->flags |= SMB_FID_NTOPEN;
6058 fidp->NTopen_dscp = dscp;
6059 cm_HoldSCache(dscp);
6060 fidp->NTopen_pathp = strdup(lastNamep);
6062 fidp->NTopen_wholepathp = realPathp;
6063 lock_ReleaseMutex(&fidp->mx);
6065 /* we don't need this any longer */
6067 cm_ReleaseSCache(dscp);
6071 cm_Open(scp, 0, userp);
6073 /* set inp->fid so that later read calls in same msg can find fid */
6074 inp->fid = fidp->fid;
6078 lock_ObtainMutex(&scp->mx);
6079 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6080 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6081 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
6082 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6083 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6084 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6085 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6086 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6087 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
6089 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6090 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6091 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6092 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6093 smb_SetSMBParmByte(outp, parmSlot,
6094 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
6095 lock_ReleaseMutex(&scp->mx);
6096 smb_SetSMBDataLength(outp, 0);
6098 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
6099 osi_LogSaveString(smb_logp, realPathp));
6101 smb_ReleaseFID(fidp);
6103 cm_ReleaseUser(userp);
6105 /* Can't free realPathp if we get here since
6106 fidp->NTopen_wholepathp is pointing there */
6108 /* leave scp held since we put it in fidp->scp */
6113 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
6114 * Instead, ultimately, would like to use a subroutine for common code.
6116 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6118 char *pathp, *realPathp;
6122 cm_scache_t *dscp; /* parent dir */
6123 cm_scache_t *scp; /* file to create or open */
6124 cm_scache_t *targetScp; /* if scp is a symlink */
6127 unsigned long nameLength;
6129 unsigned int requestOpLock;
6130 unsigned int requestBatchOpLock;
6131 unsigned int mustBeDir;
6132 unsigned int extendedRespRequired;
6134 unsigned int desiredAccess;
6135 #ifdef DEBUG_VERBOSE
6136 unsigned int allocSize;
6138 unsigned int shareAccess;
6139 unsigned int extAttributes;
6140 unsigned int createDisp;
6141 #ifdef DEBUG_VERBOSE
6144 unsigned int createOptions;
6145 int initialModeBits;
6146 unsigned short baseFid;
6147 smb_fid_t *baseFidp;
6149 cm_scache_t *baseDirp;
6150 unsigned short openAction;
6156 int parmOffset, dataOffset;
6168 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6169 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6170 parmp = inp->data + parmOffset;
6171 lparmp = (ULONG *) parmp;
6174 requestOpLock = flags & REQUEST_OPLOCK;
6175 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6176 mustBeDir = flags & OPEN_DIRECTORY;
6177 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6180 * Why all of a sudden 32-bit FID?
6181 * We will reject all bits higher than 16.
6183 if (lparmp[1] & 0xFFFF0000)
6184 return CM_ERROR_INVAL;
6185 baseFid = (unsigned short)lparmp[1];
6186 desiredAccess = lparmp[2];
6187 #ifdef DEBUG_VERBOSE
6188 allocSize = lparmp[3];
6189 #endif /* DEBUG_VERSOSE */
6190 extAttributes = lparmp[5];
6191 shareAccess = lparmp[6];
6192 createDisp = lparmp[7];
6193 createOptions = lparmp[8];
6194 #ifdef DEBUG_VERBOSE
6197 nameLength = lparmp[11];
6199 #ifdef DEBUG_VERBOSE
6200 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
6201 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
6202 osi_Log1(smb_logp,"... flags[%x]",flags);
6205 /* mustBeDir is never set; createOptions directory bit seems to be
6208 if (createOptions & FILE_DIRECTORY_FILE)
6210 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6216 * compute initial mode bits based on read-only flag in
6217 * extended attributes
6219 initialModeBits = 0666;
6220 if (extAttributes & 1)
6221 initialModeBits &= ~0222;
6223 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
6224 /* Sometimes path is not null-terminated, so we make a copy. */
6225 realPathp = malloc(nameLength+1);
6226 memcpy(realPathp, pathp, nameLength);
6227 realPathp[nameLength] = 0;
6228 if (smb_StoreAnsiFilenames)
6229 OemToChar(realPathp,realPathp);
6231 spacep = cm_GetSpace();
6232 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6235 * Nothing here to handle SMB_IOCTL_FILENAME.
6236 * Will add it if necessary.
6239 #ifdef DEBUG_VERBOSE
6241 char *hexp, *asciip;
6242 asciip = (lastNamep? lastNamep : realPathp);
6243 hexp = osi_HexifyString( asciip );
6244 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
6249 userp = smb_GetUserFromVCP(vcp, inp);
6251 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
6253 return CM_ERROR_INVAL;
6258 baseDirp = cm_data.rootSCachep;
6259 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6260 if (code == CM_ERROR_TIDIPC) {
6261 /* Attempt to use a TID allocated for IPC. The client
6262 * is probably looking for DCE RPC end points which we
6263 * don't support OR it could be looking to make a DFS
6266 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
6269 cm_ReleaseUser(userp);
6270 return CM_ERROR_NOSUCHPATH;
6274 baseFidp = smb_FindFID(vcp, baseFid, 0);
6276 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
6278 cm_ReleaseUser(userp);
6279 return CM_ERROR_INVAL;
6281 baseDirp = baseFidp->scp;
6285 /* compute open mode */
6287 if (desiredAccess & DELETE)
6288 fidflags |= SMB_FID_OPENDELETE;
6289 if (desiredAccess & AFS_ACCESS_READ)
6290 fidflags |= SMB_FID_OPENREAD;
6291 if (desiredAccess & AFS_ACCESS_WRITE)
6292 fidflags |= SMB_FID_OPENWRITE;
6293 if (createOptions & FILE_DELETE_ON_CLOSE)
6294 fidflags |= SMB_FID_DELONCLOSE;
6296 /* And the share mode */
6297 if (shareAccess & FILE_SHARE_READ)
6298 fidflags |= SMB_FID_SHARE_READ;
6299 if (shareAccess & FILE_SHARE_WRITE)
6300 fidflags |= SMB_FID_SHARE_WRITE;
6304 if ( createDisp == FILE_OPEN ||
6305 createDisp == FILE_OVERWRITE ||
6306 createDisp == FILE_OVERWRITE_IF) {
6307 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6308 userp, tidPathp, &req, &dscp);
6311 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6312 cm_ReleaseSCache(dscp);
6313 cm_ReleaseUser(userp);
6316 smb_ReleaseFID(baseFidp);
6317 if ( WANTS_DFS_PATHNAMES(inp) )
6318 return CM_ERROR_PATH_NOT_COVERED;
6320 return CM_ERROR_BADSHARENAME;
6322 #endif /* DFS_SUPPORT */
6323 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6325 if (code == CM_ERROR_NOSUCHFILE) {
6326 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6327 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6328 if (code == 0 && realDirFlag == 1) {
6329 cm_ReleaseSCache(scp);
6330 cm_ReleaseSCache(dscp);
6331 cm_ReleaseUser(userp);
6334 smb_ReleaseFID(baseFidp);
6335 return CM_ERROR_EXISTS;
6341 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6342 userp, tidPathp, &req, &scp);
6344 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6345 cm_ReleaseSCache(scp);
6346 cm_ReleaseUser(userp);
6349 smb_ReleaseFID(baseFidp);
6350 if ( WANTS_DFS_PATHNAMES(inp) )
6351 return CM_ERROR_PATH_NOT_COVERED;
6353 return CM_ERROR_BADSHARENAME;
6355 #endif /* DFS_SUPPORT */
6361 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6362 /* look up parent directory */
6364 code = cm_NameI(baseDirp, spacep->data,
6365 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6366 userp, tidPathp, &req, &dscp);
6368 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6369 cm_ReleaseSCache(dscp);
6370 cm_ReleaseUser(userp);
6373 smb_ReleaseFID(baseFidp);
6374 if ( WANTS_DFS_PATHNAMES(inp) )
6375 return CM_ERROR_PATH_NOT_COVERED;
6377 return CM_ERROR_BADSHARENAME;
6379 #endif /* DFS_SUPPORT */
6383 cm_FreeSpace(spacep);
6386 smb_ReleaseFID(baseFidp);
6389 cm_ReleaseUser(userp);
6395 lastNamep = realPathp;
6399 if (!smb_IsLegalFilename(lastNamep))
6400 return CM_ERROR_BADNTFILENAME;
6403 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
6404 code = cm_Lookup(dscp, lastNamep,
6405 CM_FLAG_FOLLOW, userp, &req, &scp);
6407 code = cm_Lookup(dscp, lastNamep,
6408 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6411 if (code && code != CM_ERROR_NOSUCHFILE) {
6412 cm_ReleaseSCache(dscp);
6413 cm_ReleaseUser(userp);
6420 smb_ReleaseFID(baseFidp);
6421 cm_FreeSpace(spacep);
6424 /* if we get here, if code is 0, the file exists and is represented by
6425 * scp. Otherwise, we have to create it. The dir may be represented
6426 * by dscp, or we may have found the file directly. If code is non-zero,
6430 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
6434 cm_ReleaseSCache(dscp);
6435 cm_ReleaseSCache(scp);
6436 cm_ReleaseUser(userp);
6441 if (createDisp == FILE_CREATE) {
6442 /* oops, file shouldn't be there */
6444 cm_ReleaseSCache(dscp);
6445 cm_ReleaseSCache(scp);
6446 cm_ReleaseUser(userp);
6448 return CM_ERROR_EXISTS;
6451 if (createDisp == FILE_OVERWRITE ||
6452 createDisp == FILE_OVERWRITE_IF) {
6453 setAttr.mask = CM_ATTRMASK_LENGTH;
6454 setAttr.length.LowPart = 0;
6455 setAttr.length.HighPart = 0;
6457 /* now watch for a symlink */
6459 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6461 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6463 /* we have a more accurate file to use (the
6464 * target of the symbolic link). Otherwise,
6465 * we'll just use the symlink anyway.
6467 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6469 cm_ReleaseSCache(scp);
6473 code = cm_SetAttr(scp, &setAttr, userp, &req);
6474 openAction = 3; /* truncated existing file */
6476 else openAction = 1; /* found existing file */
6478 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6479 /* don't create if not found */
6481 cm_ReleaseSCache(dscp);
6482 cm_ReleaseUser(userp);
6484 return CM_ERROR_NOSUCHFILE;
6486 else if (realDirFlag == 0 || realDirFlag == -1) {
6487 osi_assert(dscp != NULL);
6488 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
6489 osi_LogSaveString(smb_logp, lastNamep));
6490 openAction = 2; /* created file */
6491 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6492 setAttr.clientModTime = time(NULL);
6493 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6497 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6498 smb_NotifyChange(FILE_ACTION_ADDED,
6499 FILE_NOTIFY_CHANGE_FILE_NAME,
6500 dscp, lastNamep, NULL, TRUE);
6501 } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6502 /* Not an exclusive create, and someone else tried
6503 * creating it already, then we open it anyway. We
6504 * don't bother retrying after this, since if this next
6505 * fails, that means that the file was deleted after we
6506 * started this call.
6508 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6511 if (createDisp == FILE_OVERWRITE_IF) {
6512 setAttr.mask = CM_ATTRMASK_LENGTH;
6513 setAttr.length.LowPart = 0;
6514 setAttr.length.HighPart = 0;
6516 /* now watch for a symlink */
6518 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6520 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6522 /* we have a more accurate file to use (the
6523 * target of the symbolic link). Otherwise,
6524 * we'll just use the symlink anyway.
6526 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6528 cm_ReleaseSCache(scp);
6532 code = cm_SetAttr(scp, &setAttr, userp, &req);
6534 } /* lookup succeeded */
6537 /* create directory */
6538 osi_assert(dscp != NULL);
6540 "smb_ReceiveNTTranCreate creating directory %s",
6541 osi_LogSaveString(smb_logp, lastNamep));
6542 openAction = 2; /* created directory */
6543 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6544 setAttr.clientModTime = time(NULL);
6545 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6546 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6547 smb_NotifyChange(FILE_ACTION_ADDED,
6548 FILE_NOTIFY_CHANGE_DIR_NAME,
6549 dscp, lastNamep, NULL, TRUE);
6551 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6552 /* Not an exclusive create, and someone else tried
6553 * creating it already, then we open it anyway. We
6554 * don't bother retrying after this, since if this next
6555 * fails, that means that the file was deleted after we
6556 * started this call.
6558 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6564 /* something went wrong creating or truncating the file */
6566 cm_ReleaseSCache(scp);
6567 cm_ReleaseUser(userp);
6572 /* make sure we have file vs. dir right */
6573 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
6574 /* now watch for a symlink */
6576 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6578 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6580 /* we have a more accurate file to use (the
6581 * target of the symbolic link). Otherwise,
6582 * we'll just use the symlink anyway.
6584 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6586 cm_ReleaseSCache(scp);
6591 if (scp->fileType != CM_SCACHETYPE_FILE) {
6592 cm_ReleaseSCache(scp);
6593 cm_ReleaseUser(userp);
6595 return CM_ERROR_ISDIR;
6599 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
6600 cm_ReleaseSCache(scp);
6601 cm_ReleaseUser(userp);
6603 return CM_ERROR_NOTDIR;
6606 /* open the file itself */
6607 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6610 /* save a reference to the user */
6612 fidp->userp = userp;
6614 /* If we are restricting sharing, we should do so with a suitable
6616 if (scp->fileType == CM_SCACHETYPE_FILE &&
6617 !(fidflags & SMB_FID_SHARE_WRITE)) {
6619 LARGE_INTEGER LOffset, LLength;
6622 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
6623 LOffset.LowPart = SMB_FID_QLOCK_LOW;
6624 LLength.HighPart = 0;
6625 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
6627 if (fidflags & SMB_FID_SHARE_READ) {
6628 sLockType = LOCKING_ANDX_SHARED_LOCK;
6633 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
6635 lock_ObtainMutex(&scp->mx);
6636 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
6637 lock_ReleaseMutex(&scp->mx);
6640 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
6641 smb_CloseFID(vcp, fidp, NULL, 0);
6642 smb_ReleaseFID(fidp);
6644 cm_ReleaseSCache(scp);
6645 cm_ReleaseUser(userp);
6648 return CM_ERROR_SHARING_VIOLATION;
6652 lock_ObtainMutex(&fidp->mx);
6653 /* save a pointer to the vnode */
6656 fidp->flags = fidflags;
6658 /* remember if the file was newly created */
6660 fidp->flags |= SMB_FID_CREATED;
6662 /* save parent dir and pathname for deletion or change notification */
6663 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
6664 fidp->flags |= SMB_FID_NTOPEN;
6665 fidp->NTopen_dscp = dscp;
6666 cm_HoldSCache(dscp);
6667 fidp->NTopen_pathp = strdup(lastNamep);
6669 fidp->NTopen_wholepathp = realPathp;
6670 lock_ReleaseMutex(&fidp->mx);
6672 /* we don't need this any longer */
6674 cm_ReleaseSCache(dscp);
6676 cm_Open(scp, 0, userp);
6678 /* set inp->fid so that later read calls in same msg can find fid */
6679 inp->fid = fidp->fid;
6681 /* check whether we are required to send an extended response */
6682 if (!extendedRespRequired) {
6684 parmOffset = 8*4 + 39;
6685 parmOffset += 1; /* pad to 4 */
6686 dataOffset = parmOffset + 70;
6690 /* Total Parameter Count */
6691 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
6692 /* Total Data Count */
6693 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6694 /* Parameter Count */
6695 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
6696 /* Parameter Offset */
6697 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6698 /* Parameter Displacement */
6699 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6701 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6703 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6704 /* Data Displacement */
6705 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6706 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6707 smb_SetSMBDataLength(outp, 70);
6709 lock_ObtainMutex(&scp->mx);
6710 outData = smb_GetSMBData(outp, NULL);
6711 outData++; /* round to get to parmOffset */
6712 *outData = 0; outData++; /* oplock */
6713 *outData = 0; outData++; /* reserved */
6714 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
6715 *((ULONG *)outData) = openAction; outData += 4;
6716 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
6717 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6718 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
6719 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
6720 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
6721 *((FILETIME *)outData) = ft; outData += 8; /* change time */
6722 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
6723 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
6724 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
6725 *((USHORT *)outData) = 0; outData += 2; /* filetype */
6726 *((USHORT *)outData) = 0; outData += 2; /* dev state */
6727 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
6728 outData += 2; /* is a dir? */
6729 lock_ReleaseMutex(&scp->mx);
6732 parmOffset = 8*4 + 39;
6733 parmOffset += 1; /* pad to 4 */
6734 dataOffset = parmOffset + 104;
6738 /* Total Parameter Count */
6739 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
6740 /* Total Data Count */
6741 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6742 /* Parameter Count */
6743 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
6744 /* Parameter Offset */
6745 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6746 /* Parameter Displacement */
6747 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6749 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6751 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6752 /* Data Displacement */
6753 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6754 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6755 smb_SetSMBDataLength(outp, 105);
6757 lock_ObtainMutex(&scp->mx);
6758 outData = smb_GetSMBData(outp, NULL);
6759 outData++; /* round to get to parmOffset */
6760 *outData = 0; outData++; /* oplock */
6761 *outData = 1; outData++; /* response type */
6762 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
6763 *((ULONG *)outData) = openAction; outData += 4;
6764 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
6765 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6766 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
6767 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
6768 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
6769 *((FILETIME *)outData) = ft; outData += 8; /* change time */
6770 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
6771 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
6772 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
6773 *((USHORT *)outData) = 0; outData += 2; /* filetype */
6774 *((USHORT *)outData) = 0; outData += 2; /* dev state */
6775 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
6776 outData += 1; /* is a dir? */
6777 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
6778 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
6779 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
6780 lock_ReleaseMutex(&scp->mx);
6783 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
6785 smb_ReleaseFID(fidp);
6787 cm_ReleaseUser(userp);
6789 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
6790 /* leave scp held since we put it in fidp->scp */
6794 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
6797 smb_packet_t *savedPacketp;
6798 ULONG filter; USHORT fid, watchtree;
6802 filter = smb_GetSMBParm(inp, 19) |
6803 (smb_GetSMBParm(inp, 20) << 16);
6804 fid = smb_GetSMBParm(inp, 21);
6805 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
6807 fidp = smb_FindFID(vcp, fid, 0);
6809 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
6810 return CM_ERROR_BADFD;
6813 savedPacketp = smb_CopyPacket(inp);
6815 if (savedPacketp->vcp)
6816 smb_ReleaseVC(savedPacketp->vcp);
6817 savedPacketp->vcp = vcp;
6818 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6819 savedPacketp->nextp = smb_Directory_Watches;
6820 smb_Directory_Watches = savedPacketp;
6821 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6823 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
6824 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
6827 lock_ObtainMutex(&scp->mx);
6829 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
6831 scp->flags |= CM_SCACHEFLAG_WATCHED;
6832 lock_ReleaseMutex(&scp->mx);
6833 smb_ReleaseFID(fidp);
6835 outp->flags |= SMB_PACKETFLAG_NOSEND;
6839 unsigned char nullSecurityDesc[36] = {
6840 0x01, /* security descriptor revision */
6841 0x00, /* reserved, should be zero */
6842 0x00, 0x80, /* security descriptor control;
6843 * 0x8000 : self-relative format */
6844 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
6845 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
6846 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
6847 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
6848 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6849 /* "null SID" owner SID */
6850 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
6851 /* "null SID" group SID */
6854 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6856 int parmOffset, parmCount, dataOffset, dataCount;
6864 ULONG securityInformation;
6866 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6867 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6868 parmp = inp->data + parmOffset;
6869 sparmp = (USHORT *) parmp;
6870 lparmp = (ULONG *) parmp;
6873 securityInformation = lparmp[1];
6875 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
6876 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6884 parmOffset = 8*4 + 39;
6885 parmOffset += 1; /* pad to 4 */
6887 dataOffset = parmOffset + parmCount;
6891 /* Total Parameter Count */
6892 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6893 /* Total Data Count */
6894 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6895 /* Parameter Count */
6896 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6897 /* Parameter Offset */
6898 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6899 /* Parameter Displacement */
6900 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6902 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6904 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6905 /* Data Displacement */
6906 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6907 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6908 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
6910 outData = smb_GetSMBData(outp, NULL);
6911 outData++; /* round to get to parmOffset */
6912 *((ULONG *)outData) = 36; outData += 4; /* length */
6914 if (maxData >= 36) {
6915 memcpy(outData, nullSecurityDesc, 36);
6919 return CM_ERROR_BUFFERTOOSMALL;
6922 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6924 unsigned short function;
6926 function = smb_GetSMBParm(inp, 18);
6928 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
6930 /* We can handle long names */
6931 if (vcp->flags & SMB_VCFLAG_USENT)
6932 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
6936 return smb_ReceiveNTTranCreate(vcp, inp, outp);
6938 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
6941 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
6944 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
6946 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
6949 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
6951 return CM_ERROR_INVAL;
6955 * smb_NotifyChange -- find relevant change notification messages and
6958 * If we don't know the file name (i.e. a callback break), filename is
6959 * NULL, and we return a zero-length list.
6961 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
6962 cm_scache_t *dscp, char *filename, char *otherFilename,
6963 BOOL isDirectParent)
6965 smb_packet_t *watch, *lastWatch, *nextWatch;
6966 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
6967 char *outData, *oldOutData;
6971 BOOL twoEntries = FALSE;
6972 ULONG otherNameLen, oldParmCount = 0;
6976 /* Get ready for rename within directory */
6977 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
6979 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
6982 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
6983 osi_LogSaveString(smb_logp,filename),dscp);
6985 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6986 watch = smb_Directory_Watches;
6988 filter = smb_GetSMBParm(watch, 19)
6989 | (smb_GetSMBParm(watch, 20) << 16);
6990 fid = smb_GetSMBParm(watch, 21);
6991 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
6992 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
6993 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
6996 * Strange hack - bug in NT Client and NT Server that we
6999 if (filter == 3 && wtree)
7002 fidp = smb_FindFID(watch->vcp, fid, 0);
7004 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
7006 watch = watch->nextp;
7009 if (fidp->scp != dscp
7010 || (filter & notifyFilter) == 0
7011 || (!isDirectParent && !wtree)) {
7012 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
7013 smb_ReleaseFID(fidp);
7015 watch = watch->nextp;
7018 smb_ReleaseFID(fidp);
7021 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
7022 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
7024 nextWatch = watch->nextp;
7025 if (watch == smb_Directory_Watches)
7026 smb_Directory_Watches = nextWatch;
7028 lastWatch->nextp = nextWatch;
7030 /* Turn off WATCHED flag in dscp */
7031 lock_ObtainMutex(&dscp->mx);
7033 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
7035 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
7036 lock_ReleaseMutex(&dscp->mx);
7038 /* Convert to response packet */
7039 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
7040 ((smb_t *) watch)->wct = 0;
7043 if (filename == NULL)
7046 nameLen = (ULONG)strlen(filename);
7047 parmCount = 3*4 + nameLen*2;
7048 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
7050 otherNameLen = (ULONG)strlen(otherFilename);
7051 oldParmCount = parmCount;
7052 parmCount += 3*4 + otherNameLen*2;
7053 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
7055 if (maxLen < parmCount)
7056 parmCount = 0; /* not enough room */
7058 parmOffset = 8*4 + 39;
7059 parmOffset += 1; /* pad to 4 */
7060 dataOffset = parmOffset + parmCount;
7064 /* Total Parameter Count */
7065 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
7066 /* Total Data Count */
7067 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7068 /* Parameter Count */
7069 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
7070 /* Parameter Offset */
7071 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
7072 /* Parameter Displacement */
7073 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7075 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7077 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
7078 /* Data Displacement */
7079 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7080 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
7081 smb_SetSMBDataLength(watch, parmCount + 1);
7083 if (parmCount != 0) {
7085 outData = smb_GetSMBData(watch, NULL);
7086 outData++; /* round to get to parmOffset */
7087 oldOutData = outData;
7088 *((DWORD *)outData) = oldParmCount; outData += 4;
7089 /* Next Entry Offset */
7090 *((DWORD *)outData) = action; outData += 4;
7092 *((DWORD *)outData) = nameLen*2; outData += 4;
7093 /* File Name Length */
7094 p = strdup(filename);
7095 if (smb_StoreAnsiFilenames)
7097 mbstowcs((WCHAR *)outData, p, nameLen);
7101 outData = oldOutData + oldParmCount;
7102 *((DWORD *)outData) = 0; outData += 4;
7103 /* Next Entry Offset */
7104 *((DWORD *)outData) = otherAction; outData += 4;
7106 *((DWORD *)outData) = otherNameLen*2;
7107 outData += 4; /* File Name Length */
7108 p = strdup(otherFilename);
7109 if (smb_StoreAnsiFilenames)
7111 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
7117 * If filename is null, we don't know the cause of the
7118 * change notification. We return zero data (see above),
7119 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
7120 * (= 0x010C). We set the error code here by hand, without
7121 * modifying wct and bcc.
7123 if (filename == NULL) {
7124 ((smb_t *) watch)->rcls = 0x0C;
7125 ((smb_t *) watch)->reh = 0x01;
7126 ((smb_t *) watch)->errLow = 0;
7127 ((smb_t *) watch)->errHigh = 0;
7128 /* Set NT Status codes flag */
7129 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7132 smb_SendPacket(watch->vcp, watch);
7133 smb_FreePacket(watch);
7136 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7139 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7141 unsigned char *replyWctp;
7142 smb_packet_t *watch, *lastWatch;
7143 USHORT fid, watchtree;
7147 osi_Log0(smb_logp, "SMB3 receive NT cancel");
7149 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7150 watch = smb_Directory_Watches;
7152 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
7153 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
7154 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
7155 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
7156 if (watch == smb_Directory_Watches)
7157 smb_Directory_Watches = watch->nextp;
7159 lastWatch->nextp = watch->nextp;
7160 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7162 /* Turn off WATCHED flag in scp */
7163 fid = smb_GetSMBParm(watch, 21);
7164 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
7166 if (vcp != watch->vcp)
7167 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
7170 fidp = smb_FindFID(vcp, fid, 0);
7172 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
7174 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
7177 lock_ObtainMutex(&scp->mx);
7179 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
7181 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
7182 lock_ReleaseMutex(&scp->mx);
7183 smb_ReleaseFID(fidp);
7185 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
7188 /* assume STATUS32; return 0xC0000120 (CANCELED) */
7189 replyWctp = watch->wctp;
7193 ((smb_t *)watch)->rcls = 0x20;
7194 ((smb_t *)watch)->reh = 0x1;
7195 ((smb_t *)watch)->errLow = 0;
7196 ((smb_t *)watch)->errHigh = 0xC0;
7197 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7198 smb_SendPacket(vcp, watch);
7199 smb_FreePacket(watch);
7203 watch = watch->nextp;
7205 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7211 * NT rename also does hard links.
7214 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
7215 #define RENAME_FLAG_HARD_LINK 0x103
7216 #define RENAME_FLAG_RENAME 0x104
7217 #define RENAME_FLAG_COPY 0x105
7219 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7221 char *oldPathp, *newPathp;
7227 attrs = smb_GetSMBParm(inp, 0);
7228 rename_type = smb_GetSMBParm(inp, 1);
7230 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
7231 osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
7232 return CM_ERROR_NOACCESS;
7235 tp = smb_GetSMBData(inp, NULL);
7236 oldPathp = smb_ParseASCIIBlock(tp, &tp);
7237 if (smb_StoreAnsiFilenames)
7238 OemToChar(oldPathp,oldPathp);
7239 newPathp = smb_ParseASCIIBlock(tp, &tp);
7240 if (smb_StoreAnsiFilenames)
7241 OemToChar(newPathp,newPathp);
7243 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
7244 osi_LogSaveString(smb_logp, oldPathp),
7245 osi_LogSaveString(smb_logp, newPathp),
7246 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
7248 if (rename_type == RENAME_FLAG_RENAME) {
7249 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
7250 } else { /* RENAME_FLAG_HARD_LINK */
7251 code = smb_Link(vcp,inp,oldPathp,newPathp);
7258 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
7261 cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
7263 smb_username_t *unp;
7266 unp = smb_FindUserByName(usern, machine, flags);
7268 lock_ObtainMutex(&unp->mx);
7269 unp->userp = cm_NewUser();
7270 lock_ReleaseMutex(&unp->mx);
7271 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7273 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7277 smb_ReleaseUsername(unp);