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);
52 if (!uidp) return NULL;
54 lock_ObtainMutex(&uidp->mx);
56 up = uidp->unp->userp;
59 lock_ReleaseMutex(&uidp->mx);
67 * Return extended attributes.
68 * Right now, we aren't using any of the "new" bits, so this looks exactly
69 * like smb_Attributes() (see smb.c).
71 unsigned long smb_ExtAttributes(cm_scache_t *scp)
75 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
76 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
77 scp->fileType == CM_SCACHETYPE_INVALID)
79 attrs = SMB_ATTR_DIRECTORY;
80 #ifdef SPECIAL_FOLDERS
81 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
82 #endif /* SPECIAL_FOLDERS */
83 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
84 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
88 * We used to mark a file RO if it was in an RO volume, but that
89 * turns out to be impolitic in NT. See defect 10007.
92 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
93 attrs |= SMB_ATTR_READONLY; /* Read-only */
95 if ((scp->unixModeBits & 0222) == 0)
96 attrs |= SMB_ATTR_READONLY; /* Read-only */
100 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
105 int smb_V3IsStarMask(char *maskp)
109 while (tc = *maskp++)
110 if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
115 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
118 /* skip over null-terminated string */
119 *chainpp = inp + strlen(inp) + 1;
124 void OutputDebugF(char * format, ...) {
129 va_start( args, format );
130 len = _vscprintf( format, args ) // _vscprintf doesn't count
131 + 3; // terminating '\0' + '\n'
132 buffer = malloc( len * sizeof(char) );
133 vsprintf( buffer, format, args );
134 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buffer));
135 strcat(buffer, "\n");
136 OutputDebugString(buffer);
140 void OutputDebugHexDump(unsigned char * buffer, int len) {
143 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
145 OutputDebugF("Hexdump length [%d]",len);
147 for (i=0;i<len;i++) {
150 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
152 OutputDebugString(buf);
154 sprintf(buf,"%5x",i);
155 memset(buf+5,' ',80);
160 j = j*3 + 7 + ((j>7)?1:0);
163 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
166 j = j + 56 + ((j>7)?1:0);
168 buf[j] = (k>32 && k<127)?k:'.';
171 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
173 OutputDebugString(buf);
177 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
179 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
180 SECURITY_STATUS status, istatus;
181 CredHandle creds = {0,0};
183 SecBufferDesc secOut;
191 OutputDebugF("Negotiating Extended Security");
193 status = AcquireCredentialsHandle( NULL,
194 SMB_EXT_SEC_PACKAGE_NAME,
203 if (status != SEC_E_OK) {
204 /* Really bad. We return an empty security blob */
205 OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
210 secOut.pBuffers = &secTok;
211 secOut.ulVersion = SECBUFFER_VERSION;
213 secTok.BufferType = SECBUFFER_TOKEN;
215 secTok.pvBuffer = NULL;
217 ctx.dwLower = ctx.dwUpper = 0;
219 status = AcceptSecurityContext( &creds,
222 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
223 SECURITY_NETWORK_DREP,
230 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
231 OutputDebugF("Completing token...");
232 istatus = CompleteAuthToken(&ctx, &secOut);
233 if ( istatus != SEC_E_OK )
234 OutputDebugF("Token completion failed: %x", istatus);
237 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
238 if (secTok.pvBuffer) {
239 *secBlobLength = secTok.cbBuffer;
240 *secBlob = malloc( secTok.cbBuffer );
241 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
244 if ( status != SEC_E_OK )
245 OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
248 /* Discard partial security context */
249 DeleteSecurityContext(&ctx);
251 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
253 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
254 FreeCredentialsHandle(&creds);
260 struct smb_ext_context {
267 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
268 SECURITY_STATUS status, istatus;
272 SecBufferDesc secBufIn;
274 SecBufferDesc secBufOut;
277 struct smb_ext_context * secCtx = NULL;
278 struct smb_ext_context * newSecCtx = NULL;
279 void * assembledBlob = NULL;
280 int assembledBlobLength = 0;
283 OutputDebugF("In smb_AuthenticateUserExt");
286 *secBlobOutLength = 0;
288 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
289 secCtx = vcp->secCtx;
290 lock_ObtainMutex(&vcp->mx);
291 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
293 lock_ReleaseMutex(&vcp->mx);
297 OutputDebugF("Received incoming token:");
298 OutputDebugHexDump(secBlobIn,secBlobInLength);
302 OutputDebugF("Continuing with existing context.");
303 creds = secCtx->creds;
306 if (secCtx->partialToken) {
307 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
308 assembledBlob = malloc(assembledBlobLength);
309 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
310 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
313 status = AcquireCredentialsHandle( NULL,
314 SMB_EXT_SEC_PACKAGE_NAME,
323 if (status != SEC_E_OK) {
324 OutputDebugF("Can't acquire Credentials handle [%lX]", status);
325 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
333 secBufIn.cBuffers = 1;
334 secBufIn.pBuffers = &secTokIn;
335 secBufIn.ulVersion = SECBUFFER_VERSION;
337 secTokIn.BufferType = SECBUFFER_TOKEN;
339 secTokIn.cbBuffer = assembledBlobLength;
340 secTokIn.pvBuffer = assembledBlob;
342 secTokIn.cbBuffer = secBlobInLength;
343 secTokIn.pvBuffer = secBlobIn;
346 secBufOut.cBuffers = 1;
347 secBufOut.pBuffers = &secTokOut;
348 secBufOut.ulVersion = SECBUFFER_VERSION;
350 secTokOut.BufferType = SECBUFFER_TOKEN;
351 secTokOut.cbBuffer = 0;
352 secTokOut.pvBuffer = NULL;
354 status = AcceptSecurityContext( &creds,
355 ((secCtx)?&ctx:NULL),
357 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
358 SECURITY_NETWORK_DREP,
365 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
366 OutputDebugF("Completing token...");
367 istatus = CompleteAuthToken(&ctx, &secBufOut);
368 if ( istatus != SEC_E_OK )
369 OutputDebugF("Token completion failed: %lX", istatus);
372 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
373 OutputDebugF("Continue needed");
375 newSecCtx = malloc(sizeof(*newSecCtx));
377 newSecCtx->creds = creds;
378 newSecCtx->ctx = ctx;
379 newSecCtx->partialToken = NULL;
380 newSecCtx->partialTokenLen = 0;
382 lock_ObtainMutex( &vcp->mx );
383 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
384 vcp->secCtx = newSecCtx;
385 lock_ReleaseMutex( &vcp->mx );
387 code = CM_ERROR_GSSCONTINUE;
390 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
391 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
392 secTokOut.pvBuffer) {
393 OutputDebugF("Need to send token back to client");
395 *secBlobOutLength = secTokOut.cbBuffer;
396 *secBlobOut = malloc(secTokOut.cbBuffer);
397 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
399 OutputDebugF("Outgoing token:");
400 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
401 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
402 OutputDebugF("Incomplete message");
404 newSecCtx = malloc(sizeof(*newSecCtx));
406 newSecCtx->creds = creds;
407 newSecCtx->ctx = ctx;
408 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
409 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
410 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
412 lock_ObtainMutex( &vcp->mx );
413 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
414 vcp->secCtx = newSecCtx;
415 lock_ReleaseMutex( &vcp->mx );
417 code = CM_ERROR_GSSCONTINUE;
420 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
422 SecPkgContext_Names names;
424 OutputDebugF("Authentication completed");
425 OutputDebugF("Returned flags : [%lX]", flags);
427 if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
428 OutputDebugF("Received name [%s]", names.sUserName);
429 strcpy(usern, names.sUserName);
430 strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
431 FreeContextBuffer(names.sUserName);
433 /* Force the user to retry if the context is invalid */
434 OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
435 code = CM_ERROR_BADPASSWORD;
439 case SEC_E_INVALID_TOKEN:
440 OutputDebugF("Returning bad password :: INVALID_TOKEN");
442 case SEC_E_INVALID_HANDLE:
443 OutputDebugF("Returning bad password :: INVALID_HANDLE");
445 case SEC_E_LOGON_DENIED:
446 OutputDebugF("Returning bad password :: LOGON_DENIED");
448 case SEC_E_UNKNOWN_CREDENTIALS:
449 OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
451 case SEC_E_NO_CREDENTIALS:
452 OutputDebugF("Returning bad password :: NO_CREDENTIALS");
454 case SEC_E_CONTEXT_EXPIRED:
455 OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
457 case SEC_E_INCOMPLETE_CREDENTIALS:
458 OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
460 case SEC_E_WRONG_PRINCIPAL:
461 OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
463 case SEC_E_TIME_SKEW:
464 OutputDebugF("Returning bad password :: TIME_SKEW");
467 OutputDebugF("Returning bad password :: Status == %lX", status);
469 code = CM_ERROR_BADPASSWORD;
473 if (secCtx->partialToken) free(secCtx->partialToken);
481 if (secTokOut.pvBuffer)
482 FreeContextBuffer(secTokOut.pvBuffer);
484 if (code != CM_ERROR_GSSCONTINUE) {
485 DeleteSecurityContext(&ctx);
486 FreeCredentialsHandle(&creds);
494 #define P_RESP_LEN 128
496 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
497 So put stuff in a struct. */
498 struct Lm20AuthBlob {
499 MSV1_0_LM20_LOGON lmlogon;
500 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
501 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
502 WCHAR accountNameW[P_LEN];
503 WCHAR primaryDomainW[P_LEN];
504 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
505 TOKEN_GROUPS tgroups;
506 TOKEN_SOURCE tsource;
509 long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
512 struct Lm20AuthBlob lmAuth;
513 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
514 QUOTA_LIMITS quotaLimits;
516 ULONG lmprofilepSize;
520 OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
521 OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
523 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
524 OutputDebugF("ciPwdLength or csPwdLength is too long");
525 return CM_ERROR_BADPASSWORD;
528 memset(&lmAuth,0,sizeof(lmAuth));
530 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
532 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
533 mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
534 lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
535 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
537 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
538 mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
539 lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
540 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
542 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
543 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
544 size = MAX_COMPUTERNAME_LENGTH + 1;
545 GetComputerNameW(lmAuth.workstationW, &size);
546 lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
548 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
550 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
551 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
552 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
553 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
555 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
556 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
557 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
558 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
560 lmAuth.lmlogon.ParameterControl = 0;
562 lmAuth.tgroups.GroupCount = 0;
563 lmAuth.tgroups.Groups[0].Sid = NULL;
564 lmAuth.tgroups.Groups[0].Attributes = 0;
566 lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
567 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
568 strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
570 nts = LsaLogonUser( smb_lsaHandle,
585 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
586 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
589 OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
590 OutputDebugF("Extended status is 0x%lX", ntsEx);
592 if (nts == ERROR_SUCCESS) {
594 LsaFreeReturnBuffer(lmprofilep);
595 CloseHandle(lmToken);
599 if (nts == 0xC000015BL)
600 return CM_ERROR_BADLOGONTYPE;
601 else /* our catchall is a bad password though we could be more specific */
602 return CM_ERROR_BADPASSWORD;
606 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
607 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName)
612 /* check if we have sane input */
613 if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
616 /* we could get : [accountName][domainName]
622 atsign = strchr(accountName, '@');
624 if (atsign) /* [user@domain][] -> [user@domain][domain] */
629 /* if for some reason the client doesn't know what domain to use,
630 it will either return an empty string or a '?' */
631 if (!domain[0] || domain[0] == '?')
632 /* Empty domains and empty usernames are usually sent from tokenless contexts.
633 This way such logins will get an empty username (easy to check). I don't know
634 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
635 strcpy(usern,accountName);
637 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
638 strcpy(usern,domain);
641 strncat(usern,accountName,atsign - accountName);
643 strcat(usern,accountName);
651 /* When using SMB auth, all SMB sessions have to pass through here
652 * first to authenticate the user.
654 * Caveat: If not using SMB auth, the protocol does not require
655 * sending a session setup packet, which means that we can't rely on a
656 * UID in subsequent packets. Though in practice we get one anyway.
658 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
662 unsigned short newUid;
663 unsigned long caps = 0;
668 char usern[SMB_MAX_USERNAME_LENGTH];
669 char *secBlobOut = NULL;
670 int secBlobOutLength = 0;
672 /* Check for bad conns */
673 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
674 return CM_ERROR_REMOTECONN;
676 if (vcp->flags & SMB_VCFLAG_USENT) {
677 if (smb_authType == SMB_AUTH_EXTENDED) {
678 /* extended authentication */
682 OutputDebugF("NT Session Setup: Extended");
684 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
685 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
688 secBlobInLength = smb_GetSMBParm(inp, 7);
689 secBlobIn = smb_GetSMBData(inp, NULL);
691 code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
693 if (code == CM_ERROR_GSSCONTINUE) {
694 smb_SetSMBParm(outp, 2, 0);
695 smb_SetSMBParm(outp, 3, secBlobOutLength);
696 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
697 tp = smb_GetSMBData(outp, NULL);
698 if (secBlobOutLength) {
699 memcpy(tp, secBlobOut, secBlobOutLength);
701 tp += secBlobOutLength;
703 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
704 tp += smb_ServerOSLength;
705 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
706 tp += smb_ServerLanManagerLength;
707 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
708 tp += smb_ServerDomainNameLength;
711 /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
713 unsigned ciPwdLength, csPwdLength;
719 if (smb_authType == SMB_AUTH_NTLM)
720 OutputDebugF("NT Session Setup: NTLM");
722 OutputDebugF("NT Session Setup: None");
724 /* TODO: parse for extended auth as well */
725 ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
726 csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
728 tp = smb_GetSMBData(inp, &datalen);
730 OutputDebugF("Session packet data size [%d]",datalen);
737 accountName = smb_ParseString(tp, &tp);
738 primaryDomain = smb_ParseString(tp, NULL);
740 OutputDebugF("Account Name: %s",accountName);
741 OutputDebugF("Primary Domain: %s", primaryDomain);
742 OutputDebugF("Case Sensitive Password: %s", csPwd && csPwd[0] ? "yes" : "no");
743 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
745 if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
746 /* shouldn't happen */
747 code = CM_ERROR_BADSMB;
748 goto after_read_packet;
751 /* capabilities are only valid for first session packet */
752 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
753 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
756 if (smb_authType == SMB_AUTH_NTLM) {
757 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
759 OutputDebugF("LM authentication failed [%d]", code);
761 OutputDebugF("LM authentication succeeded");
765 unsigned ciPwdLength;
770 switch ( smb_authType ) {
771 case SMB_AUTH_EXTENDED:
772 OutputDebugF("V3 Session Setup: Extended");
775 OutputDebugF("V3 Session Setup: NTLM");
778 OutputDebugF("V3 Session Setup: None");
780 ciPwdLength = smb_GetSMBParm(inp, 7);
781 tp = smb_GetSMBData(inp, NULL);
785 accountName = smb_ParseString(tp, &tp);
786 primaryDomain = smb_ParseString(tp, NULL);
788 OutputDebugF("Account Name: %s",accountName);
789 OutputDebugF("Primary Domain: %s", primaryDomain);
790 OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
792 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
793 /* shouldn't happen */
794 code = CM_ERROR_BADSMB;
795 goto after_read_packet;
798 /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
801 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
802 code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
804 OutputDebugF("LM authentication failed [%d]", code);
806 OutputDebugF("LM authentication succeeded");
811 /* note down that we received a session setup X and set the capabilities flag */
812 if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
813 lock_ObtainMutex(&vcp->mx);
814 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
815 /* for the moment we can only deal with NTSTATUS */
816 if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
817 vcp->flags |= SMB_VCFLAG_STATUS32;
819 lock_ReleaseMutex(&vcp->mx);
822 /* code would be non-zero if there was an authentication failure.
823 Ideally we would like to invalidate the uid for this session or break
824 early to avoid accidently stealing someone else's tokens. */
830 OutputDebugF("Received username=[%s]", usern);
832 /* On Windows 2000, this function appears to be called more often than
833 it is expected to be called. This resulted in multiple smb_user_t
834 records existing all for the same user session which results in all
835 of the users tokens disappearing.
837 To avoid this problem, we look for an existing smb_user_t record
838 based on the users name, and use that one if we find it.
841 uidp = smb_FindUserByNameThisSession(vcp, usern);
842 if (uidp) { /* already there, so don't create a new one */
845 newUid = (unsigned short)uidp->userID; /* For some reason these are different types!*/
846 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
847 smb_ReleaseUID(uidp);
850 /* do a global search for the username/machine name pair */
851 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
853 /* Create a new UID and cm_user_t structure */
856 userp = cm_NewUser();
857 lock_ObtainMutex(&vcp->mx);
858 if (!vcp->uidCounter)
859 vcp->uidCounter++; /* handle unlikely wraparounds */
860 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
861 lock_ReleaseMutex(&vcp->mx);
863 /* Create a new smb_user_t structure and connect them up */
864 lock_ObtainMutex(&unp->mx);
866 lock_ReleaseMutex(&unp->mx);
868 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
869 lock_ObtainMutex(&uidp->mx);
871 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
872 lock_ReleaseMutex(&uidp->mx);
873 smb_ReleaseUID(uidp);
876 /* Return UID to the client */
877 ((smb_t *)outp)->uid = newUid;
878 /* Also to the next chained message */
879 ((smb_t *)inp)->uid = newUid;
881 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
882 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
884 smb_SetSMBParm(outp, 2, 0);
886 if (vcp->flags & SMB_VCFLAG_USENT) {
887 if (smb_authType == SMB_AUTH_EXTENDED) {
888 smb_SetSMBParm(outp, 3, secBlobOutLength);
889 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
890 tp = smb_GetSMBData(outp, NULL);
891 if (secBlobOutLength) {
892 memcpy(tp, secBlobOut, secBlobOutLength);
894 tp += secBlobOutLength;
896 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
897 tp += smb_ServerOSLength;
898 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
899 tp += smb_ServerLanManagerLength;
900 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
901 tp += smb_ServerDomainNameLength;
903 smb_SetSMBDataLength(outp, 0);
906 if (smb_authType == SMB_AUTH_EXTENDED) {
907 smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
908 tp = smb_GetSMBData(outp, NULL);
909 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
910 tp += smb_ServerOSLength;
911 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
912 tp += smb_ServerLanManagerLength;
913 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
914 tp += smb_ServerDomainNameLength;
916 smb_SetSMBDataLength(outp, 0);
923 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
927 /* don't get tokens from this VC */
928 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
930 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
932 /* find the tree and free it */
933 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
934 /* TODO: smb_ReleaseUID() ? */
936 char *s1 = NULL, *s2 = NULL;
938 if (s2 == NULL) s2 = " ";
939 if (s1 == NULL) {s1 = s2; s2 = " ";}
941 osi_Log4(smb_logp, "SMB3 user logoffX uid %d name %s%s%s", uidp->userID,
942 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "),
943 osi_LogSaveString(smb_logp,s1), osi_LogSaveString(smb_logp,s2));
945 lock_ObtainMutex(&uidp->mx);
946 uidp->flags |= SMB_USERFLAG_DELETE;
948 * it doesn't get deleted right away
949 * because the vcp points to it
951 lock_ReleaseMutex(&uidp->mx);
954 osi_Log0(smb_logp, "SMB3 user logoffX");
956 smb_SetSMBDataLength(outp, 0);
960 #define SMB_SUPPORT_SEARCH_BITS 0x0001
961 #define SMB_SHARE_IS_IN_DFS 0x0002
963 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
967 unsigned short newTid;
978 osi_Log0(smb_logp, "SMB3 receive tree connect");
980 /* parse input parameters */
981 tp = smb_GetSMBData(inp, NULL);
982 passwordp = smb_ParseString(tp, &tp);
983 pathp = smb_ParseString(tp, &tp);
984 if (smb_StoreAnsiFilenames)
985 OemToChar(pathp,pathp);
986 servicep = smb_ParseString(tp, &tp);
988 tp = strrchr(pathp, '\\');
990 return CM_ERROR_BADSMB;
992 strcpy(shareName, tp+1);
994 osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
995 osi_LogSaveString(smb_logp, pathp),
996 osi_LogSaveString(smb_logp, shareName));
998 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
1000 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1003 return CM_ERROR_NOIPC;
1007 userp = smb_GetUser(vcp, inp);
1009 lock_ObtainMutex(&vcp->mx);
1010 newTid = vcp->tidCounter++;
1011 lock_ReleaseMutex(&vcp->mx);
1013 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1016 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1017 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1019 smb_ReleaseUID(uidp);
1021 smb_ReleaseTID(tidp);
1022 return CM_ERROR_BADSHARENAME;
1025 if (vcp->flags & SMB_VCFLAG_USENT)
1027 int policy = smb_FindShareCSCPolicy(shareName);
1028 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1030 SMB_SHARE_IS_IN_DFS |
1035 smb_SetSMBParm(outp, 2, 0);
1039 lock_ObtainMutex(&tidp->mx);
1040 tidp->userp = userp;
1041 tidp->pathname = sharePath;
1043 tidp->flags |= SMB_TIDFLAG_IPC;
1044 lock_ReleaseMutex(&tidp->mx);
1045 smb_ReleaseTID(tidp);
1047 ((smb_t *)outp)->tid = newTid;
1048 ((smb_t *)inp)->tid = newTid;
1049 tp = smb_GetSMBData(outp, NULL);
1051 /* XXX - why is this a drive letter? */
1060 smb_SetSMBDataLength(outp, 8);
1063 smb_SetSMBDataLength(outp, 4);
1066 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1070 /* must be called with global tran lock held */
1071 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1073 smb_tran2Packet_t *tp;
1076 smbp = (smb_t *) inp->data;
1077 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1078 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1084 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1085 int totalParms, int totalData)
1087 smb_tran2Packet_t *tp;
1090 smbp = (smb_t *) inp->data;
1091 tp = malloc(sizeof(*tp));
1092 memset(tp, 0, sizeof(*tp));
1095 tp->curData = tp->curParms = 0;
1096 tp->totalData = totalData;
1097 tp->totalParms = totalParms;
1098 tp->tid = smbp->tid;
1099 tp->mid = smbp->mid;
1100 tp->uid = smbp->uid;
1101 tp->pid = smbp->pid;
1102 tp->res[0] = smbp->res[0];
1103 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1104 if (totalParms != 0)
1105 tp->parmsp = malloc(totalParms);
1107 tp->datap = malloc(totalData);
1108 if (smbp->com == 0x25 || smbp->com == 0x26)
1111 tp->opcode = smb_GetSMBParm(inp, 14);
1114 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1118 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1119 smb_tran2Packet_t *inp, smb_packet_t *outp,
1120 int totalParms, int totalData)
1122 smb_tran2Packet_t *tp;
1123 unsigned short parmOffset;
1124 unsigned short dataOffset;
1125 unsigned short dataAlign;
1127 tp = malloc(sizeof(*tp));
1128 memset(tp, 0, sizeof(*tp));
1130 tp->curData = tp->curParms = 0;
1131 tp->totalData = totalData;
1132 tp->totalParms = totalParms;
1133 tp->oldTotalParms = totalParms;
1138 tp->res[0] = inp->res[0];
1139 tp->opcode = inp->opcode;
1143 * We calculate where the parameters and data will start.
1144 * This calculation must parallel the calculation in
1145 * smb_SendTran2Packet.
1148 parmOffset = 10*2 + 35;
1149 parmOffset++; /* round to even */
1150 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1152 dataOffset = parmOffset + totalParms;
1153 dataAlign = dataOffset & 2; /* quad-align */
1154 dataOffset += dataAlign;
1155 tp->datap = outp->data + dataOffset;
1160 /* free a tran2 packet; must be called with smb_globalLock held */
1161 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1164 smb_ReleaseVC(t2p->vcp);
1165 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1174 /* called with a VC, an input packet to respond to, and an error code.
1175 * sends an error response.
1177 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1178 smb_packet_t *tp, long code)
1181 unsigned short errCode;
1182 unsigned char errClass;
1183 unsigned long NTStatus;
1185 if (vcp->flags & SMB_VCFLAG_STATUS32)
1186 smb_MapNTError(code, &NTStatus);
1188 smb_MapCoreError(code, vcp, &errCode, &errClass);
1190 smb_FormatResponsePacket(vcp, NULL, tp);
1191 smbp = (smb_t *) tp;
1193 /* We can handle long names */
1194 if (vcp->flags & SMB_VCFLAG_USENT)
1195 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1197 /* now copy important fields from the tran 2 packet */
1198 smbp->com = t2p->com;
1199 smbp->tid = t2p->tid;
1200 smbp->mid = t2p->mid;
1201 smbp->pid = t2p->pid;
1202 smbp->uid = t2p->uid;
1203 smbp->res[0] = t2p->res[0];
1204 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1205 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1206 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1207 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1208 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1209 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1212 smbp->rcls = errClass;
1213 smbp->errLow = (unsigned char) (errCode & 0xff);
1214 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1218 smb_SendPacket(vcp, tp);
1221 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1224 unsigned short parmOffset;
1225 unsigned short dataOffset;
1226 unsigned short totalLength;
1227 unsigned short dataAlign;
1230 smb_FormatResponsePacket(vcp, NULL, tp);
1231 smbp = (smb_t *) tp;
1233 /* We can handle long names */
1234 if (vcp->flags & SMB_VCFLAG_USENT)
1235 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1237 /* now copy important fields from the tran 2 packet */
1238 smbp->com = t2p->com;
1239 smbp->tid = t2p->tid;
1240 smbp->mid = t2p->mid;
1241 smbp->pid = t2p->pid;
1242 smbp->uid = t2p->uid;
1243 smbp->res[0] = t2p->res[0];
1245 totalLength = 1 + t2p->totalData + t2p->totalParms;
1247 /* now add the core parameters (tran2 info) to the packet */
1248 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1249 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1250 smb_SetSMBParm(tp, 2, 0); /* reserved */
1251 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1252 parmOffset = 10*2 + 35; /* parm offset in packet */
1253 parmOffset++; /* round to even */
1254 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1255 * hdr, bcc and wct */
1256 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1257 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1258 dataOffset = parmOffset + t2p->oldTotalParms;
1259 dataAlign = dataOffset & 2; /* quad-align */
1260 dataOffset += dataAlign;
1261 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1262 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1263 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1266 datap = smb_GetSMBData(tp, NULL);
1267 *datap++ = 0; /* we rounded to even */
1269 totalLength += dataAlign;
1270 smb_SetSMBDataLength(tp, totalLength);
1272 /* next, send the datagram */
1273 smb_SendPacket(vcp, tp);
1276 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1278 smb_tran2Packet_t *asp;
1291 /* We sometimes see 0 word count. What to do? */
1292 if (*inp->wctp == 0) {
1293 osi_Log0(smb_logp, "Transaction2 word count = 0");
1295 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1298 smb_SetSMBDataLength(outp, 0);
1299 smb_SendPacket(vcp, outp);
1303 totalParms = smb_GetSMBParm(inp, 0);
1304 totalData = smb_GetSMBParm(inp, 1);
1306 firstPacket = (inp->inCom == 0x25);
1308 /* find the packet we're reassembling */
1309 lock_ObtainWrite(&smb_globalLock);
1310 asp = smb_FindTran2Packet(vcp, inp);
1312 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1314 lock_ReleaseWrite(&smb_globalLock);
1316 /* now merge in this latest packet; start by looking up offsets */
1318 parmDisp = dataDisp = 0;
1319 parmOffset = smb_GetSMBParm(inp, 10);
1320 dataOffset = smb_GetSMBParm(inp, 12);
1321 parmCount = smb_GetSMBParm(inp, 9);
1322 dataCount = smb_GetSMBParm(inp, 11);
1323 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1324 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1326 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1327 totalData, dataCount, asp->maxReturnData);
1330 parmDisp = smb_GetSMBParm(inp, 4);
1331 parmOffset = smb_GetSMBParm(inp, 3);
1332 dataDisp = smb_GetSMBParm(inp, 7);
1333 dataOffset = smb_GetSMBParm(inp, 6);
1334 parmCount = smb_GetSMBParm(inp, 2);
1335 dataCount = smb_GetSMBParm(inp, 5);
1337 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1338 parmCount, dataCount);
1341 /* now copy the parms and data */
1342 if ( asp->totalParms > 0 && parmCount != 0 )
1344 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1346 if ( asp->totalData > 0 && dataCount != 0 ) {
1347 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1350 /* account for new bytes */
1351 asp->curData += dataCount;
1352 asp->curParms += parmCount;
1354 /* finally, if we're done, remove the packet from the queue and dispatch it */
1355 if (asp->totalParms > 0 &&
1356 asp->curParms > 0 &&
1357 asp->totalData <= asp->curData &&
1358 asp->totalParms <= asp->curParms) {
1359 /* we've received it all */
1360 lock_ObtainWrite(&smb_globalLock);
1361 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1362 lock_ReleaseWrite(&smb_globalLock);
1364 /* now dispatch it */
1365 rapOp = asp->parmsp[0];
1367 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1368 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1369 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1370 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
1373 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1374 code = CM_ERROR_BADOP;
1377 /* if an error is returned, we're supposed to send an error packet,
1378 * otherwise the dispatched function already did the data sending.
1379 * We give dispatched proc the responsibility since it knows how much
1380 * space to allocate.
1383 smb_SendTran2Error(vcp, asp, outp, code);
1386 /* free the input tran 2 packet */
1387 lock_ObtainWrite(&smb_globalLock);
1388 smb_FreeTran2Packet(asp);
1389 lock_ReleaseWrite(&smb_globalLock);
1391 else if (firstPacket) {
1392 /* the first packet in a multi-packet request, we need to send an
1393 * ack to get more data.
1395 smb_SetSMBDataLength(outp, 0);
1396 smb_SendPacket(vcp, outp);
1402 /* ANSI versions. The unicode versions support arbitrary length
1403 share names, but we don't support unicode yet. */
1405 typedef struct smb_rap_share_info_0 {
1406 char shi0_netname[13];
1407 } smb_rap_share_info_0_t;
1409 typedef struct smb_rap_share_info_1 {
1410 char shi1_netname[13];
1413 DWORD shi1_remark; /* char *shi1_remark; data offset */
1414 } smb_rap_share_info_1_t;
1416 typedef struct smb_rap_share_info_2 {
1417 char shi2_netname[13];
1419 unsigned short shi2_type;
1420 DWORD shi2_remark; /* char *shi2_remark; data offset */
1421 unsigned short shi2_permissions;
1422 unsigned short shi2_max_uses;
1423 unsigned short shi2_current_uses;
1424 DWORD shi2_path; /* char *shi2_path; data offset */
1425 unsigned short shi2_passwd[9];
1426 unsigned short shi2_pad2;
1427 } smb_rap_share_info_2_t;
1429 #define SMB_RAP_MAX_SHARES 512
1431 typedef struct smb_rap_share_list {
1434 smb_rap_share_info_0_t * shares;
1435 } smb_rap_share_list_t;
1437 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1438 smb_rap_share_list_t * sp;
1443 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1444 return 0; /* skip over '.' and '..' */
1446 sp = (smb_rap_share_list_t *) vrockp;
1448 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1449 sp->shares[sp->cShare].shi0_netname[12] = 0;
1453 if (sp->cShare >= sp->maxShares)
1454 return CM_ERROR_STOPNOW;
1459 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1461 smb_tran2Packet_t *outp;
1462 unsigned short * tp;
1466 int outParmsTotal; /* total parameter bytes */
1467 int outDataTotal; /* total data bytes */
1475 HKEY hkSubmount = NULL;
1476 smb_rap_share_info_1_t * shares;
1479 char thisShare[256];
1482 smb_rap_share_list_t rootShares;
1487 tp = p->parmsp + 1; /* skip over function number (always 0) */
1488 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1489 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1493 if (infoLevel != 1) {
1494 return CM_ERROR_INVAL;
1497 /* first figure out how many shares there are */
1498 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1499 KEY_QUERY_VALUE, &hkParam);
1500 if (rv == ERROR_SUCCESS) {
1501 len = sizeof(allSubmount);
1502 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1503 (BYTE *) &allSubmount, &len);
1504 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1507 RegCloseKey (hkParam);
1510 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1511 0, KEY_QUERY_VALUE, &hkSubmount);
1512 if (rv == ERROR_SUCCESS) {
1513 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1514 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1515 if (rv != ERROR_SUCCESS)
1521 /* fetch the root shares */
1522 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1523 rootShares.cShare = 0;
1524 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1528 userp = smb_GetTran2User(vcp,p);
1530 thyper.HighPart = 0;
1533 cm_HoldSCache(cm_data.rootSCachep);
1534 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1535 cm_ReleaseSCache(cm_data.rootSCachep);
1537 cm_ReleaseUser(userp);
1539 nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1541 #define REMARK_LEN 1
1542 outParmsTotal = 8; /* 4 dwords */
1543 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1544 if(outDataTotal > bufsize) {
1545 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1546 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1549 nSharesRet = nShares;
1552 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1554 /* now for the submounts */
1555 shares = (smb_rap_share_info_1_t *) outp->datap;
1556 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1558 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1561 strcpy( shares[cshare].shi1_netname, "all" );
1562 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1563 /* type and pad are zero already */
1569 for (i=0; i < nRegShares && cshare < nSharesRet; i++) {
1570 len = sizeof(thisShare);
1571 rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1572 if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1573 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1574 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1575 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1580 nShares--; /* uncount key */
1583 RegCloseKey(hkSubmount);
1586 nonrootShares = cshare;
1588 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1589 /* in case there are collisions with submounts, submounts have higher priority */
1590 for (j=0; j < nonrootShares; j++)
1591 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1594 if (j < nonrootShares) {
1595 nShares--; /* uncount */
1599 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1600 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1605 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1606 outp->parmsp[1] = 0;
1607 outp->parmsp[2] = cshare;
1608 outp->parmsp[3] = nShares;
1610 outp->totalData = (int)(cstrp - outp->datap);
1611 outp->totalParms = outParmsTotal;
1613 smb_SendTran2Packet(vcp, outp, op);
1614 smb_FreeTran2Packet(outp);
1616 free(rootShares.shares);
1621 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1623 smb_tran2Packet_t *outp;
1624 unsigned short * tp;
1626 BOOL shareFound = FALSE;
1627 unsigned short infoLevel;
1628 unsigned short bufsize;
1638 tp = p->parmsp + 1; /* skip over function number (always 1) */
1639 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1640 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1641 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1648 totalData = sizeof(smb_rap_share_info_0_t);
1649 else if(infoLevel == SMB_INFO_STANDARD)
1650 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1651 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1652 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1654 return CM_ERROR_INVAL;
1656 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1658 if(!stricmp(shareName,"all")) {
1659 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1660 KEY_QUERY_VALUE, &hkParam);
1661 if (rv == ERROR_SUCCESS) {
1662 len = sizeof(allSubmount);
1663 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1664 (BYTE *) &allSubmount, &len);
1665 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1668 RegCloseKey (hkParam);
1675 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1676 KEY_QUERY_VALUE, &hkSubmount);
1677 if (rv == ERROR_SUCCESS) {
1678 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1679 if (rv == ERROR_SUCCESS) {
1682 RegCloseKey(hkSubmount);
1687 smb_FreeTran2Packet(outp);
1688 return CM_ERROR_BADSHARENAME;
1691 memset(outp->datap, 0, totalData);
1693 outp->parmsp[0] = 0;
1694 outp->parmsp[1] = 0;
1695 outp->parmsp[2] = totalData;
1697 if (infoLevel == 0) {
1698 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1699 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1700 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1701 } else if(infoLevel == SMB_INFO_STANDARD) {
1702 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1703 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1704 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1705 info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1706 /* type and pad are already zero */
1707 } else { /* infoLevel==2 */
1708 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1709 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1710 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1711 info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1712 info->shi2_permissions = ACCESS_ALL;
1713 info->shi2_max_uses = (unsigned short) -1;
1714 info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
1717 outp->totalData = totalData;
1718 outp->totalParms = totalParam;
1720 smb_SendTran2Packet(vcp, outp, op);
1721 smb_FreeTran2Packet(outp);
1726 typedef struct smb_rap_wksta_info_10 {
1727 DWORD wki10_computername; /*char *wki10_computername;*/
1728 DWORD wki10_username; /* char *wki10_username; */
1729 DWORD wki10_langroup; /* char *wki10_langroup;*/
1730 unsigned char wki10_ver_major;
1731 unsigned char wki10_ver_minor;
1732 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1733 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1734 } smb_rap_wksta_info_10_t;
1737 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1739 smb_tran2Packet_t *outp;
1743 unsigned short * tp;
1746 smb_rap_wksta_info_10_t * info;
1750 tp = p->parmsp + 1; /* Skip over function number */
1751 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1752 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1756 if (infoLevel != 10) {
1757 return CM_ERROR_INVAL;
1763 totalData = sizeof(*info) + /* info */
1764 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1765 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1766 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1767 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1768 1; /* wki10_oth_domains (null)*/
1770 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1772 memset(outp->parmsp,0,totalParams);
1773 memset(outp->datap,0,totalData);
1775 info = (smb_rap_wksta_info_10_t *) outp->datap;
1776 cstrp = (char *) (info + 1);
1778 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1779 strcpy(cstrp, smb_localNamep);
1780 cstrp += strlen(cstrp) + 1;
1782 info->wki10_username = (DWORD) (cstrp - outp->datap);
1783 uidp = smb_FindUID(vcp, p->uid, 0);
1785 lock_ObtainMutex(&uidp->mx);
1786 if(uidp->unp && uidp->unp->name)
1787 strcpy(cstrp, uidp->unp->name);
1788 lock_ReleaseMutex(&uidp->mx);
1789 smb_ReleaseUID(uidp);
1791 cstrp += strlen(cstrp) + 1;
1793 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1794 strcpy(cstrp, "WORKGROUP");
1795 cstrp += strlen(cstrp) + 1;
1797 /* TODO: Not sure what values these should take, but these work */
1798 info->wki10_ver_major = 5;
1799 info->wki10_ver_minor = 1;
1801 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1802 strcpy(cstrp, smb_ServerDomainName);
1803 cstrp += strlen(cstrp) + 1;
1805 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1806 cstrp ++; /* no other domains */
1808 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1809 outp->parmsp[2] = outp->totalData;
1810 outp->totalParms = totalParams;
1812 smb_SendTran2Packet(vcp,outp,op);
1813 smb_FreeTran2Packet(outp);
1818 typedef struct smb_rap_server_info_0 {
1820 } smb_rap_server_info_0_t;
1822 typedef struct smb_rap_server_info_1 {
1824 char sv1_version_major;
1825 char sv1_version_minor;
1826 unsigned long sv1_type;
1827 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1828 } smb_rap_server_info_1_t;
1830 char smb_ServerComment[] = "OpenAFS Client";
1831 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1833 #define SMB_SV_TYPE_SERVER 0x00000002L
1834 #define SMB_SV_TYPE_NT 0x00001000L
1835 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1837 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1839 smb_tran2Packet_t *outp;
1843 unsigned short * tp;
1846 smb_rap_server_info_0_t * info0;
1847 smb_rap_server_info_1_t * info1;
1850 tp = p->parmsp + 1; /* Skip over function number */
1851 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1852 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1856 if (infoLevel != 0 && infoLevel != 1) {
1857 return CM_ERROR_INVAL;
1863 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1864 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1866 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1868 memset(outp->parmsp,0,totalParams);
1869 memset(outp->datap,0,totalData);
1871 if (infoLevel == 0) {
1872 info0 = (smb_rap_server_info_0_t *) outp->datap;
1873 cstrp = (char *) (info0 + 1);
1874 strcpy(info0->sv0_name, "AFS");
1875 } else { /* infoLevel == SMB_INFO_STANDARD */
1876 info1 = (smb_rap_server_info_1_t *) outp->datap;
1877 cstrp = (char *) (info1 + 1);
1878 strcpy(info1->sv1_name, "AFS");
1881 SMB_SV_TYPE_SERVER |
1883 SMB_SV_TYPE_SERVER_NT;
1885 info1->sv1_version_major = 5;
1886 info1->sv1_version_minor = 1;
1887 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1889 strcpy(cstrp, smb_ServerComment);
1891 cstrp += smb_ServerCommentLen;
1894 totalData = (DWORD)(cstrp - outp->datap);
1895 outp->totalData = min(bufsize,totalData); /* actual data size */
1896 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1897 outp->parmsp[2] = totalData;
1898 outp->totalParms = totalParams;
1900 smb_SendTran2Packet(vcp,outp,op);
1901 smb_FreeTran2Packet(outp);
1906 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1908 smb_tran2Packet_t *asp;
1920 /* We sometimes see 0 word count. What to do? */
1921 if (*inp->wctp == 0) {
1922 osi_Log0(smb_logp, "Transaction2 word count = 0");
1924 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1927 smb_SetSMBDataLength(outp, 0);
1928 smb_SendPacket(vcp, outp);
1932 totalParms = smb_GetSMBParm(inp, 0);
1933 totalData = smb_GetSMBParm(inp, 1);
1935 firstPacket = (inp->inCom == 0x32);
1937 /* find the packet we're reassembling */
1938 lock_ObtainWrite(&smb_globalLock);
1939 asp = smb_FindTran2Packet(vcp, inp);
1941 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1943 lock_ReleaseWrite(&smb_globalLock);
1945 /* now merge in this latest packet; start by looking up offsets */
1947 parmDisp = dataDisp = 0;
1948 parmOffset = smb_GetSMBParm(inp, 10);
1949 dataOffset = smb_GetSMBParm(inp, 12);
1950 parmCount = smb_GetSMBParm(inp, 9);
1951 dataCount = smb_GetSMBParm(inp, 11);
1952 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1953 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1955 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1956 totalData, dataCount, asp->maxReturnData);
1959 parmDisp = smb_GetSMBParm(inp, 4);
1960 parmOffset = smb_GetSMBParm(inp, 3);
1961 dataDisp = smb_GetSMBParm(inp, 7);
1962 dataOffset = smb_GetSMBParm(inp, 6);
1963 parmCount = smb_GetSMBParm(inp, 2);
1964 dataCount = smb_GetSMBParm(inp, 5);
1966 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1967 parmCount, dataCount);
1970 /* now copy the parms and data */
1971 if ( asp->totalParms > 0 && parmCount != 0 )
1973 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1975 if ( asp->totalData > 0 && dataCount != 0 ) {
1976 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1979 /* account for new bytes */
1980 asp->curData += dataCount;
1981 asp->curParms += parmCount;
1983 /* finally, if we're done, remove the packet from the queue and dispatch it */
1984 if (asp->totalParms > 0 &&
1985 asp->curParms > 0 &&
1986 asp->totalData <= asp->curData &&
1987 asp->totalParms <= asp->curParms) {
1988 /* we've received it all */
1989 lock_ObtainWrite(&smb_globalLock);
1990 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1991 lock_ReleaseWrite(&smb_globalLock);
1993 /* now dispatch it */
1994 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
1995 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
1996 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
1999 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2000 code = CM_ERROR_BADOP;
2003 /* if an error is returned, we're supposed to send an error packet,
2004 * otherwise the dispatched function already did the data sending.
2005 * We give dispatched proc the responsibility since it knows how much
2006 * space to allocate.
2009 smb_SendTran2Error(vcp, asp, outp, code);
2012 /* free the input tran 2 packet */
2013 lock_ObtainWrite(&smb_globalLock);
2014 smb_FreeTran2Packet(asp);
2015 lock_ReleaseWrite(&smb_globalLock);
2017 else if (firstPacket) {
2018 /* the first packet in a multi-packet request, we need to send an
2019 * ack to get more data.
2021 smb_SetSMBDataLength(outp, 0);
2022 smb_SendPacket(vcp, outp);
2028 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2031 smb_tran2Packet_t *outp;
2036 cm_scache_t *dscp; /* dir we're dealing with */
2037 cm_scache_t *scp; /* file we're creating */
2039 int initialModeBits;
2049 int parmSlot; /* which parm we're dealing with */
2050 long returnEALength;
2058 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2059 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2061 openFun = p->parmsp[6]; /* open function */
2062 excl = ((openFun & 3) == 0);
2063 trunc = ((openFun & 3) == 2); /* truncate it */
2064 openMode = (p->parmsp[1] & 0x7);
2065 openAction = 0; /* tracks what we did */
2067 attributes = p->parmsp[3];
2068 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2070 /* compute initial mode bits based on read-only flag in attributes */
2071 initialModeBits = 0666;
2073 initialModeBits &= ~0222;
2075 pathp = (char *) (&p->parmsp[14]);
2076 if (smb_StoreAnsiFilenames)
2077 OemToChar(pathp,pathp);
2079 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2081 spacep = cm_GetSpace();
2082 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2084 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2085 /* special case magic file name for receiving IOCTL requests
2086 * (since IOCTL calls themselves aren't getting through).
2088 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2089 smb_SetupIoctlFid(fidp, spacep);
2091 /* copy out remainder of the parms */
2093 outp->parmsp[parmSlot++] = fidp->fid;
2095 outp->parmsp[parmSlot++] = 0; /* attrs */
2096 outp->parmsp[parmSlot++] = 0; /* mod time */
2097 outp->parmsp[parmSlot++] = 0;
2098 outp->parmsp[parmSlot++] = 0; /* len */
2099 outp->parmsp[parmSlot++] = 0x7fff;
2100 outp->parmsp[parmSlot++] = openMode;
2101 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2102 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2104 /* and the final "always present" stuff */
2105 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2106 /* next write out the "unique" ID */
2107 outp->parmsp[parmSlot++] = 0x1234;
2108 outp->parmsp[parmSlot++] = 0x5678;
2109 outp->parmsp[parmSlot++] = 0;
2110 if (returnEALength) {
2111 outp->parmsp[parmSlot++] = 0;
2112 outp->parmsp[parmSlot++] = 0;
2115 outp->totalData = 0;
2116 outp->totalParms = parmSlot * 2;
2118 smb_SendTran2Packet(vcp, outp, op);
2120 smb_FreeTran2Packet(outp);
2122 /* and clean up fid reference */
2123 smb_ReleaseFID(fidp);
2127 #ifdef DEBUG_VERBOSE
2129 char *hexp, *asciip;
2130 asciip = (lastNamep ? lastNamep : pathp);
2131 hexp = osi_HexifyString( asciip );
2132 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2137 userp = smb_GetTran2User(vcp, p);
2138 /* In the off chance that userp is NULL, we log and abandon */
2140 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2141 smb_FreeTran2Packet(outp);
2142 return CM_ERROR_BADSMB;
2145 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2146 if (code == CM_ERROR_TIDIPC) {
2147 /* Attempt to use a TID allocated for IPC. The client
2148 * is probably looking for DCE RPC end points which we
2149 * don't support OR it could be looking to make a DFS
2152 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2154 cm_ReleaseUser(userp);
2155 smb_FreeTran2Packet(outp);
2156 return CM_ERROR_NOSUCHPATH;
2161 code = cm_NameI(cm_data.rootSCachep, pathp,
2162 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2163 userp, tidPathp, &req, &scp);
2165 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2166 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2167 userp, tidPathp, &req, &dscp);
2168 cm_FreeSpace(spacep);
2171 cm_ReleaseUser(userp);
2172 smb_FreeTran2Packet(outp);
2177 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2178 cm_ReleaseSCache(dscp);
2179 cm_ReleaseUser(userp);
2180 smb_FreeTran2Packet(outp);
2181 if ( WANTS_DFS_PATHNAMES(p) )
2182 return CM_ERROR_PATH_NOT_COVERED;
2184 return CM_ERROR_BADSHARENAME;
2186 #endif /* DFS_SUPPORT */
2188 /* otherwise, scp points to the parent directory. Do a lookup,
2189 * and truncate the file if we find it, otherwise we create the
2196 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2198 if (code && code != CM_ERROR_NOSUCHFILE) {
2199 cm_ReleaseSCache(dscp);
2200 cm_ReleaseUser(userp);
2201 smb_FreeTran2Packet(outp);
2206 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2207 cm_ReleaseSCache(scp);
2208 cm_ReleaseUser(userp);
2209 smb_FreeTran2Packet(outp);
2210 if ( WANTS_DFS_PATHNAMES(p) )
2211 return CM_ERROR_PATH_NOT_COVERED;
2213 return CM_ERROR_BADSHARENAME;
2215 #endif /* DFS_SUPPORT */
2217 /* macintosh is expensive to program for it */
2218 cm_FreeSpace(spacep);
2221 /* if we get here, if code is 0, the file exists and is represented by
2222 * scp. Otherwise, we have to create it.
2225 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2228 cm_ReleaseSCache(dscp);
2229 cm_ReleaseSCache(scp);
2230 cm_ReleaseUser(userp);
2231 smb_FreeTran2Packet(outp);
2236 /* oops, file shouldn't be there */
2238 cm_ReleaseSCache(dscp);
2239 cm_ReleaseSCache(scp);
2240 cm_ReleaseUser(userp);
2241 smb_FreeTran2Packet(outp);
2242 return CM_ERROR_EXISTS;
2246 setAttr.mask = CM_ATTRMASK_LENGTH;
2247 setAttr.length.LowPart = 0;
2248 setAttr.length.HighPart = 0;
2249 code = cm_SetAttr(scp, &setAttr, userp, &req);
2250 openAction = 3; /* truncated existing file */
2253 openAction = 1; /* found existing file */
2255 else if (!(openFun & 0x10)) {
2256 /* don't create if not found */
2258 cm_ReleaseSCache(dscp);
2259 osi_assert(scp == NULL);
2260 cm_ReleaseUser(userp);
2261 smb_FreeTran2Packet(outp);
2262 return CM_ERROR_NOSUCHFILE;
2265 osi_assert(dscp != NULL && scp == NULL);
2266 openAction = 2; /* created file */
2267 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2268 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2269 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2271 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2272 smb_NotifyChange(FILE_ACTION_ADDED,
2273 FILE_NOTIFY_CHANGE_FILE_NAME,
2274 dscp, lastNamep, NULL, TRUE);
2275 if (!excl && code == CM_ERROR_EXISTS) {
2276 /* not an exclusive create, and someone else tried
2277 * creating it already, then we open it anyway. We
2278 * don't bother retrying after this, since if this next
2279 * fails, that means that the file was deleted after we
2280 * started this call.
2282 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2286 setAttr.mask = CM_ATTRMASK_LENGTH;
2287 setAttr.length.LowPart = 0;
2288 setAttr.length.HighPart = 0;
2289 code = cm_SetAttr(scp, &setAttr, userp,
2292 } /* lookup succeeded */
2296 /* we don't need this any longer */
2298 cm_ReleaseSCache(dscp);
2301 /* something went wrong creating or truncating the file */
2303 cm_ReleaseSCache(scp);
2304 cm_ReleaseUser(userp);
2305 smb_FreeTran2Packet(outp);
2309 /* make sure we're about to open a file */
2310 if (scp->fileType != CM_SCACHETYPE_FILE) {
2312 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2313 cm_scache_t * targetScp = 0;
2314 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2316 /* we have a more accurate file to use (the
2317 * target of the symbolic link). Otherwise,
2318 * we'll just use the symlink anyway.
2320 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2322 cm_ReleaseSCache(scp);
2326 if (scp->fileType != CM_SCACHETYPE_FILE) {
2327 cm_ReleaseSCache(scp);
2328 cm_ReleaseUser(userp);
2329 smb_FreeTran2Packet(outp);
2330 return CM_ERROR_ISDIR;
2334 /* now all we have to do is open the file itself */
2335 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2338 /* save a pointer to the vnode */
2341 /* compute open mode */
2342 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2343 if (openMode == 1 || openMode == 2)
2344 fidp->flags |= SMB_FID_OPENWRITE;
2346 smb_ReleaseFID(fidp);
2348 cm_Open(scp, 0, userp);
2350 /* copy out remainder of the parms */
2352 outp->parmsp[parmSlot++] = fidp->fid;
2353 lock_ObtainMutex(&scp->mx);
2355 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2356 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2357 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2358 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2359 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2360 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2361 outp->parmsp[parmSlot++] = openMode;
2362 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2363 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2365 /* and the final "always present" stuff */
2366 outp->parmsp[parmSlot++] = openAction;
2367 /* next write out the "unique" ID */
2368 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2369 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2370 outp->parmsp[parmSlot++] = 0;
2371 if (returnEALength) {
2372 outp->parmsp[parmSlot++] = 0;
2373 outp->parmsp[parmSlot++] = 0;
2375 lock_ReleaseMutex(&scp->mx);
2376 outp->totalData = 0; /* total # of data bytes */
2377 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2379 smb_SendTran2Packet(vcp, outp, op);
2381 smb_FreeTran2Packet(outp);
2383 cm_ReleaseUser(userp);
2384 /* leave scp held since we put it in fidp->scp */
2388 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2390 osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2391 return CM_ERROR_BADOP;
2394 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2396 osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2397 return CM_ERROR_BADOP;
2400 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2402 smb_tran2Packet_t *outp;
2403 smb_tran2QFSInfo_t qi;
2406 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
2408 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2410 switch (p->parmsp[0]) {
2411 case 1: responseSize = sizeof(qi.u.allocInfo); break;
2412 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
2413 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
2414 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
2415 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
2416 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
2417 case 0x200: /* CIFS Unix Info */
2418 case 0x301: /* Mac FS Info */
2419 default: return CM_ERROR_INVAL;
2422 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2423 switch (p->parmsp[0]) {
2426 qi.u.allocInfo.FSID = 0;
2427 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2428 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2429 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2430 qi.u.allocInfo.bytesPerSector = 1024;
2435 qi.u.volumeInfo.vsn = 1234;
2436 qi.u.volumeInfo.vnCount = 4;
2437 /* we're supposed to pad it out with zeroes to the end */
2438 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2439 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2443 /* FS volume info */
2444 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
2445 qi.u.FSvolumeInfo.vsn = 1234;
2446 qi.u.FSvolumeInfo.vnCount = 8;
2447 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
2453 temp.LowPart = 0x7fffffff;
2454 qi.u.FSsizeInfo.totalAllocUnits = temp;
2455 temp.LowPart = 0x3fffffff;
2456 qi.u.FSsizeInfo.availAllocUnits = temp;
2457 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2458 qi.u.FSsizeInfo.bytesPerSector = 1024;
2462 /* FS device info */
2463 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
2464 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2468 /* FS attribute info */
2469 /* attributes, defined in WINNT.H:
2470 * FILE_CASE_SENSITIVE_SEARCH 0x1
2471 * FILE_CASE_PRESERVED_NAMES 0x2
2472 * <no name defined> 0x4000
2473 * If bit 0x4000 is not set, Windows 95 thinks
2474 * we can't handle long (non-8.3) names,
2475 * despite our protestations to the contrary.
2477 qi.u.FSattributeInfo.attributes = 0x4003;
2478 qi.u.FSattributeInfo.maxCompLength = 255;
2479 qi.u.FSattributeInfo.FSnameLength = 6;
2480 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
2484 /* copy out return data, and set corresponding sizes */
2485 outp->totalParms = 0;
2486 outp->totalData = responseSize;
2487 memcpy(outp->datap, &qi, responseSize);
2489 /* send and free the packets */
2490 smb_SendTran2Packet(vcp, outp, op);
2491 smb_FreeTran2Packet(outp);
2496 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2498 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2499 return CM_ERROR_BADOP;
2502 struct smb_ShortNameRock {
2506 size_t shortNameLen;
2509 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2512 struct smb_ShortNameRock *rockp;
2516 /* compare both names and vnodes, though probably just comparing vnodes
2517 * would be safe enough.
2519 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2521 if (ntohl(dep->fid.vnode) != rockp->vnode)
2523 /* This is the entry */
2524 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2525 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2526 return CM_ERROR_STOPNOW;
2529 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2530 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2532 struct smb_ShortNameRock rock;
2536 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2540 spacep = cm_GetSpace();
2541 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2543 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2545 cm_FreeSpace(spacep);
2550 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2551 cm_ReleaseSCache(dscp);
2552 cm_ReleaseUser(userp);
2553 return CM_ERROR_PATH_NOT_COVERED;
2555 #endif /* DFS_SUPPORT */
2557 if (!lastNamep) lastNamep = pathp;
2560 thyper.HighPart = 0;
2561 rock.shortName = shortName;
2563 rock.maskp = lastNamep;
2564 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2566 cm_ReleaseSCache(dscp);
2569 return CM_ERROR_NOSUCHFILE;
2570 if (code == CM_ERROR_STOPNOW) {
2571 *shortNameLenp = rock.shortNameLen;
2577 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2579 smb_tran2Packet_t *outp;
2582 unsigned short infoLevel;
2584 unsigned short attributes;
2585 unsigned long extAttributes;
2590 cm_scache_t *scp, *dscp;
2599 infoLevel = p->parmsp[0];
2600 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2602 else if (infoLevel == SMB_INFO_STANDARD)
2603 nbytesRequired = 22;
2604 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2605 nbytesRequired = 26;
2606 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2607 nbytesRequired = 40;
2608 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2609 nbytesRequired = 24;
2610 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2612 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2613 nbytesRequired = 30;
2615 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2616 p->opcode, infoLevel);
2617 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2620 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2621 osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
2623 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2625 if (infoLevel > 0x100)
2626 outp->totalParms = 2;
2628 outp->totalParms = 0;
2629 outp->totalData = nbytesRequired;
2631 /* now, if we're at infoLevel 6, we're only being asked to check
2632 * the syntax, so we just OK things now. In particular, we're *not*
2633 * being asked to verify anything about the state of any parent dirs.
2635 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2636 smb_SendTran2Packet(vcp, outp, opx);
2637 smb_FreeTran2Packet(outp);
2641 userp = smb_GetTran2User(vcp, p);
2643 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2644 smb_FreeTran2Packet(outp);
2645 return CM_ERROR_BADSMB;
2648 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2650 cm_ReleaseUser(userp);
2651 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2652 smb_FreeTran2Packet(outp);
2657 * XXX Strange hack XXX
2659 * As of Patch 7 (13 January 98), we are having the following problem:
2660 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2661 * requests to look up "desktop.ini" in all the subdirectories.
2662 * This can cause zillions of timeouts looking up non-existent cells
2663 * and volumes, especially in the top-level directory.
2665 * We have not found any way to avoid this or work around it except
2666 * to explicitly ignore the requests for mount points that haven't
2667 * yet been evaluated and for directories that haven't yet been
2670 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2671 spacep = cm_GetSpace();
2672 smb_StripLastComponent(spacep->data, &lastComp,
2673 (char *)(&p->parmsp[3]));
2674 #ifndef SPECIAL_FOLDERS
2675 /* Make sure that lastComp is not NULL */
2677 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2678 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2682 userp, tidPathp, &req, &dscp);
2685 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2686 if ( WANTS_DFS_PATHNAMES(p) )
2687 code = CM_ERROR_PATH_NOT_COVERED;
2689 code = CM_ERROR_BADSHARENAME;
2691 #endif /* DFS_SUPPORT */
2692 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2693 code = CM_ERROR_NOSUCHFILE;
2694 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2695 cm_buf_t *bp = buf_Find(dscp, &hzero);
2699 code = CM_ERROR_NOSUCHFILE;
2701 cm_ReleaseSCache(dscp);
2703 cm_FreeSpace(spacep);
2704 cm_ReleaseUser(userp);
2705 smb_SendTran2Error(vcp, p, opx, code);
2706 smb_FreeTran2Packet(outp);
2712 #endif /* SPECIAL_FOLDERS */
2714 cm_FreeSpace(spacep);
2717 /* now do namei and stat, and copy out the info */
2718 code = cm_NameI(cm_data.rootSCachep, (char *)(&p->parmsp[3]),
2719 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2722 cm_ReleaseUser(userp);
2723 smb_SendTran2Error(vcp, p, opx, code);
2724 smb_FreeTran2Packet(outp);
2729 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2730 cm_ReleaseSCache(scp);
2731 cm_ReleaseUser(userp);
2732 if ( WANTS_DFS_PATHNAMES(p) )
2733 code = CM_ERROR_PATH_NOT_COVERED;
2735 code = CM_ERROR_BADSHARENAME;
2736 smb_SendTran2Error(vcp, p, opx, code);
2737 smb_FreeTran2Packet(outp);
2740 #endif /* DFS_SUPPORT */
2742 lock_ObtainMutex(&scp->mx);
2743 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2744 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2745 if (code) goto done;
2747 /* now we have the status in the cache entry, and everything is locked.
2748 * Marshall the output data.
2751 /* for info level 108, figure out short name */
2752 if (infoLevel == 0x108) {
2753 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
2754 tidPathp, scp->fid.vnode, shortName,
2761 *((u_long *)op) = len * 2; op += 4;
2762 mbstowcs((unsigned short *)op, shortName, len);
2767 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2768 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2769 *((u_long *)op) = dosTime; op += 4; /* creation time */
2770 *((u_long *)op) = dosTime; op += 4; /* access time */
2771 *((u_long *)op) = dosTime; op += 4; /* write time */
2772 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
2773 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
2774 attributes = smb_Attributes(scp);
2775 *((u_short *)op) = attributes; op += 2; /* attributes */
2777 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2778 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2779 *((FILETIME *)op) = ft; op += 8; /* creation time */
2780 *((FILETIME *)op) = ft; op += 8; /* last access time */
2781 *((FILETIME *)op) = ft; op += 8; /* last write time */
2782 *((FILETIME *)op) = ft; op += 8; /* last change time */
2783 extAttributes = smb_ExtAttributes(scp);
2784 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
2785 *((u_long *)op) = 0; op += 4; /* don't know what this is */
2787 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2788 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2789 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2790 *((u_long *)op) = scp->linkCount; op += 4;
2793 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2796 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2797 memset(op, 0, 4); op += 4; /* EA size */
2800 /* now, if we are being asked about extended attrs, return a 0 size */
2801 if (infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2802 *((u_long *)op) = 0; op += 4;
2806 /* send and free the packets */
2808 lock_ReleaseMutex(&scp->mx);
2809 cm_ReleaseSCache(scp);
2810 cm_ReleaseUser(userp);
2812 smb_SendTran2Packet(vcp, outp, opx);
2814 smb_SendTran2Error(vcp, p, opx, code);
2815 smb_FreeTran2Packet(outp);
2820 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2822 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2823 return CM_ERROR_BADOP;
2826 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2828 smb_tran2Packet_t *outp;
2830 unsigned long attributes;
2831 unsigned short infoLevel;
2844 fidp = smb_FindFID(vcp, fid, 0);
2847 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2851 infoLevel = p->parmsp[1];
2852 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2853 nbytesRequired = 40;
2854 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2855 nbytesRequired = 24;
2856 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2858 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2861 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2862 p->opcode, infoLevel);
2863 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2864 smb_ReleaseFID(fidp);
2867 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2869 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2871 if (infoLevel > 0x100)
2872 outp->totalParms = 2;
2874 outp->totalParms = 0;
2875 outp->totalData = nbytesRequired;
2877 userp = smb_GetTran2User(vcp, p);
2879 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2880 code = CM_ERROR_BADSMB;
2885 lock_ObtainMutex(&scp->mx);
2886 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2887 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2891 /* now we have the status in the cache entry, and everything is locked.
2892 * Marshall the output data.
2895 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2896 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2897 *((FILETIME *)op) = ft; op += 8; /* creation time */
2898 *((FILETIME *)op) = ft; op += 8; /* last access time */
2899 *((FILETIME *)op) = ft; op += 8; /* last write time */
2900 *((FILETIME *)op) = ft; op += 8; /* last change time */
2901 attributes = smb_ExtAttributes(scp);
2902 *((u_long *)op) = attributes; op += 4;
2903 *((u_long *)op) = 0; op += 4;
2905 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2906 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2907 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2908 *((u_long *)op) = scp->linkCount; op += 4;
2909 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
2910 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2914 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2915 *((u_long *)op) = 0; op += 4;
2917 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2921 if (fidp->NTopen_wholepathp)
2922 name = fidp->NTopen_wholepathp;
2924 name = "\\"; /* probably can't happen */
2925 len = (unsigned long)strlen(name);
2926 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
2927 *((u_long *)op) = len * 2; op += 4;
2928 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2931 /* send and free the packets */
2933 lock_ReleaseMutex(&scp->mx);
2934 cm_ReleaseUser(userp);
2935 smb_ReleaseFID(fidp);
2937 smb_SendTran2Packet(vcp, outp, opx);
2939 smb_SendTran2Error(vcp, p, opx, code);
2940 smb_FreeTran2Packet(outp);
2945 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2950 unsigned short infoLevel;
2951 smb_tran2Packet_t *outp;
2959 fidp = smb_FindFID(vcp, fid, 0);
2962 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
2966 infoLevel = p->parmsp[1];
2967 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type=[%x] fid=[%x]", infoLevel, fid);
2968 if (infoLevel > 0x104 || infoLevel < 0x101) {
2969 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2970 p->opcode, infoLevel);
2971 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
2972 smb_ReleaseFID(fidp);
2976 if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) {
2977 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2978 smb_ReleaseFID(fidp);
2981 if ((infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO)
2982 && !(fidp->flags & SMB_FID_OPENWRITE)) {
2983 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2984 smb_ReleaseFID(fidp);
2988 osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
2990 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
2992 outp->totalParms = 2;
2993 outp->totalData = 0;
2995 userp = smb_GetTran2User(vcp, p);
2997 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
2998 code = CM_ERROR_BADSMB;
3004 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3006 unsigned int attribute;
3009 /* lock the vnode with a callback; we need the current status
3010 * to determine what the new status is, in some cases.
3012 lock_ObtainMutex(&scp->mx);
3013 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3014 CM_SCACHESYNC_GETSTATUS
3015 | CM_SCACHESYNC_NEEDCALLBACK);
3017 lock_ReleaseMutex(&scp->mx);
3021 /* prepare for setattr call */
3024 lastMod = *((FILETIME *)(p->datap + 16));
3025 /* when called as result of move a b, lastMod is (-1, -1).
3026 * If the check for -1 is not present, timestamp
3027 * of the resulting file will be 1969 (-1)
3029 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3030 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3031 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3032 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3033 fidp->flags |= SMB_FID_MTIMESETDONE;
3036 attribute = *((u_long *)(p->datap + 32));
3037 if (attribute != 0) {
3038 if ((scp->unixModeBits & 0222)
3039 && (attribute & 1) != 0) {
3040 /* make a writable file read-only */
3041 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3042 attr.unixModeBits = scp->unixModeBits & ~0222;
3044 else if ((scp->unixModeBits & 0222) == 0
3045 && (attribute & 1) == 0) {
3046 /* make a read-only file writable */
3047 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3048 attr.unixModeBits = scp->unixModeBits | 0222;
3051 lock_ReleaseMutex(&scp->mx);
3055 code = cm_SetAttr(scp, &attr, userp, &req);
3059 else if (infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3060 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3063 attr.mask = CM_ATTRMASK_LENGTH;
3064 attr.length.LowPart = size.LowPart;
3065 attr.length.HighPart = size.HighPart;
3066 code = cm_SetAttr(scp, &attr, userp, &req);
3068 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3069 if (*((char *)(p->datap))) {
3070 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3073 fidp->flags |= SMB_FID_DELONCLOSE;
3077 fidp->flags &= ~SMB_FID_DELONCLOSE;
3082 cm_ReleaseUser(userp);
3083 smb_ReleaseFID(fidp);
3085 smb_SendTran2Packet(vcp, outp, op);
3087 smb_SendTran2Error(vcp, p, op, code);
3088 smb_FreeTran2Packet(outp);
3094 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3096 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3097 return CM_ERROR_BADOP;
3101 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3103 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3104 return CM_ERROR_BADOP;
3108 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3110 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3111 return CM_ERROR_BADOP;
3115 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3117 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3118 return CM_ERROR_BADOP;
3122 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3124 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3125 return CM_ERROR_BADOP;
3129 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3131 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3132 return CM_ERROR_BADOP;
3135 struct smb_v2_referral {
3137 USHORT ReferralFlags;
3140 USHORT DfsPathOffset;
3141 USHORT DfsAlternativePathOffset;
3142 USHORT NetworkAddressOffset;
3146 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3148 /* This is a UNICODE only request (bit15 of Flags2) */
3149 /* The TID must be IPC$ */
3151 /* The documentation for the Flags response field is contradictory */
3153 /* Use Version 1 Referral Element Format */
3154 /* ServerType = 0; indicates the next server should be queried for the file */
3155 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3156 /* Node = UnicodeString of UNC path of the next share name */
3159 int maxReferralLevel = 0;
3160 char requestFileName[1024] = "";
3161 smb_tran2Packet_t *outp = 0;
3162 cm_user_t *userp = 0;
3164 CPINFO CodePageInfo;
3165 int i, nbnLen, reqLen;
3170 maxReferralLevel = p->parmsp[0];
3172 GetCPInfo(CP_ACP, &CodePageInfo);
3173 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
3174 requestFileName, 1024, NULL, NULL);
3176 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
3177 maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3179 nbnLen = strlen(cm_NetbiosName);
3180 reqLen = strlen(requestFileName);
3182 if (reqLen == nbnLen + 5 &&
3183 requestFileName[0] == '\\' &&
3184 !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3185 requestFileName[nbnLen+1] == '\\' &&
3186 !_strnicmp("all",&requestFileName[nbnLen+2],3))
3189 struct smb_v2_referral * v2ref;
3190 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
3192 sp = (USHORT *)outp->datap;
3194 sp[idx++] = reqLen; /* path consumed */
3195 sp[idx++] = 1; /* number of referrals */
3196 sp[idx++] = 0x03; /* flags */
3197 #ifdef DFS_VERSION_1
3198 sp[idx++] = 1; /* Version Number */
3199 sp[idx++] = reqLen + 4; /* Referral Size */
3200 sp[idx++] = 1; /* Type = SMB Server */
3201 sp[idx++] = 0; /* Do not strip path consumed */
3202 for ( i=0;i<=reqLen; i++ )
3203 sp[i+idx] = requestFileName[i];
3204 #else /* DFS_VERSION_2 */
3205 sp[idx++] = 2; /* Version Number */
3206 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3207 idx += (sizeof(struct smb_v2_referral) / 2);
3208 v2ref = (struct smb_v2_referral *) &sp[5];
3209 v2ref->ServerType = 1; /* SMB Server */
3210 v2ref->ReferralFlags = 0x03;
3211 v2ref->Proximity = 0; /* closest */
3212 v2ref->TimeToLive = 3600; /* seconds */
3213 v2ref->DfsPathOffset = idx * 2;
3214 v2ref->DfsAlternativePathOffset = idx * 2;
3215 v2ref->NetworkAddressOffset = 0;
3216 for ( i=0;i<=reqLen; i++ )
3217 sp[i+idx] = requestFileName[i];
3220 userp = smb_GetTran2User(vcp, p);
3222 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3223 code = CM_ERROR_BADSMB;
3228 code = CM_ERROR_NOSUCHPATH;
3233 cm_ReleaseUser(userp);
3235 smb_SendTran2Packet(vcp, outp, op);
3237 smb_SendTran2Error(vcp, p, op, code);
3239 smb_FreeTran2Packet(outp);
3242 #else /* DFS_SUPPORT */
3243 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3244 return CM_ERROR_BADOP;
3245 #endif /* DFS_SUPPORT */
3249 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3251 /* This is a UNICODE only request (bit15 of Flags2) */
3253 /* There is nothing we can do about this operation. The client is going to
3254 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3255 * Unfortunately, there is really nothing we can do about it other then log it
3256 * somewhere. Even then I don't think there is anything for us to do.
3257 * So let's return an error value.
3260 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3261 return CM_ERROR_BADOP;
3265 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3266 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3271 cm_scache_t *targetScp; /* target if scp is a symlink */
3276 unsigned short attr;
3277 unsigned long lattr;
3278 smb_dirListPatch_t *patchp;
3279 smb_dirListPatch_t *npatchp;
3281 for(patchp = *dirPatchespp; patchp; patchp =
3282 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3283 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3285 lock_ObtainMutex(&scp->mx);
3286 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3287 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3289 lock_ReleaseMutex(&scp->mx);
3290 cm_ReleaseSCache(scp);
3292 dptr = patchp->dptr;
3294 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3295 errors in the client. */
3296 if (infoLevel >= 0x101) {
3297 /* 1969-12-31 23:59:59 +00 */
3298 ft.dwHighDateTime = 0x19DB200;
3299 ft.dwLowDateTime = 0x5BB78980;
3301 /* copy to Creation Time */
3302 *((FILETIME *)dptr) = ft;
3305 /* copy to Last Access Time */
3306 *((FILETIME *)dptr) = ft;
3309 /* copy to Last Write Time */
3310 *((FILETIME *)dptr) = ft;
3313 /* copy to Change Time */
3314 *((FILETIME *)dptr) = ft;
3317 /* merge in hidden attribute */
3318 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3319 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3323 /* 1969-12-31 23:59:58 +00*/
3324 dosTime = 0xEBBFBF7D;
3326 /* and copy out date */
3327 shortTemp = (dosTime>>16) & 0xffff;
3328 *((u_short *)dptr) = shortTemp;
3331 /* copy out creation time */
3332 shortTemp = dosTime & 0xffff;
3333 *((u_short *)dptr) = shortTemp;
3336 /* and copy out date */
3337 shortTemp = (dosTime>>16) & 0xffff;
3338 *((u_short *)dptr) = shortTemp;
3341 /* copy out access time */
3342 shortTemp = dosTime & 0xffff;
3343 *((u_short *)dptr) = shortTemp;
3346 /* and copy out date */
3347 shortTemp = (dosTime>>16) & 0xffff;
3348 *((u_short *)dptr) = shortTemp;
3351 /* copy out mod time */
3352 shortTemp = dosTime & 0xffff;
3353 *((u_short *)dptr) = shortTemp;
3356 /* merge in hidden (dot file) attribute */
3357 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3358 attr = SMB_ATTR_HIDDEN;
3359 *dptr++ = attr & 0xff;
3360 *dptr++ = (attr >> 8) & 0xff;
3366 /* now watch for a symlink */
3368 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3369 lock_ReleaseMutex(&scp->mx);
3370 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3372 /* we have a more accurate file to use (the
3373 * target of the symbolic link). Otherwise,
3374 * we'll just use the symlink anyway.
3376 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3378 cm_ReleaseSCache(scp);
3381 lock_ObtainMutex(&scp->mx);
3384 dptr = patchp->dptr;
3386 if (infoLevel >= 0x101) {
3388 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3390 /* copy to Creation Time */
3391 *((FILETIME *)dptr) = ft;
3394 /* copy to Last Access Time */
3395 *((FILETIME *)dptr) = ft;
3398 /* copy to Last Write Time */
3399 *((FILETIME *)dptr) = ft;
3402 /* copy to Change Time */
3403 *((FILETIME *)dptr) = ft;
3406 /* Use length for both file length and alloc length */
3407 *((LARGE_INTEGER *)dptr) = scp->length;
3409 *((LARGE_INTEGER *)dptr) = scp->length;
3412 /* Copy attributes */
3413 lattr = smb_ExtAttributes(scp);
3414 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3415 if (lattr == SMB_ATTR_NORMAL)
3416 lattr = SMB_ATTR_DIRECTORY;
3418 lattr |= SMB_ATTR_DIRECTORY;
3420 /* merge in hidden (dot file) attribute */
3421 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3422 if (lattr == SMB_ATTR_NORMAL)
3423 lattr = SMB_ATTR_HIDDEN;
3425 lattr |= SMB_ATTR_HIDDEN;
3427 *((u_long *)dptr) = lattr;
3431 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3433 /* and copy out date */
3434 shortTemp = (dosTime>>16) & 0xffff;
3435 *((u_short *)dptr) = shortTemp;
3438 /* copy out creation time */
3439 shortTemp = dosTime & 0xffff;
3440 *((u_short *)dptr) = shortTemp;
3443 /* and copy out date */
3444 shortTemp = (dosTime>>16) & 0xffff;
3445 *((u_short *)dptr) = shortTemp;
3448 /* copy out access time */
3449 shortTemp = dosTime & 0xffff;
3450 *((u_short *)dptr) = shortTemp;
3453 /* and copy out date */
3454 shortTemp = (dosTime>>16) & 0xffff;
3455 *((u_short *)dptr) = shortTemp;
3458 /* copy out mod time */
3459 shortTemp = dosTime & 0xffff;
3460 *((u_short *)dptr) = shortTemp;
3463 /* copy out file length and alloc length,
3464 * using the same for both
3466 *((u_long *)dptr) = scp->length.LowPart;
3468 *((u_long *)dptr) = scp->length.LowPart;
3471 /* finally copy out attributes as short */
3472 attr = smb_Attributes(scp);
3473 /* merge in hidden (dot file) attribute */
3474 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3475 if (lattr == SMB_ATTR_NORMAL)
3476 lattr = SMB_ATTR_HIDDEN;
3478 lattr |= SMB_ATTR_HIDDEN;
3480 *dptr++ = attr & 0xff;
3481 *dptr++ = (attr >> 8) & 0xff;
3484 lock_ReleaseMutex(&scp->mx);
3485 cm_ReleaseSCache(scp);
3488 /* now free the patches */
3489 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3490 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3494 /* and mark the list as empty */
3495 *dirPatchespp = NULL;
3500 #ifndef USE_OLD_MATCHING
3501 // char table for case insensitive comparison
3502 char mapCaseTable[256];
3504 VOID initUpperCaseTable(VOID)
3507 for (i = 0; i < 256; ++i)
3508 mapCaseTable[i] = toupper(i);
3509 // make '"' match '.'
3510 mapCaseTable[(int)'"'] = toupper('.');
3511 // make '<' match '*'
3512 mapCaseTable[(int)'<'] = toupper('*');
3513 // make '>' match '?'
3514 mapCaseTable[(int)'>'] = toupper('?');
3517 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3519 // Note : this procedure works recursively calling itself.
3521 // PSZ pattern : string containing metacharacters.
3522 // PSZ name : file name to be compared with 'pattern'.
3524 // BOOL : TRUE/FALSE (match/mistmatch)
3527 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
3529 PSZ pename; // points to the last 'name' character
3531 pename = name + strlen(name) - 1;
3542 if (*pattern == '\0')
3544 for (p = pename; p >= name; --p) {
3545 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
3546 !casefold && (*p == *pattern)) &&
3547 szWildCardMatchFileName(pattern + 1, p + 1, casefold))
3552 if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
3553 (!casefold && *name != *pattern))
3560 /* if all we have left are wildcards, then we match */
3561 for (;*pattern; pattern++) {
3562 if (*pattern != '*' && *pattern != '?')
3568 /* do a case-folding search of the star name mask with the name in namep.
3569 * Return 1 if we match, otherwise 0.
3571 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3574 int i, j, star, qmark, casefold, retval;
3576 /* make sure we only match 8.3 names, if requested */
3577 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3580 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
3582 /* optimize the pattern:
3583 * if there is a mixture of '?' and '*',
3584 * for example the sequence "*?*?*?*"
3585 * must be turned into the form "*"
3587 newmask = (char *)malloc(strlen(maskp)+1);
3588 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3589 switch ( maskp[i] ) {
3601 } else if ( qmark ) {
3605 newmask[j++] = maskp[i];
3612 } else if ( qmark ) {
3616 newmask[j++] = '\0';
3618 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
3624 #else /* USE_OLD_MATCHING */
3625 /* do a case-folding search of the star name mask with the name in namep.
3626 * Return 1 if we match, otherwise 0.
3628 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3630 unsigned char tcp1, tcp2; /* Pattern characters */
3631 unsigned char tcn1; /* Name characters */
3632 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3633 char *starNamep, *starMaskp;
3634 static char nullCharp[] = {0};
3635 int casefold = flags & CM_FLAG_CASEFOLD;
3637 /* make sure we only match 8.3 names, if requested */
3638 req8dot3 = (flags & CM_FLAG_8DOT3);
3639 if (req8dot3 && !cm_Is8Dot3(namep))
3644 /* Next pattern character */
3647 /* Next name character */
3651 /* 0 - end of pattern */
3657 else if (tcp1 == '.' || tcp1 == '"') {
3667 * first dot in pattern;
3668 * must match dot or end of name
3673 else if (tcn1 == '.') {
3682 else if (tcp1 == '?') {
3683 if (tcn1 == 0 || tcn1 == '.')
3688 else if (tcp1 == '>') {
3689 if (tcn1 != 0 && tcn1 != '.')
3693 else if (tcp1 == '*' || tcp1 == '<') {
3697 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3698 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3713 * pattern character after '*' is not null or
3714 * period. If it is '?' or '>', we are not
3715 * going to understand it. If it is '*' or
3716 * '<', we are going to skip over it. None of
3717 * these are likely, I hope.
3719 /* skip over '*' and '<' */
3720 while (tcp2 == '*' || tcp2 == '<')
3723 /* skip over characters that don't match tcp2 */
3724 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
3725 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
3726 (!casefold && tcn1 != tcp2)))
3730 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3733 /* Remember where we are */
3743 /* tcp1 is not a wildcard */
3744 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
3745 (!casefold && tcn1 == tcp1)) {
3750 /* if trying to match a star pattern, go back */
3752 maskp = starMaskp - 2;
3753 namep = starNamep + 1;
3762 #endif /* USE_OLD_MATCHING */
3764 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3769 long code = 0, code2 = 0;
3773 smb_dirListPatch_t *dirListPatchesp;
3774 smb_dirListPatch_t *curPatchp;
3777 long orbytes; /* # of bytes in this output record */
3778 long ohbytes; /* # of bytes, except file name */
3779 long onbytes; /* # of bytes in name, incl. term. null */
3780 osi_hyper_t dirLength;
3781 osi_hyper_t bufferOffset;
3782 osi_hyper_t curOffset;
3784 smb_dirSearch_t *dsp;
3788 cm_pageHeader_t *pageHeaderp;
3789 cm_user_t *userp = NULL;
3792 long nextEntryCookie;
3793 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3794 char *op; /* output data ptr */
3795 char *origOp; /* original value of op */
3796 cm_space_t *spacep; /* for pathname buffer */
3797 long maxReturnData; /* max # of return data */
3798 long maxReturnParms; /* max # of return parms */
3799 long bytesInBuffer; /* # data bytes in the output buffer */
3801 char *maskp; /* mask part of path */
3805 smb_tran2Packet_t *outp; /* response packet */
3808 char shortName[13]; /* 8.3 name if needed */
3819 if (p->opcode == 1) {
3820 /* find first; obtain basic parameters from request */
3821 attribute = p->parmsp[0];
3822 maxCount = p->parmsp[1];
3823 infoLevel = p->parmsp[3];
3824 searchFlags = p->parmsp[2];
3825 dsp = smb_NewDirSearch(1);
3826 dsp->attribute = attribute;
3827 pathp = ((char *) p->parmsp) + 12; /* points to path */
3828 if (smb_StoreAnsiFilenames)
3829 OemToChar(pathp,pathp);
3831 maskp = strrchr(pathp, '\\');
3835 maskp++; /* skip over backslash */
3836 strcpy(dsp->mask, maskp); /* and save mask */
3837 /* track if this is likely to match a lot of entries */
3838 starPattern = smb_V3IsStarMask(maskp);
3841 osi_assert(p->opcode == 2);
3842 /* find next; obtain basic parameters from request or open dir file */
3843 dsp = smb_FindDirSearch(p->parmsp[0]);
3844 maxCount = p->parmsp[1];
3845 infoLevel = p->parmsp[2];
3846 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
3847 searchFlags = p->parmsp[5];
3849 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
3850 p->parmsp[0], nextCookie);
3851 return CM_ERROR_BADFD;
3853 attribute = dsp->attribute;
3856 starPattern = 1; /* assume, since required a Find Next */
3860 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
3861 attribute, infoLevel, maxCount, searchFlags);
3863 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
3864 p->opcode, dsp->cookie, nextCookie);
3866 if (infoLevel >= 0x101)
3867 searchFlags &= ~4; /* no resume keys */
3869 dirListPatchesp = NULL;
3871 maxReturnData = p->maxReturnData;
3872 if (p->opcode == 1) /* find first */
3873 maxReturnParms = 10; /* bytes */
3875 maxReturnParms = 8; /* bytes */
3877 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
3878 if (maxReturnData > 6000)
3879 maxReturnData = 6000;
3880 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
3882 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
3885 osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
3886 maxCount, osi_LogSaveString(smb_logp, pathp));
3888 /* bail out if request looks bad */
3889 if (p->opcode == 1 && !pathp) {
3890 smb_ReleaseDirSearch(dsp);
3891 smb_FreeTran2Packet(outp);
3892 return CM_ERROR_BADSMB;
3895 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
3896 dsp->cookie, nextCookie, attribute);
3898 userp = smb_GetTran2User(vcp, p);
3900 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
3901 smb_ReleaseDirSearch(dsp);
3902 smb_FreeTran2Packet(outp);
3903 return CM_ERROR_BADSMB;
3906 /* try to get the vnode for the path name next */
3907 lock_ObtainMutex(&dsp->mx);
3913 spacep = cm_GetSpace();
3914 smb_StripLastComponent(spacep->data, NULL, pathp);
3915 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3917 cm_ReleaseUser(userp);
3918 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
3919 smb_FreeTran2Packet(outp);
3920 lock_ReleaseMutex(&dsp->mx);
3921 smb_DeleteDirSearch(dsp);
3922 smb_ReleaseDirSearch(dsp);
3925 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3926 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3927 userp, tidPathp, &req, &scp);
3928 cm_FreeSpace(spacep);
3931 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
3932 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3933 cm_ReleaseSCache(scp);
3934 cm_ReleaseUser(userp);
3935 if ( WANTS_DFS_PATHNAMES(p) )
3936 code = CM_ERROR_PATH_NOT_COVERED;
3938 code = CM_ERROR_BADSHARENAME;
3939 smb_SendTran2Error(vcp, p, opx, code);
3940 smb_FreeTran2Packet(outp);
3941 lock_ReleaseMutex(&dsp->mx);
3942 smb_DeleteDirSearch(dsp);
3943 smb_ReleaseDirSearch(dsp);
3946 #endif /* DFS_SUPPORT */
3948 /* we need one hold for the entry we just stored into,
3949 * and one for our own processing. When we're done
3950 * with this function, we'll drop the one for our own
3951 * processing. We held it once from the namei call,
3952 * and so we do another hold now.
3955 lock_ObtainMutex(&scp->mx);
3956 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
3957 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3958 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3959 dsp->flags |= SMB_DIRSEARCH_BULKST;
3961 lock_ReleaseMutex(&scp->mx);
3964 lock_ReleaseMutex(&dsp->mx);
3966 cm_ReleaseUser(userp);
3967 smb_FreeTran2Packet(outp);
3968 smb_DeleteDirSearch(dsp);
3969 smb_ReleaseDirSearch(dsp);
3973 /* get the directory size */
3974 lock_ObtainMutex(&scp->mx);
3975 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3976 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3978 lock_ReleaseMutex(&scp->mx);
3979 cm_ReleaseSCache(scp);
3980 cm_ReleaseUser(userp);
3981 smb_FreeTran2Packet(outp);
3982 smb_DeleteDirSearch(dsp);
3983 smb_ReleaseDirSearch(dsp);
3988 dirLength = scp->length;
3990 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3991 curOffset.HighPart = 0;
3992 curOffset.LowPart = nextCookie;
3993 origOp = outp->datap;
4001 if (searchFlags & 4)
4002 /* skip over resume key */
4005 /* make sure that curOffset.LowPart doesn't point to the first
4006 * 32 bytes in the 2nd through last dir page, and that it doesn't
4007 * point at the first 13 32-byte chunks in the first dir page,
4008 * since those are dir and page headers, and don't contain useful
4011 temp = curOffset.LowPart & (2048-1);
4012 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4013 /* we're in the first page */
4014 if (temp < 13*32) temp = 13*32;
4017 /* we're in a later dir page */
4018 if (temp < 32) temp = 32;
4021 /* make sure the low order 5 bits are zero */
4024 /* now put temp bits back ito curOffset.LowPart */
4025 curOffset.LowPart &= ~(2048-1);
4026 curOffset.LowPart |= temp;
4028 /* check if we've passed the dir's EOF */
4029 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4030 osi_Log0(smb_logp, "T2 search dir passed eof");
4035 /* check if we've returned all the names that will fit in the
4036 * response packet; we check return count as well as the number
4037 * of bytes requested. We check the # of bytes after we find
4038 * the dir entry, since we'll need to check its size.
4040 if (returnedNames >= maxCount) {
4041 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4042 returnedNames, maxCount);
4046 /* see if we can use the bufferp we have now; compute in which
4047 * page the current offset would be, and check whether that's
4048 * the offset of the buffer we have. If not, get the buffer.
4050 thyper.HighPart = curOffset.HighPart;
4051 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4052 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4055 buf_Release(bufferp);
4058 lock_ReleaseMutex(&scp->mx);
4059 lock_ObtainRead(&scp->bufCreateLock);
4060 code = buf_Get(scp, &thyper, &bufferp);
4061 lock_ReleaseRead(&scp->bufCreateLock);
4062 lock_ObtainMutex(&dsp->mx);
4064 /* now, if we're doing a star match, do bulk fetching
4065 * of all of the status info for files in the dir.
4068 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
4071 lock_ObtainMutex(&scp->mx);
4072 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4073 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
4074 /* Don't bulk stat if risking timeout */
4075 int now = GetCurrentTime();
4076 if (now - req.startTime > 5000) {
4077 scp->bulkStatProgress = thyper;
4078 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4079 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4081 cm_TryBulkStat(scp, &thyper, userp, &req);
4084 lock_ObtainMutex(&scp->mx);
4086 lock_ReleaseMutex(&dsp->mx);
4088 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
4092 bufferOffset = thyper;
4094 /* now get the data in the cache */
4096 code = cm_SyncOp(scp, bufferp, userp, &req,
4098 CM_SCACHESYNC_NEEDCALLBACK
4099 | CM_SCACHESYNC_READ);
4101 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
4105 if (cm_HaveBuffer(scp, bufferp, 0)) {
4106 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4110 /* otherwise, load the buffer and try again */
4111 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4114 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4115 scp, bufferp, code);
4120 buf_Release(bufferp);
4124 } /* if (wrong buffer) ... */
4126 /* now we have the buffer containing the entry we're interested
4127 * in; copy it out if it represents a non-deleted entry.
4129 entryInDir = curOffset.LowPart & (2048-1);
4130 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4132 /* page header will help tell us which entries are free. Page
4133 * header can change more often than once per buffer, since
4134 * AFS 3 dir page size may be less than (but not more than)
4135 * a buffer package buffer.
4137 /* only look intra-buffer */
4138 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4139 temp &= ~(2048 - 1); /* turn off intra-page bits */
4140 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4142 /* now determine which entry we're looking at in the page.
4143 * If it is free (there's a free bitmap at the start of the
4144 * dir), we should skip these 32 bytes.
4146 slotInPage = (entryInDir & 0x7e0) >> 5;
4147 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
4148 (1 << (slotInPage & 0x7)))) {
4149 /* this entry is free */
4150 numDirChunks = 1; /* only skip this guy */
4154 tp = bufferp->datap + entryInBuffer;
4155 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4157 /* while we're here, compute the next entry's location, too,
4158 * since we'll need it when writing out the cookie into the dir
4161 * XXXX Probably should do more sanity checking.
4163 numDirChunks = cm_NameEntries(dep->name, &onbytes);
4165 /* compute offset of cookie representing next entry */
4166 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4168 /* Need 8.3 name? */
4170 if (infoLevel == SMB_QUERY_FILE_NAME_INFO
4171 && dep->fid.vnode != 0
4172 && !cm_Is8Dot3(dep->name)) {
4173 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4177 osi_Log3(smb_logp, "T2 search dir vn %u name %s (%s)",
4178 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4179 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4181 /* When matching, we are using doing a case fold if we have a wildcard mask.
4182 * If we get a non-wildcard match, it's a lookup for a specific file.
4184 if (dep->fid.vnode != 0 &&
4185 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
4187 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
4189 /* Eliminate entries that don't match requested attributes */
4190 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
4191 smb_IsDotFile(dep->name)) {
4192 osi_Log0(smb_logp, "T2 search dir skipping hidden");
4193 goto nextEntry; /* no hidden files */
4195 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4197 /* We have already done the cm_TryBulkStat above */
4198 fid.cell = scp->fid.cell;
4199 fid.volume = scp->fid.volume;
4200 fid.vnode = ntohl(dep->fid.vnode);
4201 fid.unique = ntohl(dep->fid.unique);
4202 fileType = cm_FindFileType(&fid);
4203 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
4204 "has filetype %d", dep->name,
4206 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4207 fileType == CM_SCACHETYPE_DFSLINK ||
4208 fileType == CM_SCACHETYPE_INVALID)
4209 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");