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 /*DEBUG do not checkin*/
125 void OutputDebugF(char * format, ...) {
130 va_start( args, format );
131 len = _vscprintf( format, args ) // _vscprintf doesn't count
132 + 3; // terminating '\0' + '\n'
133 buffer = malloc( len * sizeof(char) );
134 vsprintf( buffer, format, args );
135 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buffer));
136 strcat(buffer, "\n");
137 OutputDebugString(buffer);
141 void OutputDebugHexDump(unsigned char * buffer, int len) {
144 static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
146 OutputDebugF("Hexdump length [%d]",len);
148 for (i=0;i<len;i++) {
151 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
153 OutputDebugString(buf);
155 sprintf(buf,"%5x",i);
156 memset(buf+5,' ',80);
161 j = j*3 + 7 + ((j>7)?1:0);
164 buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
167 j = j + 56 + ((j>7)?1:0);
169 buf[j] = (k>32 && k<127)?k:'.';
172 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
174 OutputDebugString(buf);
179 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
180 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
181 SECURITY_STATUS status, istatus;
182 CredHandle creds = {0,0};
184 SecBufferDesc secOut;
192 OutputDebugF("Negotiating Extended Security");
194 status = AcquireCredentialsHandle( NULL,
195 SMB_EXT_SEC_PACKAGE_NAME,
204 if (status != SEC_E_OK) {
205 /* Really bad. We return an empty security blob */
206 OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
211 secOut.pBuffers = &secTok;
212 secOut.ulVersion = SECBUFFER_VERSION;
214 secTok.BufferType = SECBUFFER_TOKEN;
216 secTok.pvBuffer = NULL;
218 ctx.dwLower = ctx.dwUpper = 0;
220 status = AcceptSecurityContext( &creds,
223 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
224 SECURITY_NETWORK_DREP,
231 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
232 OutputDebugF("Completing token...");
233 istatus = CompleteAuthToken(&ctx, &secOut);
234 if ( istatus != SEC_E_OK )
235 OutputDebugF("Token completion failed: %x", istatus);
238 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
239 if (secTok.pvBuffer) {
240 *secBlobLength = secTok.cbBuffer;
241 *secBlob = malloc( secTok.cbBuffer );
242 memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
245 if ( status != SEC_E_OK )
246 OutputDebugF("AcceptSecurityContext status != CONTINUE %lX", status);
249 /* Discard partial security context */
250 DeleteSecurityContext(&ctx);
252 if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
254 /* Discard credentials handle. We'll reacquire one when we get the session setup X */
255 FreeCredentialsHandle(&creds);
261 struct smb_ext_context {
268 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
269 SECURITY_STATUS status, istatus;
273 SecBufferDesc secBufIn;
275 SecBufferDesc secBufOut;
278 struct smb_ext_context * secCtx = NULL;
279 struct smb_ext_context * newSecCtx = NULL;
280 void * assembledBlob = NULL;
281 int assembledBlobLength = 0;
284 OutputDebugF("In smb_AuthenticateUserExt");
287 *secBlobOutLength = 0;
289 if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
290 secCtx = vcp->secCtx;
291 lock_ObtainMutex(&vcp->mx);
292 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
294 lock_ReleaseMutex(&vcp->mx);
298 OutputDebugF("Received incoming token:");
299 OutputDebugHexDump(secBlobIn,secBlobInLength);
303 OutputDebugF("Continuing with existing context.");
304 creds = secCtx->creds;
307 if (secCtx->partialToken) {
308 assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
309 assembledBlob = malloc(assembledBlobLength);
310 memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
311 memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
314 status = AcquireCredentialsHandle( NULL,
315 SMB_EXT_SEC_PACKAGE_NAME,
324 if (status != SEC_E_OK) {
325 OutputDebugF("Can't acquire Credentials handle [%lX]", status);
326 code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
334 secBufIn.cBuffers = 1;
335 secBufIn.pBuffers = &secTokIn;
336 secBufIn.ulVersion = SECBUFFER_VERSION;
338 secTokIn.BufferType = SECBUFFER_TOKEN;
340 secTokIn.cbBuffer = assembledBlobLength;
341 secTokIn.pvBuffer = assembledBlob;
343 secTokIn.cbBuffer = secBlobInLength;
344 secTokIn.pvBuffer = secBlobIn;
347 secBufOut.cBuffers = 1;
348 secBufOut.pBuffers = &secTokOut;
349 secBufOut.ulVersion = SECBUFFER_VERSION;
351 secTokOut.BufferType = SECBUFFER_TOKEN;
352 secTokOut.cbBuffer = 0;
353 secTokOut.pvBuffer = NULL;
355 status = AcceptSecurityContext( &creds,
356 ((secCtx)?&ctx:NULL),
358 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
359 SECURITY_NETWORK_DREP,
366 if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
367 OutputDebugF("Completing token...");
368 istatus = CompleteAuthToken(&ctx, &secBufOut);
369 if ( istatus != SEC_E_OK )
370 OutputDebugF("Token completion failed: %lX", istatus);
373 if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
374 OutputDebugF("Continue needed");
376 newSecCtx = malloc(sizeof(*newSecCtx));
378 newSecCtx->creds = creds;
379 newSecCtx->ctx = ctx;
380 newSecCtx->partialToken = NULL;
381 newSecCtx->partialTokenLen = 0;
383 lock_ObtainMutex( &vcp->mx );
384 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
385 vcp->secCtx = newSecCtx;
386 lock_ReleaseMutex( &vcp->mx );
388 code = CM_ERROR_GSSCONTINUE;
391 if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
392 status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
393 secTokOut.pvBuffer) {
394 OutputDebugF("Need to send token back to client");
396 *secBlobOutLength = secTokOut.cbBuffer;
397 *secBlobOut = malloc(secTokOut.cbBuffer);
398 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
400 OutputDebugF("Outgoing token:");
401 OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
402 } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
403 OutputDebugF("Incomplete message");
405 newSecCtx = malloc(sizeof(*newSecCtx));
407 newSecCtx->creds = creds;
408 newSecCtx->ctx = ctx;
409 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
410 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
411 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
413 lock_ObtainMutex( &vcp->mx );
414 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
415 vcp->secCtx = newSecCtx;
416 lock_ReleaseMutex( &vcp->mx );
418 code = CM_ERROR_GSSCONTINUE;
421 if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
423 SecPkgContext_Names names;
425 OutputDebugF("Authentication completed");
426 OutputDebugF("Returned flags : [%lX]", flags);
428 if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
429 OutputDebugF("Received name [%s]", names.sUserName);
430 strcpy(usern, names.sUserName);
431 strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
432 FreeContextBuffer(names.sUserName);
434 /* Force the user to retry if the context is invalid */
435 OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
436 code = CM_ERROR_BADPASSWORD;
440 case SEC_E_INVALID_TOKEN:
441 OutputDebugF("Returning bad password :: INVALID_TOKEN");
443 case SEC_E_INVALID_HANDLE:
444 OutputDebugF("Returning bad password :: INVALID_HANDLE");
446 case SEC_E_LOGON_DENIED:
447 OutputDebugF("Returning bad password :: LOGON_DENIED");
449 case SEC_E_UNKNOWN_CREDENTIALS:
450 OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
452 case SEC_E_NO_CREDENTIALS:
453 OutputDebugF("Returning bad password :: NO_CREDENTIALS");
455 case SEC_E_CONTEXT_EXPIRED:
456 OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
458 case SEC_E_INCOMPLETE_CREDENTIALS:
459 OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
461 case SEC_E_WRONG_PRINCIPAL:
462 OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
464 case SEC_E_TIME_SKEW:
465 OutputDebugF("Returning bad password :: TIME_SKEW");
468 OutputDebugF("Returning bad password :: Status == %lX", status);
470 code = CM_ERROR_BADPASSWORD;
474 if (secCtx->partialToken) free(secCtx->partialToken);
482 if (secTokOut.pvBuffer)
483 FreeContextBuffer(secTokOut.pvBuffer);
485 if (code != CM_ERROR_GSSCONTINUE) {
486 DeleteSecurityContext(&ctx);
487 FreeCredentialsHandle(&creds);
495 #define P_RESP_LEN 128
497 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
498 So put stuff in a struct. */
499 struct Lm20AuthBlob {
500 MSV1_0_LM20_LOGON lmlogon;
501 BYTE ciResponse[P_RESP_LEN]; /* Unicode representation */
502 BYTE csResponse[P_RESP_LEN]; /* ANSI representation */
503 WCHAR accountNameW[P_LEN];
504 WCHAR primaryDomainW[P_LEN];
505 WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
506 TOKEN_GROUPS tgroups;
507 TOKEN_SOURCE tsource;
510 long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
513 struct Lm20AuthBlob lmAuth;
514 PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
515 QUOTA_LIMITS quotaLimits;
517 ULONG lmprofilepSize;
521 OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
522 OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
524 if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
525 OutputDebugF("ciPwdLength or csPwdLength is too long");
526 return CM_ERROR_BADPASSWORD;
529 memset(&lmAuth,0,sizeof(lmAuth));
531 lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
533 lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
534 mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
535 lmAuth.lmlogon.LogonDomainName.Length = wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR);
536 lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
538 lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
539 mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
540 lmAuth.lmlogon.UserName.Length = wcslen(lmAuth.accountNameW) * sizeof(WCHAR);
541 lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
543 lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
544 lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
545 size = MAX_COMPUTERNAME_LENGTH + 1;
546 GetComputerNameW(lmAuth.workstationW, &size);
547 lmAuth.lmlogon.Workstation.Length = wcslen(lmAuth.workstationW) * sizeof(WCHAR);
549 memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
551 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
552 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
553 lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
554 memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
556 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
557 lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
558 lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
559 memcpy(lmAuth.csResponse, csPwd, csPwdLength);
561 lmAuth.lmlogon.ParameterControl = 0;
563 lmAuth.tgroups.GroupCount = 0;
564 lmAuth.tgroups.Groups[0].Sid = NULL;
565 lmAuth.tgroups.Groups[0].Attributes = 0;
567 lmAuth.tsource.SourceIdentifier.HighPart = 0;
568 lmAuth.tsource.SourceIdentifier.LowPart = (DWORD) vcp;
569 strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
571 nts = LsaLogonUser( smb_lsaHandle,
586 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
587 osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
590 OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
591 OutputDebugF("Extended status is 0x%lX", ntsEx);
593 if (nts == ERROR_SUCCESS) {
595 LsaFreeReturnBuffer(lmprofilep);
596 CloseHandle(lmToken);
600 if (nts == 0xC000015BL)
601 return CM_ERROR_BADLOGONTYPE;
602 else /* our catchall is a bad password though we could be more specific */
603 return CM_ERROR_BADPASSWORD;
607 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
608 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName)
613 /* check if we have sane input */
614 if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
617 /* we could get : [accountName][domainName]
623 atsign = strchr(accountName, '@');
625 if (atsign) /* [user@domain][] -> [user@domain][domain] */
630 /* if for some reason the client doesn't know what domain to use,
631 it will either return an empty string or a '?' */
632 if (!domain[0] || domain[0] == '?')
633 /* Empty domains and empty usernames are usually sent from tokenless contexts.
634 This way such logins will get an empty username (easy to check). I don't know
635 when a non-empty username would be supplied with an anonymous domain, but *shrug* */
636 strcpy(usern,accountName);
638 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
639 strcpy(usern,domain);
642 strncat(usern,accountName,atsign - accountName);
644 strcat(usern,accountName);
652 /* When using SMB auth, all SMB sessions have to pass through here first to
653 * authenticate the user.
654 * Caveat: If not use the SMB auth the protocol does not require sending a
655 * session setup packet, which means that we can't rely on a UID in subsequent
656 * 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_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"FindUserByName:Lana[%d],lsn[%d],userid[%d],name[%s]",vcp->lana,vcp->lsn,newUid,osi_LogSaveString(smb_logp, usern));
847 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
848 smb_ReleaseUID(uidp);
851 /* do a global search for the username/machine name pair */
852 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
854 /* Create a new UID and cm_user_t structure */
857 userp = cm_NewUser();
858 lock_ObtainMutex(&vcp->mx);
859 if (!vcp->uidCounter)
860 vcp->uidCounter++; /* handle unlikely wraparounds */
861 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
862 lock_ReleaseMutex(&vcp->mx);
864 /* Create a new smb_user_t structure and connect them up */
865 lock_ObtainMutex(&unp->mx);
867 lock_ReleaseMutex(&unp->mx);
869 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
870 lock_ObtainMutex(&uidp->mx);
872 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d],TicketKTCName[%s]",(int)vcp,vcp->lana,vcp->lsn,newUid,osi_LogSaveString(smb_logp, usern));
873 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
874 lock_ReleaseMutex(&uidp->mx);
875 smb_ReleaseUID(uidp);
878 /* Return UID to the client */
879 ((smb_t *)outp)->uid = newUid;
880 /* Also to the next chained message */
881 ((smb_t *)inp)->uid = newUid;
883 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
884 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
886 smb_SetSMBParm(outp, 2, 0);
888 if (vcp->flags & SMB_VCFLAG_USENT) {
889 if (smb_authType == SMB_AUTH_EXTENDED) {
890 smb_SetSMBParm(outp, 3, secBlobOutLength);
891 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
892 tp = smb_GetSMBData(outp, NULL);
893 if (secBlobOutLength) {
894 memcpy(tp, secBlobOut, secBlobOutLength);
896 tp += secBlobOutLength;
898 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
899 tp += smb_ServerOSLength;
900 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
901 tp += smb_ServerLanManagerLength;
902 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
903 tp += smb_ServerDomainNameLength;
905 smb_SetSMBDataLength(outp, 0);
908 if (smb_authType == SMB_AUTH_EXTENDED) {
909 smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
910 tp = smb_GetSMBData(outp, NULL);
911 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
912 tp += smb_ServerOSLength;
913 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
914 tp += smb_ServerLanManagerLength;
915 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
916 tp += smb_ServerDomainNameLength;
918 smb_SetSMBDataLength(outp, 0);
925 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
929 /* don't get tokens from this VC */
930 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
932 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
934 /* find the tree and free it */
935 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
936 /* TODO: smb_ReleaseUID() ? */
938 char *s1 = NULL, *s2 = NULL;
940 if (s2 == NULL) s2 = " ";
941 if (s1 == NULL) {s1 = s2; s2 = " ";}
943 osi_Log4(smb_logp, "SMB3 user logoffX uid %d name %s%s%s", uidp->userID,
944 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "),
945 osi_LogSaveString(smb_logp,s1), osi_LogSaveString(smb_logp,s2));
947 lock_ObtainMutex(&uidp->mx);
948 uidp->flags |= SMB_USERFLAG_DELETE;
950 * it doesn't get deleted right away
951 * because the vcp points to it
953 lock_ReleaseMutex(&uidp->mx);
956 osi_Log0(smb_logp, "SMB3 user logoffX");
958 smb_SetSMBDataLength(outp, 0);
962 #define SMB_SUPPORT_SEARCH_BITS 0x0001
963 #define SMB_SHARE_IS_IN_DFS 0x0002
965 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
969 unsigned short newTid;
980 osi_Log0(smb_logp, "SMB3 receive tree connect");
982 /* parse input parameters */
983 tp = smb_GetSMBData(inp, NULL);
984 passwordp = smb_ParseString(tp, &tp);
985 pathp = smb_ParseString(tp, &tp);
986 if (smb_StoreAnsiFilenames)
987 OemToChar(pathp,pathp);
988 servicep = smb_ParseString(tp, &tp);
990 tp = strrchr(pathp, '\\');
992 return CM_ERROR_BADSMB;
994 strcpy(shareName, tp+1);
996 osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
997 osi_LogSaveString(smb_logp, pathp),
998 osi_LogSaveString(smb_logp, shareName));
1000 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
1002 osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1005 return CM_ERROR_NOIPC;
1009 userp = smb_GetUser(vcp, inp);
1011 lock_ObtainMutex(&vcp->mx);
1012 newTid = vcp->tidCounter++;
1013 lock_ReleaseMutex(&vcp->mx);
1015 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1018 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1019 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1021 smb_ReleaseUID(uidp);
1023 smb_ReleaseTID(tidp);
1024 return CM_ERROR_BADSHARENAME;
1027 if (vcp->flags & SMB_VCFLAG_USENT)
1029 int policy = smb_FindShareCSCPolicy(shareName);
1030 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1032 SMB_SHARE_IS_IN_DFS |
1037 smb_SetSMBParm(outp, 2, 0);
1041 lock_ObtainMutex(&tidp->mx);
1042 tidp->userp = userp;
1043 tidp->pathname = sharePath;
1045 tidp->flags |= SMB_TIDFLAG_IPC;
1046 lock_ReleaseMutex(&tidp->mx);
1047 smb_ReleaseTID(tidp);
1049 ((smb_t *)outp)->tid = newTid;
1050 ((smb_t *)inp)->tid = newTid;
1051 tp = smb_GetSMBData(outp, NULL);
1053 /* XXX - why is this a drive letter? */
1062 smb_SetSMBDataLength(outp, 8);
1065 smb_SetSMBDataLength(outp, 4);
1068 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1072 /* must be called with global tran lock held */
1073 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1075 smb_tran2Packet_t *tp;
1078 smbp = (smb_t *) inp->data;
1079 for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1080 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1086 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1087 int totalParms, int totalData)
1089 smb_tran2Packet_t *tp;
1092 smbp = (smb_t *) inp->data;
1093 tp = malloc(sizeof(*tp));
1094 memset(tp, 0, sizeof(*tp));
1097 tp->curData = tp->curParms = 0;
1098 tp->totalData = totalData;
1099 tp->totalParms = totalParms;
1100 tp->tid = smbp->tid;
1101 tp->mid = smbp->mid;
1102 tp->uid = smbp->uid;
1103 tp->pid = smbp->pid;
1104 tp->res[0] = smbp->res[0];
1105 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1106 if (totalParms != 0)
1107 tp->parmsp = malloc(totalParms);
1109 tp->datap = malloc(totalData);
1110 if (smbp->com == 0x25 || smbp->com == 0x26)
1113 tp->opcode = smb_GetSMBParm(inp, 14);
1116 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1120 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1121 smb_tran2Packet_t *inp, smb_packet_t *outp,
1122 int totalParms, int totalData)
1124 smb_tran2Packet_t *tp;
1125 unsigned short parmOffset;
1126 unsigned short dataOffset;
1127 unsigned short dataAlign;
1129 tp = malloc(sizeof(*tp));
1130 memset(tp, 0, sizeof(*tp));
1132 tp->curData = tp->curParms = 0;
1133 tp->totalData = totalData;
1134 tp->totalParms = totalParms;
1135 tp->oldTotalParms = totalParms;
1140 tp->res[0] = inp->res[0];
1141 tp->opcode = inp->opcode;
1145 * We calculate where the parameters and data will start.
1146 * This calculation must parallel the calculation in
1147 * smb_SendTran2Packet.
1150 parmOffset = 10*2 + 35;
1151 parmOffset++; /* round to even */
1152 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1154 dataOffset = parmOffset + totalParms;
1155 dataAlign = dataOffset & 2; /* quad-align */
1156 dataOffset += dataAlign;
1157 tp->datap = outp->data + dataOffset;
1162 /* free a tran2 packet; must be called with smb_globalLock held */
1163 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1166 smb_ReleaseVC(t2p->vcp);
1167 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1176 /* called with a VC, an input packet to respond to, and an error code.
1177 * sends an error response.
1179 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1180 smb_packet_t *tp, long code)
1183 unsigned short errCode;
1184 unsigned char errClass;
1185 unsigned long NTStatus;
1187 if (vcp->flags & SMB_VCFLAG_STATUS32)
1188 smb_MapNTError(code, &NTStatus);
1190 smb_MapCoreError(code, vcp, &errCode, &errClass);
1192 smb_FormatResponsePacket(vcp, NULL, tp);
1193 smbp = (smb_t *) tp;
1195 /* We can handle long names */
1196 if (vcp->flags & SMB_VCFLAG_USENT)
1197 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1199 /* now copy important fields from the tran 2 packet */
1200 smbp->com = t2p->com;
1201 smbp->tid = t2p->tid;
1202 smbp->mid = t2p->mid;
1203 smbp->pid = t2p->pid;
1204 smbp->uid = t2p->uid;
1205 smbp->res[0] = t2p->res[0];
1206 if (vcp->flags & SMB_VCFLAG_STATUS32) {
1207 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1208 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1209 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1210 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1211 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1214 smbp->rcls = errClass;
1215 smbp->errLow = (unsigned char) (errCode & 0xff);
1216 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1220 smb_SendPacket(vcp, tp);
1223 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1226 unsigned short parmOffset;
1227 unsigned short dataOffset;
1228 unsigned short totalLength;
1229 unsigned short dataAlign;
1232 smb_FormatResponsePacket(vcp, NULL, tp);
1233 smbp = (smb_t *) tp;
1235 /* We can handle long names */
1236 if (vcp->flags & SMB_VCFLAG_USENT)
1237 smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1239 /* now copy important fields from the tran 2 packet */
1240 smbp->com = t2p->com;
1241 smbp->tid = t2p->tid;
1242 smbp->mid = t2p->mid;
1243 smbp->pid = t2p->pid;
1244 smbp->uid = t2p->uid;
1245 smbp->res[0] = t2p->res[0];
1247 totalLength = 1 + t2p->totalData + t2p->totalParms;
1249 /* now add the core parameters (tran2 info) to the packet */
1250 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
1251 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
1252 smb_SetSMBParm(tp, 2, 0); /* reserved */
1253 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
1254 parmOffset = 10*2 + 35; /* parm offset in packet */
1255 parmOffset++; /* round to even */
1256 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
1257 * hdr, bcc and wct */
1258 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
1259 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
1260 dataOffset = parmOffset + t2p->oldTotalParms;
1261 dataAlign = dataOffset & 2; /* quad-align */
1262 dataOffset += dataAlign;
1263 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
1264 smb_SetSMBParm(tp, 8, 0); /* data displacement */
1265 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
1268 datap = smb_GetSMBData(tp, NULL);
1269 *datap++ = 0; /* we rounded to even */
1271 totalLength += dataAlign;
1272 smb_SetSMBDataLength(tp, totalLength);
1274 /* next, send the datagram */
1275 smb_SendPacket(vcp, tp);
1278 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1280 smb_tran2Packet_t *asp;
1293 /* We sometimes see 0 word count. What to do? */
1294 if (*inp->wctp == 0) {
1299 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1301 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1302 ptbuf[0] = "Transaction2 word count = 0";
1303 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1304 1, inp->ncb_length, ptbuf, inp);
1305 DeregisterEventSource(h);
1307 osi_Log0(smb_logp, "TRANSACTION word count = 0");
1310 smb_SetSMBDataLength(outp, 0);
1311 smb_SendPacket(vcp, outp);
1315 totalParms = smb_GetSMBParm(inp, 0);
1316 totalData = smb_GetSMBParm(inp, 1);
1318 firstPacket = (inp->inCom == 0x25);
1320 /* find the packet we're reassembling */
1321 lock_ObtainWrite(&smb_globalLock);
1322 asp = smb_FindTran2Packet(vcp, inp);
1324 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1326 lock_ReleaseWrite(&smb_globalLock);
1328 /* now merge in this latest packet; start by looking up offsets */
1330 parmDisp = dataDisp = 0;
1331 parmOffset = smb_GetSMBParm(inp, 10);
1332 dataOffset = smb_GetSMBParm(inp, 12);
1333 parmCount = smb_GetSMBParm(inp, 9);
1334 dataCount = smb_GetSMBParm(inp, 11);
1335 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1336 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1338 osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1339 totalData, dataCount, asp->maxReturnData);
1342 parmDisp = smb_GetSMBParm(inp, 4);
1343 parmOffset = smb_GetSMBParm(inp, 3);
1344 dataDisp = smb_GetSMBParm(inp, 7);
1345 dataOffset = smb_GetSMBParm(inp, 6);
1346 parmCount = smb_GetSMBParm(inp, 2);
1347 dataCount = smb_GetSMBParm(inp, 5);
1349 osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1350 parmCount, dataCount);
1353 /* now copy the parms and data */
1354 if ( asp->totalParms > 0 && parmCount != 0 )
1356 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1358 if ( asp->totalData > 0 && dataCount != 0 ) {
1359 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1362 /* account for new bytes */
1363 asp->curData += dataCount;
1364 asp->curParms += parmCount;
1366 /* finally, if we're done, remove the packet from the queue and dispatch it */
1367 if (asp->totalParms > 0 &&
1368 asp->curParms > 0 &&
1369 asp->totalData <= asp->curData &&
1370 asp->totalParms <= asp->curParms) {
1371 /* we've received it all */
1372 lock_ObtainWrite(&smb_globalLock);
1373 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1374 lock_ReleaseWrite(&smb_globalLock);
1376 /* now dispatch it */
1377 rapOp = asp->parmsp[0];
1379 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1380 osi_LogEvent("AFS-Dispatch-RAP[%s]",myCrt_RapDispatch(rapOp),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1381 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%x] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1382 code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1385 osi_LogEvent("AFS-Dispatch-RAP [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1386 osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1387 code = CM_ERROR_BADOP;
1390 /* if an error is returned, we're supposed to send an error packet,
1391 * otherwise the dispatched function already did the data sending.
1392 * We give dispatched proc the responsibility since it knows how much
1393 * space to allocate.
1396 smb_SendTran2Error(vcp, asp, outp, code);
1399 /* free the input tran 2 packet */
1400 lock_ObtainWrite(&smb_globalLock);
1401 smb_FreeTran2Packet(asp);
1402 lock_ReleaseWrite(&smb_globalLock);
1404 else if (firstPacket) {
1405 /* the first packet in a multi-packet request, we need to send an
1406 * ack to get more data.
1408 smb_SetSMBDataLength(outp, 0);
1409 smb_SendPacket(vcp, outp);
1415 /* ANSI versions. The unicode versions support arbitrary length
1416 share names, but we don't support unicode yet. */
1418 typedef struct smb_rap_share_info_0 {
1419 char shi0_netname[13];
1420 } smb_rap_share_info_0_t;
1422 typedef struct smb_rap_share_info_1 {
1423 char shi1_netname[13];
1426 DWORD shi1_remark; /* char *shi1_remark; data offset */
1427 } smb_rap_share_info_1_t;
1429 typedef struct smb_rap_share_info_2 {
1430 char shi2_netname[13];
1432 unsigned short shi2_type;
1433 DWORD shi2_remark; /* char *shi2_remark; data offset */
1434 unsigned short shi2_permissions;
1435 unsigned short shi2_max_uses;
1436 unsigned short shi2_current_uses;
1437 DWORD shi2_path; /* char *shi2_path; data offset */
1438 unsigned short shi2_passwd[9];
1439 unsigned short shi2_pad2;
1440 } smb_rap_share_info_2_t;
1442 #define SMB_RAP_MAX_SHARES 512
1444 typedef struct smb_rap_share_list {
1447 smb_rap_share_info_0_t * shares;
1448 } smb_rap_share_list_t;
1450 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1451 smb_rap_share_list_t * sp;
1456 if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1457 return 0; /* skip over '.' and '..' */
1459 sp = (smb_rap_share_list_t *) vrockp;
1461 strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1462 sp->shares[sp->cShare].shi0_netname[12] = 0;
1466 if (sp->cShare >= sp->maxShares)
1467 return CM_ERROR_STOPNOW;
1472 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1474 smb_tran2Packet_t *outp;
1475 unsigned short * tp;
1479 int outParmsTotal; /* total parameter bytes */
1480 int outDataTotal; /* total data bytes */
1488 HKEY hkSubmount = NULL;
1489 smb_rap_share_info_1_t * shares;
1492 char thisShare[256];
1495 smb_rap_share_list_t rootShares;
1500 tp = p->parmsp + 1; /* skip over function number (always 0) */
1501 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1502 (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1506 if (infoLevel != 1) {
1507 return CM_ERROR_INVAL;
1510 /* first figure out how many shares there are */
1511 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1512 KEY_QUERY_VALUE, &hkParam);
1513 if (rv == ERROR_SUCCESS) {
1514 len = sizeof(allSubmount);
1515 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1516 (BYTE *) &allSubmount, &len);
1517 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1520 RegCloseKey (hkParam);
1523 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1524 0, KEY_QUERY_VALUE, &hkSubmount);
1525 if (rv == ERROR_SUCCESS) {
1526 rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1527 NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1528 if (rv != ERROR_SUCCESS)
1534 /* fetch the root shares */
1535 rootShares.maxShares = SMB_RAP_MAX_SHARES;
1536 rootShares.cShare = 0;
1537 rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1541 userp = smb_GetTran2User(vcp,p);
1543 thyper.HighPart = 0;
1546 cm_HoldSCache(cm_data.rootSCachep);
1547 cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1548 cm_ReleaseSCache(cm_data.rootSCachep);
1550 cm_ReleaseUser(userp);
1552 nShares = rootShares.cShare + nRegShares + allSubmount;
1554 #define REMARK_LEN 1
1555 outParmsTotal = 8; /* 4 dwords */
1556 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1557 if(outDataTotal > bufsize) {
1558 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1559 outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1562 nSharesRet = nShares;
1565 outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1567 /* now for the submounts */
1568 shares = (smb_rap_share_info_1_t *) outp->datap;
1569 cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1571 memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1574 strcpy( shares[cshare].shi1_netname, "all" );
1575 shares[cshare].shi1_remark = cstrp - outp->datap;
1576 /* type and pad are zero already */
1582 for (i=0; i < nRegShares && cshare < nSharesRet; i++) {
1583 len = sizeof(thisShare);
1584 rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1585 if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1586 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1587 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1588 shares[cshare].shi1_remark = cstrp - outp->datap;
1593 nShares--; /* uncount key */
1596 RegCloseKey(hkSubmount);
1599 nonrootShares = cshare;
1601 for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1602 /* in case there are collisions with submounts, submounts have higher priority */
1603 for (j=0; j < nonrootShares; j++)
1604 if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1607 if (j < nonrootShares) {
1608 nShares--; /* uncount */
1612 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1613 shares[cshare].shi1_remark = cstrp - outp->datap;
1618 outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1619 outp->parmsp[1] = 0;
1620 outp->parmsp[2] = cshare;
1621 outp->parmsp[3] = nShares;
1623 outp->totalData = cstrp - outp->datap;
1624 outp->totalParms = outParmsTotal;
1626 smb_SendTran2Packet(vcp, outp, op);
1627 smb_FreeTran2Packet(outp);
1629 free(rootShares.shares);
1634 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1636 smb_tran2Packet_t *outp;
1637 unsigned short * tp;
1639 BOOL shareFound = FALSE;
1640 unsigned short infoLevel;
1641 unsigned short bufsize;
1651 tp = p->parmsp + 1; /* skip over function number (always 1) */
1652 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1653 (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1654 shareName = smb_ParseString( (char *) tp, (char **) &tp);
1661 totalData = sizeof(smb_rap_share_info_0_t);
1662 else if(infoLevel == SMB_INFO_STANDARD)
1663 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1664 else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1665 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1667 return CM_ERROR_INVAL;
1669 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1671 if(!stricmp(shareName,"all")) {
1672 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1673 KEY_QUERY_VALUE, &hkParam);
1674 if (rv == ERROR_SUCCESS) {
1675 len = sizeof(allSubmount);
1676 rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1677 (BYTE *) &allSubmount, &len);
1678 if (rv != ERROR_SUCCESS || allSubmount != 0) {
1681 RegCloseKey (hkParam);
1688 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1689 KEY_QUERY_VALUE, &hkSubmount);
1690 if (rv == ERROR_SUCCESS) {
1691 rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1692 if (rv == ERROR_SUCCESS) {
1695 RegCloseKey(hkSubmount);
1700 smb_FreeTran2Packet(outp);
1701 return CM_ERROR_BADSHARENAME;
1704 memset(outp->datap, 0, totalData);
1706 outp->parmsp[0] = 0;
1707 outp->parmsp[1] = 0;
1708 outp->parmsp[2] = totalData;
1710 if (infoLevel == 0) {
1711 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1712 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1713 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1714 } else if(infoLevel == SMB_INFO_STANDARD) {
1715 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1716 strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1717 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1718 info->shi1_remark = ((unsigned char *) (info + 1)) - outp->datap;
1719 /* type and pad are already zero */
1720 } else { /* infoLevel==2 */
1721 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1722 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1723 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1724 info->shi2_remark = ((unsigned char *) (info + 1)) - outp->datap;
1725 info->shi2_permissions = ACCESS_ALL;
1726 info->shi2_max_uses = (unsigned short) -1;
1727 info->shi2_path = 1 + (((unsigned char *) (info + 1)) - outp->datap);
1730 outp->totalData = totalData;
1731 outp->totalParms = totalParam;
1733 smb_SendTran2Packet(vcp, outp, op);
1734 smb_FreeTran2Packet(outp);
1739 typedef struct smb_rap_wksta_info_10 {
1740 DWORD wki10_computername; /*char *wki10_computername;*/
1741 DWORD wki10_username; /* char *wki10_username; */
1742 DWORD wki10_langroup; /* char *wki10_langroup;*/
1743 unsigned char wki10_ver_major;
1744 unsigned char wki10_ver_minor;
1745 DWORD wki10_logon_domain; /*char *wki10_logon_domain;*/
1746 DWORD wki10_oth_domains; /* char *wki10_oth_domains;*/
1747 } smb_rap_wksta_info_10_t;
1750 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1752 smb_tran2Packet_t *outp;
1756 unsigned short * tp;
1759 smb_rap_wksta_info_10_t * info;
1763 tp = p->parmsp + 1; /* Skip over function number */
1764 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1765 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1769 if (infoLevel != 10) {
1770 return CM_ERROR_INVAL;
1776 totalData = sizeof(*info) + /* info */
1777 MAX_COMPUTERNAME_LENGTH + /* wki10_computername */
1778 SMB_MAX_USERNAME_LENGTH + /* wki10_username */
1779 MAX_COMPUTERNAME_LENGTH + /* wki10_langroup */
1780 MAX_COMPUTERNAME_LENGTH + /* wki10_logon_domain */
1781 1; /* wki10_oth_domains (null)*/
1783 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1785 memset(outp->parmsp,0,totalParams);
1786 memset(outp->datap,0,totalData);
1788 info = (smb_rap_wksta_info_10_t *) outp->datap;
1789 cstrp = (char *) (info + 1);
1791 info->wki10_computername = (DWORD) (cstrp - outp->datap);
1792 strcpy(cstrp, smb_localNamep);
1793 cstrp += strlen(cstrp) + 1;
1795 info->wki10_username = (DWORD) (cstrp - outp->datap);
1796 uidp = smb_FindUID(vcp, p->uid, 0);
1798 lock_ObtainMutex(&uidp->mx);
1799 if(uidp->unp && uidp->unp->name)
1800 strcpy(cstrp, uidp->unp->name);
1801 lock_ReleaseMutex(&uidp->mx);
1802 smb_ReleaseUID(uidp);
1804 cstrp += strlen(cstrp) + 1;
1806 info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1807 strcpy(cstrp, "WORKGROUP");
1808 cstrp += strlen(cstrp) + 1;
1810 /* TODO: Not sure what values these should take, but these work */
1811 info->wki10_ver_major = 5;
1812 info->wki10_ver_minor = 1;
1814 info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1815 strcpy(cstrp, smb_ServerDomainName);
1816 cstrp += strlen(cstrp) + 1;
1818 info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1819 cstrp ++; /* no other domains */
1821 outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1822 outp->parmsp[2] = outp->totalData;
1823 outp->totalParms = totalParams;
1825 smb_SendTran2Packet(vcp,outp,op);
1826 smb_FreeTran2Packet(outp);
1831 typedef struct smb_rap_server_info_0 {
1833 } smb_rap_server_info_0_t;
1835 typedef struct smb_rap_server_info_1 {
1837 char sv1_version_major;
1838 char sv1_version_minor;
1839 unsigned long sv1_type;
1840 DWORD *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1841 } smb_rap_server_info_1_t;
1843 char smb_ServerComment[] = "OpenAFS Client";
1844 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1846 #define SMB_SV_TYPE_SERVER 0x00000002L
1847 #define SMB_SV_TYPE_NT 0x00001000L
1848 #define SMB_SV_TYPE_SERVER_NT 0x00008000L
1850 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1852 smb_tran2Packet_t *outp;
1856 unsigned short * tp;
1859 smb_rap_server_info_0_t * info0;
1860 smb_rap_server_info_1_t * info1;
1863 tp = p->parmsp + 1; /* Skip over function number */
1864 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1865 (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1869 if (infoLevel != 0 && infoLevel != 1) {
1870 return CM_ERROR_INVAL;
1876 (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1877 : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1879 outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1881 memset(outp->parmsp,0,totalParams);
1882 memset(outp->datap,0,totalData);
1884 if (infoLevel == 0) {
1885 info0 = (smb_rap_server_info_0_t *) outp->datap;
1886 cstrp = (char *) (info0 + 1);
1887 strcpy(info0->sv0_name, "AFS");
1888 } else { /* infoLevel == SMB_INFO_STANDARD */
1889 info1 = (smb_rap_server_info_1_t *) outp->datap;
1890 cstrp = (char *) (info1 + 1);
1891 strcpy(info1->sv1_name, "AFS");
1894 SMB_SV_TYPE_SERVER |
1896 SMB_SV_TYPE_SERVER_NT;
1898 info1->sv1_version_major = 5;
1899 info1->sv1_version_minor = 1;
1900 info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1902 strcpy(cstrp, smb_ServerComment);
1904 cstrp += smb_ServerCommentLen;
1907 totalData = cstrp - outp->datap;
1908 outp->totalData = min(bufsize,totalData); /* actual data size */
1909 outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1910 outp->parmsp[2] = totalData;
1911 outp->totalParms = totalParams;
1913 smb_SendTran2Packet(vcp,outp,op);
1914 smb_FreeTran2Packet(outp);
1919 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1921 smb_tran2Packet_t *asp;
1933 /* We sometimes see 0 word count. What to do? */
1934 if (*inp->wctp == 0) {
1939 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1941 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1942 ptbuf[0] = "Transaction2 word count = 0";
1943 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1944 1, inp->ncb_length, ptbuf, inp);
1945 DeregisterEventSource(h);
1947 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
1950 smb_SetSMBDataLength(outp, 0);
1951 smb_SendPacket(vcp, outp);
1955 totalParms = smb_GetSMBParm(inp, 0);
1956 totalData = smb_GetSMBParm(inp, 1);
1958 firstPacket = (inp->inCom == 0x32);
1960 /* find the packet we're reassembling */
1961 lock_ObtainWrite(&smb_globalLock);
1962 asp = smb_FindTran2Packet(vcp, inp);
1964 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1966 lock_ReleaseWrite(&smb_globalLock);
1968 /* now merge in this latest packet; start by looking up offsets */
1970 parmDisp = dataDisp = 0;
1971 parmOffset = smb_GetSMBParm(inp, 10);
1972 dataOffset = smb_GetSMBParm(inp, 12);
1973 parmCount = smb_GetSMBParm(inp, 9);
1974 dataCount = smb_GetSMBParm(inp, 11);
1975 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1976 asp->maxReturnData = smb_GetSMBParm(inp, 3);
1978 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1979 totalData, dataCount, asp->maxReturnData);
1982 parmDisp = smb_GetSMBParm(inp, 4);
1983 parmOffset = smb_GetSMBParm(inp, 3);
1984 dataDisp = smb_GetSMBParm(inp, 7);
1985 dataOffset = smb_GetSMBParm(inp, 6);
1986 parmCount = smb_GetSMBParm(inp, 2);
1987 dataCount = smb_GetSMBParm(inp, 5);
1989 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1990 parmCount, dataCount);
1993 /* now copy the parms and data */
1994 if ( asp->totalParms > 0 && parmCount != 0 )
1996 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1998 if ( asp->totalData > 0 && dataCount != 0 ) {
1999 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2002 /* account for new bytes */
2003 asp->curData += dataCount;
2004 asp->curParms += parmCount;
2006 /* finally, if we're done, remove the packet from the queue and dispatch it */
2007 if (asp->totalParms > 0 &&
2008 asp->curParms > 0 &&
2009 asp->totalData <= asp->curData &&
2010 asp->totalParms <= asp->curParms) {
2011 /* we've received it all */
2012 lock_ObtainWrite(&smb_globalLock);
2013 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2014 lock_ReleaseWrite(&smb_globalLock);
2016 /* now dispatch it */
2017 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2018 osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
2019 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2020 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2023 osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2024 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2025 code = CM_ERROR_BADOP;
2028 /* if an error is returned, we're supposed to send an error packet,
2029 * otherwise the dispatched function already did the data sending.
2030 * We give dispatched proc the responsibility since it knows how much
2031 * space to allocate.
2034 smb_SendTran2Error(vcp, asp, outp, code);
2037 /* free the input tran 2 packet */
2038 lock_ObtainWrite(&smb_globalLock);
2039 smb_FreeTran2Packet(asp);
2040 lock_ReleaseWrite(&smb_globalLock);
2042 else if (firstPacket) {
2043 /* the first packet in a multi-packet request, we need to send an
2044 * ack to get more data.
2046 smb_SetSMBDataLength(outp, 0);
2047 smb_SendPacket(vcp, outp);
2053 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2056 smb_tran2Packet_t *outp;
2061 cm_scache_t *dscp; /* dir we're dealing with */
2062 cm_scache_t *scp; /* file we're creating */
2064 int initialModeBits;
2074 int parmSlot; /* which parm we're dealing with */
2075 long returnEALength;
2083 extraInfo = (p->parmsp[0] & 1); /* return extra info */
2084 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
2086 openFun = p->parmsp[6]; /* open function */
2087 excl = ((openFun & 3) == 0);
2088 trunc = ((openFun & 3) == 2); /* truncate it */
2089 openMode = (p->parmsp[1] & 0x7);
2090 openAction = 0; /* tracks what we did */
2092 attributes = p->parmsp[3];
2093 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2095 /* compute initial mode bits based on read-only flag in attributes */
2096 initialModeBits = 0666;
2098 initialModeBits &= ~0222;
2100 pathp = (char *) (&p->parmsp[14]);
2101 if (smb_StoreAnsiFilenames)
2102 OemToChar(pathp,pathp);
2104 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2106 spacep = cm_GetSpace();
2107 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2109 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2110 /* special case magic file name for receiving IOCTL requests
2111 * (since IOCTL calls themselves aren't getting through).
2113 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2114 smb_SetupIoctlFid(fidp, spacep);
2116 /* copy out remainder of the parms */
2118 outp->parmsp[parmSlot++] = fidp->fid;
2120 outp->parmsp[parmSlot++] = 0; /* attrs */
2121 outp->parmsp[parmSlot++] = 0; /* mod time */
2122 outp->parmsp[parmSlot++] = 0;
2123 outp->parmsp[parmSlot++] = 0; /* len */
2124 outp->parmsp[parmSlot++] = 0x7fff;
2125 outp->parmsp[parmSlot++] = openMode;
2126 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2127 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2129 /* and the final "always present" stuff */
2130 outp->parmsp[parmSlot++] = 1; /* openAction found existing file */
2131 /* next write out the "unique" ID */
2132 outp->parmsp[parmSlot++] = 0x1234;
2133 outp->parmsp[parmSlot++] = 0x5678;
2134 outp->parmsp[parmSlot++] = 0;
2135 if (returnEALength) {
2136 outp->parmsp[parmSlot++] = 0;
2137 outp->parmsp[parmSlot++] = 0;
2140 outp->totalData = 0;
2141 outp->totalParms = parmSlot * 2;
2143 smb_SendTran2Packet(vcp, outp, op);
2145 smb_FreeTran2Packet(outp);
2147 /* and clean up fid reference */
2148 smb_ReleaseFID(fidp);
2152 #ifdef DEBUG_VERBOSE
2154 char *hexp, *asciip;
2155 asciip = (lastNamep ? lastNamep : pathp);
2156 hexp = osi_HexifyString( asciip );
2157 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2162 userp = smb_GetTran2User(vcp, p);
2163 /* In the off chance that userp is NULL, we log and abandon */
2165 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2166 smb_FreeTran2Packet(outp);
2167 return CM_ERROR_BADSMB;
2170 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2171 if (code == CM_ERROR_TIDIPC) {
2172 /* Attempt to use a TID allocated for IPC. The client
2173 * is probably looking for DCE RPC end points which we
2174 * don't support OR it could be looking to make a DFS
2177 osi_Log0(smb_logp, "Tran2Open received IPC TID");
2179 cm_ReleaseUser(userp);
2180 smb_FreeTran2Packet(outp);
2181 return CM_ERROR_NOSUCHPATH;
2186 code = cm_NameI(cm_data.rootSCachep, pathp,
2187 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2188 userp, tidPathp, &req, &scp);
2190 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2191 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2192 userp, tidPathp, &req, &dscp);
2193 cm_FreeSpace(spacep);
2196 cm_ReleaseUser(userp);
2197 smb_FreeTran2Packet(outp);
2202 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2203 cm_ReleaseSCache(dscp);
2204 cm_ReleaseUser(userp);
2205 smb_FreeTran2Packet(outp);
2206 if ( WANTS_DFS_PATHNAMES(p) )
2207 return CM_ERROR_PATH_NOT_COVERED;
2209 return CM_ERROR_BADSHARENAME;
2211 #endif /* DFS_SUPPORT */
2213 /* otherwise, scp points to the parent directory. Do a lookup,
2214 * and truncate the file if we find it, otherwise we create the
2221 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2223 if (code && code != CM_ERROR_NOSUCHFILE) {
2224 cm_ReleaseSCache(dscp);
2225 cm_ReleaseUser(userp);
2226 smb_FreeTran2Packet(outp);
2231 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2232 cm_ReleaseSCache(scp);
2233 cm_ReleaseUser(userp);
2234 smb_FreeTran2Packet(outp);
2235 if ( WANTS_DFS_PATHNAMES(p) )
2236 return CM_ERROR_PATH_NOT_COVERED;
2238 return CM_ERROR_BADSHARENAME;
2240 #endif /* DFS_SUPPORT */
2242 /* macintosh is expensive to program for it */
2243 cm_FreeSpace(spacep);
2246 /* if we get here, if code is 0, the file exists and is represented by
2247 * scp. Otherwise, we have to create it.
2250 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2253 cm_ReleaseSCache(dscp);
2254 cm_ReleaseSCache(scp);
2255 cm_ReleaseUser(userp);
2256 smb_FreeTran2Packet(outp);
2261 /* oops, file shouldn't be there */
2263 cm_ReleaseSCache(dscp);
2264 cm_ReleaseSCache(scp);
2265 cm_ReleaseUser(userp);
2266 smb_FreeTran2Packet(outp);
2267 return CM_ERROR_EXISTS;
2271 setAttr.mask = CM_ATTRMASK_LENGTH;
2272 setAttr.length.LowPart = 0;
2273 setAttr.length.HighPart = 0;
2274 code = cm_SetAttr(scp, &setAttr, userp, &req);
2275 openAction = 3; /* truncated existing file */
2278 openAction = 1; /* found existing file */
2280 else if (!(openFun & 0x10)) {
2281 /* don't create if not found */
2283 cm_ReleaseSCache(dscp);
2284 osi_assert(scp == NULL);
2285 cm_ReleaseUser(userp);
2286 smb_FreeTran2Packet(outp);
2287 return CM_ERROR_NOSUCHFILE;
2290 osi_assert(dscp != NULL && scp == NULL);
2291 openAction = 2; /* created file */
2292 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2293 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2294 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2296 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2297 smb_NotifyChange(FILE_ACTION_ADDED,
2298 FILE_NOTIFY_CHANGE_FILE_NAME,
2299 dscp, lastNamep, NULL, TRUE);
2300 if (!excl && code == CM_ERROR_EXISTS) {
2301 /* not an exclusive create, and someone else tried
2302 * creating it already, then we open it anyway. We
2303 * don't bother retrying after this, since if this next
2304 * fails, that means that the file was deleted after we
2305 * started this call.
2307 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2311 setAttr.mask = CM_ATTRMASK_LENGTH;
2312 setAttr.length.LowPart = 0;
2313 setAttr.length.HighPart = 0;
2314 code = cm_SetAttr(scp, &setAttr, userp,
2317 } /* lookup succeeded */
2321 /* we don't need this any longer */
2323 cm_ReleaseSCache(dscp);
2326 /* something went wrong creating or truncating the file */
2328 cm_ReleaseSCache(scp);
2329 cm_ReleaseUser(userp);
2330 smb_FreeTran2Packet(outp);
2334 /* make sure we're about to open a file */
2335 if (scp->fileType != CM_SCACHETYPE_FILE) {
2337 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2338 cm_scache_t * targetScp = 0;
2339 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2341 /* we have a more accurate file to use (the
2342 * target of the symbolic link). Otherwise,
2343 * we'll just use the symlink anyway.
2345 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2347 cm_ReleaseSCache(scp);
2351 if (scp->fileType != CM_SCACHETYPE_FILE) {
2352 cm_ReleaseSCache(scp);
2353 cm_ReleaseUser(userp);
2354 smb_FreeTran2Packet(outp);
2355 return CM_ERROR_ISDIR;
2359 /* now all we have to do is open the file itself */
2360 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2363 /* save a pointer to the vnode */
2366 /* compute open mode */
2367 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2368 if (openMode == 1 || openMode == 2)
2369 fidp->flags |= SMB_FID_OPENWRITE;
2371 smb_ReleaseFID(fidp);
2373 cm_Open(scp, 0, userp);
2375 /* copy out remainder of the parms */
2377 outp->parmsp[parmSlot++] = fidp->fid;
2378 lock_ObtainMutex(&scp->mx);
2380 outp->parmsp[parmSlot++] = smb_Attributes(scp);
2381 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2382 outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2383 outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2384 outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2385 outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2386 outp->parmsp[parmSlot++] = openMode;
2387 outp->parmsp[parmSlot++] = 0; /* file type 0 ==> normal file or dir */
2388 outp->parmsp[parmSlot++] = 0; /* IPC junk */
2390 /* and the final "always present" stuff */
2391 outp->parmsp[parmSlot++] = openAction;
2392 /* next write out the "unique" ID */
2393 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
2394 outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
2395 outp->parmsp[parmSlot++] = 0;
2396 if (returnEALength) {
2397 outp->parmsp[parmSlot++] = 0;
2398 outp->parmsp[parmSlot++] = 0;
2400 lock_ReleaseMutex(&scp->mx);
2401 outp->totalData = 0; /* total # of data bytes */
2402 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
2404 smb_SendTran2Packet(vcp, outp, op);
2406 smb_FreeTran2Packet(outp);
2408 cm_ReleaseUser(userp);
2409 /* leave scp held since we put it in fidp->scp */
2413 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2415 osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2416 return CM_ERROR_BADOP;
2419 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2421 osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2422 return CM_ERROR_BADOP;
2425 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2427 smb_tran2Packet_t *outp;
2428 smb_tran2QFSInfo_t qi;
2431 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
2433 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2435 switch (p->parmsp[0]) {
2436 case 1: responseSize = sizeof(qi.u.allocInfo); break;
2437 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
2438 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
2439 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
2440 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
2441 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
2442 case 0x200: /* CIFS Unix Info */
2443 case 0x301: /* Mac FS Info */
2444 default: return CM_ERROR_INVAL;
2447 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2448 switch (p->parmsp[0]) {
2451 qi.u.allocInfo.FSID = 0;
2452 qi.u.allocInfo.sectorsPerAllocUnit = 1;
2453 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2454 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2455 qi.u.allocInfo.bytesPerSector = 1024;
2460 qi.u.volumeInfo.vsn = 1234;
2461 qi.u.volumeInfo.vnCount = 4;
2462 /* we're supposed to pad it out with zeroes to the end */
2463 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2464 memcpy(qi.u.volumeInfo.label, "AFS", 4);
2468 /* FS volume info */
2469 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
2470 qi.u.FSvolumeInfo.vsn = 1234;
2471 qi.u.FSvolumeInfo.vnCount = 8;
2472 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
2478 temp.LowPart = 0x7fffffff;
2479 qi.u.FSsizeInfo.totalAllocUnits = temp;
2480 temp.LowPart = 0x3fffffff;
2481 qi.u.FSsizeInfo.availAllocUnits = temp;
2482 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2483 qi.u.FSsizeInfo.bytesPerSector = 1024;
2487 /* FS device info */
2488 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
2489 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2493 /* FS attribute info */
2494 /* attributes, defined in WINNT.H:
2495 * FILE_CASE_SENSITIVE_SEARCH 0x1
2496 * FILE_CASE_PRESERVED_NAMES 0x2
2497 * <no name defined> 0x4000
2498 * If bit 0x4000 is not set, Windows 95 thinks
2499 * we can't handle long (non-8.3) names,
2500 * despite our protestations to the contrary.
2502 qi.u.FSattributeInfo.attributes = 0x4003;
2503 qi.u.FSattributeInfo.maxCompLength = 255;
2504 qi.u.FSattributeInfo.FSnameLength = 6;
2505 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
2509 /* copy out return data, and set corresponding sizes */
2510 outp->totalParms = 0;
2511 outp->totalData = responseSize;
2512 memcpy(outp->datap, &qi, responseSize);
2514 /* send and free the packets */
2515 smb_SendTran2Packet(vcp, outp, op);
2516 smb_FreeTran2Packet(outp);
2521 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2523 osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2524 return CM_ERROR_BADOP;
2527 struct smb_ShortNameRock {
2531 size_t shortNameLen;
2534 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2537 struct smb_ShortNameRock *rockp;
2541 /* compare both names and vnodes, though probably just comparing vnodes
2542 * would be safe enough.
2544 if (cm_stricmp(dep->name, rockp->maskp) != 0)
2546 if (ntohl(dep->fid.vnode) != rockp->vnode)
2548 /* This is the entry */
2549 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2550 rockp->shortNameLen = shortNameEnd - rockp->shortName;
2551 return CM_ERROR_STOPNOW;
2554 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2555 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2557 struct smb_ShortNameRock rock;
2561 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2565 spacep = cm_GetSpace();
2566 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2568 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2570 cm_FreeSpace(spacep);
2575 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2576 cm_ReleaseSCache(dscp);
2577 cm_ReleaseUser(userp);
2578 return CM_ERROR_PATH_NOT_COVERED;
2580 #endif /* DFS_SUPPORT */
2582 if (!lastNamep) lastNamep = pathp;
2585 thyper.HighPart = 0;
2586 rock.shortName = shortName;
2588 rock.maskp = lastNamep;
2589 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2591 cm_ReleaseSCache(dscp);
2594 return CM_ERROR_NOSUCHFILE;
2595 if (code == CM_ERROR_STOPNOW) {
2596 *shortNameLenp = rock.shortNameLen;
2602 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2604 smb_tran2Packet_t *outp;
2607 unsigned short infoLevel;
2609 unsigned short attributes;
2610 unsigned long extAttributes;
2615 cm_scache_t *scp, *dscp;
2624 infoLevel = p->parmsp[0];
2625 if (infoLevel == SMB_INFO_IS_NAME_VALID)
2627 else if (infoLevel == SMB_INFO_STANDARD)
2628 nbytesRequired = 22;
2629 else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
2630 nbytesRequired = 26;
2631 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2632 nbytesRequired = 40;
2633 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2634 nbytesRequired = 24;
2635 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2637 else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
2638 nbytesRequired = 30;
2640 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2641 p->opcode, infoLevel);
2642 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2645 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2646 osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
2648 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2650 if (infoLevel > 0x100)
2651 outp->totalParms = 2;
2653 outp->totalParms = 0;
2654 outp->totalData = nbytesRequired;
2656 /* now, if we're at infoLevel 6, we're only being asked to check
2657 * the syntax, so we just OK things now. In particular, we're *not*
2658 * being asked to verify anything about the state of any parent dirs.
2660 if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2661 smb_SendTran2Packet(vcp, outp, opx);
2662 smb_FreeTran2Packet(outp);
2666 userp = smb_GetTran2User(vcp, p);
2668 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2669 smb_FreeTran2Packet(outp);
2670 return CM_ERROR_BADSMB;
2673 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2675 cm_ReleaseUser(userp);
2676 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2677 smb_FreeTran2Packet(outp);
2682 * XXX Strange hack XXX
2684 * As of Patch 7 (13 January 98), we are having the following problem:
2685 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2686 * requests to look up "desktop.ini" in all the subdirectories.
2687 * This can cause zillions of timeouts looking up non-existent cells
2688 * and volumes, especially in the top-level directory.
2690 * We have not found any way to avoid this or work around it except
2691 * to explicitly ignore the requests for mount points that haven't
2692 * yet been evaluated and for directories that haven't yet been
2695 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2696 spacep = cm_GetSpace();
2697 smb_StripLastComponent(spacep->data, &lastComp,
2698 (char *)(&p->parmsp[3]));
2699 #ifndef SPECIAL_FOLDERS
2700 /* Make sure that lastComp is not NULL */
2702 if (stricmp(lastComp, "\\desktop.ini") == 0) {
2703 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2707 userp, tidPathp, &req, &dscp);
2710 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2711 if ( WANTS_DFS_PATHNAMES(p) )
2712 code = CM_ERROR_PATH_NOT_COVERED;
2714 code = CM_ERROR_BADSHARENAME;
2716 #endif /* DFS_SUPPORT */
2717 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2718 code = CM_ERROR_NOSUCHFILE;
2719 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2720 cm_buf_t *bp = buf_Find(dscp, &hzero);
2724 code = CM_ERROR_NOSUCHFILE;
2726 cm_ReleaseSCache(dscp);
2728 cm_FreeSpace(spacep);
2729 cm_ReleaseUser(userp);
2730 smb_SendTran2Error(vcp, p, opx, code);
2731 smb_FreeTran2Packet(outp);
2737 #endif /* SPECIAL_FOLDERS */
2739 cm_FreeSpace(spacep);
2742 /* now do namei and stat, and copy out the info */
2743 code = cm_NameI(cm_data.rootSCachep, (char *)(&p->parmsp[3]),
2744 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2747 cm_ReleaseUser(userp);
2748 smb_SendTran2Error(vcp, p, opx, code);
2749 smb_FreeTran2Packet(outp);
2754 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2755 cm_ReleaseSCache(scp);
2756 cm_ReleaseUser(userp);
2757 if ( WANTS_DFS_PATHNAMES(p) )
2758 code = CM_ERROR_PATH_NOT_COVERED;
2760 code = CM_ERROR_BADSHARENAME;
2761 smb_SendTran2Error(vcp, p, opx, code);
2762 smb_FreeTran2Packet(outp);
2765 #endif /* DFS_SUPPORT */
2767 lock_ObtainMutex(&scp->mx);
2768 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2769 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2770 if (code) goto done;
2772 /* now we have the status in the cache entry, and everything is locked.
2773 * Marshall the output data.
2776 /* for info level 108, figure out short name */
2777 if (infoLevel == 0x108) {
2778 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
2779 tidPathp, scp->fid.vnode, shortName,
2786 *((u_long *)op) = len * 2; op += 4;
2787 mbstowcs((unsigned short *)op, shortName, len);
2792 if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2793 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2794 *((u_long *)op) = dosTime; op += 4; /* creation time */
2795 *((u_long *)op) = dosTime; op += 4; /* access time */
2796 *((u_long *)op) = dosTime; op += 4; /* write time */
2797 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
2798 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
2799 attributes = smb_Attributes(scp);
2800 *((u_short *)op) = attributes; op += 2; /* attributes */
2802 else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2803 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2804 *((FILETIME *)op) = ft; op += 8; /* creation time */
2805 *((FILETIME *)op) = ft; op += 8; /* last access time */
2806 *((FILETIME *)op) = ft; op += 8; /* last write time */
2807 *((FILETIME *)op) = ft; op += 8; /* last change time */
2808 extAttributes = smb_ExtAttributes(scp);
2809 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
2810 *((u_long *)op) = 0; op += 4; /* don't know what this is */
2812 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2813 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2814 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2815 *((u_long *)op) = scp->linkCount; op += 4;
2818 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2821 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2822 memset(op, 0, 4); op += 4; /* EA size */
2825 /* now, if we are being asked about extended attrs, return a 0 size */
2826 if (infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2827 *((u_long *)op) = 0; op += 4;
2831 /* send and free the packets */
2833 lock_ReleaseMutex(&scp->mx);
2834 cm_ReleaseSCache(scp);
2835 cm_ReleaseUser(userp);
2837 smb_SendTran2Packet(vcp, outp, opx);
2839 smb_SendTran2Error(vcp, p, opx, code);
2840 smb_FreeTran2Packet(outp);
2845 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2847 osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2848 return CM_ERROR_BADOP;
2851 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2853 smb_tran2Packet_t *outp;
2855 unsigned long attributes;
2856 unsigned short infoLevel;
2869 fidp = smb_FindFID(vcp, fid, 0);
2872 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2876 infoLevel = p->parmsp[1];
2877 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2878 nbytesRequired = 40;
2879 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2880 nbytesRequired = 24;
2881 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2883 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
2886 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2887 p->opcode, infoLevel);
2888 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2889 smb_ReleaseFID(fidp);
2892 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2894 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2896 if (infoLevel > 0x100)
2897 outp->totalParms = 2;
2899 outp->totalParms = 0;
2900 outp->totalData = nbytesRequired;
2902 userp = smb_GetTran2User(vcp, p);
2904 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2905 code = CM_ERROR_BADSMB;
2910 lock_ObtainMutex(&scp->mx);
2911 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2912 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2916 /* now we have the status in the cache entry, and everything is locked.
2917 * Marshall the output data.
2920 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2921 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2922 *((FILETIME *)op) = ft; op += 8; /* creation time */
2923 *((FILETIME *)op) = ft; op += 8; /* last access time */
2924 *((FILETIME *)op) = ft; op += 8; /* last write time */
2925 *((FILETIME *)op) = ft; op += 8; /* last change time */
2926 attributes = smb_ExtAttributes(scp);
2927 *((u_long *)op) = attributes; op += 4;
2928 *((u_long *)op) = 0; op += 4;
2930 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2931 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
2932 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
2933 *((u_long *)op) = scp->linkCount; op += 4;
2934 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
2935 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2939 else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2940 *((u_long *)op) = 0; op += 4;
2942 else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2946 if (fidp->NTopen_wholepathp)
2947 name = fidp->NTopen_wholepathp;
2949 name = "\\"; /* probably can't happen */
2951 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
2952 *((u_long *)op) = len * 2; op += 4;
2953 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2956 /* send and free the packets */
2958 lock_ReleaseMutex(&scp->mx);
2959 cm_ReleaseUser(userp);
2960 smb_ReleaseFID(fidp);
2962 smb_SendTran2Packet(vcp, outp, opx);
2964 smb_SendTran2Error(vcp, p, opx, code);
2965 smb_FreeTran2Packet(outp);
2970 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2975 unsigned short infoLevel;
2976 smb_tran2Packet_t *outp;
2984 fidp = smb_FindFID(vcp, fid, 0);
2987 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
2991 infoLevel = p->parmsp[1];
2992 osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type=[%x] fid=[%x]", infoLevel, fid);
2993 if (infoLevel > 0x104 || infoLevel < 0x101) {
2994 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2995 p->opcode, infoLevel);
2996 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
2997 smb_ReleaseFID(fidp);
3001 if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) {
3002 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
3003 smb_ReleaseFID(fidp);
3006 if ((infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO)
3007 && !(fidp->flags & SMB_FID_OPENWRITE)) {
3008 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
3009 smb_ReleaseFID(fidp);
3013 osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
3015 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
3017 outp->totalParms = 2;
3018 outp->totalData = 0;
3020 userp = smb_GetTran2User(vcp, p);
3022 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3023 code = CM_ERROR_BADSMB;
3029 if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3031 unsigned int attribute;
3034 /* lock the vnode with a callback; we need the current status
3035 * to determine what the new status is, in some cases.
3037 lock_ObtainMutex(&scp->mx);
3038 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3039 CM_SCACHESYNC_GETSTATUS
3040 | CM_SCACHESYNC_NEEDCALLBACK);
3042 lock_ReleaseMutex(&scp->mx);
3046 /* prepare for setattr call */
3049 lastMod = *((FILETIME *)(p->datap + 16));
3050 /* when called as result of move a b, lastMod is (-1, -1).
3051 * If the check for -1 is not present, timestamp
3052 * of the resulting file will be 1969 (-1)
3054 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
3055 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3056 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3057 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3058 fidp->flags |= SMB_FID_MTIMESETDONE;
3061 attribute = *((u_long *)(p->datap + 32));
3062 if (attribute != 0) {
3063 if ((scp->unixModeBits & 0222)
3064 && (attribute & 1) != 0) {
3065 /* make a writable file read-only */
3066 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3067 attr.unixModeBits = scp->unixModeBits & ~0222;
3069 else if ((scp->unixModeBits & 0222) == 0
3070 && (attribute & 1) == 0) {
3071 /* make a read-only file writable */
3072 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3073 attr.unixModeBits = scp->unixModeBits | 0222;
3076 lock_ReleaseMutex(&scp->mx);
3080 code = cm_SetAttr(scp, &attr, userp, &req);
3084 else if (infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3085 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3088 attr.mask = CM_ATTRMASK_LENGTH;
3089 attr.length.LowPart = size.LowPart;
3090 attr.length.HighPart = size.HighPart;
3091 code = cm_SetAttr(scp, &attr, userp, &req);
3093 else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3094 if (*((char *)(p->datap))) {
3095 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3098 fidp->flags |= SMB_FID_DELONCLOSE;
3102 fidp->flags &= ~SMB_FID_DELONCLOSE;
3107 cm_ReleaseUser(userp);
3108 smb_ReleaseFID(fidp);
3110 smb_SendTran2Packet(vcp, outp, op);
3112 smb_SendTran2Error(vcp, p, op, code);
3113 smb_FreeTran2Packet(outp);
3119 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3121 osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3122 return CM_ERROR_BADOP;
3126 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3128 osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3129 return CM_ERROR_BADOP;
3133 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3135 osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3136 return CM_ERROR_BADOP;
3140 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3142 osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3143 return CM_ERROR_BADOP;
3147 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3149 osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3150 return CM_ERROR_BADOP;
3154 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3156 osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3157 return CM_ERROR_BADOP;
3160 struct smb_v2_referral {
3162 USHORT ReferralFlags;
3165 USHORT DfsPathOffset;
3166 USHORT DfsAlternativePathOffset;
3167 USHORT NetworkAddressOffset;
3171 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3173 /* This is a UNICODE only request (bit15 of Flags2) */
3174 /* The TID must be IPC$ */
3176 /* The documentation for the Flags response field is contradictory */
3178 /* Use Version 1 Referral Element Format */
3179 /* ServerType = 0; indicates the next server should be queried for the file */
3180 /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3181 /* Node = UnicodeString of UNC path of the next share name */
3184 int maxReferralLevel = 0;
3185 char requestFileName[1024] = "";
3186 smb_tran2Packet_t *outp = 0;
3187 cm_user_t *userp = 0;
3190 CPINFO CodePageInfo;
3191 int i, nbnLen, reqLen;
3196 maxReferralLevel = p->parmsp[0];
3198 GetCPInfo(CP_ACP, &CodePageInfo);
3199 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1,
3200 requestFileName, 1024, NULL, NULL);
3202 osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]",
3203 maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3205 nbnLen = strlen(cm_NetbiosName);
3206 reqLen = strlen(requestFileName);
3208 if (reqLen == nbnLen + 5 &&
3209 requestFileName[0] == '\\' &&
3210 !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3211 requestFileName[nbnLen+1] == '\\' &&
3212 !_strnicmp("all",&requestFileName[nbnLen+2],3))
3215 struct smb_v2_referral * v2ref;
3216 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
3218 sp = (USHORT *)outp->datap;
3220 sp[idx++] = reqLen; /* path consumed */
3221 sp[idx++] = 1; /* number of referrals */
3222 sp[idx++] = 0x03; /* flags */
3223 #ifdef DFS_VERSION_1
3224 sp[idx++] = 1; /* Version Number */
3225 sp[idx++] = reqLen + 4; /* Referral Size */
3226 sp[idx++] = 1; /* Type = SMB Server */
3227 sp[idx++] = 0; /* Do not strip path consumed */
3228 for ( i=0;i<=reqLen; i++ )
3229 sp[i+idx] = requestFileName[i];
3230 #else /* DFS_VERSION_2 */
3231 sp[idx++] = 2; /* Version Number */
3232 sp[idx++] = sizeof(struct smb_v2_referral); /* Referral Size */
3233 idx += (sizeof(struct smb_v2_referral) / 2);
3234 v2ref = (struct smb_v2_referral *) &sp[5];
3235 v2ref->ServerType = 1; /* SMB Server */
3236 v2ref->ReferralFlags = 0x03;
3237 v2ref->Proximity = 0; /* closest */
3238 v2ref->TimeToLive = 3600; /* seconds */
3239 v2ref->DfsPathOffset = idx * 2;
3240 v2ref->DfsAlternativePathOffset = idx * 2;
3241 v2ref->NetworkAddressOffset = 0;
3242 for ( i=0;i<=reqLen; i++ )
3243 sp[i+idx] = requestFileName[i];
3246 userp = smb_GetTran2User(vcp, p);
3248 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3249 code = CM_ERROR_BADSMB;
3254 code = CM_ERROR_NOSUCHPATH;
3259 cm_ReleaseUser(userp);
3261 smb_SendTran2Packet(vcp, outp, op);
3263 smb_SendTran2Error(vcp, p, op, code);
3265 smb_FreeTran2Packet(outp);
3268 #else /* DFS_SUPPORT */
3269 osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
3270 return CM_ERROR_BADOP;
3271 #endif /* DFS_SUPPORT */
3275 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3277 /* This is a UNICODE only request (bit15 of Flags2) */
3279 /* There is nothing we can do about this operation. The client is going to
3280 * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3281 * Unfortunately, there is really nothing we can do about it other then log it
3282 * somewhere. Even then I don't think there is anything for us to do.
3283 * So let's return an error value.
3286 osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3287 return CM_ERROR_BADOP;
3291 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3292 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3297 cm_scache_t *targetScp; /* target if scp is a symlink */
3302 unsigned short attr;
3303 unsigned long lattr;
3304 smb_dirListPatch_t *patchp;
3305 smb_dirListPatch_t *npatchp;
3307 for(patchp = *dirPatchespp; patchp; patchp =
3308 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3309 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3311 lock_ObtainMutex(&scp->mx);
3312 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3313 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3315 lock_ReleaseMutex(&scp->mx);
3316 cm_ReleaseSCache(scp);
3318 dptr = patchp->dptr;
3320 /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3321 errors in the client. */
3322 if (infoLevel >= 0x101) {
3323 /* 1969-12-31 23:59:59 +00 */
3324 ft.dwHighDateTime = 0x19DB200;
3325 ft.dwLowDateTime = 0x5BB78980;
3327 /* copy to Creation Time */
3328 *((FILETIME *)dptr) = ft;
3331 /* copy to Last Access Time */
3332 *((FILETIME *)dptr) = ft;
3335 /* copy to Last Write Time */
3336 *((FILETIME *)dptr) = ft;
3339 /* copy to Change Time */
3340 *((FILETIME *)dptr) = ft;
3343 /* merge in hidden attribute */
3344 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3345 *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3349 /* 1969-12-31 23:59:58 +00*/
3350 dosTime = 0xEBBFBF7D;
3352 /* and copy out date */
3353 shortTemp = (dosTime>>16) & 0xffff;
3354 *((u_short *)dptr) = shortTemp;
3357 /* copy out creation time */
3358 shortTemp = dosTime & 0xffff;
3359 *((u_short *)dptr) = shortTemp;
3362 /* and copy out date */
3363 shortTemp = (dosTime>>16) & 0xffff;
3364 *((u_short *)dptr) = shortTemp;
3367 /* copy out access time */
3368 shortTemp = dosTime & 0xffff;
3369 *((u_short *)dptr) = shortTemp;
3372 /* and copy out date */
3373 shortTemp = (dosTime>>16) & 0xffff;
3374 *((u_short *)dptr) = shortTemp;
3377 /* copy out mod time */
3378 shortTemp = dosTime & 0xffff;
3379 *((u_short *)dptr) = shortTemp;
3382 /* merge in hidden (dot file) attribute */
3383 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3384 attr = SMB_ATTR_HIDDEN;
3385 *dptr++ = attr & 0xff;
3386 *dptr++ = (attr >> 8) & 0xff;
3392 /* now watch for a symlink */
3394 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3395 lock_ReleaseMutex(&scp->mx);
3396 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3398 /* we have a more accurate file to use (the
3399 * target of the symbolic link). Otherwise,
3400 * we'll just use the symlink anyway.
3402 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3404 cm_ReleaseSCache(scp);
3407 lock_ObtainMutex(&scp->mx);
3410 dptr = patchp->dptr;
3412 if (infoLevel >= 0x101) {
3414 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3416 /* copy to Creation Time */
3417 *((FILETIME *)dptr) = ft;
3420 /* copy to Last Access Time */
3421 *((FILETIME *)dptr) = ft;
3424 /* copy to Last Write Time */
3425 *((FILETIME *)dptr) = ft;
3428 /* copy to Change Time */
3429 *((FILETIME *)dptr) = ft;
3432 /* Use length for both file length and alloc length */
3433 *((LARGE_INTEGER *)dptr) = scp->length;
3435 *((LARGE_INTEGER *)dptr) = scp->length;
3438 /* Copy attributes */
3439 lattr = smb_ExtAttributes(scp);
3440 if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3441 if (lattr == SMB_ATTR_NORMAL)
3442 lattr = SMB_ATTR_DIRECTORY;
3444 lattr |= SMB_ATTR_DIRECTORY;
3446 /* merge in hidden (dot file) attribute */
3447 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3448 if (lattr == SMB_ATTR_NORMAL)
3449 lattr = SMB_ATTR_HIDDEN;
3451 lattr |= SMB_ATTR_HIDDEN;
3453 *((u_long *)dptr) = lattr;
3457 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3459 /* and copy out date */
3460 shortTemp = (dosTime>>16) & 0xffff;
3461 *((u_short *)dptr) = shortTemp;
3464 /* copy out creation time */
3465 shortTemp = dosTime & 0xffff;
3466 *((u_short *)dptr) = shortTemp;
3469 /* and copy out date */
3470 shortTemp = (dosTime>>16) & 0xffff;
3471 *((u_short *)dptr) = shortTemp;
3474 /* copy out access time */
3475 shortTemp = dosTime & 0xffff;
3476 *((u_short *)dptr) = shortTemp;
3479 /* and copy out date */
3480 shortTemp = (dosTime>>16) & 0xffff;
3481 *((u_short *)dptr) = shortTemp;
3484 /* copy out mod time */
3485 shortTemp = dosTime & 0xffff;
3486 *((u_short *)dptr) = shortTemp;
3489 /* copy out file length and alloc length,
3490 * using the same for both
3492 *((u_long *)dptr) = scp->length.LowPart;
3494 *((u_long *)dptr) = scp->length.LowPart;
3497 /* finally copy out attributes as short */
3498 attr = smb_Attributes(scp);
3499 /* merge in hidden (dot file) attribute */
3500 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3501 if (lattr == SMB_ATTR_NORMAL)
3502 lattr = SMB_ATTR_HIDDEN;
3504 lattr |= SMB_ATTR_HIDDEN;
3506 *dptr++ = attr & 0xff;
3507 *dptr++ = (attr >> 8) & 0xff;
3510 lock_ReleaseMutex(&scp->mx);
3511 cm_ReleaseSCache(scp);
3514 /* now free the patches */
3515 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3516 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3520 /* and mark the list as empty */
3521 *dirPatchespp = NULL;
3526 #ifndef USE_OLD_MATCHING
3527 // char table for case insensitive comparison
3528 char mapCaseTable[256];
3530 VOID initUpperCaseTable(VOID)
3533 for (i = 0; i < 256; ++i)
3534 mapCaseTable[i] = toupper(i);
3535 // make '"' match '.'
3536 mapCaseTable[(int)'"'] = toupper('.');
3537 // make '<' match '*'
3538 mapCaseTable[(int)'<'] = toupper('*');
3539 // make '>' match '?'
3540 mapCaseTable[(int)'>'] = toupper('?');
3543 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3545 // Note : this procedure works recursively calling itself.
3547 // PSZ pattern : string containing metacharacters.
3548 // PSZ name : file name to be compared with 'pattern'.
3550 // BOOL : TRUE/FALSE (match/mistmatch)
3553 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold)
3555 PSZ pename; // points to the last 'name' character
3557 pename = name + strlen(name) - 1;
3567 if (*pattern == '\0')
3569 for (p = pename; p >= name; --p) {
3570 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
3571 !casefold && (*p == *pattern)) &&
3572 szWildCardMatchFileName(pattern + 1, p + 1, casefold))
3577 if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
3578 (!casefold && *name != *pattern))
3585 if (*pattern == '\0' || *pattern == '*' && *(pattern+1) == '\0')
3591 /* do a case-folding search of the star name mask with the name in namep.
3592 * Return 1 if we match, otherwise 0.
3594 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3597 int i, j, star, qmark, casefold, retval;
3599 /* make sure we only match 8.3 names, if requested */
3600 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
3603 casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
3605 /* optimize the pattern:
3606 * if there is a mixture of '?' and '*',
3607 * for example the sequence "*?*?*?*"
3608 * must be turned into the form "*"
3610 newmask = (char *)malloc(strlen(maskp)+1);
3611 for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3612 switch ( maskp[i] ) {
3624 } else if ( qmark ) {
3628 newmask[j++] = maskp[i];
3635 } else if ( qmark ) {
3639 newmask[j++] = '\0';
3641 retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
3647 #else /* USE_OLD_MATCHING */
3648 /* do a case-folding search of the star name mask with the name in namep.
3649 * Return 1 if we match, otherwise 0.
3651 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3653 unsigned char tcp1, tcp2; /* Pattern characters */
3654 unsigned char tcn1; /* Name characters */
3655 int sawDot = 0, sawStar = 0, req8dot3 = 0;
3656 char *starNamep, *starMaskp;
3657 static char nullCharp[] = {0};
3658 int casefold = flags & CM_FLAG_CASEFOLD;
3660 /* make sure we only match 8.3 names, if requested */
3661 req8dot3 = (flags & CM_FLAG_8DOT3);
3662 if (req8dot3 && !cm_Is8Dot3(namep))
3667 /* Next pattern character */
3670 /* Next name character */
3674 /* 0 - end of pattern */
3680 else if (tcp1 == '.' || tcp1 == '"') {
3690 * first dot in pattern;
3691 * must match dot or end of name
3696 else if (tcn1 == '.') {
3705 else if (tcp1 == '?') {
3706 if (tcn1 == 0 || tcn1 == '.')
3711 else if (tcp1 == '>') {
3712 if (tcn1 != 0 && tcn1 != '.')
3716 else if (tcp1 == '*' || tcp1 == '<') {
3720 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3721 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3736 * pattern character after '*' is not null or
3737 * period. If it is '?' or '>', we are not
3738 * going to understand it. If it is '*' or
3739 * '<', we are going to skip over it. None of
3740 * these are likely, I hope.
3742 /* skip over '*' and '<' */
3743 while (tcp2 == '*' || tcp2 == '<')
3746 /* skip over characters that don't match tcp2 */
3747 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
3748 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
3749 (!casefold && tcn1 != tcp2)))
3753 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3756 /* Remember where we are */
3766 /* tcp1 is not a wildcard */
3767 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
3768 (!casefold && tcn1 == tcp1)) {
3773 /* if trying to match a star pattern, go back */
3775 maskp = starMaskp - 2;
3776 namep = starNamep + 1;
3785 #endif /* USE_OLD_MATCHING */
3787 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3792 long code = 0, code2 = 0;
3796 smb_dirListPatch_t *dirListPatchesp;
3797 smb_dirListPatch_t *curPatchp;
3800 long orbytes; /* # of bytes in this output record */
3801 long ohbytes; /* # of bytes, except file name */
3802 long onbytes; /* # of bytes in name, incl. term. null */
3803 osi_hyper_t dirLength;
3804 osi_hyper_t bufferOffset;
3805 osi_hyper_t curOffset;
3807 smb_dirSearch_t *dsp;
3811 cm_pageHeader_t *pageHeaderp;
3812 cm_user_t *userp = NULL;
3815 long nextEntryCookie;
3816 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3817 char *op; /* output data ptr */
3818 char *origOp; /* original value of op */
3819 cm_space_t *spacep; /* for pathname buffer */
3820 long maxReturnData; /* max # of return data */
3821 long maxReturnParms; /* max # of return parms */
3822 long bytesInBuffer; /* # data bytes in the output buffer */
3824 char *maskp; /* mask part of path */
3828 smb_tran2Packet_t *outp; /* response packet */
3831 char shortName[13]; /* 8.3 name if needed */
3842 if (p->opcode == 1) {
3843 /* find first; obtain basic parameters from request */
3844 attribute = p->parmsp[0];
3845 maxCount = p->parmsp[1];
3846 infoLevel = p->parmsp[3];
3847 searchFlags = p->parmsp[2];
3848 dsp = smb_NewDirSearch(1);
3849 dsp->attribute = attribute;
3850 pathp = ((char *) p->parmsp) + 12; /* points to path */
3851 if (smb_StoreAnsiFilenames)
3852 OemToChar(pathp,pathp);
3854 maskp = strrchr(pathp, '\\');
3858 maskp++; /* skip over backslash */
3859 strcpy(dsp->mask, maskp); /* and save mask */
3860 /* track if this is likely to match a lot of entries */
3861 starPattern = smb_V3IsStarMask(maskp);
3864 osi_assert(p->opcode == 2);
3865 /* find next; obtain basic parameters from request or open dir file */
3866 dsp = smb_FindDirSearch(p->parmsp[0]);
3867 maxCount = p->parmsp[1];
3868 infoLevel = p->parmsp[2];
3869 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
3870 searchFlags = p->parmsp[5];
3872 osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
3873 p->parmsp[0], nextCookie);
3874 return CM_ERROR_BADFD;
3876 attribute = dsp->attribute;
3879 starPattern = 1; /* assume, since required a Find Next */
3883 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
3884 attribute, infoLevel, maxCount, searchFlags);
3886 osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
3887 p->opcode, dsp->cookie, nextCookie);
3889 if (infoLevel >= 0x101)
3890 searchFlags &= ~4; /* no resume keys */
3892 dirListPatchesp = NULL;
3894 maxReturnData = p->maxReturnData;
3895 if (p->opcode == 1) /* find first */
3896 maxReturnParms = 10; /* bytes */
3898 maxReturnParms = 8; /* bytes */
3900 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
3901 if (maxReturnData > 6000)
3902 maxReturnData = 6000;
3903 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
3905 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
3908 osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
3909 maxCount, osi_LogSaveString(smb_logp, pathp));
3911 /* bail out if request looks bad */
3912 if (p->opcode == 1 && !pathp) {
3913 smb_ReleaseDirSearch(dsp);
3914 smb_FreeTran2Packet(outp);
3915 return CM_ERROR_BADSMB;
3918 osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
3919 dsp->cookie, nextCookie, attribute);
3921 userp = smb_GetTran2User(vcp, p);
3923 osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
3924 smb_ReleaseDirSearch(dsp);
3925 smb_FreeTran2Packet(outp);
3926 return CM_ERROR_BADSMB;
3929 /* try to get the vnode for the path name next */
3930 lock_ObtainMutex(&dsp->mx);
3936 spacep = cm_GetSpace();
3937 smb_StripLastComponent(spacep->data, NULL, pathp);
3938 code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3940 cm_ReleaseUser(userp);
3941 smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
3942 smb_FreeTran2Packet(outp);
3943 lock_ReleaseMutex(&dsp->mx);
3944 smb_DeleteDirSearch(dsp);
3945 smb_ReleaseDirSearch(dsp);
3948 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3949 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3950 userp, tidPathp, &req, &scp);
3951 cm_FreeSpace(spacep);
3954 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
3955 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3956 cm_ReleaseSCache(scp);
3957 cm_ReleaseUser(userp);
3958 if ( WANTS_DFS_PATHNAMES(p) )
3959 code = CM_ERROR_PATH_NOT_COVERED;
3961 code = CM_ERROR_BADSHARENAME;
3962 smb_SendTran2Error(vcp, p, opx, code);
3963 smb_FreeTran2Packet(outp);
3964 lock_ReleaseMutex(&dsp->mx);
3965 smb_DeleteDirSearch(dsp);
3966 smb_ReleaseDirSearch(dsp);
3969 #endif /* DFS_SUPPORT */
3971 /* we need one hold for the entry we just stored into,
3972 * and one for our own processing. When we're done
3973 * with this function, we'll drop the one for our own
3974 * processing. We held it once from the namei call,
3975 * and so we do another hold now.
3978 lock_ObtainMutex(&scp->mx);
3979 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
3980 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3981 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3982 dsp->flags |= SMB_DIRSEARCH_BULKST;
3984 lock_ReleaseMutex(&scp->mx);
3987 lock_ReleaseMutex(&dsp->mx);
3989 cm_ReleaseUser(userp);
3990 smb_FreeTran2Packet(outp);
3991 smb_DeleteDirSearch(dsp);
3992 smb_ReleaseDirSearch(dsp);
3996 /* get the directory size */
3997 lock_ObtainMutex(&scp->mx);
3998 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3999 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4001 lock_ReleaseMutex(&scp->mx);
4002 cm_ReleaseSCache(scp);
4003 cm_ReleaseUser(userp);
4004 smb_FreeTran2Packet(outp);
4005 smb_DeleteDirSearch(dsp);
4006 smb_ReleaseDirSearch(dsp);
4011 dirLength = scp->length;
4013 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4014 curOffset.HighPart = 0;
4015 curOffset.LowPart = nextCookie;
4016 origOp = outp->datap;
4024 if (searchFlags & 4)
4025 /* skip over resume key */
4028 /* make sure that curOffset.LowPart doesn't point to the first
4029 * 32 bytes in the 2nd through last dir page, and that it doesn't
4030 * point at the first 13 32-byte chunks in the first dir page,
4031 * since those are dir and page headers, and don't contain useful
4034 temp = curOffset.LowPart & (2048-1);
4035 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4036 /* we're in the first page */
4037 if (temp < 13*32) temp = 13*32;
4040 /* we're in a later dir page */
4041 if (temp < 32) temp = 32;
4044 /* make sure the low order 5 bits are zero */
4047 /* now put temp bits back ito curOffset.LowPart */
4048 curOffset.LowPart &= ~(2048-1);
4049 curOffset.LowPart |= temp;
4051 /* check if we've passed the dir's EOF */
4052 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4053 osi_Log0(smb_logp, "T2 search dir passed eof");
4058 /* check if we've returned all the names that will fit in the
4059 * response packet; we check return count as well as the number
4060 * of bytes requested. We check the # of bytes after we find
4061 * the dir entry, since we'll need to check its size.
4063 if (returnedNames >= maxCount) {
4064 osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4065 returnedNames, maxCount);
4069 /* see if we can use the bufferp we have now; compute in which
4070 * page the current offset would be, and check whether that's
4071 * the offset of the buffer we have. If not, get the buffer.
4073 thyper.HighPart = curOffset.HighPart;
4074 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4075 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4078 buf_Release(bufferp);
4081 lock_ReleaseMutex(&scp->mx);
4082 lock_ObtainRead(&scp->bufCreateLock);
4083 code = buf_Get(scp, &thyper, &bufferp);
4084 lock_ReleaseRead(&scp->bufCreateLock);
4085 lock_ObtainMutex(&dsp->mx);
4087 /* now, if we're doing a star match, do bulk fetching
4088 * of all of the status info for files in the dir.
4091 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
4094 lock_ObtainMutex(&scp->mx);
4095 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4096 LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
4097 /* Don't bulk stat if risking timeout */
4098 int now = GetCurrentTime();
4099 if (now - req.startTime > 5000) {
4100 scp->bulkStatProgress = thyper;
4101 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4102 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4104 cm_TryBulkStat(scp, &thyper, userp, &req);
4107 lock_ObtainMutex(&scp->mx);
4109 lock_ReleaseMutex(&dsp->mx);
4111 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
4115 bufferOffset = thyper;
4117 /* now get the data in the cache */
4119 code = cm_SyncOp(scp, bufferp, userp, &req,
4121 CM_SCACHESYNC_NEEDCALLBACK
4122 | CM_SCACHESYNC_READ);
4124 osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
4128 if (cm_HaveBuffer(scp, bufferp, 0)) {
4129 osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4133 /* otherwise, load the buffer and try again */
4134 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4137 osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4138 scp, bufferp, code);
4143 buf_Release(bufferp);
4147 } /* if (wrong buffer) ... */
4149 /* now we have the buffer containing the entry we're interested
4150 * in; copy it out if it represents a non-deleted entry.
4152 entryInDir = curOffset.LowPart & (2048-1);
4153 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4155 /* page header will help tell us which entries are free. Page
4156 * header can change more often than once per buffer, since
4157 * AFS 3 dir page size may be less than (but not more than)
4158 * a buffer package buffer.
4160 /* only look intra-buffer */
4161 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4162 temp &= ~(2048 - 1); /* turn off intra-page bits */
4163 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4165 /* now determine which entry we're looking at in the page.
4166 * If it is free (there's a free bitmap at the start of the
4167 * dir), we should skip these 32 bytes.
4169 slotInPage = (entryInDir & 0x7e0) >> 5;
4170 if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
4171 (1 << (slotInPage & 0x7)))) {
4172 /* this entry is free */
4173 numDirChunks = 1; /* only skip this guy */
4177 tp = bufferp->datap + entryInBuffer;
4178 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4180 /* while we're here, compute the next entry's location, too,
4181 * since we'll need it when writing out the cookie into the dir
4184 * XXXX Probably should do more sanity checking.
4186 numDirChunks = cm_NameEntries(dep->name, &onbytes);
4188 /* compute offset of cookie representing next entry */
4189 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4191 /* Need 8.3 name? */
4193 if (infoLevel == SMB_QUERY_FILE_NAME_INFO
4194 && dep->fid.vnode != 0
4195 && !cm_Is8Dot3(dep->name)) {
4196 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4200 osi_Log3(smb_logp, "T2 search dir vn %u name %s (%s)",
4201 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4202 NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4204 /* When matching, we are using doing a case fold if we have a wildcard mask.
4205 * If we get a non-wildcard match, it's a lookup for a specific file.
4207 if (dep->fid.vnode != 0 &&
4208 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
4210 smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
4212 /* Eliminate entries that don't match requested attributes */
4213 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
4214 smb_IsDotFile(dep->name)) {
4215 osi_Log0(smb_logp, "T2 search dir skipping hidden");
4216 goto nextEntry; /* no hidden files */
4218 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4220 /* We have already done the cm_TryBulkStat above */
4221 fid.cell = scp->fid.cell;
4222 fid.volume = scp->fid.volume;
4223 fid.vnode = ntohl(dep->fid.vnode);
4224 fid.unique = ntohl(dep->fid.unique);
4225 fileType = cm_FindFileType(&fid);
4226 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
4227 "has filetype %d", dep->name,
4229 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4230 fileType == CM_SCACHETYPE_DFSLINK ||
4231 fileType == CM_SCACHETYPE_INVALID)
4232 osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
4236 /* finally check if this name will fit */
4238 /* standard dir entry stuff */
4239 if (infoLevel < 0x101)
4240 ohbytes = 23; /* pre-NT */
4241 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
4242 ohbytes = 12; /* NT names only */
4244 ohbytes = 64; /* NT */
4246 if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
4247 ohbytes += 26; /* Short name & length */
4249 if (searchFlags & 4) {
4250 ohbytes += 4; /* if resume key required */
4254 && infoLevel != 0x101
4255 && infoLevel != 0x103)
4256 ohbytes += 4; /* EASIZE */
4258 /* add header to name & term. null */
4259 orbytes = onbytes + ohbytes + 1;
4261 /* now, we round up the record to a 4 byte alignment,
4262 * and we make sure that we have enough room here for
4263 * even the aligned version (so we don't have to worry
4264 * about an * overflow when we pad things out below).
4265 * That's the reason for the alignment arithmetic below.
4267 if (infoLevel >= 0x101)
4268 align = (4 - (orbytes & 3)) & 3;
4271 if (orbytes + bytesInBuffer + align > maxReturnData) {
4272 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4277 /* this is one of the entries to use: it is not deleted
4278 * and it matches the star pattern we're looking for.
4279 * Put out the name, preceded by its length.
4281 /* First zero everything else */
4282 memset(origOp, 0, ohbytes);
4284 if (infoLevel <= 0x101)
4285 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4286 else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
4287 *((u_long *)(op + 8)) = onbytes;
4289 *((u_long *)(op + 60)) = onbytes;
4290 strcpy(origOp+ohbytes, dep->name);
4291 if (smb_StoreAnsiFilenames)
4292 CharToOem(origOp+ohbytes, origOp+ohbytes);
4294 /* Short name if requested and needed */
4295 if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
4296 if (NeedShortName) {
4297 strcpy(op + 70, shortName);
4298 if (smb_StoreAnsiFilenames)
4299 CharToOem(op + 70, op + 70);
4300 *(op + 68) = shortNameEnd - shortName;
4304 /* now, adjust the # of entries copied */
4307 /* NextEntryOffset and FileIndex */
4308 if (infoLevel >= 101) {
4309 int entryOffset = orbytes + align;
4310 *((u_long *)op) = entryOffset;
4311 *((u_long *)(op+4)) = nextEntryCookie;
4314 /* now we emit the attribute. This is tricky, since
4315 * we need to really stat the file to find out what
4316 * type of entry we've got. Right now, we're copying
4317 * out data from a buffer, while holding the scp
4318 * locked, so it isn't really convenient to stat
4319 * something now. We'll put in a place holder
4320 * now, and make a second pass before returning this
4321 * to get the real attributes. So, we just skip the
4322 * data for now, and adjust it later. We allocate a
4323 * patch record to make it easy to find this point
4324 * later. The replay will happen at a time when it is
4325 * safe to unlock the directory.
4327 if (infoLevel != 0x103) {
4328 curPatchp = malloc(sizeof(*curPatchp));
4329 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4331 curPatchp->dptr = op;
4332 if (infoLevel >= 0x101)
4333 curPatchp->dptr += 8;
4335 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4336 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4339 curPatchp->flags = 0;
4341 curPatchp->fid.cell = scp->fid.cell;
4342 curPatchp->fid.volume = scp->fid.volume;
4343 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4344 curPatchp->fid.unique = ntohl(dep->fid.unique);
4347 curPatchp->dep = dep;
4350 if (searchFlags & 4)
4351 /* put out resume key */
4352 *((u_long *)origOp) = nextEntryCookie;
4354 /* Adjust byte ptr and count */
4355 origOp += orbytes; /* skip entire record */
4356 bytesInBuffer += orbytes;
4358 /* and pad the record out */
4359 while (--align >= 0) {
4363 } /* if we're including this name */
4364 else if (!starPattern &&
4366 dep->fid.vnode != 0 &&
4367 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4368 /* We were looking for exact matches, but here's an inexact one*/
4373 /* and adjust curOffset to be where the new cookie is */
4374 thyper.HighPart = 0;
4375 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4376 curOffset = LargeIntegerAdd(thyper, curOffset);
4377 } /* while copying data for dir listing */
4379 /* If we didn't get a star pattern, we did an exact match during the first pass.
4380 * If there were no exact matches found, we fail over to inexact matches by
4381 * marking the query as a star pattern (matches all case permutations), and
4382 * re-running the query.
4384 if (returnedNames == 0 && !starPattern && foundInexact) {
4385 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4390 /* release the mutex */
4391 lock_ReleaseMutex(&scp->mx);
4393 buf_Release(bufferp);
4395 /* apply and free last set of patches; if not doing a star match, this
4396 * will be empty, but better safe (and freeing everything) than sorry.
4398 code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4401 /* now put out the final parameters */
4402 if (returnedNames == 0)
4404 if (p->opcode == 1) {
4406 outp->parmsp[0] = (unsigned short) dsp->cookie;
4407 outp->parmsp[1] = returnedNames;
4408 outp->parmsp[2] = eos;
4409 outp->parmsp[3] = 0; /* nothing wrong with EAS */
4410 outp->parmsp[4] = 0;
4411 /* don't need last name to continue
4412 * search, cookie is enough. Normally,
4413 * this is the offset of the file name
4414 * of the last entry returned.
4416 outp->totalParms = 10; /* in bytes */
4420 outp->parmsp[0] = returnedNames;
4421 outp->parmsp[1] = eos;
4422 outp->parmsp[2] = 0; /* EAS error */
4423 outp->parmsp[3] = 0; /* last name, as above */
4424 outp->totalParms = 8; /* in bytes */
4427 /* return # of bytes in the buffer */
4428 outp->totalData = bytesInBuffer;
4430 /* Return error code if unsuccessful on first request */
4431 if (code == 0 && p->opcode == 1 && returnedNames == 0)
4432 code = CM_ERROR_NOSUCHFILE;
4434 osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
4435 p->opcode, dsp->cookie, returnedNames, code);
4437 /* if we're supposed to close the search after this request, or if
4438 * we're supposed to close the search if we're done, and we're done,
4439 * or if something went wrong, close the search.
4441 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4442 if ((searchFlags & 1) || (returnedNames == 0) ||
4443 ((searchFlags & 2) && eos) || code != 0)
4444 smb_DeleteDirSearch(dsp);
4446 smb_SendTran2Error(vcp, p, opx, code);
4448 smb_SendTran2Packet(vcp, outp, opx);
4450 smb_FreeTran2Packet(outp);
4451 smb_ReleaseDirSearch(dsp);
4452 cm_ReleaseSCache(scp);
4453 cm_ReleaseUser(userp);
4457 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4460 smb_dirSearch_t *dsp;
4462 dirHandle = smb_GetSMBParm(inp, 0);
4464 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4466 dsp = smb_FindDirSearch(dirHandle);
4469 return CM_ERROR_BADFD;
4471 /* otherwise, we have an FD to destroy */
4472 smb_DeleteDirSearch(dsp);
4473 smb_ReleaseDirSearch(dsp);
4475 /* and return results */
4476 smb_SetSMBDataLength(outp, 0);
4481 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4483 smb_SetSMBDataLength(outp, 0);
4487 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4494 cm_scache_t *dscp; /* dir we're dealing with */
4495 cm_scache_t *scp; /* file we're creating */
4497 int initialModeBits;
4507 int parmSlot; /* which parm we're dealing with */
4515 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4516 openFun = smb_GetSMBParm(inp, 8); /* open function */
4517 excl = ((openFun & 3) == 0);
4518 trunc = ((openFun & 3) == 2); /* truncate it */
4519 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4520 openAction = 0; /* tracks what we did */
4522 attributes = smb_GetSMBParm(inp, 5);
4523 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4525 /* compute initial mode bits based on read-only flag in attributes */
4526 initialModeBits = 0666;
4527 if (attributes & 1) initialModeBits &= ~0222;
4529 pathp = smb_GetSMBData(inp, NULL);
4530 if (smb_StoreAnsiFilenames)
4531 OemToChar(pathp,pathp);
4533 spacep = inp->spacep;
4534 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4536 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4537 /* special case magic file name for receiving IOCTL requests
4538 * (since IOCTL calls themselves aren't getting through).
4541 osi_Log0(smb_logp, "IOCTL Open");
4544 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4545 smb_SetupIoctlFid(fidp, spacep);
4547 /* set inp->fid so that later read calls in same msg can find fid */
4548 inp->fid = fidp->fid;
4550 /* copy out remainder of the parms */
4552 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4554 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4555 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
4556 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4557 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
4558 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4559 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4560 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4561 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4563 /* and the final "always present" stuff */
4564 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4565 /* next write out the "unique" ID */
4566 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4567 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4568 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4569 smb_SetSMBDataLength(outp, 0);
4571 /* and clean up fid reference */
4572 smb_ReleaseFID(fidp);
4576 #ifdef DEBUG_VERBOSE
4578 char *hexp, *asciip;
4579 asciip = (lastNamep ? lastNamep : pathp );
4580 hexp = osi_HexifyString(asciip);
4581 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4585 userp = smb_GetUser(vcp, inp);
4588 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4590 cm_ReleaseUser(userp);
4591 return CM_ERROR_NOSUCHPATH;
4593 code = cm_NameI(cm_data.rootSCachep, pathp,
4594 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4595 userp, tidPathp, &req, &scp);
4598 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4599 cm_ReleaseSCache(scp);
4600 cm_ReleaseUser(userp);
4601 if ( WANTS_DFS_PATHNAMES(inp) )
4602 return CM_ERROR_PATH_NOT_COVERED;
4604 return CM_ERROR_BADSHARENAME;
4606 #endif /* DFS_SUPPORT */
4609 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4610 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4611 userp, tidPathp, &req, &dscp);
4613 cm_ReleaseUser(userp);
4618 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4619 cm_ReleaseSCache(dscp);
4620 cm_ReleaseUser(userp);
4621 if ( WANTS_DFS_PATHNAMES(inp) )
4622 return CM_ERROR_PATH_NOT_COVERED;
4624 return CM_ERROR_BADSHARENAME;
4626 #endif /* DFS_SUPPORT */
4628 /* otherwise, scp points to the parent directory. Do a lookup,
4629 * and truncate the file if we find it, otherwise we create the
4636 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
4638 if (code && code != CM_ERROR_NOSUCHFILE) {
4639 cm_ReleaseSCache(dscp);
4640 cm_ReleaseUser(userp);
4645 /* if we get here, if code is 0, the file exists and is represented by
4646 * scp. Otherwise, we have to create it. The dir may be represented
4647 * by dscp, or we may have found the file directly. If code is non-zero,
4651 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
4653 if (dscp) cm_ReleaseSCache(dscp);
4654 cm_ReleaseSCache(scp);
4655 cm_ReleaseUser(userp);
4660 /* oops, file shouldn't be there */
4662 cm_ReleaseSCache(dscp);
4663 cm_ReleaseSCache(scp);
4664 cm_ReleaseUser(userp);
4665 return CM_ERROR_EXISTS;
4669 setAttr.mask = CM_ATTRMASK_LENGTH;
4670 setAttr.length.LowPart = 0;
4671 setAttr.length.HighPart = 0;
4672 code = cm_SetAttr(scp, &setAttr, userp, &req);
4673 openAction = 3; /* truncated existing file */
4675 else openAction = 1; /* found existing file */
4677 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
4678 /* don't create if not found */
4679 if (dscp) cm_ReleaseSCache(dscp);
4680 cm_ReleaseUser(userp);
4681 return CM_ERROR_NOSUCHFILE;
4684 osi_assert(dscp != NULL);
4685 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
4686 osi_LogSaveString(smb_logp, lastNamep));
4687 openAction = 2; /* created file */
4688 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4689 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
4690 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4692 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4693 smb_NotifyChange(FILE_ACTION_ADDED,
4694 FILE_NOTIFY_CHANGE_FILE_NAME,
4695 dscp, lastNamep, NULL, TRUE);
4696 if (!excl && code == CM_ERROR_EXISTS) {
4697 /* not an exclusive create, and someone else tried
4698 * creating it already, then we open it anyway. We
4699 * don't bother retrying after this, since if this next
4700 * fails, that means that the file was deleted after we
4701 * started this call.
4703 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4707 setAttr.mask = CM_ATTRMASK_LENGTH;
4708 setAttr.length.LowPart = 0;
4709 setAttr.length.HighPart = 0;
4710 code = cm_SetAttr(scp, &setAttr, userp, &req);
4712 } /* lookup succeeded */
4716 /* we don't need this any longer */
4718 cm_ReleaseSCache(dscp);
4721 /* something went wrong creating or truncating the file */
4723 cm_ReleaseSCache(scp);
4724 cm_ReleaseUser(userp);
4728 /* make sure we're about to open a file */
4729 if (scp->fileType != CM_SCACHETYPE_FILE) {
4730 cm_ReleaseSCache(scp);
4731 cm_ReleaseUser(userp);
4732 return CM_ERROR_ISDIR;
4735 /* now all we have to do is open the file itself */
4736 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4739 /* save a pointer to the vnode */
4742 /* compute open mode */
4744 fidp->flags |= SMB_FID_OPENREAD;
4745 if (openMode == 1 || openMode == 2)
4746 fidp->flags |= SMB_FID_OPENWRITE;
4748 smb_ReleaseFID(fidp);
4750 cm_Open(scp, 0, userp);
4752 /* set inp->fid so that later read calls in same msg can find fid */
4753 inp->fid = fidp->fid;
4755 /* copy out remainder of the parms */
4757 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4758 lock_ObtainMutex(&scp->mx);
4760 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
4761 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4762 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
4763 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
4764 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
4765 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
4766 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4767 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4768 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4770 /* and the final "always present" stuff */
4771 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
4772 /* next write out the "unique" ID */
4773 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
4774 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
4775 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4776 lock_ReleaseMutex(&scp->mx);
4777 smb_SetSMBDataLength(outp, 0);
4779 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
4781 cm_ReleaseUser(userp);
4782 /* leave scp held since we put it in fidp->scp */
4786 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4793 unsigned char LockType;
4794 unsigned short NumberOfUnlocks, NumberOfLocks;
4795 unsigned long Timeout;
4797 LARGE_INTEGER LOffset, LLength;
4798 smb_waitingLock_t *waitingLock;
4805 fid = smb_GetSMBParm(inp, 2);
4806 fid = smb_ChainFID(fid, inp);
4808 fidp = smb_FindFID(vcp, fid, 0);
4809 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4810 return CM_ERROR_BADFD;
4812 /* set inp->fid so that later read calls in same msg can find fid */
4815 userp = smb_GetUser(vcp, inp);
4819 lock_ObtainMutex(&scp->mx);
4820 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4821 CM_SCACHESYNC_NEEDCALLBACK
4822 | CM_SCACHESYNC_GETSTATUS
4823 | CM_SCACHESYNC_LOCK);
4827 LockType = smb_GetSMBParm(inp, 3) & 0xff;
4828 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
4829 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
4830 NumberOfLocks = smb_GetSMBParm(inp, 7);
4832 op = smb_GetSMBData(inp, NULL);
4834 for (i=0; i<NumberOfUnlocks; i++) {
4835 if (LockType & LOCKING_ANDX_LARGE_FILES) {
4837 LOffset.HighPart = *((LONG *)(op + 4));
4838 LOffset.LowPart = *((DWORD *)(op + 8));
4839 LLength.HighPart = *((LONG *)(op + 12));
4840 LLength.LowPart = *((DWORD *)(op + 16));
4844 /* Not Large Files */
4845 LOffset.HighPart = 0;
4846 LOffset.LowPart = *((DWORD *)(op + 2));
4847 LLength.HighPart = 0;
4848 LLength.LowPart = *((DWORD *)(op + 6));
4851 if (LargeIntegerNotEqualToZero(LOffset))
4853 /* Do not check length -- length check done in cm_Unlock */
4855 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
4856 if (code) goto done;
4859 for (i=0; i<NumberOfLocks; i++) {
4860 if (LockType & LOCKING_ANDX_LARGE_FILES) {
4862 LOffset.HighPart = *((LONG *)(op + 4));
4863 LOffset.LowPart = *((DWORD *)(op + 8));
4864 LLength.HighPart = *((LONG *)(op + 12));
4865 LLength.LowPart = *((DWORD *)(op + 16));
4869 /* Not Large Files */
4870 LOffset.HighPart = 0;
4871 LOffset.LowPart = *((DWORD *)(op + 2));
4872 LLength.HighPart = 0;
4873 LLength.LowPart = *((DWORD *)(op + 6));
4876 if (LargeIntegerNotEqualToZero(LOffset))
4878 if (LargeIntegerLessThan(LOffset, scp->length))
4881 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
4882 userp, &req, &lockp);
4883 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
4884 /* Put on waiting list */
4885 waitingLock = malloc(sizeof(smb_waitingLock_t));
4886 waitingLock->vcp = vcp;
4888 waitingLock->inp = smb_CopyPacket(inp);
4889 waitingLock->outp = smb_CopyPacket(outp);
4890 waitingLock->timeRemaining = Timeout;
4891 waitingLock->lockp = lockp;
4892 lock_ObtainWrite(&smb_globalLock);
4893 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
4895 osi_Wakeup((long) &smb_allWaitingLocks);
4896 lock_ReleaseWrite(&smb_globalLock);
4897 /* don't send reply immediately */
4898 outp->flags |= SMB_PACKETFLAG_NOSEND;
4905 /* release any locks acquired before the failure */
4908 smb_SetSMBDataLength(outp, 0);
4910 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
4912 lock_ReleaseMutex(&scp->mx);
4913 cm_ReleaseUser(userp);
4914 smb_ReleaseFID(fidp);
4919 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4925 afs_uint32 searchTime;
4931 fid = smb_GetSMBParm(inp, 0);
4932 fid = smb_ChainFID(fid, inp);
4934 fidp = smb_FindFID(vcp, fid, 0);
4935 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4936 return CM_ERROR_BADFD;
4939 userp = smb_GetUser(vcp, inp);
4943 /* otherwise, stat the file */
4944 lock_ObtainMutex(&scp->mx);
4945 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4946 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4947 if (code) goto done;
4949 /* decode times. We need a search time, but the response to this
4950 * call provides the date first, not the time, as returned in the
4951 * searchTime variable. So we take the high-order bits first.
4953 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
4954 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
4955 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
4956 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
4957 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
4958 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
4959 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
4961 /* now handle file size and allocation size */
4962 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
4963 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
4964 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
4965 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
4967 /* file attribute */
4968 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
4970 /* and finalize stuff */
4971 smb_SetSMBDataLength(outp, 0);
4975 lock_ReleaseMutex(&scp->mx);
4976 cm_ReleaseUser(userp);
4977 smb_ReleaseFID(fidp);
4981 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4987 afs_uint32 searchTime;
4995 fid = smb_GetSMBParm(inp, 0);
4996 fid = smb_ChainFID(fid, inp);
4998 fidp = smb_FindFID(vcp, fid, 0);
4999 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5000 return CM_ERROR_BADFD;
5003 userp = smb_GetUser(vcp, inp);
5007 /* now prepare to call cm_setattr. This message only sets various times,
5008 * and AFS only implements mtime, and we'll set the mtime if that's
5009 * requested. The others we'll ignore.
5011 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
5013 if (searchTime != 0) {
5014 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
5016 if ( unixTime != -1 ) {
5017 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
5018 attrs.clientModTime = unixTime;
5019 code = cm_SetAttr(scp, &attrs, userp, &req);
5021 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
5023 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
5028 cm_ReleaseUser(userp);
5029 smb_ReleaseFID(fidp);
5034 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5037 long count, finalCount;
5044 fd = smb_GetSMBParm(inp, 2);
5045 count = smb_GetSMBParm(inp, 5);
5046 offset.HighPart = 0; /* too bad */
5047 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5049 osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
5050 fd, offset.LowPart, count);
5052 fd = smb_ChainFID(fd, inp);
5053 fidp = smb_FindFID(vcp, fd, 0);
5055 return CM_ERROR_BADFD;
5057 /* set inp->fid so that later read calls in same msg can find fid */
5060 if (fidp->flags & SMB_FID_IOCTL) {
5061 return smb_IoctlV3Read(fidp, vcp, inp, outp);
5064 userp = smb_GetUser(vcp, inp);
5066 /* 0 and 1 are reserved for request chaining, were setup by our caller,
5067 * and will be further filled in after we return.
5069 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
5070 smb_SetSMBParm(outp, 3, 0); /* resvd */
5071 smb_SetSMBParm(outp, 4, 0); /* resvd */
5072 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
5073 /* fill in #6 when we have all the parameters' space reserved */
5074 smb_SetSMBParm(outp, 7, 0); /* resv'd */
5075 smb_SetSMBParm(outp, 8, 0); /* resv'd */
5076 smb_SetSMBParm(outp, 9, 0); /* resv'd */
5077 smb_SetSMBParm(outp, 10, 0); /* resv'd */
5078 smb_SetSMBParm(outp, 11, 0); /* reserved */
5080 /* get op ptr after putting in the parms, since otherwise we don't
5081 * know where the data really is.
5083 op = smb_GetSMBData(outp, NULL);
5085 /* now fill in offset from start of SMB header to first data byte (to op) */
5086 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
5088 /* set the packet data length the count of the # of bytes */
5089 smb_SetSMBDataLength(outp, count);
5092 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5094 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5097 /* fix some things up */
5098 smb_SetSMBParm(outp, 5, finalCount);
5099 smb_SetSMBDataLength(outp, finalCount);
5101 smb_ReleaseFID(fidp);
5103 cm_ReleaseUser(userp);
5108 * Values for createDisp, copied from NTDDK.H
5110 #define FILE_SUPERSEDE 0 // (???)
5111 #define FILE_OPEN 1 // (open)
5112 #define FILE_CREATE 2 // (exclusive)
5113 #define FILE_OPEN_IF 3 // (non-exclusive)
5114 #define FILE_OVERWRITE 4 // (open & truncate, but do not create)
5115 #define FILE_OVERWRITE_IF 5 // (open & truncate, or create)
5118 #define REQUEST_OPLOCK 2
5119 #define REQUEST_BATCH_OPLOCK 4
5120 #define OPEN_DIRECTORY 8
5121 #define EXTENDED_RESPONSE_REQUIRED 0x10
5123 /* CreateOptions field. */
5124 #define FILE_DIRECTORY_FILE 0x0001
5125 #define FILE_WRITE_THROUGH 0x0002
5126 #define FILE_SEQUENTIAL_ONLY 0x0004
5127 #define FILE_NON_DIRECTORY_FILE 0x0040
5128 #define FILE_NO_EA_KNOWLEDGE 0x0200
5129 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
5130 #define FILE_RANDOM_ACCESS 0x0800
5131 #define FILE_DELETE_ON_CLOSE 0x1000
5132 #define FILE_OPEN_BY_FILE_ID 0x2000
5134 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5136 char *pathp, *realPathp;
5140 cm_scache_t *dscp; /* parent dir */
5141 cm_scache_t *scp; /* file to create or open */
5142 cm_scache_t *targetScp; /* if scp is a symlink */
5146 unsigned short nameLength;
5148 unsigned int requestOpLock;
5149 unsigned int requestBatchOpLock;
5150 unsigned int mustBeDir;
5151 unsigned int extendedRespRequired;
5152 unsigned int treeCreate;
5154 unsigned int desiredAccess;
5155 unsigned int extAttributes;
5156 unsigned int createDisp;
5157 unsigned int createOptions;
5158 int initialModeBits;
5159 unsigned short baseFid;
5160 smb_fid_t *baseFidp;
5162 cm_scache_t *baseDirp;
5163 unsigned short openAction;
5174 /* This code is very long and has a lot of if-then-else clauses
5175 * scp and dscp get reused frequently and we need to ensure that
5176 * we don't lose a reference. Start by ensuring that they are NULL.
5183 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
5184 flags = smb_GetSMBOffsetParm(inp, 3, 1)
5185 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
5186 requestOpLock = flags & REQUEST_OPLOCK;
5187 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
5188 mustBeDir = flags & OPEN_DIRECTORY;
5189 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
5192 * Why all of a sudden 32-bit FID?
5193 * We will reject all bits higher than 16.
5195 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
5196 return CM_ERROR_INVAL;
5197 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
5198 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
5199 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
5200 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
5201 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
5202 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
5203 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
5204 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
5205 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
5207 /* mustBeDir is never set; createOptions directory bit seems to be
5210 if (createOptions & FILE_DIRECTORY_FILE)
5212 else if (createOptions & FILE_NON_DIRECTORY_FILE)
5218 * compute initial mode bits based on read-only flag in
5219 * extended attributes
5221 initialModeBits = 0666;
5222 if (extAttributes & 1)
5223 initialModeBits &= ~0222;
5225 pathp = smb_GetSMBData(inp, NULL);
5226 /* Sometimes path is not null-terminated, so we make a copy. */
5227 realPathp = malloc(nameLength+1);
5228 memcpy(realPathp, pathp, nameLength);
5229 realPathp[nameLength] = 0;
5230 if (smb_StoreAnsiFilenames)
5231 OemToChar(realPathp,realPathp);
5233 spacep = inp->spacep;
5234 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5236 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
5237 osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
5238 osi_Log2(smb_logp,"... flags=[%x] lastNamep=[%s]", flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
5240 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5241 /* special case magic file name for receiving IOCTL requests
5242 * (since IOCTL calls themselves aren't getting through).
5244 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5245 smb_SetupIoctlFid(fidp, spacep);
5246 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
5248 /* set inp->fid so that later read calls in same msg can find fid */
5249 inp->fid = fidp->fid;
5253 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5254 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5255 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
5257 memset(&ft, 0, sizeof(ft));
5258 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5259 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5260 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5261 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5262 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
5263 sz.HighPart = 0x7fff; sz.LowPart = 0;
5264 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
5265 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
5266 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
5267 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
5268 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
5269 smb_SetSMBDataLength(outp, 0);
5271 /* clean up fid reference */
5272 smb_ReleaseFID(fidp);
5277 #ifdef DEBUG_VERBOSE
5279 char *hexp, *asciip;
5280 asciip = (lastNamep? lastNamep : realPathp);
5281 hexp = osi_HexifyString( asciip );
5282 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
5286 userp = smb_GetUser(vcp, inp);
5288 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
5290 return CM_ERROR_INVAL;
5294 baseDirp = cm_data.rootSCachep;
5295 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5296 if (code == CM_ERROR_TIDIPC) {
5297 /* Attempt to use a TID allocated for IPC. The client
5298 * is probably looking for DCE RPC end points which we
5299 * don't support OR it could be looking to make a DFS
5302 osi_Log0(smb_logp, "NTCreateX received IPC TID");
5305 cm_ReleaseUser(userp);
5306 return CM_ERROR_NOSUCHFILE;
5307 #endif /* DFS_SUPPORT */
5310 baseFidp = smb_FindFID(vcp, baseFid, 0);
5312 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
5314 cm_ReleaseUser(userp);
5315 return CM_ERROR_INVAL;
5317 baseDirp = baseFidp->scp;
5321 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
5323 /* compute open mode */
5325 if (desiredAccess & DELETE)
5326 fidflags |= SMB_FID_OPENDELETE;
5327 if (desiredAccess & AFS_ACCESS_READ)
5328 fidflags |= SMB_FID_OPENREAD;
5329 if (desiredAccess & AFS_ACCESS_WRITE)
5330 fidflags |= SMB_FID_OPENWRITE;
5331 if (createOptions & FILE_DELETE_ON_CLOSE)
5332 fidflags |= SMB_FID_DELONCLOSE;
5336 /* For an exclusive create, we want to do a case sensitive match for the last component. */
5337 if ( createDisp == FILE_CREATE ||
5338 createDisp == FILE_OVERWRITE ||
5339 createDisp == FILE_OVERWRITE_IF) {
5340 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5341 userp, tidPathp, &req, &dscp);
5344 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5345 cm_ReleaseSCache(dscp);
5346 cm_ReleaseUser(userp);
5348 if ( WANTS_DFS_PATHNAMES(inp) )
5349 return CM_ERROR_PATH_NOT_COVERED;
5351 return CM_ERROR_BADSHARENAME;
5353 #endif /* DFS_SUPPORT */
5354 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5356 if (code == CM_ERROR_NOSUCHFILE) {
5357 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
5358 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
5359 if (code == 0 && realDirFlag == 1) {
5360 cm_ReleaseSCache(scp);
5361 cm_ReleaseSCache(dscp);
5362 cm_ReleaseUser(userp);
5364 return CM_ERROR_EXISTS;
5368 /* we have both scp and dscp */
5370 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5371 userp, tidPathp, &req, &scp);
5373 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5374 cm_ReleaseSCache(scp);
5375 cm_ReleaseUser(userp);
5377 if ( WANTS_DFS_PATHNAMES(inp) )
5378 return CM_ERROR_PATH_NOT_COVERED;
5380 return CM_ERROR_BADSHARENAME;
5382 #endif /* DFS_SUPPORT */
5383 /* we might have scp but not dscp */
5389 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
5390 /* look up parent directory */
5391 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
5392 * the immediate parent. We have to work our way up realPathp until we hit something that we
5396 /* we might or might not have scp */
5402 code = cm_NameI(baseDirp, spacep->data,
5403 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5404 userp, tidPathp, &req, &dscp);
5407 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5409 cm_ReleaseSCache(scp);
5410 cm_ReleaseSCache(dscp);
5411 cm_ReleaseUser(userp);
5413 if ( WANTS_DFS_PATHNAMES(inp) )
5414 return CM_ERROR_PATH_NOT_COVERED;
5416 return CM_ERROR_BADSHARENAME;
5418 #endif /* DFS_SUPPORT */
5421 (tp = strrchr(spacep->data,'\\')) &&
5422 (createDisp == FILE_CREATE) &&
5423 (realDirFlag == 1)) {
5426 treeStartp = realPathp + (tp - spacep->data);
5428 if (*tp && !smb_IsLegalFilename(tp)) {
5430 smb_ReleaseFID(baseFidp);
5431 cm_ReleaseUser(userp);
5434 cm_ReleaseSCache(scp);
5435 return CM_ERROR_BADNTFILENAME;
5439 } while (dscp == NULL && code == 0);
5443 /* we might have scp and we might have dscp */
5446 smb_ReleaseFID(baseFidp);
5449 osi_Log0(smb_logp,"NTCreateX parent not found");
5451 cm_ReleaseSCache(scp);
5453 cm_ReleaseSCache(dscp);
5454 cm_ReleaseUser(userp);
5459 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
5460 /* A file exists where we want a directory. */
5462 cm_ReleaseSCache(scp);
5463 cm_ReleaseSCache(dscp);
5464 cm_ReleaseUser(userp);
5466 return CM_ERROR_EXISTS;
5470 lastNamep = realPathp;
5474 if (!smb_IsLegalFilename(lastNamep)) {
5476 cm_ReleaseSCache(scp);
5478 cm_ReleaseSCache(dscp);
5479 cm_ReleaseUser(userp);
5481 return CM_ERROR_BADNTFILENAME;
5484 if (!foundscp && !treeCreate) {
5485 if ( createDisp == FILE_CREATE ||
5486 createDisp == FILE_OVERWRITE ||
5487 createDisp == FILE_OVERWRITE_IF)
5489 code = cm_Lookup(dscp, lastNamep,
5490 CM_FLAG_FOLLOW, userp, &req, &scp);
5492 code = cm_Lookup(dscp, lastNamep,
5493 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5496 if (code && code != CM_ERROR_NOSUCHFILE) {
5498 cm_ReleaseSCache(dscp);
5499 cm_ReleaseUser(userp);
5504 /* we have scp and dscp */
5506 /* we have scp but not dscp */
5508 smb_ReleaseFID(baseFidp);
5511 /* if we get here, if code is 0, the file exists and is represented by
5512 * scp. Otherwise, we have to create it. The dir may be represented
5513 * by dscp, or we may have found the file directly. If code is non-zero,
5516 if (code == 0 && !treeCreate) {
5517 if (createDisp == FILE_CREATE) {
5518 /* oops, file shouldn't be there */
5520 cm_ReleaseSCache(dscp);
5522 cm_ReleaseSCache(scp);
5523 cm_ReleaseUser(userp);
5525 return CM_ERROR_EXISTS;
5528 if ( createDisp == FILE_OVERWRITE ||
5529 createDisp == FILE_OVERWRITE_IF) {
5530 setAttr.mask = CM_ATTRMASK_LENGTH;
5531 setAttr.length.LowPart = 0;
5532 setAttr.length.HighPart = 0;
5533 /* now watch for a symlink */
5535 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5537 osi_assert(dscp != NULL);
5538 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5540 /* we have a more accurate file to use (the
5541 * target of the symbolic link). Otherwise,
5542 * we'll just use the symlink anyway.
5544 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5546 cm_ReleaseSCache(scp);
5550 code = cm_SetAttr(scp, &setAttr, userp, &req);
5551 openAction = 3; /* truncated existing file */
5554 openAction = 1; /* found existing file */
5556 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req);
5559 cm_ReleaseSCache(dscp);
5561 cm_ReleaseSCache(scp);
5562 cm_ReleaseUser(userp);
5566 } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
5567 /* don't create if not found */
5569 cm_ReleaseSCache(dscp);
5571 cm_ReleaseSCache(scp);
5572 cm_ReleaseUser(userp);
5574 return CM_ERROR_NOSUCHFILE;
5575 } else if (realDirFlag == 0 || realDirFlag == -1) {
5576 osi_assert(dscp != NULL);
5577 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
5578 osi_LogSaveString(smb_logp, lastNamep));
5579 openAction = 2; /* created file */
5580 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5581 setAttr.clientModTime = time(NULL);
5582 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
5583 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5584 smb_NotifyChange(FILE_ACTION_ADDED,
5585 FILE_NOTIFY_CHANGE_FILE_NAME,
5586 dscp, lastNamep, NULL, TRUE);
5587 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
5588 /* Not an exclusive create, and someone else tried
5589 * creating it already, then we open it anyway. We
5590 * don't bother retrying after this, since if this next
5591 * fails, that means that the file was deleted after we
5592 * started this call.
5594 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5597 if (createDisp == FILE_OVERWRITE_IF) {
5598 setAttr.mask = CM_ATTRMASK_LENGTH;
5599 setAttr.length.LowPart = 0;
5600 setAttr.length.HighPart = 0;
5602 /* now watch for a symlink */
5604 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5606 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5608 /* we have a more accurate file to use (the
5609 * target of the symbolic link). Otherwise,
5610 * we'll just use the symlink anyway.
5612 osi_Log2(smb_logp, "symlink vp %x to vp %x",
5614 cm_ReleaseSCache(scp);
5618 code = cm_SetAttr(scp, &setAttr, userp, &req);
5620 } /* lookup succeeded */
5624 char *cp; /* This component */
5625 int clen = 0; /* length of component */
5626 cm_scache_t *tscp1, *tscp2;
5629 /* create directory */
5631 treeStartp = lastNamep;
5632 osi_assert(dscp != NULL);
5633 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
5634 osi_LogSaveString(smb_logp, treeStartp));
5635 openAction = 2; /* created directory */
5637 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5638 setAttr.clientModTime = time(NULL);
5643 cm_HoldSCache(tscp1);
5647 tp = strchr(pp, '\\');
5651 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
5654 strncpy(cp,pp,clen);
5661 continue; /* the supplied path can't have consecutive slashes either , but */
5663 /* cp is the next component to be created. */
5664 code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
5665 if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
5666 smb_NotifyChange(FILE_ACTION_ADDED,
5667 FILE_NOTIFY_CHANGE_DIR_NAME,
5668 tscp1, cp, NULL, TRUE);
5670 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
5671 /* Not an exclusive create, and someone else tried
5672 * creating it already, then we open it anyway. We
5673 * don't bother retrying after this, since if this next
5674 * fails, that means that the file was deleted after we
5675 * started this call.
5677 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
5678 userp, &req, &tscp2);
5683 if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
5684 cm_ReleaseSCache(tscp1);
5685 tscp1 = tscp2; /* Newly created directory will be next parent */
5686 /* the hold is transfered to tscp1 from tscp2 */
5691 cm_ReleaseSCache(dscp);
5694 cm_ReleaseSCache(scp);
5697 * if we get here and code == 0, then scp is the last directory created, and dscp is the
5703 /* something went wrong creating or truncating the file */
5705 cm_ReleaseSCache(scp);
5707 cm_ReleaseSCache(dscp);
5708 cm_ReleaseUser(userp);
5713 /* make sure we have file vs. dir right (only applies for single component case) */
5714 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5715 /* now watch for a symlink */
5717 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5718 cm_scache_t * targetScp = 0;
5719 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5721 /* we have a more accurate file to use (the
5722 * target of the symbolic link). Otherwise,
5723 * we'll just use the symlink anyway.
5725 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
5726 cm_ReleaseSCache(scp);
5731 if (scp->fileType != CM_SCACHETYPE_FILE) {
5733 cm_ReleaseSCache(dscp);
5734 cm_ReleaseSCache(scp);
5735 cm_ReleaseUser(userp);
5737 return CM_ERROR_ISDIR;
5741 /* (only applies to single component case) */
5742 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5743 cm_ReleaseSCache(scp);
5745 cm_ReleaseSCache(dscp);
5746 cm_ReleaseUser(userp);
5748 return CM_ERROR_NOTDIR;
5751 /* open the file itself */
5752 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5754 /* save a pointer to the vnode */
5755 fidp->scp = scp; /* Hold transfered to fidp->scp and no longer needed */
5757 fidp->flags = fidflags;
5759 /* save parent dir and pathname for delete or change notification */
5760 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5761 fidp->flags |= SMB_FID_NTOPEN;
5762 fidp->NTopen_dscp = dscp;
5763 cm_HoldSCache(dscp);
5764 fidp->NTopen_pathp = strdup(lastNamep);
5766 fidp->NTopen_wholepathp = realPathp;
5768 /* we don't need this any longer */
5770 cm_ReleaseSCache(dscp);
5773 cm_Open(scp, 0, userp);
5775 /* set inp->fid so that later read calls in same msg can find fid */
5776 inp->fid = fidp->fid;
5780 lock_ObtainMutex(&scp->mx);
5781 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
5782 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5783 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
5784 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5785 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5786 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5787 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5788 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5789 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
5791 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5792 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5793 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
5794 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
5795 smb_SetSMBParmByte(outp, parmSlot,
5796 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
5797 lock_ReleaseMutex(&scp->mx);
5798 smb_SetSMBDataLength(outp, 0);
5800 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
5801 osi_LogSaveString(smb_logp, realPathp));
5803 smb_ReleaseFID(fidp);
5805 cm_ReleaseUser(userp);
5807 /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
5809 /* leave scp held since we put it in fidp->scp */
5814 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
5815 * Instead, ultimately, would like to use a subroutine for common code.
5817 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5819 char *pathp, *realPathp;
5823 cm_scache_t *dscp; /* parent dir */
5824 cm_scache_t *scp; /* file to create or open */
5825 cm_scache_t *targetScp; /* if scp is a symlink */
5828 unsigned long nameLength;
5830 unsigned int requestOpLock;
5831 unsigned int requestBatchOpLock;
5832 unsigned int mustBeDir;
5833 unsigned int extendedRespRequired;
5835 unsigned int desiredAccess;
5836 #ifdef DEBUG_VERBOSE
5837 unsigned int allocSize;
5838 unsigned int shareAccess;
5840 unsigned int extAttributes;
5841 unsigned int createDisp;
5842 #ifdef DEBUG_VERBOSE
5845 unsigned int createOptions;
5846 int initialModeBits;
5847 unsigned short baseFid;
5848 smb_fid_t *baseFidp;
5850 cm_scache_t *baseDirp;
5851 unsigned short openAction;
5857 int parmOffset, dataOffset;
5868 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
5869 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
5870 parmp = inp->data + parmOffset;
5871 lparmp = (ULONG *) parmp;
5874 requestOpLock = flags & REQUEST_OPLOCK;
5875 requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
5876 mustBeDir = flags & OPEN_DIRECTORY;
5877 extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
5880 * Why all of a sudden 32-bit FID?
5881 * We will reject all bits higher than 16.
5883 if (lparmp[1] & 0xFFFF0000)
5884 return CM_ERROR_INVAL;
5885 baseFid = (unsigned short)lparmp[1];
5886 desiredAccess = lparmp[2];
5887 #ifdef DEBUG_VERBOSE
5888 allocSize = lparmp[3];
5889 #endif /* DEBUG_VERSOSE */
5890 extAttributes = lparmp[5];
5892 shareAccess = lparmp[6];
5894 createDisp = lparmp[7];
5895 createOptions = lparmp[8];
5896 #ifdef DEBUG_VERBOSE
5899 nameLength = lparmp[11];
5901 #ifdef DEBUG_VERBOSE
5902 osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
5903 osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
5904 osi_Log1(smb_logp,"... flags[%x]",flags);
5907 /* mustBeDir is never set; createOptions directory bit seems to be
5910 if (createOptions & FILE_DIRECTORY_FILE)
5912 else if (createOptions & FILE_NON_DIRECTORY_FILE)
5918 * compute initial mode bits based on read-only flag in
5919 * extended attributes
5921 initialModeBits = 0666;
5922 if (extAttributes & 1)
5923 initialModeBits &= ~0222;
5925 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
5926 /* Sometimes path is not null-terminated, so we make a copy. */
5927 realPathp = malloc(nameLength+1);
5928 memcpy(realPathp, pathp, nameLength);
5929 realPathp[nameLength] = 0;
5930 if (smb_StoreAnsiFilenames)
5931 OemToChar(realPathp,realPathp);
5933 spacep = cm_GetSpace();
5934 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5937 * Nothing here to handle SMB_IOCTL_FILENAME.
5938 * Will add it if necessary.
5941 #ifdef DEBUG_VERBOSE
5943 char *hexp, *asciip;
5944 asciip = (lastNamep? lastNamep : realPathp);
5945 hexp = osi_HexifyString( asciip );
5946 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
5951 userp = smb_GetUser(vcp, inp);
5953 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
5955 return CM_ERROR_INVAL;
5959 baseDirp = cm_data.rootSCachep;
5960 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5961 if (code == CM_ERROR_TIDIPC) {
5962 /* Attempt to use a TID allocated for IPC. The client
5963 * is probably looking for DCE RPC end points which we
5964 * don't support OR it could be looking to make a DFS
5967 osi_Log0(smb_logp, "NTTranCreate received IPC TID");
5970 cm_ReleaseUser(userp);
5971 return CM_ERROR_NOSUCHPATH;
5975 baseFidp = smb_FindFID(vcp, baseFid, 0);
5977 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
5979 cm_ReleaseUser(userp);
5980 return CM_ERROR_INVAL;
5982 baseDirp = baseFidp->scp;
5986 /* compute open mode */
5988 if (desiredAccess & DELETE)
5989 fidflags |= SMB_FID_OPENDELETE;
5990 if (desiredAccess & AFS_ACCESS_READ)
5991 fidflags |= SMB_FID_OPENREAD;
5992 if (desiredAccess & AFS_ACCESS_WRITE)
5993 fidflags |= SMB_FID_OPENWRITE;
5994 if (createOptions & FILE_DELETE_ON_CLOSE)
5995 fidflags |= SMB_FID_DELONCLOSE;
5999 if ( createDisp == FILE_OPEN ||
6000 createDisp == FILE_OVERWRITE ||
6001 createDisp == FILE_OVERWRITE_IF) {
6002 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6003 userp, tidPathp, &req, &dscp);
6006 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6007 cm_ReleaseSCache(dscp);
6008 cm_ReleaseUser(userp);
6010 if ( WANTS_DFS_PATHNAMES(inp) )
6011 return CM_ERROR_PATH_NOT_COVERED;
6013 return CM_ERROR_BADSHARENAME;
6015 #endif /* DFS_SUPPORT */
6016 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6018 if (code == CM_ERROR_NOSUCHFILE) {
6019 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
6020 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6021 if (code == 0 && realDirFlag == 1) {
6022 cm_ReleaseSCache(scp);
6023 cm_ReleaseSCache(dscp);
6024 cm_ReleaseUser(userp);
6026 return CM_ERROR_EXISTS;
6032 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6033 userp, tidPathp, &req, &scp);
6035 if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6036 cm_ReleaseSCache(scp);
6037 cm_ReleaseUser(userp);
6039 if ( WANTS_DFS_PATHNAMES(inp) )
6040 return CM_ERROR_PATH_NOT_COVERED;
6042 return CM_ERROR_BADSHARENAME;
6044 #endif /* DFS_SUPPORT */
6050 if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6051 /* look up parent directory */
6053 code = cm_NameI(baseDirp, spacep->data,
6054 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6055 userp, tidPathp, &req, &dscp);
6057 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6058 cm_ReleaseSCache(dscp);
6059 cm_ReleaseUser(userp);
6061 if ( WANTS_DFS_PATHNAMES(inp) )
6062 return CM_ERROR_PATH_NOT_COVERED;
6064 return CM_ERROR_BADSHARENAME;
6066 #endif /* DFS_SUPPORT */
6070 cm_FreeSpace(spacep);
6073 smb_ReleaseFID(baseFidp);
6078 cm_ReleaseUser(userp);
6083 if (!lastNamep) lastNamep = realPathp;
6086 if (!smb_IsLegalFilename(lastNamep))
6087 return CM_ERROR_BADNTFILENAME;
6090 if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
6091 code = cm_Lookup(dscp, lastNamep,
6092 CM_FLAG_FOLLOW, userp, &req, &scp);
6094 code = cm_Lookup(dscp, lastNamep,
6095 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6098 if (code && code != CM_ERROR_NOSUCHFILE) {
6099 cm_ReleaseSCache(dscp);
6100 cm_ReleaseUser(userp);
6107 smb_ReleaseFID(baseFidp);
6110 cm_FreeSpace(spacep);
6113 /* if we get here, if code is 0, the file exists and is represented by
6114 * scp. Otherwise, we have to create it. The dir may be represented
6115 * by dscp, or we may have found the file directly. If code is non-zero,
6119 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
6123 cm_ReleaseSCache(dscp);
6124 cm_ReleaseSCache(scp);
6125 cm_ReleaseUser(userp);
6130 if (createDisp == FILE_CREATE) {
6131 /* oops, file shouldn't be there */
6133 cm_ReleaseSCache(dscp);
6134 cm_ReleaseSCache(scp);
6135 cm_ReleaseUser(userp);
6137 return CM_ERROR_EXISTS;
6140 if (createDisp == FILE_OVERWRITE ||
6141 createDisp == FILE_OVERWRITE_IF) {
6142 setAttr.mask = CM_ATTRMASK_LENGTH;
6143 setAttr.length.LowPart = 0;
6144 setAttr.length.HighPart = 0;
6146 /* now watch for a symlink */
6148 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6150 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6152 /* we have a more accurate file to use (the
6153 * target of the symbolic link). Otherwise,
6154 * we'll just use the symlink anyway.
6156 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6158 cm_ReleaseSCache(scp);
6162 code = cm_SetAttr(scp, &setAttr, userp, &req);
6163 openAction = 3; /* truncated existing file */
6165 else openAction = 1; /* found existing file */
6167 else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6168 /* don't create if not found */
6170 cm_ReleaseSCache(dscp);
6171 cm_ReleaseUser(userp);
6173 return CM_ERROR_NOSUCHFILE;
6175 else if (realDirFlag == 0 || realDirFlag == -1) {
6176 osi_assert(dscp != NULL);
6177 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
6178 osi_LogSaveString(smb_logp, lastNamep));
6179 openAction = 2; /* created file */
6180 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6181 setAttr.clientModTime = time(NULL);
6182 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6184 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6185 smb_NotifyChange(FILE_ACTION_ADDED,
6186 FILE_NOTIFY_CHANGE_FILE_NAME,
6187 dscp, lastNamep, NULL, TRUE);
6188 if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6189 /* Not an exclusive create, and someone else tried
6190 * creating it already, then we open it anyway. We
6191 * don't bother retrying after this, since if this next
6192 * fails, that means that the file was deleted after we
6193 * started this call.
6195 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6198 if (createDisp == FILE_OVERWRITE_IF) {
6199 setAttr.mask = CM_ATTRMASK_LENGTH;
6200 setAttr.length.LowPart = 0;
6201 setAttr.length.HighPart = 0;
6203 /* now watch for a symlink */
6205 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6207 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6209 /* we have a more accurate file to use (the
6210 * target of the symbolic link). Otherwise,
6211 * we'll just use the symlink anyway.
6213 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6215 cm_ReleaseSCache(scp);
6219 code = cm_SetAttr(scp, &setAttr, userp, &req);
6221 } /* lookup succeeded */
6224 /* create directory */
6225 osi_assert(dscp != NULL);
6227 "smb_ReceiveNTTranCreate creating directory %s",
6228 osi_LogSaveString(smb_logp, lastNamep));
6229 openAction = 2; /* created directory */
6230 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6231 setAttr.clientModTime = time(NULL);
6232 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6233 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6234 smb_NotifyChange(FILE_ACTION_ADDED,
6235 FILE_NOTIFY_CHANGE_DIR_NAME,
6236 dscp, lastNamep, NULL, TRUE);
6238 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6239 /* Not an exclusive create, and someone else tried
6240 * creating it already, then we open it anyway. We
6241 * don't bother retrying after this, since if this next
6242 * fails, that means that the file was deleted after we
6243 * started this call.
6245 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6251 /* something went wrong creating or truncating the file */
6253 cm_ReleaseSCache(scp);
6254 cm_ReleaseUser(userp);
6259 /* make sure we have file vs. dir right */
6260 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
6261 /* now watch for a symlink */
6263 while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6265 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6267 /* we have a more accurate file to use (the
6268 * target of the symbolic link). Otherwise,
6269 * we'll just use the symlink anyway.
6271 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6273 cm_ReleaseSCache(scp);
6278 if (scp->fileType != CM_SCACHETYPE_FILE) {
6279 cm_ReleaseSCache(scp);
6280 cm_ReleaseUser(userp);
6282 return CM_ERROR_ISDIR;
6286 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
6287 cm_ReleaseSCache(scp);
6288 cm_ReleaseUser(userp);
6290 return CM_ERROR_NOTDIR;
6293 /* open the file itself */
6294 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6297 /* save a pointer to the vnode */
6300 fidp->flags = fidflags;
6302 /* save parent dir and pathname for deletion or change notification */
6303 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
6304 fidp->flags |= SMB_FID_NTOPEN;
6305 fidp->NTopen_dscp = dscp;
6306 cm_HoldSCache(dscp);
6307 fidp->NTopen_pathp = strdup(lastNamep);
6309 fidp->NTopen_wholepathp = realPathp;
6311 /* we don't need this any longer */
6313 cm_ReleaseSCache(dscp);
6315 cm_Open(scp, 0, userp);
6317 /* set inp->fid so that later read calls in same msg can find fid */
6318 inp->fid = fidp->fid;
6320 /* check whether we are required to send an extended response */
6321 if (!extendedRespRequired) {
6323 parmOffset = 8*4 + 39;
6324 parmOffset += 1; /* pad to 4 */
6325 dataOffset = parmOffset + 70;
6329 /* Total Parameter Count */
6330 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
6331 /* Total Data Count */
6332 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6333 /* Parameter Count */
6334 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
6335 /* Parameter Offset */
6336 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6337 /* Parameter Displacement */
6338 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6340 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6342 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6343 /* Data Displacement */
6344 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6345 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6346 smb_SetSMBDataLength(outp, 70);
6348 lock_ObtainMutex(&scp->mx);
6349 outData = smb_GetSMBData(outp, NULL);
6350 outData++; /* round to get to parmOffset */
6351 *outData = 0; outData++; /* oplock */
6352 *outData = 0; outData++; /* reserved */
6353 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
6354 *((ULONG *)outData) = openAction; outData += 4;
6355 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
6356 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6357 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
6358 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
6359 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
6360 *((FILETIME *)outData) = ft; outData += 8; /* change time */
6361 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
6362 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
6363 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
6364 *((USHORT *)outData) = 0; outData += 2; /* filetype */
6365 *((USHORT *)outData) = 0; outData += 2; /* dev state */
6366 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
6367 outData += 2; /* is a dir? */
6368 lock_ReleaseMutex(&scp->mx);
6371 parmOffset = 8*4 + 39;
6372 parmOffset += 1; /* pad to 4 */
6373 dataOffset = parmOffset + 104;
6377 /* Total Parameter Count */
6378 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
6379 /* Total Data Count */
6380 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6381 /* Parameter Count */
6382 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
6383 /* Parameter Offset */
6384 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6385 /* Parameter Displacement */
6386 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6388 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6390 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6391 /* Data Displacement */
6392 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6393 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6394 smb_SetSMBDataLength(outp, 105);
6396 lock_ObtainMutex(&scp->mx);
6397 outData = smb_GetSMBData(outp, NULL);
6398 outData++; /* round to get to parmOffset */
6399 *outData = 0; outData++; /* oplock */
6400 *outData = 1; outData++; /* response type */
6401 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
6402 *((ULONG *)outData) = openAction; outData += 4;
6403 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
6404 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6405 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
6406 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
6407 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
6408 *((FILETIME *)outData) = ft; outData += 8; /* change time */
6409 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
6410 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
6411 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
6412 *((USHORT *)outData) = 0; outData += 2; /* filetype */
6413 *((USHORT *)outData) = 0; outData += 2; /* dev state */
6414 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
6415 outData += 1; /* is a dir? */
6416 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
6417 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
6418 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
6419 lock_ReleaseMutex(&scp->mx);
6422 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
6424 smb_ReleaseFID(fidp);
6426 cm_ReleaseUser(userp);
6428 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
6429 /* leave scp held since we put it in fidp->scp */
6433 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
6436 smb_packet_t *savedPacketp;
6437 ULONG filter; USHORT fid, watchtree;
6441 filter = smb_GetSMBParm(inp, 19) |
6442 (smb_GetSMBParm(inp, 20) << 16);
6443 fid = smb_GetSMBParm(inp, 21);
6444 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
6446 fidp = smb_FindFID(vcp, fid, 0);
6448 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
6449 return CM_ERROR_BADFD;
6452 savedPacketp = smb_CopyPacket(inp);
6454 savedPacketp->vcp = vcp;
6455 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6456 savedPacketp->nextp = smb_Directory_Watches;
6457 smb_Directory_Watches = savedPacketp;
6458 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6460 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
6461 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
6464 lock_ObtainMutex(&scp->mx);
6466 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
6468 scp->flags |= CM_SCACHEFLAG_WATCHED;
6469 lock_ReleaseMutex(&scp->mx);
6470 smb_ReleaseFID(fidp);
6472 outp->flags |= SMB_PACKETFLAG_NOSEND;
6476 unsigned char nullSecurityDesc[36] = {
6477 0x01, /* security descriptor revision */
6478 0x00, /* reserved, should be zero */
6479 0x00, 0x80, /* security descriptor control;
6480 * 0x8000 : self-relative format */
6481 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
6482 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
6483 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
6484 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
6485 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6486 /* "null SID" owner SID */
6487 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
6488 /* "null SID" group SID */
6491 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6493 int parmOffset, parmCount, dataOffset, dataCount;
6501 ULONG securityInformation;
6503 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6504 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6505 parmp = inp->data + parmOffset;
6506 sparmp = (USHORT *) parmp;
6507 lparmp = (ULONG *) parmp;
6510 securityInformation = lparmp[1];
6512 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
6513 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6521 parmOffset = 8*4 + 39;
6522 parmOffset += 1; /* pad to 4 */
6524 dataOffset = parmOffset + parmCount;
6528 /* Total Parameter Count */
6529 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6530 /* Total Data Count */
6531 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6532 /* Parameter Count */
6533 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6534 /* Parameter Offset */
6535 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6536 /* Parameter Displacement */
6537 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6539 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6541 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6542 /* Data Displacement */
6543 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6544 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
6545 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
6547 outData = smb_GetSMBData(outp, NULL);
6548 outData++; /* round to get to parmOffset */
6549 *((ULONG *)outData) = 36; outData += 4; /* length */
6551 if (maxData >= 36) {
6552 memcpy(outData, nullSecurityDesc, 36);
6556 return CM_ERROR_BUFFERTOOSMALL;
6559 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6561 unsigned short function;
6563 function = smb_GetSMBParm(inp, 18);
6565 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
6567 /* We can handle long names */
6568 if (vcp->flags & SMB_VCFLAG_USENT)
6569 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
6573 return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
6575 return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
6577 return smb_ReceiveNTTranCreate(vcp, inp, outp);
6579 return CM_ERROR_INVAL;
6584 * smb_NotifyChange -- find relevant change notification messages and
6587 * If we don't know the file name (i.e. a callback break), filename is
6588 * NULL, and we return a zero-length list.
6590 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
6591 cm_scache_t *dscp, char *filename, char *otherFilename,
6592 BOOL isDirectParent)
6594 smb_packet_t *watch, *lastWatch, *nextWatch;
6595 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
6596 char *outData, *oldOutData;
6600 BOOL twoEntries = FALSE;
6601 ULONG otherNameLen, oldParmCount = 0;
6606 /* Get ready for rename within directory */
6607 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
6609 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
6612 osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
6613 osi_LogSaveString(smb_logp,filename),dscp);
6615 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6616 watch = smb_Directory_Watches;
6618 filter = smb_GetSMBParm(watch, 19)
6619 | (smb_GetSMBParm(watch, 20) << 16);
6620 fid = smb_GetSMBParm(watch, 21);
6621 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
6622 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
6623 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
6627 * Strange hack - bug in NT Client and NT Server that we
6630 if (filter == 3 && wtree)
6633 fidp = smb_FindFID(vcp, fid, 0);
6635 osi_Log1(smb_logp," no fidp for fid[%d]",fid);
6637 watch = watch->nextp;
6640 if (fidp->scp != dscp
6641 || (filter & notifyFilter) == 0
6642 || (!isDirectParent && !wtree)) {
6643 osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
6644 smb_ReleaseFID(fidp);
6646 watch = watch->nextp;
6649 smb_ReleaseFID(fidp);
6652 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
6653 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
6655 nextWatch = watch->nextp;
6656 if (watch == smb_Directory_Watches)
6657 smb_Directory_Watches = nextWatch;
6659 lastWatch->nextp = nextWatch;
6661 /* Turn off WATCHED flag in dscp */
6662 lock_ObtainMutex(&dscp->mx);
6664 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6666 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
6667 lock_ReleaseMutex(&dscp->mx);
6669 /* Convert to response packet */
6670 ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
6671 ((smb_t *) watch)->wct = 0;
6674 if (filename == NULL)
6677 nameLen = strlen(filename);
6678 parmCount = 3*4 + nameLen*2;
6679 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6681 otherNameLen = strlen(otherFilename);
6682 oldParmCount = parmCount;
6683 parmCount += 3*4 + otherNameLen*2;
6684 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6686 if (maxLen < parmCount)
6687 parmCount = 0; /* not enough room */
6689 parmOffset = 8*4 + 39;
6690 parmOffset += 1; /* pad to 4 */
6691 dataOffset = parmOffset + parmCount;
6695 /* Total Parameter Count */
6696 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6697 /* Total Data Count */
6698 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6699 /* Parameter Count */
6700 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6701 /* Parameter Offset */
6702 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
6703 /* Parameter Displacement */
6704 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6706 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6708 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
6709 /* Data Displacement */
6710 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6711 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
6712 smb_SetSMBDataLength(watch, parmCount + 1);
6714 if (parmCount != 0) {
6716 outData = smb_GetSMBData(watch, NULL);
6717 outData++; /* round to get to parmOffset */
6718 oldOutData = outData;
6719 *((DWORD *)outData) = oldParmCount; outData += 4;
6720 /* Next Entry Offset */
6721 *((DWORD *)outData) = action; outData += 4;
6723 *((DWORD *)outData) = nameLen*2; outData += 4;
6724 /* File Name Length */
6725 p = strdup(filename);
6726 if (smb_StoreAnsiFilenames)
6728 mbstowcs((WCHAR *)outData, p, nameLen);
6732 outData = oldOutData + oldParmCount;
6733 *((DWORD *)outData) = 0; outData += 4;
6734 /* Next Entry Offset */
6735 *((DWORD *)outData) = otherAction; outData += 4;
6737 *((DWORD *)outData) = otherNameLen*2;
6738 outData += 4; /* File Name Length */
6739 p = strdup(otherFilename);
6740 if (smb_StoreAnsiFilenames)
6742 mbstowcs((WCHAR *)outData, p, otherNameLen); /* File Name */
6748 * If filename is null, we don't know the cause of the
6749 * change notification. We return zero data (see above),
6750 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
6751 * (= 0x010C). We set the error code here by hand, without
6752 * modifying wct and bcc.
6754 if (filename == NULL) {
6755 ((smb_t *) watch)->rcls = 0x0C;
6756 ((smb_t *) watch)->reh = 0x01;
6757 ((smb_t *) watch)->errLow = 0;
6758 ((smb_t *) watch)->errHigh = 0;
6759 /* Set NT Status codes flag */
6760 ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
6763 smb_SendPacket(vcp, watch);
6764 smb_FreePacket(watch);
6767 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6770 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6772 unsigned char *replyWctp;
6773 smb_packet_t *watch, *lastWatch;
6774 USHORT fid, watchtree;
6778 osi_Log0(smb_logp, "SMB3 receive NT cancel");
6780 lock_ObtainMutex(&smb_Dir_Watch_Lock);
6781 watch = smb_Directory_Watches;
6783 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
6784 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
6785 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
6786 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
6787 if (watch == smb_Directory_Watches)
6788 smb_Directory_Watches = watch->nextp;
6790 lastWatch->nextp = watch->nextp;
6791 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6793 /* Turn off WATCHED flag in scp */
6794 fid = smb_GetSMBParm(watch, 21);
6795 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
6797 if (vcp != watch->vcp)
6798 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
6801 fidp = smb_FindFID(vcp, fid, 0);
6803 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
6805 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
6808 lock_ObtainMutex(&scp->mx);
6810 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6812 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
6813 lock_ReleaseMutex(&scp->mx);
6814 smb_ReleaseFID(fidp);
6816 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
6819 /* assume STATUS32; return 0xC0000120 (CANCELED) */
6820 replyWctp = watch->wctp;
6824 ((smb_t *)watch)->rcls = 0x20;
6825 ((smb_t *)watch)->reh = 0x1;
6826 ((smb_t *)watch)->errLow = 0;
6827 ((smb_t *)watch)->errHigh = 0xC0;
6828 ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
6829 smb_SendPacket(vcp, watch);
6830 smb_FreePacket(watch);
6834 watch = watch->nextp;
6836 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6842 * NT rename also does hard links.
6845 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
6846 #define RENAME_FLAG_HARD_LINK 0x103
6847 #define RENAME_FLAG_RENAME 0x104
6848 #define RENAME_FLAG_COPY 0x105
6850 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6852 char *oldPathp, *newPathp;
6858 attrs = smb_GetSMBParm(inp, 0);
6859 rename_type = smb_GetSMBParm(inp, 1);
6861 if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
6862 osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
6863 return CM_ERROR_NOACCESS;
6866 tp = smb_GetSMBData(inp, NULL);
6867 oldPathp = smb_ParseASCIIBlock(tp, &tp);
6868 if (smb_StoreAnsiFilenames)
6869 OemToChar(oldPathp,oldPathp);
6870 newPathp = smb_ParseASCIIBlock(tp, &tp);
6871 if (smb_StoreAnsiFilenames)
6872 OemToChar(newPathp,newPathp);
6874 osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
6875 osi_LogSaveString(smb_logp, oldPathp),
6876 osi_LogSaveString(smb_logp, newPathp),
6877 ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
6879 if (rename_type == RENAME_FLAG_RENAME) {
6880 code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
6881 } else { /* RENAME_FLAG_HARD_LINK */
6882 code = smb_Link(vcp,inp,oldPathp,newPathp);
6889 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
6892 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
6895 smb_username_t *unp;
6897 unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
6899 lock_ObtainMutex(&unp->mx);
6900 unp->userp = cm_NewUser();
6901 lock_ReleaseMutex(&unp->mx);
6902 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6903 osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
6905 osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6906 osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);