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;
2070 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2071 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2073 openFun = p->parmsp[6]; /* open function */
2074 excl = ((openFun & 3) == 0);
2075 trunc = ((openFun & 3) == 2); /* truncate it */
2076 openMode = (p->parmsp[1] & 0x7);
2077 openAction = 0; /* tracks what we did */
2079 attributes = p->parmsp[3];
2080 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2082 /* compute initial mode bits based on read-only flag in attributes */
2083 initialModeBits = 0666;
2085 initialModeBits &= ~0222;
2087 pathp = (char *) (&p->parmsp[14]);
2088 if (smb_StoreAnsiFilenames)
2089 OemToChar(pathp,pathp);
2091 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2093 spacep = cm_GetSpace();
2094 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2096 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2097 /* special case magic file name for receiving IOCTL requests
2098 * (since IOCTL calls themselves aren't getting through).
2100 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2101 smb_SetupIoctlFid(fidp, spacep);
2103 /* copy out remainder of the parms */
2105 outp->parmsp[parmSlot++] = fidp->fid;
2107 outp->parmsp[parmSlot++] = 0; /* attrs */
2108 outp->parmsp[parmSlot++] = 0; /* mod time */
2109 outp->parmsp[parmSlot++] = 0;
2110 outp->parmsp[parmSlot++] = 0; /* len */
2111 outp->parmsp[parmSlot++] = 0x7fff;
2112 outp->parmsp[parmSlot++] = openMode;
2113 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2114 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2116 /* and the final "always present" stuff */
2117 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2118 /* next write out the "unique" ID */
2119 outp->parmsp[parmSlot++] = 0x1234;
2120 outp->parmsp[parmSlot++] = 0x5678;
2121 outp->parmsp[parmSlot++] = 0;
2122 if (returnEALength) {
2123 outp->parmsp[parmSlot++] = 0;
2124 outp->parmsp[parmSlot++] = 0;
2127 outp->totalData = 0;
2128 outp->totalParms = parmSlot * 2;
2130 smb_SendTran2Packet(vcp, outp, op);
2132 smb_FreeTran2Packet(outp);
2134 /* and clean up fid reference */
2135 smb_ReleaseFID(fidp);
2139 #ifdef DEBUG_VERBOSE
2141 char *hexp, *asciip;
2142 asciip = (lastNamep ? lastNamep : pathp);
2143 hexp = osi_HexifyString( asciip );
2144 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2149 userp = smb_GetTran2User(vcp, p);
2150 /* In the off chance that userp is NULL, we log and abandon */
2152 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2153 smb_FreeTran2Packet(outp);
2154 return CM_ERROR_BADSMB;
2157 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2158 if (code == CM_ERROR_TIDIPC) {
2159 /* Attempt to use a TID allocated for IPC. The client
2160 * is probably looking for DCE RPC end points which we
2161 * don't support OR it could be looking to make a DFS
2164 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2166 cm_ReleaseUser(userp);
2167 smb_FreeTran2Packet(outp);
2168 return CM_ERROR_NOSUCHPATH;
2173 code = cm_NameI(cm_data.rootSCachep, pathp,
2174 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2175 userp, tidPathp, &req, &scp);
2177 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2178 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2179 userp, tidPathp, &req, &dscp);
2180 cm_FreeSpace(spacep);
2183 cm_ReleaseUser(userp);
2184 smb_FreeTran2Packet(outp);
2189 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2190 cm_ReleaseSCache(dscp);
2191 cm_ReleaseUser(userp);
2192 smb_FreeTran2Packet(outp);
2193 if ( WANTS_DFS_PATHNAMES(p) )
2194 return CM_ERROR_PATH_NOT_COVERED;
2196 return CM_ERROR_BADSHARENAME;
2198 #endif /* DFS_SUPPORT */
2200 /* otherwise, scp points to the parent directory. Do a lookup,
2201 * and truncate the file if we find it, otherwise we create the
2208 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2210 if (code && code != CM_ERROR_NOSUCHFILE) {
2211 cm_ReleaseSCache(dscp);
2212 cm_ReleaseUser(userp);
2213 smb_FreeTran2Packet(outp);
2218 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2219 cm_ReleaseSCache(scp);
2220 cm_ReleaseUser(userp);
2221 smb_FreeTran2Packet(outp);
2222 if ( WANTS_DFS_PATHNAMES(p) )
2223 return CM_ERROR_PATH_NOT_COVERED;
2225 return CM_ERROR_BADSHARENAME;
2227 #endif /* DFS_SUPPORT */
2229 /* macintosh is expensive to program for it */
2230 cm_FreeSpace(spacep);
2233 /* if we get here, if code is 0, the file exists and is represented by
2234 * scp. Otherwise, we have to create it.
2237 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2240 cm_ReleaseSCache(dscp);
2241 cm_ReleaseSCache(scp);
2242 cm_ReleaseUser(userp);
2243 smb_FreeTran2Packet(outp);
2248 /* oops, file shouldn't be there */
2250 cm_ReleaseSCache(dscp);
2251 cm_ReleaseSCache(scp);
2252 cm_ReleaseUser(userp);
2253 smb_FreeTran2Packet(outp);
2254 return CM_ERROR_EXISTS;
2258 setAttr.mask = CM_ATTRMASK_LENGTH;
2259 setAttr.length.LowPart = 0;
2260 setAttr.length.HighPart = 0;
2261 code = cm_SetAttr(scp, &setAttr, userp, &req);
2262 openAction = 3; /* truncated existing file */
2265 openAction = 1; /* found existing file */
2267 else if (!(openFun & 0x10)) {
2268 /* don't create if not found */
2270 cm_ReleaseSCache(dscp);
2271 osi_assert(scp == NULL);
2272 cm_ReleaseUser(userp);
2273 smb_FreeTran2Packet(outp);
2274 return CM_ERROR_NOSUCHFILE;
2277 osi_assert(dscp != NULL && scp == NULL);
2278 openAction = 2; /* created file */
2279 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2280 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2281 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2283 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2284 smb_NotifyChange(FILE_ACTION_ADDED,
2285 FILE_NOTIFY_CHANGE_FILE_NAME,
2286 dscp, lastNamep, NULL, TRUE);
2287 if (!excl && code == CM_ERROR_EXISTS) {
2288 /* not an exclusive create, and someone else tried
2289 * creating it already, then we open it anyway. We
2290 * don't bother retrying after this, since if this next
2291 * fails, that means that the file was deleted after we
2292 * started this call.
2294 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2298 setAttr.mask = CM_ATTRMASK_LENGTH;
2299 setAttr.length.LowPart = 0;
2300 setAttr.length.HighPart = 0;
2301 code = cm_SetAttr(scp, &setAttr, userp,
2304 } /* lookup succeeded */
2308 /* we don't need this any longer */
2310 cm_ReleaseSCache(dscp);
2313 /* something went wrong creating or truncating the file */
2315 cm_ReleaseSCache(scp);
2316 cm_ReleaseUser(userp);
2317 smb_FreeTran2Packet(outp);
2321 /* make sure we're about to open a file */
2322 if (scp->fileType != CM_SCACHETYPE_FILE) {
2324 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2325 cm_scache_t * targetScp = 0;
2326 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2328 /* we have a more accurate file to use (the
2329 * target of the symbolic link). Otherwise,
2330 * we'll just use the symlink anyway.
2332 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2334 cm_ReleaseSCache(scp);
2338 if (scp->fileType != CM_SCACHETYPE_FILE) {
2339 cm_ReleaseSCache(scp);
2340 cm_ReleaseUser(userp);
2341 smb_FreeTran2Packet(outp);
2342 return CM_ERROR_ISDIR;
2346 /* now all we have to do is open the file itself */
2347 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2351 lock_ObtainMutex(&fidp->mx);
2352 /* save a pointer to the vnode */
2355 fidp->userp = userp;
2357 /* compute open mode */
2359 fidp->flags |= SMB_FID_OPENREAD;
2360 if (openMode == 1 || openMode == 2)
2361 fidp->flags |= SMB_FID_OPENWRITE;
2362 lock_ReleaseMutex(&fidp->mx);
2364 smb_ReleaseFID(fidp);
2366 cm_Open(scp, 0, userp);
2368 /* copy out remainder of the parms */
2370 outp->parmsp[parmSlot++] = fidp->fid;
2371 lock_ObtainMutex(&scp->mx);
2373 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2374 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2375 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2376 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2377 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2378 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2379 outp->parmsp[parmSlot++] = openMode;
2380 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2381 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2383 /* and the final "always present" stuff */
2384 outp->parmsp[parmSlot++] = openAction;
2385 /* next write out the "unique" ID */
2386 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2387 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2388 outp->parmsp[parmSlot++] = 0;
2389 if (returnEALength) {
2390 outp->parmsp[parmSlot++] = 0;
2391 outp->parmsp[parmSlot++] = 0;
2393 lock_ReleaseMutex(&scp->mx);
2394 outp->totalData = 0; /* total # of data bytes */
2395 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2397 smb_SendTran2Packet(vcp, outp, op);
2399 smb_FreeTran2Packet(outp);
2401 cm_ReleaseUser(userp);
2402 /* leave scp held since we put it in fidp->scp */
2406 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2408 osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2409 return CM_ERROR_BADOP;
2412 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2414 osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2415 return CM_ERROR_BADOP;
2418 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2420 smb_tran2Packet_t *outp;
2421 smb_tran2QFSInfo_t qi;
2424 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
2426 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2428 switch (p->parmsp[0]) {
2429 case 1: responseSize = sizeof(qi.u.allocInfo); break;
2430 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
2431 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
2432 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
2433 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
2434 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
2435 case 0x200: /* CIFS Unix Info */
2436 case 0x301: /* Mac FS Info */
2437 default: return CM_ERROR_INVAL;
2440 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2441 switch (p->parmsp[0]) {
2444 qi.u.allocInfo.FSID = 0;
2445 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2446 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2447 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2448 qi.u.allocInfo.bytesPerSector = 1024;
2453 qi.u.volumeInfo.vsn = 1234;
2454 qi.u.volumeInfo.vnCount = 4;
2455 /* we're supposed to pad it out with zeroes to the end */
2456 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2457 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2461 /* FS volume info */
2462 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
2463 qi.u.FSvolumeInfo.vsn = 1234;
2464 qi.u.FSvolumeInfo.vnCount = 8;
2465 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
2471 temp.LowPart = 0x7fffffff;
2472 qi.u.FSsizeInfo.totalAllocUnits = temp;
2473 temp.LowPart = 0x3fffffff;
2474 qi.u.FSsizeInfo.availAllocUnits = temp;
2475 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2476 qi.u.FSsizeInfo.bytesPerSector = 1024;
2480 /* FS device info */
2481 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
2482 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2486 /* FS attribute info */
2487 /* attributes, defined in WINNT.H:
2488 * FILE_CASE_SENSITIVE_SEARCH 0x1
2489 * FILE_CASE_PRESERVED_NAMES 0x2
2490 * <no name defined> 0x4000
2491 * If bit 0x4000 is not set, Windows 95 thinks
2492 * we can't handle long (non-8.3) names,
2493 * despite our protestations to the contrary.
2495 qi.u.FSattributeInfo.attributes = 0x4003;
2496 qi.u.FSattributeInfo.maxCompLength = 255;
2497 qi.u.FSattributeInfo.FSnameLength = 6;
2498 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
2502 /* copy out return data, and set corresponding sizes */
2503 outp->totalParms = 0;
2504 outp->totalData = responseSize;
2505 memcpy(outp->datap, &qi, responseSize);
2507 /* send and free the packets */
2508 smb_SendTran2Packet(vcp, outp, op);
2509 smb_FreeTran2Packet(outp);
2514 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2516 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2517 return CM_ERROR_BADOP;
2520 struct smb_ShortNameRock {
2524 size_t shortNameLen;
2527 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2530 struct smb_ShortNameRock *rockp;
2534 /* compare both names and vnodes, though probably just comparing vnodes
2535 * would be safe enough.
2537 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2539 if (ntohl(dep->fid.vnode) != rockp->vnode)
2541 /* This is the entry */
2542 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2543 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2544 return CM_ERROR_STOPNOW;
2547 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2548 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2550 struct smb_ShortNameRock rock;
2554 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2558 spacep = cm_GetSpace();
2559 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2561 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2563 cm_FreeSpace(spacep);
2568 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2569 cm_ReleaseSCache(dscp);
2570 cm_ReleaseUser(userp);
2571 return CM_ERROR_PATH_NOT_COVERED;
2573 #endif /* DFS_SUPPORT */
2575 if (!lastNamep) lastNamep = pathp;
2578 thyper.HighPart = 0;
2579 rock.shortName = shortName;
2581 rock.maskp = lastNamep;
2582 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2584 cm_ReleaseSCache(dscp);
2587 return CM_ERROR_NOSUCHFILE;
2588 if (code == CM_ERROR_STOPNOW) {
2589 *shortNameLenp = rock.shortNameLen;
2595 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2597 smb_tran2Packet_t *outp;
2600 unsigned short infoLevel;
2602 unsigned short attributes;
2603 unsigned long extAttributes;
2608 cm_scache_t *scp, *dscp;
2617 infoLevel = p->parmsp[0];
2618 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2620 else if (infoLevel == SMB_INFO_STANDARD)
2621 nbytesRequired = 22;
2622 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2623 nbytesRequired = 26;
2624 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2625 nbytesRequired = 40;
2626 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2627 nbytesRequired = 24;
2628 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2630 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2631 nbytesRequired = 30;
2633 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2634 p->opcode, infoLevel);
2635 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2638 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2639 osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
2641 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2643 if (infoLevel > 0x100)
2644 outp->totalParms = 2;
2646 outp->totalParms = 0;
2647 outp->totalData = nbytesRequired;
2649 /* now, if we're at infoLevel 6, we're only being asked to check
2650 * the syntax, so we just OK things now. In particular, we're *not*
2651 * being asked to verify anything about the state of any parent dirs.
2653 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2654 smb_SendTran2Packet(vcp, outp, opx);
2655 smb_FreeTran2Packet(outp);
2659 userp = smb_GetTran2User(vcp, p);
2661 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2662 smb_FreeTran2Packet(outp);
2663 return CM_ERROR_BADSMB;
2666 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2668 cm_ReleaseUser(userp);
2669 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2670 smb_FreeTran2Packet(outp);
2675 * XXX Strange hack XXX
2677 * As of Patch 7 (13 January 98), we are having the following problem:
2678 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2679 * requests to look up "desktop.ini" in all the subdirectories.
2680 * This can cause zillions of timeouts looking up non-existent cells
2681 * and volumes, especially in the top-level directory.
2683 * We have not found any way to avoid this or work around it except
2684 * to explicitly ignore the requests for mount points that haven't
2685 * yet been evaluated and for directories that haven't yet been
2688 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2689 spacep = cm_GetSpace();
2690 smb_StripLastComponent(spacep->data, &lastComp,
2691 (char *)(&p->parmsp[3]));
2692 #ifndef SPECIAL_FOLDERS
2693 /* Make sure that lastComp is not NULL */
2695 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2696 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2700 userp, tidPathp, &req, &dscp);
2703 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2704 if ( WANTS_DFS_PATHNAMES(p) )
2705 code = CM_ERROR_PATH_NOT_COVERED;
2707 code = CM_ERROR_BADSHARENAME;
2709 #endif /* DFS_SUPPORT */
2710 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2711 code = CM_ERROR_NOSUCHFILE;
2712 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2713 cm_buf_t *bp = buf_Find(dscp, &hzero);
2717 code = CM_ERROR_NOSUCHFILE;
2719 cm_ReleaseSCache(dscp);
2721 cm_FreeSpace(spacep);
2722 cm_ReleaseUser(userp);
2723 smb_SendTran2Error(vcp, p, opx, code);
2724 smb_FreeTran2Packet(outp);
2730 #endif /* SPECIAL_FOLDERS */
2732 cm_FreeSpace(spacep);
2735 /* now do namei and stat, and copy out the info */
2736 code = cm_NameI(cm_data.rootSCachep, (char *)(&p->parmsp[3]),
2737 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2740 cm_ReleaseUser(userp);
2741 smb_SendTran2Error(vcp, p, opx, code);
2742 smb_FreeTran2Packet(outp);
2747 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2748 cm_ReleaseSCache(scp);
2749 cm_ReleaseUser(userp);
2750 if ( WANTS_DFS_PATHNAMES(p) )
2751 code = CM_ERROR_PATH_NOT_COVERED;
2753 code = CM_ERROR_BADSHARENAME;
2754 smb_SendTran2Error(vcp, p, opx, code);
2755 smb_FreeTran2Packet(outp);
2758 #endif /* DFS_SUPPORT */
2760 lock_ObtainMutex(&scp->mx);
2761 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2762 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2763 if (code) goto done;
2765 /* now we have the status in the cache entry, and everything is locked.
2766 * Marshall the output data.
2769 /* for info level 108, figure out short name */
2770 if (infoLevel == 0x108) {
2771 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
2772 tidPathp, scp->fid.vnode, shortName,
2779 *((u_long *)op) = len * 2; op += 4;
2780 mbstowcs((unsigned short *)op, shortName, len);
2785 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2786 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2787 *((u_long *)op) = dosTime; op += 4; /* creation time */
2788 *((u_long *)op) = dosTime; op += 4; /* access time */
2789 *((u_long *)op) = dosTime; op += 4; /* write time */
2790 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
2791 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
2792 attributes = smb_Attributes(scp);
2793 *((u_short *)op) = attributes; op += 2; /* attributes */
2795 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2796 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2797 *((FILETIME *)op) = ft; op += 8; /* creation time */
2798 *((FILETIME *)op) = ft; op += 8; /* last access time */
2799 *((FILETIME *)op) = ft; op += 8; /* last write time */
2800 *((FILETIME *)op) = ft; op += 8; /* last change time */
2801 extAttributes = smb_ExtAttributes(scp);
2802 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
2803 *((u_long *)op) = 0; op += 4; /* don't know what this is */
2805 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2806 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2807 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2808 *((u_long *)op) = scp->linkCount; op += 4;
2811 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2814 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2815 memset(op, 0, 4); op += 4; /* EA size */
2818 /* now, if we are being asked about extended attrs, return a 0 size */
2819 if (infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2820 *((u_long *)op) = 0; op += 4;
2824 /* send and free the packets */
2826 lock_ReleaseMutex(&scp->mx);
2827 cm_ReleaseSCache(scp);
2828 cm_ReleaseUser(userp);
2830 smb_SendTran2Packet(vcp, outp, opx);
2832 smb_SendTran2Error(vcp, p, opx, code);
2833 smb_FreeTran2Packet(outp);
2838 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2840 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2841 return CM_ERROR_BADOP;
2844 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2846 smb_tran2Packet_t *outp;
2848 unsigned long attributes;
2849 unsigned short infoLevel;
2862 fidp = smb_FindFID(vcp, fid, 0);
2865 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2869 infoLevel = p->parmsp[1];
2870 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2871 nbytesRequired = 40;
2872 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2873 nbytesRequired = 24;
2874 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2876 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2879 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2880 p->opcode, infoLevel);
2881 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2882 smb_ReleaseFID(fidp);
2885 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2887 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2889 if (infoLevel > 0x100)
2890 outp->totalParms = 2;
2892 outp->totalParms = 0;
2893 outp->totalData = nbytesRequired;
2895 userp = smb_GetTran2User(vcp, p);
2897 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2898 code = CM_ERROR_BADSMB;
2903 lock_ObtainMutex(&scp->mx);
2904 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2905 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2909 /* now we have the status in the cache entry, and everything is locked.
2910 * Marshall the output data.
2913 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2914 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2915 *((FILETIME *)op) = ft; op += 8; /* creation time */
2916 *((FILETIME *)op) = ft; op += 8; /* last access time */
2917 *((FILETIME *)op) = ft; op += 8; /* last write time */
2918 *((FILETIME *)op) = ft; op += 8; /* last change time */
2919 attributes = smb_ExtAttributes(scp);
2920 *((u_long *)op) = attributes; op += 4;
2921 *((u_long *)op) = 0; op += 4;
2923 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2924 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2925 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2926 *((u_long *)op) = scp->linkCount; op += 4;
2927 lock_ObtainMutex(&fidp->mx);
2928 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
2929 lock_ReleaseMutex(&fidp->mx);
2930 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2934 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2935 *((u_long *)op) = 0; op += 4;
2937 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2941 if (fidp->NTopen_wholepathp)
2942 name = fidp->NTopen_wholepathp;
2944 name = "\\"; /* probably can't happen */
2945 len = (unsigned long)strlen(name);
2946 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
2947 *((u_long *)op) = len * 2; op += 4;
2948 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2951 /* send and free the packets */
2953 lock_ReleaseMutex(&scp->mx);
2954 cm_ReleaseUser(userp);
2955 smb_ReleaseFID(fidp);
2957 smb_SendTran2Packet(vcp, outp, opx);
2959 smb_SendTran2Error(vcp, p, opx, code);
2960 smb_FreeTran2Packet(outp);
2965 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2970 unsigned short infoLevel;
2971 smb_tran2Packet_t *outp;
2979 fidp = smb_FindFID(vcp, fid, 0);
2982 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
2986 infoLevel = p->parmsp[1];
2987 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type=[%x] fid=[%x]", infoLevel, fid);
2988 if (infoLevel > 0x104 || infoLevel < 0x101) {
2989 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2990 p->opcode, infoLevel);
2991 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
2992 smb_ReleaseFID(fidp);
2996 lock_ObtainMutex(&fidp->mx);
2997 if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) {
2998 lock_ReleaseMutex(&fidp->mx);
2999 smb_ReleaseFID(fidp);
3000 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
3003 if ((infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO)
3004 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3005 lock_ReleaseMutex(&fidp->mx);
3006 smb_ReleaseFID(fidp);
3007 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
3010 lock_ReleaseMutex(&fidp->mx);
3012 osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
3014 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
3016 outp->totalParms = 2;
3017 outp->totalData = 0;
3019 userp = smb_GetTran2User(vcp, p);
3021 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3022 code = CM_ERROR_BADSMB;
3028 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3030 unsigned int attribute;
3033 /* lock the vnode with a callback; we need the current status
3034 * to determine what the new status is, in some cases.
3036 lock_ObtainMutex(&scp->mx);
3037 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3038 CM_SCACHESYNC_GETSTATUS
3039 | CM_SCACHESYNC_NEEDCALLBACK);
3041 lock_ReleaseMutex(&scp->mx);
3045 /* prepare for setattr call */
3048 lastMod = *((FILETIME *)(p->datap + 16));
3049 /* when called as result of move a b, lastMod is (-1, -1).
3050 * If the check for -1 is not present, timestamp
3051 * of the resulting file will be 1969 (-1)
3053 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3054 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3055 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3056 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3057 lock_ObtainMutex(&fidp->mx);
3058 fidp->flags |= SMB_FID_MTIMESETDONE;
3059 lock_ReleaseMutex(&fidp->mx);
3062 attribute = *((u_long *)(p->datap + 32));
3063 if (attribute != 0) {
3064 if ((scp->unixModeBits & 0222)
3065 && (attribute & 1) != 0) {
3066 /* make a writable file read-only */
3067 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3068 attr.unixModeBits = scp->unixModeBits & ~0222;
3070 else if ((scp->unixModeBits & 0222) == 0
3071 && (attribute & 1) == 0) {
3072 /* make a read-only file writable */
3073 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3074 attr.unixModeBits = scp->unixModeBits | 0222;
3077 lock_ReleaseMutex(&scp->mx);
3081 code = cm_SetAttr(scp, &attr, userp, &req);
3085 else if (infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3086 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3089 attr.mask = CM_ATTRMASK_LENGTH;
3090 attr.length.LowPart = size.LowPart;
3091 attr.length.HighPart = size.HighPart;
3092 code = cm_SetAttr(scp, &attr, userp, &req);
3094 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3095 if (*((char *)(p->datap))) {
3096 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3099 lock_ObtainMutex(&fidp->mx);
3100 fidp->flags |= SMB_FID_DELONCLOSE;
3101 lock_ReleaseMutex(&fidp->mx);
3106 lock_ObtainMutex(&fidp->mx);
3107 fidp->flags &= ~SMB_FID_DELONCLOSE;
3108 lock_ReleaseMutex(&fidp->mx);
3113 cm_ReleaseUser(userp);
3114 smb_ReleaseFID(fidp);
3116 smb_SendTran2Packet(vcp, outp, op);
3118 smb_SendTran2Error(vcp, p, op, code);
3119 smb_FreeTran2Packet(outp);
3125 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3127 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3128 return CM_ERROR_BADOP;
3132 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3134 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3135 return CM_ERROR_BADOP;
3139 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3141 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3142 return CM_ERROR_BADOP;
3146 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3148 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3149 return CM_ERROR_BADOP;
3153 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3155 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3156 return CM_ERROR_BADOP;
3160 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3162 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3163 return CM_ERROR_BADOP;
3166 struct smb_v2_referral {
3168 USHORT ReferralFlags;
3171 USHORT DfsPathOffset;
3172 USHORT DfsAlternativePathOffset;
3173 USHORT NetworkAddressOffset;
3177 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3179 /* This is a UNICODE only request (bit15 of Flags2) */
3180 /* The TID must be IPC$ */
3182 /* The documentation for the Flags response field is contradictory */
3184 /* Use Version 1 Referral Element Format */
3185 /* ServerType = 0; indicates the next server should be queried for the file */
3186 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3187 /* Node = UnicodeString of UNC path of the next share name */
3190 int maxReferralLevel = 0;
3191 char requestFileName[1024] = "";
3192 smb_tran2Packet_t *outp = 0;
3193 cm_user_t *userp = 0;
3195 CPINFO CodePageInfo;
3196 int i, nbnLen, reqLen;
3201 maxReferralLevel = p->parmsp[0];
3203 GetCPInfo(CP_ACP, &CodePageInfo);
3204 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
3205 requestFileName, 1024, NULL, NULL);
3207 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
3208 maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3210 nbnLen = strlen(cm_NetbiosName);
3211 reqLen = strlen(requestFileName);
3213 if (reqLen == nbnLen + 5 &&
3214 requestFileName[0] == '\\' &&
3215 !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3216 requestFileName[nbnLen+1] == '\\' &&
3217 !_strnicmp("all",&requestFileName[nbnLen+2],3))
3220 struct smb_v2_referral * v2ref;
3221 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
3223 sp = (USHORT *)outp->datap;
3225 sp[idx++] = reqLen; /* path consumed */
3226 sp[idx++] = 1; /* number of referrals */
3227 sp[idx++] = 0x03; /* flags */
3228 #ifdef DFS_VERSION_1
3229 sp[idx++] = 1; /* Version Number */
3230 sp[idx++] = reqLen + 4; /* Referral Size */
3231 sp[idx++] = 1; /* Type = SMB Server */
3232 sp[idx++] = 0; /* Do not strip path consumed */
3233 for ( i=0;i<=reqLen; i++ )
3234 sp[i+idx] = requestFileName[i];
3235 #else /* DFS_VERSION_2 */
3236 sp[idx++] = 2; /* Version Number */
3237 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3238 idx += (sizeof(struct smb_v2_referral) / 2);
3239 v2ref = (struct smb_v2_referral *) &sp[5];
3240 v2ref->ServerType = 1; /* SMB Server */
3241 v2ref->ReferralFlags = 0x03;
3242 v2ref->Proximity = 0; /* closest */
3243 v2ref->TimeToLive = 3600; /* seconds */
3244 v2ref->DfsPathOffset = idx * 2;
3245 v2ref->DfsAlternativePathOffset = idx * 2;
3246 v2ref->NetworkAddressOffset = 0;
3247 for ( i=0;i<=reqLen; i++ )
3248 sp[i+idx] = requestFileName[i];
3251 userp = smb_GetTran2User(vcp, p);
3253 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3254 code = CM_ERROR_BADSMB;
3259 code = CM_ERROR_NOSUCHPATH;
3264 cm_ReleaseUser(userp);
3266 smb_SendTran2Packet(vcp, outp, op);
3268 smb_SendTran2Error(vcp, p, op, code);
3270 smb_FreeTran2Packet(outp);
3273 #else /* DFS_SUPPORT */
3274 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3275 return CM_ERROR_BADOP;
3276 #endif /* DFS_SUPPORT */
3280 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3282 /* This is a UNICODE only request (bit15 of Flags2) */
3284 /* There is nothing we can do about this operation. The client is going to
3285 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3286 * Unfortunately, there is really nothing we can do about it other then log it
3287 * somewhere. Even then I don't think there is anything for us to do.
3288 * So let's return an error value.
3291 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3292 return CM_ERROR_BADOP;
3296 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3297 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3302 cm_scache_t *targetScp; /* target if scp is a symlink */
3307 unsigned short attr;
3308 unsigned long lattr;
3309 smb_dirListPatch_t *patchp;
3310 smb_dirListPatch_t *npatchp;
3312 for(patchp = *dirPatchespp; patchp; patchp =
3313 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3314 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3316 lock_ObtainMutex(&scp->mx);
3317 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3318 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3320 lock_ReleaseMutex(&scp->mx);
3321 cm_ReleaseSCache(scp);
3323 dptr = patchp->dptr;
3325 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3326 errors in the client. */
3327 if (infoLevel >= 0x101) {
3328 /* 1969-12-31 23:59:59 +00 */
3329 ft.dwHighDateTime = 0x19DB200;
3330 ft.dwLowDateTime = 0x5BB78980;
3332 /* copy to Creation Time */
3333 *((FILETIME *)dptr) = ft;
3336 /* copy to Last Access Time */
3337 *((FILETIME *)dptr) = ft;
3340 /* copy to Last Write Time */
3341 *((FILETIME *)dptr) = ft;
3344 /* copy to Change Time */
3345 *((FILETIME *)dptr) = ft;
3348 /* merge in hidden attribute */
3349 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3350 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3354 /* 1969-12-31 23:59:58 +00*/
3355 dosTime = 0xEBBFBF7D;
3357 /* and copy out date */
3358 shortTemp = (dosTime>>16) & 0xffff;
3359 *((u_short *)dptr) = shortTemp;
3362 /* copy out creation time */
3363 shortTemp = dosTime & 0xffff;
3364 *((u_short *)dptr) = shortTemp;
3367 /* and copy out date */
3368 shortTemp = (dosTime>>16) & 0xffff;
3369 *((u_short *)dptr) = shortTemp;
3372 /* copy out access 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 mod time */
3383 shortTemp = dosTime & 0xffff;
3384 *((u_short *)dptr) = shortTemp;
3387 /* merge in hidden (dot file) attribute */
3388 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3389 attr = SMB_ATTR_HIDDEN;
3390 *dptr++ = attr & 0xff;
3391 *dptr++ = (attr >> 8) & 0xff;
3397 /* now watch for a symlink */
3399 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3400 lock_ReleaseMutex(&scp->mx);
3401 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3403 /* we have a more accurate file to use (the
3404 * target of the symbolic link). Otherwise,
3405 * we'll just use the symlink anyway.
3407 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3409 cm_ReleaseSCache(scp);
3412 lock_ObtainMutex(&scp->mx);
3415 dptr = patchp->dptr;
3417 if (infoLevel >= 0x101) {
3419 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3421 /* copy to Creation Time */
3422 *((FILETIME *)dptr) = ft;
3425 /* copy to Last Access Time */
3426 *((FILETIME *)dptr) = ft;
3429 /* copy to Last Write Time */
3430 *((FILETIME *)dptr) = ft;
3433 /* copy to Change Time */
3434 *((FILETIME *)dptr) = ft;
3437 /* Use length for both file length and alloc length */
3438 *((LARGE_INTEGER *)dptr) = scp->length;
3440 *((LARGE_INTEGER *)dptr) = scp->length;
3443 /* Copy attributes */
3444 lattr = smb_ExtAttributes(scp);
3445 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3446 if (lattr == SMB_ATTR_NORMAL)
3447 lattr = SMB_ATTR_DIRECTORY;
3449 lattr |= SMB_ATTR_DIRECTORY;
3451 /* merge in hidden (dot file) attribute */
3452 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3453 if (lattr == SMB_ATTR_NORMAL)
3454 lattr = SMB_ATTR_HIDDEN;
3456 lattr |= SMB_ATTR_HIDDEN;
3458 *((u_long *)dptr) = lattr;
3462 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3464 /* and copy out date */
3465 shortTemp = (dosTime>>16) & 0xffff;
3466 *((u_short *)dptr) = shortTemp;
3469 /* copy out creation time */
3470 shortTemp = dosTime & 0xffff;
3471 *((u_short *)dptr) = shortTemp;
3474 /* and copy out date */
3475 shortTemp = (dosTime>>16) & 0xffff;
3476 *((u_short *)dptr) = shortTemp;
3479 /* copy out access 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 mod time */
3490 shortTemp = dosTime & 0xffff;
3491 *((u_short *)dptr) = shortTemp;
3494 /* copy out file length and alloc length,
3495 * using the same for both
3497 *((u_long *)dptr) = scp->length.LowPart;
3499 *((u_long *)dptr) = scp->length.LowPart;
3502 /* finally copy out attributes as short */
3503 attr = smb_Attributes(scp);
3504 /* merge in hidden (dot file) attribute */
3505 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3506 if (lattr == SMB_ATTR_NORMAL)
3507 lattr = SMB_ATTR_HIDDEN;
3509 lattr |= SMB_ATTR_HIDDEN;
3511 *dptr++ = attr & 0xff;
3512 *dptr++ = (attr >> 8) & 0xff;
3515 lock_ReleaseMutex(&scp->mx);
3516 cm_ReleaseSCache(scp);
3519 /* now free the patches */
3520 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3521 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3525 /* and mark the list as empty */
3526 *dirPatchespp = NULL;
3531 #ifndef USE_OLD_MATCHING
3532 // char table for case insensitive comparison
3533 char mapCaseTable[256];
3535 VOID initUpperCaseTable(VOID)
3538 for (i = 0; i < 256; ++i)
3539 mapCaseTable[i] = toupper(i);
3540 // make '"' match '.'
3541 mapCaseTable[(int)'"'] = toupper('.');
3542 // make '<' match '*'
3543 mapCaseTable[(int)'<'] = toupper('*');
3544 // make '>' match '?'
3545 mapCaseTable[(int)'>'] = toupper('?');
3548 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3550 // Note : this procedure works recursively calling itself.
3552 // PSZ pattern : string containing metacharacters.
3553 // PSZ name : file name to be compared with 'pattern'.
3555 // BOOL : TRUE/FALSE (match/mistmatch)
3558 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
3560 PSZ pename; // points to the last 'name' character
3562 pename = name + strlen(name) - 1;
3573 if (*pattern == '\0')
3575 for (p = pename; p >= name; --p) {
3576 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
3577 !casefold && (*p == *pattern)) &&
3578 szWildCardMatchFileName(pattern + 1, p + 1, casefold))
3583 if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
3584 (!casefold && *name != *pattern))
3591 /* if all we have left are wildcards, then we match */
3592 for (;*pattern; pattern++) {
3593 if (*pattern != '*' && *pattern != '?')
3599 /* do a case-folding search of the star name mask with the name in namep.
3600 * Return 1 if we match, otherwise 0.
3602 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3605 int i, j, star, qmark, casefold, retval;
3607 /* make sure we only match 8.3 names, if requested */
3608 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3611 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
3613 /* optimize the pattern:
3614 * if there is a mixture of '?' and '*',
3615 * for example the sequence "*?*?*?*"
3616 * must be turned into the form "*"
3618 newmask = (char *)malloc(strlen(maskp)+1);
3619 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3620 switch ( maskp[i] ) {
3632 } else if ( qmark ) {
3636 newmask[j++] = maskp[i];
3643 } else if ( qmark ) {
3647 newmask[j++] = '\0';
3649 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
3655 #else /* USE_OLD_MATCHING */
3656 /* do a case-folding search of the star name mask with the name in namep.
3657 * Return 1 if we match, otherwise 0.
3659 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3661 unsigned char tcp1, tcp2; /* Pattern characters */
3662 unsigned char tcn1; /* Name characters */
3663 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3664 char *starNamep, *starMaskp;
3665 static char nullCharp[] = {0};
3666 int casefold = flags & CM_FLAG_CASEFOLD;
3668 /* make sure we only match 8.3 names, if requested */
3669 req8dot3 = (flags & CM_FLAG_8DOT3);
3670 if (req8dot3 && !cm_Is8Dot3(namep))
3675 /* Next pattern character */
3678 /* Next name character */
3682 /* 0 - end of pattern */
3688 else if (tcp1 == '.' || tcp1 == '"') {
3698 * first dot in pattern;
3699 * must match dot or end of name
3704 else if (tcn1 == '.') {
3713 else if (tcp1 == '?') {
3714 if (tcn1 == 0 || tcn1 == '.')
3719 else if (tcp1 == '>') {
3720 if (tcn1 != 0 && tcn1 != '.')
3724 else if (tcp1 == '*' || tcp1 == '<') {
3728 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3729 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3744 * pattern character after '*' is not null or
3745 * period. If it is '?' or '>', we are not
3746 * going to understand it. If it is '*' or
3747 * '<', we are going to skip over it. None of
3748 * these are likely, I hope.
3750 /* skip over '*' and '<' */
3751 while (tcp2 == '*' || tcp2 == '<')
3754 /* skip over characters that don't match tcp2 */
3755 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
3756 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
3757 (!casefold && tcn1 != tcp2)))
3761 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3764 /* Remember where we are */
3774 /* tcp1 is not a wildcard */
3775 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
3776 (!casefold && tcn1 == tcp1)) {
3781 /* if trying to match a star pattern, go back */
3783 maskp = starMaskp - 2;
3784 namep = starNamep + 1;
3793 #endif /* USE_OLD_MATCHING */
3795 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3800 long code = 0, code2 = 0;
3804 smb_dirListPatch_t *dirListPatchesp;
3805 smb_dirListPatch_t *curPatchp;
3808 long orbytes; /* # of bytes in this output record */
3809 long ohbytes; /* # of bytes, except file name */
3810 long onbytes; /* # of bytes in name, incl. term. null */
3811 osi_hyper_t dirLength;
3812 osi_hyper_t bufferOffset;
3813 osi_hyper_t curOffset;
3815 smb_dirSearch_t *dsp;
3819 cm_pageHeader_t *pageHeaderp;
3820 cm_user_t *userp = NULL;
3823 long nextEntryCookie;
3824 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3825 char *op; /* output data ptr */
3826 char *origOp; /* original value of op */
3827 cm_space_t *spacep; /* for pathname buffer */
3828 long maxReturnData; /* max # of return data */
3829 long maxReturnParms; /* max # of return parms */
3830 long bytesInBuffer; /* # data bytes in the output buffer */
3832 char *maskp; /* mask part of path */
3836 smb_tran2Packet_t *outp; /* response packet */
3839 char shortName[13]; /* 8.3 name if needed */
3850 if (p->opcode == 1) {
3851 /* find first; obtain basic parameters from request */
3852 attribute = p->parmsp[0];
3853 maxCount = p->parmsp[1];
3854 infoLevel = p->parmsp[3];
3855 searchFlags = p->parmsp[2];
3856 dsp = smb_NewDirSearch(1);
3857 dsp->attribute = attribute;
3858 pathp = ((char *) p->parmsp) + 12; /* points to path */
3859 if (smb_StoreAnsiFilenames)
3860 OemToChar(pathp,pathp);
3862 maskp = strrchr(pathp, '\\');
3866 maskp++; /* skip over backslash */
3867 strcpy(dsp->mask, maskp); /* and save mask */
3868 /* track if this is likely to match a lot of entries */
3869 starPattern = smb_V3IsStarMask(maskp);
3872 osi_assert(p->opcode == 2);
3873 /* find next; obtain basic parameters from request or open dir file */
3874 dsp = smb_FindDirSearch(p->parmsp[0]);
3875 maxCount = p->parmsp[1];
3876 infoLevel = p->parmsp[2];
3877 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
3878 searchFlags = p->parmsp[5];
3880 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
3881 p->parmsp[0], nextCookie);
3882 return CM_ERROR_BADFD;
3884 attribute = dsp->attribute;
3887 starPattern = 1; /* assume, since required a Find Next */
3891 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
3892 attribute, infoLevel, maxCount, searchFlags);
3894 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
3895 p->opcode, dsp->cookie, nextCookie);
3897 if (infoLevel >= 0x101)
3898 searchFlags &= ~4; /* no resume keys */
3900 dirListPatchesp = NULL;
3902 maxReturnData = p->maxReturnData;
3903 if (p->opcode == 1) /* find first */
3904 maxReturnParms = 10; /* bytes */
3906 maxReturnParms = 8; /* bytes */
3908 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
3909 if (maxReturnData > 6000)
3910 maxReturnData = 6000;
3911 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
3913 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
3916 osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
3917 maxCount, osi_LogSaveString(smb_logp, pathp));
3919 /* bail out if request looks bad */
3920 if (p->opcode == 1 && !pathp) {
3921 smb_ReleaseDirSearch(dsp);
3922 smb_FreeTran2Packet(outp);
3923 return CM_ERROR_BADSMB;
3926 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
3927 dsp->cookie, nextCookie, attribute);
3929 userp = smb_GetTran2User(vcp, p);
3931 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
3932 smb_ReleaseDirSearch(dsp);
3933 smb_FreeTran2Packet(outp);
3934 return CM_ERROR_BADSMB;
3937 /* try to get the vnode for the path name next */
3938 lock_ObtainMutex(&dsp->mx);
3944 spacep = cm_GetSpace();
3945 smb_StripLastComponent(spacep->data, NULL, pathp);
3946 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3948 cm_ReleaseUser(userp);
3949 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
3950 smb_FreeTran2Packet(outp);
3951 lock_ReleaseMutex(&dsp->mx);
3952 smb_DeleteDirSearch(dsp);
3953 smb_ReleaseDirSearch(dsp);
3956 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3957 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3958 userp, tidPathp, &req, &scp);
3959 cm_FreeSpace(spacep);
3962 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
3963 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3964 cm_ReleaseSCache(scp);
3965 cm_ReleaseUser(userp);
3966 if ( WANTS_DFS_PATHNAMES(p) )
3967 code = CM_ERROR_PATH_NOT_COVERED;
3969 code = CM_ERROR_BADSHARENAME;
3970 smb_SendTran2Error(vcp, p, opx, code);
3971 smb_FreeTran2Packet(outp);
3972 lock_ReleaseMutex(&dsp->mx);
3973 smb_DeleteDirSearch(dsp);
3974 smb_ReleaseDirSearch(dsp);
3977 #endif /* DFS_SUPPORT */
3979 /* we need one hold for the entry we just stored into,
3980 * and one for our own processing. When we're done
3981 * with this function, we'll drop the one for our own
3982 * processing. We held it once from the namei call,
3983 * and so we do another hold now.
3986 lock_ObtainMutex(&scp->mx);
3987 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
3988 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3989 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3990 dsp->flags |= SMB_DIRSEARCH_BULKST;
3992 lock_ReleaseMutex(&scp->mx);
3995 lock_ReleaseMutex(&dsp->mx);
3997 cm_ReleaseUser(userp);
3998 smb_FreeTran2Packet(outp);
3999 smb_DeleteDirSearch(dsp);
4000 smb_ReleaseDirSearch(dsp);
4004 /* get the directory size */
4005 lock_ObtainMutex(&scp->mx);
4006 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4007 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4009 lock_ReleaseMutex(&scp->mx);
4010 cm_ReleaseSCache(scp);
4011 cm_ReleaseUser(userp);
4012 smb_FreeTran2Packet(outp);
4013 smb_DeleteDirSearch(dsp);
4014 smb_ReleaseDirSearch(dsp);
4019 dirLength = scp->length;
4021 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4022 curOffset.HighPart = 0;
4023 curOffset.LowPart = nextCookie;
4024 origOp = outp->datap;
4032 if (searchFlags & 4)
4033 /* skip over resume key */
4036 /* make sure that curOffset.LowPart doesn't point to the first
4037 * 32 bytes in the 2nd through last dir page, and that it doesn't
4038 * point at the first 13 32-byte chunks in the first dir page,
4039 * since those are dir and page headers, and don't contain useful
4042 temp = curOffset.LowPart & (2048-1);
4043 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4044 /* we're in the first page */
4045 if (temp < 13*32) temp = 13*32;
4048 /* we're in a later dir page */
4049 if (temp < 32) temp = 32;
4052 /* make sure the low order 5 bits are zero */
4055 /* now put temp bits back ito curOffset.LowPart */
4056 curOffset.LowPart &= ~(2048-1);
4057 curOffset.LowPart |= temp;
4059 /* check if we've passed the dir's EOF */
4060 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4061 osi_Log0(smb_logp, "T2 search dir passed eof");
4066 /* check if we've returned all the names that will fit in the
4067 * response packet; we check return count as well as the number
4068 * of bytes requested. We check the # of bytes after we find
4069 * the dir entry, since we'll need to check its size.
4071 if (returnedNames >= maxCount) {
4072 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4073 returnedNames, maxCount);
4077 /* see if we can use the bufferp we have now; compute in which
4078 * page the current offset would be, and check whether that's
4079 * the offset of the buffer we have. If not, get the buffer.
4081 thyper.HighPart = curOffset.HighPart;
4082 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4083 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4086 buf_Release(bufferp);
4089 lock_ReleaseMutex(&scp->mx);
4090 lock_ObtainRead(&scp->bufCreateLock);
4091 code = buf_Get(scp, &thyper, &bufferp);
4092 lock_ReleaseRead(&scp->bufCreateLock);
4093 lock_ObtainMutex(&dsp->mx);
4095 /* now, if we're doing a star match, do bulk fetching
4096 * of all of the status info for files in the dir.
4099 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
4102 lock_ObtainMutex(&scp->mx);
4103 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4104 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
4105 /* Don't bulk stat if risking timeout */
4106 int now = GetTickCount();
4107 if (now - req.startTime > 5000) {
4108 scp->bulkStatProgress = thyper;
4109 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4110 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4112 cm_TryBulkStat(scp, &thyper, userp, &req);
4115 lock_ObtainMutex(&scp->mx);
4117 lock_ReleaseMutex(&dsp->mx);
4119 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
4123 bufferOffset = thyper;
4125 /* now get the data in the cache */
4127 code = cm_SyncOp(scp, bufferp, userp, &req,
4129 CM_SCACHESYNC_NEEDCALLBACK
4130 | CM_SCACHESYNC_READ);
4132 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
4136 if (cm_HaveBuffer(scp, bufferp, 0)) {
4137 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4141 /* otherwise, load the buffer and try again */
4142 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4145 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4146 scp, bufferp, code);
4151 buf_Release(bufferp);
4155 } /* if (wrong buffer) ... */
4157 /* now we have the buffer containing the entry we're interested
4158 * in; copy it out if it represents a non-deleted entry.
4160 entryInDir = curOffset.LowPart & (2048-1);
4161 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4163 /* page header will help tell us which entries are free. Page
4164 * header can change more often than once per buffer, since
4165 * AFS 3 dir page size may be less than (but not more than)
4166 * a buffer package buffer.
4168 /* only look intra-buffer */
4169 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4170 temp &= ~(2048 - 1); /* turn off intra-page bits */
4171 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4173 /* now determine which entry we're looking at in the page.
4174 * If it is free (there's a free bitmap at the start of the
4175 * dir), we should skip these 32 bytes.
4177 slotInPage = (entryInDir & 0x7e0) >> 5;
4178 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
4179 (1 << (slotInPage & 0x7)))) {
4180 /* this entry is free */
4181 numDirChunks = 1; /* only skip this guy */
4185 tp = bufferp->datap + entryInBuffer;
4186 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4188 /* while we're here, compute the next entry's location, too,
4189 * since we'll need it when writing out the cookie into the dir
4192 * XXXX Probably should do more sanity checking.
4194 numDirChunks = cm_NameEntries(dep->name, &onbytes);
4196 /* compute offset of cookie representing next entry */
4197 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4199 /* Need 8.3 name? */
4201 if (infoLevel == SMB_QUERY_FILE_NAME_INFO
4202 && dep->fid.vnode != 0
4203 && !cm_Is8Dot3(dep->name)) {
4204 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4208 osi_Log3(smb_logp, "T2 search dir vn %u name %s (%s)",
4209 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4210 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4212 /* When matching, we are using doing a case fold if we have a wildcard mask.
4213 * If we get a non-wildcard match, it's a lookup for a specific file.
4215 if (dep->fid.vnode != 0 &&
4216 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
4218 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
4220 /* Eliminate entries that don't match requested attributes */
4221 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
4222 smb_IsDotFile(dep->name)) {
4223 osi_Log0(smb_logp, "T2 search dir skipping hidden");
4224 goto nextEntry; /* no hidden files */
4226 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4228 /* We have already done the cm_TryBulkStat above */
4229 fid.cell = scp->fid.cell;
4230 fid.volume = scp->fid.volume;
4231 fid.vnode = ntohl(dep->fid.vnode);
4232 fid.unique = ntohl(dep->fid.unique);
4233 fileType = cm_FindFileType(&fid);
4234 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
4235 "has filetype %d", dep->name,
4237 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4238 fileType == CM_SCACHETYPE_DFSLINK ||
4239 fileType == CM_SCACHETYPE_INVALID)
4240 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
4244 /* finally check if this name will fit */
4246 /* standard dir entry stuff */
4247 if (infoLevel < 0x101)
4248 ohbytes = 23; /* pre-NT */
4249 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
4250 ohbytes = 12; /* NT names only */
4252 ohbytes = 64; /* NT */
4254 if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
4255 ohbytes += 26; /* Short name & length */
4257 if (searchFlags & 4) {
4258 ohbytes += 4; /* if resume key required */
4262 && infoLevel != 0x101
4263 && infoLevel != 0x103)
4264 ohbytes += 4; /* EASIZE */
4266 /* add header to name & term. null */
4267 orbytes = onbytes + ohbytes + 1;
4269 /* now, we round up the record to a 4 byte alignment,
4270 * and we make sure that we have enough room here for
4271 * even the aligned version (so we don't have to worry
4272 * about an * overflow when we pad things out below).
4273 * That's the reason for the alignment arithmetic below.
4275 if (infoLevel >= 0x101)
4276 align = (4 - (orbytes & 3)) & 3;
4279 if (orbytes + bytesInBuffer + align > maxReturnData) {
4280 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4285 /* this is one of the entries to use: it is not deleted
4286 * and it matches the star pattern we're looking for.
4287 * Put out the name, preceded by its length.
4289 /* First zero everything else */
4290 memset(origOp, 0, ohbytes);
4292 if (infoLevel <= 0x101)
4293 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4294 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
4295 *((u_long *)(op + 8)) = onbytes;
4297 *((u_long *)(op + 60)) = onbytes;
4298 strcpy(origOp+ohbytes, dep->name);
4299 if (smb_StoreAnsiFilenames)
4300 CharToOem(origOp+ohbytes, origOp+ohbytes);
4302 /* Short name if requested and needed */
4303 if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
4304 if (NeedShortName) {
4305 strcpy(op + 70, shortName);
4306 if (smb_StoreAnsiFilenames)
4307 CharToOem(op + 70, op + 70);
4308 *(op + 68) = (char)(shortNameEnd - shortName);
4312 /* now, adjust the # of entries copied */
4315 /* NextEntryOffset and FileIndex */
4316 if (infoLevel >= 101) {
4317 int entryOffset = orbytes + align;
4318 *((u_long *)op) = entryOffset;
4319 *((u_long *)(op+4)) = nextEntryCookie;
4322 /* now we emit the attribute. This is tricky, since
4323 * we need to really stat the file to find out what
4324 * type of entry we've got. Right now, we're copying
4325 * out data from a buffer, while holding the scp
4326 * locked, so it isn't really convenient to stat
4327 * something now. We'll put in a place holder
4328 * now, and make a second pass before returning this
4329 * to get the real attributes. So, we just skip the
4330 * data for now, and adjust it later. We allocate a
4331 * patch record to make it easy to find this point
4332 * later. The replay will happen at a time when it is
4333 * safe to unlock the directory.
4335 if (infoLevel != 0x103) {
4336 curPatchp = malloc(sizeof(*curPatchp));
4337 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4339 curPatchp->dptr = op;
4340 if (infoLevel >= 0x101)
4341 curPatchp->dptr += 8;
4343 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4344 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4347 curPatchp->flags = 0;
4349 curPatchp->fid.cell = scp->fid.cell;
4350 curPatchp->fid.volume = scp->fid.volume;
4351 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4352 curPatchp->fid.unique = ntohl(dep->fid.unique);
4355 curPatchp->dep = dep;
4358 if (searchFlags & 4)
4359 /* put out resume key */
4360 *((u_long *)origOp) = nextEntryCookie;
4362 /* Adjust byte ptr and count */
4363 origOp += orbytes; /* skip entire record */
4364 bytesInBuffer += orbytes;
4366 /* and pad the record out */
4367 while (--align >= 0) {
4371 } /* if we're including this name */
4372 else if (!starPattern &&
4374 dep->fid.vnode != 0 &&
4375 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4376 /* We were looking for exact matches, but here's an inexact one*/
4381 /* and adjust curOffset to be where the new cookie is */
4382 thyper.HighPart = 0;
4383 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4384 curOffset = LargeIntegerAdd(thyper, curOffset);
4385 } /* while copying data for dir listing */
4387 /* If we didn't get a star pattern, we did an exact match during the first pass.
4388 * If there were no exact matches found, we fail over to inexact matches by
4389 * marking the query as a star pattern (matches all case permutations), and
4390 * re-running the query.
4392 if (returnedNames == 0 && !starPattern && foundInexact) {
4393 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4398 /* release the mutex */
4399 lock_ReleaseMutex(&scp->mx);
4401 buf_Release(bufferp);
4403 /* apply and free last set of patches; if not doing a star match, this
4404 * will be empty, but better safe (and freeing everything) than sorry.
4406 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4409 /* now put out the final parameters */
4410 if (returnedNames == 0)
4412 if (p->opcode == 1) {
4414 outp->parmsp[0] = (unsigned short) dsp->cookie;
4415 outp->parmsp[1] = returnedNames;
4416 outp->parmsp[2] = eos;
4417 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4418 outp->parmsp[4] = 0;
4419 /* don't need last name to continue
4420 * search, cookie is enough. Normally,
4421 * this is the offset of the file name
4422 * of the last entry returned.
4424 outp->totalParms = 10; /* in bytes */
4428 outp->parmsp[0] = returnedNames;
4429 outp->parmsp[1] = eos;
4430 outp->parmsp[2] = 0; /* EAS error */
4431 outp->parmsp[3] = 0; /* last name, as above */
4432 outp->totalParms = 8; /* in bytes */
4435 /* return # of bytes in the buffer */
4436 outp->totalData = bytesInBuffer;
4438 /* Return error code if unsuccessful on first request */
4439 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4440 code = CM_ERROR_NOSUCHFILE;
4442 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
4443 p->opcode, dsp->cookie, returnedNames, code);
4445 /* if we're supposed to close the search after this request, or if
4446 * we're supposed to close the search if we're done, and we're done,
4447 * or if something went wrong, close the search.
4449 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4450 if ((searchFlags & 1) || (returnedNames == 0) ||
4451 ((searchFlags & 2) && eos) || code != 0)
4452 smb_DeleteDirSearch(dsp);
4454 smb_SendTran2Error(vcp, p, opx, code);
4456 smb_SendTran2Packet(vcp, outp, opx);
4458 smb_FreeTran2Packet(outp);
4459 smb_ReleaseDirSearch(dsp);
4460 cm_ReleaseSCache(scp);
4461 cm_ReleaseUser(userp);
4465 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4468 smb_dirSearch_t *dsp;
4470 dirHandle = smb_GetSMBParm(inp, 0);
4472 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4474 dsp = smb_FindDirSearch(dirHandle);
4477 return CM_ERROR_BADFD;
4479 /* otherwise, we have an FD to destroy */
4480 smb_DeleteDirSearch(dsp);
4481 smb_ReleaseDirSearch(dsp);
4483 /* and return results */
4484 smb_SetSMBDataLength(outp, 0);
4489 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4491 smb_SetSMBDataLength(outp, 0);
4495 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4502 cm_scache_t *dscp; /* dir we're dealing with */
4503 cm_scache_t *scp; /* file we're creating */
4505 int initialModeBits;
4515 int parmSlot; /* which parm we're dealing with */
4523 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4524 openFun = smb_GetSMBParm(inp, 8); /* open function */
4525 excl = ((openFun & 3) == 0);
4526 trunc = ((openFun & 3) == 2); /* truncate it */
4527 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4528 openAction = 0; /* tracks what we did */
4530 attributes = smb_GetSMBParm(inp, 5);
4531 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4533 /* compute initial mode bits based on read-only flag in attributes */
4534 initialModeBits = 0666;
4535 if (attributes & 1) initialModeBits &= ~0222;
4537 pathp = smb_GetSMBData(inp, NULL);
4538 if (smb_StoreAnsiFilenames)
4539 OemToChar(pathp,pathp);
4541 spacep = inp->spacep;
4542 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4544 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4545 /* special case magic file name for receiving IOCTL requests
4546 * (since IOCTL calls themselves aren't getting through).
4549 osi_Log0(smb_logp, "IOCTL Open");
4552 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4553 smb_SetupIoctlFid(fidp, spacep);
4555 /* set inp->fid so that later read calls in same msg can find fid */
4556 inp->fid = fidp->fid;
4558 /* copy out remainder of the parms */
4560 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4562 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4563 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4564 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4565 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4566 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4567 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4568 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4569 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4571 /* and the final "always present" stuff */
4572 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4573 /* next write out the "unique" ID */
4574 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4575 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4576 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4577 smb_SetSMBDataLength(outp, 0);
4579 /* and clean up fid reference */
4580 smb_ReleaseFID(fidp);
4584 #ifdef DEBUG_VERBOSE
4586 char *hexp, *asciip;
4587 asciip = (lastNamep ? lastNamep : pathp );
4588 hexp = osi_HexifyString(asciip);
4589 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4593 userp = smb_GetUserFromVCP(vcp, inp);
4596 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4598 cm_ReleaseUser(userp);
4599 return CM_ERROR_NOSUCHPATH;
4601 code = cm_NameI(cm_data.rootSCachep, pathp,
4602 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4603 userp, tidPathp, &req, &scp);
4606 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4607 cm_ReleaseSCache(scp);
4608 cm_ReleaseUser(userp);
4609 if ( WANTS_DFS_PATHNAMES(inp) )
4610 return CM_ERROR_PATH_NOT_COVERED;
4612 return CM_ERROR_BADSHARENAME;
4614 #endif /* DFS_SUPPORT */
4617 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4618 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4619 userp, tidPathp, &req, &dscp);
4621 cm_ReleaseUser(userp);
4626 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4627 cm_ReleaseSCache(dscp);
4628 cm_ReleaseUser(userp);
4629 if ( WANTS_DFS_PATHNAMES(inp) )
4630 return CM_ERROR_PATH_NOT_COVERED;
4632 return CM_ERROR_BADSHARENAME;
4634 #endif /* DFS_SUPPORT */
4636 /* otherwise, scp points to the parent directory. Do a lookup,
4637 * and truncate the file if we find it, otherwise we create the
4644 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
4646 if (code && code != CM_ERROR_NOSUCHFILE) {
4647 cm_ReleaseSCache(dscp);
4648 cm_ReleaseUser(userp);
4653 /* if we get here, if code is 0, the file exists and is represented by
4654 * scp. Otherwise, we have to create it. The dir may be represented
4655 * by dscp, or we may have found the file directly. If code is non-zero,
4659 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
4661 if (dscp) cm_ReleaseSCache(dscp);
4662 cm_ReleaseSCache(scp);
4663 cm_ReleaseUser(userp);
4668 /* oops, file shouldn't be there */
4670 cm_ReleaseSCache(dscp);
4671 cm_ReleaseSCache(scp);
4672 cm_ReleaseUser(userp);
4673 return CM_ERROR_EXISTS;
4677 setAttr.mask = CM_ATTRMASK_LENGTH;
4678 setAttr.length.LowPart = 0;
4679 setAttr.length.HighPart = 0;
4680 code = cm_SetAttr(scp, &setAttr, userp, &req);
4681 openAction = 3; /* truncated existing file */
4683 else openAction = 1; /* found existing file */
4685 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
4686 /* don't create if not found */
4687 if (dscp) cm_ReleaseSCache(dscp);
4688 cm_ReleaseUser(userp);
4689 return CM_ERROR_NOSUCHFILE;
4692 osi_assert(dscp != NULL);
4693 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
4694 osi_LogSaveString(smb_logp, lastNamep));
4695 openAction = 2; /* created file */
4696 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4697 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
4698 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4700 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4701 smb_NotifyChange(FILE_ACTION_ADDED,
4702 FILE_NOTIFY_CHANGE_FILE_NAME,
4703 dscp, lastNamep, NULL, TRUE);
4704 if (!excl && code == CM_ERROR_EXISTS) {
4705 /* not an exclusive create, and someone else tried
4706 * creating it already, then we open it anyway. We
4707 * don't bother retrying after this, since if this next
4708 * fails, that means that the file was deleted after we
4709 * started this call.
4711 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4715 setAttr.mask = CM_ATTRMASK_LENGTH;
4716 setAttr.length.LowPart = 0;
4717 setAttr.length.HighPart = 0;
4718 code = cm_SetAttr(scp, &setAttr, userp, &req);
4720 } /* lookup succeeded */
4724 /* we don't need this any longer */
4726 cm_ReleaseSCache(dscp);
4729 /* something went wrong creating or truncating the file */
4731 cm_ReleaseSCache(scp);
4732 cm_ReleaseUser(userp);
4736 /* make sure we're about to open a file */
4737 if (scp->fileType != CM_SCACHETYPE_FILE) {
4738 cm_ReleaseSCache(scp);
4739 cm_ReleaseUser(userp);
4740 return CM_ERROR_ISDIR;
4743 /* now all we have to do is open the file itself */
4744 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4748 lock_ObtainMutex(&fidp->mx);
4749 /* save a pointer to the vnode */
4752 fidp->userp = userp;
4754 /* compute open mode */
4756 fidp->flags |= SMB_FID_OPENREAD;
4757 if (openMode == 1 || openMode == 2)
4758 fidp->flags |= SMB_FID_OPENWRITE;
4760 lock_ReleaseMutex(&fidp->mx);
4761 smb_ReleaseFID(fidp);
4763 cm_Open(scp, 0, userp);
4765 /* set inp->fid so that later read calls in same msg can find fid */
4766 inp->fid = fidp->fid;
4768 /* copy out remainder of the parms */
4770 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4771 lock_ObtainMutex(&scp->mx);
4773 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
4774 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4775 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
4776 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
4777 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
4778 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
4779 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4780 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4781 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4783 /* and the final "always present" stuff */
4784 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
4785 /* next write out the "unique" ID */
4786 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
4787 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
4788 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4789 lock_ReleaseMutex(&scp->mx);
4790 smb_SetSMBDataLength(outp, 0);
4792 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
4794 cm_ReleaseUser(userp);
4795 /* leave scp held since we put it in fidp->scp */
4799 static void smb_GetLockParams(unsigned char LockType,
4801 unsigned int * ppid,
4802 LARGE_INTEGER * pOffset,
4803 LARGE_INTEGER * pLength)
4805 if (LockType & LOCKING_ANDX_LARGE_FILES) {
4807 *ppid = *((USHORT *) *buf);
4808 pOffset->HighPart = *((LONG *)(*buf + 4));
4809 pOffset->LowPart = *((DWORD *)(*buf + 8));
4810 pLength->HighPart = *((LONG *)(*buf + 12));
4811 pLength->LowPart = *((DWORD *)(*buf + 16));
4815 /* Not Large Files */
4816 *ppid = *((USHORT *) *buf);
4817 pOffset->HighPart = 0;
4818 pOffset->LowPart = *((DWORD *)(*buf + 2));
4819 pLength->HighPart = 0;
4820 pLength->LowPart = *((DWORD *)(*buf + 6));
4825 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4832 unsigned char LockType;
4833 unsigned short NumberOfUnlocks, NumberOfLocks;
4837 LARGE_INTEGER LOffset, LLength;
4838 smb_waitingLockRequest_t *wlRequest = NULL;
4839 cm_file_lock_t *lockp;
4847 fid = smb_GetSMBParm(inp, 2);
4848 fid = smb_ChainFID(fid, inp);
4850 fidp = smb_FindFID(vcp, fid, 0);
4852 return CM_ERROR_BADFD;
4854 lock_ObtainMutex(&fidp->mx);
4855 if (fidp->flags & SMB_FID_IOCTL) {
4856 osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
4857 lock_ReleaseMutex(&fidp->mx);
4858 smb_ReleaseFID(fidp);
4859 return CM_ERROR_BADFD;
4861 lock_ReleaseMutex(&fidp->mx);
4863 /* set inp->fid so that later read calls in same msg can find fid */
4866 userp = smb_GetUserFromVCP(vcp, inp);
4870 lock_ObtainMutex(&scp->mx);
4871 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4872 CM_SCACHESYNC_NEEDCALLBACK
4873 | CM_SCACHESYNC_GETSTATUS
4874 | CM_SCACHESYNC_LOCK);
4876 osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
4880 LockType = smb_GetSMBParm(inp, 3) & 0xff;
4881 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
4882 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
4883 NumberOfLocks = smb_GetSMBParm(inp, 7);
4885 if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
4886 (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
4888 /* We don't support these requests. Apparently, we can safely
4889 not deal with them too. */
4890 osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
4891 ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
4892 "LOCKING_ANDX_CANCEL_LOCK":
4893 "LOCKING_ANDX_CHANGE_LOCKTYPE"));
4894 /* No need to call osi_LogSaveString since these are string
4897 code = CM_ERROR_BADOP;
4902 op = smb_GetSMBData(inp, NULL);
4904 for (i=0; i<NumberOfUnlocks; i++) {
4905 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
4907 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
4909 code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
4917 for (i=0; i<NumberOfLocks; i++) {
4918 smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
4920 key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
4922 code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
4923 userp, &req, &lockp);
4925 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
4926 smb_waitingLock_t * wLock;
4928 /* Put on waiting list */
4929 if(wlRequest == NULL) {
4933 LARGE_INTEGER tOffset, tLength;
4935 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
4937 osi_assert(wlRequest != NULL);
4939 wlRequest->vcp = vcp;
4941 wlRequest->scp = scp;
4943 wlRequest->inp = smb_CopyPacket(inp);
4944 wlRequest->outp = smb_CopyPacket(outp);
4945 wlRequest->lockType = LockType;
4946 wlRequest->timeRemaining = Timeout;
4947 wlRequest->locks = NULL;
4949 /* The waiting lock request needs to have enough
4950 information to undo all the locks in the request.
4951 We do the following to store info about locks that
4952 have already been granted. Sure, we can get most
4953 of the info from the packet, but the packet doesn't
4954 hold the result of cm_Lock call. In practice we
4955 only receive packets with one or two locks, so we
4956 are only wasting a few bytes here and there and
4957 only for a limited period of time until the waiting
4958 lock times out or is freed. */
4960 for(opt = op_locks, j=i; j > 0; j--) {
4961 smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
4963 tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
4965 wLock = malloc(sizeof(smb_waitingLock_t));
4967 osi_assert(wLock != NULL);
4970 wLock->LOffset = tOffset;
4971 wLock->LLength = tLength;
4972 wLock->lockp = NULL;
4973 wLock->state = SMB_WAITINGLOCKSTATE_DONE;
4974 osi_QAdd((osi_queue_t **) &wlRequest->locks,
4979 wLock = malloc(sizeof(smb_waitingLock_t));
4981 osi_assert(wLock != NULL);
4984 wLock->LOffset = LOffset;
4985 wLock->LLength = LLength;
4986 wLock->lockp = lockp;
4987 wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
4988 osi_QAdd((osi_queue_t **) &wlRequest->locks,
4991 osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
4999 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
5006 /* Since something went wrong with the lock number i, we now
5007 have to go ahead and release any locks acquired before the
5008 failure. All locks before lock number i (of which there
5009 are i of them) have either been successful or are waiting.
5010 Either case requires calling cm_Unlock(). */
5012 /* And purge the waiting lock */
5013 if(wlRequest != NULL) {
5014 smb_waitingLock_t * wl;
5015 smb_waitingLock_t * wlNext;
5018 for(wl = wlRequest->locks; wl; wl = wlNext) {
5020 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
5022 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
5025 osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
5027 osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
5030 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
5035 smb_ReleaseVC(wlRequest->vcp);
5036 cm_ReleaseSCache(wlRequest->scp);
5037 smb_FreePacket(wlRequest->inp);
5038 smb_FreePacket(wlRequest->outp);
5047 if (wlRequest != NULL) {
5049 lock_ObtainWrite(&smb_globalLock);
5050 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
5052 osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
5053 lock_ReleaseWrite(&smb_globalLock);
5055 /* don't send reply immediately */
5056 outp->flags |= SMB_PACKETFLAG_NOSEND;
5059 smb_SetSMBDataLength(outp, 0);
5063 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5066 lock_ReleaseMutex(&scp->mx);
5067 cm_ReleaseUser(userp);
5068 smb_ReleaseFID(fidp);
5073 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5079 afs_uint32 searchTime;
5085 fid = smb_GetSMBParm(inp, 0);
5086 fid = smb_ChainFID(fid, inp);
5088 fidp = smb_FindFID(vcp, fid, 0);
5090 return CM_ERROR_BADFD;
5092 lock_ObtainMutex(&fidp->mx);
5093 if (fidp->flags & SMB_FID_IOCTL) {
5094 lock_ReleaseMutex(&fidp->mx);
5095 smb_ReleaseFID(fidp);
5096 return CM_ERROR_BADFD;
5098 lock_ReleaseMutex(&fidp->mx);
5100 userp = smb_GetUserFromVCP(vcp, inp);
5104 /* otherwise, stat the file */
5105 lock_ObtainMutex(&scp->mx);
5106 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5107 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5108 if (code) goto done;
5110 /* decode times. We need a search time, but the response to this
5111 * call provides the date first, not the time, as returned in the
5112 * searchTime variable. So we take the high-order bits first.
5114 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
5115 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
5116 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
5117 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
5118 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
5119 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
5120 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
5122 /* now handle file size and allocation size */
5123 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
5124 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
5125 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
5126 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
5128 /* file attribute */
5129 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
5131 /* and finalize stuff */
5132 smb_SetSMBDataLength(outp, 0);
5136 lock_ReleaseMutex(&scp->mx);
5137 cm_ReleaseUser(userp);
5138 smb_ReleaseFID(fidp);
5142 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5148 afs_uint32 searchTime;
5156 fid = smb_GetSMBParm(inp, 0);
5157 fid = smb_ChainFID(fid, inp);
5159 fidp = smb_FindFID(vcp, fid, 0);
5161 return CM_ERROR_BADFD;
5163 lock_ObtainMutex(&fidp->mx);
5164 if (fidp->flags & SMB_FID_IOCTL) {
5165 lock_ReleaseMutex(&fidp->mx);
5166 smb_ReleaseFID(fidp);
5167 return CM_ERROR_BADFD;
5169 lock_ReleaseMutex(&fidp->mx);
5171 userp = smb_GetUserFromVCP(vcp, inp);
5175 /* now prepare to call cm_setattr. This message only sets various times,
5176 * and AFS only implements mtime, and we'll set the mtime if that's
5177 * requested. The others we'll ignore.
5179 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
5181 if (searchTime != 0) {
5182 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
5184 if ( unixTime != -1 ) {
5185 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
5186 attrs.clientModTime = unixTime;
5187 code = cm_SetAttr(scp, &attrs, userp, &req);
5189 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
5191 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
5196 cm_ReleaseUser(userp);
5197 smb_ReleaseFID(fidp);
5202 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5206 long finalCount = 0;
5215 fd = smb_GetSMBParm(inp, 2);
5216 count = smb_GetSMBParm(inp, 5);
5217 offset.HighPart = 0; /* too bad */
5218 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5220 osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
5221 fd, offset.LowPart, count);
5223 fd = smb_ChainFID(fd, inp);
5224 fidp = smb_FindFID(vcp, fd, 0);
5226 return CM_ERROR_BADFD;
5229 pid = ((smb_t *) inp)->pid;
5230 key = cm_GenerateKey(vcp->vcID, pid, fd);
5232 LARGE_INTEGER LOffset, LLength;
5234 LOffset.HighPart = offset.HighPart;
5235 LOffset.LowPart = offset.LowPart;
5236 LLength.HighPart = 0;
5237 LLength.LowPart = count;
5239 lock_ObtainMutex(&fidp->scp->mx);
5240 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
5241 lock_ReleaseMutex(&fidp->scp->mx);
5245 smb_ReleaseFID(fidp);
5249 /* set inp->fid so that later read calls in same msg can find fid */
5252 lock_ObtainMutex(&fidp->mx);
5253 if (fidp->flags & SMB_FID_IOCTL) {
5254 lock_ReleaseMutex(&fidp->mx);
5255 code = smb_IoctlV3Read(fidp, vcp, inp, outp);
5256 smb_ReleaseFID(fidp);
5259 lock_ReleaseMutex(&fidp->mx);
5261 userp = smb_GetUserFromVCP(vcp, inp);
5263 /* 0 and 1 are reserved for request chaining, were setup by our caller,
5264 * and will be further filled in after we return.
5266 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
5267 smb_SetSMBParm(outp, 3, 0); /* resvd */
5268 smb_SetSMBParm(outp, 4, 0); /* resvd */
5269 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
5270 /* fill in #6 when we have all the parameters' space reserved */
5271 smb_SetSMBParm(outp, 7, 0); /* resv'd */
5272 smb_SetSMBParm(outp, 8, 0); /* resv'd */
5273 smb_SetSMBParm(outp, 9, 0); /* resv'd */
5274 smb_SetSMBParm(outp, 10, 0); /* resv'd */
5275 smb_SetSMBParm(outp, 11, 0); /* reserved */
5277 /* get op ptr after putting in the parms, since otherwise we don't
5278 * know where the data really is.
5280 op = smb_GetSMBData(outp, NULL);
5282 /* now fill in offset from start of SMB header to first data byte (to op) */
5283 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
5285 /* set the packet data length the count of the # of bytes */
5286 smb_SetSMBDataLength(outp, count);
5289 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5291 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5294 /* fix some things up */
5295 smb_SetSMBParm(outp, 5, finalCount);
5296 smb_SetSMBDataLength(outp, finalCount);
5298 smb_ReleaseFID(fidp);
5300 cm_ReleaseUser(userp);
5305 * Values for createDisp, copied from NTDDK.H
5307 #define FILE_SUPERSEDE 0 // (???)
5308 #define FILE_OPEN 1 // (open)
5309 #define FILE_CREATE 2 // (exclusive)
5310 #define FILE_OPEN_IF 3 // (non-exclusive)
5311 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
5312 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
5315 #define REQUEST_OPLOCK 2
5316 #define REQUEST_BATCH_OPLOCK 4
5317 #define OPEN_DIRECTORY 8
5318 #define EXTENDED_RESPONSE_REQUIRED 0x10
5320 /* CreateOptions field. */
5321 #define FILE_DIRECTORY_FILE 0x0001
5322 #define FILE_WRITE_THROUGH 0x0002
5323 #define FILE_SEQUENTIAL_ONLY 0x0004
5324 #define FILE_NON_DIRECTORY_FILE 0x0040
5325 #define FILE_NO_EA_KNOWLEDGE 0x0200
5326 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
5327 #define FILE_RANDOM_ACCESS 0x0800
5328 #define FILE_DELETE_ON_CLOSE 0x1000
5329 #define FILE_OPEN_BY_FILE_ID 0x2000
5331 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5333 char *pathp, *realPathp;
5337 cm_scache_t *dscp; /* parent dir */
5338 cm_scache_t *scp; /* file to create or open */
5339 cm_scache_t *targetScp; /* if scp is a symlink */
5343 unsigned short nameLength;
5345 unsigned int requestOpLock;
5346 unsigned int requestBatchOpLock;
5347 unsigned int mustBeDir;
5348 unsigned int extendedRespRequired;
5349 unsigned int treeCreate;
5351 unsigned int desiredAccess;
5352 unsigned int extAttributes;
5353 unsigned int createDisp;
5354 unsigned int createOptions;
5355 unsigned int shareAccess;
5356 int initialModeBits;
5357 unsigned short baseFid;
5358 smb_fid_t *baseFidp;
5360 cm_scache_t *baseDirp;
5361 unsigned short openAction;
5372 /* This code is very long and has a lot of if-then-else clauses
5373 * scp and dscp get reused frequently and we need to ensure that
5374 * we don't lose a reference. Start by ensuring that they are NULL.
5381 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
5382 flags = smb_GetSMBOffsetParm(inp, 3, 1)
5383 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
5384 requestOpLock = flags & REQUEST_OPLOCK;
5385 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
5386 mustBeDir = flags & OPEN_DIRECTORY;
5387 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
5390 * Why all of a sudden 32-bit FID?
5391 * We will reject all bits higher than 16.
5393 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
5394 return CM_ERROR_INVAL;
5395 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
5396 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
5397 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
5398 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
5399 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
5400 shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
5401 | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
5402 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
5403 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
5404 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
5405 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
5407 /* mustBeDir is never set; createOptions directory bit seems to be
5410 if (createOptions & FILE_DIRECTORY_FILE)
5412 else if (createOptions & FILE_NON_DIRECTORY_FILE)
5418 * compute initial mode bits based on read-only flag in
5419 * extended attributes
5421 initialModeBits = 0666;
5422 if (extAttributes & SMB_ATTR_READONLY)
5423 initialModeBits &= ~0222;
5425 pathp = smb_GetSMBData(inp, NULL);
5426 /* Sometimes path is not null-terminated, so we make a copy. */
5427 realPathp = malloc(nameLength+1);
5428 memcpy(realPathp, pathp, nameLength);
5429 realPathp[nameLength] = 0;
5430 if (smb_StoreAnsiFilenames)
5431 OemToChar(realPathp,realPathp);
5433 spacep = inp->spacep;
5434 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5436 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
5437 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
5438 osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
5440 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5441 /* special case magic file name for receiving IOCTL requests
5442 * (since IOCTL calls themselves aren't getting through).
5444 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5445 smb_SetupIoctlFid(fidp, spacep);
5446 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
5448 /* set inp->fid so that later read calls in same msg can find fid */
5449 inp->fid = fidp->fid;
5453 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5454 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5455 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
5457 memset(&ft, 0, sizeof(ft));
5458 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5459 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5460 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5461 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5462 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
5463 sz.HighPart = 0x7fff; sz.LowPart = 0;
5464 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
5465 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
5466 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
5467 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
5468 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
5469 smb_SetSMBDataLength(outp, 0);
5471 /* clean up fid reference */
5472 smb_ReleaseFID(fidp);
5477 #ifdef DEBUG_VERBOSE
5479 char *hexp, *asciip;
5480 asciip = (lastNamep? lastNamep : realPathp);
5481 hexp = osi_HexifyString( asciip );
5482 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
5487 userp = smb_GetUserFromVCP(vcp, inp);
5489 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
5491 return CM_ERROR_INVAL;
5496 baseDirp = cm_data.rootSCachep;
5497 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5498 if (code == CM_ERROR_TIDIPC) {
5499 /* Attempt to use a TID allocated for IPC. The client
5500 * is probably looking for DCE RPC end points which we
5501 * don't support OR it could be looking to make a DFS
5504 osi_Log0(smb_logp, "NTCreateX received IPC TID");
5507 cm_ReleaseUser(userp);
5508 return CM_ERROR_NOSUCHFILE;
5509 #endif /* DFS_SUPPORT */
5512 baseFidp = smb_FindFID(vcp, baseFid, 0);
5514 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
5516 cm_ReleaseUser(userp);
5517 return CM_ERROR_INVAL;
5519 baseDirp = baseFidp->scp;
5523 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
5525 /* compute open mode */
5527 if (desiredAccess & DELETE)
5528 fidflags |= SMB_FID_OPENDELETE;
5529 if (desiredAccess & AFS_ACCESS_READ)
5530 fidflags |= SMB_FID_OPENREAD;
5531 if (desiredAccess & AFS_ACCESS_WRITE)
5532 fidflags |= SMB_FID_OPENWRITE;
5533 if (createOptions & FILE_DELETE_ON_CLOSE)
5534 fidflags |= SMB_FID_DELONCLOSE;
5536 /* and the share mode */
5537 if (shareAccess & FILE_SHARE_READ)
5538 fidflags |= SMB_FID_SHARE_READ;
5539 if (shareAccess & FILE_SHARE_WRITE)
5540 fidflags |= SMB_FID_SHARE_WRITE;
5544 /* For an exclusive create, we want to do a case sensitive match for the last component. */
5545 if ( createDisp == FILE_CREATE ||
5546 createDisp == FILE_OVERWRITE ||
5547 createDisp == FILE_OVERWRITE_IF) {
5548 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5549 userp, tidPathp, &req, &dscp);
5552 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5553 cm_ReleaseSCache(dscp);
5554 cm_ReleaseUser(userp);
5557 smb_ReleaseFID(baseFidp);
5558 if ( WANTS_DFS_PATHNAMES(inp) )
5559 return CM_ERROR_PATH_NOT_COVERED;
5561 return CM_ERROR_BADSHARENAME;
5563 #endif /* DFS_SUPPORT */
5564 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5566 if (code == CM_ERROR_NOSUCHFILE) {
5567 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
5568 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
5569 if (code == 0 && realDirFlag == 1) {
5570 cm_ReleaseSCache(scp);
5571 cm_ReleaseSCache(dscp);
5572 cm_ReleaseUser(userp);
5575 smb_ReleaseFID(baseFidp);
5576 return CM_ERROR_EXISTS;
5580 /* we have both scp and dscp */
5582 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5583 userp, tidPathp, &req, &scp);
5585 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5586 cm_ReleaseSCache(scp);
5587 cm_ReleaseUser(userp);
5590 smb_ReleaseFID(baseFidp);
5591 if ( WANTS_DFS_PATHNAMES(inp) )
5592 return CM_ERROR_PATH_NOT_COVERED;
5594 return CM_ERROR_BADSHARENAME;
5596 #endif /* DFS_SUPPORT */
5597 /* we might have scp but not dscp */
5603 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
5604 /* look up parent directory */
5605 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
5606 * the immediate parent. We have to work our way up realPathp until we hit something that we
5610 /* we might or might not have scp */
5616 code = cm_NameI(baseDirp, spacep->data,
5617 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5618 userp, tidPathp, &req, &dscp);
5621 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5623 cm_ReleaseSCache(scp);
5624 cm_ReleaseSCache(dscp);
5625 cm_ReleaseUser(userp);
5628 smb_ReleaseFID(baseFidp);
5629 if ( WANTS_DFS_PATHNAMES(inp) )
5630 return CM_ERROR_PATH_NOT_COVERED;
5632 return CM_ERROR_BADSHARENAME;
5634 #endif /* DFS_SUPPORT */
5637 (tp = strrchr(spacep->data,'\\')) &&
5638 (createDisp == FILE_CREATE) &&
5639 (realDirFlag == 1)) {
5642 treeStartp = realPathp + (tp - spacep->data);
5644 if (*tp && !smb_IsLegalFilename(tp)) {
5646 smb_ReleaseFID(baseFidp);
5647 cm_ReleaseUser(userp);
5650 cm_ReleaseSCache(scp);
5651 return CM_ERROR_BADNTFILENAME;
5655 } while (dscp == NULL && code == 0);
5659 /* we might have scp and we might have dscp */
5662 smb_ReleaseFID(baseFidp);
5665 osi_Log0(smb_logp,"NTCreateX parent not found");
5667 cm_ReleaseSCache(scp);
5669 cm_ReleaseSCache(dscp);
5670 cm_ReleaseUser(userp);
5675 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
5676 /* A file exists where we want a directory. */
5678 cm_ReleaseSCache(scp);
5679 cm_ReleaseSCache(dscp);
5680 cm_ReleaseUser(userp);
5682 return CM_ERROR_EXISTS;
5686 lastNamep = realPathp;
5690 if (!smb_IsLegalFilename(lastNamep)) {
5692 cm_ReleaseSCache(scp);
5694 cm_ReleaseSCache(dscp);
5695 cm_ReleaseUser(userp);
5697 return CM_ERROR_BADNTFILENAME;
5700 if (!foundscp && !treeCreate) {
5701 if ( createDisp == FILE_CREATE ||
5702 createDisp == FILE_OVERWRITE ||
5703 createDisp == FILE_OVERWRITE_IF)
5705 code = cm_Lookup(dscp, lastNamep,
5706 CM_FLAG_FOLLOW, userp, &req, &scp);
5708 code = cm_Lookup(dscp, lastNamep,
5709 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5712 if (code && code != CM_ERROR_NOSUCHFILE) {
5714 cm_ReleaseSCache(dscp);
5715 cm_ReleaseUser(userp);
5720 /* we have scp and dscp */
5722 /* we have scp but not dscp */
5724 smb_ReleaseFID(baseFidp);
5727 /* if we get here, if code is 0, the file exists and is represented by
5728 * scp. Otherwise, we have to create it. The dir may be represented
5729 * by dscp, or we may have found the file directly. If code is non-zero,
5732 if (code == 0 && !treeCreate) {
5733 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req);
5736 cm_ReleaseSCache(dscp);
5738 cm_ReleaseSCache(scp);
5739 cm_ReleaseUser(userp);
5744 if (createDisp == FILE_CREATE) {
5745 /* oops, file shouldn't be there */
5747 cm_ReleaseSCache(dscp);
5749 cm_ReleaseSCache(scp);
5750 cm_ReleaseUser(userp);
5752 return CM_ERROR_EXISTS;
5755 if ( createDisp == FILE_OVERWRITE ||
5756 createDisp == FILE_OVERWRITE_IF) {
5758 setAttr.mask = CM_ATTRMASK_LENGTH;
5759 setAttr.length.LowPart = 0;
5760 setAttr.length.HighPart = 0;
5761 /* now watch for a symlink */
5763 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5765 osi_assert(dscp != NULL);
5766 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5768 /* we have a more accurate file to use (the
5769 * target of the symbolic link). Otherwise,
5770 * we'll just use the symlink anyway.
5772 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5774 cm_ReleaseSCache(scp);
5778 code = cm_SetAttr(scp, &setAttr, userp, &req);
5779 openAction = 3; /* truncated existing file */
5782 openAction = 1; /* found existing file */
5784 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
5785 /* don't create if not found */
5787 cm_ReleaseSCache(dscp);
5789 cm_ReleaseSCache(scp);
5790 cm_ReleaseUser(userp);
5792 return CM_ERROR_NOSUCHFILE;
5793 } else if (realDirFlag == 0 || realDirFlag == -1) {
5794 osi_assert(dscp != NULL);
5795 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
5796 osi_LogSaveString(smb_logp, lastNamep));
5797 openAction = 2; /* created file */
5798 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5799 setAttr.clientModTime = time(NULL);
5800 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
5801 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5802 smb_NotifyChange(FILE_ACTION_ADDED,
5803 FILE_NOTIFY_CHANGE_FILE_NAME,
5804 dscp, lastNamep, NULL, TRUE);
5805 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
5806 /* Not an exclusive create, and someone else tried
5807 * creating it already, then we open it anyway. We
5808 * don't bother retrying after this, since if this next
5809 * fails, that means that the file was deleted after we
5810 * started this call.
5812 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5815 if (createDisp == FILE_OVERWRITE_IF) {
5816 setAttr.mask = CM_ATTRMASK_LENGTH;
5817 setAttr.length.LowPart = 0;
5818 setAttr.length.HighPart = 0;
5820 /* now watch for a symlink */
5822 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5824 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5826 /* we have a more accurate file to use (the
5827 * target of the symbolic link). Otherwise,
5828 * we'll just use the symlink anyway.
5830 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5832 cm_ReleaseSCache(scp);
5836 code = cm_SetAttr(scp, &setAttr, userp, &req);
5838 } /* lookup succeeded */
5842 char *cp; /* This component */
5843 int clen = 0; /* length of component */
5844 cm_scache_t *tscp1, *tscp2;
5847 /* create directory */
5849 treeStartp = lastNamep;
5850 osi_assert(dscp != NULL);
5851 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
5852 osi_LogSaveString(smb_logp, treeStartp));
5853 openAction = 2; /* created directory */
5855 /* if the request is to create the root directory
5856 * it will appear as a directory name of the nul-string
5857 * and a code of CM_ERROR_NOSUCHFILE
5859 if ( !*treeStartp && code == CM_ERROR_NOSUCHFILE)
5860 code = CM_ERROR_EXISTS;
5862 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5863 setAttr.clientModTime = time(NULL);
5868 cm_HoldSCache(tscp1);
5872 tp = strchr(pp, '\\');
5875 clen = (int)strlen(cp);
5876 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
5878 clen = (int)(tp - pp);
5879 strncpy(cp,pp,clen);
5886 continue; /* the supplied path can't have consecutive slashes either , but */
5888 /* cp is the next component to be created. */
5889 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
5890 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
5891 smb_NotifyChange(FILE_ACTION_ADDED,
5892 FILE_NOTIFY_CHANGE_DIR_NAME,
5893 tscp1, cp, NULL, TRUE);
5895 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
5896 /* Not an exclusive create, and someone else tried
5897 * creating it already, then we open it anyway. We
5898 * don't bother retrying after this, since if this next
5899 * fails, that means that the file was deleted after we
5900 * started this call.
5902 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
5903 userp, &req, &tscp2);
5908 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
5909 cm_ReleaseSCache(tscp1);
5910 tscp1 = tscp2; /* Newly created directory will be next parent */
5911 /* the hold is transfered to tscp1 from tscp2 */
5916 cm_ReleaseSCache(dscp);
5919 cm_ReleaseSCache(scp);
5922 * if we get here and code == 0, then scp is the last directory created, and dscp is the
5928 /* something went wrong creating or truncating the file */
5930 cm_ReleaseSCache(scp);
5932 cm_ReleaseSCache(dscp);
5933 cm_ReleaseUser(userp);
5938 /* make sure we have file vs. dir right (only applies for single component case) */
5939 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5940 /* now watch for a symlink */
5942 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5943 cm_scache_t * targetScp = 0;
5944 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5946 /* we have a more accurate file to use (the
5947 * target of the symbolic link). Otherwise,
5948 * we'll just use the symlink anyway.
5950 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
5951 cm_ReleaseSCache(scp);
5956 if (scp->fileType != CM_SCACHETYPE_FILE) {
5958 cm_ReleaseSCache(dscp);
5959 cm_ReleaseSCache(scp);
5960 cm_ReleaseUser(userp);
5962 return CM_ERROR_ISDIR;
5966 /* (only applies to single component case) */
5967 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5968 cm_ReleaseSCache(scp);
5970 cm_ReleaseSCache(dscp);
5971 cm_ReleaseUser(userp);
5973 return CM_ERROR_NOTDIR;
5976 /* open the file itself */
5977 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5980 /* save a reference to the user */
5982 fidp->userp = userp;
5984 /* If we are restricting sharing, we should do so with a suitable
5986 if (scp->fileType == CM_SCACHETYPE_FILE &&
5987 !(fidflags & SMB_FID_SHARE_WRITE)) {
5989 LARGE_INTEGER LOffset, LLength;
5992 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
5993 LOffset.LowPart = SMB_FID_QLOCK_LOW;
5994 LLength.HighPart = 0;
5995 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
5997 if (fidflags & SMB_FID_SHARE_READ) {
5998 sLockType = LOCKING_ANDX_SHARED_LOCK;
6003 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
6005 lock_ObtainMutex(&scp->mx);
6006 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
6007 lock_ReleaseMutex(&scp->mx);
6010 /* shouldn't this be smb_CloseFID() fidp->flags = SMB_FID_DELETE; */
6011 smb_CloseFID(vcp, fidp, NULL, 0);
6012 smb_ReleaseFID(fidp);
6014 cm_ReleaseSCache(scp);
6016 cm_ReleaseSCache(dscp);
6017 cm_ReleaseUser(userp);
6024 lock_ObtainMutex(&fidp->mx);
6025 /* save a pointer to the vnode */
6026 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
6028 fidp->flags = fidflags;
6030 /* save parent dir and pathname for delete or change notification */
6031 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
6032 fidp->flags |= SMB_FID_NTOPEN;
6033 fidp->NTopen_dscp = dscp;
6034 cm_HoldSCache(dscp);
6035 fidp->NTopen_pathp = strdup(lastNamep);
6037 fidp->NTopen_wholepathp = realPathp;
6038 lock_ReleaseMutex(&fidp->mx);
6040 /* we don't need this any longer */
6042 cm_ReleaseSCache(dscp);
6046 cm_Open(scp, 0, userp);
6048 /* set inp->fid so that later read calls in same msg can find fid */
6049 inp->fid = fidp->fid;
6053 lock_ObtainMutex(&scp->mx);
6054 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
6055 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6056 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
6057 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6058 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6059 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6060 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6061 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6062 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
6064 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6065 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6066 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
6067 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
6068 smb_SetSMBParmByte(outp, parmSlot,
6069 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
6070 lock_ReleaseMutex(&scp->mx);
6071 smb_SetSMBDataLength(outp, 0);
6073 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
6074 osi_LogSaveString(smb_logp, realPathp));
6076 smb_ReleaseFID(fidp);
6078 cm_ReleaseUser(userp);
6080 /* Can't free realPathp if we get here since
6081 fidp->NTopen_wholepathp is pointing there */
6083 /* leave scp held since we put it in fidp->scp */
6088 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
6089 * Instead, ultimately, would like to use a subroutine for common code.
6091 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6093 char *pathp, *realPathp;
6097 cm_scache_t *dscp; /* parent dir */
6098 cm_scache_t *scp; /* file to create or open */
6099 cm_scache_t *targetScp; /* if scp is a symlink */
6102 unsigned long nameLength;
6104 unsigned int requestOpLock;
6105 unsigned int requestBatchOpLock;
6106 unsigned int mustBeDir;
6107 unsigned int extendedRespRequired;
6109 unsigned int desiredAccess;
6110 #ifdef DEBUG_VERBOSE
6111 unsigned int allocSize;
6113 unsigned int shareAccess;
6114 unsigned int extAttributes;
6115 unsigned int createDisp;
6116 #ifdef DEBUG_VERBOSE
6119 unsigned int createOptions;
6120 int initialModeBits;
6121 unsigned short baseFid;
6122 smb_fid_t *baseFidp;
6124 cm_scache_t *baseDirp;
6125 unsigned short openAction;
6131 int parmOffset, dataOffset;
6142 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6143 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6144 parmp = inp->data + parmOffset;
6145 lparmp = (ULONG *) parmp;
6148 requestOpLock = flags & REQUEST_OPLOCK;
6149 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6150 mustBeDir = flags & OPEN_DIRECTORY;
6151 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6154 * Why all of a sudden 32-bit FID?
6155 * We will reject all bits higher than 16.
6157 if (lparmp[1] & 0xFFFF0000)
6158 return CM_ERROR_INVAL;
6159 baseFid = (unsigned short)lparmp[1];
6160 desiredAccess = lparmp[2];
6161 #ifdef DEBUG_VERBOSE
6162 allocSize = lparmp[3];
6163 #endif /* DEBUG_VERSOSE */
6164 extAttributes = lparmp[5];
6165 shareAccess = lparmp[6];
6166 createDisp = lparmp[7];
6167 createOptions = lparmp[8];
6168 #ifdef DEBUG_VERBOSE
6171 nameLength = lparmp[11];
6173 #ifdef DEBUG_VERBOSE
6174 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
6175 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
6176 osi_Log1(smb_logp,"... flags[%x]",flags);
6179 /* mustBeDir is never set; createOptions directory bit seems to be
6182 if (createOptions & FILE_DIRECTORY_FILE)
6184 else if (createOptions & FILE_NON_DIRECTORY_FILE)
6190 * compute initial mode bits based on read-only flag in
6191 * extended attributes
6193 initialModeBits = 0666;
6194 if (extAttributes & 1)
6195 initialModeBits &= ~0222;
6197 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
6198 /* Sometimes path is not null-terminated, so we make a copy. */
6199 realPathp = malloc(nameLength+1);
6200 memcpy(realPathp, pathp, nameLength);
6201 realPathp[nameLength] = 0;
6202 if (smb_StoreAnsiFilenames)
6203 OemToChar(realPathp,realPathp);
6205 spacep = cm_GetSpace();
6206 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6209 * Nothing here to handle SMB_IOCTL_FILENAME.
6210 * Will add it if necessary.
6213 #ifdef DEBUG_VERBOSE
6215 char *hexp, *asciip;
6216 asciip = (lastNamep? lastNamep : realPathp);
6217 hexp = osi_HexifyString( asciip );
6218 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
6223 userp = smb_GetUserFromVCP(vcp, inp);
6225 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
6227 return CM_ERROR_INVAL;
6232 baseDirp = cm_data.rootSCachep;
6233 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6234 if (code == CM_ERROR_TIDIPC) {
6235 /* Attempt to use a TID allocated for IPC. The client
6236 * is probably looking for DCE RPC end points which we
6237 * don't support OR it could be looking to make a DFS
6240 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
6243 cm_ReleaseUser(userp);
6244 return CM_ERROR_NOSUCHPATH;
6248 baseFidp = smb_FindFID(vcp, baseFid, 0);
6250 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
6252 cm_ReleaseUser(userp);
6253 return CM_ERROR_INVAL;
6255 baseDirp = baseFidp->scp;
6259 /* compute open mode */
6261 if (desiredAccess & DELETE)
6262 fidflags |= SMB_FID_OPENDELETE;
6263 if (desiredAccess & AFS_ACCESS_READ)
6264 fidflags |= SMB_FID_OPENREAD;
6265 if (desiredAccess & AFS_ACCESS_WRITE)
6266 fidflags |= SMB_FID_OPENWRITE;
6267 if (createOptions & FILE_DELETE_ON_CLOSE)
6268 fidflags |= SMB_FID_DELONCLOSE;
6270 /* And the share mode */
6271 if (shareAccess & FILE_SHARE_READ)
6272 fidflags |= SMB_FID_SHARE_READ;
6273 if (shareAccess & FILE_SHARE_WRITE)
6274 fidflags |= SMB_FID_SHARE_WRITE;
6278 if ( createDisp == FILE_OPEN ||
6279 createDisp == FILE_OVERWRITE ||
6280 createDisp == FILE_OVERWRITE_IF) {
6281 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6282 userp, tidPathp, &req, &dscp);
6285 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6286 cm_ReleaseSCache(dscp);
6287 cm_ReleaseUser(userp);
6290 smb_ReleaseFID(baseFidp);
6291 if ( WANTS_DFS_PATHNAMES(inp) )
6292 return CM_ERROR_PATH_NOT_COVERED;
6294 return CM_ERROR_BADSHARENAME;
6296 #endif /* DFS_SUPPORT */
6297 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6299 if (code == CM_ERROR_NOSUCHFILE) {
6300 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6301 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6302 if (code == 0 && realDirFlag == 1) {
6303 cm_ReleaseSCache(scp);
6304 cm_ReleaseSCache(dscp);
6305 cm_ReleaseUser(userp);
6308 smb_ReleaseFID(baseFidp);
6309 return CM_ERROR_EXISTS;
6315 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6316 userp, tidPathp, &req, &scp);
6318 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6319 cm_ReleaseSCache(scp);
6320 cm_ReleaseUser(userp);
6323 smb_ReleaseFID(baseFidp);
6324 if ( WANTS_DFS_PATHNAMES(inp) )
6325 return CM_ERROR_PATH_NOT_COVERED;
6327 return CM_ERROR_BADSHARENAME;
6329 #endif /* DFS_SUPPORT */
6335 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6336 /* look up parent directory */
6338 code = cm_NameI(baseDirp, spacep->data,
6339 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6340 userp, tidPathp, &req, &dscp);
6342 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6343 cm_ReleaseSCache(dscp);
6344 cm_ReleaseUser(userp);
6347 smb_ReleaseFID(baseFidp);
6348 if ( WANTS_DFS_PATHNAMES(inp) )
6349 return CM_ERROR_PATH_NOT_COVERED;
6351 return CM_ERROR_BADSHARENAME;
6353 #endif /* DFS_SUPPORT */
6357 cm_FreeSpace(spacep);
6360 smb_ReleaseFID(baseFidp);
6363 cm_ReleaseUser(userp);
6369 lastNamep = realPathp;
6373 if (!smb_IsLegalFilename(lastNamep))
6374 return CM_ERROR_BADNTFILENAME;
6377 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
6378 code = cm_Lookup(dscp, lastNamep,
6379 CM_FLAG_FOLLOW, userp, &req, &scp);
6381 code = cm_Lookup(dscp, lastNamep,
6382 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6385 if (code && code != CM_ERROR_NOSUCHFILE) {
6386 cm_ReleaseSCache(dscp);
6387 cm_ReleaseUser(userp);
6394 smb_ReleaseFID(baseFidp);
6395 cm_FreeSpace(spacep);
6398 /* if we get here, if code is 0, the file exists and is represented by
6399 * scp. Otherwise, we have to create it. The dir may be represented
6400 * by dscp, or we may have found the file directly. If code is non-zero,
6404 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
6408 cm_ReleaseSCache(dscp);
6409 cm_ReleaseSCache(scp);
6410 cm_ReleaseUser(userp);
6415 if (createDisp == FILE_CREATE) {
6416 /* oops, file shouldn't be there */
6418 cm_ReleaseSCache(dscp);
6419 cm_ReleaseSCache(scp);
6420 cm_ReleaseUser(userp);
6422 return CM_ERROR_EXISTS;
6425 if (createDisp == FILE_OVERWRITE ||
6426 createDisp == FILE_OVERWRITE_IF) {
6427 setAttr.mask = CM_ATTRMASK_LENGTH;
6428 setAttr.length.LowPart = 0;
6429 setAttr.length.HighPart = 0;
6431 /* now watch for a symlink */
6433 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6435 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6437 /* we have a more accurate file to use (the
6438 * target of the symbolic link). Otherwise,
6439 * we'll just use the symlink anyway.
6441 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6443 cm_ReleaseSCache(scp);
6447 code = cm_SetAttr(scp, &setAttr, userp, &req);
6448 openAction = 3; /* truncated existing file */
6450 else openAction = 1; /* found existing file */
6452 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6453 /* don't create if not found */
6455 cm_ReleaseSCache(dscp);
6456 cm_ReleaseUser(userp);
6458 return CM_ERROR_NOSUCHFILE;
6460 else if (realDirFlag == 0 || realDirFlag == -1) {
6461 osi_assert(dscp != NULL);
6462 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
6463 osi_LogSaveString(smb_logp, lastNamep));
6464 openAction = 2; /* created file */
6465 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6466 setAttr.clientModTime = time(NULL);
6467 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6469 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6470 smb_NotifyChange(FILE_ACTION_ADDED,
6471 FILE_NOTIFY_CHANGE_FILE_NAME,
6472 dscp, lastNamep, NULL, TRUE);
6473 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6474 /* Not an exclusive create, and someone else tried
6475 * creating it already, then we open it anyway. We
6476 * don't bother retrying after this, since if this next
6477 * fails, that means that the file was deleted after we
6478 * started this call.
6480 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6483 if (createDisp == FILE_OVERWRITE_IF) {
6484 setAttr.mask = CM_ATTRMASK_LENGTH;
6485 setAttr.length.LowPart = 0;
6486 setAttr.length.HighPart = 0;
6488 /* now watch for a symlink */
6490 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6492 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6494 /* we have a more accurate file to use (the
6495 * target of the symbolic link). Otherwise,
6496 * we'll just use the symlink anyway.
6498 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6500 cm_ReleaseSCache(scp);
6504 code = cm_SetAttr(scp, &setAttr, userp, &req);
6506 } /* lookup succeeded */
6509 /* create directory */
6510 osi_assert(dscp != NULL);
6512 "smb_ReceiveNTTranCreate creating directory %s",
6513 osi_LogSaveString(smb_logp, lastNamep));
6514 openAction = 2; /* created directory */
6515 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6516 setAttr.clientModTime = time(NULL);
6517 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6518 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6519 smb_NotifyChange(FILE_ACTION_ADDED,
6520 FILE_NOTIFY_CHANGE_DIR_NAME,
6521 dscp, lastNamep, NULL, TRUE);
6523 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6524 /* Not an exclusive create, and someone else tried
6525 * creating it already, then we open it anyway. We
6526 * don't bother retrying after this, since if this next
6527 * fails, that means that the file was deleted after we
6528 * started this call.
6530 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6536 /* something went wrong creating or truncating the file */
6538 cm_ReleaseSCache(scp);
6539 cm_ReleaseUser(userp);
6544 /* make sure we have file vs. dir right */
6545 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
6546 /* now watch for a symlink */
6548 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6550 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6552 /* we have a more accurate file to use (the
6553 * target of the symbolic link). Otherwise,
6554 * we'll just use the symlink anyway.
6556 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6558 cm_ReleaseSCache(scp);
6563 if (scp->fileType != CM_SCACHETYPE_FILE) {
6564 cm_ReleaseSCache(scp);
6565 cm_ReleaseUser(userp);
6567 return CM_ERROR_ISDIR;
6571 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
6572 cm_ReleaseSCache(scp);
6573 cm_ReleaseUser(userp);
6575 return CM_ERROR_NOTDIR;
6578 /* open the file itself */
6579 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6582 /* save a reference to the user */
6584 fidp->userp = userp;
6586 /* If we are restricting sharing, we should do so with a suitable
6588 if (scp->fileType == CM_SCACHETYPE_FILE &&
6589 !(fidflags & SMB_FID_SHARE_WRITE)) {
6591 LARGE_INTEGER LOffset, LLength;
6594 LOffset.HighPart = SMB_FID_QLOCK_HIGH;
6595 LOffset.LowPart = SMB_FID_QLOCK_LOW;
6596 LLength.HighPart = 0;
6597 LLength.LowPart = SMB_FID_QLOCK_LENGTH;
6599 if (fidflags & SMB_FID_SHARE_READ) {
6600 sLockType = LOCKING_ANDX_SHARED_LOCK;
6605 key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
6607 lock_ObtainMutex(&scp->mx);
6608 code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
6609 lock_ReleaseMutex(&scp->mx);
6612 /* Shouldn't this be smb_CloseFID()? fidp->flags = SMB_FID_DELETE; */
6613 smb_CloseFID(vcp, fidp, NULL, 0);
6614 smb_ReleaseFID(fidp);
6616 cm_ReleaseSCache(scp);
6617 cm_ReleaseUser(userp);
6620 return CM_ERROR_SHARING_VIOLATION;
6624 lock_ObtainMutex(&fidp->mx);
6625 /* save a pointer to the vnode */
6628 fidp->flags = fidflags;
6630 /* save parent dir and pathname for deletion or change notification */
6631 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
6632 fidp->flags |= SMB_FID_NTOPEN;
6633 fidp->NTopen_dscp = dscp;
6634 cm_HoldSCache(dscp);
6635 fidp->NTopen_pathp = strdup(lastNamep);
6637 fidp->NTopen_wholepathp = realPathp;
6638 lock_ReleaseMutex(&fidp->mx);
6640 /* we don't need this any longer */
6642 cm_ReleaseSCache(dscp);
6644 cm_Open(scp, 0, userp);
6646 /* set inp->fid so that later read calls in same msg can find fid */
6647 inp->fid = fidp->fid;
6649 /* check whether we are required to send an extended response */
6650 if (!extendedRespRequired) {
6652 parmOffset = 8*4 + 39;
6653 parmOffset += 1; /* pad to 4 */
6654 dataOffset = parmOffset + 70;
6658 /* Total Parameter Count */
6659 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
6660 /* Total Data Count */
6661 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6662 /* Parameter Count */
6663 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
6664 /* Parameter Offset */
6665 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6666 /* Parameter Displacement */
6667 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6669 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6671 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6672 /* Data Displacement */
6673 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6674 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6675 smb_SetSMBDataLength(outp, 70);
6677 lock_ObtainMutex(&scp->mx);
6678 outData = smb_GetSMBData(outp, NULL);
6679 outData++; /* round to get to parmOffset */
6680 *outData = 0; outData++; /* oplock */
6681 *outData = 0; outData++; /* reserved */
6682 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
6683 *((ULONG *)outData) = openAction; outData += 4;
6684 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
6685 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6686 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
6687 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
6688 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
6689 *((FILETIME *)outData) = ft; outData += 8; /* change time */
6690 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
6691 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
6692 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
6693 *((USHORT *)outData) = 0; outData += 2; /* filetype */
6694 *((USHORT *)outData) = 0; outData += 2; /* dev state */
6695 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
6696 outData += 2; /* is a dir? */
6697 lock_ReleaseMutex(&scp->mx);
6700 parmOffset = 8*4 + 39;
6701 parmOffset += 1; /* pad to 4 */
6702 dataOffset = parmOffset + 104;
6706 /* Total Parameter Count */
6707 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
6708 /* Total Data Count */
6709 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6710 /* Parameter Count */
6711 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
6712 /* Parameter Offset */
6713 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6714 /* Parameter Displacement */
6715 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6717 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6719 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6720 /* Data Displacement */
6721 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6722 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6723 smb_SetSMBDataLength(outp, 105);
6725 lock_ObtainMutex(&scp->mx);
6726 outData = smb_GetSMBData(outp, NULL);
6727 outData++; /* round to get to parmOffset */
6728 *outData = 0; outData++; /* oplock */
6729 *outData = 1; outData++; /* response type */
6730 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
6731 *((ULONG *)outData) = openAction; outData += 4;
6732 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
6733 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6734 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
6735 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
6736 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
6737 *((FILETIME *)outData) = ft; outData += 8; /* change time */
6738 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
6739 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
6740 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
6741 *((USHORT *)outData) = 0; outData += 2; /* filetype */
6742 *((USHORT *)outData) = 0; outData += 2; /* dev state */
6743 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
6744 outData += 1; /* is a dir? */
6745 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
6746 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
6747 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
6748 lock_ReleaseMutex(&scp->mx);
6751 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
6753 smb_ReleaseFID(fidp);
6755 cm_ReleaseUser(userp);
6757 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
6758 /* leave scp held since we put it in fidp->scp */
6762 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
6765 smb_packet_t *savedPacketp;
6766 ULONG filter; USHORT fid, watchtree;
6770 filter = smb_GetSMBParm(inp, 19) |
6771 (smb_GetSMBParm(inp, 20) << 16);
6772 fid = smb_GetSMBParm(inp, 21);
6773 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
6775 fidp = smb_FindFID(vcp, fid, 0);
6777 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
6778 return CM_ERROR_BADFD;
6781 savedPacketp = smb_CopyPacket(inp);
6783 if (savedPacketp->vcp)
6784 smb_ReleaseVC(savedPacketp->vcp);
6785 savedPacketp->vcp = vcp;
6786 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6787 savedPacketp->nextp = smb_Directory_Watches;
6788 smb_Directory_Watches = savedPacketp;
6789 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6791 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
6792 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
6795 lock_ObtainMutex(&scp->mx);
6797 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
6799 scp->flags |= CM_SCACHEFLAG_WATCHED;
6800 lock_ReleaseMutex(&scp->mx);
6801 smb_ReleaseFID(fidp);
6803 outp->flags |= SMB_PACKETFLAG_NOSEND;
6807 unsigned char nullSecurityDesc[36] = {
6808 0x01, /* security descriptor revision */
6809 0x00, /* reserved, should be zero */
6810 0x00, 0x80, /* security descriptor control;
6811 * 0x8000 : self-relative format */
6812 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
6813 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
6814 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
6815 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
6816 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6817 /* "null SID" owner SID */
6818 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
6819 /* "null SID" group SID */
6822 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6824 int parmOffset, parmCount, dataOffset, dataCount;
6832 ULONG securityInformation;
6834 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6835 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6836 parmp = inp->data + parmOffset;
6837 sparmp = (USHORT *) parmp;
6838 lparmp = (ULONG *) parmp;
6841 securityInformation = lparmp[1];
6843 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
6844 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6852 parmOffset = 8*4 + 39;
6853 parmOffset += 1; /* pad to 4 */
6855 dataOffset = parmOffset + parmCount;
6859 /* Total Parameter Count */
6860 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6861 /* Total Data Count */
6862 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6863 /* Parameter Count */
6864 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6865 /* Parameter Offset */
6866 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6867 /* Parameter Displacement */
6868 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6870 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6872 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6873 /* Data Displacement */
6874 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6875 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6876 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
6878 outData = smb_GetSMBData(outp, NULL);
6879 outData++; /* round to get to parmOffset */
6880 *((ULONG *)outData) = 36; outData += 4; /* length */
6882 if (maxData >= 36) {
6883 memcpy(outData, nullSecurityDesc, 36);
6887 return CM_ERROR_BUFFERTOOSMALL;
6890 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6892 unsigned short function;
6894 function = smb_GetSMBParm(inp, 18);
6896 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
6898 /* We can handle long names */
6899 if (vcp->flags & SMB_VCFLAG_USENT)
6900 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
6904 return smb_ReceiveNTTranCreate(vcp, inp, outp);
6906 osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
6909 osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
6912 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
6914 osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
6917 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
6919 return CM_ERROR_INVAL;
6923 * smb_NotifyChange -- find relevant change notification messages and
6926 * If we don't know the file name (i.e. a callback break), filename is
6927 * NULL, and we return a zero-length list.
6929 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
6930 cm_scache_t *dscp, char *filename, char *otherFilename,
6931 BOOL isDirectParent)
6933 smb_packet_t *watch, *lastWatch, *nextWatch;
6934 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
6935 char *outData, *oldOutData;
6939 BOOL twoEntries = FALSE;
6940 ULONG otherNameLen, oldParmCount = 0;
6944 /* Get ready for rename within directory */
6945 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
6947 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
6950 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
6951 osi_LogSaveString(smb_logp,filename),dscp);
6953 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6954 watch = smb_Directory_Watches;
6956 filter = smb_GetSMBParm(watch, 19)
6957 | (smb_GetSMBParm(watch, 20) << 16);
6958 fid = smb_GetSMBParm(watch, 21);
6959 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
6960 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
6961 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
6964 * Strange hack - bug in NT Client and NT Server that we
6967 if (filter == 3 && wtree)
6970 fidp = smb_FindFID(watch->vcp, fid, 0);
6972 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
6974 watch = watch->nextp;
6977 if (fidp->scp != dscp
6978 || (filter & notifyFilter) == 0
6979 || (!isDirectParent && !wtree)) {
6980 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
6981 smb_ReleaseFID(fidp);
6983 watch = watch->nextp;
6986 smb_ReleaseFID(fidp);
6989 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
6990 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
6992 nextWatch = watch->nextp;
6993 if (watch == smb_Directory_Watches)
6994 smb_Directory_Watches = nextWatch;
6996 lastWatch->nextp = nextWatch;
6998 /* Turn off WATCHED flag in dscp */
6999 lock_ObtainMutex(&dscp->mx);
7001 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
7003 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
7004 lock_ReleaseMutex(&dscp->mx);
7006 /* Convert to response packet */
7007 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
7008 ((smb_t *) watch)->wct = 0;
7011 if (filename == NULL)
7014 nameLen = (ULONG)strlen(filename);
7015 parmCount = 3*4 + nameLen*2;
7016 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
7018 otherNameLen = (ULONG)strlen(otherFilename);
7019 oldParmCount = parmCount;
7020 parmCount += 3*4 + otherNameLen*2;
7021 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
7023 if (maxLen < parmCount)
7024 parmCount = 0; /* not enough room */
7026 parmOffset = 8*4 + 39;
7027 parmOffset += 1; /* pad to 4 */
7028 dataOffset = parmOffset + parmCount;
7032 /* Total Parameter Count */
7033 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
7034 /* Total Data Count */
7035 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7036 /* Parameter Count */
7037 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
7038 /* Parameter Offset */
7039 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
7040 /* Parameter Displacement */
7041 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7043 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7045 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
7046 /* Data Displacement */
7047 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7048 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
7049 smb_SetSMBDataLength(watch, parmCount + 1);
7051 if (parmCount != 0) {
7053 outData = smb_GetSMBData(watch, NULL);
7054 outData++; /* round to get to parmOffset */
7055 oldOutData = outData;
7056 *((DWORD *)outData) = oldParmCount; outData += 4;
7057 /* Next Entry Offset */
7058 *((DWORD *)outData) = action; outData += 4;
7060 *((DWORD *)outData) = nameLen*2; outData += 4;
7061 /* File Name Length */
7062 p = strdup(filename);
7063 if (smb_StoreAnsiFilenames)
7065 mbstowcs((WCHAR *)outData, p, nameLen);
7069 outData = oldOutData + oldParmCount;
7070 *((DWORD *)outData) = 0; outData += 4;
7071 /* Next Entry Offset */
7072 *((DWORD *)outData) = otherAction; outData += 4;
7074 *((DWORD *)outData) = otherNameLen*2;
7075 outData += 4; /* File Name Length */
7076 p = strdup(otherFilename);
7077 if (smb_StoreAnsiFilenames)
7079 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
7085 * If filename is null, we don't know the cause of the
7086 * change notification. We return zero data (see above),
7087 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
7088 * (= 0x010C). We set the error code here by hand, without
7089 * modifying wct and bcc.
7091 if (filename == NULL) {
7092 ((smb_t *) watch)->rcls = 0x0C;
7093 ((smb_t *) watch)->reh = 0x01;
7094 ((smb_t *) watch)->errLow = 0;
7095 ((smb_t *) watch)->errHigh = 0;
7096 /* Set NT Status codes flag */
7097 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7100 smb_SendPacket(watch->vcp, watch);
7101 smb_FreePacket(watch);
7104 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7107 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7109 unsigned char *replyWctp;
7110 smb_packet_t *watch, *lastWatch;
7111 USHORT fid, watchtree;
7115 osi_Log0(smb_logp, "SMB3 receive NT cancel");
7117 lock_ObtainMutex(&smb_Dir_Watch_Lock);
7118 watch = smb_Directory_Watches;
7120 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
7121 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
7122 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
7123 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
7124 if (watch == smb_Directory_Watches)
7125 smb_Directory_Watches = watch->nextp;
7127 lastWatch->nextp = watch->nextp;
7128 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7130 /* Turn off WATCHED flag in scp */
7131 fid = smb_GetSMBParm(watch, 21);
7132 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
7134 if (vcp != watch->vcp)
7135 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
7138 fidp = smb_FindFID(vcp, fid, 0);
7140 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
7142 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
7145 lock_ObtainMutex(&scp->mx);
7147 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
7149 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
7150 lock_ReleaseMutex(&scp->mx);
7151 smb_ReleaseFID(fidp);
7153 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
7156 /* assume STATUS32; return 0xC0000120 (CANCELED) */
7157 replyWctp = watch->wctp;
7161 ((smb_t *)watch)->rcls = 0x20;
7162 ((smb_t *)watch)->reh = 0x1;
7163 ((smb_t *)watch)->errLow = 0;
7164 ((smb_t *)watch)->errHigh = 0xC0;
7165 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7166 smb_SendPacket(vcp, watch);
7167 smb_FreePacket(watch);
7171 watch = watch->nextp;
7173 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7179 * NT rename also does hard links.
7182 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
7183 #define RENAME_FLAG_HARD_LINK 0x103
7184 #define RENAME_FLAG_RENAME 0x104
7185 #define RENAME_FLAG_COPY 0x105
7187 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7189 char *oldPathp, *newPathp;
7195 attrs = smb_GetSMBParm(inp, 0);
7196 rename_type = smb_GetSMBParm(inp, 1);
7198 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
7199 osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
7200 return CM_ERROR_NOACCESS;
7203 tp = smb_GetSMBData(inp, NULL);
7204 oldPathp = smb_ParseASCIIBlock(tp, &tp);
7205 if (smb_StoreAnsiFilenames)
7206 OemToChar(oldPathp,oldPathp);
7207 newPathp = smb_ParseASCIIBlock(tp, &tp);
7208 if (smb_StoreAnsiFilenames)
7209 OemToChar(newPathp,newPathp);
7211 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
7212 osi_LogSaveString(smb_logp, oldPathp),
7213 osi_LogSaveString(smb_logp, newPathp),
7214 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
7216 if (rename_type == RENAME_FLAG_RENAME) {
7217 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
7218 } else { /* RENAME_FLAG_HARD_LINK */
7219 code = smb_Link(vcp,inp,oldPathp,newPathp);
7226 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
7229 cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
7231 smb_username_t *unp;
7234 unp = smb_FindUserByName(usern, machine, flags);
7236 lock_ObtainMutex(&unp->mx);
7237 unp->userp = cm_NewUser();
7238 lock_ReleaseMutex(&unp->mx);
7239 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7241 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7245 smb_ReleaseUsername(unp);